mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-02-22 18:22:35 +00:00
Merge pull request #275 from GNS3/As-user-I-can-add-QEMU-VM
As user i can add qemu vm Fixes: #272 #273 #280 #281 #282 #283 #284 #285 #286
This commit is contained in:
commit
f3e2e8bf28
@ -1,3 +1,11 @@
|
|||||||
// This file is required by the index.html file and will
|
// This file is required by the index.html file and will
|
||||||
// be executed in the renderer process for that window.
|
// be executed in the renderer process for that window.
|
||||||
// All of the Node.js APIs are available in this process.
|
// All of the Node.js APIs are available in this process.
|
||||||
|
|
||||||
|
let shell = require('electron').shell
|
||||||
|
document.addEventListener('click', function (event) {
|
||||||
|
if (event.target.tagName === 'A' && event.target.href.startsWith('http')) {
|
||||||
|
event.preventDefault()
|
||||||
|
shell.openExternal(event.target.href)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
@ -2,13 +2,54 @@ import { NgModule } from '@angular/core';
|
|||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
import { ProjectMapComponent } from './components/project-map/project-map.component';
|
import { ProjectMapComponent } from './components/project-map/project-map.component';
|
||||||
import { ServersComponent } from "./components/servers/servers.component";
|
import { ServersComponent } from './components/servers/servers.component';
|
||||||
import { ProjectsComponent } from "./components/projects/projects.component";
|
import { ProjectsComponent } from './components/projects/projects.component';
|
||||||
import { DefaultLayoutComponent } from "./layouts/default-layout/default-layout.component";
|
import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.component';
|
||||||
import { SettingsComponent } from "./components/settings/settings.component";
|
import { SettingsComponent } from './components/settings/settings.component';
|
||||||
import { LocalServerComponent } from "./components/local-server/local-server.component";
|
import { LocalServerComponent } from './components/local-server/local-server.component';
|
||||||
|
import { PreferencesComponent } from './components/preferences/preferences.component';
|
||||||
|
import { QemuPreferencesComponent } from './components/preferences/qemu/qemu-preferences/qemu-preferences.component';
|
||||||
|
import { QemuVmTemplatesComponent } from './components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component';
|
||||||
|
import { QemuVmTemplateDetailsComponent } from './components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component';
|
||||||
|
import { AddQemuVmTemplateComponent } from './components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component';
|
||||||
|
import { GeneralPreferencesComponent } from './components/preferences/general/general-preferences.component';
|
||||||
|
import { VpcsPreferencesComponent } from './components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component';
|
||||||
|
import { VpcsTemplatesComponent } from './components/preferences/vpcs/vpcs-templates/vpcs-templates.component';
|
||||||
|
import { AddVpcsTemplateComponent } from './components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component';
|
||||||
|
import { VpcsTemplateDetailsComponent } from './components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component';
|
||||||
|
import { VirtualBoxPreferencesComponent } from './components/preferences/virtual-box/virtual-box-preferences/virtual-box-preferences.component';
|
||||||
|
import { VirtualBoxTemplatesComponent } from './components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component';
|
||||||
|
import { VirtualBoxTemplateDetailsComponent } from './components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component';
|
||||||
|
import { AddVirtualBoxTemplateComponent } from './components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component';
|
||||||
|
import { BuiltInPreferencesComponent } from './components/preferences/built-in/built-in-preferences.component';
|
||||||
|
import { EthernetHubsTemplatesComponent } from './components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component';
|
||||||
|
import { EthernetHubsAddTemplateComponent } from './components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component';
|
||||||
|
import { EthernetHubsTemplateDetailsComponent } from './components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component';
|
||||||
|
import { CloudNodesTemplatesComponent } from './components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component';
|
||||||
|
import { CloudNodesAddTemplateComponent } from './components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component';
|
||||||
|
import { CloudNodesTemplateDetailsComponent } from './components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component';
|
||||||
|
import { EthernetSwitchesTemplatesComponent } from './components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component';
|
||||||
|
import { EthernetSwitchesAddTemplateComponent } from './components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component';
|
||||||
|
import { EthernetSwitchesTemplateDetailsComponent } from './components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component';
|
||||||
|
import { DynamipsPreferencesComponent } from './components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component';
|
||||||
|
import { IosTemplatesComponent } from './components/preferences/dynamips/ios-templates/ios-templates.component';
|
||||||
import { InstalledSoftwareComponent } from './components/installed-software/installed-software.component';
|
import { InstalledSoftwareComponent } from './components/installed-software/installed-software.component';
|
||||||
|
import { IosTemplateDetailsComponent } from './components/preferences/dynamips/ios-template-details/ios-template-details.component';
|
||||||
|
import { AddIosTemplateComponent } from './components/preferences/dynamips/add-ios-template/add-ios-template.component';
|
||||||
|
import { VmwarePreferencesComponent } from './components/preferences/vmware/vmware-preferences/vmware-preferences.component';
|
||||||
|
import { VmwareTemplatesComponent } from './components/preferences/vmware/vmware-templates/vmware-templates.component';
|
||||||
|
import { VmwareTemplateDetailsComponent } from './components/preferences/vmware/vmware-template-details/vmware-template-details.component';
|
||||||
|
import { AddVmwareTemplateComponent } from './components/preferences/vmware/add-vmware-template/add-vmware-template.component';
|
||||||
|
import { DockerTemplatesComponent } from './components/preferences/docker/docker-templates/docker-templates.component';
|
||||||
|
import { AddDockerTemplateComponent } from './components/preferences/docker/add-docker-template/add-docker-template.component';
|
||||||
|
import { DockerTemplateDetailsComponent } from './components/preferences/docker/docker-template-details/docker-template-details.component';
|
||||||
|
import { IouTemplatesComponent } from './components/preferences/ios-on-unix/iou-templates/iou-templates.component';
|
||||||
|
import { AddIouTemplateComponent } from './components/preferences/ios-on-unix/add-iou-template/add-iou-template.component';
|
||||||
|
import { IouTemplateDetailsComponent } from './components/preferences/ios-on-unix/iou-template-details/iou-template-details.component';
|
||||||
|
import { CopyQemuVmTemplateComponent } from './components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component';
|
||||||
|
import { CopyIosTemplateComponent } from './components/preferences/dynamips/copy-ios-template/copy-ios-template.component';
|
||||||
|
import { CopyDockerTemplateComponent } from './components/preferences/docker/copy-docker-template/copy-docker-template.component';
|
||||||
|
import { CopyIouTemplateComponent } from './components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
@ -21,6 +62,58 @@ const routes: Routes = [
|
|||||||
{ path: 'server/:server_id/projects', component: ProjectsComponent },
|
{ path: 'server/:server_id/projects', component: ProjectsComponent },
|
||||||
{ path: 'settings', component: SettingsComponent },
|
{ path: 'settings', component: SettingsComponent },
|
||||||
{ path: 'installed-software', component: InstalledSoftwareComponent },
|
{ path: 'installed-software', component: InstalledSoftwareComponent },
|
||||||
|
{ path: 'server/:server_id/preferences', component: PreferencesComponent },
|
||||||
|
// { path: 'server/:server_id/preferences/general', component: GeneralPreferencesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/builtin', component: BuiltInPreferencesComponent},
|
||||||
|
|
||||||
|
{ path: 'server/:server_id/preferences/builtin/ethernet-hubs', component: EthernetHubsTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/builtin/ethernet-hubs/addtemplate', component: EthernetHubsAddTemplateComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/builtin/ethernet-hubs/:template_id', component: EthernetHubsTemplateDetailsComponent },
|
||||||
|
|
||||||
|
{ path: 'server/:server_id/preferences/builtin/ethernet-switches', component: EthernetSwitchesTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/builtin/ethernet-switches/addtemplate', component: EthernetSwitchesAddTemplateComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/builtin/ethernet-switches/:template_id', component: EthernetSwitchesTemplateDetailsComponent },
|
||||||
|
|
||||||
|
{ path: 'server/:server_id/preferences/builtin/cloud-nodes', component: CloudNodesTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/builtin/cloud-nodes/addtemplate', component: CloudNodesAddTemplateComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/builtin/cloud-nodes/:template_id', component: CloudNodesTemplateDetailsComponent },
|
||||||
|
|
||||||
|
//{ path: 'server/:server_id/preferences/dynamips', component: DynamipsPreferencesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/dynamips/templates', component: IosTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/dynamips/templates/addtemplate', component: AddIosTemplateComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/dynamips/templates/:template_id', component: IosTemplateDetailsComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/dynamips/templates/:template_id/copy', component: CopyIosTemplateComponent },
|
||||||
|
|
||||||
|
// { path: 'server/:server_id/preferences/qemu', component: QemuPreferencesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/qemu/templates', component: QemuVmTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/qemu/templates/:template_id/copy', component: CopyQemuVmTemplateComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/qemu/templates/:template_id', component: QemuVmTemplateDetailsComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/qemu/addtemplate', component: AddQemuVmTemplateComponent },
|
||||||
|
|
||||||
|
// { path: 'server/:server_id/preferences/vpcs', component: VpcsPreferencesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/vpcs/templates', component: VpcsTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/vpcs/templates/:template_id', component: VpcsTemplateDetailsComponent},
|
||||||
|
{ path: 'server/:server_id/preferences/vpcs/addtemplate', component: AddVpcsTemplateComponent },
|
||||||
|
|
||||||
|
// { path: 'server/:server_id/preferences/virtualbox', component: VirtualBoxPreferencesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/virtualbox/templates', component: VirtualBoxTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/virtualbox/templates/:template_id', component: VirtualBoxTemplateDetailsComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/virtualbox/addtemplate', component: AddVirtualBoxTemplateComponent },
|
||||||
|
|
||||||
|
// { path: 'server/:server_id/preferences/vmware', component: VmwarePreferencesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/vmware/templates', component: VmwareTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/vmware/templates/:template_id', component: VmwareTemplateDetailsComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/vmware/addtemplate', component: AddVmwareTemplateComponent },
|
||||||
|
|
||||||
|
{ path: 'server/:server_id/preferences/docker/templates', component: DockerTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/docker/templates/:template_id', component: DockerTemplateDetailsComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/docker/templates/:template_id/copy', component: CopyDockerTemplateComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/docker/addtemplate', component: AddDockerTemplateComponent },
|
||||||
|
|
||||||
|
{ path: 'server/:server_id/preferences/iou/templates', component: IouTemplatesComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/iou/templates/:template_id', component: IouTemplateDetailsComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/iou/templates/:template_id/copy', component: CopyIouTemplateComponent },
|
||||||
|
{ path: 'server/:server_id/preferences/iou/addtemplate', component: AddIouTemplateComponent }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ path: 'server/:server_id/project/:project_id', component: ProjectMapComponent }
|
{ path: 'server/:server_id/project/:project_id', component: ProjectMapComponent }
|
||||||
|
@ -35,7 +35,8 @@ import { ProgressDialogComponent } from './common/progress-dialog/progress-dialo
|
|||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
import { ProjectMapComponent } from './components/project-map/project-map.component';
|
import { ProjectMapComponent } from './components/project-map/project-map.component';
|
||||||
import { ServersComponent, AddServerDialogComponent } from './components/servers/servers.component';
|
import { ServersComponent } from './components/servers/servers.component';
|
||||||
|
import { AddServerDialogComponent } from './components/servers/add-server-dialog/add-server-dialog.component';
|
||||||
import { ContextMenuComponent } from './components/project-map/context-menu/context-menu.component';
|
import { ContextMenuComponent } from './components/project-map/context-menu/context-menu.component';
|
||||||
import { StartNodeActionComponent } from './components/project-map/context-menu/actions/start-node-action/start-node-action.component';
|
import { StartNodeActionComponent } from './components/project-map/context-menu/actions/start-node-action/start-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';
|
||||||
@ -92,9 +93,76 @@ import { InstallSoftwareComponent } from './components/installed-software/instal
|
|||||||
import { StyleEditorDialogComponent } from './components/project-map/drawings-editors/style-editor/style-editor.component';
|
import { StyleEditorDialogComponent } from './components/project-map/drawings-editors/style-editor/style-editor.component';
|
||||||
import { EditTextActionComponent } from './components/project-map/context-menu/actions/edit-text-action/edit-text-action.component';
|
import { EditTextActionComponent } from './components/project-map/context-menu/actions/edit-text-action/edit-text-action.component';
|
||||||
import { TextEditorDialogComponent } from './components/project-map/drawings-editors/text-editor/text-editor.component';
|
import { TextEditorDialogComponent } from './components/project-map/drawings-editors/text-editor/text-editor.component';
|
||||||
|
import { PreferencesComponent } from './components/preferences/preferences.component';
|
||||||
|
import { QemuPreferencesComponent } from './components/preferences/qemu/qemu-preferences/qemu-preferences.component';
|
||||||
|
import { ServerSettingsService } from './services/server-settings.service';
|
||||||
|
import { QemuVmTemplatesComponent } from './components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component';
|
||||||
|
import { AddQemuVmTemplateComponent } from './components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component';
|
||||||
|
import { QemuVmTemplateDetailsComponent } from './components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component';
|
||||||
|
import { QemuService } from './services/qemu.service';
|
||||||
|
import { GeneralPreferencesComponent } from './components/preferences/general/general-preferences.component';
|
||||||
|
import { VpcsPreferencesComponent } from './components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component';
|
||||||
|
import { VpcsTemplatesComponent } from './components/preferences/vpcs/vpcs-templates/vpcs-templates.component';
|
||||||
|
import { VpcsService } from './services/vpcs.service';
|
||||||
|
import { AddVpcsTemplateComponent } from './components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component';
|
||||||
|
import { VpcsTemplateDetailsComponent } from './components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component';
|
||||||
|
import { TemplateMocksService } from './services/template-mocks.service';
|
||||||
|
import { VirtualBoxPreferencesComponent } from './components/preferences/virtual-box/virtual-box-preferences/virtual-box-preferences.component';
|
||||||
|
import { VirtualBoxTemplatesComponent } from './components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component';
|
||||||
|
import { VirtualBoxService } from './services/virtual-box.service';
|
||||||
|
import { VirtualBoxTemplateDetailsComponent } from './components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component';
|
||||||
|
import { AddVirtualBoxTemplateComponent } from './components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component';
|
||||||
|
import { BuiltInPreferencesComponent } from './components/preferences/built-in/built-in-preferences.component';
|
||||||
|
import { EthernetHubsTemplatesComponent } from './components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component';
|
||||||
|
import { BuiltInTemplatesService } from './services/built-in-templates.service';
|
||||||
|
import { EthernetHubsAddTemplateComponent } from './components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component';
|
||||||
|
import { EthernetHubsTemplateDetailsComponent } from './components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component';
|
||||||
|
import { CloudNodesTemplatesComponent } from './components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component';
|
||||||
|
import { CloudNodesAddTemplateComponent } from './components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component';
|
||||||
|
import { CloudNodesTemplateDetailsComponent } from './components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component';
|
||||||
|
import { EthernetSwitchesTemplatesComponent } from './components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component';
|
||||||
|
import { EthernetSwitchesAddTemplateComponent } from './components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component';
|
||||||
|
import { EthernetSwitchesTemplateDetailsComponent } from './components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component';
|
||||||
|
import { DynamipsPreferencesComponent } from './components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component';
|
||||||
|
import { IosTemplatesComponent } from './components/preferences/dynamips/ios-templates/ios-templates.component';
|
||||||
|
import { IosService } from './services/ios.service';
|
||||||
|
import { SymbolsComponent } from './components/preferences/common/symbols/symbols.component';
|
||||||
import { InstalledSoftwareService } from './services/installed-software.service';
|
import { InstalledSoftwareService } from './services/installed-software.service';
|
||||||
import { ExternalSoftwareDefinitionService } from './services/external-software-definition.service';
|
import { ExternalSoftwareDefinitionService } from './services/external-software-definition.service';
|
||||||
import { PlatformService } from './services/platform.service';
|
import { PlatformService } from './services/platform.service';
|
||||||
|
import { IosTemplateDetailsComponent } from './components/preferences/dynamips/ios-template-details/ios-template-details.component';
|
||||||
|
import { AddIosTemplateComponent } from './components/preferences/dynamips/add-ios-template/add-ios-template.component';
|
||||||
|
import { IosConfigurationService } from './services/ios-configuration.service';
|
||||||
|
import { QemuConfigurationService } from './services/qemu-configuration.service';
|
||||||
|
import { VirtualBoxConfigurationService } from './services/virtual-box-configuration.service';
|
||||||
|
import { VpcsConfigurationService } from './services/vpcs-configuration.service';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from './services/built-in-templates-configuration.service';
|
||||||
|
import { VmwarePreferencesComponent } from './components/preferences/vmware/vmware-preferences/vmware-preferences.component';
|
||||||
|
import { VmwareTemplatesComponent } from './components/preferences/vmware/vmware-templates/vmware-templates.component';
|
||||||
|
import { VmwareService } from './services/vmware.service';
|
||||||
|
import { VmwareConfigurationService } from './services/vmware-configuration.service';
|
||||||
|
import { VmwareTemplateDetailsComponent } from './components/preferences/vmware/vmware-template-details/vmware-template-details.component';
|
||||||
|
import { AddVmwareTemplateComponent } from './components/preferences/vmware/add-vmware-template/add-vmware-template.component';
|
||||||
|
import { DeleteConfirmationDialogComponent } from './components/preferences/common/delete-confirmation-dialog/delete-confirmation-dialog.component';
|
||||||
|
import { DeleteTemplateComponent } from './components/preferences/common/delete-template-component/delete-template.component';
|
||||||
|
import { DockerService } from './services/docker.service';
|
||||||
|
import { DockerTemplatesComponent } from './components/preferences/docker/docker-templates/docker-templates.component';
|
||||||
|
import { DockerConfigurationService } from './services/docker-configuration.service';
|
||||||
|
import { AddDockerTemplateComponent } from './components/preferences/docker/add-docker-template/add-docker-template.component';
|
||||||
|
import { DockerTemplateDetailsComponent } from './components/preferences/docker/docker-template-details/docker-template-details.component';
|
||||||
|
import { IouTemplatesComponent } from './components/preferences/ios-on-unix/iou-templates/iou-templates.component';
|
||||||
|
import { IouService } from './services/iou.service';
|
||||||
|
import { AddIouTemplateComponent } from './components/preferences/ios-on-unix/add-iou-template/add-iou-template.component';
|
||||||
|
import { IouConfigurationService } from './services/iou-configuration.service';
|
||||||
|
import { IouTemplateDetailsComponent } from './components/preferences/ios-on-unix/iou-template-details/iou-template-details.component';
|
||||||
|
import { CopyQemuVmTemplateComponent } from './components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component';
|
||||||
|
import { CopyIosTemplateComponent } from './components/preferences/dynamips/copy-ios-template/copy-ios-template.component';
|
||||||
|
import { CopyIouTemplateComponent } from './components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component';
|
||||||
|
import { CopyDockerTemplateComponent } from './components/preferences/docker/copy-docker-template/copy-docker-template.component';
|
||||||
|
import { EmptyTemplatesListComponent } from './components/preferences/common/empty-templates-list/empty-templates-list.component';
|
||||||
|
import { SymbolsMenuComponent } from './components/preferences/common/symbols-menu/symbols-menu.component';
|
||||||
|
import { SearchFilter } from './filters/searchFilter.pipe';
|
||||||
|
import { RecentlyOpenedProjectService } from './services/recentlyOpenedProject.service';
|
||||||
import { ServerManagementService } from './services/server-management.service';
|
import { ServerManagementService } from './services/server-management.service';
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
@ -132,6 +200,7 @@ if (environment.production) {
|
|||||||
EditTextActionComponent,
|
EditTextActionComponent,
|
||||||
ProjectMapShortcutsComponent,
|
ProjectMapShortcutsComponent,
|
||||||
SettingsComponent,
|
SettingsComponent,
|
||||||
|
PreferencesComponent,
|
||||||
LocalServerComponent,
|
LocalServerComponent,
|
||||||
ProgressComponent,
|
ProgressComponent,
|
||||||
ServerDiscoveryComponent,
|
ServerDiscoveryComponent,
|
||||||
@ -149,7 +218,54 @@ if (environment.production) {
|
|||||||
InterfaceLabelDraggedComponent,
|
InterfaceLabelDraggedComponent,
|
||||||
InstallSoftwareComponent,
|
InstallSoftwareComponent,
|
||||||
StyleEditorDialogComponent,
|
StyleEditorDialogComponent,
|
||||||
TextEditorDialogComponent
|
TextEditorDialogComponent,
|
||||||
|
QemuPreferencesComponent,
|
||||||
|
QemuVmTemplatesComponent,
|
||||||
|
AddQemuVmTemplateComponent,
|
||||||
|
QemuVmTemplateDetailsComponent,
|
||||||
|
GeneralPreferencesComponent,
|
||||||
|
VpcsPreferencesComponent,
|
||||||
|
VpcsTemplatesComponent,
|
||||||
|
AddVpcsTemplateComponent,
|
||||||
|
VpcsTemplateDetailsComponent,
|
||||||
|
VirtualBoxPreferencesComponent,
|
||||||
|
VirtualBoxTemplatesComponent,
|
||||||
|
VirtualBoxTemplateDetailsComponent,
|
||||||
|
AddVirtualBoxTemplateComponent,
|
||||||
|
BuiltInPreferencesComponent,
|
||||||
|
EthernetHubsTemplatesComponent,
|
||||||
|
EthernetHubsAddTemplateComponent,
|
||||||
|
EthernetHubsTemplateDetailsComponent,
|
||||||
|
CloudNodesTemplatesComponent,
|
||||||
|
CloudNodesAddTemplateComponent,
|
||||||
|
CloudNodesTemplateDetailsComponent,
|
||||||
|
EthernetSwitchesTemplatesComponent,
|
||||||
|
EthernetSwitchesAddTemplateComponent,
|
||||||
|
EthernetSwitchesTemplateDetailsComponent,
|
||||||
|
DynamipsPreferencesComponent,
|
||||||
|
IosTemplatesComponent,
|
||||||
|
IosTemplateDetailsComponent,
|
||||||
|
AddIosTemplateComponent,
|
||||||
|
SymbolsComponent,
|
||||||
|
VmwarePreferencesComponent,
|
||||||
|
VmwareTemplatesComponent,
|
||||||
|
VmwareTemplateDetailsComponent,
|
||||||
|
AddVmwareTemplateComponent,
|
||||||
|
DeleteConfirmationDialogComponent,
|
||||||
|
DeleteTemplateComponent,
|
||||||
|
DockerTemplatesComponent,
|
||||||
|
AddDockerTemplateComponent,
|
||||||
|
DockerTemplateDetailsComponent,
|
||||||
|
IouTemplatesComponent,
|
||||||
|
AddIouTemplateComponent,
|
||||||
|
IouTemplateDetailsComponent,
|
||||||
|
CopyQemuVmTemplateComponent,
|
||||||
|
CopyIosTemplateComponent,
|
||||||
|
CopyIouTemplateComponent,
|
||||||
|
CopyDockerTemplateComponent,
|
||||||
|
EmptyTemplatesListComponent,
|
||||||
|
SymbolsMenuComponent,
|
||||||
|
SearchFilter
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
@ -196,9 +312,28 @@ if (environment.production) {
|
|||||||
ServerDatabase,
|
ServerDatabase,
|
||||||
ProjectNameValidator,
|
ProjectNameValidator,
|
||||||
ToolsService,
|
ToolsService,
|
||||||
|
ServerSettingsService,
|
||||||
|
QemuService,
|
||||||
|
VpcsService,
|
||||||
|
TemplateMocksService,
|
||||||
|
VirtualBoxService,
|
||||||
|
BuiltInTemplatesService,
|
||||||
|
IosService,
|
||||||
InstalledSoftwareService,
|
InstalledSoftwareService,
|
||||||
ExternalSoftwareDefinitionService,
|
ExternalSoftwareDefinitionService,
|
||||||
PlatformService,
|
PlatformService,
|
||||||
|
IosConfigurationService,
|
||||||
|
QemuConfigurationService,
|
||||||
|
VirtualBoxConfigurationService,
|
||||||
|
VpcsConfigurationService,
|
||||||
|
BuiltInTemplatesConfigurationService,
|
||||||
|
VmwareService,
|
||||||
|
VmwareConfigurationService,
|
||||||
|
DockerService,
|
||||||
|
DockerConfigurationService,
|
||||||
|
IouService,
|
||||||
|
IouConfigurationService,
|
||||||
|
RecentlyOpenedProjectService,
|
||||||
ServerManagementService
|
ServerManagementService
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
@ -210,7 +345,9 @@ if (environment.production) {
|
|||||||
ImportProjectDialogComponent,
|
ImportProjectDialogComponent,
|
||||||
ConfirmationDialogComponent,
|
ConfirmationDialogComponent,
|
||||||
StyleEditorDialogComponent,
|
StyleEditorDialogComponent,
|
||||||
TextEditorDialogComponent
|
TextEditorDialogComponent,
|
||||||
|
SymbolsComponent,
|
||||||
|
DeleteConfirmationDialogComponent
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<h1>Installed software</h1>
|
<h1>Installed software</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="default-content">
|
<div class="default-content">
|
||||||
<div class="example-container mat-elevation-z8">
|
<div class="container mat-elevation-z8">
|
||||||
<mat-table #table [dataSource]="dataSource">
|
<mat-table #table [dataSource]="dataSource">
|
||||||
|
|
||||||
<ng-container matColumnDef="name">
|
<ng-container matColumnDef="name">
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Built-in preferences</h1>
|
||||||
|
<button class="top-button" class="cancel-button" routerLink="/server/{{serverId}}/preferences" mat-button>Back</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<div class="listcontainer mat-elevation-z8">
|
||||||
|
<mat-nav-list>
|
||||||
|
<mat-list-item routerLink="/server/{{serverId}}/preferences/builtin/ethernet-hubs">
|
||||||
|
Ethernet hubs
|
||||||
|
</mat-list-item>
|
||||||
|
<mat-list-item routerLink="/server/{{serverId}}/preferences/builtin/ethernet-switches">
|
||||||
|
Ethernet switches
|
||||||
|
</mat-list-item>
|
||||||
|
<mat-list-item routerLink="/server/{{serverId}}/preferences/builtin/cloud-nodes">
|
||||||
|
Cloud nodes
|
||||||
|
</mat-list-item>
|
||||||
|
</mat-nav-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,44 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatCheckboxModule, MatIconModule, MatToolbarModule, MatMenuModule } from '@angular/material';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { MockedActivatedRoute } from '../preferences.component.spec';
|
||||||
|
import { BuiltInPreferencesComponent } from './built-in-preferences.component';
|
||||||
|
|
||||||
|
describe('BuiltInPreferencesComponent', () => {
|
||||||
|
let component: BuiltInPreferencesComponent;
|
||||||
|
let fixture: ComponentFixture<BuiltInPreferencesComponent>;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
}
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
BuiltInPreferencesComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(BuiltInPreferencesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set correct server id', () => {
|
||||||
|
expect(component.serverId).toBe('1');
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,20 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-built-in-preferences',
|
||||||
|
templateUrl: './built-in-preferences.component.html',
|
||||||
|
styleUrls: ['./built-in-preferences.component.scss', '../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class BuiltInPreferencesComponent implements OnInit {
|
||||||
|
public serverId: string = "";
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.serverId = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">New cloud node template</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="formGroup">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input formControlName="templateName" matInput type="text" [(ngModel)]="templateName" placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,87 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { CloudTemplate } from '../../../../../models/templates/cloud-template';
|
||||||
|
import { CloudNodesAddTemplateComponent } from './cloud-nodes-add-template.component';
|
||||||
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
|
import { MockedToasterService } from '../../../../../services/toaster.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../../preferences.component.spec';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { TemplateMocksService } from '../../../../../services/template-mocks.service';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
export class MockedBuiltInTemplatesService {
|
||||||
|
public addTemplate(server: Server, cloudTemplate: CloudTemplate) {
|
||||||
|
return of(cloudTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('CloudNodesAddTemplateComponent', () => {
|
||||||
|
let component: CloudNodesAddTemplateComponent;
|
||||||
|
let fixture: ComponentFixture<CloudNodesAddTemplateComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
CloudNodesAddTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CloudNodesAddTemplateComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call add template', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as CloudTemplate));
|
||||||
|
component.templateName = "sample name";
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
component.formGroup.controls['templateName'].setValue('template name');
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.addTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when template name is empty', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as CloudTemplate));
|
||||||
|
spyOn(mockedToasterService, 'error');
|
||||||
|
component.templateName = "";
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
expect(mockedToasterService.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,66 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { TemplateMocksService } from '../../../../../services/template-mocks.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { CloudTemplate } from '../../../../../models/templates/cloud-template';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-cloud-nodes-add-template',
|
||||||
|
templateUrl: './cloud-nodes-add-template.component.html',
|
||||||
|
styleUrls: ['./cloud-nodes-add-template.component.scss', '../../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class CloudNodesAddTemplateComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
templateName: string = '';
|
||||||
|
formGroup: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private builtInTemplatesService: BuiltInTemplatesService,
|
||||||
|
private router: Router,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private templateMocksService: TemplateMocksService,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.formGroup = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'cloud-nodes']);
|
||||||
|
}
|
||||||
|
|
||||||
|
addTemplate() {
|
||||||
|
if (!this.formGroup.invalid) {
|
||||||
|
let cloudTemplate: CloudTemplate;
|
||||||
|
|
||||||
|
this.templateMocksService.getCloudNodeTemplate().subscribe((template: CloudTemplate) => {
|
||||||
|
cloudTemplate = template;
|
||||||
|
});
|
||||||
|
|
||||||
|
cloudTemplate.template_id = uuid();
|
||||||
|
cloudTemplate.name = this.templateName;
|
||||||
|
|
||||||
|
this.builtInTemplatesService.addTemplate(this.server, cloudTemplate).subscribe((cloudNodeTemplate) => {
|
||||||
|
this.goBack();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,173 @@
|
|||||||
|
<div class="content" [ngClass]="{ shadowed: isSymbolSelectionOpened}">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Cloud configuration</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content" *ngIf="cloudNodeTemplate">
|
||||||
|
<mat-accordion>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
General
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="cloudNodeTemplate.name"
|
||||||
|
placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="cloudNodeTemplate.default_name_format"
|
||||||
|
placeholder="Default name format">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="cloudNodeTemplate.symbol"
|
||||||
|
placeholder="Symbol">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Category"
|
||||||
|
[(ngModel)]="cloudNodeTemplate.category">
|
||||||
|
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
||||||
|
{{category[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Console type"
|
||||||
|
[(ngModel)]="cloudNodeTemplate.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="cloudNodeTemplate.remote_console_host"
|
||||||
|
placeholder="Console host">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="cloudNodeTemplate.remote_console_port"
|
||||||
|
placeholder="Console port">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="cloudNodeTemplate.remote_console_http_path"
|
||||||
|
placeholder="Console HTTP path">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
Ethernet interfaces
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<div class="form-field" *ngFor="let port of portsMappingEthernet">
|
||||||
|
<div class="form-field">{{port.name}}</div><br/><br/>
|
||||||
|
</div>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Ethernet interface"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="ethernetInterface">
|
||||||
|
<mat-option *ngFor="let type of " [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="form-field" (click)="onAddEthernetInterface()">Add</button>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
TAP interfaces
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<div class="form-field" *ngFor="let port of portsMappingTap">
|
||||||
|
<div class="form-field">{{port.name}}</div><br/><br/>
|
||||||
|
</div>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="tapInterface"
|
||||||
|
placeholder="TAP interface">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="form-field" (click)="onAddTapInterface()">Add</button>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
UDP tunnels
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<table *ngIf="dataSourceUdp.length" class="table" mat-table [dataSource]="dataSourceUdp">
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Name </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="rport">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Local port </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.rport}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="rhost">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Type </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.rhost}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="lport">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Remote port </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.lport}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
<br *ngIf="dataSourceUdp.length"/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="newPort.name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="newPort.lport"
|
||||||
|
placeholder="Local port">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="newPort.rhost"
|
||||||
|
placeholder="Remote host">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="newPort.rport"
|
||||||
|
placeholder="Remote port">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="form-field" (click)="onAddUdpInterface()">Add</button>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button><br/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && cloudNodeTemplate" [server]="server" [symbol]="cloudNodeTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
@ -0,0 +1,77 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatTableModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { CloudTemplate } from '../../../../../models/templates/cloud-template';
|
||||||
|
import { CloudNodesTemplateDetailsComponent } from './cloud-nodes-template-details.component';
|
||||||
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
|
import { MockedToasterService } from '../../../../../services/toaster.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../../preferences.component.spec';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
|
||||||
|
export class MockedBuiltInTemplatesService {
|
||||||
|
public getTemplate(server: Server, template_id: string) {
|
||||||
|
return of({ports_mapping: []} as CloudTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public saveTemplate(server: Server, cloudTemplate: CloudTemplate) {
|
||||||
|
return of(cloudTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('CloudNodesTemplateDetailsComponent', () => {
|
||||||
|
let component: CloudNodesTemplateDetailsComponent;
|
||||||
|
let fixture: ComponentFixture<CloudNodesTemplateDetailsComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, MatTableModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService },
|
||||||
|
{ provide: BuiltInTemplatesConfigurationService, useClass: BuiltInTemplatesConfigurationService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
CloudNodesTemplateDetailsComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CloudNodesTemplateDetailsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call save template', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as CloudTemplate));
|
||||||
|
|
||||||
|
component.cloudNodeTemplate = {ports_mapping: []} as CloudTemplate;
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.saveTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,131 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { CloudTemplate } from '../../../../../models/templates/cloud-template';
|
||||||
|
import { PortsMappingEntity } from '../../../../../models/ethernetHub/ports-mapping-enity';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-cloud-nodes-template-details',
|
||||||
|
templateUrl: './cloud-nodes-template-details.component.html',
|
||||||
|
styleUrls: ['./cloud-nodes-template-details.component.scss', '../../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class CloudNodesTemplateDetailsComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
cloudNodeTemplate: CloudTemplate;
|
||||||
|
|
||||||
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
|
categories = [];
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
|
||||||
|
tapInterface: string = '';
|
||||||
|
ethernetInterface: string = '';
|
||||||
|
ethernetInterfaces: string[] = ['Ethernet 2', 'Ethernet 3'];
|
||||||
|
portsMappingEthernet: PortsMappingEntity[] = [];
|
||||||
|
portsMappingTap: PortsMappingEntity[] = [];
|
||||||
|
portsMappingUdp: PortsMappingEntity[] = [];
|
||||||
|
newPort: PortsMappingEntity;
|
||||||
|
displayedColumns: string[] = ['name', 'lport', 'rhost', 'rport'];
|
||||||
|
dataSourceUdp: PortsMappingEntity[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private builtInTemplatesService: BuiltInTemplatesService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService,
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
this.newPort = {
|
||||||
|
name: '',
|
||||||
|
port_number: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
const template_id = this.route.snapshot.paramMap.get("template_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.getConfiguration();
|
||||||
|
this.builtInTemplatesService.getTemplate(this.server, template_id).subscribe((cloudNodeTemplate: CloudTemplate) => {
|
||||||
|
this.cloudNodeTemplate = cloudNodeTemplate;
|
||||||
|
|
||||||
|
this.portsMappingEthernet = this.cloudNodeTemplate.ports_mapping
|
||||||
|
.filter((elem) => elem.type === 'ethernet');
|
||||||
|
|
||||||
|
this.portsMappingTap = this.cloudNodeTemplate.ports_mapping
|
||||||
|
.filter((elem) => elem.type === 'tap');
|
||||||
|
|
||||||
|
this.portsMappingUdp = this.cloudNodeTemplate.ports_mapping
|
||||||
|
.filter((elem) => elem.type === 'udp');
|
||||||
|
|
||||||
|
this.dataSourceUdp = this.portsMappingUdp;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'cloud-nodes']);
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.categories = this.builtInTemplatesConfigurationService.getCategoriesForCloudNodes();
|
||||||
|
this.consoleTypes = this.builtInTemplatesConfigurationService.getConsoleTypesForCloudNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddEthernetInterface() {
|
||||||
|
if (this.ethernetInterface) {
|
||||||
|
this.portsMappingEthernet.push({
|
||||||
|
interface: this.ethernetInterface,
|
||||||
|
name: this.ethernetInterface,
|
||||||
|
port_number: 0,
|
||||||
|
type: "ethernet"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddTapInterface() {
|
||||||
|
if (this.tapInterface) {
|
||||||
|
this.portsMappingTap.push({
|
||||||
|
interface: this.tapInterface,
|
||||||
|
name: this.tapInterface,
|
||||||
|
port_number: 0,
|
||||||
|
type: "tap"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddUdpInterface() {
|
||||||
|
this.portsMappingUdp.push(this.newPort);
|
||||||
|
this.dataSourceUdp = [...this.portsMappingUdp];
|
||||||
|
|
||||||
|
this.newPort = {
|
||||||
|
name: '',
|
||||||
|
port_number: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onSave() {
|
||||||
|
this.cloudNodeTemplate.ports_mapping = [...this.portsMappingEthernet, ...this.portsMappingTap];
|
||||||
|
|
||||||
|
this.builtInTemplatesService.saveTemplate(this.server, this.cloudNodeTemplate).subscribe((cloudNodeTemplate: CloudTemplate) => {
|
||||||
|
this.toasterService.success("Changes saved");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
chooseSymbol() {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
this.cloudNodeTemplate.symbol = chosenSymbol;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Cloud nodes templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences/builtin" mat-button>Back</button>
|
||||||
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/builtin/cloud-nodes/addtemplate" mat-raised-button color="primary">Add cloud node template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-empty-templates-list *ngIf="!cloudNodesTemplates.length"></app-empty-templates-list>
|
||||||
|
<div class="default-content" *ngIf="cloudNodesTemplates.length">
|
||||||
|
<div class="listcontainer mat-elevation-z8">
|
||||||
|
<mat-nav-list *ngIf="server">
|
||||||
|
<div class="list-item" *ngFor='let template of cloudNodesTemplates'>
|
||||||
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
|
<button mat-button class="menu-button" [matMenuTriggerFor]="menu">
|
||||||
|
<mat-icon>more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menu="matMenu">
|
||||||
|
<button mat-menu-item (click)="deleteTemplate(template)">
|
||||||
|
<mat-icon>delete</mat-icon><span>Delete</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
||||||
|
</mat-nav-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-delete-template
|
||||||
|
#deleteComponent
|
||||||
|
[server]="server"
|
||||||
|
(deleteEvent)="onDeleteEvent()">
|
||||||
|
</app-delete-template>
|
@ -0,0 +1,57 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { CloudTemplate } from '../../../../../models/templates/cloud-template';
|
||||||
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../../preferences.component.spec';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { CloudNodesTemplatesComponent } from './cloud-nodes-templates.component';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
|
||||||
|
export class MockedBuiltInTemplatesService {
|
||||||
|
public getTemplates(server: Server) {
|
||||||
|
return of([{} as CloudTemplate]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('CloudNodesTemplatesComponent', () => {
|
||||||
|
let component: CloudNodesTemplatesComponent;
|
||||||
|
let fixture: ComponentFixture<CloudNodesTemplatesComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
CloudNodesTemplatesComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CloudNodesTemplatesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,47 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { CloudTemplate } from '../../../../../models/templates/cloud-template';
|
||||||
|
import { DeleteTemplateComponent } from '../../../common/delete-template-component/delete-template.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-cloud-nodes-templates',
|
||||||
|
templateUrl: './cloud-nodes-templates.component.html',
|
||||||
|
styleUrls: ['./cloud-nodes-templates.component.scss', '../../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class CloudNodesTemplatesComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
cloudNodesTemplates: CloudTemplate[] = [];
|
||||||
|
@ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private builtInTemplatesService: BuiltInTemplatesService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
this.getTemplates();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplates() {
|
||||||
|
this.builtInTemplatesService.getTemplates(this.server).subscribe((cloudNodesTemplates: CloudTemplate[]) => {
|
||||||
|
this.cloudNodesTemplates = cloudNodesTemplates.filter((elem) => elem.template_type === "cloud" && !elem.builtin);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTemplate(template: CloudTemplate) {
|
||||||
|
this.deleteComponent.deleteItem(template.name, template.template_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteEvent() {
|
||||||
|
this.getTemplates();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">New Ethernet hub template</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="formGroup">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input formControlName="templateName" matInput type="text" [(ngModel)]="templateName" placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input formControlName="numberOfPorts" matInput type="text" [(ngModel)]="numberOfPorts" placeholder="Number of ports">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,102 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
|
import { MockedToasterService } from '../../../../../services/toaster.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../../preferences.component.spec';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { TemplateMocksService } from '../../../../../services/template-mocks.service';
|
||||||
|
import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template';
|
||||||
|
import { EthernetHubsAddTemplateComponent } from './ethernet-hubs-add-template.component';
|
||||||
|
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
export class MockedBuiltInTemplatesService {
|
||||||
|
public addTemplate(server: Server, ethernetHubTemplate: EthernetHubTemplate) {
|
||||||
|
return of(ethernetHubTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('EthernetHubsAddTemplateComponent', () => {
|
||||||
|
let component: EthernetHubsAddTemplateComponent;
|
||||||
|
let fixture: ComponentFixture<EthernetHubsAddTemplateComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
EthernetHubsAddTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(EthernetHubsAddTemplateComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call add template', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetHubTemplate));
|
||||||
|
component.templateName = "sample name";
|
||||||
|
component.numberOfPorts = 2;
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
component.formGroup.controls['templateName'].setValue('template name');
|
||||||
|
component.formGroup.controls['numberOfPorts'].setValue('1');
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.addTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when template name is empty', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetHubTemplate));
|
||||||
|
spyOn(mockedToasterService, 'error');
|
||||||
|
component.templateName = "";
|
||||||
|
component.numberOfPorts = 2;
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
expect(mockedToasterService.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when number of ports is missing', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetHubTemplate));
|
||||||
|
spyOn(mockedToasterService, 'error');
|
||||||
|
component.templateName = "sample name";
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
expect(mockedToasterService.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,75 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { TemplateMocksService } from '../../../../../services/template-mocks.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template';
|
||||||
|
import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ethernet-hubs-add-template',
|
||||||
|
templateUrl: './ethernet-hubs-add-template.component.html',
|
||||||
|
styleUrls: ['./ethernet-hubs-add-template.component.scss', '../../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class EthernetHubsAddTemplateComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
numberOfPorts: number;
|
||||||
|
templateName: string = '';
|
||||||
|
formGroup: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private builtInTemplatesService: BuiltInTemplatesService,
|
||||||
|
private router: Router,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private templateMocksService: TemplateMocksService,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.formGroup = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
numberOfPorts: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'ethernet-hubs']);
|
||||||
|
}
|
||||||
|
|
||||||
|
addTemplate() {
|
||||||
|
if (!this.formGroup.invalid) {
|
||||||
|
let ethernetHubTemplate: EthernetHubTemplate;
|
||||||
|
|
||||||
|
this.templateMocksService.getEthernetHubTemplate().subscribe((template: EthernetHubTemplate) => {
|
||||||
|
ethernetHubTemplate = template;
|
||||||
|
});
|
||||||
|
|
||||||
|
ethernetHubTemplate.template_id = uuid();
|
||||||
|
ethernetHubTemplate.name = this.templateName;
|
||||||
|
|
||||||
|
for(let i=0; i<this.numberOfPorts; i++){
|
||||||
|
ethernetHubTemplate.ports_mapping.push({
|
||||||
|
name: `Ethernet${i}`,
|
||||||
|
port_number: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.builtInTemplatesService.addTemplate(this.server, ethernetHubTemplate).subscribe(() => {
|
||||||
|
this.goBack();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
<div class="content" [ngClass]="{ shadowed: isSymbolSelectionOpened}">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Ethernet hub settings</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content" *ngIf="ethernetHubTemplate">
|
||||||
|
<mat-card>
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="ethernetHubTemplate.name"
|
||||||
|
formControlName="templateName"
|
||||||
|
placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="ethernetHubTemplate.default_name_format"
|
||||||
|
formControlName="defaultName"
|
||||||
|
placeholder="Default name format">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="ethernetHubTemplate.symbol"
|
||||||
|
formControlName="symbol"
|
||||||
|
placeholder="Symbol">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Category"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="ethernetHubTemplate.category">
|
||||||
|
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
||||||
|
{{category[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="numberOfPorts"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
placeholder="Number of ports">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button><br/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && ethernetHubTemplate" [server]="server" [symbol]="ethernetHubTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
@ -0,0 +1,120 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatTableModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
|
import { MockedToasterService } from '../../../../../services/toaster.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../../preferences.component.spec';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template';
|
||||||
|
import { EthernetHubsTemplateDetailsComponent } from './ethernet-hubs-template-details.component';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
|
||||||
|
export class MockedBuiltInTemplatesService {
|
||||||
|
public getTemplate(server: Server, template_id: string) {
|
||||||
|
return of({ports_mapping: []} as EthernetHubTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public saveTemplate(server: Server, cloudTemplate: EthernetHubTemplate) {
|
||||||
|
return of(cloudTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('EthernetHubsTemplateDetailsComponent', () => {
|
||||||
|
let component: EthernetHubsTemplateDetailsComponent;
|
||||||
|
let fixture: ComponentFixture<EthernetHubsTemplateDetailsComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, MatTableModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: BuiltInTemplatesConfigurationService, useClass: BuiltInTemplatesConfigurationService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
EthernetHubsTemplateDetailsComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(EthernetHubsTemplateDetailsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call save template', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetHubTemplate));
|
||||||
|
component.numberOfPorts = 2;
|
||||||
|
component.inputForm.controls['templateName'].setValue('template name');
|
||||||
|
component.inputForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.inputForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.ethernetHubTemplate = {ports_mapping: []} as EthernetHubTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.saveTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call save template when template name is empty', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetHubTemplate));
|
||||||
|
component.numberOfPorts = 2;
|
||||||
|
component.inputForm.controls['templateName'].setValue('');
|
||||||
|
component.inputForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.inputForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.ethernetHubTemplate = {ports_mapping: []} as EthernetHubTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call save template when default name is empty', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetHubTemplate));
|
||||||
|
component.numberOfPorts = 2;
|
||||||
|
component.inputForm.controls['templateName'].setValue('template name');
|
||||||
|
component.inputForm.controls['defaultName'].setValue('');
|
||||||
|
component.inputForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.ethernetHubTemplate = {ports_mapping: []} as EthernetHubTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call save template when symbol path is empty', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetHubTemplate));
|
||||||
|
component.numberOfPorts = 2;
|
||||||
|
component.inputForm.controls['templateName'].setValue('template name');
|
||||||
|
component.inputForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.inputForm.controls['symbol'].setValue('');
|
||||||
|
component.ethernetHubTemplate = {ports_mapping: []} as EthernetHubTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,86 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ethernet-hubs-template-details',
|
||||||
|
templateUrl: './ethernet-hubs-template-details.component.html',
|
||||||
|
styleUrls: ['./ethernet-hubs-template-details.component.scss', '../../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class EthernetHubsTemplateDetailsComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
ethernetHubTemplate: EthernetHubTemplate;
|
||||||
|
numberOfPorts: number;
|
||||||
|
inputForm: FormGroup;
|
||||||
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
|
categories = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private builtInTemplatesService: BuiltInTemplatesService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService,
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
defaultName: new FormControl('', Validators.required),
|
||||||
|
symbol: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
const template_id = this.route.snapshot.paramMap.get("template_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.categories = this.builtInTemplatesConfigurationService.getCategoriesForEthernetHubs();
|
||||||
|
this.builtInTemplatesService.getTemplate(this.server, template_id).subscribe((ethernetHubTemplate: EthernetHubTemplate) => {
|
||||||
|
this.ethernetHubTemplate = ethernetHubTemplate;
|
||||||
|
this.numberOfPorts = this.ethernetHubTemplate.ports_mapping.length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'ethernet-hubs']);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSave() {
|
||||||
|
if (this.inputForm.invalid || ! this.numberOfPorts) {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
} else {
|
||||||
|
this.ethernetHubTemplate.ports_mapping = [];
|
||||||
|
for(let i=0; i<this.numberOfPorts; i++){
|
||||||
|
this.ethernetHubTemplate.ports_mapping.push({
|
||||||
|
name: `Ethernet${i}`,
|
||||||
|
port_number: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.builtInTemplatesService.saveTemplate(this.server, this.ethernetHubTemplate).subscribe((ethernetHubTemplate: EthernetHubTemplate) => {
|
||||||
|
this.toasterService.success("Changes saved");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chooseSymbol() {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
this.ethernetHubTemplate.symbol = chosenSymbol;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Ethernet hubs templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences/builtin" mat-button>Back</button>
|
||||||
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/builtin/ethernet-hubs/addtemplate" mat-raised-button color="primary">Add Ethernet hub template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-empty-templates-list *ngIf="!ethernetHubsTemplates.length"></app-empty-templates-list>
|
||||||
|
<div class="default-content" *ngIf="ethernetHubsTemplates.length">
|
||||||
|
<div class="listcontainer mat-elevation-z8">
|
||||||
|
<mat-nav-list *ngIf="server">
|
||||||
|
<div class="list-item" *ngFor='let template of ethernetHubsTemplates'>
|
||||||
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
|
<button mat-button class="menu-button" [matMenuTriggerFor]="menu">
|
||||||
|
<mat-icon>more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menu="matMenu">
|
||||||
|
<button mat-menu-item (click)="deleteTemplate(template)">
|
||||||
|
<mat-icon>delete</mat-icon><span>Delete</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
||||||
|
</mat-nav-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-delete-template
|
||||||
|
#deleteComponent
|
||||||
|
[server]="server"
|
||||||
|
(deleteEvent)="onDeleteEvent()">
|
||||||
|
</app-delete-template>
|
@ -0,0 +1,57 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../../preferences.component.spec';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template';
|
||||||
|
import { EthernetHubsTemplatesComponent } from './ethernet-hubs-templates.component';
|
||||||
|
|
||||||
|
export class MockedBuiltInTemplatesService {
|
||||||
|
public getTemplates(server: Server) {
|
||||||
|
return of([{} as EthernetHubTemplate]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('EthernetHubsTemplatesComponent', () => {
|
||||||
|
let component: EthernetHubsTemplatesComponent;
|
||||||
|
let fixture: ComponentFixture<EthernetHubsTemplatesComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
EthernetHubsTemplatesComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(EthernetHubsTemplatesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,47 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { DeleteTemplateComponent } from '../../../common/delete-template-component/delete-template.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ethernet-hubs-templates',
|
||||||
|
templateUrl: './ethernet-hubs-templates.component.html',
|
||||||
|
styleUrls: ['./ethernet-hubs-templates.component.scss', '../../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class EthernetHubsTemplatesComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
ethernetHubsTemplates: EthernetHubTemplate[] = [];
|
||||||
|
@ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private builtInTemplatesService: BuiltInTemplatesService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
this.getTemplates();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplates() {
|
||||||
|
this.builtInTemplatesService.getTemplates(this.server).subscribe((ethernetHubsTemplates: EthernetHubTemplate[]) => {
|
||||||
|
this.ethernetHubsTemplates = ethernetHubsTemplates.filter((elem) => elem.template_type === "ethernet_hub" && !elem.builtin);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTemplate(template: EthernetHubTemplate) {
|
||||||
|
this.deleteComponent.deleteItem(template.name, template.template_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteEvent() {
|
||||||
|
this.getTemplates();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">New Ethernet switch template</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="formGroup">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input formControlName="templateName" matInput type="text" [(ngModel)]="templateName" placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,101 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
|
import { MockedToasterService } from '../../../../../services/toaster.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../../preferences.component.spec';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { TemplateMocksService } from '../../../../../services/template-mocks.service';
|
||||||
|
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
||||||
|
import { EthernetSwitchesAddTemplateComponent } from './ethernet-switches-add-template.component';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
export class MockedBuiltInTemplatesService {
|
||||||
|
public addTemplate(server: Server, ethernetHubTemplate: EthernetSwitchTemplate) {
|
||||||
|
return of(ethernetHubTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('EthernetSwitchesAddTemplateComponent', () => {
|
||||||
|
let component: EthernetSwitchesAddTemplateComponent;
|
||||||
|
let fixture: ComponentFixture<EthernetSwitchesAddTemplateComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
EthernetSwitchesAddTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(EthernetSwitchesAddTemplateComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call add template', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
||||||
|
component.templateName = "sample name";
|
||||||
|
component.numberOfPorts = 2;
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
component.formGroup.controls['templateName'].setValue('template name');
|
||||||
|
component.formGroup.controls['numberOfPorts'].setValue('1');
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.addTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when template name is empty', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
||||||
|
spyOn(mockedToasterService, 'error');
|
||||||
|
component.formGroup.controls['numberOfPorts'].setValue('1');
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
expect(mockedToasterService.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when number of ports is missing', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
||||||
|
spyOn(mockedToasterService, 'error');
|
||||||
|
component.formGroup.controls['templateName'].setValue('template name');
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
expect(mockedToasterService.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,78 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { TemplateMocksService } from '../../../../../services/template-mocks.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ethernet-switches-add-template',
|
||||||
|
templateUrl: './ethernet-switches-add-template.component.html',
|
||||||
|
styleUrls: ['./ethernet-switches-add-template.component.scss', '../../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class EthernetSwitchesAddTemplateComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
numberOfPorts: number;
|
||||||
|
templateName: string = '';
|
||||||
|
formGroup: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private builtInTemplatesService: BuiltInTemplatesService,
|
||||||
|
private router: Router,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private templateMocksService: TemplateMocksService,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.formGroup = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
numberOfPorts: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'ethernet-switches']);
|
||||||
|
}
|
||||||
|
|
||||||
|
addTemplate() {
|
||||||
|
if (!this.formGroup.invalid) {
|
||||||
|
let ethernetSwitchTemplate: EthernetSwitchTemplate;
|
||||||
|
|
||||||
|
this.templateMocksService.getEthernetSwitchTemplate().subscribe((template: EthernetSwitchTemplate) => {
|
||||||
|
ethernetSwitchTemplate = template;
|
||||||
|
});
|
||||||
|
|
||||||
|
ethernetSwitchTemplate.template_id = uuid();
|
||||||
|
ethernetSwitchTemplate.name = this.templateName;
|
||||||
|
|
||||||
|
for(let i=0; i<this.numberOfPorts; i++){
|
||||||
|
ethernetSwitchTemplate.ports_mapping.push({
|
||||||
|
ethertype: '',
|
||||||
|
name: `Ethernet${i}`,
|
||||||
|
port_number: i,
|
||||||
|
type: 'access',
|
||||||
|
vlan: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.builtInTemplatesService.addTemplate(this.server, ethernetSwitchTemplate).subscribe((ethernetSwitchTemplate) => {
|
||||||
|
this.goBack();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
<div class="content" [ngClass]="{ shadowed: isSymbolSelectionOpened}">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Ethernet switch configuration</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content" *ngIf="ethernetSwitchTemplate">
|
||||||
|
<mat-accordion>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
General settings
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="ethernetSwitchTemplate.name"
|
||||||
|
formControlName="templateName"
|
||||||
|
placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="ethernetSwitchTemplate.default_name_format"
|
||||||
|
formControlName="defaultName"
|
||||||
|
placeholder="Default name format">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="ethernetSwitchTemplate.symbol"
|
||||||
|
formControlName="symbol"
|
||||||
|
placeholder="Symbol">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Category"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="ethernetSwitchTemplate.category">
|
||||||
|
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
||||||
|
{{category[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Console type"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="ethernetSwitchTemplate.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel *ngIf="newPort">
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
Port settings
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<table class="table" mat-table [dataSource]="dataSource">
|
||||||
|
<ng-container matColumnDef="port_number">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Port number </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.port_number}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="vlan">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> VLAN </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.vlan}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="type">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Type </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.type}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="ethertype">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> EtherType </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.ethertype}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="newPort.port_number"
|
||||||
|
placeholder="Port">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="newPort.vlan"
|
||||||
|
placeholder="VLAN">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Type"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="newPort.type">
|
||||||
|
<mat-option *ngFor="let type of portTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="EtherType"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="newPort.ethertype">
|
||||||
|
<mat-option *ngFor="let type of etherTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="form-field" (click)="onAdd()">Add</button>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && ethernetSwitchTemplate" [server]="server" [symbol]="ethernetSwitchTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
@ -0,0 +1,116 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatTableModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
|
import { MockedToasterService } from '../../../../../services/toaster.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../../preferences.component.spec';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
||||||
|
import { EthernetSwitchesTemplateDetailsComponent } from './ethernet-switches-template-details.component';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
|
||||||
|
export class MockedBuiltInTemplatesService {
|
||||||
|
public getTemplate(server: Server, template_id: string) {
|
||||||
|
return of({ports_mapping: []} as EthernetSwitchTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public saveTemplate(server: Server, cloudTemplate: EthernetSwitchTemplate) {
|
||||||
|
return of(cloudTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('EthernetSwitchesTemplateDetailsComponent', () => {
|
||||||
|
let component: EthernetSwitchesTemplateDetailsComponent;
|
||||||
|
let fixture: ComponentFixture<EthernetSwitchesTemplateDetailsComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, MatTableModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: BuiltInTemplatesConfigurationService, useClass: BuiltInTemplatesConfigurationService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
EthernetSwitchesTemplateDetailsComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(EthernetSwitchesTemplateDetailsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call save template', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
||||||
|
component.inputForm.controls['templateName'].setValue('template name');
|
||||||
|
component.inputForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.inputForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.ethernetSwitchTemplate = {ports_mapping: []} as EthernetSwitchTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.saveTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call save template when template name is empty', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
||||||
|
component.inputForm.controls['templateName'].setValue('');
|
||||||
|
component.inputForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.inputForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.ethernetSwitchTemplate = {ports_mapping: []} as EthernetSwitchTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call save template when default name is empty', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
||||||
|
component.inputForm.controls['templateName'].setValue('template name');
|
||||||
|
component.inputForm.controls['defaultName'].setValue('');
|
||||||
|
component.inputForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.ethernetSwitchTemplate = {ports_mapping: []} as EthernetSwitchTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call save template when symbol path is empty', () => {
|
||||||
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
||||||
|
component.inputForm.controls['templateName'].setValue('template name');
|
||||||
|
component.inputForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.inputForm.controls['symbol'].setValue('');
|
||||||
|
component.ethernetSwitchTemplate = {ports_mapping: []} as EthernetSwitchTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedBuiltInTemplatesService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,109 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
||||||
|
import { PortsMappingEntity } from '../../../../../models/ethernetHub/ports-mapping-enity';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ethernet-switches-template-details',
|
||||||
|
templateUrl: './ethernet-switches-template-details.component.html',
|
||||||
|
styleUrls: ['./ethernet-switches-template-details.component.scss', '../../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class EthernetSwitchesTemplateDetailsComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
ethernetSwitchTemplate: EthernetSwitchTemplate;
|
||||||
|
inputForm: FormGroup;
|
||||||
|
ethernetPorts: PortsMappingEntity[] = [];
|
||||||
|
dataSource: PortsMappingEntity[] = [];
|
||||||
|
newPort: PortsMappingEntity;
|
||||||
|
|
||||||
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
|
categories = [];
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
portTypes: string[] = [];
|
||||||
|
etherTypes: string[] = [];
|
||||||
|
displayedColumns: string[] = ['port_number', 'vlan', 'type', 'ethertype'];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private builtInTemplatesService: BuiltInTemplatesService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService,
|
||||||
|
private router: Router
|
||||||
|
){
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
defaultName: new FormControl('', Validators.required),
|
||||||
|
symbol: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.newPort = {
|
||||||
|
name: '',
|
||||||
|
port_number: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
const template_id = this.route.snapshot.paramMap.get("template_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.getConfiguration();
|
||||||
|
this.builtInTemplatesService.getTemplate(this.server, template_id).subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => {
|
||||||
|
this.ethernetSwitchTemplate = ethernetSwitchTemplate;
|
||||||
|
this.ethernetPorts = this.ethernetSwitchTemplate.ports_mapping;
|
||||||
|
this.dataSource = this.ethernetSwitchTemplate.ports_mapping;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.categories = this.builtInTemplatesConfigurationService.getCategoriesForEthernetSwitches();
|
||||||
|
this.consoleTypes = this.builtInTemplatesConfigurationService.getConsoleTypesForEthernetSwitches();
|
||||||
|
this.portTypes = this.builtInTemplatesConfigurationService.getPortTypesForEthernetSwitches();
|
||||||
|
this.etherTypes = this.builtInTemplatesConfigurationService.getEtherTypesForEthernetSwitches();
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdd() {
|
||||||
|
this.ethernetPorts.push(this.newPort);
|
||||||
|
this.dataSource = [...this.ethernetPorts];
|
||||||
|
|
||||||
|
this.newPort = {
|
||||||
|
name: '',
|
||||||
|
port_number: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'ethernet-switches']);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSave() {
|
||||||
|
if (this.inputForm.invalid) {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
} else {
|
||||||
|
this.builtInTemplatesService.saveTemplate(this.server, this.ethernetSwitchTemplate).subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => {
|
||||||
|
this.toasterService.success("Changes saved");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chooseSymbol() {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
this.ethernetSwitchTemplate.symbol = chosenSymbol;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Ethernet switches templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences/builtin" mat-button>Back</button>
|
||||||
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/builtin/ethernet-switches/addtemplate" mat-raised-button color="primary">Add Ethernet switch template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-empty-templates-list *ngIf="!ethernetSwitchesTemplates.length"></app-empty-templates-list>
|
||||||
|
<div class="default-content" *ngIf="ethernetSwitchesTemplates.length">
|
||||||
|
<div class="listcontainer mat-elevation-z8">
|
||||||
|
<mat-nav-list *ngIf="server">
|
||||||
|
<div class="list-item" *ngFor='let template of ethernetSwitchesTemplates'>
|
||||||
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
|
<button mat-button class="menu-button" [matMenuTriggerFor]="menu">
|
||||||
|
<mat-icon>more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menu="matMenu">
|
||||||
|
<button mat-menu-item (click)="deleteTemplate(template)">
|
||||||
|
<mat-icon>delete</mat-icon><span>Delete</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
||||||
|
</mat-nav-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-delete-template
|
||||||
|
#deleteComponent
|
||||||
|
[server]="server"
|
||||||
|
(deleteEvent)="onDeleteEvent()">
|
||||||
|
</app-delete-template>
|
@ -0,0 +1,57 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../../preferences.component.spec';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { EthernetSwitchesTemplatesComponent } from './ethernet-switches-templates.component';
|
||||||
|
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
||||||
|
|
||||||
|
export class MockedBuiltInTemplatesService {
|
||||||
|
public getTemplates(server: Server) {
|
||||||
|
return of([{} as EthernetSwitchTemplate]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('EthernetSwitchesTemplatesComponent', () => {
|
||||||
|
let component: EthernetSwitchesTemplatesComponent;
|
||||||
|
let fixture: ComponentFixture<EthernetSwitchesTemplatesComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
EthernetSwitchesTemplatesComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(EthernetSwitchesTemplatesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,47 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
|
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
||||||
|
import { DeleteTemplateComponent } from '../../../common/delete-template-component/delete-template.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ethernet-switches-templates',
|
||||||
|
templateUrl: './ethernet-switches-templates.component.html',
|
||||||
|
styleUrls: ['./ethernet-switches-templates.component.scss', '../../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class EthernetSwitchesTemplatesComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
ethernetSwitchesTemplates: EthernetSwitchTemplate[] = [];
|
||||||
|
@ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private builtInTemplatesService: BuiltInTemplatesService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
this.getTemplates();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplates() {
|
||||||
|
this.builtInTemplatesService.getTemplates(this.server).subscribe((ethernetSwitchesTemplates: EthernetSwitchTemplate[]) => {
|
||||||
|
this.ethernetSwitchesTemplates = ethernetSwitchesTemplates.filter((elem) => elem.template_type === "ethernet_switch" && !elem.builtin);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTemplate(template: EthernetSwitchTemplate) {
|
||||||
|
this.deleteComponent.deleteItem(template.name, template.template_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteEvent() {
|
||||||
|
this.getTemplates();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
<div class="dialogcontainer">
|
||||||
|
<h1 mat-dialog-title>Delete template</h1>
|
||||||
|
<div mat-dialog-content>Are you sure you want to delete template {{templateName}}?</div>
|
||||||
|
|
||||||
|
<div class="spacer"></div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button class="cancelButton" (click)="onNoClick()" color="accent">
|
||||||
|
No
|
||||||
|
</button>
|
||||||
|
<button mat-button class="confirmButton" (click)="onYesClick()" tabindex="2" mat-raised-button color="primary">
|
||||||
|
Yes
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,9 @@
|
|||||||
|
.dialogcontainer {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spacer {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
import { Component, OnInit, Inject } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-delete-confirmation-dialog',
|
||||||
|
templateUrl: './delete-confirmation-dialog.component.html',
|
||||||
|
styleUrls: ['./delete-confirmation-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class DeleteConfirmationDialogComponent implements OnInit {
|
||||||
|
templateName: string = '';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<DeleteConfirmationDialogComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
|
) {
|
||||||
|
this.templateName = data['templateName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {}
|
||||||
|
|
||||||
|
onNoClick(): void {
|
||||||
|
this.dialogRef.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
onYesClick(): void {
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
import { Component, Input, Output, EventEmitter } from "@angular/core";
|
||||||
|
import { TemplateService } from '../../../../services/template.service';
|
||||||
|
import { MatDialog } from '@angular/material';
|
||||||
|
import { DeleteConfirmationDialogComponent } from '../delete-confirmation-dialog/delete-confirmation-dialog.component';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-delete-template',
|
||||||
|
templateUrl: './delete-template.component.html',
|
||||||
|
styleUrls: ['./delete-template.component.scss']
|
||||||
|
})
|
||||||
|
export class DeleteTemplateComponent {
|
||||||
|
@Input() server: Server;
|
||||||
|
@Output() deleteEvent = new EventEmitter<string>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private templateService: TemplateService,
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private toasterService: ToasterService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
deleteItem(templateName, templateId) {
|
||||||
|
const dialogRef = this.dialog.open(DeleteConfirmationDialogComponent, {
|
||||||
|
width: '300px',
|
||||||
|
height: '250px',
|
||||||
|
data: {
|
||||||
|
templateName: templateName
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((answer: boolean) => {
|
||||||
|
if (answer) {
|
||||||
|
this.templateService.deleteTemplate(this.server, templateId).subscribe((answer: boolean) => {
|
||||||
|
if(answer) {
|
||||||
|
this.deleteEvent.emit(templateId);
|
||||||
|
this.toasterService.success(`Template ${templateName} deleted.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<h6 class="header">
|
||||||
|
{{emptyTemplatesListMessage}}
|
||||||
|
</h6>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
@ -0,0 +1,4 @@
|
|||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
color: darkgray;
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
import { Component, Input } from "@angular/core";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-empty-templates-list',
|
||||||
|
templateUrl: './empty-templates-list.component.html',
|
||||||
|
styleUrls: ['./empty-templates-list.component.scss']
|
||||||
|
})
|
||||||
|
export class EmptyTemplatesListComponent {
|
||||||
|
@Input() textMessage: string;
|
||||||
|
emptyTemplatesListMessage: string = 'Empty templates list';
|
||||||
|
|
||||||
|
constructor(){
|
||||||
|
if (this.textMessage) {
|
||||||
|
this.emptyTemplatesListMessage = this.textMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
<div class="content" class="configurator">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Symbol selection</h1>
|
||||||
|
<button class="top-button" class="cancel-button" (click)="cancelChooseSymbol()" mat-button>Cancel</button>
|
||||||
|
<button class="top-button" (click)="chooseSymbol()" mat-raised-button color="primary">Choose symbol</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<app-symbols [server]="server" [symbol]="symbol" (symbolChanged)="symbolChanged($event)"></app-symbols>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,28 @@
|
|||||||
|
import { Component, Input, Output, EventEmitter } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-symbols-menu',
|
||||||
|
templateUrl: './symbols-menu.component.html',
|
||||||
|
styleUrls: ['./symbols-menu.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class SymbolsMenuComponent {
|
||||||
|
@Input() server: Server;
|
||||||
|
@Input() symbol: string;
|
||||||
|
@Output() symbolChangedEmitter = new EventEmitter<string>();
|
||||||
|
|
||||||
|
chosenSymbol: string = '';
|
||||||
|
|
||||||
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.chosenSymbol = chosenSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
chooseSymbol() {
|
||||||
|
this.symbolChangedEmitter.emit(this.chosenSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelChooseSymbol() {
|
||||||
|
this.symbolChangedEmitter.emit(this.symbol);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
<mat-card>
|
||||||
|
<input matInput type="text" [(ngModel)]="searchText" placeholder="Search by filename"><br/><br/>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="buttonWrapper" *ngFor="let symbol of symbols | filenamefilter: searchText">
|
||||||
|
<button [ngClass]="{ buttonSelected: isSelected === symbol.symbol_id }" class="button" (click)="setSelected(symbol.symbol_id)">
|
||||||
|
<img [ngClass]="{ imageSelected: isSelected === symbol.symbol_id }" class="image" src="http://127.0.0.1:3080/v2/symbols/{{symbol.symbol_id}}/raw"/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
@ -0,0 +1,38 @@
|
|||||||
|
.buttonWrapper {
|
||||||
|
width: 85px;
|
||||||
|
height: 85px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
background: border-box;
|
||||||
|
border-width: 0px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonSelected {
|
||||||
|
border-width: 3px;
|
||||||
|
border-color: #0097a7;
|
||||||
|
width: 77px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
width: 65px;
|
||||||
|
height: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imageSelected {
|
||||||
|
margin-left: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto;
|
||||||
|
grid-template-columns: repeat(7, 1fr);
|
||||||
|
grid-row-gap: 3em;
|
||||||
|
grid-column-gap: 1em;
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatCheckboxModule, MatIconModule, MatToolbarModule, MatMenuModule } from '@angular/material';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { SymbolsComponent } from './symbols.component';
|
||||||
|
import { SymbolService } from '../../../../services/symbol.service';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { SearchFilter } from '../../../../filters/searchFilter.pipe';
|
||||||
|
|
||||||
|
export class MockedSymbolService {
|
||||||
|
public list() {
|
||||||
|
return of([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Symbols component', () => {
|
||||||
|
let component: SymbolsComponent;
|
||||||
|
let fixture: ComponentFixture<SymbolsComponent>;
|
||||||
|
let mockedSymbolsService = new MockedSymbolService;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [HttpClientModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: SymbolService, useValue: mockedSymbolsService
|
||||||
|
}
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
SymbolsComponent,
|
||||||
|
SearchFilter
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(SymbolsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit event when symbol selected', () => {
|
||||||
|
spyOn(component.symbolChanged, 'emit');
|
||||||
|
|
||||||
|
component.setSelected('id');
|
||||||
|
|
||||||
|
expect(component.symbolChanged.emit).toHaveBeenCalled();
|
||||||
|
expect(component.isSelected).toBe('id');
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,37 @@
|
|||||||
|
import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core";
|
||||||
|
import { SymbolService } from '../../../../services/symbol.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { Symbol } from '../../../../models/symbol';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-symbols',
|
||||||
|
templateUrl: './symbols.component.html',
|
||||||
|
styleUrls: ['./symbols.component.scss']
|
||||||
|
})
|
||||||
|
export class SymbolsComponent implements OnInit {
|
||||||
|
@Input() server: Server;
|
||||||
|
@Input() symbol: string;
|
||||||
|
@Output() symbolChanged = new EventEmitter<string>();
|
||||||
|
|
||||||
|
symbols: Symbol[] = [];
|
||||||
|
isSelected: string = '';
|
||||||
|
searchText: string = '';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private symbolService: SymbolService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.isSelected = this.symbol;
|
||||||
|
|
||||||
|
this.symbolService.list(this.server).subscribe((symbols: Symbol[]) => {
|
||||||
|
this.symbols = symbols;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelected(symbol_id: string) {
|
||||||
|
this.isSelected = symbol_id;
|
||||||
|
this.symbolChanged.emit(this.isSelected);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">New Docker container template</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<div class="container mat-elevation-z8">
|
||||||
|
<mat-vertical-stepper [linear]="true">
|
||||||
|
<mat-step label="Server type">
|
||||||
|
<mat-radio-group class="radio-group">
|
||||||
|
<mat-radio-button class="radio-button" value="1" (click)="setServerType('remote computer')">Run this Docker container on a remote computer</mat-radio-button>
|
||||||
|
<mat-radio-button class="radio-button" value="2" (click)="setServerType('gns3 vm')" checked>Run this Docker container on the GNS3 VM</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Docker Virtual Machine">
|
||||||
|
<form [formGroup]="virtualMachineForm">
|
||||||
|
<mat-radio-group class="radio-group">
|
||||||
|
<mat-radio-button class="radio-button" value="1" (click)="setDiskImage('existingImage')" checked>Existing image</mat-radio-button>
|
||||||
|
<mat-radio-button class="radio-button" value="2" (click)="setDiskImage('newImage')">New image</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
<mat-select
|
||||||
|
*ngIf="!newImageSelected"
|
||||||
|
placeholder="Image list"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="selectedImage">
|
||||||
|
<mat-option *ngFor="let image of dockerImages" [value]="image">
|
||||||
|
{{image.filename}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<div *ngIf="newImageSelected">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="dockerTemplate.image"
|
||||||
|
formControlName="filename"
|
||||||
|
placeholder="Image name"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Container name">
|
||||||
|
<form [formGroup]="containerNameForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="dockerTemplate.name"
|
||||||
|
formControlName="templateName"
|
||||||
|
placeholder="Container name"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Network adapters">
|
||||||
|
<form [formGroup]="networkAdaptersForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="number"
|
||||||
|
[(ngModel)]="dockerTemplate.adapters"
|
||||||
|
formControlName="adapters"
|
||||||
|
placeholder="Adapters"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Start command">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="dockerTemplate.start_command"
|
||||||
|
placeholder="Start command"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Console type">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Console type"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="dockerTemplate.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Environment">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="dockerTemplate.environment"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-step>
|
||||||
|
</mat-vertical-stepper>
|
||||||
|
</div>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,111 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatInputModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatSelectModule, MatFormFieldModule, MatAutocompleteModule, MatTableModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { MockedServerService } from '../../../../services/server.service.spec';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
||||||
|
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
|
import { AddDockerTemplateComponent } from './add-docker-template.component';
|
||||||
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
|
import { DockerConfigurationService } from '../../../../services/docker-configuration.service';
|
||||||
|
|
||||||
|
export class MockedDockerService {
|
||||||
|
public addTemplate(server: Server, dockerTemplate: DockerTemplate) {
|
||||||
|
return of(dockerTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('AddDockerTemplateComponent', () => {
|
||||||
|
let component: AddDockerTemplateComponent;
|
||||||
|
let fixture: ComponentFixture<AddDockerTemplateComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedDockerService = new MockedDockerService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ FormsModule, MatTableModule, MatAutocompleteModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule, MatSelectModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: DockerService, useValue: mockedDockerService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
||||||
|
{ provide: DockerConfigurationService, useClass: DockerConfigurationService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AddDockerTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AddDockerTemplateComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call add template', () => {
|
||||||
|
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
||||||
|
component.virtualMachineForm.controls['filename'].setValue('sample name');
|
||||||
|
component.containerNameForm.controls['templateName'].setValue('template name');
|
||||||
|
component.networkAdaptersForm.controls['adapters'].setValue(1);
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedDockerService.addTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when file name is missing', () => {
|
||||||
|
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
||||||
|
component.containerNameForm.controls['templateName'].setValue('template name');
|
||||||
|
component.networkAdaptersForm.controls['adapters'].setValue(1);
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedDockerService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when template name is missing', () => {
|
||||||
|
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
||||||
|
component.virtualMachineForm.controls['filename'].setValue('sample name');
|
||||||
|
component.networkAdaptersForm.controls['adapters'].setValue(1);
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedDockerService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when adapters field is empty', () => {
|
||||||
|
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
||||||
|
component.virtualMachineForm.controls['filename'].setValue('sample name');
|
||||||
|
component.containerNameForm.controls['templateName'].setValue('template name');
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedDockerService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,98 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
||||||
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
|
import { DockerConfigurationService } from '../../../../services/docker-configuration.service';
|
||||||
|
import { DockerImage } from '../../../../models/docker/docker-image';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-docker-template',
|
||||||
|
templateUrl: './add-docker-template.component.html',
|
||||||
|
styleUrls: ['./add-docker-template.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class AddDockerTemplateComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
dockerTemplate: DockerTemplate;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
isGns3VmChosen: boolean = false;
|
||||||
|
isRemoteComputerChosen: boolean = false;
|
||||||
|
dockerImages: DockerImage[] = [];
|
||||||
|
newImageSelected: boolean = false;
|
||||||
|
|
||||||
|
virtualMachineForm: FormGroup;
|
||||||
|
containerNameForm: FormGroup;
|
||||||
|
networkAdaptersForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private dockerService: DockerService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private router: Router,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private templateMocksService: TemplateMocksService,
|
||||||
|
private configurationService: DockerConfigurationService
|
||||||
|
) {
|
||||||
|
this.dockerTemplate = new DockerTemplate();
|
||||||
|
|
||||||
|
this.virtualMachineForm = this.formBuilder.group({
|
||||||
|
filename: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.containerNameForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.networkAdaptersForm = this.formBuilder.group({
|
||||||
|
adapters: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.consoleTypes = this.configurationService.getConsoleTypes();
|
||||||
|
|
||||||
|
this.templateMocksService.getDockerTemplate().subscribe((dockerTemplate: DockerTemplate) => {
|
||||||
|
this.dockerTemplate = dockerTemplate;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setServerType(serverType: string) {
|
||||||
|
if (serverType === 'gns3 vm') {
|
||||||
|
this.isGns3VmChosen = true;
|
||||||
|
} else {
|
||||||
|
this.isRemoteComputerChosen = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setDiskImage(value: string) {
|
||||||
|
this.newImageSelected = value === "newImage";
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
|
addTemplate() {
|
||||||
|
if (!this.virtualMachineForm.invalid && !this.containerNameForm.invalid && !this.networkAdaptersForm.invalid) {
|
||||||
|
this.dockerTemplate.template_id = uuid();
|
||||||
|
|
||||||
|
this.dockerService.addTemplate(this.server, this.dockerTemplate).subscribe((template: DockerTemplate) => {
|
||||||
|
this.goBack();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Copy Docker container template</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<div class="container mat-elevation-z8">
|
||||||
|
<form [formGroup]="templateNameForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="templateName"
|
||||||
|
placeholder="Name"
|
||||||
|
formControlName="templateName"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Copy template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,66 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-copy-docker-template',
|
||||||
|
templateUrl: './copy-docker-template.component.html',
|
||||||
|
styleUrls: ['./copy-docker-template.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class CopyDockerTemplateComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
templateName: string = '';
|
||||||
|
dockerTemplate: DockerTemplate;
|
||||||
|
templateNameForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private dockerService: DockerService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private router: Router,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.templateNameForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
const template_id = this.route.snapshot.paramMap.get("template_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.dockerService.getTemplate(this.server, template_id).subscribe((dockerTemplate: DockerTemplate) => {
|
||||||
|
this.dockerTemplate = dockerTemplate;
|
||||||
|
this.templateName = `Copy of ${this.dockerTemplate.name}`;
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
|
addTemplate() {
|
||||||
|
if (!this.templateNameForm.invalid) {
|
||||||
|
this.dockerTemplate.template_id = uuid();
|
||||||
|
this.dockerTemplate.name = this.templateName;
|
||||||
|
|
||||||
|
this.dockerService.addTemplate(this.server, this.dockerTemplate).subscribe((template: DockerTemplate) => {
|
||||||
|
this.goBack();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
<div class="content" [ngClass]="{ shadowed: isSymbolSelectionOpened}">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Docker image configuration</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content" *ngIf="dockerTemplate">
|
||||||
|
<mat-accordion>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
General settings
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input formControlName="templateName" matInput type="text" [(ngModel)]="dockerTemplate.name" placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input formControlName="defaultName" matInput type="text" [(ngModel)]="dockerTemplate.default_name_format" placeholder="Default name format">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Category" [(ngModel)]="dockerTemplate.category">
|
||||||
|
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
||||||
|
{{category[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input formControlName="symbol" matInput type="text" [(ngModel)]="dockerTemplate.symbol" placeholder="Symbol">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="dockerTemplate.start_command" placeholder="Start command">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input formControlName="adapter" matInput type="number" [(ngModel)]="dockerTemplate.adapters" placeholder="Adapters">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Console type" [(ngModel)]="dockerTemplate.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="dockerTemplate.console_auto_start">
|
||||||
|
Auto start console
|
||||||
|
</mat-checkbox>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="VNC console resolution" [(ngModel)]="dockerTemplate.console_resolution">
|
||||||
|
<mat-option *ngFor="let resolution of consoleResolutions" [value]="resolution">
|
||||||
|
{{resolution}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input [ngModelOptions]="{standalone: true}" matInput type="number" [(ngModel)]="dockerTemplate.console_http_port" placeholder="HTTP port in the container">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input [ngModelOptions]="{standalone: true}" matInput type="text" [(ngModel)]="dockerTemplate.console_http_path" placeholder="HTTP path">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<h6>Environment</h6>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="dockerTemplate.environment"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
Advanced
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<h6>Extra hosts</h6>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="dockerTemplate.extra_hosts"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
Usage
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="dockerTemplate.usage"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && dockerTemplate" [server]="server" [symbol]="dockerTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
@ -0,0 +1,80 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { MockedServerService } from '../../../../services/server.service.spec';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
|
import { DockerTemplateDetailsComponent } from './docker-template-details.component';
|
||||||
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
|
import { DockerConfigurationService } from '../../../../services/docker-configuration.service';
|
||||||
|
|
||||||
|
export class MockedDockerService {
|
||||||
|
public getTemplate(server: Server, template_id: string) {
|
||||||
|
return of({} as DockerTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public saveTemplate(server: Server, dockerTemplate: DockerTemplate) {
|
||||||
|
return of(dockerTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('DockerTemplateDetailsComponent', () => {
|
||||||
|
let component: DockerTemplateDetailsComponent;
|
||||||
|
let fixture: ComponentFixture<DockerTemplateDetailsComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedDockerService = new MockedDockerService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: DockerService, useValue: mockedDockerService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService },
|
||||||
|
{ provide: DockerConfigurationService, useClass: DockerConfigurationService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
DockerTemplateDetailsComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DockerTemplateDetailsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call save template', () => {
|
||||||
|
spyOn(mockedDockerService, 'saveTemplate').and.returnValue(of({} as DockerTemplate));
|
||||||
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.generalSettingsForm.controls['adapter'].setValue(1);
|
||||||
|
component.generalSettingsForm.controls['symbol'].setValue('symbol path');
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedDockerService.saveTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,89 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
||||||
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
|
import { DockerConfigurationService } from '../../../../services/docker-configuration.service';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-docker-template-details',
|
||||||
|
templateUrl: './docker-template-details.component.html',
|
||||||
|
styleUrls: ['./docker-template-details.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class DockerTemplateDetailsComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
dockerTemplate: DockerTemplate;
|
||||||
|
|
||||||
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
consoleResolutions: string[] = [];
|
||||||
|
categories = [];
|
||||||
|
adapters: CustomAdapter[] = [];
|
||||||
|
displayedColumns: string[] = ['adapter_number', 'port_name'];
|
||||||
|
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private dockerService: DockerService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private configurationService: DockerConfigurationService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router
|
||||||
|
){
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
defaultName: new FormControl('', Validators.required),
|
||||||
|
adapter: new FormControl('', Validators.required),
|
||||||
|
symbol: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(){
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
const template_id = this.route.snapshot.paramMap.get("template_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.getConfiguration();
|
||||||
|
this.dockerService.getTemplate(this.server, template_id).subscribe((dockerTemplate: DockerTemplate) => {
|
||||||
|
this.dockerTemplate = dockerTemplate;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration(){
|
||||||
|
this.consoleTypes = this.configurationService.getConsoleTypes();
|
||||||
|
this.categories = this.configurationService.getCategories();
|
||||||
|
this.consoleResolutions = this.configurationService.getConsoleResolutions();
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.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.toasterService.success("Changes saved");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chooseSymbol() {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.dockerTemplate.symbol = chosenSymbol;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Docker container templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences" mat-button>Back</button>
|
||||||
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/docker/addtemplate" mat-raised-button color="primary">Add Docker container template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-empty-templates-list *ngIf="!dockerTemplates.length"></app-empty-templates-list>
|
||||||
|
<div class="default-content" *ngIf="dockerTemplates.length">
|
||||||
|
<div class="listcontainer mat-elevation-z8">
|
||||||
|
<mat-nav-list *ngIf="server">
|
||||||
|
<div class="list-item" *ngFor='let template of dockerTemplates'>
|
||||||
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
|
<button mat-button class="menu-button" [matMenuTriggerFor]="menu">
|
||||||
|
<mat-icon>more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menu="matMenu">
|
||||||
|
<button mat-menu-item (click)="deleteTemplate(template)">
|
||||||
|
<mat-icon>delete</mat-icon><span>Delete</span>
|
||||||
|
</button>
|
||||||
|
<button mat-menu-item (click)="copyTemplate(template)">
|
||||||
|
<mat-icon>content_copy</mat-icon><span>Copy</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
||||||
|
</mat-nav-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-delete-template
|
||||||
|
#deleteComponent
|
||||||
|
[server]="server"
|
||||||
|
(deleteEvent)="onDeleteEvent()">
|
||||||
|
</app-delete-template>
|
@ -0,0 +1,55 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { MockedServerService } from '../../../../services/server.service.spec';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
|
import { DockerTemplatesComponent } from './docker-templates.component';
|
||||||
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
|
|
||||||
|
export class MockedDockerService {
|
||||||
|
public getTemplates(server: Server) {
|
||||||
|
return of([{} as DockerTemplate]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('DockerTemplatesComponent', () => {
|
||||||
|
let component: DockerTemplatesComponent;
|
||||||
|
let fixture: ComponentFixture<DockerTemplatesComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedDockerService = new MockedDockerService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: DockerService, useValue: mockedDockerService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
DockerTemplatesComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DockerTemplatesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,52 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
||||||
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-docker-templates',
|
||||||
|
templateUrl: './docker-templates.component.html',
|
||||||
|
styleUrls: ['./docker-templates.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class DockerTemplatesComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
dockerTemplates: DockerTemplate[] = [];
|
||||||
|
@ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private dockerService: DockerService,
|
||||||
|
private router: Router
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
this.getTemplates();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplates() {
|
||||||
|
this.dockerService.getTemplates(this.server).subscribe((dockerTemplates: DockerTemplate[]) => {
|
||||||
|
this.dockerTemplates = dockerTemplates.filter((elem) => elem.template_type === 'docker' && !elem.builtin);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTemplate(template: DockerTemplate) {
|
||||||
|
this.deleteComponent.deleteItem(template.name, template.template_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteEvent() {
|
||||||
|
this.getTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
|
copyTemplate(template: DockerTemplate) {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates', template.template_id, 'copy']);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">New IOS router</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content" *ngIf="iosTemplate">
|
||||||
|
<div class="container mat-elevation-z8">
|
||||||
|
<mat-vertical-stepper [linear]="true">
|
||||||
|
<mat-step label="IOS image">
|
||||||
|
<form [formGroup]="iosImageForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="iosTemplate.image"
|
||||||
|
formControlName="imageName"
|
||||||
|
placeholder="IOS image"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Name and platform">
|
||||||
|
<form [formGroup]="iosNameForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="iosTemplate.name"
|
||||||
|
formControlName="templateName"
|
||||||
|
placeholder="Name"/>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Platform"
|
||||||
|
(selectionChange)="onPlatformChosen($event)"
|
||||||
|
formControlName="platform"
|
||||||
|
[(ngModel)]="iosTemplate.platform">
|
||||||
|
<mat-option *ngFor="let platform of platforms" [value]="platform">
|
||||||
|
{{platform}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field" *ngIf="chassis[iosTemplate.platform]">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Chassis"
|
||||||
|
(selectionChange)="onChassisChosen($event)"
|
||||||
|
formControlName="chassis"
|
||||||
|
[(ngModel)]="iosTemplate.chassis">
|
||||||
|
<mat-option *ngFor="let chassis of chassis[iosTemplate.platform]" [value]="chassis">
|
||||||
|
{{chassis}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-checkbox
|
||||||
|
*ngIf="platformsWithEtherSwitchRouterOption[iosTemplate.platform]"
|
||||||
|
[(ngModel)]="isEtherSwitchRouter">
|
||||||
|
This is an EtherSwitch router
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Memory">
|
||||||
|
<form [formGroup]="iosMemoryForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="iosTemplate.ram"
|
||||||
|
formControlName="memory"
|
||||||
|
value="defaultRam[iosTemplate.platform]"
|
||||||
|
placeholder="Default RAM"/>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-label>
|
||||||
|
<a href="{{ciscoUrl}}">Check for minimum and maximum RAM requirement</a>
|
||||||
|
</mat-label>
|
||||||
|
</form>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Network adapters">
|
||||||
|
<div *ngIf="iosTemplate.chassis && chassis[iosTemplate.platform]">
|
||||||
|
<div *ngFor="let index of [0,1,2,3,4,5,6,7]">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Slot {{index}}"
|
||||||
|
[(ngModel)]="networkAdaptersForTemplate[index]"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
*ngIf="networkAdapters[iosTemplate.chassis][index]">
|
||||||
|
<mat-option *ngFor="let option of networkAdapters[iosTemplate.chassis][index]" [value]="option">
|
||||||
|
{{option}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="iosTemplate.platform && !chassis[iosTemplate.platform]">
|
||||||
|
<div *ngFor="let index of [0,1,2,3,4,5,6,7]">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Slot {{index}}"
|
||||||
|
[(ngModel)]="networkAdaptersForTemplate[index]"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
*ngIf="networkAdaptersForPlatform[iosTemplate.platform][index]">
|
||||||
|
<mat-option *ngFor="let option of networkAdaptersForPlatform[iosTemplate.platform][index]" [value]="option">
|
||||||
|
{{option}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="WIC modules">
|
||||||
|
<div *ngIf="iosTemplate.platform && networkModules[iosTemplate.platform]">
|
||||||
|
<div *ngFor="let index of [0,1,2,3]">
|
||||||
|
<mat-select
|
||||||
|
placeholder="WIC {{index}}"
|
||||||
|
[(ngModel)]="networkModulesForTemplate[index]"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
*ngIf="networkModules[iosTemplate.platform][index]">
|
||||||
|
<mat-option *ngFor="let option of networkModules[iosTemplate.platform][index]" [value]="option">
|
||||||
|
{{option}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Idle-PC">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="iosTemplate.idlepc"
|
||||||
|
placeholder="Idle-PC"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-step>
|
||||||
|
</mat-vertical-stepper>
|
||||||
|
</div>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,120 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatInputModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatSelectModule, MatFormFieldModule, MatAutocompleteModule, MatTableModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { MockedServerService } from '../../../../services/server.service.spec';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
||||||
|
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
||||||
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
|
import { IosTemplate } from '../../../../models/templates/ios-template';
|
||||||
|
import { AddIosTemplateComponent } from './add-ios-template.component';
|
||||||
|
import { IosService } from '../../../../services/ios.service';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { IosConfigurationService } from '../../../../services/ios-configuration.service';
|
||||||
|
|
||||||
|
export class MockedIosService {
|
||||||
|
public addTemplate(server: Server, iosTemplate: IosTemplate) {
|
||||||
|
return of(iosTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('AddIosTemplateComponent', () => {
|
||||||
|
let component: AddIosTemplateComponent;
|
||||||
|
let fixture: ComponentFixture<AddIosTemplateComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedIosService = new MockedIosService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ FormsModule, MatTableModule, MatAutocompleteModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule, MatSelectModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: IosService, useValue: mockedIosService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
||||||
|
{ provide: IosConfigurationService, useClass: IosConfigurationService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AddIosTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AddIosTemplateComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call add template', () => {
|
||||||
|
spyOn(mockedIosService, 'addTemplate').and.returnValue(of({} as IosTemplate));
|
||||||
|
component.iosImageForm.controls['imageName'].setValue('image name');
|
||||||
|
component.iosNameForm.controls['templateName'].setValue('template name');
|
||||||
|
component.iosNameForm.controls['platform'].setValue('platform');
|
||||||
|
component.iosNameForm.controls['chassis'].setValue('chassis');
|
||||||
|
component.iosMemoryForm.controls['memory'].setValue(0);
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedIosService.addTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when template name is not defined', () => {
|
||||||
|
spyOn(mockedIosService, 'addTemplate').and.returnValue(of({} as IosTemplate));
|
||||||
|
component.iosImageForm.controls['imageName'].setValue('image name');
|
||||||
|
component.iosNameForm.controls['templateName'].setValue('');
|
||||||
|
component.iosNameForm.controls['platform'].setValue('platform');
|
||||||
|
component.iosNameForm.controls['chassis'].setValue('chassis');
|
||||||
|
component.iosMemoryForm.controls['memory'].setValue(0);
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedIosService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when image name is not defined', () => {
|
||||||
|
spyOn(mockedIosService, 'addTemplate').and.returnValue(of({} as IosTemplate));
|
||||||
|
component.iosNameForm.controls['templateName'].setValue('template name');
|
||||||
|
component.iosNameForm.controls['platform'].setValue('platform');
|
||||||
|
component.iosNameForm.controls['chassis'].setValue('chassis');
|
||||||
|
component.iosMemoryForm.controls['memory'].setValue(0);
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedIosService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call add template when memory is not defined', () => {
|
||||||
|
spyOn(mockedIosService, 'addTemplate').and.returnValue(of({} as IosTemplate));
|
||||||
|
component.iosImageForm.controls['imageName'].setValue('image name');
|
||||||
|
component.iosNameForm.controls['templateName'].setValue('template name');
|
||||||
|
component.iosNameForm.controls['platform'].setValue('platform');
|
||||||
|
component.iosNameForm.controls['chassis'].setValue('chassis');
|
||||||
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
|
component.addTemplate();
|
||||||
|
|
||||||
|
expect(mockedIosService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,160 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { IosTemplate } from '../../../../models/templates/ios-template';
|
||||||
|
import { IosService } from '../../../../services/ios.service';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
||||||
|
import { IosConfigurationService } from '../../../../services/ios-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-ios-template',
|
||||||
|
templateUrl: './add-ios-template.component.html',
|
||||||
|
styleUrls: ['./add-ios-template.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class AddIosTemplateComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
iosTemplate: IosTemplate;
|
||||||
|
isEtherSwitchRouter: boolean = false;
|
||||||
|
|
||||||
|
iosImageForm: FormGroup;
|
||||||
|
iosNameForm: FormGroup;
|
||||||
|
iosMemoryForm: FormGroup;
|
||||||
|
|
||||||
|
networkAdaptersForTemplate: string[] = [];
|
||||||
|
networkModulesForTemplate: string[] = [];
|
||||||
|
|
||||||
|
platforms: string[] = [];
|
||||||
|
platformsWithEtherSwitchRouterOption = {};
|
||||||
|
platformsWithChassis = {};
|
||||||
|
chassis = {};
|
||||||
|
defaultRam = {};
|
||||||
|
defaultNvram = {};
|
||||||
|
networkAdapters = {};
|
||||||
|
networkAdaptersForPlatform = {};
|
||||||
|
networkModules = {};
|
||||||
|
|
||||||
|
ciscoUrl: string = "https://cfn.cloudapps.cisco.com/ITDIT/CFN/jsp/SearchBySoftware.jsp";
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private iosService: IosService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router,
|
||||||
|
private templateMocksService: TemplateMocksService,
|
||||||
|
private iosConfigurationService: IosConfigurationService
|
||||||
|
) {
|
||||||
|
this.iosTemplate = new IosTemplate();
|
||||||
|
|
||||||
|
this.iosImageForm = this.formBuilder.group({
|
||||||
|
imageName: new FormControl(null, [Validators.required])
|
||||||
|
});
|
||||||
|
|
||||||
|
this.iosNameForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl(null, [Validators.required]),
|
||||||
|
platform: new FormControl(null, [Validators.required]),
|
||||||
|
chassis: new FormControl(null, [Validators.required])
|
||||||
|
});
|
||||||
|
|
||||||
|
this.iosMemoryForm = this.formBuilder.group({
|
||||||
|
memory: new FormControl(null, [Validators.required])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(){
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.templateMocksService.getIosTemplate().subscribe((iosTemplate: IosTemplate) => {
|
||||||
|
this.iosTemplate = iosTemplate;
|
||||||
|
|
||||||
|
this.networkModules = this.iosConfigurationService.getNetworkModules();
|
||||||
|
this.networkAdaptersForPlatform = this.iosConfigurationService.getNetworkAdaptersForPlatform();
|
||||||
|
this.networkAdapters = this.iosConfigurationService.getNetworkAdapters();
|
||||||
|
this.platforms = this.iosConfigurationService.getAvailablePlatforms();
|
||||||
|
this.platformsWithEtherSwitchRouterOption = this.iosConfigurationService.getPlatformsWithEtherSwitchRouterOption();
|
||||||
|
this.platformsWithChassis = this.iosConfigurationService.getPlatformsWithChassis();
|
||||||
|
this.chassis = this.iosConfigurationService.getChassis();
|
||||||
|
this.defaultRam = this.iosConfigurationService.getDefaultRamSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addTemplate() {
|
||||||
|
if (!this.iosImageForm.invalid && !this.iosNameForm.invalid && !this.iosMemoryForm.invalid) {
|
||||||
|
this.iosTemplate.template_id = uuid();
|
||||||
|
|
||||||
|
if (this.isEtherSwitchRouter) {
|
||||||
|
this.iosTemplate.symbol = ":/symbols/multilayer_switch.svg";
|
||||||
|
this.iosTemplate.category = "switch";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.networkAdaptersForTemplate.length>0) this.completeAdaptersData();
|
||||||
|
if (this.networkModulesForTemplate.length>0) this.completeModulesData();
|
||||||
|
|
||||||
|
this.iosService.addTemplate(this.server, this.iosTemplate).subscribe((template: IosTemplate) => {
|
||||||
|
this.goBack();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
completeAdaptersData() {
|
||||||
|
if (this.chassis[this.iosTemplate.platform]) {
|
||||||
|
if(Object.keys(this.networkAdapters[this.iosTemplate.platform])){
|
||||||
|
for(let i=0; i<Object.keys(this.networkAdapters[this.iosTemplate.platform]).length; i++){
|
||||||
|
if(!this.networkAdaptersForTemplate[i]) this.networkAdaptersForTemplate[i] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(Object.keys(this.networkAdaptersForPlatform[this.iosTemplate.platform])){
|
||||||
|
for(let i=0; i<Object.keys(this.networkAdaptersForPlatform[this.iosTemplate.platform]).length; i++){
|
||||||
|
if(!this.networkAdaptersForTemplate[i]) this.networkAdaptersForTemplate[i] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.networkAdaptersForTemplate[0]) this.iosTemplate.slot0 = this.networkAdaptersForTemplate[0];
|
||||||
|
if (this.networkAdaptersForTemplate[1]) this.iosTemplate.slot1 = this.networkAdaptersForTemplate[1];
|
||||||
|
if (this.networkAdaptersForTemplate[2]) this.iosTemplate.slot2 = this.networkAdaptersForTemplate[2];
|
||||||
|
if (this.networkAdaptersForTemplate[3]) this.iosTemplate.slot3 = this.networkAdaptersForTemplate[3];
|
||||||
|
if (this.networkAdaptersForTemplate[4]) this.iosTemplate.slot4 = this.networkAdaptersForTemplate[4];
|
||||||
|
if (this.networkAdaptersForTemplate[5]) this.iosTemplate.slot5 = this.networkAdaptersForTemplate[5];
|
||||||
|
if (this.networkAdaptersForTemplate[6]) this.iosTemplate.slot6 = this.networkAdaptersForTemplate[6];
|
||||||
|
if (this.networkAdaptersForTemplate[7]) this.iosTemplate.slot7 = this.networkAdaptersForTemplate[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
completeModulesData() {
|
||||||
|
if(Object.keys(this.networkModules[this.iosTemplate.platform])){
|
||||||
|
for(let i=0; i<Object.keys(this.networkModules[this.iosTemplate.platform]).length; i++){
|
||||||
|
if(!this.networkModulesForTemplate[i]) this.networkModulesForTemplate[i] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.networkModulesForTemplate[0]) this.iosTemplate.wic0 = this.networkModulesForTemplate[0];
|
||||||
|
if (this.networkModulesForTemplate[1]) this.iosTemplate.wic1 = this.networkModulesForTemplate[1];
|
||||||
|
if (this.networkModulesForTemplate[2]) this.iosTemplate.wic2 = this.networkModulesForTemplate[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'dynamips', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlatformChosen() {
|
||||||
|
this.iosTemplate.chassis = '';
|
||||||
|
this.networkAdaptersForTemplate = [];
|
||||||
|
this.networkModulesForTemplate = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
onChassisChosen() {
|
||||||
|
this.networkAdaptersForTemplate = [];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Copy IOS router template</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="formGroup">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="templateName"
|
||||||
|
placeholder="Name"
|
||||||
|
formControlName="templateName"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Copy template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,66 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { IosTemplate } from '../../../../models/templates/ios-template';
|
||||||
|
import { IosService } from '../../../../services/ios.service';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-copy-ios-template',
|
||||||
|
templateUrl: './copy-ios-template.component.html',
|
||||||
|
styleUrls: ['./copy-ios-template.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class CopyIosTemplateComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
templateName: string = '';
|
||||||
|
iosTemplate: IosTemplate;
|
||||||
|
formGroup: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private iosService: IosService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private router: Router,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.formGroup = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
const template_id = this.route.snapshot.paramMap.get("template_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.iosService.getTemplate(this.server, template_id).subscribe((iosTemplate: IosTemplate) => {
|
||||||
|
this.iosTemplate = iosTemplate;
|
||||||
|
this.templateName = `Copy of ${this.iosTemplate.name}`;
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'dynamips', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
|
addTemplate() {
|
||||||
|
if (!this.formGroup.invalid) {
|
||||||
|
this.iosTemplate.template_id = uuid();
|
||||||
|
this.iosTemplate.name = this.templateName;
|
||||||
|
|
||||||
|
this.iosService.addTemplate(this.server, this.iosTemplate).subscribe((template: IosTemplate) => {
|
||||||
|
this.goBack();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Dynamips preferences</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" [(ngModel)]="dynamipsPath" placeholder="Path to Dynamips"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,8 @@
|
|||||||
|
.top-button {
|
||||||
|
height: 36px;
|
||||||
|
margin-top: 22px
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { MockedServerService } from '../../../../services/server.service.spec';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
|
import { ServerSettingsService } from '../../../../services/server-settings.service';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { MockedServerSettingsService } from '../../../../services/server-settings.service.spec';
|
||||||
|
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { DynamipsPreferencesComponent } from './dynamips-preferences.component';
|
||||||
|
|
||||||
|
describe('DynamipsPreferencesComponent', () => {
|
||||||
|
let component: DynamipsPreferencesComponent;
|
||||||
|
let fixture: ComponentFixture<DynamipsPreferencesComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
let mockedServerSettingsService = new MockedServerSettingsService();
|
||||||
|
let mockedToasterService = new MockedToasterService();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [HttpClientModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: ServerSettingsService, useValue: mockedServerSettingsService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
DynamipsPreferencesComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DynamipsPreferencesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear path when restore defaults called', () => {
|
||||||
|
component.dynamipsPath = 'Non empty';
|
||||||
|
component.restoreDefaults();
|
||||||
|
|
||||||
|
expect(component.dynamipsPath).toBe('');
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,33 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ServerSettingsService } from '../../../../services/server-settings.service';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-dynamips-preferences',
|
||||||
|
templateUrl: './dynamips-preferences.component.html',
|
||||||
|
styleUrls: ['./dynamips-preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class DynamipsPreferencesComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
dynamipsPath: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private serverSettingsService: ServerSettingsService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreDefaults() {
|
||||||
|
this.dynamipsPath = '';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,198 @@
|
|||||||
|
<div class="content" [ngClass]="{ shadowed: isSymbolSelectionOpened }">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Dynamips IOS Router configuration</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content" *ngIf="iosTemplate">
|
||||||
|
<mat-accordion>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
General settings
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" formControlName="templateName" [(ngModel)]="iosTemplate.name" placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" formControlName="defaultName" [(ngModel)]="iosTemplate.default_name_format" placeholder="Default name format">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-label>Platform - {{iosTemplate.platform}}</mat-label><br/><br/>
|
||||||
|
<mat-label>Chassis - {{iosTemplate.chassis}}</mat-label><br/><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" formControlName="symbol" [(ngModel)]="iosTemplate.symbol" placeholder="Symbol">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Category" [(ngModel)]="iosTemplate.category">
|
||||||
|
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
||||||
|
{{category[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" formControlName="path" [(ngModel)]="iosTemplate.image" placeholder="IOS image path">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" formControlName="initialConfig" [(ngModel)]="iosTemplate.startup_config" placeholder="Initial startup-config">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input [ngModelOptions]="{standalone: true}" matInput type="text" [(ngModel)]="iosTemplate.private_config" placeholder="Initial private-config">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select placeholder="Console type" [(ngModel)]="iosTemplate.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox [(ngModel)]="iosTemplate.console_auto_start">
|
||||||
|
Auto start console
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
Memories and disks
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<form [formGroup]="memoryForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" formControlName="ram" [(ngModel)]="iosTemplate.ram" placeholder="RAM size">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" formControlName="nvram" [(ngModel)]="iosTemplate.nvram" placeholder="NVRAM size">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" formControlName="iomemory" [(ngModel)]="iosTemplate.iomem" placeholder="I/O memory">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" formControlName="disk0" [(ngModel)]="iosTemplate.disk0" placeholder="PCMCIA disk0">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" formControlName="disk1" [(ngModel)]="iosTemplate.disk1" placeholder="PCMCIA disk1">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-checkbox [(ngModel)]="iosTemplate.auto_delete_disks">
|
||||||
|
Automatically delete NVRAM and disk files
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
Slots
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<h6>Adapters</h6>
|
||||||
|
<div *ngIf="iosTemplate.chassis && chassis[iosTemplate.platform]">
|
||||||
|
<div *ngFor="let index of [0,1,2,3,4,5,6,7]">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Slot {{index}}"
|
||||||
|
[(ngModel)]="networkAdaptersForTemplate[index]"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
*ngIf="networkAdapters[iosTemplate.chassis][index]">
|
||||||
|
<mat-option *ngFor="let option of networkAdapters[iosTemplate.chassis][index]" [value]="option">
|
||||||
|
{{option}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="iosTemplate.platform && !chassis[iosTemplate.platform]">
|
||||||
|
<div *ngFor="let index of [0,1,2,3,4,5,6,7]">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Slot {{index}}"
|
||||||
|
[(ngModel)]="networkAdaptersForTemplate[index]"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
*ngIf="networkAdaptersForPlatform[iosTemplate.platform][index]">
|
||||||
|
<mat-option *ngFor="let option of networkAdaptersForPlatform[iosTemplate.platform][index]" [value]="option">
|
||||||
|
{{option}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</div>
|
||||||
|
</div><br/><br/>
|
||||||
|
<h6>WICs</h6>
|
||||||
|
<div *ngIf="iosTemplate.wic0 || iosTemplate.wic0===''">
|
||||||
|
<mat-select
|
||||||
|
placeholder="WIC 0"
|
||||||
|
[(ngModel)]="iosTemplate.wic0"
|
||||||
|
[ngModelOptions]="{standalone: true}">
|
||||||
|
<mat-option *ngFor="let option of networkModules[iosTemplate.platform][0]" [value]="option">
|
||||||
|
{{option}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="iosTemplate.wic1 || iosTemplate.wic1===''">
|
||||||
|
<mat-select
|
||||||
|
placeholder="WIC 1"
|
||||||
|
[(ngModel)]="iosTemplate.wic1"
|
||||||
|
[ngModelOptions]="{standalone: true}">
|
||||||
|
<mat-option *ngFor="let option of networkModules[iosTemplate.platform][1]" [value]="option">
|
||||||
|
{{option}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="iosTemplate.wic2 || iosTemplate.wic2===''">
|
||||||
|
<mat-select
|
||||||
|
placeholder="WIC 2"
|
||||||
|
[(ngModel)]="iosTemplate.wic2"
|
||||||
|
[ngModelOptions]="{standalone: true}">
|
||||||
|
<mat-option *ngFor="let option of networkModules[iosTemplate.platform][2]" [value]="option">
|
||||||
|
{{option}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
Advanced
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<form [formGroup]="advancedForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="systemId" type="text" [(ngModel)]="iosTemplate.system_id" placeholder="System ID">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input [ngModelOptions]="{standalone: true}" matInput type="text" [(ngModel)]="iosTemplate.mac_addr" placeholder="Base MAC">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input [ngModelOptions]="{standalone: true}" matInput type="text" [(ngModel)]="iosTemplate.idlepc" placeholder="Idle-PC">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="idlemax" type="number" [(ngModel)]="iosTemplate.idlemax" placeholder="Idlemax">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="idlesleep" type="number" [(ngModel)]="iosTemplate.idlesleep" placeholder="Idlesleep">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="execarea" type="number" [(ngModel)]="iosTemplate.exec_area" placeholder="Exec area">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-checkbox [(ngModel)]="iosTemplate.mmap">
|
||||||
|
Enable mmap support
|
||||||
|
</mat-checkbox><br/><br/>
|
||||||
|
<mat-checkbox [(ngModel)]="iosTemplate.sparsemem">
|
||||||
|
Enable sparse memory supoport
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
Usage
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="iosTemplate.usage"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && iosTemplate" [server]="server" [symbol]="iosTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
@ -0,0 +1,90 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { MockedServerService } from '../../../../services/server.service.spec';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
|
import { IosTemplate } from '../../../../models/templates/ios-template';
|
||||||
|
import { IosTemplateDetailsComponent } from './ios-template-details.component';
|
||||||
|
import { IosService } from '../../../../services/ios.service';
|
||||||
|
import { IosConfigurationService } from '../../../../services/ios-configuration.service';
|
||||||
|
|
||||||
|
export class MockedIosService {
|
||||||
|
public getTemplate(server: Server, template_id: string) {
|
||||||
|
return of({} as IosTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public saveTemplate(server: Server, iosTemplate: IosTemplate) {
|
||||||
|
return of(iosTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('IosTemplateDetailsComponent', () => {
|
||||||
|
let component: IosTemplateDetailsComponent;
|
||||||
|
let fixture: ComponentFixture<IosTemplateDetailsComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedIosService = new MockedIosService;
|
||||||
|
let mockedToasterService = new MockedToasterService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: IosService, useValue: mockedIosService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService },
|
||||||
|
{ provide: IosConfigurationService, useClass: IosConfigurationService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
IosTemplateDetailsComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(IosTemplateDetailsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call save template', () => {
|
||||||
|
spyOn(mockedIosService, 'saveTemplate').and.returnValue(of({} as IosTemplate));
|
||||||
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.generalSettingsForm.controls['path'].setValue('path');
|
||||||
|
component.generalSettingsForm.controls['initialConfig'].setValue('txt');
|
||||||
|
component.memoryForm.controls['ram'].setValue('0');
|
||||||
|
component.memoryForm.controls['nvram'].setValue('0');
|
||||||
|
component.memoryForm.controls['iomemory'].setValue('0');
|
||||||
|
component.memoryForm.controls['disk0'].setValue('0');
|
||||||
|
component.memoryForm.controls['disk1'].setValue('0');
|
||||||
|
component.advancedForm.controls['systemId'].setValue('0');
|
||||||
|
component.advancedForm.controls['idlemax'].setValue('0');
|
||||||
|
component.advancedForm.controls['idlesleep'].setValue('0');
|
||||||
|
component.advancedForm.controls['execarea'].setValue('0');
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedIosService.saveTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,145 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { IosTemplate } from '../../../../models/templates/ios-template';
|
||||||
|
import { IosService } from '../../../../services/ios.service';
|
||||||
|
import { IosConfigurationService } from '../../../../services/ios-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ios-template-details',
|
||||||
|
templateUrl: './ios-template-details.component.html',
|
||||||
|
styleUrls: ['./ios-template-details.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class IosTemplateDetailsComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
iosTemplate: IosTemplate;
|
||||||
|
|
||||||
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
|
networkAdaptersForTemplate: string[] = [];
|
||||||
|
platforms: string[] = [];
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
platformsWithEtherSwitchRouterOption = {};
|
||||||
|
platformsWithChassis = {};
|
||||||
|
chassis = {};
|
||||||
|
defaultRam = {};
|
||||||
|
defaultNvram = {};
|
||||||
|
networkAdapters = {};
|
||||||
|
networkAdaptersForPlatform = {};
|
||||||
|
networkModules = {};
|
||||||
|
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
memoryForm: FormGroup;
|
||||||
|
advancedForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private iosService: IosService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private iosConfigurationService: IosConfigurationService,
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
defaultName: new FormControl('', Validators.required),
|
||||||
|
symbol: new FormControl('', Validators.required),
|
||||||
|
path: new FormControl('', Validators.required),
|
||||||
|
initialConfig: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.memoryForm = this.formBuilder.group({
|
||||||
|
ram: new FormControl('', Validators.required),
|
||||||
|
nvram: new FormControl('', Validators.required),
|
||||||
|
iomemory: new FormControl('', Validators.required),
|
||||||
|
disk0: new FormControl('', Validators.required),
|
||||||
|
disk1: new FormControl('', Validators.required),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.advancedForm = this.formBuilder.group({
|
||||||
|
systemId: new FormControl('', Validators.required),
|
||||||
|
idlemax: new FormControl('', Validators.required),
|
||||||
|
idlesleep: new FormControl('', Validators.required),
|
||||||
|
execarea: new FormControl('', Validators.required),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
const template_id = this.route.snapshot.paramMap.get("template_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.getConfiguration();
|
||||||
|
this.iosService.getTemplate(this.server, template_id).subscribe((iosTemplate: IosTemplate) => {
|
||||||
|
this.iosTemplate = iosTemplate;
|
||||||
|
|
||||||
|
this.fillAdaptersData();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.networkModules = this.iosConfigurationService.getNetworkModules();
|
||||||
|
this.networkAdaptersForPlatform = this.iosConfigurationService.getNetworkAdaptersForPlatform();
|
||||||
|
this.networkAdapters = this.iosConfigurationService.getNetworkAdapters();
|
||||||
|
this.platforms = this.iosConfigurationService.getAvailablePlatforms();
|
||||||
|
this.platformsWithEtherSwitchRouterOption = this.iosConfigurationService.getPlatformsWithEtherSwitchRouterOption();
|
||||||
|
this.platformsWithChassis = this.iosConfigurationService.getPlatformsWithChassis();
|
||||||
|
this.chassis = this.iosConfigurationService.getChassis();
|
||||||
|
this.defaultRam = this.iosConfigurationService.getDefaultRamSettings();
|
||||||
|
this.consoleTypes = this.iosConfigurationService.getConsoleTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
fillAdaptersData() {
|
||||||
|
if (this.iosTemplate.slot0) this.networkAdaptersForTemplate[0] = this.iosTemplate.slot0;
|
||||||
|
if (this.iosTemplate.slot1) this.networkAdaptersForTemplate[1] = this.iosTemplate.slot1;
|
||||||
|
if (this.iosTemplate.slot2) this.networkAdaptersForTemplate[2] = this.iosTemplate.slot2;
|
||||||
|
if (this.iosTemplate.slot3) this.networkAdaptersForTemplate[3] = this.iosTemplate.slot3;
|
||||||
|
if (this.iosTemplate.slot4) this.networkAdaptersForTemplate[4] = this.iosTemplate.slot4;
|
||||||
|
if (this.iosTemplate.slot5) this.networkAdaptersForTemplate[5] = this.iosTemplate.slot5;
|
||||||
|
if (this.iosTemplate.slot6) this.networkAdaptersForTemplate[6] = this.iosTemplate.slot6;
|
||||||
|
if (this.iosTemplate.slot7) this.networkAdaptersForTemplate[7] = this.iosTemplate.slot7;
|
||||||
|
}
|
||||||
|
|
||||||
|
completeAdaptersData() {
|
||||||
|
if (this.networkAdaptersForTemplate[0]) this.iosTemplate.slot0 = this.networkAdaptersForTemplate[0];
|
||||||
|
if (this.networkAdaptersForTemplate[1]) this.iosTemplate.slot1 = this.networkAdaptersForTemplate[1];
|
||||||
|
if (this.networkAdaptersForTemplate[2]) this.iosTemplate.slot2 = this.networkAdaptersForTemplate[2];
|
||||||
|
if (this.networkAdaptersForTemplate[3]) this.iosTemplate.slot3 = this.networkAdaptersForTemplate[3];
|
||||||
|
if (this.networkAdaptersForTemplate[4]) this.iosTemplate.slot4 = this.networkAdaptersForTemplate[4];
|
||||||
|
if (this.networkAdaptersForTemplate[5]) this.iosTemplate.slot5 = this.networkAdaptersForTemplate[5];
|
||||||
|
if (this.networkAdaptersForTemplate[6]) this.iosTemplate.slot6 = this.networkAdaptersForTemplate[6];
|
||||||
|
if (this.networkAdaptersForTemplate[7]) this.iosTemplate.slot7 = this.networkAdaptersForTemplate[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
onSave() {
|
||||||
|
if (this.generalSettingsForm.invalid || this.memoryForm.invalid || this.advancedForm.invalid) {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
} else {
|
||||||
|
this.completeAdaptersData();
|
||||||
|
|
||||||
|
this.iosService.saveTemplate(this.server, this.iosTemplate).subscribe((iosTemplate: IosTemplate) => {
|
||||||
|
this.toasterService.success("Changes saved");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'dynamips', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
|
chooseSymbol() {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
this.iosTemplate.symbol = chosenSymbol;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">IOS routers templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences" mat-button>Back</button>
|
||||||
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/dynamips/templates/addtemplate" mat-raised-button color="primary">Add IOS router template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-empty-templates-list *ngIf="!iosTemplates.length"></app-empty-templates-list>
|
||||||
|
<div class="default-content" *ngIf="iosTemplates.length">
|
||||||
|
<div class="listcontainer mat-elevation-z8">
|
||||||
|
<mat-nav-list *ngIf="server">
|
||||||
|
<div class="list-item" *ngFor='let template of iosTemplates'>
|
||||||
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
|
<button mat-button class="menu-button" [matMenuTriggerFor]="menu">
|
||||||
|
<mat-icon>more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menu="matMenu">
|
||||||
|
<button mat-menu-item (click)="deleteTemplate(template)">
|
||||||
|
<mat-icon>delete</mat-icon><span>Delete</span>
|
||||||
|
</button>
|
||||||
|
<button mat-menu-item (click)="copyTemplate(template)">
|
||||||
|
<mat-icon>content_copy</mat-icon><span>Copy</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
||||||
|
</mat-nav-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-delete-template
|
||||||
|
#deleteComponent
|
||||||
|
[server]="server"
|
||||||
|
(deleteEvent)="onDeleteEvent()">
|
||||||
|
</app-delete-template>
|
@ -0,0 +1,57 @@
|
|||||||
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { MockedServerService } from '../../../../services/server.service.spec';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
|
import { IosTemplate } from '../../../../models/templates/ios-template';
|
||||||
|
import { IosTemplatesComponent } from './ios-templates.component';
|
||||||
|
import { IosService } from '../../../../services/ios.service';
|
||||||
|
|
||||||
|
export class MockedIosService {
|
||||||
|
public getTemplates(server: Server) {
|
||||||
|
return of([{} as IosTemplate]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('IosTemplatesComponent', () => {
|
||||||
|
let component: IosTemplatesComponent;
|
||||||
|
let fixture: ComponentFixture<IosTemplatesComponent>;
|
||||||
|
|
||||||
|
let mockedServerService = new MockedServerService;
|
||||||
|
let mockedIosService = new MockedIosService;
|
||||||
|
let activatedRoute = new MockedActivatedRoute().get();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: IosService, useValue: mockedIosService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
IosTemplatesComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(IosTemplatesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,53 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { IosService } from '../../../../services/ios.service';
|
||||||
|
import { IosTemplate } from '../../../../models/templates/ios-template';
|
||||||
|
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
||||||
|
import { VpcsTemplate } from '../../../../models/templates/vpcs-template';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ios-templates',
|
||||||
|
templateUrl: './ios-templates.component.html',
|
||||||
|
styleUrls: ['./ios-templates.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class IosTemplatesComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
iosTemplates: IosTemplate[] = [];
|
||||||
|
@ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private iosService: IosService,
|
||||||
|
private router: Router
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
this.getTemplates();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplates() {
|
||||||
|
this.iosService.getTemplates(this.server).subscribe((templates: IosTemplate[]) => {
|
||||||
|
this.iosTemplates = templates.filter((elem) => elem.template_type === 'dynamips' && !elem.builtin);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTemplate(template: VpcsTemplate) {
|
||||||
|
this.deleteComponent.deleteItem(template.name, template.template_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteEvent() {
|
||||||
|
this.getTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
|
copyTemplate(template: IosTemplate) {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'dynamips', 'templates', template.template_id, 'copy']);
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user