Initial Commit - NG UI 43/8843/19 release-v8.0-start v7.1.3
authorkumaran.m <kumaran.m@tataelxsi.co.in>
Fri, 1 May 2020 14:18:54 +0000 (19:48 +0530)
committerkumaran.m <kumaran.m@tataelxsi.co.in>
Mon, 15 Jun 2020 13:08:00 +0000 (18:38 +0530)
* Roboto and font-awesome fonts are added in package.json
* Replace Nginx alpine varient to stable
* Devops files are added
* Docker file aligned as per community reviews
* Enhancement - NS primitive, Azure inclusion and domain name
* RWD changes

Change-Id: If543efbf127964cbd8f4be4c5a67260c91407fd9
Signed-off-by: kumaran.m <kumaran.m@tataelxsi.co.in>
337 files changed:
.editorconfig [new file with mode: 0644]
.gitignore [new file with mode: 0644]
Dockerfile
README.md
angular.json [new file with mode: 0644]
browserslist [new file with mode: 0644]
build-debpkg.sh
docker/Dockerfile [new file with mode: 0644]
nginx/nginx.conf [new file with mode: 0644]
package.json [new file with mode: 0644]
proxy.conf.json [new file with mode: 0644]
src/app/AppComponent.html [new file with mode: 0644]
src/app/AppComponent.scss [new file with mode: 0644]
src/app/AppComponent.ts [new file with mode: 0644]
src/app/AppModule.ts [new file with mode: 0644]
src/app/approutes.module.ts [new file with mode: 0644]
src/app/dashboard/DashboardComponent.html [new file with mode: 0644]
src/app/dashboard/DashboardComponent.scss [new file with mode: 0644]
src/app/dashboard/DashboardComponent.ts [new file with mode: 0644]
src/app/dashboard/DashboardModule.ts [new file with mode: 0644]
src/app/instances/InstancesComponent.html [new file with mode: 0644]
src/app/instances/InstancesComponent.scss [new file with mode: 0644]
src/app/instances/InstancesComponent.ts [new file with mode: 0644]
src/app/instances/InstancesModule.ts [new file with mode: 0644]
src/app/instances/netslice-instances/NetsliceInstancesComponent.html [new file with mode: 0644]
src/app/instances/netslice-instances/NetsliceInstancesComponent.scss [new file with mode: 0644]
src/app/instances/netslice-instances/NetsliceInstancesComponent.ts [new file with mode: 0644]
src/app/instances/ns-history-operations/HistoryOperationsComponent.html [new file with mode: 0644]
src/app/instances/ns-history-operations/HistoryOperationsComponent.scss [new file with mode: 0644]
src/app/instances/ns-history-operations/HistoryOperationsComponent.ts [new file with mode: 0644]
src/app/instances/ns-instances/NSInstancesComponent.html [new file with mode: 0644]
src/app/instances/ns-instances/NSInstancesComponent.scss [new file with mode: 0644]
src/app/instances/ns-instances/NSInstancesComponent.ts [new file with mode: 0644]
src/app/instances/ns-primitive/NSPrimitiveComponent.html [new file with mode: 0644]
src/app/instances/ns-primitive/NSPrimitiveComponent.scss [new file with mode: 0644]
src/app/instances/ns-primitive/NSPrimitiveComponent.ts [new file with mode: 0644]
src/app/instances/ns-topology/NSTopologyComponent.html [new file with mode: 0644]
src/app/instances/ns-topology/NSTopologyComponent.scss [new file with mode: 0644]
src/app/instances/ns-topology/NSTopologyComponent.ts [new file with mode: 0644]
src/app/instances/pdu-instances/PDUInstancesComponent.html [new file with mode: 0644]
src/app/instances/pdu-instances/PDUInstancesComponent.scss [new file with mode: 0644]
src/app/instances/pdu-instances/PDUInstancesComponent.ts [new file with mode: 0644]
src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.html [new file with mode: 0644]
src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.scss [new file with mode: 0644]
src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.ts [new file with mode: 0644]
src/app/instances/vnf-instances/VNFInstancesComponent.html [new file with mode: 0644]
src/app/instances/vnf-instances/VNFInstancesComponent.scss [new file with mode: 0644]
src/app/instances/vnf-instances/VNFInstancesComponent.ts [new file with mode: 0644]
src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.html [new file with mode: 0644]
src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.scss [new file with mode: 0644]
src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.ts [new file with mode: 0644]
src/app/k8s/K8sComponent.html [new file with mode: 0644]
src/app/k8s/K8sComponent.scss [new file with mode: 0644]
src/app/k8s/K8sComponent.ts [new file with mode: 0644]
src/app/k8s/K8sModule.ts [new file with mode: 0644]
src/app/k8s/k8s-action/K8sActionComponent.html [new file with mode: 0644]
src/app/k8s/k8s-action/K8sActionComponent.scss [new file with mode: 0644]
src/app/k8s/k8s-action/K8sActionComponent.ts [new file with mode: 0644]
src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.html [new file with mode: 0644]
src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.scss [new file with mode: 0644]
src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.ts [new file with mode: 0644]
src/app/k8s/k8s-add-repo/K8sAddRepoComponent.html [new file with mode: 0644]
src/app/k8s/k8s-add-repo/K8sAddRepoComponent.scss [new file with mode: 0644]
src/app/k8s/k8s-add-repo/K8sAddRepoComponent.ts [new file with mode: 0644]
src/app/k8s/k8scluster/K8sClusterComponent.html [new file with mode: 0644]
src/app/k8s/k8scluster/K8sClusterComponent.scss [new file with mode: 0644]
src/app/k8s/k8scluster/K8sClusterComponent.ts [new file with mode: 0644]
src/app/k8s/k8srepository/K8sRepositoryComponent.html [new file with mode: 0644]
src/app/k8s/k8srepository/K8sRepositoryComponent.scss [new file with mode: 0644]
src/app/k8s/k8srepository/K8sRepositoryComponent.ts [new file with mode: 0644]
src/app/layouts/LayoutComponent.html [new file with mode: 0644]
src/app/layouts/LayoutComponent.scss [new file with mode: 0644]
src/app/layouts/LayoutComponent.ts [new file with mode: 0644]
src/app/layouts/breadcrumb/BreadcrumbComponent.html [new file with mode: 0644]
src/app/layouts/breadcrumb/BreadcrumbComponent.scss [new file with mode: 0644]
src/app/layouts/breadcrumb/BreadcrumbComponent.ts [new file with mode: 0644]
src/app/layouts/header/HeaderComponent.html [new file with mode: 0644]
src/app/layouts/header/HeaderComponent.scss [new file with mode: 0644]
src/app/layouts/header/HeaderComponent.ts [new file with mode: 0644]
src/app/layouts/sidebar/SidebarComponent.html [new file with mode: 0644]
src/app/layouts/sidebar/SidebarComponent.scss [new file with mode: 0644]
src/app/layouts/sidebar/SidebarComponent.ts [new file with mode: 0644]
src/app/login/LoginComponent.html [new file with mode: 0644]
src/app/login/LoginComponent.scss [new file with mode: 0644]
src/app/login/LoginComponent.ts [new file with mode: 0644]
src/app/packages/PackagesComponent.html [new file with mode: 0644]
src/app/packages/PackagesComponent.scss [new file with mode: 0644]
src/app/packages/PackagesComponent.ts [new file with mode: 0644]
src/app/packages/PackagesModule.ts [new file with mode: 0644]
src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.html [new file with mode: 0644]
src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.scss [new file with mode: 0644]
src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.ts [new file with mode: 0644]
src/app/packages/instantiate-ns/InstantiateNsComponent.html [new file with mode: 0644]
src/app/packages/instantiate-ns/InstantiateNsComponent.scss [new file with mode: 0644]
src/app/packages/instantiate-ns/InstantiateNsComponent.ts [new file with mode: 0644]
src/app/packages/netslice-template/NetsliceTemplateComponent.html [new file with mode: 0644]
src/app/packages/netslice-template/NetsliceTemplateComponent.scss [new file with mode: 0644]
src/app/packages/netslice-template/NetsliceTemplateComponent.ts [new file with mode: 0644]
src/app/packages/ns-packages/NSPackagesComponent.html [new file with mode: 0644]
src/app/packages/ns-packages/NSPackagesComponent.scss [new file with mode: 0644]
src/app/packages/ns-packages/NSPackagesComponent.ts [new file with mode: 0644]
src/app/packages/ns-packages/ns-composer/NSComposerComponent.html [new file with mode: 0644]
src/app/packages/ns-packages/ns-composer/NSComposerComponent.scss [new file with mode: 0644]
src/app/packages/ns-packages/ns-composer/NSComposerComponent.ts [new file with mode: 0644]
src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.html [new file with mode: 0644]
src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.scss [new file with mode: 0644]
src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.ts [new file with mode: 0644]
src/app/packages/show-content/ShowContentComponent.html [new file with mode: 0644]
src/app/packages/show-content/ShowContentComponent.scss [new file with mode: 0644]
src/app/packages/show-content/ShowContentComponent.ts [new file with mode: 0644]
src/app/packages/vnf-packages/VNFPackagesComponent.html [new file with mode: 0644]
src/app/packages/vnf-packages/VNFPackagesComponent.scss [new file with mode: 0644]
src/app/packages/vnf-packages/VNFPackagesComponent.ts [new file with mode: 0644]
src/app/page-not-found/PageNotFoundComponent.html [new file with mode: 0644]
src/app/page-not-found/PageNotFoundComponent.scss [new file with mode: 0644]
src/app/page-not-found/PageNotFoundComponent.ts [new file with mode: 0644]
src/app/projects/ProjectsComponent.html [new file with mode: 0644]
src/app/projects/ProjectsComponent.scss [new file with mode: 0644]
src/app/projects/ProjectsComponent.ts [new file with mode: 0644]
src/app/projects/ProjectsModule.ts [new file with mode: 0644]
src/app/projects/project-create-update/ProjectCreateUpdateComponent.html [new file with mode: 0644]
src/app/projects/project-create-update/ProjectCreateUpdateComponent.scss [new file with mode: 0644]
src/app/projects/project-create-update/ProjectCreateUpdateComponent.ts [new file with mode: 0644]
src/app/roles/RolesComponent.html [new file with mode: 0644]
src/app/roles/RolesComponent.scss [new file with mode: 0644]
src/app/roles/RolesComponent.ts [new file with mode: 0644]
src/app/roles/RolesModule.ts [new file with mode: 0644]
src/app/roles/roles-create-edit/RolesCreateEditComponent.html [new file with mode: 0644]
src/app/roles/roles-create-edit/RolesCreateEditComponent.scss [new file with mode: 0644]
src/app/roles/roles-create-edit/RolesCreateEditComponent.ts [new file with mode: 0644]
src/app/roles/roles-details/RolesDetailsComponent.html [new file with mode: 0644]
src/app/roles/roles-details/RolesDetailsComponent.scss [new file with mode: 0644]
src/app/roles/roles-details/RolesDetailsComponent.ts [new file with mode: 0644]
src/app/sdn-controller/SDNControllerComponent.html [new file with mode: 0644]
src/app/sdn-controller/SDNControllerComponent.scss [new file with mode: 0644]
src/app/sdn-controller/SDNControllerComponent.ts [new file with mode: 0644]
src/app/sdn-controller/SDNControllerModule.ts [new file with mode: 0644]
src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.html [new file with mode: 0644]
src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.scss [new file with mode: 0644]
src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.ts [new file with mode: 0644]
src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.html [new file with mode: 0644]
src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.scss [new file with mode: 0644]
src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.ts [new file with mode: 0644]
src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.html [new file with mode: 0644]
src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.scss [new file with mode: 0644]
src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.ts [new file with mode: 0644]
src/app/user-settings/UserSettingsComponent.html [new file with mode: 0644]
src/app/user-settings/UserSettingsComponent.scss [new file with mode: 0644]
src/app/user-settings/UserSettingsComponent.ts [new file with mode: 0644]
src/app/users/UsersComponent.html [new file with mode: 0644]
src/app/users/UsersComponent.scss [new file with mode: 0644]
src/app/users/UsersComponent.ts [new file with mode: 0644]
src/app/users/UsersModule.ts [new file with mode: 0644]
src/app/users/add-user/AddEditUserComponent.html [new file with mode: 0644]
src/app/users/add-user/AddEditUserComponent.scss [new file with mode: 0644]
src/app/users/add-user/AddEditUserComponent.ts [new file with mode: 0644]
src/app/users/project-role/ProjectRoleComponent.html [new file with mode: 0644]
src/app/users/project-role/ProjectRoleComponent.scss [new file with mode: 0644]
src/app/users/project-role/ProjectRoleComponent.ts [new file with mode: 0644]
src/app/users/user-details/UserDetailsComponent.html [new file with mode: 0644]
src/app/users/user-details/UserDetailsComponent.scss [new file with mode: 0644]
src/app/users/user-details/UserDetailsComponent.ts [new file with mode: 0644]
src/app/utilities/clone-package/ClonePackageComponent.html [new file with mode: 0644]
src/app/utilities/clone-package/ClonePackageComponent.scss [new file with mode: 0644]
src/app/utilities/clone-package/ClonePackageComponent.ts [new file with mode: 0644]
src/app/utilities/compose-packages/ComposePackages.html [new file with mode: 0644]
src/app/utilities/compose-packages/ComposePackages.scss [new file with mode: 0644]
src/app/utilities/compose-packages/ComposePackages.ts [new file with mode: 0644]
src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.html [new file with mode: 0644]
src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.scss [new file with mode: 0644]
src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.ts [new file with mode: 0644]
src/app/utilities/delete/DeleteComponent.html [new file with mode: 0644]
src/app/utilities/delete/DeleteComponent.scss [new file with mode: 0644]
src/app/utilities/delete/DeleteComponent.ts [new file with mode: 0644]
src/app/utilities/dragDropUpload/DragDirective.ts [new file with mode: 0644]
src/app/utilities/edit-packages/EditPackagesComponent.html [new file with mode: 0644]
src/app/utilities/edit-packages/EditPackagesComponent.scss [new file with mode: 0644]
src/app/utilities/edit-packages/EditPackagesComponent.ts [new file with mode: 0644]
src/app/utilities/loader/LoaderComponent.html [new file with mode: 0644]
src/app/utilities/loader/LoaderComponent.scss [new file with mode: 0644]
src/app/utilities/loader/LoaderComponent.ts [new file with mode: 0644]
src/app/utilities/loader/LoaderModule.ts [new file with mode: 0644]
src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.html [new file with mode: 0644]
src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.scss [new file with mode: 0644]
src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.ts [new file with mode: 0644]
src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.html [new file with mode: 0644]
src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.scss [new file with mode: 0644]
src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.ts [new file with mode: 0644]
src/app/utilities/ns-instances-action/NSInstancesActionComponent.html [new file with mode: 0644]
src/app/utilities/ns-instances-action/NSInstancesActionComponent.scss [new file with mode: 0644]
src/app/utilities/ns-instances-action/NSInstancesActionComponent.ts [new file with mode: 0644]
src/app/utilities/ns-packages-action/NsPackagesActionComponent.html [new file with mode: 0644]
src/app/utilities/ns-packages-action/NsPackagesActionComponent.scss [new file with mode: 0644]
src/app/utilities/ns-packages-action/NsPackagesActionComponent.ts [new file with mode: 0644]
src/app/utilities/page-per-row/PagePerRow.html [new file with mode: 0644]
src/app/utilities/page-per-row/PagePerRow.scss [new file with mode: 0644]
src/app/utilities/page-per-row/PagePerRow.ts [new file with mode: 0644]
src/app/utilities/page-per-row/PagePerRowModule.ts [new file with mode: 0644]
src/app/utilities/page-reload/PageReload.html [new file with mode: 0644]
src/app/utilities/page-reload/PageReload.scss [new file with mode: 0644]
src/app/utilities/page-reload/PageReload.ts [new file with mode: 0644]
src/app/utilities/page-reload/PageReloadModule.ts [new file with mode: 0644]
src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.html [new file with mode: 0644]
src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.scss [new file with mode: 0644]
src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.ts [new file with mode: 0644]
src/app/utilities/project-link/ProjectLinkComponent.html [new file with mode: 0644]
src/app/utilities/project-link/ProjectLinkComponent.scss [new file with mode: 0644]
src/app/utilities/project-link/ProjectLinkComponent.ts [new file with mode: 0644]
src/app/utilities/projects-action/ProjectsActionComponent.html [new file with mode: 0644]
src/app/utilities/projects-action/ProjectsActionComponent.scss [new file with mode: 0644]
src/app/utilities/projects-action/ProjectsActionComponent.ts [new file with mode: 0644]
src/app/utilities/roles-action/RolesActionComponent.html [new file with mode: 0644]
src/app/utilities/roles-action/RolesActionComponent.scss [new file with mode: 0644]
src/app/utilities/roles-action/RolesActionComponent.ts [new file with mode: 0644]
src/app/utilities/sdn-controller-action/SDNControllerActionComponent.html [new file with mode: 0644]
src/app/utilities/sdn-controller-action/SDNControllerActionComponent.scss [new file with mode: 0644]
src/app/utilities/sdn-controller-action/SDNControllerActionComponent.ts [new file with mode: 0644]
src/app/utilities/show-info/ShowInfoComponent.html [new file with mode: 0644]
src/app/utilities/show-info/ShowInfoComponent.scss [new file with mode: 0644]
src/app/utilities/show-info/ShowInfoComponent.ts [new file with mode: 0644]
src/app/utilities/switch-project/SwitchProjectComponent.html [new file with mode: 0644]
src/app/utilities/switch-project/SwitchProjectComponent.scss [new file with mode: 0644]
src/app/utilities/switch-project/SwitchProjectComponent.ts [new file with mode: 0644]
src/app/utilities/users-action/UsersActionComponent.html [new file with mode: 0644]
src/app/utilities/users-action/UsersActionComponent.scss [new file with mode: 0644]
src/app/utilities/users-action/UsersActionComponent.ts [new file with mode: 0644]
src/app/utilities/vim-accounts-action/VimAccountsActionComponent.html [new file with mode: 0644]
src/app/utilities/vim-accounts-action/VimAccountsActionComponent.scss [new file with mode: 0644]
src/app/utilities/vim-accounts-action/VimAccountsActionComponent.ts [new file with mode: 0644]
src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.html [new file with mode: 0644]
src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.scss [new file with mode: 0644]
src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.ts [new file with mode: 0644]
src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.html [new file with mode: 0644]
src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.scss [new file with mode: 0644]
src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.ts [new file with mode: 0644]
src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.html [new file with mode: 0644]
src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.scss [new file with mode: 0644]
src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.ts [new file with mode: 0644]
src/app/vim-accounts/VimAccountsComponent.html [new file with mode: 0644]
src/app/vim-accounts/VimAccountsComponent.scss [new file with mode: 0644]
src/app/vim-accounts/VimAccountsComponent.ts [new file with mode: 0644]
src/app/vim-accounts/VimAccountsModule.ts [new file with mode: 0644]
src/app/vim-accounts/info-vim/InfoVimComponent.html [new file with mode: 0644]
src/app/vim-accounts/info-vim/InfoVimComponent.scss [new file with mode: 0644]
src/app/vim-accounts/info-vim/InfoVimComponent.ts [new file with mode: 0644]
src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.html [new file with mode: 0644]
src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.scss [new file with mode: 0644]
src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.ts [new file with mode: 0644]
src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.html [new file with mode: 0644]
src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.scss [new file with mode: 0644]
src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.ts [new file with mode: 0644]
src/app/wim-accounts/WIMAccountsComponent.html [new file with mode: 0644]
src/app/wim-accounts/WIMAccountsComponent.scss [new file with mode: 0644]
src/app/wim-accounts/WIMAccountsComponent.ts [new file with mode: 0644]
src/app/wim-accounts/WIMAccountsModule.ts [new file with mode: 0644]
src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.html [new file with mode: 0644]
src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.scss [new file with mode: 0644]
src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.ts [new file with mode: 0644]
src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.html [new file with mode: 0644]
src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.scss [new file with mode: 0644]
src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.ts [new file with mode: 0644]
src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.html [new file with mode: 0644]
src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.scss [new file with mode: 0644]
src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.ts [new file with mode: 0644]
src/assets/config/rolePermissions.json [new file with mode: 0644]
src/assets/i18n/de.json [new file with mode: 0644]
src/assets/i18n/en.json [new file with mode: 0644]
src/assets/i18n/es.json [new file with mode: 0644]
src/assets/i18n/pt.json [new file with mode: 0644]
src/assets/images/CP-VNF.svg [new file with mode: 0644]
src/assets/images/CP.svg [new file with mode: 0644]
src/assets/images/INTCP.svg [new file with mode: 0644]
src/assets/images/INTVL.svg [new file with mode: 0644]
src/assets/images/TICK.svg [new file with mode: 0644]
src/assets/images/VDU.svg [new file with mode: 0644]
src/assets/images/VL.svg [new file with mode: 0644]
src/assets/images/VNFD.svg [new file with mode: 0644]
src/assets/images/login_background.jpg [new file with mode: 0644]
src/assets/images/logo.png [new file with mode: 0644]
src/assets/images/map-icon.png [new file with mode: 0644]
src/assets/images/page-not-found.jpg [new file with mode: 0644]
src/assets/js/tar.js [new file with mode: 0644]
src/assets/scss/app.scss [new file with mode: 0644]
src/assets/scss/mixins/_animation.scss [new file with mode: 0644]
src/assets/scss/mixins/_background.scss [new file with mode: 0644]
src/assets/scss/mixins/_border.scss [new file with mode: 0644]
src/assets/scss/mixins/_box-shadow.scss [new file with mode: 0644]
src/assets/scss/mixins/_custom.scss [new file with mode: 0644]
src/assets/scss/mixins/_flex.scss [new file with mode: 0644]
src/assets/scss/mixins/_font-weight.scss [new file with mode: 0644]
src/assets/scss/mixins/_position.scss [new file with mode: 0644]
src/assets/scss/mixins/_rem.scss [new file with mode: 0644]
src/assets/scss/mixins/_rounded-corners.scss [new file with mode: 0644]
src/assets/scss/mixins/_transform.scss [new file with mode: 0644]
src/assets/scss/mixins/_transition.scss [new file with mode: 0644]
src/assets/scss/mixins/mixin.scss [new file with mode: 0644]
src/assets/scss/style.scss [new file with mode: 0644]
src/assets/scss/variable.scss [new file with mode: 0644]
src/directive/GoToTopDirective.ts [new file with mode: 0644]
src/environments/environment.prod.ts [new file with mode: 0644]
src/environments/environment.ts [new file with mode: 0644]
src/favicon.ico [new file with mode: 0644]
src/index.html [new file with mode: 0644]
src/karma.conf.js [new file with mode: 0644]
src/main.ts [new file with mode: 0644]
src/models/CommonModel.ts [new file with mode: 0644]
src/models/K8sModel.ts [new file with mode: 0644]
src/models/MenuModel.ts [new file with mode: 0644]
src/models/NSDModel.ts [new file with mode: 0644]
src/models/NSInstanceModel.ts [new file with mode: 0644]
src/models/NSTopologyModel.ts [new file with mode: 0644]
src/models/NetworkSliceModel.ts [new file with mode: 0644]
src/models/PDUInstanceModel.ts [new file with mode: 0644]
src/models/ProjectModel.ts [new file with mode: 0644]
src/models/RoleModel.ts [new file with mode: 0644]
src/models/SDNControllerModel.ts [new file with mode: 0644]
src/models/UserModel.ts [new file with mode: 0644]
src/models/VNFDModel.ts [new file with mode: 0644]
src/models/VNFInstanceModel.ts [new file with mode: 0644]
src/models/VimAccountModel.ts [new file with mode: 0644]
src/models/WIMAccountModel.ts [new file with mode: 0644]
src/polyfills.ts [new file with mode: 0644]
src/services/AcessGuardService.ts [new file with mode: 0644]
src/services/AuthGuardService.ts [new file with mode: 0644]
src/services/AuthInterceptorService.ts [new file with mode: 0644]
src/services/AuthenticationService.ts [new file with mode: 0644]
src/services/DataService.ts [new file with mode: 0644]
src/services/DeviceCheckService.ts [new file with mode: 0644]
src/services/ProjectService.ts [new file with mode: 0644]
src/services/RestService.ts [new file with mode: 0644]
src/services/SharedService.ts [new file with mode: 0644]
src/test.ts [new file with mode: 0644]
src/tsconfig.app.json [new file with mode: 0644]
src/tsconfig.spec.json [new file with mode: 0644]
src/tslint.json [new file with mode: 0644]
tsconfig.json [new file with mode: 0644]
tslint.json [new file with mode: 0644]

diff --git a/.editorconfig b/.editorconfig
new file mode 100644 (file)
index 0000000..3903e75
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2020 TATA ELXSI
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..9a88115
--- /dev/null
@@ -0,0 +1,61 @@
+# Copyright 2020 TATA ELXSI
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# compiled output
+/dist
+/tmp
+/out-tsc
+
+# dependencies
+/node_modules
+package-lock.json
+
+# profiling files
+chrome-profiler-events.json
+speed-measure-plugin.json
+
+# IDEs and editors
+/.idea
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# IDE - VSCode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+
+# misc
+/.sass-cache
+/connect.lock
+/coverage
+/libpeerconnection.log
+npm-debug.log
+yarn-error.log
+testem.log
+/typings
+
+# System Files
+.DS_Store
+Thumbs.db
index 54f0fd5..e7c221b 100644 (file)
@@ -1,5 +1,3 @@
-# Copyright 2020 ETSI
-#
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM ubuntu:18.04
+# This Dockerfile is intented for devops and deb package generation
+#
+# Use Dockerfile.local for running osm/NBI in a docker container from source
+# Use Dockerfile.fromdeb for running osm/NBI in a docker container from last stable package
+
+
+FROM ubuntu:16.04
 
 
-RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install git \
-    make python3 debhelper python3-setuptools apt-utils
+RUN apt-get update && apt-get -y install git make libcurl4-gnutls-dev \
+    libgnutls-dev debhelper apt-utils dh-make
+       
+       
\ No newline at end of file
index 9f1db33..a2117a0 100644 (file)
--- a/README.md
+++ b/README.md
 <!--
 <!--
-Copyright 2020 ETSI
+Copyright 2020 TATA ELXSI
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
-   http://www.apache.org/licenses/LICENSE-2.0
+    http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-implied.
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 See the License for the specific language governing permissions and
-limitations under the License
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
 -->
 -->
-# Project Title
 
 
-One Paragraph of project description goes here
+## Angular Based OSM NG UI
+This project focuses on the implementation of a web GUI to interact with the Northbound API of OSM. 
+
+The project is based on ([Angular](https://angular.io/)), a One framework for Mobile & desktop, app-design framework and development platform for creating efficient and sophisticated single-page web apps.
+
+## Table of Contents
+
+* [Community](#community)
+* [Getting Started](#getting-started)
+* [Prerequisites](#prerequisites)
+* [Installation](#installation)
+* [Running the application](#running-the-application)
+* [Check the lint](#check-the-lint)
+* [Supported Browsers](#supported-browsers)
+* [Deployment](#deployment)
+* [Built With](#built-with)
+* [Contributing](#contributing)
+* [Versioning](#versioning)
+* [License](#license)
+
+## Community
+
+Contact [kumaran.m@tataelxsi.co.in](mailto:kumaran.m@tataelxsi.co.in), [rajesh.s@tataelxsi.co.in](mailto:rajesh.s@tataelxsi.co.in), [barath.r@tataelxsi.co.in](mailto:barath.r@tataelxsi.co.in) for architecture and design discussions, requests for help, features request and bug reports on NG UI. 
 
 ## Getting Started
 
 
 ## Getting Started
 
-These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
+Following instructions in the sections below will get you a copy of the project up and running on your local machine for development and testing purposes. See Deployment section for notes on how to deploy the project on a live system.
 
 ### Prerequisites
 
 
 ### Prerequisites
 
-What things you need to install the software and how to install them
+Angular Setup, Install, & Build Guide
 
 
-```
-Give examples
-```
+1. Install Node.js from [here](https://nodejs.org/en/download/)
+To check if nodejs is installed on your system, type below command. This will help you see the version of nodejs currently installed on your system.
+`node -version`
+After downloading Node.js, the node package manager (npm) should automatically be installed. Test it out by doing:
+`npm --version`
+2. Install Angluar CLI. [More details](https://cli.angular.io/) Angular can be installed Globally (or) Locally,
+Install Globally
+`npm install -g @angular/cli`
+Install Locally
+`npm install @angular/cli`
+After installation done you can check the version using below command. It will display version details of angular-cli
+`ng version`
 
 
-### Installing
+We are done with the installation of Angular
 
 
-A step by step series of examples that tell you how to get a development env running
+### Installation
 
 
-Say what the step will be
+Clone the NG UI from the repository
 
 
-```
-Give the example
-```
+`git clone "https://osm.etsi.org/gerrit/osm/NG-UI"`
 
 
-And repeat
+Install the packages
 
 
-```
-until finished
-```
+`cd NG-UI`
 
 
-End with an example of getting some data out of the system or using it for a little demo
+`npm install`
 
 
-## Running the tests
+### Running the application
 
 
-Explain how to run the automated tests for this system
+The following instructions is for running NG UI locally for development purpose,
 
 
+On the folder project
+
+Open `proxy.conf.json`
+
+Add the below code
+```typescript
+{
+    "/osm/*": {
+        "target": "https://OSM-NBI-IP:9999",
+        "secure": false,
+        "logLevel": "info"
+    }
+}
 ```
 ```
-Give an example
-```
+To run the application give the below command
+
+`npm run proxy`
+- To Run the NG-UI page Navigate to <http://localhost:4200/>
+
+## Check the lint
+
+To check the typescript lint run the below command
+
+`npm run lint`
+
+## Supported Browsers
+
+- Edge (42.17134.1098.0) and IE 11 (Windows)
+- Firefox (75.0)(Ubunutu)
+- Firefox (75.0)(Windows)
+- Chrome (81.0.4044.92) (Ubunutu)
+- Chrome (81.0.4044.122) (Windows)
 
 ## Deployment
 
 
 ## Deployment
 
-Add additional notes about how to deploy this on a live system
+To deploy the NG UI use the [Dockerfile](Dockerfile)
 
 ## Built With
 
 
 ## Built With
 
-* [Python](www.python.org/) - The language used
+* [Angular Frame work](https://angular.io/) - The languages used are Javascript, Typescript, HTML, and SCSS
 
 ## Contributing
 
 
 ## Contributing
 
@@ -75,4 +131,3 @@ We use [SemVer](http://semver.org/) for versioning. For the versions available,
 ## License
 
 This project is licensed under the Apache2 License - see the [LICENSE.md](LICENSE) file for details
 ## License
 
 This project is licensed under the Apache2 License - see the [LICENSE.md](LICENSE) file for details
-
diff --git a/angular.json b/angular.json
new file mode 100644 (file)
index 0000000..5420910
--- /dev/null
@@ -0,0 +1,145 @@
+{
+    "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+    "version": 1,
+    "newProjectRoot": "projects",
+    "projects": {
+        "osm": {
+            "root": "",
+            "sourceRoot": "src",
+            "projectType": "application",
+            "prefix": "app",
+            "schematics": {
+                "@schematics/angular:component": {
+                    "styleext": "scss"
+                }
+            },
+            "architect": {
+                "build": {
+                    "builder": "@angular-devkit/build-angular:browser",
+                    "options": {
+                        "outputPath": "dist/osm",
+                        "index": "src/index.html",
+                        "main": "src/main.ts",
+                        "polyfills": "src/polyfills.ts",
+                        "tsConfig": "src/tsconfig.app.json",
+                        "assets": [
+                            "src/favicon.ico",
+                            "src/assets"
+                        ],
+                        "styles": [
+                            "src/assets/scss/style.scss",
+                            "node_modules/ol/ol.css",
+                            "node_modules/@fortawesome/fontawesome-free/css/all.min.css"
+                        ],
+                        "scripts": [
+                            "src/assets/js/tar.js"
+                        ],
+                        "es5BrowserSupport": true
+                    },
+                    "configurations": {
+                        "production": {
+                            "fileReplacements": [
+                                {
+                                    "replace": "src/environments/environment.ts",
+                                    "with": "src/environments/environment.prod.ts"
+                                }
+                            ],
+                            "optimization": true,
+                            "outputHashing": "all",
+                            "sourceMap": false,
+                            "extractCss": true,
+                            "namedChunks": false,
+                            "aot": true,
+                            "extractLicenses": true,
+                            "vendorChunk": false,
+                            "buildOptimizer": true,
+                            "budgets": [
+                                {
+                                    "type": "initial",
+                                    "maximumWarning": "2mb",
+                                    "maximumError": "5mb"
+                                }
+                            ]
+                        }
+                    }
+                },
+                "serve": {
+                    "builder": "@angular-devkit/build-angular:dev-server",
+                    "options": {
+                        "browserTarget": "osm:build"
+                    },
+                    "configurations": {
+                        "production": {
+                            "browserTarget": "osm:build:production"
+                        }
+                    }
+                },
+                "extract-i18n": {
+                    "builder": "@angular-devkit/build-angular:extract-i18n",
+                    "options": {
+                        "browserTarget": "osm:build"
+                    }
+                },
+                "test": {
+                    "builder": "@angular-devkit/build-angular:karma",
+                    "options": {
+                        "main": "src/test.ts",
+                        "polyfills": "src/polyfills.ts",
+                        "tsConfig": "src/tsconfig.spec.json",
+                        "karmaConfig": "src/karma.conf.js",
+                        "styles": [
+                            "src/styles.css",
+                            "node_modules/ol/ol.css"
+                        ],
+                        "scripts": [],
+                        "assets": [
+                            "src/favicon.ico",
+                            "src/assets"
+                        ]
+                    }
+                },
+                "lint": {
+                    "builder": "@angular-devkit/build-angular:tslint",
+                    "options": {
+                        "tsConfig": [
+                            "src/tsconfig.app.json",
+                            "src/tsconfig.spec.json"
+                        ],
+                        "exclude": [
+                            "**/node_modules/**"
+                        ]
+                    }
+                }
+            }
+        },
+        "osm-e2e": {
+            "root": "e2e/",
+            "projectType": "application",
+            "prefix": "",
+            "architect": {
+                "e2e": {
+                    "builder": "@angular-devkit/build-angular:protractor",
+                    "options": {
+                        "protractorConfig": "e2e/protractor.conf.js",
+                        "devServerTarget": "osm:serve"
+                    },
+                    "configurations": {
+                        "production": {
+                            "devServerTarget": "osm:serve:production"
+                        }
+                    }
+                },
+                "lint": {
+                    "builder": "@angular-devkit/build-angular:tslint",
+                    "options": {
+                        "tsConfig": "e2e/tsconfig.e2e.json",
+                        "exclude": [
+                            "**/node_modules/**"
+                        ]
+                    }
+                }
+            }
+        }
+    },
+    "defaultProject": "osm"
+}
\ No newline at end of file
diff --git a/browserslist b/browserslist
new file mode 100644 (file)
index 0000000..412910d
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright 2020 TATA ELXSI
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+
+# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+#
+# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11
\ No newline at end of file
index 9a0960a..07a6d43 100755 (executable)
@@ -15,8 +15,8 @@
 #    under the License.
 
 
 #    under the License.
 
 
-PKG_DIRECTORIES="lib static template"
-PKG_FILES="LICENSE README.md"
+PKG_DIRECTORIES="nginx src"
+PKG_FILES="angular.json browserslist CONTRIBUTING.md package.json proxy.conf.json tsconfig.json tslint.json LICENSE README.md"
 MDG_NAME=ngui
 DEB_INSTALL=debian/osm-${MDG_NAME}.install
 export DEBEMAIL="gerardo.garciadeblas@telefonica.com"
 MDG_NAME=ngui
 DEB_INSTALL=debian/osm-${MDG_NAME}.install
 export DEBEMAIL="gerardo.garciadeblas@telefonica.com"
@@ -52,5 +52,3 @@ pushd $PKG_DIR
 dh_make -y --indep --createorig --a -c apache
 dpkg-buildpackage -uc -us -tc -rfakeroot
 popd
 dh_make -y --indep --createorig --a -c apache
 dpkg-buildpackage -uc -us -tc -rfakeroot
 popd
-
-
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644 (file)
index 0000000..78643d4
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright 2020 TATA ELXSI
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in), VIJAY NAG (vijaynag.bs@tataelxsi.co.in)
+
+FROM ubuntu:16.04
+# Installing node dependencies.
+RUN apt-get update && apt-get install -y curl xz-utils gnupg2 \
+    && apt-get update && apt-get install -y apt-transport-https \
+    && curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - \
+    && echo "deb https://deb.nodesource.com/node_10.x xenial main" | tee -a /etc/apt/sources.list.d/nodesource.list \
+    && echo "deb-src https://deb.nodesource.com/node_10.x xenial main" | tee -a /etc/apt/sources.list.d/nodesource.list \
+    && apt-get update && apt-get install -y nodejs \
+    && apt-get install -y nginx
+
+# Preparing working environment.
+RUN mkdir -p /usr/src/osm-angularapp
+WORKDIR /usr/src/osm-angularapp
+
+# Installing dependencies.
+COPY ./package.json /usr/src/osm-angularapp/
+RUN npm install
+
+# Copy osm-angularapp source into image.
+COPY ./ /usr/src/osm-angularapp
+
+# Building app.
+RUN npm run build
+
+# Removing nginx default page.
+RUN rm -rf /usr/share/nginx/html/*
+
+# Copying nginx configuration.
+COPY nginx/nginx.conf /etc/nginx/sites-available/default
+RUN cp -r /usr/src/osm-angularapp/dist/osm/* /usr/share/nginx/html
+
+# Exposing ports.
+EXPOSE 80
+
+# Starting server.
+CMD ["nginx", "-g", "daemon off;"]
+
diff --git a/nginx/nginx.conf b/nginx/nginx.conf
new file mode 100644 (file)
index 0000000..d686603
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright 2020 TATA ELXSI
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+
+server {
+    listen       80;
+    server_name  localhost;
+    root   /usr/share/nginx/html;
+    index  index.html index.htm;
+    client_max_body_size 15M;
+
+    location /osm {
+        proxy_pass https://nbi:9999;
+        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
+        proxy_set_header Accept-Encoding "";
+    }
+
+    location / {
+        try_files $uri $uri/ /index.html;
+    }
+}
diff --git a/package.json b/package.json
new file mode 100644 (file)
index 0000000..fc1d601
--- /dev/null
@@ -0,0 +1,91 @@
+{
+  "name": "osm",
+  "version": "1.0.2",
+  "scripts": {
+    "ng": "ng",
+    "start": "ng serve",
+    "build": "ng build --prod --aot",
+    "test": "ng test",
+    "lint": "tslint --type-check --project tsconfig.json -c tslint.json",
+    "e2e": "ng e2e",
+    "proxy": "ng serve --proxy-config proxy.conf.json"
+  },
+  "private": true,
+  "dependencies": {
+    "@akveo/ng2-completer": "^9.0.1",
+    "@angular/animations": "~9.1.0",
+    "@angular/cdk": "^7.3.7",
+    "@angular/common": "~9.1.0",
+    "@angular/compiler": "~9.1.0",
+    "@angular/core": "~9.1.0",
+    "@angular/flex-layout": "^9.0.0-beta.29",
+    "@angular/forms": "~9.1.0",
+    "@angular/localize": "^9.1.2",
+    "@angular/platform-browser": "~9.1.0",
+    "@angular/platform-browser-dynamic": "~9.1.0",
+    "@angular/router": "~9.1.0",
+    "@ctrl/ngx-codemirror": "^2.2.1",
+    "@fortawesome/fontawesome-free": "^5.13.0",
+    "@ng-bootstrap/ng-bootstrap": "^5.3.0",
+    "@ng-idle/core": "^8.0.0-beta.4",
+    "@ng-idle/keepalive": "^8.0.0-beta.4",
+    "@ng-select/ng-select": "^3.7.3",
+    "@ngx-translate/core": "^12.1.2",
+    "@ngx-translate/http-loader": "^4.0.0",
+    "@nomadreservations/ngx-codemirror": "^2.0.0",
+    "@types/d3": "^5.7.2",
+    "@types/js-yaml": "^3.12.1",
+    "@types/jsonpath": "^0.2.0",
+    "@types/ol": "^5.3.5",
+    "angular-notifier": "^6.0.1",
+    "bootstrap": "^4.4.1",
+    "chart.js": "^2.8.0",
+    "codemirror": "^5.51.0",
+    "core-js": "^2.5.4",
+    "d3": "^5.9.2",
+    "http-status-codes": "^1.3.2",
+    "js-untar": "^2.0.0",
+    "js-yaml": "^3.13.1",
+    "jsonpath": "^1.0.2",
+    "ng-sidebar": "^9.2.0",
+    "ng2-charts": "^3.0.0-beta.5",
+    "ng2-file-upload": "^1.3.0",
+    "ng2-smart-table": "^1.6.0",
+    "ol": "^5.3.3",
+    "pako": "^1.0.10",
+    "roboto-fontface": "^0.10.0",
+    "rxjs": "^6.5.4",
+    "rxjs-compat": "^6.5.5",
+    "stream": "0.0.2",
+    "text-encoding": "^0.7.0",
+    "tslib": "^1.11.1",
+    "web-animations-js": "^2.3.2",
+    "zone.js": "~0.10.3"
+  },
+  "devDependencies": {
+    "@angular-devkit/build-angular": "~0.901.0",
+    "@angular/cli": "~9.1.0",
+    "@angular/compiler-cli": "~9.1.0",
+    "@angular/language-service": "~9.1.0",
+    "@types/jasmine": "~2.8.8",
+    "@types/jasminewd2": "~2.0.3",
+    "@types/jquery": "^3.3.31",
+    "@types/node": "^8.10.59",
+    "codelyzer": "^5.0.1",
+    "jasmine-core": "~2.99.1",
+    "jasmine-spec-reporter": "~4.2.1",
+    "karma": "~3.1.1",
+    "karma-chrome-launcher": "~2.2.0",
+    "karma-coverage-istanbul-reporter": "~2.0.1",
+    "karma-jasmine": "~1.1.2",
+    "karma-jasmine-html-reporter": "^0.2.2",
+    "ng2-completer": "^3.0.3",
+    "node-sass": "^4.14.1",
+    "protractor": "~5.4.0",
+    "ts-node": "~7.0.0",
+    "tslint": "^5.11.0",
+    "tslint-html-report": "^2.0.3",
+    "tslint-microsoft-contrib": "^6.1.1",
+    "typescript": "~3.8.3"
+  }
+}
diff --git a/proxy.conf.json b/proxy.conf.json
new file mode 100644 (file)
index 0000000..e6a63c6
--- /dev/null
@@ -0,0 +1,7 @@
+{
+    "/osm/*": {
+        "target": "https://nbi:9999",
+        "secure": false,
+        "logLevel": "info"
+    }
+}
\ No newline at end of file
diff --git a/src/app/AppComponent.html b/src/app/AppComponent.html
new file mode 100644 (file)
index 0000000..bee03c8
--- /dev/null
@@ -0,0 +1,19 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<router-outlet> </router-outlet>
+<notifier-container></notifier-container>
\ No newline at end of file
diff --git a/src/app/AppComponent.scss b/src/app/AppComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/AppComponent.ts b/src/app/AppComponent.ts
new file mode 100644 (file)
index 0000000..04ad8d8
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+
+/**
+ * @file App Components
+ */
+import { Component, HostListener, Injector } from '@angular/core';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { DEFAULT_INTERRUPTSOURCES, Idle } from '@ng-idle/core';
+import { AuthenticationService } from 'AuthenticationService';
+import { DeviceCheckService } from 'DeviceCheckService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes AppComponent.html as template url
+ */
+@Component({
+    selector: 'app-root',
+    templateUrl: './AppComponent.html',
+    styleUrls: ['./AppComponent.scss']
+})
+/** Exporting a class @exports AppComponent */
+export class AppComponent {
+    /** To inject services @public */
+    public injector: Injector;
+    /** Instance for modal service @public */
+    public modalService: NgbModal;
+    /** Device Check service @private */
+    private deviceCheckService: DeviceCheckService;
+    /** Utilizes auth service for any auth operations @private */
+    private authService: AuthenticationService;
+    /** Handle idle time out service @private */
+    private idle: Idle;
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.idle = this.injector.get(Idle);
+        this.authService = this.injector.get(AuthenticationService);
+        this.modalService = this.injector.get(NgbModal);
+        this.deviceCheckService = this.injector.get(DeviceCheckService);
+        this.handleIdle();
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.sharedService.fetchOSMVersion();
+    }
+
+    /** To handle handleIdle @public */
+    public handleIdle(): void {
+        const idleTime: number = 1200;
+        const idleTimeOutWarning: number = 5;
+        //  sets an idle timeout in seconds.
+        this.idle.setIdle(idleTime);
+        //sets a timeout period in seconds. after idleTime seconds of inactivity, the user will be considered timed out.
+        this.idle.setTimeout(idleTimeOutWarning);
+        // sets the default interrupts, in this case, things like clicks, scrolls, touches to the document
+        this.idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);
+        this.idle.watch(true);
+        this.idleTimeOut();
+    }
+
+    /** Method to capture idle time out event @public */
+    public idleTimeOut(): void {
+        this.idle.onTimeout.subscribe(() => {
+            this.idle.stop();
+            if (localStorage.getItem('id_token') !== null) {
+                this.authService.logout();
+            }
+        });
+    }
+
+    /** Handling Window's Storage Hostlistener @public */
+    @HostListener('window:storage', ['$event'])
+    public handleLocalStorageEvent(evt: StorageEvent): void {
+        // On Token Change
+        if (evt.key === 'token_state' && !isNullOrUndefined(evt.key)) {
+            if (evt.oldValue !== evt.newValue) {
+                window.location.reload();
+            }
+        }
+        // On Langauges Change
+        if (evt.key === 'languageCode' && !isNullOrUndefined(evt.key)) {
+            if (evt.oldValue !== evt.newValue) {
+                window.location.reload();
+            }
+        }
+    }
+
+    /** Handling Window's POP State Hostlistener @public */
+    @HostListener('window:popstate', ['$event'])
+    public handleOnPOPState(evt: PopStateEvent): void {
+        this.modalService.dismissAll();
+    }
+
+    /** Handling Window's orientationchange Hostlistener @public */
+    @HostListener('window:resize', ['$event'])
+    public onResize(event: Event): void {
+        this.deviceCheckService.checkDeviceType();
+    }
+}
diff --git a/src/app/AppModule.ts b/src/app/AppModule.ts
new file mode 100644 (file)
index 0000000..02fa736
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Instance Module file
+ */
+import { CommonModule, LOCATION_INITIALIZED } from '@angular/common';
+import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
+import { APP_INITIALIZER, Injector, NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { BrowserModule } from '@angular/platform-browser';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { RouterModule } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
+import { TranslateHttpLoader } from '@ngx-translate/http-loader';
+import { NotifierModule, NotifierOptions } from 'angular-notifier';
+import { AuthInterceptorService } from 'AuthInterceptorService';
+import { HeaderComponent } from 'HeaderComponent';
+import { LayoutComponent } from 'LayoutComponent';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { SidebarComponent } from 'SidebarComponent';
+import { AppComponent } from './AppComponent';
+
+import { appRoutes } from './approutes.module';
+
+import { DataService } from 'DataService';
+import { ProjectService } from 'ProjectService';
+import { SharedService } from 'SharedService';
+
+import { CodemirrorModule } from '@ctrl/ngx-codemirror';
+import { NgSelectModule } from '@ng-select/ng-select';
+
+import { NgIdleKeepaliveModule } from '@ng-idle/keepalive';
+import { AuthenticationService } from 'AuthenticationService';
+import { AuthGuardService } from 'AuthGuardService';
+import { BreadcrumbComponent } from 'BreadCrumb';
+import { ComposePackages } from 'ComposePackages';
+import { ConfirmationTopologyComponent } from 'ConfirmationTopology';
+import { DeleteComponent } from 'DeleteComponent';
+import { DeviceCheckService } from 'DeviceCheckService';
+import { GoToTopDirective } from 'GoToTopDirective';
+import { InstantiateNetSliceTemplateComponent } from 'InstantiateNetSliceTemplate';
+import { InstantiateNsComponent } from 'InstantiateNs';
+import { LoaderModule } from 'LoaderModule';
+import { LoginComponent } from 'LoginComponent';
+import { NetsliceInstancesActionComponent } from 'NetsliceInstancesActionComponent';
+import { NetslicePackagesActionComponent } from 'NetslicePackagesAction';
+import { NSInstancesActionComponent } from 'NSInstancesActionComponent';
+import { NsPackagesActionComponent } from 'NsPackagesAction';
+import { PageNotFoundComponent } from 'PageNotFound';
+import { PDUInstancesActionComponent } from 'PDUInstancesActionComponent';
+import { ProjectLinkComponent } from 'ProjectLinkComponent';
+import { ProjectsActionComponent } from 'ProjectsAction';
+import { SDNControllerActionComponent } from 'SDNControllerActionComponent';
+import { ShowInfoComponent } from 'ShowInfoComponent';
+import { SwitchProjectComponent } from 'SwitchProjectComponent';
+import { UsersActionComponent } from 'UsersActionComponent';
+import { UserSettingsComponent } from 'UserSettingsComponent';
+import { VimAccountsActionComponent } from 'VimAccountsAction';
+import { VNFInstancesActionComponent } from 'VNFInstancesActionComponent';
+import { VNFLinkComponent } from 'VNFLinkComponent';
+import { VNFPackagesActionComponent } from 'VNFPackagesAction';
+import { WIMAccountsActionComponent } from 'WIMAccountsAction';
+
+/**
+ * Custom angular notifier options
+ */
+const customNotifierOptions: NotifierOptions = {
+    position: { horizontal: { position: 'right' }, vertical: { position: 'top' } },
+    behaviour: { autoHide: 3000, onClick: 'hide', onMouseover: 'pauseAutoHide' }
+};
+
+/**
+ * An NgModule is a class adorned with the @NgModule decorator function.
+ * @NgModule takes a metadata object that tells Angular how to compile and run module code.
+ */
+@NgModule({
+    declarations: [
+        AppComponent,
+        LayoutComponent,
+        HeaderComponent,
+        SidebarComponent,
+        LoginComponent,
+        PageNotFoundComponent,
+        VNFPackagesActionComponent,
+        NsPackagesActionComponent,
+        NSInstancesActionComponent,
+        VNFInstancesActionComponent,
+        VNFLinkComponent,
+        NetsliceInstancesActionComponent,
+        BreadcrumbComponent,
+        DeleteComponent,
+        NetslicePackagesActionComponent,
+        UsersActionComponent,
+        VimAccountsActionComponent,
+        ProjectsActionComponent,
+        ProjectLinkComponent,
+        UserSettingsComponent,
+        ShowInfoComponent,
+        InstantiateNetSliceTemplateComponent,
+        InstantiateNsComponent,
+        ConfirmationTopologyComponent,
+        ComposePackages,
+        WIMAccountsActionComponent,
+        PDUInstancesActionComponent,
+        SDNControllerActionComponent,
+        SwitchProjectComponent,
+        GoToTopDirective
+    ],
+    imports: [
+        NotifierModule.withConfig(customNotifierOptions),
+        CommonModule,
+        BrowserModule,
+        BrowserAnimationsModule,
+        FormsModule,
+        ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }),
+        Ng2SmartTableModule,
+        CodemirrorModule,
+        NgSelectModule,
+        HttpClientModule,
+        TranslateModule.forRoot({
+            loader: {
+                provide: TranslateLoader,
+                useFactory: HttpLoaderFactory,
+                deps: [HttpClient]
+            }
+        }),
+        NgbModule,
+        NgSelectModule,
+        RouterModule.forRoot(appRoutes, { useHash: false }),
+        NgIdleKeepaliveModule.forRoot(),
+        LoaderModule
+    ],
+    providers: [
+        {
+            provide: APP_INITIALIZER,
+            useFactory: appInitializerFactory,
+            deps: [TranslateService, Injector],
+            multi: true
+        },
+        {
+            provide: HTTP_INTERCEPTORS,
+            useClass: AuthInterceptorService,
+            multi: true
+        },
+        RestService,
+        AuthenticationService,
+        AuthGuardService,
+        DataService,
+        ProjectService,
+        SharedService,
+        DeviceCheckService
+    ],
+    bootstrap: [AppComponent],
+    entryComponents: [
+        VNFPackagesActionComponent,
+        NsPackagesActionComponent,
+        NSInstancesActionComponent,
+        VNFInstancesActionComponent,
+        VNFLinkComponent,
+        NetsliceInstancesActionComponent,
+        BreadcrumbComponent,
+        DeleteComponent,
+        NetslicePackagesActionComponent,
+        UsersActionComponent,
+        VimAccountsActionComponent,
+        ProjectsActionComponent,
+        ProjectLinkComponent,
+        UserSettingsComponent,
+        ShowInfoComponent,
+        InstantiateNetSliceTemplateComponent,
+        InstantiateNsComponent,
+        ConfirmationTopologyComponent,
+        ComposePackages,
+        WIMAccountsActionComponent,
+        PDUInstancesActionComponent,
+        SDNControllerActionComponent,
+        SwitchProjectComponent
+    ]
+})
+
+/** Exporting a class @exports AppModule */
+export class AppModule {
+    /** Variables declared to avoid state-less class */
+    private appModule: string;
+}
+
+/**
+ * HttpLoaderFactory is for translate service of the application.
+ */
+// tslint:disable:function-name
+export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
+    const now: number = new Date().getTime();
+    return new TranslateHttpLoader(http, './assets/i18n/', '.json?locale=' + now);
+}
+/**
+ * HttpLoaderFactory is for translate service of the application.
+ */
+// tslint:disable:function-name
+export function appInitializerFactory(translate: TranslateService, injector: Injector): Object {
+    // tslint:disable-next-line: no-any
+    return async (): Promise<any> => {
+        await injector.get(LOCATION_INITIALIZED, Promise.resolve(null));
+        translate.setDefaultLang('en');
+        const languageCode: string = localStorage.getItem('languageCode');
+        if (languageCode !== null && languageCode !== undefined && languageCode !== '') {
+            await translate.use(languageCode).toPromise().catch(() => {
+                translate.setDefaultLang('en');
+            });
+        } else {
+            await translate.use('en').toPromise();
+            localStorage.setItem('languageCode', 'en');
+        }
+    };
+}
diff --git a/src/app/approutes.module.ts b/src/app/approutes.module.ts
new file mode 100644 (file)
index 0000000..e2f863c
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Routing Module
+ */
+import { Routes } from '@angular/router';
+import { AuthGuardService } from 'AuthGuardService';
+import { LayoutComponent } from 'LayoutComponent';
+import { LoginComponent } from 'LoginComponent';
+import { PageNotFoundComponent } from 'PageNotFound';
+
+/** Exporting a function using Routes @exports AppRoutes */
+export const appRoutes: Routes = [
+    {
+        path: 'login',
+        component: LoginComponent
+    },
+    {
+        path: '',
+        component: LayoutComponent,
+        canActivate: [AuthGuardService],
+        children: [
+            {
+                path: '',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./dashboard/DashboardModule')
+                    .then((m: typeof import('./dashboard/DashboardModule')) => m.DashboardModule),
+                canActivate: [AuthGuardService]
+            },
+            {
+                path: 'packages',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./packages/PackagesModule')
+                    .then((m: typeof import('./packages/PackagesModule')) => m.PackagesModule),
+                canActivate: [AuthGuardService]
+            },
+            {
+                path: 'instances',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./instances/InstancesModule')
+                    .then((m: typeof import('./instances/InstancesModule')) => m.InstancesModule),
+                canActivate: [AuthGuardService]
+            },
+            {
+                path: 'vim',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./vim-accounts/VimAccountsModule')
+                    .then((m: typeof import('./vim-accounts/VimAccountsModule')) => m.VimAccountsModule),
+                canActivate: [AuthGuardService]
+            },
+            {
+                path: 'wim',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./wim-accounts/WIMAccountsModule')
+                    .then((m: typeof import('./wim-accounts/WIMAccountsModule')) => m.WIMAccountsModule),
+                canActivate: [AuthGuardService]
+            },
+            {
+                path: 'sdn',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./sdn-controller/SDNControllerModule')
+                    .then((m: typeof import('./sdn-controller/SDNControllerModule')) => m.SDNControllerModule),
+                canActivate: [AuthGuardService]
+            },
+            {
+                path: 'users',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./users/UsersModule')
+                    .then((m: typeof import('./users/UsersModule')) => m.UsersModule),
+                canActivate: [AuthGuardService]
+            },
+            {
+                path: 'projects',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./projects/ProjectsModule')
+                    .then((m: typeof import('./projects/ProjectsModule')) => m.ProjectsModule),
+                canActivate: [AuthGuardService]
+            },
+            {
+                path: 'roles',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./roles/RolesModule')
+                    .then((m: typeof import('./roles/RolesModule')) => m.RolesModule),
+                canActivate: [AuthGuardService]
+            },
+            {
+                path: 'k8s',
+                // tslint:disable-next-line: no-any
+                loadChildren: async (): Promise<any> => import('./k8s/K8sModule')
+                    .then((m: typeof import('./k8s/K8sModule')) => m.K8sModule),
+                canActivate: [AuthGuardService]
+            }
+        ]
+    },
+    {
+        path: '**',
+        component: PageNotFoundComponent
+    }
+];
diff --git a/src/app/dashboard/DashboardComponent.html b/src/app/dashboard/DashboardComponent.html
new file mode 100644 (file)
index 0000000..5b09dc9
--- /dev/null
@@ -0,0 +1,167 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row dashboard">
+    <div class="col-xs-9 col-sm-12 col-md-12 col-lg-9 col-xl-9 p-0">
+        <div class="row instances">
+            <div class="col-xs-8 col-sm-8 col-md-12 col-lg-8 col-xl-8">
+                <div class="custom-card card mb-3 text-center graph-section">
+                    <div class="card-title">
+                        <h6 class="font-weight-bold" *ngIf="nsRunningInstance.length">
+                            {{'PAGE.DASHBOARD.UPTIME' | translate}} {{'PAGE.DASHBOARD.RUNNINGINSTANCES' | translate}}
+                        </h6>
+                        <h6 *ngIf="!nsRunningInstance.length">
+                            <span> {{'PAGE.DASHBOARD.NOINSTANCES' | translate}}</span>
+                        </h6>
+                        <div [ngClass]="{'show-canvas':nsRunningInstance.length}" class="instances-canvas">
+                            <canvas id="canvas"></canvas>
+                        </div>
+                    </div>
+                </div>
+                <app-loader [waitingMessage]="message" *ngIf="isCanvasLoadingResults"></app-loader>
+            </div>
+            <div class="col-xs-4 col-sm-4 col-md-12 col-lg-4 col-xl-4">
+                <div class="custom-card card card mb-3">
+                    <div class="card-header custom-card-header">
+                        {{'PAGE.DASHBOARD.FAILEDINSTANCES' | translate}}
+                    </div>
+                    <div class="card-body list-overflow failed-instances">
+                        <ul class="list-group">
+                            <li class="list-group-item text-left" *ngIf="!nsFailedInstances.length">
+                                {{'PAGE.DASHBOARD.NOINSTANCES' | translate}}</li>
+                            <li class="list-group-item text-left d-flex justify-content-between align-items-center"
+                                *ngFor="let nsFailedInstance of nsFailedInstances">
+                                <span class="text-truncate">{{nsFailedInstance.name}}</span>
+                                <ng-template #popTitle>
+                                    <strong>{{nsFailedInstance.name}}</strong>
+                                    <button class="button-xs close" type="button" (click)="p.close()">
+                                        <i class="fas fa-times-circle text-danger"></i>
+                                    </button>
+                                </ng-template>
+                                <span class="badge badge-pill">
+                                    <i placement="left" container="body"
+                                        ngbPopover="{{'DETAILEDSTATUS' | translate}}: {{nsFailedInstance['detailed-status']}}"
+                                        triggers="manual" #p="ngbPopover" (click)="p.open()" [autoClose]="'outside'"
+                                        [popoverTitle]="popTitle"
+                                        class="fas fa-exclamation-circle text-danger float-left"></i></span>
+                            </li>
+                        </ul>
+                    </div>
+                </div>
+                <app-loader [waitingMessage]="message" *ngIf="isCanvasLoadingResults"></app-loader>
+            </div>
+        </div>
+        <div class="row module-counts">
+            <div class="col-xs-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-0">
+                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-3">
+                    <div class="status-card custom-card card-hover card aqua-card" routerLink="/packages/ns">
+                        <i class="fas fa-box-open"></i>
+                        <h3>{{ (nsdPackageCount)?nsdPackageCount:0 }}</h3>
+                        <h6>{{'NSPACKAGES' | translate}}</h6>
+                        <span class="link-icon">
+                            <i class="fa fa-link" aria-hidden="true"></i>
+                        </span>
+                    </div>
+                </div>
+                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-3">
+                    <div class="status-card custom-card card-hover card aqua-card" routerLink="/instances/ns">
+                        <i class="fas fa-sitemap"></i>
+                        <h3>{{ (nsInstanceCount)?nsInstanceCount:0 }}</h3>
+                        <h6>{{'NSINSTANCES' | translate}}</h6>
+                        <span class="link-icon">
+                            <i class="fa fa-link" aria-hidden="true"></i>
+                        </span>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-0">
+                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-3">
+                    <div class="status-card custom-card card-hover card purple-card" routerLink="/packages/vnf">
+                        <i class="fas fa-box-open"></i>
+                        <h3>{{ (vnfdPackageCount)?vnfdPackageCount:0 }}</h3>
+                        <h6>{{'VNFPACKAGES' | translate}}</h6>
+                        <span class="link-icon">
+                            <i class="fa fa-link" aria-hidden="true"></i>
+                        </span>
+                    </div>
+                </div>
+                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-3">
+                    <div class="status-card custom-card card-hover card purple-card" routerLink="/instances/vnf">
+                        <i class="fas fa-hdd"></i>
+                        <h3>{{ (vnfInstanceCount)?vnfInstanceCount:0 }}</h3>
+                        <h6>{{'VNFINSTANCES' | translate}}</h6>
+                        <span class="link-icon">
+                            <i class="fa fa-link" aria-hidden="true"></i>
+                        </span>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-0">
+                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-3">
+                    <div class="status-card custom-card card-hover card pink-card" routerLink="/vim/details">
+                        <i class="fas fa-server"></i>
+                        <h3>{{ (vimAccountCount)?vimAccountCount:0 }}</h3>
+                        <h6>{{'VIMACCOUNTS' | translate}}</h6>
+                        <span class="link-icon">
+                            <i class="fa fa-link" aria-hidden="true"></i>
+                        </span>
+                    </div>
+                </div>
+                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-3">
+                    <div class="status-card custom-card card-hover card pink-card" routerLink="/sdn/details">
+                        <i class="fas fa-globe"></i>
+                        <h3>{{ (sdnControllerCount)?sdnControllerCount:0 }}</h3>
+                        <h6>{{'SDNCONTROLLER' | translate}}</h6>
+                        <span class="link-icon">
+                            <i class="fa fa-link" aria-hidden="true"></i>
+                        </span>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="col-xs-3 col-sm-12 col-md-12 col-lg-3 col-xl-3 p-0">
+        <div class="custom-card">
+            <div class="card-header p-0 custom-card-header">
+                <a routerLink="/projects">
+                    {{'ALL' | translate}} {{'PAGE.DASHBOARD.PROJECTS' | translate}}
+                    <span
+                        class="badge badge-primary badge-pill bg-white text-body font-weight-bold">{{allProjectList.length}}</span>
+                </a>
+            </div>
+            <div class="card-body list-overflow project-list">
+                <ul class="list-group">
+                    <li class="list-group-item text-left d-flex justify-content-between align-items-center selectProject"
+                        *ngFor='let list of allProjectList'>
+                        {{list.projectName}}
+                        <span class="badge badge-pill" *ngFor='let listcheck of projectList' placement="top"
+                            container="body"
+                            ngbTooltip="{{ (list.projectName === (selectedProject | async) ? 'CURRENTPROJECT' : 'SWITCHPROJECT') | translate}}">
+                            <i *ngIf="list.projectName === (selectedProject | async) && listcheck.project === list.project"
+                                [ngClass]="list.projectName === (selectedProject | async) ? 'activeProjectLink' : ''"
+                                class="fas fa-check-circle text-success"></i>
+                            <i *ngIf="list.projectName !== (selectedProject | async) && listcheck.project === list.project"
+                                (click)="this.projectService.switchProjectModal(list)"
+                                class="fas fa-exchange-alt text-danger selectProjectLink"></i>
+                        </span>
+                    </li>
+                </ul>
+            </div>
+            <app-loader [waitingMessage]="message" *ngIf="isProjectsLoadingResults"></app-loader>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/app/dashboard/DashboardComponent.scss b/src/app/dashboard/DashboardComponent.scss
new file mode 100644 (file)
index 0000000..df3c6b1
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+ @import "../../assets/scss/mixins/mixin";
+ @import "../../assets/scss/variable";
+ $min-height-set: 200px;
+ .dashboard {
+   .custom-card {
+     word-wrap: break-word;
+     @include box-shadow(0px, 1px, 15px, 0px, rgba(69, 90, 100, 0.1));
+     @include transition(all, 0.2s, null, null);
+     @include roundedCorners(5);
+     @include border(all, 1, solid, rgba(238, 238, 238, 0.75));
+     color: $white;
+     &.card-hover {
+       @include transition(all, 0.25s, ease, null);
+       &:hover {
+         -moz-transform: translateY(-4px) scale(1.01);
+         -ms-transform: translateY(-4px) scale(1.01);
+         -o-transform: translateY(-4px) scale(1.01);
+         transform: translateY(-4px) scale(1.01);
+       }
+     }
+     &.pink-card {
+       @include background(
+         linear-gradient(to left top, #d81b60, #e0306d, #e7407a, #ee4f87, #f55c94),
+         null,
+         null,
+         null,
+         null
+       );
+     }
+     &.purple-card {
+       @include background(
+         linear-gradient(to left top, #605ca8, #736ebb, #8681ce, #9994e2, #aca7f6),
+         null,
+         null,
+         null,
+         null
+       );
+     }
+     &.aqua-card {
+       @include background(
+         linear-gradient(to left top, #00c0ef, #00cdf5, #00dafa, #00e6fd, #0af3ff),
+         null,
+         null,
+         null,
+         null
+       );
+     }
+     .custom-card-header {
+       @include background(null, $primary, null, null, null);
+       @include roundedTop(5);
+       a {
+         color: $white;
+         @include flexbox(flex, space-between, null, null, center, null);
+         @include padding-value(12, 20, 12, 20);
+       }
+     }
+     .card-body {
+       @include padding-value(5, 5, 5, 10);
+       &.list-overflow {
+         overflow-y: scroll;
+         .list-group {
+           .list-group-item {
+             cursor: default;
+             @include border(all, 0, solid, $black-coral);
+             @include border(bottom, 1, solid, rgba(0, 0, 0, 0.125));
+             @include padding-value(10, 0, 10, 0);
+             @include margin-value(0, 0, 0, 0);
+             color: $gray-600;
+             i {
+               cursor: pointer;
+               @include font(null, 14px, null);
+               &.activeProjectLink {
+                 cursor: default;
+               }
+             }
+             &:last-child {
+               @include border(bottom, 0, solid, rgba(0, 0, 0, 0.125));
+             }
+           }
+         }
+         &.failed-instances {
+           max-height: $min-height-set;
+         }
+         &.project-list {
+           max-height: 65vh;
+         }
+       }
+     }
+   }
+   .instances {
+     .graph-section {
+       min-height: $min-height-set;
+       @include flexbox(null, center, null, null, null, null);
+       @include padding-value(10, 10, 10, 10);
+       .card-title {
+         color: $gray-600;
+       }
+       .instances-canvas {
+         @include flexbox(none !important, null, null, null, null, null);
+         &.show-canvas {
+           @include flexbox(block !important, null, null, null, null, null);
+         }
+         #canvas{
+          @include wh-value(100%, $min-height-set);
+        }
+       }
+     }
+   }
+   .module-counts {
+     .status-card {
+       overflow: hidden;
+       @include wh-value(null, 130px);
+       @include roundedCorners(4);
+       @include box-shadow(0px, 5px, 20px, 2px, $transparent-dark-bg);
+       cursor: pointer;
+       @include flexbox(null, null, null, null, center, null);
+       @include padding-value(20, 20, 20, 20);
+       @include border(all, 0, solid, $gray-80);
+       i {
+         @include font(null, 2rem, null);
+         @include margin-value(0, 0, 8, 0);
+       }
+       h6 {
+         @include font(null, 0.8rem, null);
+       }
+       &:hover .link-icon {
+         @include position_value(null, null, -60px, null, null);
+       }
+       .link-icon {
+         @include background(null, rgba(255, 255, 255, 0.5), null, null, null);
+         @include position_value(absolute, 0px, -130px, null, null);
+         @include wh-value(130px, 130px);
+         @include font(null, 30px, null);
+         @include padding-value(40, 20, 40, 20);
+         @include roundedCornersPercentage(50%);
+         @include transition(all, 0.3s, ease-in-out, null);
+         i {
+           @include font(null, 1.875rem, null);
+         }
+       }
+     }
+   }
+ }
\ No newline at end of file
diff --git a/src/app/dashboard/DashboardComponent.ts b/src/app/dashboard/DashboardComponent.ts
new file mode 100644 (file)
index 0000000..4ab802f
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Dashboard Component
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { AuthenticationService } from 'AuthenticationService';
+import { Chart } from 'chart.js';
+import { ERRORDATA } from 'CommonModel';
+import { environment } from 'environment';
+import { NSDDetails } from 'NSDModel';
+import { NSInstanceDetails } from 'NSInstanceModel';
+import { ProjectData, ProjectDetails } from 'ProjectModel';
+import { ProjectService } from 'ProjectService';
+import { RestService } from 'RestService';
+import { Observable, Subscription } from 'rxjs';
+import { SDNControllerModel } from 'SDNControllerModel';
+import { SharedService } from 'SharedService';
+import { ProjectRoleMappings, UserDetail } from 'UserModel';
+import { VimAccountDetails } from 'VimAccountModel';
+import { VNFDDetails } from 'VNFDModel';
+import { VNFInstanceDetails } from 'VNFInstanceModel';
+
+/**
+ * Creating component
+ * @Component takes DashboardComponent.html as template url
+ */
+@Component({
+    styleUrls: ['./DashboardComponent.scss'],
+    templateUrl: './DashboardComponent.html'
+})
+
+/**
+ * This file created during the angular project creation
+ */
+
+/** Exporting a class @exports DashboardComponent */
+export class DashboardComponent implements OnInit {
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** handle translate @public */
+    public translateService: TranslateService;
+
+    /** Observable holds logined value  @public */
+    public username$: Observable<string>;
+
+    /** Variables holds admin is logged or not @public */
+    public isAdmin: boolean;
+
+    /** List of NS failed Instances @public */
+    public nsFailedInstances: {}[] = [];
+
+    /** Setting up count for vnfdPackages @public */
+    public vnfdPackageCount: number;
+
+    /** Setting up count for nsdPackage @public */
+    public nsdPackageCount: number;
+
+    /** Setting up count for nsInstance @public */
+    public nsInstanceCount: number;
+
+    /** Setting up count for vnfInstance @public */
+    public vnfInstanceCount: number;
+
+    /** Setting up count for vimAccount @public */
+    public vimAccountCount: number;
+
+    /** Setting up count for sdnController @public */
+    public sdnControllerCount: number;
+
+    /** Variables holds current project details @public */
+    public currentProjectDetails: {};
+
+    /** Array holds all the projects @public */
+    public projectList: {}[] = [];
+
+    /** Array holds all the projects @public */
+    public allProjectList: {}[] = [];
+
+    /** Variables holds the selected project @public */
+    public selectedProject: Observable<string>;
+
+    /** Check the Instances loading results @public */
+    public isCanvasLoadingResults: boolean = true;
+
+    /** Check the Projects loading results @public */
+    public isProjectsLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** List of NS Success Instances @private */
+    public nsRunningInstance: string[] = [];
+
+    /** Utilizes rest service for any CRUD operations @private */
+    private restService: RestService;
+
+    /** Utilizes auth service for any auth operations @private */
+    private authService: AuthenticationService;
+
+    /** Used to subscribe vnfdPackage @private */
+    private vnfdPackageCountSub: Subscription;
+
+    /** Used to subscribe nsdPackage @private */
+    private nsdPackageCountSub: Subscription;
+
+    /** Used to subscribe nsInstance @private */
+    private nsInstanceCountSub: Subscription;
+
+    /** Used to subscribe vnfInstance @private */
+    private vnfInstanceCountSub: Subscription;
+
+    /** Used to subscribe vimAccount @private */
+    private vimAccountCountSub: Subscription;
+
+    /** Used to subscribe sdnController @private */
+    private sdnControllerCountSub: Subscription;
+
+    /** No of Hours of NS Success Instances @private */
+    private noOfHours: number[] = [];
+
+    /** collects charts objects @private */
+    private charts: object = [];
+
+    /** Contains all methods related to projects @private */
+    private projectService: ProjectService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** Contains NS Instance Details */
+    private nsInstancesDataArr: {}[];
+
+    /** Container created time array @private */
+    private createdTimes: string[] = [];
+
+    /** Contains slice limit const @private */
+    private sliceLimit: number = 10;
+
+    /** Contians hour converter @private */
+    private hourConverter: number = 3600;
+
+    /** Contians color code for chart @private */
+    private chartColorPink: string = '#e4397c';
+
+    /** Contians color code for chart @private */
+    private chartColorPurple: string = '#605ca8';
+
+    /** Contians color code for chart @private */
+    private chartColorCyan: string = '#00c0ef';
+
+    /** Contians color code for chart @private */
+    private chartColorBlue: string = '#054C8C';
+
+    /** Contians color code for chart @private */
+    private chartColorYellow: string = '#ffce56';
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.authService = this.injector.get(AuthenticationService);
+        this.projectService = this.injector.get(ProjectService);
+        this.sharedService = this.injector.get(SharedService);
+        this.translateService = this.injector.get(TranslateService);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.username$ = this.authService.username;
+        this.isAdmin = (localStorage.getItem('isAdmin') === 'true') ? true : false;
+        this.selectedProject = this.authService.ProjectName;
+        this.checkAdminPrivilege();
+        this.getUserAccessedProjects();
+        this.getAllProjects();
+        this.getVnfdPackageCount();
+        this.getNsdPackageCount();
+        this.getNsInstanceCount();
+        this.getVnfInstanceCount();
+        this.getVimAccountCount();
+        this.getSDNControllerCount();
+    }
+
+    /** Get all the projects @public */
+    public getUserAccessedProjects(): void {
+        this.projectService.getUserProjects().subscribe((projects: UserDetail) => {
+            const projectList: {}[] = projects.project_role_mappings;
+            this.projectList = projectList.filter(
+                (thing: ProjectRoleMappings, i: number, arr: []) => arr
+                    .findIndex((t: ProjectRoleMappings) => t.project_name === thing.project_name) === i
+            );
+        }, (error: Error) => {
+            // TODO: Handle failure
+        });
+    }
+
+    /** Fetching all the Project in dashboard @public */
+    public getAllProjects(): void {
+        this.isProjectsLoadingResults = true;
+        this.restService.getResource(environment.PROJECTS_URL).subscribe((projectsData: ProjectDetails[]) => {
+            this.allProjectList = [];
+            projectsData.forEach((projectData: ProjectDetails) => {
+                const projectDataObj: ProjectData = this.generateProjectData(projectData);
+                this.allProjectList.push(projectDataObj);
+            });
+            this.isProjectsLoadingResults = false;
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isProjectsLoadingResults = false;
+        });
+    }
+
+    /** Generate Projects object from loop and return for the datasource @public */
+    public generateProjectData(projectData: ProjectDetails): ProjectData {
+        return {
+            projectName: projectData.name,
+            modificationDate: this.sharedService.convertEpochTime(projectData._admin.modified),
+            creationDate: this.sharedService.convertEpochTime(projectData._admin.created),
+            id: projectData._id,
+            project: projectData._id
+        };
+    }
+
+    /** Function to check admin privilege @public */
+    public checkAdminPrivilege(): void {
+        if (!this.isAdmin) {
+            this.projectService.getCurrentProjectDetails().subscribe((projectDetails: {}) => {
+                this.currentProjectDetails = projectDetails;
+            }, (error: Error) => {
+                // TODO: Handle failure
+            });
+        }
+    }
+
+    /** Get VNFD Package details @public */
+    public getVnfdPackageCount(): void {
+        this.vnfdPackageCountSub = this.restService.getResource(environment.VNFPACKAGESCONTENT_URL)
+            .subscribe((vnfdPackageData: VNFDDetails[]) => {
+            this.vnfdPackageCount = vnfdPackageData.length;
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+        });
+    }
+
+    /** Get NSD Package details @public */
+    public getNsdPackageCount(): void {
+        this.nsdPackageCountSub = this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL)
+            .subscribe((nsdPackageData: NSDDetails[]) => {
+            this.nsdPackageCount = nsdPackageData.length;
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+        });
+    }
+
+    /** Get NS Instance details @public */
+    public getNsInstanceCount(): void {
+        this.isCanvasLoadingResults = true;
+        this.nsInstanceCountSub = this.restService.getResource(environment.NSDINSTANCES_URL)
+            .subscribe((nsInstancesData: NSInstanceDetails[]) => {
+                this.nsInstancesDataArr = nsInstancesData;
+                this.nsInstanceCount = nsInstancesData.length;
+                this.nsInstanceChart();
+                this.isCanvasLoadingResults = false;
+            }, (error: ERRORDATA) => {
+                this.restService.handleError(error, 'get');
+                this.isCanvasLoadingResults = false;
+            });
+    }
+
+    /** Get NS Instance chart details @public */
+    public nsInstanceChart(): void {
+        this.nsInstancesDataArr.forEach((nsdInstanceData: NSDDetails) => {
+            const operationalStatus: string = nsdInstanceData['operational-status'];
+            const configStatus: string = nsdInstanceData['config-status'];
+            if (operationalStatus === 'failed' || configStatus === 'failed') {
+                this.nsFailedInstances.push(nsdInstanceData);
+            } else if (operationalStatus === 'running' && configStatus === 'configured') {
+                this.nsRunningInstance.push(nsdInstanceData.name);
+                this.createdTimes.push(((nsdInstanceData._admin.created).toString()).slice(0, this.sliceLimit));
+            }
+        });
+        const now: Date = new Date();
+        const currentTime: number = Number((now.getTime().toString().slice(0, this.sliceLimit)));
+        this.createdTimes.forEach((createdTime: string) => {
+            this.noOfHours.push((Math.round((currentTime - Number(createdTime)) / this.hourConverter)));
+        });
+        this.drawNsChart();
+    }
+
+    /** Prepare and sketch NS instance chart */
+    public drawNsChart(): void {
+        this.charts = new Chart('canvas', {
+            type: 'bar',
+            data: {
+                labels: this.nsRunningInstance,
+                datasets: [{
+                    data: this.noOfHours,
+                    label: this.translateService.instant('NOOFHOURS'),
+                    borderColor: [this.chartColorPurple, this.chartColorPink, this.chartColorCyan,
+                    this.chartColorBlue, this.chartColorYellow],
+                    fill: false,
+                    backgroundColor: [this.chartColorPurple, this.chartColorPink, this.chartColorCyan,
+                    this.chartColorBlue, this.chartColorYellow]
+                }]
+            },
+            options: {
+                legend: { display: false },
+                scales: {
+                    xAxes: [{
+                        display: true,
+                        ticks: {
+                            // tslint:disable-next-line: no-any
+                            callback: (label: any, index: number, labels: string): string => {
+                                const length: number = 20;
+                                const ending: string = '...';
+                                if (label.length > length) {
+                                    return label.substring(0, length - ending.length) + ending;
+                                } else {
+                                    return label;
+                                }
+                            }
+                        },
+                        scaleLabel: {
+                            display: true,
+                            labelString: this.translateService.instant('INSTANCES')
+                        }
+                    }],
+                    yAxes: [{
+                        ticks: {
+                            beginAtZero: true
+                        },
+                        display: true,
+                        scaleLabel: {
+                            display: true,
+                            labelString: this.translateService.instant('NOOFHOURS')
+                        }
+                    }]
+                }
+            }
+        });
+    }
+
+    /** Get VNFD instance details @public */
+    public getVnfInstanceCount(): void {
+        this.vnfInstanceCountSub = this.restService.getResource(environment.NSDINSTANCES_URL)
+            .subscribe((vnfInstanceData: VNFInstanceDetails[]) => {
+                this.vnfInstanceCount = vnfInstanceData.length;
+            }, (error: ERRORDATA) => {
+                this.restService.handleError(error, 'get');
+            });
+    }
+
+    /** Get VIM account details @public */
+    public getVimAccountCount(): void {
+        this.vimAccountCountSub = this.restService.getResource(environment.VIMACCOUNTS_URL)
+            .subscribe((vimAccountData: VimAccountDetails[]) => {
+                this.vimAccountCount = vimAccountData.length;
+            }, (error: ERRORDATA) => {
+                this.restService.handleError(error, 'get');
+            });
+    }
+
+    /** Get SDN Controller Count  @public */
+    public getSDNControllerCount(): void {
+        this.sdnControllerCountSub = this.restService.getResource(environment.SDNCONTROLLER_URL)
+            .subscribe((sdnControllerData: SDNControllerModel[]) => {
+                this.sdnControllerCount = sdnControllerData.length;
+            }, (error: ERRORDATA) => {
+                this.restService.handleError(error, 'get');
+            });
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is deleted
+     */
+    public ngOnDestroy(): void {
+        this.vnfdPackageCountSub.unsubscribe();
+        this.nsdPackageCountSub.unsubscribe();
+        this.nsInstanceCountSub.unsubscribe();
+        this.vnfInstanceCountSub.unsubscribe();
+        this.vimAccountCountSub.unsubscribe();
+        this.sdnControllerCountSub.unsubscribe();
+    }
+}
diff --git a/src/app/dashboard/DashboardModule.ts b/src/app/dashboard/DashboardModule.ts
new file mode 100644 (file)
index 0000000..4d882e2
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file Dashboard Module
+ */
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { NgModule } from '@angular/core';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { FormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateModule } from '@ngx-translate/core';
+import { DashboardComponent } from 'DashboardComponent';
+import { LoaderModule } from 'LoaderModule';
+import { ChartsModule } from 'ng2-charts';
+
+/** To halndle project information */
+const projectInfo: {} = { title: '{project}', url: '/' };
+
+/** const values for dashboard Routes */
+const routes: Routes = [
+    {
+        path: '',
+        data: {
+            breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                projectInfo]
+        },
+        component: DashboardComponent
+    }
+];
+/**
+ * An NgModule is a class adorned with the @NgModule decorator function.
+ * @NgModule takes a metadata object that tells Angular how to compile and run module code.
+ */
+@NgModule({
+    imports: [FormsModule, CommonModule, HttpClientModule, FlexLayoutModule, TranslateModule,
+        ChartsModule, RouterModule.forChild(routes), NgbModule, LoaderModule],
+    declarations: [DashboardComponent]
+})
+/** Exporting a class @exports DashboardModule */
+export class DashboardModule {
+    /** Variables declared to avoid state-less class */
+    private dashboardModule: string;
+}
diff --git a/src/app/instances/InstancesComponent.html b/src/app/instances/InstancesComponent.html
new file mode 100644 (file)
index 0000000..06b8876
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<router-outlet></router-outlet>
diff --git a/src/app/instances/InstancesComponent.scss b/src/app/instances/InstancesComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/instances/InstancesComponent.ts b/src/app/instances/InstancesComponent.ts
new file mode 100644 (file)
index 0000000..fe46d8c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Instance components
+ */
+import { Component, Injector } from '@angular/core';
+import { Router, RouterEvent } from '@angular/router';
+/**
+ * Creating component
+ * @Component takes InstancesComponent.html as template url
+ */
+@Component({
+    selector: 'app-instances',
+    templateUrl: './InstancesComponent.html',
+    styleUrls: ['./InstancesComponent.scss']
+})
+/** Exporting a class @exports InstancesComponent */
+export class InstancesComponent {
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** Holds teh instance of AuthService class of type AuthService @private */
+    private router: Router;
+
+    // creates packages component
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.router = this.injector.get(Router);
+        this.router.events.subscribe((event: RouterEvent) => {
+            this.redirectToList(event.url);
+        });
+    }
+
+    /** Return to list NS Package List */
+    public redirectToList(getURL: string): void {
+        if (getURL === '/instances') {
+            this.router.navigate(['/instances/ns']).catch();
+        }
+    }
+}
diff --git a/src/app/instances/InstancesModule.ts b/src/app/instances/InstancesModule.ts
new file mode 100644 (file)
index 0000000..7e47d32
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Instance module
+ */
+import { CommonModule } from '@angular/common';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { FormsModule } from '@angular/forms';
+import { ReactiveFormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { CodemirrorModule } from '@ctrl/ngx-codemirror';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgSelectModule } from '@ng-select/ng-select';
+import { TranslateModule } from '@ngx-translate/core';
+import { AddPDUInstancesComponent } from 'AddPDUInstancesComponent';
+import { DataService } from 'DataService';
+import { HistoryOperationsComponent } from 'HistoryOperationsComponent';
+import { InstancesComponent } from 'InstancesComponent';
+import { LoaderModule } from 'LoaderModule';
+import { NetsliceInstancesComponent } from 'NetsliceInstancesComponent';
+import { SidebarModule } from 'ng-sidebar';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { NSInstancesComponent } from 'NSInstancesComponent';
+import { NSPrimitiveComponent } from 'NSPrimitiveComponent';
+import { NSTopologyComponent } from 'NSTopologyComponent';
+import { PagePerRowModule } from 'PagePerRowModule';
+import { PageReloadModule } from 'PageReloadModule';
+import { PDUInstancesComponent } from 'PDUInstancesComponent';
+import { VNFInstancesComponent } from 'VNFInstancesComponent';
+
+/** To halndle project information */
+const projectInfo: {} = { title: '{project}', url: '/' };
+
+/** Exporting a function using Routes @exports routes */
+const routes: Routes = [
+    {
+        path: '',
+        component: InstancesComponent,
+        children: [
+            {
+                path: 'ns',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'NSINSTANCES', url: null }]
+                },
+                component: NSInstancesComponent
+            },
+            {
+                path: 'vnf',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'VNFINSTANCES', url: null }]
+                },
+                component: VNFInstancesComponent
+            },
+            {
+                path: 'pdu',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'PDUINSTANCES', url: null }]
+                },
+                component: PDUInstancesComponent
+            },
+            {
+                path: 'netslice',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'PAGE.DASHBOARD.NETSLICEINSTANCE', url: null }]
+                },
+                component: NetsliceInstancesComponent
+            },
+            {
+                path: ':type/history-operations/:id',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: '{type}', url: '/instances/{type}' }, { title: '{id}', url: null }]
+                },
+                component: HistoryOperationsComponent
+            },
+            {
+                path: 'ns/:id',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'NSINSTANCES', url: '/instances/ns' }, { title: '{id}', url: null }]
+                },
+                component: NSTopologyComponent
+            }
+        ]
+    }
+];
+
+/**
+ * An NgModule is a class adorned with the @NgModule decorator function.
+ * @NgModule takes a metadata object that tells Angular how to compile and run module code.
+ */
+@NgModule({
+    imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, TranslateModule,
+        CodemirrorModule, CommonModule, Ng2SmartTableModule, FlexLayoutModule, RouterModule.forChild(routes), NgbModule,
+        NgSelectModule, PagePerRowModule, LoaderModule, SidebarModule.forRoot(), PageReloadModule],
+    declarations: [InstancesComponent, NSInstancesComponent, VNFInstancesComponent, PDUInstancesComponent, AddPDUInstancesComponent,
+        NetsliceInstancesComponent, HistoryOperationsComponent, NSTopologyComponent, NSPrimitiveComponent],
+    schemas: [CUSTOM_ELEMENTS_SCHEMA],
+    providers: [DataService],
+    entryComponents: [NSPrimitiveComponent, AddPDUInstancesComponent]
+})
+/** Exporting a class @exports InstancesModule */
+export class InstancesModule {
+    /** Resolves state-less class */
+    private instancesModule: string;
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.instancesModule = '';
+    }
+}
diff --git a/src/app/instances/netslice-instances/NetsliceInstancesComponent.html b/src/app/instances/netslice-instances/NetsliceInstancesComponent.html
new file mode 100644 (file)
index 0000000..e8b3c0c
--- /dev/null
@@ -0,0 +1,44 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'PAGE.DASHBOARD.NETSLICEINSTANCE' | translate}}</div>
+    <span class="button">
+        <button class="btn btn-primary" type="button" placement="top" container="body"
+            ngbTooltip="{{'PAGE.NETSLICEINSTANCE.CREATENETSLICEINSTANCE' | translate}}" (click)="instantiateNetSlice()">
+            <i class="fa fa-paper-plane" aria-hidden="true"></i>&nbsp;
+            {{'PAGE.NETSLICEINSTANCE.CREATENETSLICEINSTANCE' | translate}}
+        </button>
+    </span>
+</div>
+<div class="row mt-2 mb-0 list-utilites-actions">
+    <div class="col-auto mr-auto">
+        <nav class="custom-items-config">
+            <span><i class="fas fa-clock text-warning"></i>{{operationalStateFirstStep}}</span>
+            <span><i class="fas fa-check-circle text-success"></i>{{operationalStateSecondStep}} /
+                {{configStateSecondStep}}</span>
+            <span><i class="fas fa-times-circle text-danger"></i>{{operationalStateThirdStep}}</span>
+        </nav>
+    </div>
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/instances/netslice-instances/NetsliceInstancesComponent.scss b/src/app/instances/netslice-instances/NetsliceInstancesComponent.scss
new file mode 100644 (file)
index 0000000..0ecd95d
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
\ No newline at end of file
diff --git a/src/app/instances/netslice-instances/NetsliceInstancesComponent.ts b/src/app/instances/netslice-instances/NetsliceInstancesComponent.ts
new file mode 100644 (file)
index 0000000..3b9564a
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Netslice Instance Component
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { InstantiateNetSliceTemplateComponent } from 'InstantiateNetSliceTemplate';
+import { NetsliceInstancesActionComponent } from 'NetsliceInstancesActionComponent';
+import { NSTInstanceData, NSTInstanceDetails } from 'NetworkSliceModel';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes NetsliceInstancesComponent.html as template url
+ */
+@Component({
+    templateUrl: './NetsliceInstancesComponent.html',
+    styleUrls: ['./NetsliceInstancesComponent.scss']
+})
+
+/** Exporting a class @exports NetsliceInstancesComponent */
+export class NetsliceInstancesComponent implements OnInit {
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** handle translate @public */
+    public translateService: TranslateService;
+
+    /** Columns list of the smart table @public */
+    public columnLists: object = {};
+
+    /** Settings for smarttable to populate the table with columns @public */
+    public settings: object = {};
+
+    /** Datasource instance inititated  @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** Datasource table Data for the NST @public */
+    public nstInstanceData: NSTInstanceData[] = [];
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+
+    /** operational State init data @public */
+    public operationalStateFirstStep: string = CONFIGCONSTANT.operationalStateFirstStep;
+
+    /** operational State running data @public */
+    public operationalStateSecondStep: string = CONFIGCONSTANT.operationalStateSecondStep;
+
+    /** operational State failed data @public */
+    public operationalStateThirdStep: string = CONFIGCONSTANT.operationalStateThirdStep;
+
+    /** Config State init data @public */
+    public configStateFirstStep: string = CONFIGCONSTANT.configStateFirstStep;
+
+    /** Config State init data @public */
+    public configStateSecondStep: string = CONFIGCONSTANT.configStateSecondStep;
+
+    /** Config State init data @public */
+    public configStateThirdStep: string = CONFIGCONSTANT.configStateThirdStep;
+
+    /** config status assign @public */
+    public configStatusCheck: string;
+
+    /** To consume REST API calls @private */
+    private dataService: DataService;
+
+    /** Utilizes rest service for any CRUD operations @public */
+    private restService: RestService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.translateService = this.injector.get(TranslateService);
+        this.sharedService = this.injector.get(SharedService);
+        this.modalService = this.injector.get(NgbModal);
+        this.dataService = this.injector.get(DataService);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.generateTableColumn();
+        this.generateTableSettings();
+        this.generateData();
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** smart table listing manipulation @private */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** smart table listing manipulation @private */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'net-slice-instance' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** Instantiate Net Slice using modalservice @public */
+    public instantiateNetSlice(): void {
+        const modalRef: NgbModalRef = this.modalService.open(InstantiateNetSliceTemplateComponent, { backdrop: 'static' });
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.generateData();
+            }
+        }).catch();
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableSettings(): void {
+        this.settings = {
+            columns: this.columnLists,
+            actions: { add: false, edit: false, delete: false, position: 'right' },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableColumn(): void {
+        this.columnLists = {
+            name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' },
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '15%' },
+            NstName: { title: this.translateService.instant('NSTNAME'), width: '15%' },
+            OperationalStatus: {
+                type: 'html',
+                title: this.translateService.instant('OPERATIONALSTATUS'),
+                width: '15%',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: [
+                            { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep },
+                            { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep },
+                            { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep }
+                        ]
+                    }
+                },
+                valuePrepareFunction: (cell: NSTInstanceData, row: NSTInstanceData): string => {
+                    if (row.OperationalStatus === this.operationalStateFirstStep) {
+                        return `<span class="icon-label" title="${row.OperationalStatus}">
+                        <i class="fas fa-clock text-warning"></i>
+                        </span>`;
+                    } else if (row.OperationalStatus === this.operationalStateSecondStep) {
+                        return `<span class="icon-label" title="${row.OperationalStatus}">
+                        <i class="fas fa-check-circle text-success"></i>
+                        </span>`;
+                    } else if (row.OperationalStatus === this.operationalStateThirdStep) {
+                        return `<span class="icon-label" title="${row.OperationalStatus}">
+                        <i class="fas fa-times-circle text-danger"></i>
+                        </span>`;
+                    } else {
+                        return `<span>${row.OperationalStatus}</span>`;
+                    }
+                }
+            },
+            ConfigStatus: {
+                type: 'html',
+                title: this.translateService.instant('CONFIGSTATUS'),
+                width: '15%',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: [
+                            { value: this.configStateFirstStep, title: this.configStateFirstStep },
+                            { value: this.configStateSecondStep, title: this.configStateSecondStep },
+                            { value: this.configStateThirdStep, title: this.configStateThirdStep }
+                        ]
+                    }
+                },
+                valuePrepareFunction: (cell: NSTInstanceData, row: NSTInstanceData): string => {
+                    if (row.ConfigStatus === this.configStateFirstStep) {
+                        return `<span class="icon-label" title="${row.ConfigStatus}">
+                        <i class="fas fa-clock text-warning"></i>
+                        </span>`;
+                    } else if (row.ConfigStatus === this.configStateSecondStep) {
+                        return `<span class="icon-label" title="${row.ConfigStatus}">
+                        <i class="fas fa-check-circle text-success"></i>
+                        </span>`;
+                    } else if (row.ConfigStatus === this.configStateThirdStep) {
+                        return `<span class="icon-label" title="${row.ConfigStatus}">
+                        <i class="fas fa-times-circle text-danger"></i>
+                        </span>`;
+                    } else {
+                        return `<span>${row.ConfigStatus}</span>`;
+                    }
+                }
+            },
+            DetailedStatus: { title: this.translateService.instant('DETAILEDSTATUS'), width: '15%' },
+            Actions: {
+                name: 'Action', width: '10%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom',
+                valuePrepareFunction: (cell: NSTInstanceData, row: NSTInstanceData): NSTInstanceData => row,
+                renderComponent: NetsliceInstancesActionComponent
+            }
+        };
+    }
+
+    /** generateData initiate the net-slice-instance list @public */
+    public generateData(): void {
+        this.isLoadingResults = true;
+        this.restService.getResource(environment.NETWORKSLICEINSTANCESCONTENT_URL)
+            .subscribe((netSliceInstancesData: NSTInstanceDetails[]) => {
+            this.nstInstanceData = [];
+            netSliceInstancesData.forEach((netSliceInstanceData: NSTInstanceDetails) => {
+                if (netSliceInstanceData['config-status'] !== undefined) {
+                    this.configStatusCheck = netSliceInstanceData['config-status'];
+                } else {
+                    this.configStatusCheck = netSliceInstanceData['operational-status'];
+                }
+                const netSliceDataObj: NSTInstanceData = {
+                    name: netSliceInstanceData.name,
+                    identifier: netSliceInstanceData.id,
+                    NstName: netSliceInstanceData['nst-ref'],
+                    OperationalStatus: netSliceInstanceData['operational-status'],
+                    ConfigStatus: this.configStatusCheck,
+                    DetailedStatus: netSliceInstanceData['detailed-status']
+                };
+                this.nstInstanceData.push(netSliceDataObj);
+            });
+            if (this.nstInstanceData.length > 0) {
+                this.checkDataClass = 'dataTables_present';
+            } else {
+                this.checkDataClass = 'dataTables_empty';
+            }
+            this.dataSource.load(this.nstInstanceData).then((data: {}) => {
+                this.isLoadingResults = false;
+            }).catch();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+}
diff --git a/src/app/instances/ns-history-operations/HistoryOperationsComponent.html b/src/app/instances/ns-history-operations/HistoryOperationsComponent.html
new file mode 100644 (file)
index 0000000..7890a13
--- /dev/null
@@ -0,0 +1,36 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'HISTORYOFOPERATIONS' | translate}}</div>
+</div>
+<div class="row mt-2 mb-0 list-utilites-actions">
+    <div class="col-auto mr-auto">
+        <nav class="custom-items-config">
+            <span><i class="fas fa-clock text-warning"></i>{{historyStateFirstStep}}</span>
+            <span><i class="fas fa-check-circle text-success"></i>{{historyStateSecondStep}}</span>
+            <span><i class="fas fa-times-circle text-danger"></i>{{historyStateThirdStep}}</span>
+        </nav>
+    </div>
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)" (custom)="showInformation($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/instances/ns-history-operations/HistoryOperationsComponent.scss b/src/app/instances/ns-history-operations/HistoryOperationsComponent.scss
new file mode 100644 (file)
index 0000000..fdec4ed
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
diff --git a/src/app/instances/ns-history-operations/HistoryOperationsComponent.ts b/src/app/instances/ns-history-operations/HistoryOperationsComponent.ts
new file mode 100644 (file)
index 0000000..a0cac86
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file NS History Of Operations Component
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { Router } from '@angular/router';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { CONFIGCONSTANT, ERRORDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import * as HttpStatus from 'http-status-codes';
+import { LocalDataSource } from 'ng2-smart-table';
+import { NSDInstanceData } from 'NSInstanceModel';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+import { ShowInfoComponent } from 'ShowInfoComponent';
+
+/**
+ * Creating component
+ * @Component takes HistoryOperationsComponent.html as template url
+ */
+@Component({
+  templateUrl: './HistoryOperationsComponent.html',
+  styleUrls: ['./HistoryOperationsComponent.scss']
+})
+/** Exporting a class @exports HistoryOperationsComponent */
+export class HistoryOperationsComponent implements OnInit {
+  /** Injector to invoke other services @public */
+  public injector: Injector;
+
+  /** NS Instance array @public */
+  public nsAndnstInstanceData: object[] = [];
+
+  /** Datasource instance @public */
+  public dataSource: LocalDataSource = new LocalDataSource();
+
+  /** Instance component are stored in settings @public */
+  public settings: {} = {};
+
+  /** Contains objects for smart table title and filter settings @public */
+  public columnList: {} = {};
+
+  /** Variable handles the page name @public */
+  public page: string;
+
+  /** Variable handles the title name @public */
+  public titleName: string;
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = true;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Class for empty and present data @public */
+  public checkDataClass: string;
+
+  /** History State init data @public */
+  public historyStateFirstStep: string = CONFIGCONSTANT.historyStateFirstStep;
+
+  /** History State running data @public */
+  public historyStateSecondStep: string = CONFIGCONSTANT.historyStateSecondStep;
+
+  /** History State failed data @public */
+  public historyStateThirdStep: string = CONFIGCONSTANT.historyStateThirdStep;
+
+  /** dataService to pass the data from one component to another @private */
+  private dataService: DataService;
+
+  /** Utilizes rest service for any CRUD operations @private */
+  private restService: RestService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private activatedRoute: ActivatedRoute;
+
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  /** variables contains paramsID @private */
+  private paramsID: string;
+
+  /** variables contains paramsID @private */
+  private paramsType: string;
+
+  /** variables conatins URL of the History operations @public */
+  private historyURL: string;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Instance of subscriptions @private */
+  private generateDataSub: Subscription;
+
+  /** Service holds the router information @private */
+  private router: Router;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.dataService = this.injector.get(DataService);
+    this.sharedService = this.injector.get(SharedService);
+    this.activatedRoute = this.injector.get(ActivatedRoute);
+    this.modalService = this.injector.get(NgbModal);
+    this.translateService = this.injector.get(TranslateService);
+    this.router = this.injector.get(Router);
+  }
+
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    // tslint:disable-next-line:no-backbone-get-set-outside-model
+    this.paramsID = this.activatedRoute.snapshot.paramMap.get('id');
+    // tslint:disable-next-line:no-backbone-get-set-outside-model
+    this.paramsType = this.activatedRoute.snapshot.paramMap.get('type');
+    if (this.paramsType === 'ns') {
+      this.historyURL = environment.NSHISTORYOPERATIONS_URL + '/?nsInstanceId=' + this.paramsID;
+      this.page = 'ns-history-operation';
+      this.titleName = 'INSTANCEDETAILS';
+    } else if (this.paramsType === 'netslice') {
+      this.historyURL = environment.NSTHISTORYOPERATIONS_URL + '/?netsliceInstanceId=' + this.paramsID;
+      this.page = 'nst-history-operation';
+      this.titleName = 'INSTANCEDETAILS';
+    }
+    this.generateTableColumn();
+    this.generateTableSettings();
+    this.generateData();
+    this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+  }
+
+  /** Generate smart table row title and filters @public  */
+  public generateTableSettings(): void {
+    this.settings = {
+      columns: this.columnList,
+      actions: {
+        add: false, edit: false, delete: false, position: 'right',
+        custom: [{
+          name: 'showInformation', title: '<i class="fas fa-info" title=" ' + this.translateService.instant('INFO') + ' "></i>'}]
+      },
+      attr: this.sharedService.tableClassConfig(),
+      pager: this.sharedService.paginationPagerConfig(),
+      noDataMessage: this.translateService.instant('NODATAMSG')
+    };
+  }
+
+  /** Generate smart table row title and filters @public  */
+  public generateTableColumn(): void {
+    this.columnList = {
+      id: { title: this.translateService.instant('ID'), width: '30%' },
+      type: { title: this.translateService.instant('TYPE'), width: '20%' },
+      state: {
+        type: 'html', title: this.translateService.instant('OPERATIONSTATE'), width: '15%',
+        filter: {
+          type: 'list',
+          config: {
+            selectText: 'Select',
+            list: [
+              { value: this.historyStateFirstStep, title: this.historyStateFirstStep },
+              { value: this.historyStateSecondStep, title: this.historyStateSecondStep },
+              { value: this.historyStateThirdStep, title: this.historyStateThirdStep }
+            ]
+          }
+        },
+        valuePrepareFunction: (cell: NSDInstanceData, row: NSDInstanceData): string => {
+          if (row.state === this.historyStateFirstStep) {
+            return `<span class="icon-label" title="${row.state}">
+                        <i class="fas fa-clock text-warning"></i>
+                        </span>`;
+          } else if (row.state === this.historyStateSecondStep) {
+            return `<span class="icon-label" title="${row.state}">
+                        <i class="fas fa-check-circle text-success"></i>
+                        </span>`;
+          } else if (row.state === this.historyStateThirdStep) {
+            return `<span class="icon-label" title="${row.state}">
+                        <i class="fas fa-times-circle text-danger"></i>
+                        </span>`;
+          } else {
+            return `<span>${row.state}</span>`;
+          }
+        }
+      },
+      startTime: { title: this.translateService.instant('STARTTIME'), width: '15%' },
+      statusEnteredTime: { title: this.translateService.instant('STATUSENTEREDTIME'), width: '15%' }
+    };
+  }
+
+  /** smart table listing manipulation @public */
+  public onUserRowSelect(event: MessageEvent): void {
+    this.dataService.changeMessage(event.data);
+  }
+  /** smart table listing manipulation @public */
+  public onChange(perPageValue: number): void {
+    this.dataSource.setPaging(1, perPageValue, true);
+  }
+  /** show information methods modal with ns history info */
+  public showInformation(event: MessageEvent): void {
+    this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = {
+      id: event.data.id,
+      page: this.page,
+      titleName: this.titleName
+    };
+  }
+
+  /**
+   * Lifecyle hook which get trigger on component destruction
+   */
+  public ngOnDestroy(): void {
+    this.generateDataSub.unsubscribe();
+  }
+
+  /** generateData initiate the ns-instance list @private */
+  private generateData(): void {
+    this.isLoadingResults = true;
+    this.restService.getResource(this.historyURL).subscribe((nsdInstancesData: {}[]) => {
+      this.nsAndnstInstanceData = [];
+      nsdInstancesData.forEach((nsdAndnstInstanceData: NSDInstanceData) => {
+        const nsAndnstDataObj: {} = {
+          id: nsdAndnstInstanceData.id,
+          type: nsdAndnstInstanceData.lcmOperationType,
+          state: nsdAndnstInstanceData.operationState,
+          startTime: this.sharedService.convertEpochTime(nsdAndnstInstanceData.startTime),
+          statusEnteredTime: this.sharedService.convertEpochTime(nsdAndnstInstanceData.statusEnteredTime)
+        };
+        this.nsAndnstInstanceData.push(nsAndnstDataObj);
+      });
+
+      if (this.nsAndnstInstanceData.length > 0) {
+        this.checkDataClass = 'dataTables_present';
+      } else {
+        this.checkDataClass = 'dataTables_empty';
+      }
+      this.dataSource.load(this.nsAndnstInstanceData).then((data: {}) => {
+        //empty block
+      }).catch();
+      this.isLoadingResults = false;
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
+        this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
+      } else {
+        this.restService.handleError(error, 'get');
+      }
+    });
+  }
+}
diff --git a/src/app/instances/ns-instances/NSInstancesComponent.html b/src/app/instances/ns-instances/NSInstancesComponent.html
new file mode 100644 (file)
index 0000000..6047a2f
--- /dev/null
@@ -0,0 +1,43 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'NSINSTANCES' | translate}}</div>
+    <span class="button">
+        <button class="btn btn-primary" type="button" placement="top" container="body" ngbTooltip="{{'PAGE.NSINSTANCE.NEWNSINSTANCE' | translate}}"
+            (click)="instantiateNS()">
+            <i class="fa fa-paper-plane" aria-hidden="true"></i>&nbsp; {{'PAGE.NSINSTANCE.NEWNSINSTANCE' | translate}}
+        </button>
+    </span>
+</div>
+<div class="row mt-2 mb-0 list-utilites-actions">
+    <div class="col-auto mr-auto">
+        <nav class="custom-items-config">
+            <span><i class="fas fa-clock text-warning"></i>{{operationalStateFirstStep}}</span>
+            <span><i class="fas fa-check-circle text-success"></i>{{operationalStateSecondStep}} /
+                {{configStateSecondStep}}</span>
+            <span><i class="fas fa-times-circle text-danger"></i>{{operationalStateThirdStep}}</span>
+        </nav>
+    </div>
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/instances/ns-instances/NSInstancesComponent.scss b/src/app/instances/ns-instances/NSInstancesComponent.scss
new file mode 100644 (file)
index 0000000..0ecd95d
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
\ No newline at end of file
diff --git a/src/app/instances/ns-instances/NSInstancesComponent.ts b/src/app/instances/ns-instances/NSInstancesComponent.ts
new file mode 100644 (file)
index 0000000..07184da
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file NS Instance Component
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { InstantiateNsComponent } from 'InstantiateNs';
+import { LocalDataSource } from 'ng2-smart-table';
+import { NSDInstanceData, NSInstanceDetails } from 'NSInstanceModel';
+import { NSInstancesActionComponent } from 'NSInstancesActionComponent';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes NSInstancesComponent.html as template url
+ */
+@Component({
+    templateUrl: './NSInstancesComponent.html',
+    styleUrls: ['./NSInstancesComponent.scss']
+})
+/** Exporting a class @exports NSInstancesComponent */
+export class NSInstancesComponent implements OnInit {
+    /** Injector to invoke other services @public */
+    public injector: Injector;
+
+    /** NS Instance array @public */
+    public nsInstanceData: object[] = [];
+
+    /** Datasource instance @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** SelectedRows array @public */
+    public selectedRows: object[] = [];
+
+    /** Selected list array @public */
+    public selectList: object[] = [];
+
+    /** Instance component are stored in settings @public */
+    public settings: {} = {};
+
+    /** Contains objects for menu settings @public */
+    public columnList: {} = {};
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+
+    /** operational State init data @public */
+    public operationalStateFirstStep: string = CONFIGCONSTANT.operationalStateFirstStep;
+
+    /** operational State running data @public */
+    public operationalStateSecondStep: string = CONFIGCONSTANT.operationalStateSecondStep;
+
+    /** operational State failed data @public */
+    public operationalStateThirdStep: string = CONFIGCONSTANT.operationalStateThirdStep;
+
+    /** Config State init data @public */
+    public configStateFirstStep: string = CONFIGCONSTANT.configStateFirstStep;
+
+    /** Config State init data @public */
+    public configStateSecondStep: string = CONFIGCONSTANT.configStateSecondStep;
+
+    /** Config State init data @public */
+    public configStateThirdStep: string = CONFIGCONSTANT.configStateThirdStep;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** dataService to pass the data from one component to another @private */
+    private dataService: DataService;
+
+    /** Utilizes rest service for any CRUD operations @private */
+    private restService: RestService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** Contains tranlsate instance @private */
+    private translateService: TranslateService;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.sharedService = this.injector.get(SharedService);
+        this.translateService = this.injector.get(TranslateService);
+        this.modalService = this.injector.get(NgbModal);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.generateTableColumn();
+        this.generateTableSettings();
+        this.generateData();
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableSettings(): void {
+        this.settings = {
+            columns: this.columnList,
+            actions: { add: false, edit: false, delete: false, position: 'right' },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableColumn(): void {
+        this.columnList = {
+            name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' },
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' },
+            NsdName: { title: this.translateService.instant('NSDNAME'), width: '15%' },
+            OperationalStatus: {
+                title: this.translateService.instant('OPERATIONALSTATUS'), width: '10%', type: 'html',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: [
+                            { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep },
+                            { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep },
+                            { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep }
+                        ]
+                    }
+                },
+                valuePrepareFunction: (cell: NSDInstanceData, row: NSDInstanceData): string => {
+                    if (row.OperationalStatus === this.operationalStateFirstStep) {
+                        return `<span class="icon-label" title="${row.OperationalStatus}">
+                        <i class="fas fa-clock text-warning"></i>
+                        </span>`;
+                    } else if (row.OperationalStatus === this.operationalStateSecondStep) {
+                        return `<span class="icon-label" title="${row.OperationalStatus}">
+                        <i class="fas fa-check-circle text-success"></i>
+                        </span>`;
+                    } else if (row.OperationalStatus === this.operationalStateThirdStep) {
+                        return `<span class="icon-label" title="${row.OperationalStatus}">
+                        <i class="fas fa-times-circle text-danger"></i>
+                        </span>`;
+                    } else {
+                        return `<span>${row.OperationalStatus}</span>`;
+                    }
+                }
+            },
+            ConfigStatus: {
+                title: this.translateService.instant('CONFIGSTATUS'), width: '10%', type: 'html',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: [
+                            { value: this.configStateFirstStep, title: this.configStateFirstStep },
+                            { value: this.configStateSecondStep, title: this.configStateSecondStep },
+                            { value: this.configStateThirdStep, title: this.configStateThirdStep }
+                        ]
+                    }
+                },
+                valuePrepareFunction: (cell: NSDInstanceData, row: NSDInstanceData): string => {
+                    if (row.ConfigStatus === this.configStateFirstStep) {
+                        return `<span class="icon-label" title="${row.ConfigStatus}">
+                        <i class="fas fa-clock text-warning"></i>
+                        </span>`;
+                    } else if (row.ConfigStatus === this.configStateSecondStep) {
+                        return `<span class="icon-label" title="${row.ConfigStatus}">
+                        <i class="fas fa-check-circle text-success"></i>
+                        </span>`;
+                    } else if (row.ConfigStatus === this.configStateThirdStep) {
+                        return `<span class="icon-label" title="${row.ConfigStatus}">
+                        <i class="fas fa-times-circle text-danger"></i>
+                        </span>`;
+                    } else {
+                        return `<span>${row.ConfigStatus}</span>`;
+                    }
+                }
+            },
+            DetailedStatus: { title: this.translateService.instant('DETAILEDSTATUS'), width: '15%' },
+            Actions: {
+                name: 'Action', width: '15%', filter: false, sort: false, type: 'custom',
+                title: this.translateService.instant('ACTIONS'),
+                valuePrepareFunction: (cell: NSDInstanceData, row: NSDInstanceData): NSDInstanceData => row,
+                renderComponent: NSInstancesActionComponent
+            }
+        };
+    }
+
+    /** generateData initiate the ns-instance list @public */
+    public generateData(): void {
+        this.isLoadingResults = true;
+        this.restService.getResource(environment.NSDINSTANCES_URL).subscribe((nsdInstancesData: NSInstanceDetails[]) => {
+            this.nsInstanceData = [];
+            nsdInstancesData.forEach((nsdInstanceData: NSInstanceDetails) => {
+                const nsDataObj: NSDInstanceData = {
+                    name: nsdInstanceData.name,
+                    identifier: nsdInstanceData.id,
+                    NsdName: nsdInstanceData['nsd-name-ref'],
+                    OperationalStatus: nsdInstanceData['operational-status'],
+                    ConfigStatus: nsdInstanceData['config-status'],
+                    DetailedStatus: nsdInstanceData['detailed-status'],
+                    memberIndex: nsdInstanceData.nsd['constituent-vnfd'],
+                    nsConfig: nsdInstanceData.nsd['ns-configuration']
+                };
+                this.nsInstanceData.push(nsDataObj);
+            });
+            if (this.nsInstanceData.length > 0) {
+                this.checkDataClass = 'dataTables_present';
+            } else {
+                this.checkDataClass = 'dataTables_empty';
+            }
+            this.dataSource.load(this.nsInstanceData).then((data: {}) => {
+                this.isLoadingResults = false;
+            }).catch();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+
+    /** smart table listing manipulation @public */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** smart table listing manipulation @public */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'ns-instance' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** Instantiate NS using modalservice @public */
+    public instantiateNS(): void {
+        const modalRef: NgbModalRef = this.modalService.open(InstantiateNsComponent, { backdrop: 'static' });
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.generateData();
+            }
+        }).catch();
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+}
diff --git a/src/app/instances/ns-primitive/NSPrimitiveComponent.html b/src/app/instances/ns-primitive/NSPrimitiveComponent.html
new file mode 100644 (file)
index 0000000..646c8ae
--- /dev/null
@@ -0,0 +1,92 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{'PERFORMACTION' | translate}}</h4>
+    <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+        <i class="fas fa-times-circle text-danger"></i>
+    </button>
+</div>
+<form [formGroup]="primitiveForm" (ngSubmit)="execNSPrimitive()">
+    <div class="modal-body">
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label">{{'PRIMITIVETYPE' | translate}}*</label>
+            <div class="col-sm-8">
+                <ng-select (change)="primitiveTypeChange($event)" [clearable]="false"
+                    placeholder="{{'SELECT' | translate}}" [items]="primitiveTypeList" bindLabel="title"
+                    bindValue="value" [(ngModel)]="primitiveType" id="primitiveType"
+                    [ngModelOptions]="{standalone: true}"></ng-select>
+            </div>
+        </div>
+        <div class="form-group row">
+            <ng-container *ngIf="primitiveType == 'VNF_Primitive'">
+                <label class="col-sm-4 col-form-label">VNF {{'MEMBERINDEX' | translate}}*</label>
+                <div class="col-sm-3">
+                    <ng-select (change)="indexChange($event)" [clearable]="false" placeholder="{{'SELECT' | translate}}"
+                        [items]="params.memberIndex" bindLabel="member-vnf-index" bindValue="member-vnf-index"
+                        formControlName="vnf_member_index" id="vnf_member_index"
+                        [ngClass]="{ 'is-invalid': submitted && f.vnf_member_index.errors }"></ng-select>
+                </div>
+            </ng-container>
+            <label [ngClass]="{ 'col-sm-4': primitiveType != 'VNF_Primitive', 'col-sm-2': primitiveType == 'VNF_Primitive' }" class="col-form-label">
+                {{'PAGE.NSPRIMITIVE.PRIMITIVE' | translate}}*</label>
+            <div [ngClass]="{ 'col-sm-8': primitiveType != 'VNF_Primitive', 'col-sm-3': primitiveType == 'VNF_Primitive' }" class="col-sm-3">
+                <ng-select (change)="primitiveChange($event)" [clearable]="false" placeholder="{{'SELECT' | translate}}"
+                    [items]="primitiveList" bindLabel="name" bindValue="name" formControlName="primitive" id="primitive"
+                    [ngClass]="{ 'is-invalid': submitted && f.primitive.errors }"></ng-select>
+            </div>
+        </div>
+        <ng-container *ngIf="primitiveParameter.length > 0">
+            <div class="form-group row p-2 bg-light text-white justify-content-end">
+                <div class="col-5">
+                    <button type="button" class="btn btn-primary" (click)="createPrimitiveParams()">
+                        <i class="fas fa-plus-circle"></i>
+                        {{'PAGE.NSPRIMITIVE.ADDPRIMITIVEPARAMS' | translate}}</button>
+                </div>
+            </div>
+            <div formArrayName="primitive_params" *ngFor="let params of getControls(); let i = index;">
+                <div class="form-group row" [formGroupName]="i">
+                    <label class="col-sm-2 col-form-label">{{'NAME' | translate}}:</label>
+                    <div class="col-sm-3">
+                        <ng-select placeholder="{{'SELECT' | translate}}" [clearable]="false"
+                            [items]="primitiveParameter" bindLabel="name" bindValue="name"
+                            formControlName="primitive_params_name" id="parameter{{i}}"
+                            [ngClass]="{ 'is-invalid': submitted && params.controls.primitive_params_name.errors }">
+                        </ng-select>
+                    </div>
+                    <div class="col-sm-1"></div>
+                    <label class="col-sm-2 col-form-label">{{'VALUE' | translate}}:</label>
+                    <div class="col-sm-3">
+                        <input type="text" class="form-control" formControlName="primitive_params_value"
+                            [ngClass]="{ 'is-invalid': submitted && params.controls.primitive_params_value.errors }">
+                    </div>
+                    <div class="col-sm-1" [hidden]="i==0">
+                        <button type="button" class="btn btn-sm btn-danger remove-mapping"
+                            (click)="removePrimitiveParams(i)">
+                            <i class="fas fa-times-circle"></i>
+                        </button>
+                    </div>
+                </div>
+            </div>
+        </ng-container>
+    </div>
+    <div class="modal-footer">
+        <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+        <button type="submit" class="btn btn-primary">{{'EXECUTE' | translate}}</button>
+    </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/instances/ns-primitive/NSPrimitiveComponent.scss b/src/app/instances/ns-primitive/NSPrimitiveComponent.scss
new file mode 100644 (file)
index 0000000..edad97f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+@import '../../../assets/scss/mixins/mixin';
+@import '../../../assets/scss/variable';
+
+.primitive-params-head {
+    @include padding-value(10, 10, 10, 10);
+    line-height: 2em;
+    .btn-params {
+        @include border(all, 1, solid, $white);
+    }
+}
+
+.remove-params {
+    display: flex;
+    align-items: center;
+    font-size: 20px;
+    cursor: pointer;
+}
\ No newline at end of file
diff --git a/src/app/instances/ns-primitive/NSPrimitiveComponent.ts b/src/app/instances/ns-primitive/NSPrimitiveComponent.ts
new file mode 100644 (file)
index 0000000..02269d3
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file NS Instance Primitive Component
+ */
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, URLPARAMS } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { NSData } from 'NSDModel';
+import { NSPrimitiveParams } from 'NSInstanceModel';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes NSPrimitiveComponent.html as template url
+ */
+@Component({
+    templateUrl: './NSPrimitiveComponent.html',
+    styleUrls: ['./NSPrimitiveComponent.scss']
+})
+/** Exporting a class @exports NSPrimitiveComponent */
+export class NSPrimitiveComponent implements OnInit {
+    /** Form valid on submit trigger @public */
+    public submitted: boolean = false;
+
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Instance for active modal service @public */
+    public activeModal: NgbActiveModal;
+
+    /** FormGroup instance added to the form @ html @public */
+    public primitiveForm: FormGroup;
+
+    /** Primitive params array @public */
+    public primitiveParams: FormArray;
+
+    /** Variable set for twoway binding @public */
+    public nsdId: string;
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = false;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Contains list of primitive parameter @public */
+    public primitiveParameter: {}[] = [];
+
+    /** Input contains component objects @public */
+    @Input() public params: URLPARAMS;
+
+    /** Contains list of primitive actions @public */
+    public primitiveList: {}[];
+
+    /** Contains objects that is used to hold types of primitive @public */
+    public primitiveTypeList: {}[] = [];
+
+    /** Model value used to hold selected primitive type @public */
+    public primitiveType: string;
+
+    /** FormBuilder instance added to the formBuilder @private */
+    private formBuilder: FormBuilder;
+
+    /** Utilizes rest service for any CRUD operations @private */
+    private restService: RestService;
+
+    /** packages data service collections @private */
+    private dataService: DataService;
+
+    /** Contains tranlsate instance @private */
+    private translateService: TranslateService;
+
+    /** Notifier service to popup notification @private */
+    private notifierService: NotifierService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** Contains objects that is used to convert key/value pair @private */
+    private objectPrimitiveParams: {} = {};
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.translateService = this.injector.get(TranslateService);
+        this.notifierService = this.injector.get(NotifierService);
+        this.sharedService = this.injector.get(SharedService);
+        this.activeModal = this.injector.get(NgbActiveModal);
+        this.formBuilder = this.injector.get(FormBuilder);
+        this.primitiveTypeList = [{ title: this.translateService.instant('VNFPRIMITIVE'), value: 'VNF_Primitive' }];
+        this.primitiveType = 'VNF_Primitive';
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        /** Setting up initial value for NSD */
+        this.dataService.currentMessage.subscribe((event: NSData) => {
+            if (event.identifier !== undefined || event.identifier !== '' || event.identifier !== null) {
+                this.nsdId = event.identifier;
+            }
+        });
+        if (!isNullOrUndefined(this.params.nsConfig)) {
+            this.primitiveTypeList.push({ title: this.translateService.instant('NSPRIMITIVE'), value: 'NS_Primitive' });
+        }
+        this.initializeForm();
+    }
+
+    /** convenience getter for easy access to form fields */
+    get f(): FormGroup['controls'] { return this.primitiveForm.controls; }
+
+    /** initialize Forms @public */
+    public initializeForm(): void {
+        this.primitiveForm = this.formBuilder.group({
+            primitive: [null, [Validators.required]],
+            vnf_member_index: [null, [Validators.required]],
+            primitive_params: this.formBuilder.array([this.primitiveParamsBuilder()])
+        });
+    }
+
+    /** Generate primitive params @public */
+    public primitiveParamsBuilder(): FormGroup {
+        return this.formBuilder.group({
+            primitive_params_name: [null, [Validators.required]],
+            primitive_params_value: ['', [Validators.required]]
+        });
+    }
+
+    /** Handle FormArray Controls @public */
+    public getControls(): AbstractControl[] {
+        return (this.getFormControl('primitive_params') as FormArray).controls;
+    }
+
+    /** Push all primitive params on user's action @public */
+    public createPrimitiveParams(): void {
+        this.primitiveParams = this.getFormControl('primitive_params') as FormArray;
+        this.primitiveParams.push(this.primitiveParamsBuilder());
+    }
+
+    /** Remove primitive params on user's action @public */
+    public removePrimitiveParams(index: number): void {
+        this.primitiveParams.removeAt(index);
+    }
+
+    /** Execute NS Primitive @public */
+    public execNSPrimitive(): void {
+        this.submitted = true;
+        this.objectPrimitiveParams = {};
+        this.sharedService.cleanForm(this.primitiveForm);
+        if (this.primitiveForm.invalid) { return; } // Proceed, onces form is valid
+        this.primitiveForm.value.primitive_params.forEach((params: NSPrimitiveParams) => {
+            if (params.primitive_params_name !== null && params.primitive_params_value !== '') {
+                this.objectPrimitiveParams[params.primitive_params_name] = params.primitive_params_value;
+            }
+        });
+        //Prepare primitive params
+        const primitiveParamsPayLoads: {} = {
+            primitive: this.primitiveForm.value.primitive,
+            primitive_params: this.objectPrimitiveParams
+        };
+        if (this.primitiveType === 'VNF_Primitive') {
+            // tslint:disable-next-line: no-string-literal
+            primitiveParamsPayLoads['vnf_member_index'] = this.primitiveForm.value.vnf_member_index;
+        }
+        const apiURLHeader: APIURLHEADER = {
+            url: environment.NSDINSTANCES_URL + '/' + this.nsdId + '/action'
+        };
+        this.isLoadingResults = true;
+        this.restService.postResource(apiURLHeader, primitiveParamsPayLoads).subscribe((result: {}) => {
+            this.activeModal.dismiss();
+            this.notifierService.notify('success', this.translateService.instant('PAGE.NSPRIMITIVE.EXECUTEDSUCCESSFULLY'));
+            this.isLoadingResults = false;
+        }, (error: ERRORDATA) => {
+            this.isLoadingResults = false;
+            this.restService.handleError(error, 'post');
+        });
+    }
+    /** Primitive type change event @public */
+    public primitiveTypeChange(data: { value: string }): void {
+        this.primitiveList = [];
+        this.primitiveParameter = [];
+        this.initializeForm();
+        if (data.value === 'NS_Primitive') {
+            this.primitiveList = !isNullOrUndefined(this.params.nsConfig['config-primitive']) ?
+                this.params.nsConfig['config-primitive'] : [];
+            this.getFormControl('vnf_member_index').setValidators([]);
+        }
+    }
+    /** Member index change event */
+    public indexChange(data: {}): void {
+        if (data) {
+            this.getVnfdInfo(data['vnfd-id-ref']);
+        } else {
+            this.primitiveList = [];
+            this.getFormControl('primitive').setValue(null);
+            this.primitiveParameter = [];
+        }
+    }
+    /** Primivtive change event */
+    public primitiveChange(data: { parameter: {}[] }): void {
+        this.primitiveParameter = [];
+        const formArr: FormArray = this.getFormControl('primitive_params') as FormArray;
+        formArr.controls = [];
+        this.createPrimitiveParams();
+        if (data) {
+            this.updatePrimitive(data);
+        }
+    }
+    /** Update primitive value based on parameter */
+    private updatePrimitive(primitive: { parameter: {}[] }): void {
+        if (primitive.parameter) {
+            this.primitiveParameter = primitive.parameter;
+        } else {
+            this.primitiveParameter = [];
+            const formArr: AbstractControl[] = this.getControls();
+            formArr.forEach((formGp: FormGroup) => {
+                formGp.controls.primitive_params_name.setValidators([]);
+                formGp.controls.primitive_params_name.updateValueAndValidity();
+                formGp.controls.primitive_params_value.setValidators([]);
+                formGp.controls.primitive_params_value.updateValueAndValidity();
+            });
+        }
+    }
+    /** Get primivitive actions from vnfd data */
+    private getVnfdInfo(vnfdRef: string): void {
+        this.primitiveList = [];
+        this.primitiveParameter = [];
+        this.getFormControl('primitive').setValue(null);
+        const apiUrl: string = environment.VNFPACKAGES_URL + '?short-name=' + vnfdRef;
+        this.isLoadingResults = true;
+        this.restService.getResource(apiUrl)
+            .subscribe((vnfdInfo: {}) => {
+                if (vnfdInfo[0]['vnf-configuration']) {
+                    this.primitiveList = vnfdInfo[0]['vnf-configuration']['config-primitive'];
+                }
+                this.isLoadingResults = false;
+            }, (error: ERRORDATA) => {
+                this.isLoadingResults = false;
+                this.restService.handleError(error, 'get');
+            });
+    }
+    /** Used to get the AbstractControl of controlName passed @private */
+    private getFormControl(controlName: string): AbstractControl {
+        return this.primitiveForm.controls[controlName];
+    }
+}
diff --git a/src/app/instances/ns-topology/NSTopologyComponent.html b/src/app/instances/ns-topology/NSTopologyComponent.html
new file mode 100644 (file)
index 0000000..0a3051c
--- /dev/null
@@ -0,0 +1,173 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<ng-sidebar-container class="ns-instance-topology-sidebar-container">
+    <!-- A sidebar -->
+    <ng-sidebar [(opened)]="sideBarOpened" position="left">
+        <div class="sidebar-header">
+            <span class="topology_title" *ngIf="isShowNSDetails">{{'NS' | translate}} {{'VIEW' | translate}}</span>
+            <span class="topology_title" *ngIf="isShowVLetails">{{'PAGE.TOPOLOGY.VIRTUALLINK' | translate}}</span>
+            <span class="topology_title" *ngIf="isShowVNFRDetails">{{'PAGE.TOPOLOGY.VNF' | translate}}</span>
+        </div>
+        <div class="sidebar-body">
+            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="isShowNSDetails && nsInfo">
+                <div class="row">
+                    <div class="col-12 p-0">
+                        <table class="table table-bordered text-dark custom-table">
+                            <tr>
+                                <td>{{'NS' | translate}} {{'INSTANCE' | translate}} Id</td>
+                                <td>{{(nsInfo.nsInstanceID)?nsInfo.nsInstanceID:'-'}}</td>
+                            </tr>
+                            <tr>
+                                <td>{{'NSDNAME' | translate}}</td>
+                                <td>{{(nsInfo.nsName)?nsInfo.nsName:'-'}}</td>
+                            </tr>
+                            <tr>
+                                <td>{{'OPERATIONALSTATUS' | translate}}</td>
+                                <td>{{(nsInfo.nsOperationalStatus)?nsInfo.nsOperationalStatus:'-'}}</td>
+                            </tr>
+                            <tr>
+                                <td>{{'CONFIGSTATUS' | translate}}</td>
+                                <td>{{(nsInfo.nsConfigStatus)?nsInfo.nsConfigStatus:'-'}}</td>
+                            </tr>
+                            <tr>
+                                <td>{{'DETAILEDSTATUS' | translate}}</td>
+                                <td>{{(nsInfo.nsDetailedStatus)?nsInfo.nsDetailedStatus:'-'}}</td>
+                            </tr>
+                            <tr>
+                                <td>{{'RESOURCEORCHESTRATOR' | translate}}</td>
+                                <td>{{(nsInfo.nsResourceOrchestrator)?nsInfo.nsResourceOrchestrator:'-'}}</td>
+                            </tr>
+                        </table>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="isShowVLetails && virtualLink">
+                <div class="row">
+                    <div class="col-12 p-0">
+                        <table class="table table-bordered text-dark custom-table">
+                            <tbody>
+                                <tr>
+                                    <td>short-name</td>
+                                    <td>{{(virtualLink.shortName)?virtualLink.shortName:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>Name</td>
+                                    <td>{{(virtualLink.name)?virtualLink.name:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>Vim network name</td>
+                                    <td>{{(virtualLink.vimNetworkName)?virtualLink.vimNetworkName:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>Type</td>
+                                    <td>{{(virtualLink.type)?virtualLink.type:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>Id</td>
+                                    <td>{{(virtualLink.id)?virtualLink.id:'-'}}</td>
+                                </tr>
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="isShowVNFRDetails && vnfr">
+                <div class="row">
+                    <div class="col-12 p-0">
+                        <table class="table table-bordered text-dark custom-table">
+                            <tbody>
+                                <tr>
+                                    <td>VIM Id</td>
+                                    <td>{{(vnfr.vimID)?vnfr.vimID:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>_id</td>
+                                    <td>{{(vnfr._id)?vnfr._id:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>IP</td>
+                                    <td>{{(vnfr.ip)?vnfr.ip:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>Nsr Id</td>
+                                    <td>{{(vnfr.nsrID)?vnfr.nsrID:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>Id</td>
+                                    <td>{{(vnfr.id)?vnfr.id:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>Vnfd Ref</td>
+                                    <td>{{(vnfr.vnfdRef)?vnfr.vnfdRef:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>Vnfd Id</td>
+                                    <td>{{(vnfr.vnfdID)?vnfr.vnfdID:'-'}}</td>
+                                </tr>
+                                <tr>
+                                    <td>Member index</td>
+                                    <td>{{(vnfr.memberIndex)?vnfr.memberIndex:'-'}}</td>
+                                </tr>
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </ng-sidebar>
+    <!-- Page content -->
+    <div ng-sidebar-content>
+        <button (click)="toggleSidebar()" class="btn btn-default" placement="right" ngbTooltip="{{'OPEN' | translate }}">
+            <i class="fa fa-arrow-right detail-sidebar" aria-hidden="true"></i>
+        </button>
+    </div>
+</ng-sidebar-container>
+<div class="container-fluid text-dark">
+    <div class="row ns-instance-form justify-content-end ">
+        <div class="col-xs-9 col-sm-9 col-md-9 col-lg-9">
+            <div class="row">
+                <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 pl-0">
+                    <div class="btn-group list" role="group" aria-label="Basic example">
+                        <button type="button" class="btn btn-primary topology-btn" (click)="onFreeze()"
+                            [class.pinned]="classApplied" placement="top" container="body"
+                            ngbTooltip="{{(classApplied ? 'UNFREEZE' : 'FREEZE') | translate}}">
+                            <i class="fas fa-thumbtack"></i>
+                        </button>
+                    </div>
+                </div>
+                <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 text-right pr-0 badgegroup">
+                    <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+                        <img src="assets/images/VNFD.svg" class="ns-svg" draggable="false"/>
+                        <br>VNFR</span>
+                    <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+                        <img src="assets/images/VL.svg" class="ns-svg" draggable="false"/>
+                        <br>VL</span>
+                    <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+                        <img src="assets/images/CP.svg" class="ns-svg" draggable="false"/>
+                        <br>CP</span>
+                </div>
+            </div>
+            <div class="row border-all">
+                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 svg-container">
+                    <svg preserveAspectRatio="xMidYMin slice" id="graphContainer" #graphContainer></svg>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/instances/ns-topology/NSTopologyComponent.scss b/src/app/instances/ns-topology/NSTopologyComponent.scss
new file mode 100644 (file)
index 0000000..d750ccc
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/instances/ns-topology/NSTopologyComponent.ts b/src/app/instances/ns-topology/NSTopologyComponent.ts
new file mode 100644 (file)
index 0000000..44c6309
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file NS Topology Component
+ */
+/* tslint:disable:no-increment-decrement */
+import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { Router } from '@angular/router';
+import { TranslateService } from '@ngx-translate/core';
+import { ERRORDATA } from 'CommonModel';
+import * as d3 from 'd3';
+import { environment } from 'environment';
+import * as HttpStatus from 'http-status-codes';
+import { VNFDCONNECTIONPOINTREF } from 'NSDModel';
+import { COMPOSERNODES, CONNECTIONPOINT, NSD, NSDVLD, NSINFO, NSInstanceDetails, NSINSTANCENODES, VLINFO, VNFRINFO } from 'NSInstanceModel';
+import { GRAPHDETAILS, Tick, TickPath } from 'NSTopologyModel';
+import { RestService } from 'src/services/RestService';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes NSTopologyComponent.html as template url
+ */
+@Component({
+  selector: 'app-ns-topology',
+  templateUrl: './NSTopologyComponent.html',
+  styleUrls: ['./NSTopologyComponent.scss'],
+  encapsulation: ViewEncapsulation.None
+})
+/** Exporting a class @exports NSTopologyComponent */
+export class NSTopologyComponent {
+  /** Injector to invoke other services @public */
+  public injector: Injector;
+  /** View child contains graphContainer ref @public  */
+  @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef;
+  /** Holds the basic information of NS @public */
+  public nsInfo: NSINFO;
+  /** Contains tranlsate instance @private */
+  public translateService: TranslateService;
+  /** Add the activeclass for the selected @public */
+  public activeClass: string = 'active';
+  /** Add the fixed class for the freeze @public */
+  public fixedClass: string = 'fixed';
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = true;
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+  /** Assign the forcesimulation active @public */
+  public forceSimulationActive: boolean = false;
+  /** Assign pinned class for the button when freezed @public */
+  public classApplied: boolean = false;
+  /** Contains sidebar open status @public */
+  public sideBarOpened: boolean = true;
+  /** Need to show the NS Details @public */
+  public isShowNSDetails: boolean = true;
+  /** Need to show the VL Details @public */
+  public isShowVLetails: boolean = false;
+  /** Need to show the VNFR Details @public */
+  public isShowVNFRDetails: boolean = false;
+  /** Show right side info of Virtual Link @public */
+  public virtualLink: VLINFO;
+  /** Show right side info of Virtual Link @public */
+  public vnfr: VNFRINFO;
+
+  /** Contains lastkeypressed instance @private */
+  private lastKeyDown: number = -1;
+  /** Instance of the rest service @private */
+  private restService: RestService;
+  /** Holds the instance of AuthService class of type AuthService @private */
+  private activatedRoute: ActivatedRoute;
+  /** Holds the NS Id @private */
+  private nsIdentifier: string;
+  /** Contains SVG attributes @private */
+  // tslint:disable-next-line:no-any
+  private svg: any;
+  /** Contains forced node animations @private */
+  // tslint:disable-next-line:no-any
+  private force: any;
+  /** Contains path information of the node */
+  // tslint:disable-next-line:no-any
+  private path: any;
+  /** Contains node network @private */
+  // tslint:disable-next-line:no-any
+  private network: any;
+  /** Contains node square @private */
+  // tslint:disable-next-line:no-any
+  private square: any;
+  /** Contains node circle @private */
+  // tslint:disable-next-line:no-any
+  private circle: any;
+  /** Contains the NS information @private */
+  private nsData: NSInstanceDetails;
+  /** Contains NDS information of a descriptors */
+  private nsdData: NSD;
+  /** Contains node information @private */
+  private nodes: NSINSTANCENODES[] = [];
+  /** Contains links information @private */
+  private links: {}[] = [];
+  /** holds cp count/iteration @private */
+  private cpCount: number;
+  /** VNFD nodes @private */
+  private vnfdNodes: {}[] = [];
+  /** VLD nodes @private */
+  private vldNodes: {}[] = [];
+  /** Connection CP nodes @private */
+  private cpNodes: {}[] = [];
+  /** Set timeout @private */
+  private TIMEOUT: number = 2000;
+  /** Rendered nodes represent vnf @private */
+  // tslint:disable-next-line:no-any
+  private gSquare: any;
+  /** Rendered nodes represent network @private */
+  // tslint:disable-next-line:no-any
+  private gNetwork: any;
+  /** Rendered nodes represent network @private */
+  // tslint:disable-next-line:no-any
+  private gCircle: any;
+  /** Service holds the router information @private */
+  private router: Router;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.activatedRoute = this.injector.get(ActivatedRoute);
+    this.translateService = this.injector.get(TranslateService);
+    this.router = this.injector.get(Router);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate @public
+   */
+  public ngOnInit(): void {
+    // tslint:disable-next-line:no-backbone-get-set-outside-model
+    this.nsIdentifier = this.activatedRoute.snapshot.paramMap.get('id');
+    this.generateData();
+  }
+  /** Event to freeze the animation @public */
+  public onFreeze(): void {
+    this.classApplied = !this.classApplied;
+    const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
+    d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
+    if (alreadyFixedIsActive) {
+      this.force.stop();
+    }
+    this.forceSimulationActive = alreadyFixedIsActive;
+    this.nodes.forEach((d: COMPOSERNODES) => {
+      d.fx = (alreadyFixedIsActive) ? null : d.x;
+      d.fy = (alreadyFixedIsActive) ? null : d.y;
+    });
+    if (alreadyFixedIsActive) {
+      this.force.restart();
+    }
+  }
+  /** Events handles when dragended @public */
+  public toggleSidebar(): void {
+    this.sideBarOpened = !this.sideBarOpened;
+    this.deselectAllNodes();
+    this.showRightSideInfo(true, false, false);
+  }
+  /** Get the default Configuration of containers @private */
+  private getGraphContainerAttr(): GRAPHDETAILS {
+    return {
+      width: 700,
+      height: 400,
+      nodeHeight: 50,
+      nodeWidth: 35,
+      textX: -35,
+      textY: 30,
+      radius: 5,
+      distance: 50,
+      strength: -500,
+      forcex: 2,
+      forcey: 2,
+      sourcePaddingYes: 17,
+      sourcePaddingNo: 12,
+      targetPaddingYes: 4,
+      targetPaddingNo: 3,
+      alphaTarget: 0.3,
+      imageX: -25,
+      imageY: -25,
+      shiftKeyCode: 17
+    };
+  }
+  /** Show the right-side information @private */
+  private showRightSideInfo(nsDetails: boolean, vlDetails: boolean, vnfrDeails: boolean): void {
+    this.isShowNSDetails = nsDetails;
+    this.isShowVLetails = vlDetails;
+    this.isShowVNFRDetails = vnfrDeails;
+  }
+  /** De-select all the selected nodes @private */
+  private deselectAllNodes(): void {
+    this.square.select('image').classed(this.activeClass, false);
+    this.network.select('image').classed(this.activeClass, false);
+    this.circle.select('image').classed(this.activeClass, false);
+  }
+  /** Prepare all the information for node creation @private */
+  private generateData(): void {
+    this.restService.getResource(environment.NSINSTANCESCONTENT_URL + '/' + this.nsIdentifier).subscribe((nsData: NSInstanceDetails) => {
+      this.nsData = nsData;
+      this.nsInfo = {
+        nsInstanceID: nsData._id,
+        nsName: nsData.name,
+        nsOperationalStatus: nsData['operational-status'],
+        nsConfigStatus: nsData['config-status'],
+        nsDetailedStatus: nsData['detailed-status'],
+        nsResourceOrchestrator: nsData['resource-orchestrator']
+      };
+      if (this.nsData['constituent-vnfr-ref'] !== undefined) {
+        this.generateVNFRCPNodes();
+      }
+      if (this.nsData.vld !== undefined) {
+        this.generateVLDNetworkNodes();
+      }
+      setTimeout(() => {
+        this.pushAllNodes();
+        this.generateVNFDCP();
+        this.generateVLDCP();
+        this.isLoadingResults = false;
+        this.createNode(this.nodes, this.links);
+      }, this.TIMEOUT);
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
+        this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
+      } else {
+        this.restService.handleError(error, 'get');
+      }
+    });
+  }
+
+  /** Fetching all the VNFR Information @private */
+  private generateVNFRCPNodes(): void {
+    this.nsData['constituent-vnfr-ref'].forEach((vnfdrID: string) => {
+      this.restService.getResource(environment.VNFINSTANCES_URL + '/' + vnfdrID).subscribe((vndfrDetail: NSD) => {
+        this.nodes.push({
+          id: vndfrDetail['vnfd-ref'] + ':' + vndfrDetail['member-vnf-index-ref'],
+          nodeTypeRef: 'vnfd',
+          cp: vndfrDetail['connection-point'],
+          vdur: vndfrDetail.vdur,
+          vld: vndfrDetail.vld,
+          nsID: vndfrDetail['nsr-id-ref'],
+          vnfdID: vndfrDetail['vnfd-id'],
+          vimID: vndfrDetail['vim-account-id'],
+          vndfrID: vndfrDetail.id,
+          ipAddress: vndfrDetail['ip-address'],
+          memberIndex: vndfrDetail['member-vnf-index-ref'],
+          vnfdRef: vndfrDetail['vnfd-ref'],
+          selectorId: 'nsInst-' + vndfrDetail.id
+        });
+        // Fetching all the connection point of VNF & Interface
+        vndfrDetail['connection-point'].forEach((cp: CONNECTIONPOINT) => {
+          this.nodes.push({
+            id: cp.name + ':' + vndfrDetail['member-vnf-index-ref'],
+            vndfCPRef: vndfrDetail['vnfd-ref'] + ':' + vndfrDetail['member-vnf-index-ref'],
+            nodeTypeRef: 'cp',
+            name: cp.name
+          });
+        });
+      }, (error: ERRORDATA) => {
+        this.restService.handleError(error, 'get');
+      });
+    });
+  }
+
+  /** Fetching all the VLD/Network Information @private */
+  private generateVLDNetworkNodes(): void {
+    this.nsdData = this.nsData.nsd;
+    this.nsdData.vld.forEach((ref: NSDVLD) => {
+      this.nodes.push({
+        id: ref.id,
+        nodeTypeRef: 'vld',
+        name: ref.name,
+        type: ref.type,
+        vnfdCP: ref['vnfd-connection-point-ref'],
+        vimNetworkName: ref['vim-network-name'],
+        shortName: ref['short-name'],
+        selectorId: 'nsInst-' + ref.id
+      });
+    });
+  }
+
+  /** Pushing connection points of path/links nodes @private */
+  private pushAllNodes(): void {
+    this.nodes.forEach((nodeList: NSINSTANCENODES) => {
+      if (nodeList.nodeTypeRef === 'vnfd') {
+        this.vnfdNodes.push(nodeList);
+      } else if (nodeList.nodeTypeRef === 'vld') {
+        this.vldNodes.push(nodeList);
+      } else if (nodeList.nodeTypeRef === 'cp') {
+        this.cpNodes.push(nodeList);
+      }
+    });
+  }
+
+  /** Get CP position based on vndf @private */
+  private generateVNFDCP(): void {
+    this.vnfdNodes.forEach((list: NSINSTANCENODES) => {
+      const vndfPos: number = this.nodes.map((e: NSINSTANCENODES) => { return e.id; }).indexOf(list.id);
+      this.cpCount = 0;
+      this.nodes.forEach((res: NSINSTANCENODES) => {
+        if (res.nodeTypeRef === 'cp' && res.vndfCPRef === list.id) {
+          this.links.push({ source: this.nodes[vndfPos], target: this.nodes[this.cpCount] });
+        }
+        this.cpCount++;
+      });
+    });
+  }
+
+  /** Get CP position based on vld @private */
+  private generateVLDCP(): void {
+    let vldPos: number = 0;
+    this.vldNodes.forEach((list: NSINSTANCENODES) => {
+      if (!isNullOrUndefined(list.vnfdCP)) {
+        list.vnfdCP.forEach((cpRef: VNFDCONNECTIONPOINTREF) => {
+          this.cpCount = 0;
+          this.nodes.forEach((res: NSINSTANCENODES) => {
+            if (res.nodeTypeRef === 'cp' && res.id === cpRef['vnfd-connection-point-ref'] + ':' + cpRef['member-vnf-index-ref']) {
+              this.links.push({ source: this.nodes[vldPos], target: this.nodes[this.cpCount] });
+            }
+            this.cpCount++;
+          });
+        });
+        vldPos++;
+      }
+    });
+  }
+
+  /** Node is created and render at D3 region @private */
+  private createNode(nodes: NSINSTANCENODES[], links: {}[]): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    d3.selectAll('svg#graphContainer > *').remove();
+    d3.select(window).on('keydown', () => { this.keyDown(); });
+    d3.select(window).on('keyup', () => { this.keyUp(); });
+    this.svg = d3.select('#graphContainer')
+      .attr('oncontextmenu', 'return false;')
+      .attr('width', graphContainerAttr.width)
+      .attr('height', graphContainerAttr.height);
+    this.force = d3.forceSimulation()
+      .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
+      .force('link', d3.forceLink().id((d: TickPath) => d.id).distance(graphContainerAttr.distance))
+      .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex,
+        graphContainerAttr.height / graphContainerAttr.forcey))
+      .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
+      .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
+      .on('tick', () => { this.tick(); });
+    // handles to link and node element groups
+    this.path = this.svg.append('svg:g').selectAll('path');
+    this.network = this.svg.append('svg:g').selectAll('network');
+    this.square = this.svg.append('svg:g').selectAll('rect');
+    this.circle = this.svg.append('svg:g').selectAll('circle');
+    this.restart(nodes, links);
+  }
+
+  /** Update force layout (called automatically each iteration) @private */
+  private tick(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    // draw directed edges with proper padding from node centers
+    this.path.attr('class', 'link').attr('d', (d: Tick) => {
+      const deltaX: number = d.target.x - d.source.x;
+      const deltaY: number = d.target.y - d.source.y;
+      const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+      const normX: number = deltaX / dist;
+      const normY: number = deltaY / dist;
+      const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
+      const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
+      const sourceX: number = d.source.x + (sourcePadding * normX);
+      const sourceY: number = d.source.y + (sourcePadding * normY);
+      const targetX: number = d.target.x - (targetPadding * normX);
+      const targetY: number = d.target.y - (targetPadding * normY);
+      return `M${sourceX},${sourceY}L${targetX},${targetY}`;
+    });
+    this.network.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`);
+    this.square.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`);
+    this.circle.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`);
+  }
+
+  /** Update graph (called when needed) @private */
+  private restart(nodes: NSINSTANCENODES[], links: {}[]): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.path = this.path.data(links);
+    const vnfdNodes: {}[] = []; const vldNodes: {}[] = []; const cpNodes: {}[] = []; // NB: Nodes are known by id, not by index!
+    nodes.forEach((nodeList: NSINSTANCENODES) => {
+      if (nodeList.nodeTypeRef === 'vnfd') { vnfdNodes.push(nodeList); }
+      else if (nodeList.nodeTypeRef === 'vld') { vldNodes.push(nodeList); }
+      else if (nodeList.nodeTypeRef === 'cp') { cpNodes.push(nodeList); }
+    });
+    this.square = this.square.data(vnfdNodes, (d: { id: number }) => d.id);
+    this.network = this.network.data(vldNodes, (d: { id: number }) => d.id);
+    this.circle = this.circle.data(cpNodes, (d: { id: number }) => d.id);
+    this.resetAndCreateNodes();
+    this.force.nodes(nodes).force('link').links(links); //Set the graph in motion
+    this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
+  }
+
+  /** Rest and create nodes @private */
+  private resetAndCreateNodes(): void {
+    this.path.exit().remove();
+    this.square.exit().remove();
+    this.network.exit().remove();
+    this.circle.exit().remove();
+    // tslint:disable-next-line:no-any
+    const gPath: any = this.path.enter().append('svg:path').attr('class', 'link');
+    this.getgSquare();
+    this.getgNetwork();
+    this.getgCircle();
+    this.square = this.gSquare.merge(this.square);
+    this.network = this.gNetwork.merge(this.network);
+    this.path = gPath.merge(this.path);
+    this.circle = this.gCircle.merge(this.circle);
+  }
+
+  /** Events handles when Shift Click to perform create cp @private */
+  // tslint:disable-next-line: no-any
+  private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
+    this.selectNodeExclusive(nodeSelected, d);
+  }
+  /** Selected nodes @private */
+  // tslint:disable-next-line: no-any
+  private selectNodeExclusive(nodeSelected: any, d: COMPOSERNODES): void {
+    const alreadyIsActive: boolean = nodeSelected.select('#' + d.selectorId).classed(this.activeClass);
+    this.deselectAllNodes();
+    nodeSelected.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive);
+    if (d.nodeTypeRef === 'vld' && !alreadyIsActive) {
+      this.virtualLink = {
+        id: d.id,
+        name: d.name,
+        type: d.type,
+        shortName: d.shortName,
+        vimNetworkName: d.vimNetworkName
+      };
+      this.showRightSideInfo(false, true, false);
+    } else if (d.nodeTypeRef === 'vnfd' && !alreadyIsActive) {
+      this.vnfr = {
+        vimID: d.vimID,
+        _id: d.vndfrID,
+        ip: d.ipAddress,
+        nsrID: d.nsID,
+        id: d.selectorId,
+        vnfdRef: d.vnfdRef,
+        vnfdId: d.vnfdID,
+        memberIndex: d.memberIndex
+      };
+      this.showRightSideInfo(false, false, true);
+    } else {
+      this.showRightSideInfo(true, false, false);
+    }
+  }
+  /** Setting all the square/vnf attributes of nodes @private */
+  private getgSquare(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gSquare = this.square.enter().append('svg:g');
+    this.gSquare.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gSquare.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('id', (d: COMPOSERNODES) => { return d.selectorId; })
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/VNFD.svg')
+      .on('click', (d: COMPOSERNODES) => { this.singleClick(this.gSquare, d); this.onNodeClickToggleSidebar(); });
+    this.gSquare.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: COMPOSERNODES) => d.id);
+  }
+
+  /** Settings all the network attributes of nodes @private */
+  private getgNetwork(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gNetwork = this.network.enter().append('svg:g');
+    this.gNetwork.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gNetwork.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('id', (d: COMPOSERNODES) => { return d.selectorId; })
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/VL.svg')
+      .on('click', (d: COMPOSERNODES) => { this.singleClick(this.gNetwork, d); this.onNodeClickToggleSidebar(); });
+    this.gNetwork.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: COMPOSERNODES) => d.name);
+  }
+
+  /** Settings all the connection point attributes of nodes @private */
+  private getgCircle(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gCircle = this.circle.enter().append('svg:g');
+    this.gCircle.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gCircle.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/CP.svg');
+    this.gCircle.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: COMPOSERNODES) => d.name);
+  }
+
+  /** Key press event @private */
+  private keyDown(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    if (this.lastKeyDown !== -1) { return; }
+    this.lastKeyDown = d3.event.keyCode;
+    if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
+      this.gSquare.call(d3.drag()
+        .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
+      );
+      this.gNetwork.call(d3.drag()
+        .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
+      );
+      this.gCircle.call(d3.drag()
+        .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
+      );
+      this.svg.classed('ctrl', true);
+    }
+  }
+  /** Key realse event @private */
+  private keyUp(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.lastKeyDown = -1;
+    if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
+      this.gSquare.on('.drag', null);
+      this.gNetwork.on('.drag', null);
+      this.gCircle.on('.drag', null);
+      this.svg.classed('ctrl', false);
+    }
+  }
+  /** Events handles when dragstarted @private */
+  private dragstarted(d: COMPOSERNODES): void {
+    d.fx = d.x;
+    d.fy = d.y;
+  }
+  /** Events handles when dragged @private */
+  private dragged(d: COMPOSERNODES): void {
+    d.fx = d.x = d3.event.x;
+    d.fy = d.y = d3.event.y;
+  }
+  /** Events handles when dragended @private */
+  private dragended(d: COMPOSERNODES): void {
+    if (this.forceSimulationActive) {
+      d.fx = null;
+      d.fy = null;
+    } else {
+      d.fx = d.x;
+      d.fy = d.y;
+      this.forceSimulationActive = false;
+    }
+  }
+  /** Events handles when node single click   @private */
+  private onNodeClickToggleSidebar(): void {
+    this.sideBarOpened = true;
+  }
+}
diff --git a/src/app/instances/pdu-instances/PDUInstancesComponent.html b/src/app/instances/pdu-instances/PDUInstancesComponent.html
new file mode 100644 (file)
index 0000000..3c18bfa
--- /dev/null
@@ -0,0 +1,36 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'PDUINSTANCES' | translate}}</div>
+    <span class="button">
+        <button class="btn btn-primary" type="button" placement="top" container="body"
+            ngbTooltip="{{'PAGE.PDUINSTANCE.NEWPDUINSTANCE' | translate}}" (click)="addPDUInstanceModal()">
+            <i class="fas fa-plus-circle" aria-hidden="true"></i>&nbsp;
+            {{'PAGE.PDUINSTANCE.NEWPDUINSTANCE' | translate}}
+        </button>
+    </span>
+</div>
+<div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/instances/pdu-instances/PDUInstancesComponent.scss b/src/app/instances/pdu-instances/PDUInstancesComponent.scss
new file mode 100644 (file)
index 0000000..0ecd95d
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
\ No newline at end of file
diff --git a/src/app/instances/pdu-instances/PDUInstancesComponent.ts b/src/app/instances/pdu-instances/PDUInstancesComponent.ts
new file mode 100644 (file)
index 0000000..20b44df
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file PDU Instance Component
+ */
+import { Component, Injector, OnDestroy, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { AddPDUInstancesComponent } from 'AddPDUInstancesComponent';
+import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { LocalDataSource } from 'ng2-smart-table';
+import { PDUInstanceDetails } from 'PDUInstanceModel';
+import { PDUInstancesActionComponent } from 'PDUInstancesActionComponent';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes PDUInstancesComponent.html as template url
+ */
+@Component({
+    templateUrl: './PDUInstancesComponent.html',
+    styleUrls: ['./PDUInstancesComponent.scss']
+})
+/** Exporting a class @exports PDUInstancesComponent */
+export class PDUInstancesComponent implements OnInit, OnDestroy {
+    /** Injector to invoke other services @public */
+    public injector: Injector;
+
+    /** NS Instance array @public */
+    public pduInstanceData: object[] = [];
+
+    /** Datasource instance @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** SelectedRows array @public */
+    public selectedRows: object[] = [];
+
+    /** Selected list array @public */
+    public selectList: object[] = [];
+
+    /** Instance component are stored in settings @public */
+    public settings: {} = {};
+
+    /** Contains objects for menu settings @public */
+    public columnList: {} = {};
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** dataService to pass the data from one component to another @private */
+    private dataService: DataService;
+
+    /** Utilizes rest service for any CRUD operations @private */
+    private restService: RestService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** Contains tranlsate instance @private */
+    private translateService: TranslateService;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.sharedService = this.injector.get(SharedService);
+        this.translateService = this.injector.get(TranslateService);
+        this.modalService = this.injector.get(NgbModal);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.generateTableColumn();
+        this.generateTableSettings();
+        this.generateData();
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableSettings(): void {
+        this.settings = {
+            columns: this.columnList,
+            actions: { add: false, edit: false, delete: false, position: 'right' },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableColumn(): void {
+        this.columnList = {
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '25%' },
+            name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' },
+            type: { title: this.translateService.instant('TYPE'), width: '15%' },
+            usageState: { title: this.translateService.instant('USAGESTATE'), width: '15%' },
+            CreatedAt: { title: this.translateService.instant('CREATEDAT'), width: '15%' },
+            Actions: {
+                name: 'Action', width: '10%', filter: false, sort: false, type: 'custom',
+                title: this.translateService.instant('ACTIONS'),
+                valuePrepareFunction: (cell: PDUInstanceDetails, row: PDUInstanceDetails): PDUInstanceDetails => row,
+                renderComponent: PDUInstancesActionComponent
+            }
+        };
+    }
+
+    /** generateData initiate the ns-instance list @public */
+    public generateData(): void {
+        this.pduInstanceData = [];
+        this.isLoadingResults = true;
+        this.restService.getResource(environment.PDUINSTANCE_URL).subscribe((pduInstancesData: PDUInstanceDetails[]) => {
+            pduInstancesData.forEach((pduInstanceData: PDUInstanceDetails) => {
+                const pduDataObj: {} = {
+                    name: pduInstanceData.name,
+                    identifier: pduInstanceData._id,
+                    type: pduInstanceData.type,
+                    usageState: pduInstanceData._admin.usageState,
+                    CreatedAt: this.sharedService.convertEpochTime(Number(pduInstanceData._admin.created))
+                };
+                this.pduInstanceData.push(pduDataObj);
+            });
+            if (this.pduInstanceData.length > 0) {
+                this.checkDataClass = 'dataTables_present';
+            } else {
+                this.checkDataClass = 'dataTables_empty';
+            }
+            this.dataSource.load(this.pduInstanceData).then((data: {}) => {
+                this.isLoadingResults = false;
+            }).catch();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+
+    /** smart table listing manipulation @public */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** smart table listing manipulation @public */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'pdu-instances' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** Add PDU Instance modal using modalservice @public */
+    public addPDUInstanceModal(): void {
+        const modalRef: NgbModalRef = this.modalService.open(AddPDUInstancesComponent, { backdrop: 'static' });
+        modalRef.componentInstance.title = this.translateService.instant('PAGE.PDUINSTANCE.NEWPDUINSTANCE');
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.generateData();
+            }
+        }).catch();
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+}
diff --git a/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.html b/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.html
new file mode 100644 (file)
index 0000000..f785426
--- /dev/null
@@ -0,0 +1,95 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{title}}</h4>
+    <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+        <i class="fas fa-times-circle text-danger"></i>
+    </button>
+</div>
+<form [formGroup]="pduInstancesForm" (ngSubmit)="createPDUInstances()" autocomplete="off">
+    <div class="modal-body">
+        <div class="form-group row">
+            <label class="col-sm-12 col-form-label mandatory-label" [ngClass]="{'text-danger': pduInstancesForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+            <label class="col-sm-3 col-form-label" for="name">{{'NAME' | translate}}*</label>
+            <div class="col-sm-3">
+                <input placeholder="{{'NAME' | translate}}" type="text" class="form-control" formControlName="name" id="name" [ngClass]="{ 'is-invalid': submitted && f.name.errors }"
+                    required>
+            </div>
+            <label class="col-sm-3 col-form-label" for="type">{{'PAGE.PDUINSTANCE.PDUTYPE' | translate}}*</label>
+            <div class="col-sm-3">
+                <input placeholder="{{'PAGE.PDUINSTANCE.PDUTYPE' | translate}}" type="text" class="form-control" formControlName="type" id="type" [ngClass]="{ 'is-invalid': submitted && f.type.errors }">
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-3 col-form-label" for="vim_accounts">{{'VIMACCOUNTS' | translate}}*</label>
+            <div class="col-sm-9">
+                <ng-select placeholder="{{'VIMACCOUNTS' | translate}}" [items]="vimAccountSelect" multiple="true" bindLabel="name" bindValue="_id" formControlName="vim_accounts" id="vim_accounts"
+                    [ngClass]="{ 'is-invalid': submitted && f.vim_accounts.errors }" [(ngModel)]="selectedVIM">
+                </ng-select>
+            </div>
+        </div>
+        <div class="form-group row p-2 bg-light text-dark">
+            <div class="col-sm-7 align-self-center"><span>{{'PAGE.PDUINSTANCE.PARAMETERS' | translate}}</span></div>
+            <div class="col-sm-5">
+                <button type="button" class="btn btn-primary" (click)="createInterfaces()">
+                    <i class="fas fa-plus-square"></i> {{'PAGE.PDUINSTANCE.ADDINSTANCEPARAMS' | translate}}</button>
+            </div>
+        </div>
+        <div formArrayName="interfaces" *ngFor="let params of getControls(); let i = index;">
+            <div class="form-group" [formGroupName]="i">
+                <div class="row">
+                    <div class="col-sm-11">
+                        <div class="row">
+                            <label class="col-sm-2 col-form-label" for="name_{{i}}">{{'NAME' | translate}}*</label>
+                            <div class="col-sm-4">
+                                <input placeholder="{{'NAME' | translate}}" type="text" class="form-control" formControlName="name" id="name_{{i}}" [ngClass]="{ 'is-invalid': submitted && params.controls.name.errors }">
+                            </div>
+                            <label class="col-sm-2 col-form-label padLeft0 padRight0" for="ipAddress{{i}}">{{'IPADDRESS' | translate}}*</label>
+                            <div class="col-sm-4">
+                                <input placeholder="{{'IPADDRESS' | translate}}" type="text" class="form-control" formControlName="ip-address" id="ipAddress{{i}}" [ngClass]="{ 'is-invalid': submitted && params.controls['ip-address'].errors }">
+                                <div *ngIf="pduInstancesForm.invalid" class="invalid-feedback">
+                                    <div *ngIf="params.controls['ip-address'].errors && params.controls['ip-address'].value">{{'DOMVALIDATIONS.INVALIDIPADDRESS' | translate}}</div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="row mr-top-5">
+                            <label class="col-sm-2 col-form-label" for="mgmt{{i}}">{{'MGMT' | translate}}*</label>
+                            <div class="col-sm-4">
+                                <ng-select placeholder="{{'SELECT' | translate}} {{'MGMT' | translate}}" [items]="mgmtState" bindLabel="name" bindValue="value" formControlName="mgmt" id="mgmt{{i}}" [(ngModel)]="selectedMgmt" [ngClass]="{ 'is-invalid': submitted && params.controls.mgmt.errors }"></ng-select>
+                            </div>
+                            <label class="col-sm-2 col-form-label padLeft0 padRight0" for="vimNetName{{i}}">{{'NETNAME' | translate}}*</label>
+                            <div class="col-sm-4">
+                                <input placeholder="{{'NETNAME' | translate}}" type="text" class="form-control" formControlName="vim-network-name" id="vimNetName{{i}}" [ngClass]="{ 'is-invalid': submitted && params.controls['vim-network-name'].errors }">
+                            </div>
+                        </div>
+                    </div>
+                    <div class="col-sm-1 remove-params" [hidden]="i==0">
+                        <button type="button" class="btn btn-sm btn-danger remove-mapping" (click)="removeInterfaces(i)">
+                            <i class="fas fa-times-circle"></i>
+                        </button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+        <button type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+    </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.scss b/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.scss
new file mode 100644 (file)
index 0000000..950bb39
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+@import '../../../../assets/scss/mixins/mixin';
+@import '../../../../assets/scss/variable';
+
+.head {
+    @include padding-value(10, 10, 10, 10);
+    line-height: 2em;
+    .btn-params {
+        @include border(all, 1, solid, $white);
+    }
+}
+
+.remove-params {
+       display: flex;
+    align-items: center;
+    font-size: 20px;
+    cursor: pointer;
+}
\ No newline at end of file
diff --git a/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.ts b/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.ts
new file mode 100644 (file)
index 0000000..0dcbb60
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file ADD PDU Instances Component
+ */
+import { Component, Injector, Input, OnInit, Output } from '@angular/core';
+import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { PDUInstanceDetails } from 'PDUInstanceModel';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { VimAccountDetails } from 'VimAccountModel';
+
+/**
+ * Creating component
+ * @Component takes AddPDUInstancesComponent.html as template url
+ */
+@Component({
+    templateUrl: './AddPDUInstancesComponent.html',
+    styleUrls: ['./AddPDUInstancesComponent.scss']
+})
+/** Exporting a class @exports AddPDUInstancesComponent */
+export class AddPDUInstancesComponent implements OnInit {
+    /** Form valid on submit trigger @public */
+    public submitted: boolean = false;
+
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Instance for active modal service @public */
+    public activeModal: NgbActiveModal;
+
+    /** FormGroup instance added to the form @ html @public */
+    public pduInstancesForm: FormGroup;
+
+    /** Primitive params array @public */
+    public pduInterfaces: FormArray;
+
+    /** Variable set for twoway binding @public */
+    public pduInstanceId: string;
+
+    /** Set mgmt field to empty on load @public */
+    public selectedMgmt: string;
+
+    /** Set vim field to empty on load @public */
+    public selectedVIM: string;
+
+    /** Contains boolean value as select options for mgmt @public */
+    public mgmtState: {}[] = [{ name: 'True', value: true }, { name: 'False', value: false }];
+
+    /** Input contains Modal dialog component Instance @private */
+    @Input() public title: string;
+
+    /** Contains all the vim accounts list @public */
+    public vimAccountSelect: VimAccountDetails;
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = false;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** FormBuilder instance added to the formBuilder @private */
+    private formBuilder: FormBuilder;
+
+    /** Utilizes rest service for any CRUD operations @private */
+    private restService: RestService;
+
+    /** packages data service collections @private */
+    private dataService: DataService;
+
+    /** Contains tranlsate instance @private */
+    private translateService: TranslateService;
+
+    /** Notifier service to popup notification @private */
+    private notifierService: NotifierService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.translateService = this.injector.get(TranslateService);
+        this.notifierService = this.injector.get(NotifierService);
+        this.sharedService = this.injector.get(SharedService);
+        this.activeModal = this.injector.get(NgbActiveModal);
+        this.formBuilder = this.injector.get(FormBuilder);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        /** Setting up initial value for NSD */
+        this.dataService.currentMessage.subscribe((event: PDUInstanceDetails) => {
+            if (event.identifier !== undefined || event.identifier !== '' || event.identifier !== null) {
+                this.pduInstanceId = event.identifier;
+            }
+        });
+        this.generateVIMAccounts();
+        this.initializeForm();
+    }
+
+    /** convenience getter for easy access to form fields */
+    get f(): FormGroup['controls'] { return this.pduInstancesForm.controls; }
+
+    /** initialize Forms @public */
+    public initializeForm(): void {
+        this.pduInstancesForm = this.formBuilder.group({
+            name: ['', [Validators.required]],
+            type: ['', [Validators.required]],
+            vim_accounts: ['', [Validators.required]],
+            interfaces: this.formBuilder.array([this.interfacesBuilder()])
+        });
+    }
+
+    /** Generate interfaces fields @public */
+    public interfacesBuilder(): FormGroup {
+        return this.formBuilder.group({
+            name: ['', [Validators.required]],
+            'ip-address': ['', [Validators.required, Validators.pattern(this.sharedService.REGX_IP_PATTERN)]],
+            mgmt: ['', [Validators.required]],
+            'vim-network-name': ['', [Validators.required]]
+        });
+    }
+
+    /** Handle FormArray Controls @public */
+    public getControls(): AbstractControl[] {
+        // tslint:disable-next-line:no-backbone-get-set-outside-model
+        return (this.pduInstancesForm.get('interfaces') as FormArray).controls;
+    }
+
+    /** Push all primitive params on user's action @public */
+    public createInterfaces(): void {
+        // tslint:disable-next-line:no-backbone-get-set-outside-model
+        this.pduInterfaces = this.pduInstancesForm.get('interfaces') as FormArray;
+        this.pduInterfaces.push(this.interfacesBuilder());
+    }
+
+    /** Remove interfaces on user's action @public */
+    public removeInterfaces(index: number): void {
+        this.pduInterfaces.removeAt(index);
+    }
+
+    /** Execute New PDU Instances @public */
+    public createPDUInstances(): void {
+        this.submitted = true;
+        this.sharedService.cleanForm(this.pduInstancesForm);
+        if (this.pduInstancesForm.invalid) { return; } // Proceed, onces form is valid
+        this.isLoadingResults = true;
+        const modalData: MODALCLOSERESPONSEDATA = {
+            message: 'Done'
+        };
+        const apiURLHeader: APIURLHEADER = {
+            url: environment.PDUINSTANCE_URL
+        };
+        this.restService.postResource(apiURLHeader, this.pduInstancesForm.value).subscribe((result: {}) => {
+            this.activeModal.close(modalData);
+            this.notifierService.notify('success', this.translateService.instant('PAGE.PDUINSTANCE.CREATEDSUCCESSFULLY'));
+            this.isLoadingResults = false;
+        }, (error: ERRORDATA) => {
+                this.restService.handleError(error, 'post');
+                this.isLoadingResults = false;
+        });
+    }
+
+    /** Generate vim accounts list @public */
+    public generateVIMAccounts(): void {
+        this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimData: VimAccountDetails) => {
+            this.vimAccountSelect = vimData;
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+        });
+    }
+}
diff --git a/src/app/instances/vnf-instances/VNFInstancesComponent.html b/src/app/instances/vnf-instances/VNFInstancesComponent.html
new file mode 100644 (file)
index 0000000..e36cc3d
--- /dev/null
@@ -0,0 +1,29 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'VNFINSTANCES' | translate}}</div>
+</div>
+<div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/instances/vnf-instances/VNFInstancesComponent.scss b/src/app/instances/vnf-instances/VNFInstancesComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/instances/vnf-instances/VNFInstancesComponent.ts b/src/app/instances/vnf-instances/VNFInstancesComponent.ts
new file mode 100644 (file)
index 0000000..d829ee2
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file NVF Instance Component
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { ERRORDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+import { VNFInstanceData, VNFInstanceDetails } from 'VNFInstanceModel';
+import { VNFInstancesActionComponent } from 'VNFInstancesActionComponent';
+import { VNFLinkComponent } from 'VNFLinkComponent';
+
+/**
+ * Creating component
+ * @Component takes VNFInstancesComponent.html as template url
+ */
+@Component({
+    templateUrl: './VNFInstancesComponent.html',
+    styleUrls: ['./VNFInstancesComponent.scss']
+})
+/** Exporting a class @exports VNFInstancesComponent */
+export class VNFInstancesComponent implements OnInit {
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** smart table data service collections @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** Instance component are stored in settings @public */
+    public settings: {} = {};
+
+    /** Contains objects for menu settings @public */
+    public columnList: {} = {};
+
+    /** vnf instance array @public */
+    public vnfInstanceData: {}[] = [];
+
+    /** selected rows array @public */
+    public selectedRows: string[] = [];
+
+    /** selected list array @public */
+    public selectList: string[] = [];
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+
+    /** Utilizes rest service for any CRUD operations @private */
+    private restService: RestService;
+
+    /** packages data service collections @private */
+    private dataService: DataService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** Contains tranlsate instance @private */
+    private translateService: TranslateService;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.sharedService = this.injector.get(SharedService);
+        this.translateService = this.injector.get(TranslateService);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.generateTableColumn();
+        this.generateTableSettings();
+        this.generateData();
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableSettings(): void {
+        this.settings = {
+            actions: { add: false, edit: false, delete: false, position: 'right' },
+            columns: this.columnList,
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableColumn(): void {
+        this.columnList = {
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '25%', sortDirection: 'asc' },
+            VNFD: {
+                title: this.translateService.instant('VNFD'), width: '20%', type: 'custom',
+                valuePrepareFunction: (cell: VNFInstanceData, row: VNFInstanceData): VNFInstanceData => row,
+                renderComponent: VNFLinkComponent
+            },
+            MemberIndex: { title: this.translateService.instant('MEMBERINDEX'), width: '15%' },
+            NS: { title: this.translateService.instant('NS'), width: '20%' },
+            CreatedAt: { title: this.translateService.instant('CREATEDAT'), width: '15%' },
+            Actions: {
+                name: 'Action', width: '5%', filter: false, sort: false, type: 'custom',
+                title: this.translateService.instant('ACTIONS'),
+                valuePrepareFunction: (cell: VNFInstanceData, row: VNFInstanceData): VNFInstanceData => row,
+                renderComponent: VNFInstancesActionComponent
+            }
+        };
+    }
+
+    /** generateData initiate the vnf-instance list */
+    public generateData(): void {
+        this.isLoadingResults = true;
+        this.restService.getResource(environment.VNFINSTANCES_URL).subscribe((vnfInstancesData: VNFInstanceDetails[]) => {
+            this.vnfInstanceData = [];
+            vnfInstancesData.forEach((vnfInstanceData: VNFInstanceDetails) => {
+                const vnfDataObj: {} =
+                {
+                    VNFD: vnfInstanceData['vnfd-ref'],
+                    identifier: vnfInstanceData._id,
+                    MemberIndex: vnfInstanceData['member-vnf-index-ref'],
+                    NS: vnfInstanceData['nsr-id-ref'],
+                    VNFID: vnfInstanceData['vnfd-id'],
+                    CreatedAt: this.sharedService.convertEpochTime(Number(vnfInstanceData['created-time']))
+                };
+                this.vnfInstanceData.push(vnfDataObj);
+            });
+            if (this.vnfInstanceData.length > 0) {
+                this.checkDataClass = 'dataTables_present';
+            } else {
+                this.checkDataClass = 'dataTables_empty';
+            }
+            this.dataSource.load(this.vnfInstanceData).then((data: {}) => {
+                this.isLoadingResults = false;
+            }).catch();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+
+    /** smart table listing manipulation @public */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** smart table listing manipulation @public */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'vnf-instance' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+}
diff --git a/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.html b/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.html
new file mode 100644 (file)
index 0000000..450e8a3
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<a class="link" routerLink="/packages/vnf/edit/{{value.VNFID}}">{{value.VNFD}}</a>
diff --git a/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.scss b/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.ts b/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.ts
new file mode 100644 (file)
index 0000000..15ea6ff
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file VNFD Link Component.
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { VNFInstanceData } from 'VNFInstanceModel';
+/**
+ * Creating component
+ * @Component takes VNFLinkComponent.html as template url
+ */
+@Component({
+  selector: 'app-vnf-link',
+  templateUrl: './VNFLinkComponent.html',
+  styleUrls: ['./VNFLinkComponent.scss']
+})
+/** Exporting a class @exports VnfLinkComponent */
+export class VNFLinkComponent implements OnInit {
+  /** Invoke service injectors @public */
+  public injector: Injector;
+  /** To get the value from the VNFInstance via valuePrepareFunction default Property of ng-smarttable @public */
+  public value: VNFInstanceData;
+  constructor(injector: Injector) {
+    this.injector = injector;
+  }
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    //empty
+  }
+
+}
diff --git a/src/app/k8s/K8sComponent.html b/src/app/k8s/K8sComponent.html
new file mode 100644 (file)
index 0000000..3f96ff8
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<router-outlet></router-outlet>
\ No newline at end of file
diff --git a/src/app/k8s/K8sComponent.scss b/src/app/k8s/K8sComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/k8s/K8sComponent.ts b/src/app/k8s/K8sComponent.ts
new file mode 100644 (file)
index 0000000..5427a8f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file k8s.ts.
+ */
+import { Component, Injector } from '@angular/core';
+import { Router, RouterEvent } from '@angular/router';
+/**
+ * Creating Component
+ * @Component takes K8sComponent.html as template url
+ */
+@Component({
+  selector: 'app-k8s',
+  templateUrl: './K8sComponent.html',
+  styleUrls: ['./K8sComponent.scss']
+})
+/** Exporting a class @exports K8sComponent */
+export class K8sComponent {
+  /** Invoke service injectors @public */
+  public injector: Injector;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private router: Router;
+
+  /** creates k8s component */
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.router = this.injector.get(Router);
+    this.router.events.subscribe((event: RouterEvent) => {
+      this.redirectToList(event.url);
+    });
+  }
+
+  /** Return to list NS Package List */
+  public redirectToList(getURL: string): void {
+    if (getURL === '/k8s') {
+      this.router.navigate(['/k8s/cluster']).catch();
+    }
+  }
+
+}
diff --git a/src/app/k8s/K8sModule.ts b/src/app/k8s/K8sModule.ts
new file mode 100644 (file)
index 0000000..51f27b2
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file K8s Module.
+ */
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { ReactiveFormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgSelectModule } from '@ng-select/ng-select';
+import { TranslateModule } from '@ngx-translate/core';
+import { DataService } from 'DataService';
+import { K8sActionComponent } from 'K8sActionComponent';
+import { K8sAddClusterComponent } from 'K8sAddClusterComponent';
+import { K8sAddRepoComponent } from 'K8sAddRepoComponent';
+import { K8sClusterComponent } from 'K8sClusterComponent';
+import { K8sComponent } from 'K8sComponent';
+import { K8sRepositoryComponent } from 'K8sRepositoryComponent';
+import { LoaderModule } from 'LoaderModule';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { PagePerRowModule } from 'PagePerRowModule';
+import { PageReloadModule } from 'PageReloadModule';
+
+/** To halndle project information */
+const projectInfo: {} = { title: '{project}', url: '/' };
+
+/**
+ * configures  routers
+ */
+const routes: Routes = [
+  {
+    path: '',
+    component: K8sComponent,
+    children: [
+      {
+        path: 'cluster',
+        data: {
+          breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+            projectInfo, { title: 'PAGE.K8S.MENUK8SCLUSTER', url: null }]
+        },
+        component: K8sClusterComponent
+      },
+      {
+        path: 'repo',
+        data: {
+          breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+            projectInfo, { title: 'PAGE.K8S.MENUK8SREPO', url: null }]
+        },
+        component: K8sRepositoryComponent
+      }
+    ]
+  }
+];
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+  imports: [
+    ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }),
+    FormsModule,
+    CommonModule,
+    HttpClientModule,
+    NgSelectModule,
+    Ng2SmartTableModule,
+    TranslateModule,
+    RouterModule.forChild(routes),
+    NgbModule,
+    PagePerRowModule,
+    LoaderModule,
+    PageReloadModule
+  ],
+  declarations: [
+    K8sComponent,
+    K8sClusterComponent,
+    K8sRepositoryComponent,
+    K8sActionComponent,
+    K8sAddClusterComponent,
+    K8sAddRepoComponent
+  ],
+  providers: [DataService],
+  schemas: [CUSTOM_ELEMENTS_SCHEMA],
+  entryComponents: [K8sActionComponent, K8sAddClusterComponent, K8sAddRepoComponent]
+})
+/** Exporting a class @exports K8sModule */
+export class K8sModule {
+  /** Variables declared to avoid state-less class */
+  private k8sModule: string;
+}
diff --git a/src/app/k8s/k8s-action/K8sActionComponent.html b/src/app/k8s/k8s-action/K8sActionComponent.html
new file mode 100644 (file)
index 0000000..c35bb19
--- /dev/null
@@ -0,0 +1,27 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+  <button type="button" class="btn btn-primary" (click)="infoK8s(getK8sType)" placement="top" container="body"
+    ngbTooltip="{{'INFO' | translate}}">
+    <i class="fas fa-info icons list" title="info"></i>
+  </button>
+  <button type="button" class="btn btn-primary" (click)="deleteK8s(getK8sType)" placement="top"
+    container="body" ngbTooltip="{{'DELETE' | translate}}">
+    <i class="far fa-trash-alt icons" title="delete"></i>
+  </button>
+</div>
\ No newline at end of file
diff --git a/src/app/k8s/k8s-action/K8sActionComponent.scss b/src/app/k8s/k8s-action/K8sActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/k8s/k8s-action/K8sActionComponent.ts b/src/app/k8s/k8s-action/K8sActionComponent.ts
new file mode 100644 (file)
index 0000000..a524277
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file K8 Action Component
+ */
+import { Component, Injector } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { K8SCLUSTERDATADISPLAY, K8SREPODATADISPLAY } from 'K8sModel';
+import { SharedService } from 'SharedService';
+import { ShowInfoComponent } from 'ShowInfoComponent';
+/**
+ * Creating component
+ * @Component takes K8sActionComponent.html as template url
+ */
+@Component({
+  selector: 'app-k8s-action',
+  templateUrl: './K8sActionComponent.html',
+  styleUrls: ['./K8sActionComponent.scss']
+})
+/** Exporting a class @exports K8sActionComponent */
+export class K8sActionComponent{
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** To get the value from the Users action via valuePrepareFunction default Property of ng-smarttable @public */
+  public value: K8SCLUSTERDATADISPLAY | K8SREPODATADISPLAY;
+
+  /** handle translate @public */
+  public translateService: TranslateService;
+
+  /** Contains K8s Type @private */
+  public getK8sType: string;
+
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Contains instance ID @private */
+  private instanceID: string;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.modalService = this.injector.get(NgbModal);
+    this.sharedService = this.injector.get(SharedService);
+    this.translateService = this.injector.get(TranslateService);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.instanceID = this.value.identifier;
+    this.getK8sType = this.value.pageType;
+  }
+
+  /** Delete User Account @public */
+  public deleteK8s(pageType: string): void {
+    const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+
+  /** Shows information using modalservice @public */
+  public infoK8s(pageType: string): void {
+    let pageName: string = '';
+    let title: string = '';
+    if (pageType === 'repo') {
+      pageName = 'k8s-repo';
+      title = 'PAGE.K8S.K8SREPODETAILS';
+    } else {
+      pageName = 'k8s-cluster';
+      title = 'PAGE.K8S.K8SCLUSTERDETAILS';
+    }
+    this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = {
+      id: this.instanceID,
+      page: pageName,
+      titleName: title
+    };
+  }
+}
diff --git a/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.html b/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.html
new file mode 100644 (file)
index 0000000..84f2150
--- /dev/null
@@ -0,0 +1,92 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="k8sclusterForm" (ngSubmit)="k8sAddClusterSubmit();">
+  <div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{'PAGE.K8S.NEWK8SCLUSTER' | translate}}</h4>
+    <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+      <i class="fas fa-times-circle text-danger"></i>
+    </button>
+  </div>
+  <div class="modal-body modal-body-custom-height">
+    <div class="form-group row">
+      <label class="col-sm-12 col-form-label mandatory-label"
+        [ngClass]="{'text-danger': k8sclusterForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+      <label class="col-sm-4 col-form-label" for="name">{{'PAGE.K8S.NAME' | translate}}*</label>
+      <div class="col-sm-8">
+        <input autocomplete="off" class="form-control" placeholder="{{'PAGE.K8S.NAME' | translate}}" type="text"
+          formControlName="name" id="name" [ngClass]="{ 'is-invalid': submitted && f.name.errors }" required>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="k8s_version">{{'PAGE.K8S.K8SVERSION' | translate}}*</label>
+      <div class="col-sm-8">
+        <input autocomplete="off" class="form-control" placeholder="{{'PAGE.K8S.K8SVERSION' | translate}}" type="text"
+          formControlName="k8s_version" id="k8s_version" [ngClass]="{ 'is-invalid': submitted && f.k8s_version.errors }"
+          required>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="vim_account">{{'PAGE.K8S.VIMACCOUNT' | translate}}*</label>
+      <div class="col-sm-8">
+        <ng-select placeholder="{{'SELECT' | translate}} {{'PAGE.K8S.VIMACCOUNT' | translate}}"
+          [items]="vimAccountSelect" bindLabel="name" bindValue="_id" formControlName="vim_account" id="vimAccountId"
+          [ngClass]="{ 'is-invalid': submitted && f.vim_account.errors }" required>
+        </ng-select>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="description">{{'PAGE.K8S.DESCRIPTION' | translate}}*</label>
+      <div class="col-sm-8">
+        <textarea class="form-control" placeholder="{{'PAGE.K8S.DESCRIPTION' | translate}}" type="text"
+          formControlName="description" id="description" [ngClass]="{ 'is-invalid': submitted && f.description.errors }"
+          required></textarea>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="nets">{{'PAGE.K8S.NETS' | translate}}*</label>
+      <div class="col-sm-8">
+        <textarea rows="5" cols="50" class="form-control" placeholder="{{'PAGE.K8S.NETSPLACEHOLDER' | translate}}"
+          formControlName="nets" id="nets" [ngClass]="{ 'is-invalid': submitted && f.nets.errors }" required></textarea>
+        <div class="fileupload-text mt-1 mb-1">{{'FILEUPLOADLABEL' | translate}}</div>
+        <div class="custom-file">
+          <input type="file" #fileInputNets class="custom-file-input" (change)="netsFile($event.target.files)"
+            id="customFileNets">
+          <label class="custom-file-label" #fileInputNetsLabel for="customFileNets">{{'CHOOSEFILE' | translate}}</label>
+        </div>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="credentials">{{'PAGE.K8S.CREDENTIALS' | translate}}*</label>
+      <div class="col-sm-8">
+        <textarea rows="5" cols="50" class="form-control" placeholder="{{'YAMLCONFIG' | translate}}" formControlName="credentials"
+          id="credentials" [ngClass]="{ 'is-invalid': submitted && f.credentials.errors }" required></textarea>
+        <div class="fileupload-text mt-1 mb-1">{{'FILEUPLOADLABEL' | translate}}</div>
+        <div class="custom-file">
+          <input type="file" #fileInputCredentials class="custom-file-input" (change)="credentialsFile($event.target.files)"
+            id="customFileCredentials">
+          <label class="custom-file-label" #fileInputCredentialsLabel for="customFileCredentials">{{'CHOOSEFILE' | translate}}</label>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+    <button type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+  </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.scss b/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.ts b/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.ts
new file mode 100644 (file)
index 0000000..0295b35
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file K8sAddClusterComponent.ts.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { environment } from 'environment';
+import * as jsyaml from 'js-yaml';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+import { VimAccountDetails } from 'VimAccountModel';
+/**
+ * Creating Component
+ * @Component takes K8sAddClusterComponent.html as template url
+ */
+@Component({
+  selector: 'app-k8s-add-cluster',
+  templateUrl: './K8sAddClusterComponent.html',
+  styleUrls: ['./K8sAddClusterComponent.scss']
+})
+/** Exporting a class @exports K8sAddClusterComponent */
+export class K8sAddClusterComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** FormGroup instance added to the form @ html @public */
+  public k8sclusterForm: FormGroup;
+
+  /** Contains all vim account collections */
+  public vimAccountSelect: VimAccountDetails;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Variable set for twoway bindng @public  */
+  public vimAccountId: string;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Element ref for fileInputNets @public */
+  @ViewChild('fileInputNets', { static: true }) public fileInputNets: ElementRef;
+
+  /** Element ref for fileInputNetsLabel @public */
+  @ViewChild('fileInputNetsLabel', { static: true }) public fileInputNetsLabel: ElementRef;
+
+  /** Element ref for fileInputCredentials @public */
+  @ViewChild('fileInputCredentials', { static: true }) public fileInputCredentials: ElementRef;
+
+  /** Element ref for fileInputCredentialsLabel @public */
+  @ViewChild('fileInputCredentialsLabel', { static: true }) public fileInputCredentialsLabel: ElementRef;
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Utilizes rest service for any CRUD operations @private */
+  private restService: RestService;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  public ngOnInit(): void {
+    /** On Initializing call the methods */
+    this.k8sclusterFormAction();
+    this.getDetailsvimAccount();
+    this.headers = new HttpHeaders({
+      Accept: 'application/json',
+      'Content-Type': 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+  }
+
+  /** On modal initializing forms  @public */
+  public k8sclusterFormAction(): void {
+    this.k8sclusterForm = this.formBuilder.group({
+      name: ['', [Validators.required]],
+      k8s_version: ['', [Validators.required]],
+      vim_account: [null, [Validators.required]],
+      description: ['', [Validators.required]],
+      nets: ['', [Validators.required]],
+      credentials: ['', [Validators.required]]
+    });
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.k8sclusterForm.controls; }
+
+  /** Call the vimAccount details in the selection options @public */
+  public getDetailsvimAccount(): void {
+    this.isLoadingResults = true;
+    this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimAccounts: VimAccountDetails) => {
+      this.vimAccountSelect = vimAccounts;
+      this.isLoadingResults = false;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+    });
+  }
+
+  /** On modal submit k8sAddClusterSubmit will called @public */
+  public k8sAddClusterSubmit(): void {
+    this.submitted = true;
+    this.sharedService.cleanForm(this.k8sclusterForm);
+    if (this.k8sclusterForm.invalid) {
+      return;
+    }
+    const modalData: MODALCLOSERESPONSEDATA = {
+      message: 'Done'
+    };
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.K8SCLUSTER_URL,
+      httpOptions: { headers: this.headers }
+    };
+    const validJSONCredentails: boolean = this.sharedService.checkJson(this.k8sclusterForm.value.credentials);
+    if (validJSONCredentails) {
+      this.k8sclusterForm.value.credentials = jsyaml.load(this.k8sclusterForm.value.credentials.toString(), { json: true });
+    } else {
+      this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG'));
+      return;
+    }
+    const validJSONNets: boolean = this.sharedService.checkJson(this.k8sclusterForm.value.nets);
+    if (validJSONNets) {
+      this.k8sclusterForm.value.nets = jsyaml.load(this.k8sclusterForm.value.nets.toString(), { json: true });
+    } else {
+      this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG'));
+      return;
+    }
+    this.isLoadingResults = true;
+    this.restService.postResource(apiURLHeader, this.k8sclusterForm.value).subscribe((result: {}) => {
+      this.activeModal.close(modalData);
+      this.isLoadingResults = false;
+      this.notifierService.notify('success', this.k8sclusterForm.value.name +
+        this.translateService.instant('PAGE.K8S.CREATEDSUCCESSFULLY'));
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'post');
+      this.isLoadingResults = false;
+    });
+  }
+
+  /** Nets file process @private */
+  public netsFile(files: FileList): void {
+    if (files && files.length === 1) {
+      this.sharedService.getFileString(files, 'json').then((fileContent: string): void => {
+        const getNetsJson: string = jsyaml.load(fileContent, { json: true });
+        // tslint:disable-next-line: no-backbone-get-set-outside-model
+        this.k8sclusterForm.get('nets').setValue(JSON.stringify(getNetsJson));
+      }).catch((err: string): void => {
+        if (err === 'typeError') {
+          this.notifierService.notify('error', this.translateService.instant('JSONFILETYPEERRROR'));
+        } else {
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        }
+        this.fileInputNetsLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+        this.fileInputNets.nativeElement.value = null;
+      });
+    } else if (files && files.length > 1) {
+      this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+    }
+    this.fileInputNetsLabel.nativeElement.innerText = files[0].name;
+    this.fileInputNets.nativeElement.value = null;
+  }
+
+  /** credentials file process @private */
+  public credentialsFile(files: FileList): void {
+    if (files && files.length === 1) {
+      this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
+        const getCredentialsJson: string = jsyaml.load(fileContent, { json: true });
+        // tslint:disable-next-line: no-backbone-get-set-outside-model
+        this.k8sclusterForm.get('credentials').setValue(JSON.stringify(getCredentialsJson));
+      }).catch((err: string): void => {
+        if (err === 'typeError') {
+          this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
+        } else {
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        }
+        this.fileInputCredentialsLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+        this.fileInputCredentials.nativeElement.value = null;
+      });
+    } else if (files && files.length > 1) {
+      this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+    }
+    this.fileInputCredentialsLabel.nativeElement.innerText = files[0].name;
+    this.fileInputCredentials.nativeElement.value = null;
+  }
+
+}
diff --git a/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.html b/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.html
new file mode 100644 (file)
index 0000000..8caec5e
--- /dev/null
@@ -0,0 +1,68 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="k8srepoForm" (ngSubmit)="k8sAddRepoSubmit();">
+  <div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{'PAGE.K8S.NEWK8SREPO' | translate}}</h4>
+    <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+      <i class="fas fa-times-circle text-danger"></i>
+    </button>
+  </div>
+  <div class="modal-body k8saddrepo">
+    <div class="form-group row">
+      <label class="col-sm-12 col-form-label mandatory-label"
+        [ngClass]="{'text-danger': k8srepoForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+      <label class="col-sm-4 col-form-label" for="name">{{'PAGE.K8S.NAME' | translate}}*</label>
+      <div class="col-sm-8">
+        <input autocomplete="off" class="form-control" placeholder="{{'PAGE.K8S.NAME' | translate}}" type="text"
+          formControlName="name" id="name" [ngClass]="{ 'is-invalid': submitted && f.name.errors }" required>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="type">{{'PAGE.K8S.TYPE' | translate}}*</label>
+      <div class="col-sm-8">
+        <ng-select [items]="repoTypeSelect" bindLabel="name" bindValue="id"
+          placeholder="{{'SELECT' | translate}} {{'PAGE.K8S.TYPE' | translate}}" formControlName="type" id="type"
+          [ngClass]="{ 'is-invalid': submitted && f.type.errors }" required>
+        </ng-select>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="url">{{'PAGE.K8S.URL' | translate}}*</label>
+      <div class="col-sm-8">
+        <input autocomplete="off" class="form-control" placeholder="{{'PAGE.K8S.URL' | translate}}" type="url"
+          formControlName="url" id="url" [ngClass]="{ 'is-invalid': submitted && f.url.errors }" required>
+        <div *ngIf="k8srepoForm.invalid" class="invalid-feedback">
+          <div *ngIf="f.url.errors && f.url.value">{{'DOMVALIDATIONS.INVALIDURL' | translate}}</div>
+        </div>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="description">{{'PAGE.K8S.DESCRIPTION' | translate}}*</label>
+      <div class="col-sm-8">
+        <textarea class="form-control" placeholder="{{'PAGE.K8S.DESCRIPTION' | translate}}" type="text"
+          formControlName="description" id="description" [ngClass]="{ 'is-invalid': submitted && f.description.errors }"
+          required></textarea>
+      </div>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+    <button type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+  </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.scss b/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.scss
new file mode 100644 (file)
index 0000000..fdec4ed
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
diff --git a/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.ts b/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.ts
new file mode 100644 (file)
index 0000000..c8b96bb
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file k8sAddRepoComponent.ts.
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { environment } from 'environment';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+/**
+ * Creating Component
+ * @Component takes K8sAddRepoComponent.html as template url
+ */
+@Component({
+  selector: 'app-k8s-add-repo',
+  templateUrl: './K8sAddRepoComponent.html',
+  styleUrls: ['./K8sAddRepoComponent.scss']
+})
+/** Exporting a class @exports K8sAddRepoComponent */
+export class K8sAddRepoComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** FormGroup instance added to the form @ html @public */
+  public k8srepoForm: FormGroup;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Supported Vim type for the dropdown */
+  public repoTypeSelect: {}[];
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Utilizes rest service for any CRUD operations @private */
+  private restService: RestService;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  public ngOnInit(): void {
+    this.repoTypeSelect = [
+      { id: 'helm-chart', name: 'Helm Chart' },
+      { id: 'juju-bundle', name: 'Juju Bundle' }
+    ];
+    /** On Initializing call the methods */
+    this.k8srepoFormAction();
+  }
+
+  /** On modal initializing forms  @public */
+  public k8srepoFormAction(): void {
+    this.k8srepoForm = this.formBuilder.group({
+      name: ['', [Validators.required]],
+      type: [null, [Validators.required]],
+      url: ['', [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]],
+      description: ['', [Validators.required]]
+    });
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.k8srepoForm.controls; }
+
+  /** On modal submit k8sAddRepoSubmit will called @public */
+  public k8sAddRepoSubmit(): void {
+    this.submitted = true;
+    this.sharedService.cleanForm(this.k8srepoForm);
+    if (this.k8srepoForm.invalid) {
+      return;
+    }
+    this.isLoadingResults = true;
+    const modalData: MODALCLOSERESPONSEDATA = {
+      message: 'Done'
+    };
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.K8REPOS_URL
+    };
+    this.restService.postResource(apiURLHeader, this.k8srepoForm.value).subscribe((result: {}) => {
+      this.activeModal.close(modalData);
+      this.notifierService.notify('success', this.k8srepoForm.value.name +
+        this.translateService.instant('PAGE.K8S.CREATEDSUCCESSFULLY'));
+      this.isLoadingResults = false;
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      this.restService.handleError(error, 'post');
+    });
+  }
+
+}
diff --git a/src/app/k8s/k8scluster/K8sClusterComponent.html b/src/app/k8s/k8scluster/K8sClusterComponent.html
new file mode 100644 (file)
index 0000000..ebed3e4
--- /dev/null
@@ -0,0 +1,42 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+  <div class="d-flex align-items-center header-style">{{'PAGE.K8S.REGISTERK8CLUSTER' | translate}}</div>
+  <span class="button">
+    <button class="btn btn-primary" type="button" placement="top" container="body" ngbTooltip="{{'PAGE.K8S.ADDK8CLUSTER' | translate}}"
+      (click)="addK8sCluster()">
+      <i class="fas fa-plus-circle" aria-hidden="true"></i>&nbsp; {{'PAGE.K8S.ADDK8CLUSTER' | translate}}
+    </button>
+  </span>
+</div>
+<div class="row mt-2 mb-0 list-utilites-actions">
+  <div class="col-auto mr-auto">
+    <nav class="custom-items-config">
+      <span><i class="fas fa-clock text-warning"></i>{{operationalStateFirstStep}}</span>
+      <span><i class="fas fa-check-circle text-success"></i>{{operationalStateSecondStep}}</span>
+      <span><i class="fas fa-times-circle text-danger"></i>{{operationalStateThirdStep}}</span>
+    </nav>
+  </div>
+  <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+  <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+  <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+  </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/k8s/k8scluster/K8sClusterComponent.scss b/src/app/k8s/k8scluster/K8sClusterComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/k8s/k8scluster/K8sClusterComponent.ts b/src/app/k8s/k8scluster/K8sClusterComponent.ts
new file mode 100644 (file)
index 0000000..7ab7583
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file k8sclustercomponent.ts.
+ */
+import { Component, Injector, OnDestroy, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { K8sActionComponent } from 'K8sActionComponent';
+import { K8sAddClusterComponent } from 'K8sAddClusterComponent';
+import { K8SCLUSTERDATA, K8SCLUSTERDATADISPLAY } from 'K8sModel';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+/**
+ * Creating Component
+ * @Component takes K8sClusterComponent.html as template url
+ */
+@Component({
+  selector: 'app-k8scluster',
+  templateUrl: './K8sClusterComponent.html',
+  styleUrls: ['./K8sClusterComponent.scss']
+})
+/** Exporting a class @exports K8sClusterComponent */
+export class K8sClusterComponent implements OnInit, OnDestroy {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** handle translate @public */
+  public translateService: TranslateService;
+
+  /** Data of smarttable populate through LocalDataSource @public */
+  public dataSource: LocalDataSource = new LocalDataSource();
+
+  /** Columns list of the smart table @public */
+  public columnList: object = {};
+
+  /** Settings for smarttable to populate the table with columns @public */
+  public settings: object = {};
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = true;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Class for empty and present data @public */
+  public checkDataClass: string;
+
+  /** operational State init data @public */
+  public operationalStateFirstStep: string = CONFIGCONSTANT.k8OperationalStateFirstStep;
+
+  /** operational State running data @public */
+  public operationalStateSecondStep: string = CONFIGCONSTANT.k8OperationalStateStateSecondStep;
+
+  /** operational State failed data @public */
+  public operationalStateThirdStep: string = CONFIGCONSTANT.k8OperationalStateThirdStep;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** dataService to pass the data from one component to another @private */
+  private dataService: DataService;
+
+  /** Formation of appropriate Data for LocalDatasource @private */
+  private k8sClusterData: {}[] = [];
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  /** Instance of subscriptions @private */
+  private generateDataSub: Subscription;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.dataService = this.injector.get(DataService);
+    this.sharedService = this.injector.get(SharedService);
+    this.translateService = this.injector.get(TranslateService);
+    this.modalService = this.injector.get(NgbModal);
+  }
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.generateColumns();
+    this.generateSettings();
+    this.generateData();
+    this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+  }
+
+  /** smart table Header Colums @public */
+  public generateColumns(): void {
+    this.columnList = {
+      name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' },
+      identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' },
+      version: { title: this.translateService.instant('K8VERSION'), width: '10%' },
+      operationalState: {
+        title: this.translateService.instant('OPERATIONALSTATE'), width: '15%', type: 'html',
+        filter: {
+          type: 'list',
+          config: {
+            selectText: 'Select',
+            list: [
+              { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep },
+              { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep },
+              { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep }
+            ]
+          }
+        },
+        valuePrepareFunction: (cell: K8SCLUSTERDATADISPLAY, row: K8SCLUSTERDATADISPLAY): string => {
+          if (row.operationalState === this.operationalStateFirstStep) {
+            return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-clock text-warning"></i>
+                        </span>`;
+          } else if (row.operationalState === this.operationalStateSecondStep) {
+            return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-check-circle text-success"></i>
+                        </span>`;
+          } else if (row.operationalState === this.operationalStateThirdStep) {
+            return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-times-circle text-danger"></i>
+                        </span>`;
+          } else {
+            return `<span>${row.operationalState}</span>`;
+          }
+        }
+      },
+      created: { title: this.translateService.instant('CREATED'), width: '15%' },
+      modified: { title: this.translateService.instant('MODIFIED'), width: '15%' },
+      Actions: {
+        name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom',
+        valuePrepareFunction: (cell: K8SCLUSTERDATADISPLAY, row: K8SCLUSTERDATADISPLAY): K8SCLUSTERDATADISPLAY => row,
+        renderComponent: K8sActionComponent
+      }
+    };
+  }
+
+  /** smart table Data Settings @public */
+  public generateSettings(): void {
+    this.settings = {
+      columns: this.columnList,
+      actions: { add: false, edit: false, delete: false, position: 'right' },
+      attr: this.sharedService.tableClassConfig(),
+      pager: this.sharedService.paginationPagerConfig(),
+      noDataMessage: this.translateService.instant('NODATAMSG')
+    };
+  }
+
+  /** smart table listing manipulation @public */
+  public onChange(perPageValue: number): void {
+    this.dataSource.setPaging(1, perPageValue, true);
+  }
+
+  /** smart table listing manipulation @public */
+  public onUserRowSelect(event: MessageEvent): void {
+    Object.assign(event.data, { page: 'k8-cluster' });
+    this.dataService.changeMessage(event.data);
+  }
+
+  /** Compose new K8s Cluster Accounts @public */
+  public addK8sCluster(): void {
+    const modalRef: NgbModalRef = this.modalService.open(K8sAddClusterComponent, { backdrop: 'static' });
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+
+  /**
+   * Lifecyle hook which get trigger on component destruction
+   */
+  public ngOnDestroy(): void {
+    this.generateDataSub.unsubscribe();
+  }
+
+  /** Generate nsData object from loop and return for the datasource @public */
+  public generateK8sclusterData(k8sClusterdata: K8SCLUSTERDATA): K8SCLUSTERDATADISPLAY {
+    return {
+      name: k8sClusterdata.name,
+      identifier: k8sClusterdata._id,
+      operationalState: k8sClusterdata._admin.operationalState,
+      version: k8sClusterdata.k8s_version,
+      created: this.sharedService.convertEpochTime(Number(k8sClusterdata._admin.created)),
+      modified: this.sharedService.convertEpochTime(Number(k8sClusterdata._admin.modified)),
+      pageType: 'cluster'
+    };
+  }
+
+  /** Fetching the data from server to Load in the smarttable @protected */
+  protected generateData(): void {
+    this.isLoadingResults = true;
+    this.restService.getResource(environment.K8SCLUSTER_URL).subscribe((k8sClusterDatas: K8SCLUSTERDATA[]) => {
+      this.k8sClusterData = [];
+      k8sClusterDatas.forEach((k8sClusterdata: K8SCLUSTERDATA) => {
+        const k8sClusterDataObj: K8SCLUSTERDATADISPLAY = this.generateK8sclusterData(k8sClusterdata);
+        this.k8sClusterData.push(k8sClusterDataObj);
+      });
+      if (this.k8sClusterData.length > 0) {
+        this.checkDataClass = 'dataTables_present';
+      } else {
+        this.checkDataClass = 'dataTables_empty';
+      }
+      this.dataSource.load(this.k8sClusterData).then((data: boolean) => {
+        this.isLoadingResults = false;
+      }).catch(() => {
+        this.isLoadingResults = false;
+      });
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+    });
+  }
+
+}
diff --git a/src/app/k8s/k8srepository/K8sRepositoryComponent.html b/src/app/k8s/k8srepository/K8sRepositoryComponent.html
new file mode 100644 (file)
index 0000000..e546356
--- /dev/null
@@ -0,0 +1,35 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+  <div class="d-flex align-items-center header-style">{{'PAGE.K8S.REGISTERK8REPO' | translate}}</div>
+  <span class="button">
+    <button class="btn btn-primary" type="button" placement="top" container="body" ngbTooltip="{{'PAGE.K8S.ADDK8REPO' | translate}}"
+      (click)="addK8sRepo()">
+      <i class="fas fa-plus-circle" aria-hidden="true"></i>&nbsp; {{'PAGE.K8S.ADDK8REPO' | translate}}
+    </button>
+  </span>
+</div>
+<div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+  <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+  <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+  <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+  </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/k8s/k8srepository/K8sRepositoryComponent.scss b/src/app/k8s/k8srepository/K8sRepositoryComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/k8s/k8srepository/K8sRepositoryComponent.ts b/src/app/k8s/k8srepository/K8sRepositoryComponent.ts
new file mode 100644 (file)
index 0000000..1b6c9f7
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file K8sRepositoryComponent.ts.
+ */
+import { Component, Injector, OnDestroy, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { K8sActionComponent } from 'K8sActionComponent';
+import { K8sAddRepoComponent } from 'K8sAddRepoComponent';
+import { K8SREPODATA, K8SREPODATADISPLAY } from 'K8sModel';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+/**
+ * Creating Component
+ * @Component takes K8sRepositoryComponent.html as template url
+ */
+@Component({
+  selector: 'app-k8srepository',
+  templateUrl: './K8sRepositoryComponent.html',
+  styleUrls: ['./K8sRepositoryComponent.scss']
+})
+/** Exporting a class @exports K8sRepositoryComponent */
+export class K8sRepositoryComponent implements OnInit, OnDestroy {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** handle translate @public */
+  public translateService: TranslateService;
+
+  /** Data of smarttable populate through LocalDataSource @public */
+  public dataSource: LocalDataSource = new LocalDataSource();
+
+  /** Columns list of the smart table @public */
+  public columnList: object = {};
+
+  /** Settings for smarttable to populate the table with columns @public */
+  public settings: object = {};
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = true;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Class for empty and present data @public */
+  public checkDataClass: string;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** dataService to pass the data from one component to another @private */
+  private dataService: DataService;
+
+  /** Formation of appropriate Data for LocalDatasource @private */
+  private k8sRepoData: {}[] = [];
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  /** Instance of subscriptions @private */
+  private generateDataSub: Subscription;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.dataService = this.injector.get(DataService);
+    this.sharedService = this.injector.get(SharedService);
+    this.translateService = this.injector.get(TranslateService);
+    this.modalService = this.injector.get(NgbModal);
+  }
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.generateColumns();
+    this.generateSettings();
+    this.generateData();
+    this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+  }
+
+  /** smart table Header Colums @public */
+  public generateColumns(): void {
+    this.columnList = {
+      name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' },
+      identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' },
+      url: { title: this.translateService.instant('URL'), width: '15%' },
+      type: { title: this.translateService.instant('TYPE'), width: '10%' },
+      created: { title: this.translateService.instant('CREATED'), width: '15%' },
+      modified: { title: this.translateService.instant('MODIFIED'), width: '15%' },
+      Actions: {
+        name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom',
+        valuePrepareFunction: (cell: K8SREPODATADISPLAY, row: K8SREPODATADISPLAY): K8SREPODATADISPLAY => row,
+        renderComponent: K8sActionComponent
+      }
+    };
+  }
+
+  /** smart table Data Settings @public */
+  public generateSettings(): void {
+    this.settings = {
+      columns: this.columnList,
+      actions: { add: false, edit: false, delete: false, position: 'right' },
+      attr: this.sharedService.tableClassConfig(),
+      pager: this.sharedService.paginationPagerConfig(),
+      noDataMessage: this.translateService.instant('NODATAMSG')
+    };
+  }
+
+  /** smart table listing manipulation @public */
+  public onChange(perPageValue: number): void {
+    this.dataSource.setPaging(1, perPageValue, true);
+  }
+
+  /** smart table listing manipulation @public */
+  public onUserRowSelect(event: MessageEvent): void {
+    Object.assign(event.data, { page: 'k8-repo' });
+    this.dataService.changeMessage(event.data);
+  }
+
+  /** Compose new K8s Repo Accounts @public */
+  public addK8sRepo(): void {
+    const modalRef: NgbModalRef = this.modalService.open(K8sAddRepoComponent, { backdrop: 'static' });
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+
+  /**
+   * Lifecyle hook which get trigger on component destruction
+   */
+  public ngOnDestroy(): void {
+    this.generateDataSub.unsubscribe();
+  }
+
+  /** Generate nsData object from loop and return for the datasource @public */
+  // tslint:disable-next-line: typedef
+  public generateK8sRepoData(k8sRepodata: K8SREPODATA): K8SREPODATADISPLAY {
+    return {
+      name: k8sRepodata.name,
+      identifier: k8sRepodata._id,
+      url: k8sRepodata.url,
+      type: k8sRepodata.type,
+      created: this.sharedService.convertEpochTime(Number(k8sRepodata._admin.created)),
+      modified: this.sharedService.convertEpochTime(Number(k8sRepodata._admin.modified)),
+      pageType: 'repo'
+    };
+  }
+
+  /** Fetching the data from server to Load in the smarttable @protected */
+  protected generateData(): void {
+    this.isLoadingResults = true;
+    this.restService.getResource(environment.K8REPOS_URL).subscribe((k8sRepoDatas: K8SREPODATA[]) => {
+      this.k8sRepoData = [];
+      k8sRepoDatas.forEach((k8sRepodata: K8SREPODATA) => {
+        const k8sRepoDataObj: K8SREPODATADISPLAY = this.generateK8sRepoData(k8sRepodata);
+        this.k8sRepoData.push(k8sRepoDataObj);
+      });
+      if (this.k8sRepoData.length > 0) {
+        this.checkDataClass = 'dataTables_present';
+      } else {
+        this.checkDataClass = 'dataTables_empty';
+      }
+      this.dataSource.load(this.k8sRepoData).then((data: boolean) => {
+        this.isLoadingResults = false;
+      }).catch(() => {
+        this.isLoadingResults = false;
+      });
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+    });
+  }
+
+}
diff --git a/src/app/layouts/LayoutComponent.html b/src/app/layouts/LayoutComponent.html
new file mode 100644 (file)
index 0000000..96f1302
--- /dev/null
@@ -0,0 +1,37 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<app-header></app-header>
+<div id="main-wrapper" class="container-fluid" dir="ltr" appGottoTop>
+    <div class="layout-wrapper mt-2">
+        <app-sidebar></app-sidebar>
+        <div class="content-section pl-4">
+            <app-breadcrumb></app-breadcrumb>
+            <div class="mt-2">
+                <div class="card custom-card shadow">
+                    <div class="card-body custom-card-body">
+                        <router-outlet></router-outlet>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <button class="btn btn-sm btn-primary border border-radius-default goto-top" type="button"
+        *ngIf="sharedService.showGotoTop" (click)="gotoTop()">
+        <i class="fas fa-angle-up"></i>
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/app/layouts/LayoutComponent.scss b/src/app/layouts/LayoutComponent.scss
new file mode 100644 (file)
index 0000000..649387a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import "../../assets/scss/mixins/mixin";
+@import "../../assets/scss/variable";
+#main-wrapper {
+  @include wh-value(100%, null);
+  .layout-wrapper {
+    @include flexbox(flex, null, null, null, stretch, null);
+    .content-section {
+      @include wh-value(100%, null);
+      @include transition(all, 0.3s, null, null);
+      overflow-x: auto;
+    }
+  }
+  .goto-top {
+    @include position_value(fixed, null, 30px, 10px, null);
+    @include font(null, 20px, null);
+    outline: none;
+    @include wh-value(40px, 40px);
+  }
+}
\ No newline at end of file
diff --git a/src/app/layouts/LayoutComponent.ts b/src/app/layouts/LayoutComponent.ts
new file mode 100644 (file)
index 0000000..b99221a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file NS Instance Component
+ */
+import { Component } from '@angular/core';
+import { SharedService } from 'SharedService';
+/**
+ * Creating component
+ * @Component takes LayoutComponent.html as template url
+ */
+@Component({
+    selector: 'app-layout',
+    templateUrl: './LayoutComponent.html',
+    styleUrls: ['./LayoutComponent.scss']
+})
+/** Exporting a class @exports LayoutComponent */
+export class LayoutComponent {
+    /** Contains all methods related to shared @private */
+    public sharedService: SharedService;
+
+    constructor(sharedService: SharedService) {
+        this.sharedService = sharedService;
+    }
+    /** method to handle go to top event @public */
+    public gotoTop(): void {
+        window.scroll({ behavior: 'smooth', top: 0, left: 0 });
+    }
+}
diff --git a/src/app/layouts/breadcrumb/BreadcrumbComponent.html b/src/app/layouts/breadcrumb/BreadcrumbComponent.html
new file mode 100644 (file)
index 0000000..9d028b3
--- /dev/null
@@ -0,0 +1,27 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<nav aria-label="breadcrumb" class="breadcrumb-holder">
+  <ul class="breadcrumb-custom pl-0">
+    <li class="breadcrumb-item-custom" [routerLink]="item.url" *ngFor="let item of menuItems; let i = index" [class.active]="i===menuItems.length-1">
+      <a *ngIf="i!==menuItems.length-1">
+        <i *ngIf="i==0" class="fas fa-th-large"></i>&nbsp;&nbsp;{{item.title | translate}}
+      </a>
+      <span *ngIf="i===menuItems.length-1"><i *ngIf="i==0" class="fas fa-th-large"></i>&nbsp;&nbsp;{{item.title | translate}}</span>
+    </li>
+  </ul>
+</nav>
\ No newline at end of file
diff --git a/src/app/layouts/breadcrumb/BreadcrumbComponent.scss b/src/app/layouts/breadcrumb/BreadcrumbComponent.scss
new file mode 100644 (file)
index 0000000..7ed3da6
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import "../../../assets/scss/mixins/mixin";
+@import "../../../assets/scss/variable";
+.breadcrumb-holder {
+  .breadcrumb-custom {
+    @include box-shadow(0, 2px, 5px, 0, rgba(0, 0, 0, 0.25));
+    @include roundedCorners(5);
+    @include background(null, $white, null, null, null);
+    @include margin-value(0, 0, 0, 0);
+    @include flexbox(inline-block, null, null, null, null, null);
+    overflow: hidden;
+    .breadcrumb-item-custom {
+      @include flexbox(block, null, null, null, null, null);
+      @include line-height(35px);
+      @include font(null, 12px, null);
+      @include padding-value(0, 10, 0, 30);
+      @include position_value(relative, null, null, null, null);
+      float: left;
+      cursor: pointer;
+      &:hover {
+        @include background(null, $secondary, null, null, null);
+        a {
+          color: $white;
+        }
+        &::after {
+          @include background(null, $secondary, null, null, null);
+        }
+      }
+      a {
+        color: $primary;
+      }
+      &:first-child {
+        padding-left: 20px;
+        @include roundedTopLeftRadius(5);
+        @include roundedBottomLeftRadius(5);
+        &::before {
+          @include position_value(null, null, null, null, 14px);
+        }
+      }
+      &:last-child {
+        @include roundedTopRightRadius(5);
+        @include roundedBottomRightRadius(5);
+        padding-right: 20px;
+        &::after {
+          content: none;
+        }
+      }
+      &::after {
+        content: "";
+        @include position_value(absolute, 0, -18px, null, null);
+        @include wh-value(36px, 36px);
+        @include background(null, $white, null, null, null);
+        @include box-shadow(2px, -2px, 0, 1px, $breadcrumb-after-color);
+        transform: scale(0.707) rotate(45deg);
+        z-index: 1;
+        @include roundedTopRightRadius(5);
+        @include roundedBottomLeftRadius(50);
+      }
+      &.active {
+        @include background(null, $primary, null, null, null);
+        color: $white;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/app/layouts/breadcrumb/BreadcrumbComponent.ts b/src/app/layouts/breadcrumb/BreadcrumbComponent.ts
new file mode 100644 (file)
index 0000000..ccb9588
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Bread Crumb component.
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { ActivatedRoute, NavigationEnd, Router, RouterEvent, UrlSegment } from '@angular/router';
+import { TranslateService } from '@ngx-translate/core';
+import { BREADCRUMBITEM } from 'CommonModel';
+import { filter, startWith } from 'rxjs/operators';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes BreadcrumbComponent.html as template url
+ */
+@Component({
+  selector: 'app-breadcrumb',
+  templateUrl: './BreadcrumbComponent.html',
+  styleUrls: ['./BreadcrumbComponent.scss']
+})
+
+/** Exporting a class @exports BreadcrumbComponent */
+export class BreadcrumbComponent implements OnInit {
+  /** To inject breadCrumb @public */
+  public static readonly ROUTE_DATA_BREADCRUMB: string = 'breadcrumb';
+
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** To inject breadCrumb Default icon and url @public */
+  public readonly home: {} = { icon: 'pi pi-th-large', url: '/' };
+
+  /** To inject breadCrumb Menus @public */
+  public menuItems: BREADCRUMBITEM[];
+
+  /** Service holds the router information @private */
+  private router: Router;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private activatedRoute: ActivatedRoute;
+
+  /** handle translate service @private */
+  private translateService: TranslateService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.router = this.injector.get(Router);
+    this.activatedRoute = this.injector.get(ActivatedRoute);
+    this.translateService = this.injector.get(TranslateService);
+  }
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.router.events
+      .pipe(filter((event: RouterEvent) => event instanceof NavigationEnd), startWith(undefined))
+      .subscribe(() => this.menuItems = this.createBreadcrumbs(this.activatedRoute.root));
+  }
+
+  /** Generate breadcrumbs from data given the module routes @private */
+  private createBreadcrumbs(route: ActivatedRoute, url: string = '', breadcrumbs: BREADCRUMBITEM[] = []):
+    BREADCRUMBITEM[] {
+    const children: ActivatedRoute[] = route.children;
+    if (children.length === 0) {
+      return breadcrumbs;
+    }
+    for (const child of children) {
+      const routeURL: string = child.snapshot.url.map((segment: UrlSegment) => segment.path).join('/');
+      if (routeURL !== '') {
+        url += `/${routeURL}`;
+      }
+      let menuLIst: BREADCRUMBITEM[] = child.snapshot.data[BreadcrumbComponent.ROUTE_DATA_BREADCRUMB];
+      if (!isNullOrUndefined(menuLIst)) {
+        menuLIst = JSON.parse(JSON.stringify(menuLIst));
+        menuLIst.forEach((item: BREADCRUMBITEM) => {
+          if (!isNullOrUndefined(item.title)) {
+            item.title = item.title.replace('{type}', this.checkTitle(item, child.snapshot.params.type));
+            item.title = item.title.replace('{id}', child.snapshot.params.id);
+            item.title = item.title.replace('{project}', localStorage.getItem('project'));
+          }
+          if (!isNullOrUndefined(item.url)) {
+            item.url = item.url.replace('{type}', child.snapshot.params.type);
+            item.url = item.url.replace('{id}', child.snapshot.params.id);
+          }
+          breadcrumbs.push(item);
+        });
+      }
+      return this.createBreadcrumbs(child, url, breadcrumbs);
+    }
+  }
+  /** Check and update title based on type of operations @private */
+  private checkTitle(breadcrumbItem: BREADCRUMBITEM, opertionType: string): string {
+    if (!isNullOrUndefined(breadcrumbItem.url)) {
+      if (breadcrumbItem.url.indexOf('packages') !== -1) {
+        return this.matchPackageTitle(opertionType);
+      }
+      if (breadcrumbItem.url.indexOf('instances') !== -1) {
+        return this.matchInstanceTitle(opertionType);
+      }
+      return breadcrumbItem.title;
+    }
+  }
+  /** check and update package title based on package type @private */
+  private matchPackageTitle(opertionType: string): string {
+    if (opertionType === 'ns') {
+      return this.translateService.instant('NSPACKAGES');
+    } else if (opertionType === 'vnf') {
+      return this.translateService.instant('VNFPACKAGES');
+    } else {
+      return this.translateService.instant('PAGE.DASHBOARD.NETSLICETEMPLATE');
+    }
+  }
+  /** check and update package title based on instance type @private */
+  private matchInstanceTitle(opertionType: string): string {
+    if (opertionType === 'ns') {
+      return this.translateService.instant('NSINSTANCES');
+    } else if (opertionType === 'vnf') {
+      return this.translateService.instant('VNFINSTANCES');
+    } else if (opertionType === 'pdu') {
+      return this.translateService.instant('PDUINSTANCES');
+    } else {
+      return this.translateService.instant('PAGE.DASHBOARD.NETSLICEINSTANCE');
+    }
+  }
+
+}
diff --git a/src/app/layouts/header/HeaderComponent.html b/src/app/layouts/header/HeaderComponent.html
new file mode 100644 (file)
index 0000000..a9ff5ac
--- /dev/null
@@ -0,0 +1,71 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<span class="d-none px-3 py-2 text-center text-bold bg-primary text-white">Here is a newer {{'APPVERSION' | translate}} {{PACKAGEVERSION}}
+    of OSM!</span>
+
+<nav class="navbar navbar-expand-md sticky-top bg-white" role="navigation">
+    <a class="navbar-brand">
+        <img routerLink="/" src="assets/images/logo.png" class="osm-logo"
+            alt="OPEN SOURCE MANO" draggable="false">
+    </a>
+    <div class="nav navbar-nav nav-flex-icons ml-auto">
+        <ul class="navbar-nav cursor-pointer" ngbDropdown display="dynamic" placement="bottom-right">
+            <li class="nav-item dropdown">
+                <a class="nav-link dropdown-toggle" id="navbarDropdownProject" ngbDropdownToggle>
+                    <i class="fas fa-folder-open"></i> {{'PAGE.DASHBOARD.PROJECTS' | translate}}
+                    ({{selectedProject | async}})
+                </a>
+                <div class="dropdown-menu custom-dropdown-menu m-0 p-0" ngbDropdownMenu *ngIf="getSelectedProject"
+                    aria-labelledby="navbarDropdownProject">
+                    <a ngbDropdownItem class="dropdown-item project-item"
+                        [ngClass]="list.project_name === getSelectedProject ? 'activeProject' : ''"
+                        (click)="list.project_name === getSelectedProject ? '' : this.projectService.switchProjectModal(list)"
+                        *ngFor="let list of projectList$ | async" placement="left" container="body"
+                        ngbTooltip="{{ (list.project_name === getSelectedProject ? 'CURRENTPROJECT' : 'SWITCHPROJECT') | translate}}">
+                        <span>{{list.project_name}}</span>
+                        <i *ngIf="list.project_name === getSelectedProject"
+                            class="fas fa-check-circle text-success"></i>
+                        <i *ngIf="list.project_name !== getSelectedProject" class="fas fa-exchange-alt text-danger"></i>
+                    </a>
+                </div>
+            </li>
+        </ul>
+        <ul class="navbar-nav cursor-pointer text-right" ngbDropdown display="dynamic" placement="bottom-right">
+            <li class="nav-item dropdown">
+                <a class="nav-link dropdown-toggle" id="navbarDropdown" ngbDropdownToggle>
+                    <i class="fas fa-user-circle"></i> {{'USER' | translate}} ({{username$ | async}})
+                </a>
+                <div class="dropdown-menu custom-dropdown-menu m-0 p-0" ngbDropdownMenu
+                    aria-labelledby="navbarDropdown">
+                    <a ngbDropdownItem class="dropdown-item project-item" (click)="userSettings()">
+                        <span>{{'PAGE.DASHBOARD.USERSETTINGS' | translate}}</span>
+                        <i class="fas fa-users-cog"></i>
+                    </a>
+                    <a ngbDropdownItem class="dropdown-item project-item" (click)="logout()">
+                        <span>{{'PAGE.DASHBOARD.LOGOUT' | translate}}</span>
+                        <i class="fas fa-sign-out-alt"></i>
+                    </a>
+                    <div class="custom-divider"></div>
+                    <a *ngIf="sharedService.osmVersion" ngbDropdownItem class="dropdown-item project-item osm-version" href="javascript:void(0);">
+                        <span>{{'OSMVERSION' | translate}} {{sharedService.osmVersion}}</span>
+                    </a>
+                </div>
+            </li>
+        </ul>
+    </div>
+</nav>
\ No newline at end of file
diff --git a/src/app/layouts/header/HeaderComponent.scss b/src/app/layouts/header/HeaderComponent.scss
new file mode 100644 (file)
index 0000000..86200b7
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import '../../../assets/scss/mixins/mixin';
+@import '../../../assets/scss/variable';
+
+.navbar{
+    @include box-shadow(0px, 0px, 12px, 0px, rgba($black,0.14));
+    @include border(all, 0, solid, $gray-80);
+    .osm-logo{
+        cursor: pointer;
+    }
+    .custom-dropdown-menu {
+        .dropdown-item{
+            &.project-item{
+                @include flexbox(flex, space-between, row, null, center, null);
+            }
+            &:active, &:hover, &.active{
+                @include background(null, $theme-bg-color, null, null, null);
+                color: $primary;
+            }
+            &.activeProject{
+                cursor: default;
+            }
+        }
+        .custom-divider{
+            @include wh-value(null, 0);
+            @include border(top, 2, solid, $primary);
+            overflow: hidden;
+        }
+    }
+    .osm-version{
+        @include background(null, $theme-bg-color, null, null, null);
+        color: $primary;
+        cursor: default;
+    }
+}
\ No newline at end of file
diff --git a/src/app/layouts/header/HeaderComponent.ts b/src/app/layouts/header/HeaderComponent.ts
new file mode 100644 (file)
index 0000000..4d7f3b1
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file Header Component
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { AuthenticationService } from 'AuthenticationService';
+import { environment } from 'environment';
+import { ProjectService } from 'ProjectService';
+import { Observable } from 'rxjs';
+import { SharedService } from 'SharedService';
+import { ProjectRoleMappings, UserDetail } from 'UserModel';
+import { UserSettingsComponent } from 'UserSettingsComponent';
+
+/**
+ * Creating component
+ * @Component takes HeaderComponent.html as template url
+ */
+@Component({
+    selector: 'app-header',
+    templateUrl: './HeaderComponent.html',
+    styleUrls: ['./HeaderComponent.scss']
+})
+/** Exporting a class @exports HeaderComponent */
+export class HeaderComponent implements OnInit {
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** Variables holds all the projects @public */
+    public projectList$: Observable<{}[]>;
+
+    /** Observable holds logined value  @public */
+    public username$: Observable<string>;
+
+    /** Variables holds admin is logged or not @public */
+    public isAdmin: boolean;
+
+    /** Variables holds the selected project @public */
+    public selectedProject: Observable<string>;
+
+    /** project @public */
+    public getSelectedProject: string;
+
+    /** Version holds packages version @public */
+    public PACKAGEVERSION: string;
+
+    /** Contains all methods related to shared @public */
+    public sharedService: SharedService;
+
+    /** Utilizes auth service for any auth operations @private */
+    private authService: AuthenticationService;
+
+    /** Holds all project details @private */
+    private projectService: ProjectService;
+
+    /** Utilizes modal service for any modal operations @private */
+    private modalService: NgbModal;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.authService = this.injector.get(AuthenticationService);
+        this.modalService = this.injector.get(NgbModal);
+        this.projectService = this.injector.get(ProjectService);
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.isAdmin = (localStorage.getItem('isAdmin') === 'true') ? true : false;
+        this.selectedProject = this.authService.ProjectName;
+        this.authService.ProjectName.subscribe((projectNameFinal: string) => {
+            this.getSelectedProject = projectNameFinal;
+        });
+        this.username$ = this.authService.username;
+        this.projectService.setHeaderProjects();
+        this.projectList$ = this.projectService.projectList;
+        this.PACKAGEVERSION = environment.packageVersion;
+    }
+
+    /** Logout function  @public */
+    public logout(): void {
+        this.authService.logout();
+    }
+
+    /** Implementation of model for UserSettings options.@public */
+    public userSettings(): void {
+        this.modalService.open(UserSettingsComponent, { backdrop: 'static' });
+    }
+}
diff --git a/src/app/layouts/sidebar/SidebarComponent.html b/src/app/layouts/sidebar/SidebarComponent.html
new file mode 100644 (file)
index 0000000..1fa4f82
--- /dev/null
@@ -0,0 +1,52 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div id="sidebar" class="p-2 sidebar-mini" [class.sidebar-collapse]="classAppliedForDesktop" [class.sidebar-open]="classAppliedForMobile">
+    <div class="custom-menu" (click)="sideBarOpenClose()">
+        <button type="button" id="sidebarCollapse" class="btn btn-primary">
+            <i class="fa fa-bars"></i>
+        </button>
+    </div>
+    <nav>
+        <ul class="scrollable-menu">
+            <li *ngFor="let menu of getMenus; let i = index" [ngClass]="{'hasChild': menu.isChildExists }"
+                class="{{menu.liClass}}" id="{{menu.clickFunction}}{{i}}"
+                (click)="handleMenuFunction(i, menu.clickFunction, 'menu-open', menu.isChildExists)"
+                [routerLinkActiveOptions]="{exact: menu.routerLinkActiveOptions !== undefined ? menu.routerLinkActiveOptions : false}"
+                [routerLinkActive]="menu.routerLinkActive !== undefined ? menu.routerLinkActive : ''">
+                <a *ngIf="menu.isChildExists" class="{{menu.anchorTagClass}}">
+                    <i class="{{menu.icon}}"></i>
+                    <span>{{ menu.menuName | translate}}</span>
+                </a>
+                <a *ngIf="!menu.isChildExists" class="{{menu.anchorTagClass}}" [routerLink]="menu.routerLink">
+                    <i class="{{menu.icon}}"></i>
+                    <span>{{ menu.menuName | translate}}</span>
+                </a>
+                <ul *ngIf="menu.isChildExists" class="{{menu.ulClass}}">
+                    <li *ngFor="let childMenu of menu.childItems"
+                        [routerLinkActiveOptions]="{exact: childMenu.routerLinkActiveOptions}"
+                        [routerLinkActive]="childMenu.routerLinkActive" (click)="checkAndCloseSideBar(childMenu.isChildExists)">
+                        <a class="{{childMenu.anchorTagClass}}" [routerLink]="childMenu.routerLink">
+                            <i class="{{childMenu.icon}}"></i>
+                            <span>{{childMenu.menuName | translate}}</span>
+                        </a>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </nav>
+</div>
\ No newline at end of file
diff --git a/src/app/layouts/sidebar/SidebarComponent.scss b/src/app/layouts/sidebar/SidebarComponent.scss
new file mode 100644 (file)
index 0000000..7b5f92e
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import "../../../assets/scss/mixins/mixin";
+@import "../../../assets/scss/variable";
+$active-margin-left: -230;
+$minimize-left: 45px;
+.sidebar-mini {
+  @include transition(all, 0.3s, ease-in-out, 0s);
+  @include position_value(relative, null, null, null, null);
+  z-index: 10;
+  .custom-menu {
+    @include flexbox(inline-block, null, null, null, null, null);
+    @include position_value(absolute, 25px, 4px, null, null);
+    @include margin-value(0, -20, 0, 0);
+    .btn {
+      @include wh-value(55px, 55px);
+      @include roundedCornersPercentage(50%);
+      @include position_value(relative, null, null, null, null);
+      @include background(null, transparent, null, null, null);
+      @include border(all, 0, solid, transparent);
+      i {
+        @include margin-value(0, -40, 0, 0);
+        @include font(null, 14px, null);
+      }
+      &.btn-primary {
+        &:after {
+          content: "";
+          @include position_value(absolute, 0, 0, 0, 0);
+          @include background(null, $secondary, null, null, null);
+          @include roundedCorners(10);
+          @include rotate(45);
+          z-index: -1;
+        }
+      }
+      &:hover,
+      &:focus,
+      &:active {
+        @include background(null, transparent !important, null, null, null);
+      }
+    }
+  }
+  nav {
+    @include wh-value(200px, null);
+    @include transition(width, 0.2s, ease-in-out, 0s);
+    ul {
+      @include padding-value(0, 0, 0, 0);
+      @include margin-value(0, 0, 0, 0);
+      @include wh-value(100%, null);
+      @include background(null, $theme-bg-color, null, null, null);
+      li {
+        @include position_value(relative, null, null, null, null);
+        @include background(null, $secondary, null, null, null);
+        @include line-height(14px);
+        list-style-type: none;
+        cursor: pointer;
+        color: $white;
+        &.round-edge-top-3 {
+          @include roundedTopRightRadius(3);
+          @include roundedTopLeftRadius(3);
+        }
+        &.round-edge-bottom-3 {
+          @include roundedBottomLeftRadius(3);
+          @include roundedBottomRightRadius(3);
+        }
+        &.border-bottom-none {
+          @include border(bottom, 0, !important, null);
+        }
+        &.header-menu {
+          @include background(null, $theme-bg-color, null, null, null);
+          @include padding-value(10, 20, 0, 4);
+          @include font(null, null, bold);
+          cursor: default;
+          .heading {
+            @include border(bottom, 2, solid, $primary);
+            @include font(null, 12px, null);
+            @include line-height(16px);
+            @include flexbox(block, null, null, null, null, null);
+            cursor: default;
+            color: $primary;
+          }
+        }
+        a {
+          &.individual {
+            @include padding-value(12, 5, 12, 15);
+            color: $white;
+          }
+          i {
+            @include wh-value(30px, null);
+          }
+          &.parentlink::after {
+            content: "\f105";
+            @include font("Font Awesome 5 Free", null, 900);
+            @include position_value(absolute, 14px, 15px, null, null);
+            @include transition(all, 0.3s, ease, 0s);
+            -webkit-font-smoothing: antialiased;
+            -moz-osx-font-smoothing: grayscale;
+          }
+        }
+        .sidebar-submenu {
+          opacity: 0;
+          @include transition(opacity, 0.4s, ease-in-out, 0s);
+          li {
+            @include background(null, $secondary, null, null, null);
+            @include wh-value(null, 0);
+            @include transition(height, 200ms, ease-in, 0s);
+            overflow: hidden;
+            &:last-child {
+              @include roundedBottomLeftRadius(4);
+              @include roundedBottomRightRadius(4);
+            }
+            .link {
+              color: $gray-500;
+            }
+            &:hover,
+            &.active {
+              .link {
+                color: $white;
+              }
+            }
+          }
+        }
+        &.menu-open {
+          @include background(null, $primary, null, null, null);
+          a {
+            &::after {
+              @include rotate(90);
+            }
+          }
+          .sidebar-submenu {
+            opacity: 1;
+            li {
+              @include wh-value(null, 45px);
+            }
+          }
+        }
+        &.parentactive {
+          @include background(null, $primary, null, null, null);
+          .parentlink {
+            color: $white;
+          }
+        }
+        .parentlink,
+        .link {
+          @include padding-value(12, 5, 12, 15);
+          @include flexbox(flex, null, null, null, null, null);
+        }
+      }
+    }
+  }
+  &.sidebar-collapse {
+    @include background(null, transparent, null, null, null);
+    nav {
+      transform: translate(0, 0);
+      @include wh-value($minimize-left, null);
+      ul {
+        &.scrollable-menu {
+          li {
+            a {
+              span {
+                @include position_value(null, 0, null, null, null);
+                @include padding-value(12, 5, 12, 20);
+              }
+              &.individual {
+                span {
+                  @include roundedBottomRightRadius(4);
+                }
+              }
+              &.parentlink,
+              &.individual {
+                span {
+                  @include background(null, $primary, null, null, null);
+                  @include roundedTopRightRadius(4);
+                }
+              }
+            }
+            &:hover {
+              .sidebar-submenu {
+                li {
+                  @include wh-value(null, 45px);
+                }
+              }
+              .sidebar-submenu,
+              a span {
+                @include flexbox(block !important, null, null, null, null, null);
+                @include position_value(absolute, null, null, null, $minimize-left);
+                @include wh-value(220px, null);
+                opacity: 1;
+              }
+            }
+            &.header-menu,
+            .sidebar-submenu {
+              @include flexbox(none !important, null, null, null, null, null);
+              transform: translateZ(0);
+            }
+          }
+        }
+        li {
+          a::after,
+          span {
+            @include flexbox(none !important, null, null, null, null, null);
+            transform: translateZ(0);
+          }
+        }
+      }
+    }
+  }
+  &.sidebar-open {
+    @include margin-value(0, 0, 0, $active-margin-left);
+  }
+}
\ No newline at end of file
diff --git a/src/app/layouts/sidebar/SidebarComponent.ts b/src/app/layouts/sidebar/SidebarComponent.ts
new file mode 100644 (file)
index 0000000..9cae634
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+
+/**
+ * @file Sidebar Component
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { DeviceCheckService } from 'DeviceCheckService';
+import { MENU_ITEMS, MENUITEMS } from 'src/models/MenuModel';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes SidebarComponent.html as template url
+ */
+@Component({
+    selector: 'app-sidebar',
+    templateUrl: './SidebarComponent.html',
+    styleUrls: ['./SidebarComponent.scss']
+})
+/** Exporting a class @exports SidebarComponent */
+export class SidebarComponent implements OnInit {
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** submenu router endpoints @public */
+    public routerEndpoint: string;
+
+    /** submenu router endpoints @public */
+    public getMenus: MENUITEMS[];
+
+    /** selected Menu @public */
+    public selectedItem: string;
+
+    /** get the classlist @public */
+    public elementCheck: HTMLCollection;
+
+    /** Apply active class for Desktop @public */
+    public classAppliedForDesktop: boolean = false;
+
+    /** Apply active class for mobile @public */
+    public classAppliedForMobile: boolean = false;
+
+    /** Device Check service @public */
+    public deviceCheckService: DeviceCheckService;
+
+    /** Check for the mobile @public */
+    public isMobile$: boolean;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.deviceCheckService = this.injector.get(DeviceCheckService);
+        this.getMenus = MENU_ITEMS;
+    }
+
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.deviceCheckService.checkDeviceType();
+        this.deviceCheckService.isMobile.subscribe((checkIsMobile: boolean) => {
+            this.isMobile$ = checkIsMobile;
+            this.getDeviceType();
+        });
+    }
+    /** method to open sideBarOpen in all the views */
+    public sideBarOpenClose(): void {
+        if (this.isMobile$) {
+            this.classAppliedForMobile = !this.classAppliedForMobile;
+        } else {
+            this.classAppliedForDesktop = !this.classAppliedForDesktop;
+        }
+        this.addClassMainWrapper();
+    }
+    /** Add class for mobile/Desktop in main-wrapper @public */
+    public addClassMainWrapper(): void {
+        const elementMain: HTMLElement = document.querySelector('#main-wrapper');
+        if (!isNullOrUndefined(elementMain)) {
+            if (this.isMobile$) {
+                elementMain.classList.toggle('sidebar-mobile');
+            } else {
+                elementMain.classList.toggle('sidebar-desktop');
+            }
+        }
+    }
+    /** Return the Device type @public */
+    public getDeviceType(): void {
+        if (this.isMobile$) {
+            this.classAppliedForMobile = true;
+            this.classAppliedForDesktop = false;
+        } else {
+            this.classAppliedForMobile = false;
+            this.classAppliedForDesktop = false;
+        }
+        this.addClassMainWrapper();
+    }
+    /** Set the SideBar Menus click function @public */
+    public handleMenuFunction(index: number, method: string, className: string, childExists: boolean): void {
+        this.selectedItem = method;
+        if (!isNullOrUndefined(method)) {
+            this.parentactiveClassAddRemove(index, method, className, childExists);
+        }
+    }
+    /** Removing the parentactive class which is already present and add it to current @public */
+    public parentactiveClassAddRemove(index: number, method: string, className: string, childExists: boolean): void {
+        const element: HTMLElement = document.querySelector('#' + method + '' + index);
+        const checkOpenedelement: boolean = element.classList.contains(className);
+        if (!checkOpenedelement) {
+            this.elementCheck = document.getElementsByClassName(className);
+            if (this.elementCheck.length > 0) {
+                this.removeClasses(className);
+            }
+        }
+        if (method !== 'nosubmenu') {
+            element.classList.toggle(className);
+        }
+        if (this.isMobile$ && !childExists) {
+            this.checkAndCloseSideBar(childExists);
+        }
+    }
+    /** Hide / Show Menus based on the clicking in the menus @public */
+    public checkAndCloseSideBar(childExists: boolean): void {
+        event.stopPropagation();
+        if (this.isMobile$ && !childExists) {
+            this.sideBarOpenClose();
+        }
+    }
+    /** remove existing Class @public */
+    public removeClasses(className: string): void {
+        this.elementCheck[0].classList.remove(className);
+        if (this.elementCheck[0]) {
+            this.removeClasses(className);
+        }
+    }
+}
diff --git a/src/app/login/LoginComponent.html b/src/app/login/LoginComponent.html
new file mode 100644 (file)
index 0000000..296d51b
--- /dev/null
@@ -0,0 +1,57 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="login-container">
+    <div class="wrap-login">
+        <div class="login-logo">
+            <img src="assets/images/logo.png" alt="Logo">
+        </div>
+        <form [formGroup]="loginForm" (ngSubmit)="onSubmit()" class="login-form" autocomplete="off">
+            <div class="wrap-input">
+                <input autocomplete="off" class="input-control" type="text" formControlName="userName" placeholder="{{ 'PAGE.LOGIN.USERNAME' | translate }}"
+                />
+                <span class="input-icon">
+                    <i class="fa fa-user" aria-hidden="true"></i>
+                </span>
+            </div>
+            <div *ngIf="submitted && loginForm.controls['userName'].errors" class="input-validation-msg">
+                <div *ngIf="loginForm.controls['userName'].errors.required">{{'PAGE.LOGIN.USERNAMEVALIDMESSAGE' | translate}}</div>
+            </div>
+            <div class="wrap-input">
+                <input autocomplete="off" class="input-control" type="password" formControlName="password" placeholder="{{ 'PAGE.LOGIN.PASSWORD' | translate }}"
+                />
+                <span class="input-icon">
+                    <i class="fa fa-lock" aria-hidden="true"></i>
+                </span>
+            </div>
+            <div *ngIf="submitted && loginForm.controls['password'].errors" class="input-validation-msg">
+                <div *ngIf="loginForm.controls['password'].errors.required">{{'PAGE.LOGIN.PASSWORDVALIDMESSAGE' | translate}}</div>
+            </div>
+            <button type="submit" class="submit-btn">
+                <i class="fa fa-arrow-right" aria-hidden="true"></i>
+            </button>
+            <div class="signup-text-center">
+                <span class="caret">{{'PAGE.LOGIN.SIGNINMSG' | translate}}</span>
+            </div>
+
+        </form>
+    </div>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
+<div class="login-footer">
+   <a href="https://osm.etsi.org" target="_blank">{{'OSMSOURCEMANO' | translate}} {{sharedService.osmVersion}}</a>
+</div>
diff --git a/src/app/login/LoginComponent.scss b/src/app/login/LoginComponent.scss
new file mode 100644 (file)
index 0000000..28ac159
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import "../../assets/scss/mixins/mixin";
+@import "../../assets/scss/variable";
+
+.login-container {
+  @include wh-value(100%, 100vh);
+  @include flexbox(flex, center, null, null, center, null);
+  @include background(url("../../assets/images/login_background.jpg"), null, cover, no-repeat, center);
+  background-attachment: fixed;
+  flex-wrap: wrap;
+  .wrap-login {
+    @include background(
+      linear-gradient(
+        to left bottom,
+        #00c0ef,
+        #00b3f9,
+        #3ea3fd,
+        #7190f8,
+        #9c78e8,
+        #a86cdd,
+        #b25fd1,
+        #bb51c3,
+        #b151c4,
+        #a652c6,
+        #9b53c6,
+        #9053c7
+      ),
+      null,
+      null,
+      null,
+      null
+    );
+    @include roundedCorners(15);
+    @include flexbox(flex, space-between, null, null, null, null);
+    @include position_value(relative, null, null, null, null);
+    @include box-shadow(0px, 3px, 10px, 0px, rgba($black, 0.5));
+    @include padding-value(20, 30, 20, 30);
+    flex-wrap: wrap;
+    color: $white;
+    overflow: visible;
+    .login-logo {
+      @include flexbox(flex, center, null, null, center, null);
+      @include position_value(absolute, -80px, null, null, 95px);
+      @include box-shadow(1px, 2px, 0px, 0px, $cerise-pink);
+      @include margin-value(0, 0, 10, 0);
+      @include wh-value(160px, 150px);
+      @include background(null, $white, null, null, null);
+      @include roundedCornersPercentage(50%);
+      img {
+        @include wh-value(130px, auto);
+        @include position_value(null, 50px, null, null, null);
+      }
+    }
+    .login-form {
+      @include wh-value(290px, null);
+      @include padding-value(70, 0, 0, 0);
+      text-align: center;
+      .wrap-input {
+        @include position_value(relative, null, null, null, null);
+        @include wh-value(100%, null);
+        @include margin-value(0, 0, 10, 0);
+        z-index: 1;
+        .input-control {
+          @include font(null, 15px, null);
+          @include line-height(1.5);
+          @include wh-value(100%, 42px);
+          @include padding-value(0, 30, 0, 65);
+          @include flexbox(block, null, null, null, null, null);
+          @include roundedCorners(25);
+          @include border(all, 0, solid, $gray-80);
+          @include background(null, $white, null, null, null);
+          &:focus + .input-icon {
+            color: $cerise-pink;
+            @include padding-value(0, 0, 0, 25);
+          }
+        }
+        .input-icon {
+          @include font(null, 13px, null);
+          @include flexbox(flex, null, null, null, center, null);
+          @include position_value(absolute, null, null, 0, 0);
+          @include wh-value(100%, 100%);
+          @include padding-value(0, 0, 0, 35);
+          @include roundedCorners(25);
+          @include transition(all, 0.5s, null, null);
+          pointer-events: none;
+          color: $gray-600;
+        }
+      }
+      .submit-btn {
+        @include background(null, $white, null, null, null);
+        @include roundedCornersPercentage(50%);
+        @include border(all, 0, solid, $gray-80);
+        @include transition(all, 0.3s, null, null);
+        @include box-shadow(1px, 5px, 5px, 0px, rgba($black, 0.3), inset);
+        cursor: pointer;
+        @include font(null, 25px, null);
+        @include wh-value(60px, 60px);
+        @include margin-value(0, 0, 10, 0);
+        @include padding-value(0, 0, 0, 0);
+        color: $cerise-pink;
+        &:hover {
+          @include box-shadow(1px, 5px, 10px, 0px, rgba($black, 0.3));
+        }
+        .fa {
+          @include transition(all, 0.4s, null, null);
+          @include flexbox(block, null, null, null, null, null);
+          @include padding-value(18, 18, 18, 18);
+          &:hover {
+            transform: scale(1.2);
+          }
+        }
+      }
+      .input-validation-msg {
+        @include roundedCorners(25);
+        @include background(null, $cerise-pink, null, null, null);
+        @include margin-value(0, 0, 10, 0);
+        @include padding-value(1, 0, 1, 15);
+        @include font(null, 11px, null);
+        color: $white;
+        text-align: left;
+      }
+    }
+  }
+}
+.login-footer {
+  @include flexbox(flex, space-between, null, null, center, null);
+  @include position_value(fixed, null, null, 0px, null);
+  @include background(null, $purple, null, null, null);
+  @include wh-value(100%, 40px);
+  @include padding-value(0, 10, 0, 10);
+  color: $white;
+  opacity: 0.9;
+  a {
+    @include font(null, null, bold);
+    color: $white;
+    &:hover {
+      text-decoration: underline;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/app/login/LoginComponent.ts b/src/app/login/LoginComponent.ts
new file mode 100644 (file)
index 0000000..2f4f67e
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+
+/**
+ * @file Page for Login component
+ */
+import { HttpErrorResponse } from '@angular/common/http';
+import { Component, Injector, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { Router } from '@angular/router';
+import { AuthenticationService } from 'AuthenticationService';
+import { RestService } from 'RestService';
+import { Observable } from 'rxjs';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes LoginComponent.html as template url
+ */
+@Component({
+    selector: 'app-login',
+    templateUrl: './LoginComponent.html',
+    styleUrls: ['./LoginComponent.scss']
+})
+/** Exporting a class @exports LoginComponent */
+export class LoginComponent implements OnInit {
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** contains loginform group information @public */
+    public loginForm: FormGroup;
+
+    /** submitted set to boolean state @public */
+    public submitted: boolean = false;
+
+    /** contains return URL link @public */
+    public returnUrl: string;
+
+    /** Observable Hold the value of subscription  @public */
+    public isLoggedIn$: Observable<boolean>;
+
+    /** contains access token information @public */
+    public accessToken: string;
+
+    /** Utilizes rest service for any CRUD operations @public */
+    public restService: RestService;
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = false;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Contains all methods related to shared @public */
+    public sharedService: SharedService;
+
+    /** Utilizes auth service for any auth operations @private */
+    private authService: AuthenticationService;
+
+    /** contians form builder module @private */
+    private formBuilder: FormBuilder;
+
+    /** Holds teh instance of AuthService class of type AuthService @private */
+    private router: Router;
+
+    // creates instance of login component
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.authService = this.injector.get(AuthenticationService);
+        this.formBuilder = this.injector.get(FormBuilder);
+        this.router = this.injector.get(Router);
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.isLoggedIn$ = this.authService.isLoggedIn;
+        if (this.isLoggedIn$) {
+            this.router.navigate(['/']).catch(() => {
+                // Catch Navigation Error
+            });
+        }
+        this.loginForm = this.formBuilder.group({
+            userName: ['', [Validators.required]],
+            password: ['', [Validators.required]]
+        });
+        this.returnUrl = isNullOrUndefined(localStorage.getItem('returnUrl')) ? '/' : localStorage.getItem('returnUrl');
+    }
+
+    /**
+     * called on form submit @private onSubmit
+     */
+    public onSubmit(): void {
+        this.submitted = true;
+        if (this.loginForm.invalid) {
+            return;
+        }
+        this.isLoadingResults = true;
+        this.sharedService.cleanForm(this.loginForm);
+        this.authService.login(this.loginForm.value.userName, this.loginForm.value.password).subscribe(
+            (data: {}) => {
+                this.isLoadingResults = false;
+                this.router.navigate([this.returnUrl]).catch(() => {
+                    // Catch Navigation Error
+                });
+                localStorage.removeItem('returnUrl');
+            }, (err: HttpErrorResponse) => {
+                this.isLoadingResults = false;
+                this.restService.handleError(err, 'post');
+            });
+    }
+}
diff --git a/src/app/packages/PackagesComponent.html b/src/app/packages/PackagesComponent.html
new file mode 100644 (file)
index 0000000..06b8876
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<router-outlet></router-outlet>
diff --git a/src/app/packages/PackagesComponent.scss b/src/app/packages/PackagesComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/packages/PackagesComponent.ts b/src/app/packages/PackagesComponent.ts
new file mode 100644 (file)
index 0000000..eb9991d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Packages-Component.ts.
+ */
+import { Component, Injector } from '@angular/core';
+import { Router, RouterEvent } from '@angular/router';
+/**
+ * Creating Component
+ * @Component takes PackagesComponent.html as template url
+ */
+@Component({
+    selector: 'app-packages',
+    templateUrl: './PackagesComponent.html',
+    styleUrls: ['./PackagesComponent.scss']
+})
+/** Exporting a class @exports PackagesComponent */
+export class PackagesComponent{
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** Holds teh instance of AuthService class of type AuthService @private */
+    private router: Router;
+
+    // creates packages component
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.router = this.injector.get(Router);
+        this.router.events.subscribe((event: RouterEvent) => {
+            this.redirectToList(event.url);
+        });
+    }
+
+    /** Return to list NS Package List */
+    public redirectToList(getURL: string): void {
+        if (getURL === '/packages') {
+            this.router.navigate(['/packages/ns']).catch();
+        }
+    }
+}
diff --git a/src/app/packages/PackagesModule.ts b/src/app/packages/PackagesModule.ts
new file mode 100644 (file)
index 0000000..e6c6628
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Packages Module.
+ */
+import { CommonModule } from '@angular/common';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { ReactiveFormsModule } from '@angular/forms';
+import { FormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { CodemirrorModule } from '@ctrl/ngx-codemirror';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgSelectModule } from '@ng-select/ng-select';
+import { TranslateModule } from '@ngx-translate/core';
+import { ClonePackageComponent } from 'ClonePackage';
+import { DataService } from 'DataService';
+import { DragDirective } from 'DragDirective';
+import { EditPackagesComponent } from 'EditPackagesComponent';
+import { LoaderModule } from 'LoaderModule';
+import { NetsliceTemplateComponent } from 'NetsliceTemplate';
+import { SidebarModule } from 'ng-sidebar';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { NSComposerComponent } from 'NSComposer';
+import { NSPackagesComponent } from 'NSPackages';
+import { PackagesComponent } from 'Packages';
+import { PagePerRowModule } from 'PagePerRowModule';
+import { PageReloadModule } from 'PageReloadModule';
+import { ShowContentComponent } from 'ShowContent';
+import { VNFComposerComponent } from 'VNFComposer';
+import { VNFPackagesComponent } from 'VNFPackages';
+
+/** To halndle project information */
+const projectInfo: {} = { title: '{project}', url: '/' };
+
+/**
+ * configures  routers
+ */
+const routes: Routes = [
+    {
+        path: '',
+        component: PackagesComponent,
+        children: [
+            {
+                path: 'ns',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'NSPACKAGES', url: null }]
+                },
+                component: NSPackagesComponent
+            },
+            {
+                path: 'vnf',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'VNFPACKAGES', url: null }]
+                },
+                component: VNFPackagesComponent
+            },
+            {
+                path: 'netslice',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }
+                        , projectInfo, { title: 'PAGE.DASHBOARD.NETSLICETEMPLATE', url: null }]
+                },
+                component: NetsliceTemplateComponent
+            },
+            {
+                path: ':type/edit/:id',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }
+                        , projectInfo, { title: '{type}', url: '/packages/{type}' }, { title: '{id}', url: null }]
+                },
+                component: EditPackagesComponent
+            },
+            {
+                path: 'ns/compose/:id',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }
+                        , projectInfo, { title: 'NSPACKAGES', url: '/packages/ns' }, { title: '{id}', url: null }]
+                },
+                component: NSComposerComponent
+            },
+            {
+                path: 'vnf/compose/:id',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'VNFPACKAGES', url: '/packages/vnf' }, { title: '{id}', url: null }]
+                },
+                component: VNFComposerComponent
+            }
+        ]
+    }
+];
+
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+    imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, CommonModule, Ng2SmartTableModule,
+        CodemirrorModule, TranslateModule, RouterModule.forChild(routes), NgbModule, NgSelectModule,
+        PagePerRowModule, SidebarModule.forRoot(), LoaderModule, PageReloadModule],
+    declarations: [PackagesComponent, NSPackagesComponent, VNFPackagesComponent, NetsliceTemplateComponent,
+        DragDirective, ShowContentComponent, NSComposerComponent, VNFComposerComponent, EditPackagesComponent, ClonePackageComponent],
+    providers: [DataService],
+    schemas: [CUSTOM_ELEMENTS_SCHEMA],
+    entryComponents: [ShowContentComponent, ClonePackageComponent]
+})
+/** Exporting a class @exports PackagesModule */
+export class PackagesModule {
+    /** Variables declared to avoid state-less class */
+    private packagesModule: string;
+}
diff --git a/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.html b/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.html
new file mode 100644 (file)
index 0000000..af52927
--- /dev/null
@@ -0,0 +1,98 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="netSliceInstantiateForm" (ngSubmit)="instantiateNSTSubmit()">
+  <div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{'NEW' | translate}} NSI</h4>
+    <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+      <i class="fas fa-times-circle text-danger"></i>
+    </button>
+  </div>
+  <div class="modal-body modal-body-custom-height netsliceinstantiate-ns">
+    <div class="form-group row">
+      <label class="col-sm-12 col-form-label mandatory-label"
+        [ngClass]="{'text-danger': netSliceInstantiateForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+      <label class="col-sm-4 col-form-label" for="nsiName">{{'PAGE.NSTINSTANCEINSTANTIATE.NSNAME' | translate}}*</label>
+      <div class="col-sm-8">
+        <input autocomplete="off" class="form-control"
+          placeholder="{{'PAGE.NSTINSTANCEINSTANTIATE.NSNAME' | translate}}" type="text" formControlName="nsiName"
+          id="nsiName" [ngClass]="{ 'is-invalid': submitted && f.nsiName.errors }" required>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label"
+        for="nsiDescription">{{'PAGE.NSTINSTANCEINSTANTIATE.DESCRIPTION' | translate}}*</label>
+      <div class="col-sm-8">
+        <textarea class="form-control" placeholder="{{'PAGE.NSTINSTANCEINSTANTIATE.DESCRIPTION' | translate}}"
+          type="text" formControlName="nsiDescription" id="nsiDescription"
+          [ngClass]="{ 'is-invalid': submitted && f.nsiDescription.errors }" required></textarea>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="nstId">{{'PAGE.NSTINSTANCEINSTANTIATE.NSTID' | translate}}*</label>
+      <div class="col-sm-8">
+        <ng-select [items]="netSliceSelect" bindLabel="name" bindValue="_id"
+          placeholder="{{'SELECT' | translate}} {{'PAGE.NSTINSTANCEINSTANTIATE.NSTID' | translate}}"
+          formControlName="nstId" [(ngModel)]="netsliceNstId" id="nstId"
+          [ngClass]="{ 'is-invalid': submitted && f.nstId.errors }" required>
+        </ng-select>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label"
+        for="vimAccountId">{{'PAGE.NSTINSTANCEINSTANTIATE.VIMACCOUNT' | translate}}*</label>
+      <div class="col-sm-8">
+        <ng-select [items]="vimDetailsSelect" bindLabel="name" bindValue="_id"
+          placeholder="{{'SELECT' | translate}} {{'PAGE.NSTINSTANCEINSTANTIATE.VIMACCOUNT' | translate}}"
+          formControlName="vimAccountId" [(ngModel)]="vimAccountId" id="vimAccountId"
+          [ngClass]="{ 'is-invalid': submitted && f.vimAccountId.errors }" required>
+        </ng-select>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="ssh_keys">{{'PAGE.NSTINSTANCEINSTANTIATE.SSHKEY' | translate}}</label>
+      <div class="col-sm-8">
+        <textarea class="form-control" placeholder="{{'PAGE.NSTINSTANCEINSTANTIATE.SSHKEYMSG' | translate}}"
+          formControlName="ssh_keys" id="ssh_keys"></textarea>
+        <div class="fileupload-text mt-1 mb-1">{{'FILEUPLOADLABEL' | translate}}</div>
+        <div class="custom-file">
+          <input type="file" #fileInputSSH class="custom-file-input" (change)="sshFile($event.target.files)"
+            id="customSSHFile">
+          <label class="custom-file-label" #fileInputSSHLabel for="customSSHFile">{{'CHOOSEFILE' | translate}}</label>
+        </div>
+      </div>
+    </div>
+    <div class="form-group row">
+      <label class="col-sm-4 col-form-label" for="config">{{'CONFIG' | translate}}</label>
+      <div class="col-sm-8">
+        <textarea class="form-control" placeholder="{{'YAMLCONFIG' | translate}}" formControlName="config"
+          id="config"></textarea>
+        <div class="fileupload-text mt-1 mb-1">{{'FILEUPLOADLABEL' | translate}}</div>
+        <div class="custom-file">
+          <input type="file" #fileInputConfig class="custom-file-input" (change)="configFile($event.target.files)"
+            id="customConfigFile">
+          <label class="custom-file-label" #fileInputConfigLabel for="customConfigFile">{{'CHOOSEFILE' | translate}}</label>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+    <button type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+  </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.scss b/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.scss
new file mode 100644 (file)
index 0000000..0ecd95d
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
\ No newline at end of file
diff --git a/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.ts b/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.ts
new file mode 100644 (file)
index 0000000..ed5e414
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Instantiate NS Modal Component.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { Router } from '@angular/router';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import * as jsyaml from 'js-yaml';
+import { NetworkSliceData } from 'NetworkSliceModel';
+import { NSICREATEPARAMS } from 'NSDModel';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+import { VimAccountDetails } from 'VimAccountModel';
+/**
+ * Creating component
+ * @Component takes InstantiateNetSliceTemplateComponent.html as template url
+ */
+@Component({
+  selector: 'app-instantiate-net-slice-template',
+  templateUrl: './InstantiateNetSliceTemplateComponent.html',
+  styleUrls: ['./InstantiateNetSliceTemplateComponent.scss']
+})
+/** Exporting a class @exports InstantiateNetSliceTemplateComponent */
+export class InstantiateNetSliceTemplateComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** FormGroup instance added to the form @ html @public */
+  public netSliceInstantiateForm: FormGroup;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Variable set for twoway bindng @public  */
+  public vimAccountId: string;
+
+  /** Contains all the net slice data collections */
+  public netSliceSelect: NetworkSliceData;
+
+  /** Contains all the VIM data collections */
+  public vimDetailsSelect: VimAccountDetails;
+
+  /** Variable set for twoway binding @public */
+  public netsliceNstId: string;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Element ref for fileInputConfig @public */
+  @ViewChild('fileInputConfig', { static: true }) public fileInputConfig: ElementRef;
+
+  /** Element ref for fileInputConfigLabel @public */
+  @ViewChild('fileInputConfigLabel', { static: true }) public fileInputConfigLabel: ElementRef;
+
+  /** Element ref for fileInputSSH @public */
+  @ViewChild('fileInputSSH', { static: true }) public fileInputSSH: ElementRef;
+
+  /** Element ref for fileInputSSHLabel @public */
+  @ViewChild('fileInputSSHLabel', { static: true }) public fileInputSSHLabel: ElementRef;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private router: Router;
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Utilizes rest service for any CRUD operations @private */
+  private restService: RestService;
+
+  /** Utilizes data service for any communication @private */
+  private dataService: DataService;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Contains the ssh key to be hosted in dom @private */
+  private copySSHKey: string;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.dataService = this.injector.get(DataService);
+    this.notifierService = this.injector.get(NotifierService);
+    this.router = this.injector.get(Router);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    /** Setting up initial value for NSD */
+    this.netsliceNstId = '';
+    this.dataService.currentMessage.subscribe((event: NetworkSliceData) => {
+      if (event.identifier !== undefined || event.identifier !== '' || event.identifier !== null) {
+        this.netsliceNstId = event.identifier;
+      }
+    });
+    this.netSliceInstantiateFormAction();
+    this.headers = new HttpHeaders({
+      'Content-Type': 'application/json',
+      Accept: 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    /** On Initializing call the methods */
+    this.getNetSliceDetails();
+    this.getVIMDetails();
+  }
+
+  /** Call the netSlice details in the selection options @public */
+  public getNetSliceDetails(): void {
+    this.restService.getResource(environment.NETWORKSLICETEMPLATECONTENT_URL).subscribe((netSlicePackages: NetworkSliceData) => {
+      this.netSliceSelect = netSlicePackages;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+    });
+  }
+
+  /** Call the VIM details in the selection options @public */
+  public getVIMDetails(): void {
+    this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimDetails: VimAccountDetails) => {
+      this.vimDetailsSelect = vimDetails;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+    });
+  }
+
+  /** On modal initializing forms  @public */
+  public netSliceInstantiateFormAction(): void {
+    this.netSliceInstantiateForm = this.formBuilder.group({
+      nsiName: ['', [Validators.required]],
+      nsiDescription: ['', [Validators.required]],
+      nstId: ['', [Validators.required]],
+      vimAccountId: ['', [Validators.required]],
+      ssh_keys: [null],
+      config: [null]
+    });
+  }
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.netSliceInstantiateForm.controls; }
+
+  /** On modal submit instantiateNsSubmit will called @public */
+  public instantiateNSTSubmit(): void {
+    this.submitted = true;
+    this.sharedService.cleanForm(this.netSliceInstantiateForm);
+    if (this.netSliceInstantiateForm.invalid) {
+      return;
+    }
+    const modalData: MODALCLOSERESPONSEDATA = {
+      message: 'Done'
+    };
+    if (isNullOrUndefined(this.netSliceInstantiateForm.value.ssh_keys) || this.netSliceInstantiateForm.value.ssh_keys === '') {
+      delete this.netSliceInstantiateForm.value.ssh_keys;
+    } else {
+      this.copySSHKey = JSON.parse(JSON.stringify(this.netSliceInstantiateForm.value.ssh_keys));
+      // tslint:disable-next-line: no-backbone-get-set-outside-model
+      this.netSliceInstantiateForm.get('ssh_keys').setValue(this.copySSHKey);
+    }
+    if (isNullOrUndefined(this.netSliceInstantiateForm.value.config) || this.netSliceInstantiateForm.value.config === '') {
+      delete this.netSliceInstantiateForm.value.config;
+    } else {
+      const validJSON: boolean = this.sharedService.checkJson(this.netSliceInstantiateForm.value.config);
+      if (validJSON) {
+        this.netSliceInstantiateForm.value.config = JSON.parse(this.netSliceInstantiateForm.value.config);
+        Object.keys(this.netSliceInstantiateForm.value.config).forEach((item: string) => {
+          this.netSliceInstantiateForm.value[item] = this.netSliceInstantiateForm.value.config[item];
+        });
+        delete this.netSliceInstantiateForm.value.config;
+      } else {
+        this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG'));
+        return;
+      }
+    }
+    this.isLoadingResults = true;
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.NETWORKSLICEINSTANCESCONTENT_URL,
+      httpOptions: { headers: this.headers }
+    };
+    this.restService.postResource(apiURLHeader, this.netSliceInstantiateForm.value)
+      .subscribe((result: {}) => {
+        this.activeModal.close(modalData);
+        this.isLoadingResults = false;
+        this.notifierService.notify('success', this.netSliceInstantiateForm.value.nsiName +
+          this.translateService.instant('PAGE.NETSLICE.CREATEDSUCCESSFULLY'));
+        this.router.navigate(['/instances/netslice']).catch();
+      }, (error: ERRORDATA) => {
+        this.restService.handleError(error, 'post');
+        if (!isNullOrUndefined(this.copySSHKey)) {
+          // tslint:disable-next-line: no-backbone-get-set-outside-model
+          this.netSliceInstantiateForm.get('ssh_keys').setValue(this.copySSHKey);
+        }
+        this.isLoadingResults = false;
+      });
+  }
+
+  /** ssh file process @private */
+  public sshFile(files: FileList): void {
+    if (files && files.length === 1) {
+      this.sharedService.getFileString(files, 'pub').then((fileContent: string): void => {
+        const getSSHJson: string = jsyaml.load(fileContent, { json: true });
+        // tslint:disable-next-line: no-backbone-get-set-outside-model
+        this.netSliceInstantiateForm.get('ssh_keys').setValue(getSSHJson);
+      }).catch((err: string): void => {
+        if (err === 'typeError') {
+          this.notifierService.notify('error', this.translateService.instant('PUBFILETYPEERRROR'));
+        } else {
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        }
+        this.fileInputSSHLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+        this.fileInputSSH.nativeElement.value = null;
+      });
+    } else if (files && files.length > 1) {
+      this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+    }
+    this.fileInputSSHLabel.nativeElement.innerText = files[0].name;
+    this.fileInputSSH.nativeElement.value = null;
+  }
+
+  /** Config file process @private */
+  public configFile(files: FileList): void {
+    if (files && files.length === 1) {
+      this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
+        const getConfigJson: string = jsyaml.load(fileContent, { json: true });
+        // tslint:disable-next-line: no-backbone-get-set-outside-model
+        this.netSliceInstantiateForm.get('config').setValue(JSON.stringify(getConfigJson));
+      }).catch((err: string): void => {
+        if (err === 'typeError') {
+          this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
+        } else {
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        }
+        this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+        this.fileInputConfig.nativeElement.value = null;
+      });
+    } else if (files && files.length > 1) {
+      this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+    }
+    this.fileInputConfigLabel.nativeElement.innerText = files[0].name;
+    this.fileInputConfig.nativeElement.value = null;
+  }
+
+}
diff --git a/src/app/packages/instantiate-ns/InstantiateNsComponent.html b/src/app/packages/instantiate-ns/InstantiateNsComponent.html
new file mode 100644 (file)
index 0000000..dabd469
--- /dev/null
@@ -0,0 +1,103 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="instantiateForm" (ngSubmit)="instantiateNsSubmit();">
+    <div class="modal-header">
+        <h4 class="modal-title" id="modal-basic-title">{{'PAGE.INSTANCEINSTANTIATE.NEWINSTANCE' | translate}}</h4>
+        <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+            <i class="fas fa-times-circle text-danger"></i>
+        </button>
+    </div>
+    <div class="modal-body modal-body-custom-height instantiate-ns">
+        <div class="form-group row">
+            <label class="col-sm-12 col-form-label mandatory-label"
+                [ngClass]="{'text-danger': instantiateForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+            <label class="col-sm-4 col-form-label"
+                for="nsName">{{'PAGE.INSTANCEINSTANTIATE.NSNAME' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control"
+                    placeholder="{{'PAGE.INSTANCEINSTANTIATE.NSNAME' | translate}}" type="text" formControlName="nsName"
+                    id="nsName" (keydown.space)="$event.preventDefault();"
+                    [ngClass]="{ 'is-invalid': submitted && f.nsName.errors }" required>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label"
+                for="nsDescription">{{'PAGE.INSTANCEINSTANTIATE.DESCRIPTION' | translate}}*</label>
+            <div class="col-sm-8">
+                <textarea class="form-control" placeholder="{{'PAGE.INSTANCEINSTANTIATE.DESCRIPTION' | translate}}"
+                    type="text" formControlName="nsDescription" id="nsDescription"
+                    [ngClass]="{ 'is-invalid': submitted && f.nsDescription.errors }" required></textarea>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="nsdId">{{'PAGE.INSTANCEINSTANTIATE.NSID' | translate}}*</label>
+            <div class="col-sm-8">
+                <ng-select [items]="nsdSelect" bindLabel="name" bindValue="_id"
+                    placeholder="{{'SELECT' | translate}} {{'PAGE.INSTANCEINSTANTIATE.NSID' | translate}}"
+                    formControlName="nsdId" [(ngModel)]="nsdId" id="nsdId"
+                    [ngClass]="{ 'is-invalid': submitted && f.nsdId.errors }" required>
+                </ng-select>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label"
+                for="vimAccountId">{{'PAGE.INSTANCEINSTANTIATE.VIMACCOUNT' | translate}}*</label>
+            <div class="col-sm-8">
+                <ng-select [items]="vimAccountSelect" bindLabel="name" bindValue="_id"
+                    placeholder="{{'SELECT' | translate}} {{'PAGE.INSTANCEINSTANTIATE.VIMACCOUNT' | translate}}"
+                    formControlName="vimAccountId" [(ngModel)]="vimAccountId" id="vimAccountId"
+                    [ngClass]="{ 'is-invalid': submitted && f.vimAccountId.errors }" required>
+                </ng-select>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label"
+                for="ssh_keys">{{'PAGE.INSTANCEINSTANTIATE.SSHKEY' | translate}}</label>
+            <div class="col-sm-8">
+                <textarea class="form-control" placeholder="{{'PAGE.INSTANCEINSTANTIATE.SSHKEYMSG' | translate}}"
+                    formControlName="ssh_keys" id="ssh_keys"></textarea>
+                <div class="fileupload-text mt-1 mb-1">{{'FILEUPLOADLABEL' | translate}}</div>
+                <div class="custom-file">
+                    <input type="file" #fileInputSSH class="custom-file-input" (change)="sshFile($event.target.files)"
+                        id="customSSHFile">
+                    <label class="custom-file-label" #fileInputSSHLabel
+                        for="customSSHFile">{{'CHOOSEFILE' | translate}}</label>
+                </div>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="config">{{'CONFIG' | translate}}</label>
+            <div class="col-sm-8">
+                <textarea class="form-control" placeholder="{{'YAMLCONFIG' | translate}}" formControlName="config"
+                    id="config"></textarea>
+                <div class="fileupload-text mt-1 mb-1">{{'FILEUPLOADLABEL' | translate}}</div>
+                <div class="custom-file">
+                    <input type="file" #fileInputConfig class="custom-file-input"
+                        (change)="configFile($event.target.files)" id="customConfigFile">
+                    <label class="custom-file-label" #fileInputConfigLabel
+                        for="customConfigFile">{{'CHOOSEFILE' | translate}}</label>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+        <button type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+    </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/packages/instantiate-ns/InstantiateNsComponent.scss b/src/app/packages/instantiate-ns/InstantiateNsComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/packages/instantiate-ns/InstantiateNsComponent.ts b/src/app/packages/instantiate-ns/InstantiateNsComponent.ts
new file mode 100644 (file)
index 0000000..515a24b
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Instantiate NS Modal Component.
+ */
+import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { Router } from '@angular/router';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import * as jsyaml from 'js-yaml';
+import { NSCREATEPARAMS, NSData, NSDDetails } from 'NSDModel';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+import { VimAccountDetails } from 'VimAccountModel';
+
+/**
+ * Creating component
+ * @Component takes InstantiateNsComponent.html as template url
+ */
+@Component({
+  selector: 'app-instantiate-ns',
+  templateUrl: './InstantiateNsComponent.html',
+  styleUrls: ['./InstantiateNsComponent.scss']
+})
+/** Exporting a class @exports InstantiateNsComponent */
+export class InstantiateNsComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Contains all the nsd data collections */
+  public nsdSelect: NSDDetails;
+
+  /** FormGroup instance added to the form @ html @public */
+  public instantiateForm: FormGroup;
+
+  /** Contains all vim account collections */
+  public vimAccountSelect: VimAccountDetails;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Variable set for twoway binding @public */
+  public nsdId: string;
+
+  /** Variable set for twoway bindng @public  */
+  public vimAccountId: string;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Element ref for fileInputConfig @public */
+  @ViewChild('fileInputConfig', { static: true }) public fileInputConfig: ElementRef;
+
+  /** Element ref for fileInputConfigLabel @public */
+  @ViewChild('fileInputConfigLabel', { static: true }) public fileInputConfigLabel: ElementRef;
+
+  /** Element ref for fileInputSSH @public */
+  @ViewChild('fileInputSSH', { static: true }) public fileInputSSH: ElementRef;
+
+  /** Element ref for fileInputSSHLabel @public */
+  @ViewChild('fileInputSSHLabel', { static: true }) public fileInputSSHLabel: ElementRef;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private router: Router;
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Utilizes rest service for any CRUD operations @private */
+  private restService: RestService;
+
+  /** Utilizes data service for any communication @private */
+  private dataService: DataService;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Contains the ssh key to be hosted in dom @private */
+  private copySSHKey: string;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.dataService = this.injector.get(DataService);
+    this.notifierService = this.injector.get(NotifierService);
+    this.router = this.injector.get(Router);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  public ngOnInit(): void {
+    /** Setting up initial value for NSD */
+    this.dataService.currentMessage.subscribe((event: NSData) => {
+      if (event.identifier !== undefined || event.identifier !== '' || event.identifier !== null) {
+        this.nsdId = event.identifier;
+      }
+    });
+    /** On Initializing call the methods */
+    this.instantiateFormAction();
+    this.getDetailsnsd();
+    this.getDetailsvimAccount();
+  }
+
+  /** On modal initializing forms  @public */
+  public instantiateFormAction(): void {
+    this.instantiateForm = this.formBuilder.group({
+      nsName: ['', [Validators.required]],
+      nsDescription: ['', [Validators.required]],
+      nsdId: ['', [Validators.required]],
+      vimAccountId: ['', [Validators.required]],
+      ssh_keys: [null],
+      config: [null]
+    });
+  }
+
+  /** Convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.instantiateForm.controls; }
+
+  /** Call the nsd details in the selection options @public */
+  public getDetailsnsd(): void {
+    this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL).subscribe((nsPackages: NSDDetails) => {
+      this.nsdSelect = nsPackages;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+    });
+  }
+
+  /** Call the vimAccount details in the selection options @public */
+  public getDetailsvimAccount(): void {
+    this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimAccounts: VimAccountDetails) => {
+      this.vimAccountSelect = vimAccounts;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+    });
+  }
+
+  /** On modal submit instantiateNsSubmit will called @public */
+  public instantiateNsSubmit(): void {
+    this.submitted = true;
+    this.sharedService.cleanForm(this.instantiateForm);
+    if (this.instantiateForm.invalid) {
+      return;
+    }
+    const modalData: MODALCLOSERESPONSEDATA = {
+      message: 'Done'
+    };
+    if (isNullOrUndefined(this.instantiateForm.value.ssh_keys) || this.instantiateForm.value.ssh_keys === '') {
+      delete this.instantiateForm.value.ssh_keys;
+    } else {
+      this.copySSHKey = JSON.parse(JSON.stringify(this.instantiateForm.value.ssh_keys));
+      // tslint:disable-next-line: no-backbone-get-set-outside-model
+      this.instantiateForm.get('ssh_keys').setValue([this.copySSHKey]);
+    }
+    if (isNullOrUndefined(this.instantiateForm.value.config) || this.instantiateForm.value.config === '') {
+      delete this.instantiateForm.value.config;
+    } else {
+      const validJSON: boolean = this.sharedService.checkJson(this.instantiateForm.value.config);
+      if (validJSON) {
+        this.instantiateForm.value.config = JSON.parse(this.instantiateForm.value.config);
+        Object.keys(this.instantiateForm.value.config).forEach((item: string) => {
+          this.instantiateForm.value[item] = this.instantiateForm.value.config[item];
+        });
+        delete this.instantiateForm.value.config;
+      } else {
+        this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG'));
+        return;
+      }
+    }
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.NSINSTANCESCONTENT_URL
+    };
+    this.isLoadingResults = true;
+    this.restService.postResource(apiURLHeader, this.instantiateForm.value).subscribe((result: {}) => {
+      this.activeModal.close(modalData);
+      this.notifierService.notify('success', this.instantiateForm.value.nsName +
+        this.translateService.instant('PAGE.NSINSTANCE.CREATEDSUCCESSFULLY'));
+      this.router.navigate(['/instances/ns']).catch();
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      this.restService.handleError(error, 'post');
+      if (!isNullOrUndefined(this.copySSHKey)) {
+        // tslint:disable-next-line: no-backbone-get-set-outside-model
+        this.instantiateForm.get('ssh_keys').setValue(this.copySSHKey);
+      }
+    });
+  }
+
+  /** ssh file process @private */
+  public sshFile(files: FileList): void {
+    if (files && files.length === 1) {
+      this.sharedService.getFileString(files, 'pub').then((fileContent: string): void => {
+        const getSSHJson: string = jsyaml.load(fileContent, { json: true });
+        // tslint:disable-next-line: no-backbone-get-set-outside-model
+        this.instantiateForm.get('ssh_keys').setValue(getSSHJson);
+      }).catch((err: string): void => {
+        if (err === 'typeError') {
+          this.notifierService.notify('error', this.translateService.instant('PUBFILETYPEERRROR'));
+        } else {
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        }
+        this.fileInputSSHLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+        this.fileInputSSH.nativeElement.value = null;
+      });
+    } else if (files && files.length > 1) {
+      this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+    }
+    this.fileInputSSHLabel.nativeElement.innerText = files[0].name;
+    this.fileInputSSH.nativeElement.value = null;
+  }
+
+  /** Config file process @private */
+  public configFile(files: FileList): void {
+    if (files && files.length === 1) {
+      this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
+        const getConfigJson: string = jsyaml.load(fileContent, { json: true });
+        // tslint:disable-next-line: no-backbone-get-set-outside-model
+        this.instantiateForm.get('config').setValue(JSON.stringify(getConfigJson));
+      }).catch((err: string): void => {
+        if (err === 'typeError') {
+          this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
+        } else {
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        }
+        this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+        this.fileInputConfig.nativeElement.value = null;
+      });
+    } else if (files && files.length > 1) {
+      this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+    }
+    this.fileInputConfigLabel.nativeElement.innerText = files[0].name;
+    this.fileInputConfig.nativeElement.value = null;
+  }
+}
diff --git a/src/app/packages/netslice-template/NetsliceTemplateComponent.html b/src/app/packages/netslice-template/NetsliceTemplateComponent.html
new file mode 100644 (file)
index 0000000..6d41e11
--- /dev/null
@@ -0,0 +1,38 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'PAGE.DASHBOARD.NETSLICETEMPLATE' | translate}}</div>
+</div>
+<div class="row">
+    <div class="dropzone mt-2" appDrag (click)="fileInput.click()" (files)="filesDropped($event)">
+        <input hidden type="file" #fileInput (change)="filesDropped($event.target.files)">
+        <div class="text-wrapper">
+            <div class="text-center file-drop-title">
+                <i class="fas fa-upload"></i> {{'DROPFILES' | translate}}</div>
+        </div>
+    </div>
+</div>
+<div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/packages/netslice-template/NetsliceTemplateComponent.scss b/src/app/packages/netslice-template/NetsliceTemplateComponent.scss
new file mode 100644 (file)
index 0000000..2c07d1b
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+.ng2-smart-th.identifier{
+    width:40% !important;
+}
\ No newline at end of file
diff --git a/src/app/packages/netslice-template/NetsliceTemplateComponent.ts b/src/app/packages/netslice-template/NetsliceTemplateComponent.ts
new file mode 100644 (file)
index 0000000..5360518
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Netslice-Template.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, ViewChild } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { NetslicePackagesActionComponent } from 'NetslicePackagesAction';
+import { NetworkSliceData, NetworkSliceModel } from 'NetworkSliceModel';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes NetsliceTemplateComponent.html as template url
+ */
+@Component({
+    selector: 'app-netslice-template',
+    templateUrl: './NetsliceTemplateComponent.html',
+    styleUrls: ['./NetsliceTemplateComponent.scss']
+})
+/** Exporting a class @exports NetsliceTemplateComponent */
+export class NetsliceTemplateComponent {
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Values for map config @public */
+    public selectedRows: object[] = [];
+
+    /** To consume REST API calls @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** handle translate @public */
+    public translateService: TranslateService;
+
+    /** Columns list of the smart table @public */
+    public columnLists: object = {};
+
+    /** Settings for smarttable to populate the table with columns @public */
+    public settings: object = {};
+
+    /** Values for map config @public */
+    public selectList: object[] = [];
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+
+    /** Element ref for fileInput @public */
+    @ViewChild('fileInput', { static: true }) public fileInput: ElementRef;
+
+    /** To consume REST API calls @private */
+    private dataService: DataService;
+
+    /** To consume REST API calls @private */
+    private restService: RestService;
+
+    /** Formation of appropriate Data for LocalDatasource @private */
+    private networkSliceData: NetworkSliceData[] = [];
+
+    /** variables holds file information @private */
+    private fileData: string | ArrayBuffer;
+
+    /** Controls the header form @private */
+    private headers: HttpHeaders;
+
+    /** Notifier service to popup notification @private */
+    private notifierService: NotifierService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.translateService = this.injector.get(TranslateService);
+        this.notifierService = this.injector.get(NotifierService);
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.generateColumns();
+        this.generateSettings();
+        this.generateData();
+        this.headers = new HttpHeaders({
+            'Content-Type': 'application/x-yaml',
+            Accept: 'application/json',
+            'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+        });
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** smart table Header Colums @public */
+    public generateColumns(): void {
+        this.columnLists = {
+            name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' },
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '50%' },
+            usageState: { title: this.translateService.instant('USAGESTATE'), width: '20%' },
+            Actions: {
+                name: 'Actions', width: '10%', filter: false, sort: false, type: 'custom',
+                title: this.translateService.instant('ACTIONS'),
+                valuePrepareFunction: (cell: NetworkSliceData, row: NetworkSliceData): NetworkSliceData => row,
+                renderComponent: NetslicePackagesActionComponent
+            }
+        };
+    }
+
+    /** smart table Data Settings @public */
+    public generateSettings(): void {
+        this.settings = {
+            edit: {
+                editButtonContent: '<i class="fa fa-edit" title="Edit"></i>',
+                confirmSave: true
+            },
+            delete: {
+                deleteButtonContent: '<i class="far fa-trash-alt" title="delete"></i>',
+                confirmDelete: true
+            },
+            columns: this.columnLists,
+            actions: {
+                add: false,
+                edit: false,
+                delete: false,
+                position: 'right'
+            },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** smart table listing manipulation @private */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** smart table listing manipulation @private */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'network-slice' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** Drag and drop feature and fetchind the details of files  @private */
+    public filesDropped(files: FileList): void {
+        if (files && files.length === 1) {
+            this.isLoadingResults = true;
+            this.sharedService.getFileString(files, 'yaml').then((fileContent: String | ArrayBuffer): void => {
+                const apiURLHeader: APIURLHEADER = {
+                    url: environment.NETWORKSLICETEMPLATECONTENT_URL,
+                    httpOptions: { headers: this.headers }
+                };
+                this.saveFileData(apiURLHeader, fileContent);
+            }).catch((err: string): void => {
+                this.isLoadingResults = false;
+                if (err === 'typeError') {
+                    this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
+                } else {
+                    this.notifierService.notify('error', this.translateService.instant('ERROR'));
+                }
+            });
+        } else if (files && files.length > 1) {
+            this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+        }
+    }
+
+    /** Post the droped files and reload the page @public */
+    public saveFileData(urlHeader: APIURLHEADER, fileData: {}): void {
+        this.fileInput.nativeElement.value = null;
+        this.restService.postResource(urlHeader, fileData).subscribe((result: {}) => {
+            this.notifierService.notify('success', this.translateService.instant('PAGE.NETSLICE.TEMPLATECREATEDSUCCESSFULLY'));
+            this.generateData();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'post');
+            this.isLoadingResults = false;
+        });
+    }
+
+    /** Generate nsData object from loop and return for the datasource @public */
+    public generateNetworkSliceData(networkSlicePackageData: NetworkSliceModel): NetworkSliceData {
+        return {
+            name: networkSlicePackageData.name,
+            identifier: networkSlicePackageData._id,
+            usageState: networkSlicePackageData._admin.usageState
+        };
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+
+    /** Fetching the data from server to Load in the smarttable @protected */
+    protected generateData(): void {
+        this.isLoadingResults = true;
+        this.restService.getResource(environment.NETWORKSLICETEMPLATECONTENT_URL).subscribe((networkSliceList: NetworkSliceModel[]) => {
+            this.networkSliceData = [];
+            networkSliceList.forEach((networkSlicePackageData: NetworkSliceModel) => {
+                const networkSliceDataObj: NetworkSliceData = this.generateNetworkSliceData(networkSlicePackageData);
+                this.networkSliceData.push(networkSliceDataObj);
+            });
+            if (this.networkSliceData.length > 0) {
+                this.checkDataClass = 'dataTables_present';
+            } else {
+                this.checkDataClass = 'dataTables_empty';
+            }
+            this.dataSource.load(this.networkSliceData).then((data: boolean) => {
+                this.isLoadingResults = false;
+            }).catch(() => {
+                this.isLoadingResults = false;
+            });
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+}
diff --git a/src/app/packages/ns-packages/NSPackagesComponent.html b/src/app/packages/ns-packages/NSPackagesComponent.html
new file mode 100644 (file)
index 0000000..5b67268
--- /dev/null
@@ -0,0 +1,44 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+  <div class="d-flex align-items-center header-style">NS {{'PACKAGES' | translate}}</div>
+  <span class="button">
+    <button class="btn btn-primary" type="button" placement="top" container="body" ngbTooltip="{{'PAGE.NSPACKAGE.ADDNSPACKAGE' | translate}}"
+      (click)="composeNSPackage()">
+      <i class="fas fa-plus-circle" aria-hidden="true"></i>&nbsp; {{'PAGE.NSPACKAGE.ADDNSPACKAGE' | translate}}
+    </button>
+  </span>
+</div>
+<div class="row">
+  <div class="dropzone mt-2" appDrag (click)="fileInput.click()" (files)="filesDropped($event)">
+    <input hidden type="file" #fileInput (change)="filesDropped($event.target.files)">
+    <div class="text-wrapper">
+      <div class="text-center file-drop-title">
+        <i class="fas fa-upload"></i> {{'DROPFILES' | translate}}</div>
+    </div>
+  </div>
+</div>
+<div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+  <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+  <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+  <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+  </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/packages/ns-packages/NSPackagesComponent.scss b/src/app/packages/ns-packages/NSPackagesComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/packages/ns-packages/NSPackagesComponent.ts b/src/app/packages/ns-packages/NSPackagesComponent.ts
new file mode 100644 (file)
index 0000000..46366e0
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file NS-Packages component.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA } from 'CommonModel';
+import { ComposePackages } from 'ComposePackages';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { LocalDataSource } from 'ng2-smart-table';
+import { NSData, NSDDetails } from 'NSDModel';
+import { NsPackagesActionComponent } from 'NsPackagesAction';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes NSPackagesComponent.html as template url
+ */
+@Component({
+    selector: 'app-ns-packages',
+    templateUrl: './NSPackagesComponent.html',
+    styleUrls: ['./NSPackagesComponent.scss']
+})
+
+/** Exporting a class @exports NSPackagesComponent */
+export class NSPackagesComponent implements OnInit {
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Formation of appropriate Data for LocalDatasource @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** handle translate @public */
+    public translateService: TranslateService;
+
+    /** Columns list of the smart table @public */
+    public columnLists: object = {};
+
+    /** Settings for smarttable to populate the table with columns @public */
+    public settings: object = {};
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+
+    /** Element ref for fileInput @public */
+    @ViewChild('fileInput', { static: true }) public fileInput: ElementRef;
+
+    /** Instance of the rest service @private */
+    private restService: RestService;
+
+    /** dataService to pass the data from one component to another @private */
+    private dataService: DataService;
+
+    /** Formation of appropriate Data for LocalDatasource @private */
+    private nsData: NSData[] = [];
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** variables holds file information @private */
+    private fileData: string | ArrayBuffer;
+
+    /** Controls the header form @private */
+    private headers: HttpHeaders;
+
+    /** Notifier service to popup notification @private */
+    private notifierService: NotifierService;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.sharedService = this.injector.get(SharedService);
+        this.translateService = this.injector.get(TranslateService);
+        this.notifierService = this.injector.get(NotifierService);
+        this.modalService = this.injector.get(NgbModal);
+    }
+
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.generateColumns();
+        this.generateSettings();
+        this.generateData();
+        this.headers = new HttpHeaders({
+            'Content-Type': 'application/gzip',
+            Accept: 'application/json',
+            'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+        });
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** smart table Header Colums @public */
+    public generateColumns(): void {
+        this.columnLists = {
+            shortName: { title: this.translateService.instant('SHORTNAME'), width: '15%', sortDirection: 'asc' },
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' },
+            description: { title: this.translateService.instant('DESCRIPTION'), width: '25%' },
+            vendor: { title: this.translateService.instant('VENDOR'), width: '15%' },
+            version: { title: this.translateService.instant('VERSION'), width: '10%' },
+            Actions: {
+                name: 'Actions', width: '15%', filter: false, sort: false, type: 'custom',
+                title: this.translateService.instant('ACTIONS'),
+                valuePrepareFunction: (cell: NSData, row: NSData): NSData => row, renderComponent: NsPackagesActionComponent
+            }
+        };
+    }
+
+    /** smart table Data Settings @public */
+    public generateSettings(): void {
+        this.settings = {
+            edit: {
+                editButtonContent: '<i class="fa fa-edit" title="Edit"></i>',
+                confirmSave: true
+            },
+            delete: {
+                deleteButtonContent: '<i class="far fa-trash-alt" title="delete"></i>',
+                confirmDelete: true
+            },
+            columns: this.columnLists,
+            actions: {
+                add: false,
+                edit: false,
+                delete: false,
+                position: 'right'
+            },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** smart table listing manipulation @public */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** smart table listing manipulation @public */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'ns-package' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** Drag and drop feature and fetchind the details of files  @public */
+    public filesDropped(files: FileList): void {
+        if (files && files.length === 1) {
+            this.isLoadingResults = true;
+            this.sharedService.getFileString(files, 'gz').then((fileContent: ArrayBuffer): void => {
+                const apiURLHeader: APIURLHEADER = {
+                    url: environment.NSDESCRIPTORSCONTENT_URL,
+                    httpOptions: { headers: this.headers }
+                };
+                this.saveFileData(apiURLHeader, fileContent);
+            }).catch((err: string): void => {
+                this.isLoadingResults = false;
+                if (err === 'typeError') {
+                    this.notifierService.notify('error', this.translateService.instant('GZFILETYPEERRROR'));
+                } else {
+                    this.notifierService.notify('error', this.translateService.instant('ERROR'));
+                }
+            });
+        } else if (files && files.length > 1) {
+            this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+        }
+    }
+
+    /** Post the droped files and reload the page @public */
+    public saveFileData(urlHeader: APIURLHEADER, fileData: {}): void {
+        this.fileInput.nativeElement.value = null;
+        this.restService.postResource(urlHeader, fileData).subscribe((result: {}) => {
+            this.notifierService.notify('success', this.translateService.instant('PAGE.NSPACKAGE.CREATEDSUCCESSFULLY'));
+            this.generateData();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'post');
+            this.isLoadingResults = false;
+        });
+    }
+
+    /** Generate nsData object from loop and return for the datasource @public */
+    public generateNSData(nsdpackagedata: NSDDetails): NSData {
+        return {
+            shortName: nsdpackagedata['short-name'],
+            identifier: nsdpackagedata._id,
+            description: nsdpackagedata.description,
+            vendor: nsdpackagedata.vendor,
+            version: nsdpackagedata.version
+        };
+    }
+
+    /** Fetching the data from server to Load in the smarttable @public */
+    public generateData(): void {
+        this.isLoadingResults = true;
+        this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL).subscribe((nsdPackageData: NSDDetails[]) => {
+            this.nsData = [];
+            nsdPackageData.forEach((nsdpackagedata: NSDDetails) => {
+                const nsDataObj: NSData = this.generateNSData(nsdpackagedata);
+                this.nsData.push(nsDataObj);
+            });
+            if (this.nsData.length > 0) {
+                this.checkDataClass = 'dataTables_present';
+            } else {
+                this.checkDataClass = 'dataTables_empty';
+            }
+            this.dataSource.load(this.nsData).then((data: boolean) => {
+                this.isLoadingResults = false;
+            }).catch(() => {
+                this.isLoadingResults = false;
+            });
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+    /** Handle compose new ns package method  @public */
+    public composeNSPackage(): void {
+        this.modalService.open(ComposePackages, { backdrop: 'static' }).componentInstance.params = { page: 'ns-package' };
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+}
diff --git a/src/app/packages/ns-packages/ns-composer/NSComposerComponent.html b/src/app/packages/ns-packages/ns-composer/NSComposerComponent.html
new file mode 100644 (file)
index 0000000..4e78c16
--- /dev/null
@@ -0,0 +1,264 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<ng-sidebar-container class="ns-topology-sidebar-container">
+  <!-- A sidebar -->
+  <ng-sidebar [(opened)]="sideBarOpened" position="left">
+    <div class="sidebar-header">
+      <span class="topology_title" *ngIf="isShowNSDDetails">{{'PAGE.TOPOLOGY.NSD' | translate}}</span>
+      <span class="topology_title" *ngIf="isShowVLDetails">{{'PAGE.TOPOLOGY.VIRTUALLINK' | translate}}</span>
+      <span class="topology_title" *ngIf="isShowVNFDetails">{{'PAGE.TOPOLOGY.VNF' | translate}}</span>
+      <span class="topology_title" *ngIf="isShowCPDetails">{{'PAGE.TOPOLOGY.CONNECTIONPOINT' | translate}}</span>
+      <button (click)="toggleSidebar()" class="close" type="button">
+        <i class="fas fa-times-circle text-danger" aria-hidden="true"></i>
+      </button>
+    </div>
+    <div class="sidebar-body">
+      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="isShowNSDDetails">
+        <div class="row">
+          <div class="col-12 p-0">
+            <form autocomplete="off">
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'SHORTNAME' | translate }}</label>
+                <div class="col-sm-8 p-0">
+                  <input type="text" class="form-control" placeholder="{{ 'SHORTNAME' | translate }}" name="shortName"
+                    [(ngModel)]="vnfdPackageDetails.shortName">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'VENDOR' | translate }}</label>
+                <div class="col-sm-8 p-0">
+                  <input type="text" class="form-control" placeholder="{{ 'VENDOR' | translate }}" name="vendor"
+                    [(ngModel)]="vnfdPackageDetails.vendor">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'DESCRIPTION' | translate }}</label>
+                <div class="col-sm-8 p-0">
+                  <textarea type="text" class="form-control" placeholder="{{ 'DESCRIPTION' | translate }}"
+                    name="description" [(ngModel)]="vnfdPackageDetails.description"></textarea>
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'VERSION' | translate }}</label>
+                <div class="col-sm-8 p-0">
+                  <input type="text" class="form-control" placeholder="{{ 'VERSION' | translate }}" name="version"
+                    [(ngModel)]="vnfdPackageDetails.version">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'ID' | translate }}</label>
+                <div class="col-sm-8 p-0">
+                  <input type="text" class="form-control" placeholder="{{ 'ID' | translate }}" name="id"
+                    [(ngModel)]="vnfdPackageDetails.id">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'NAME' | translate }}</label>
+                <div class="col-sm-8 p-0">
+                  <input type="text" class="form-control" placeholder="{{ 'NAME' | translate }}" name="name"
+                    [(ngModel)]="vnfdPackageDetails.name">
+                </div>
+              </div>
+              <button type="button" class="btn btn-primary" (click)="saveNSD()" placement="top"
+                ngbTooltip="Save">
+                <i class="fas fa-save"></i> {{'SAVE' | translate}}
+              </button>
+            </form>
+          </div>
+        </div>
+      </div>
+      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="isShowVLDetails">
+        <div class="row">
+          <div class="col-12 p-0">
+            <form autocomplete="off">
+              <div class="form-group row">
+                <label class="col-sm-4 p-0 col-form-label">{{ 'NAME' | translate }}</label>
+                <div class="col-sm-8 p-0">
+                  <input type="text" class="form-control" placeholder="{{ 'NAME' | translate }}" name="name"
+                    [(ngModel)]="vlDetails.name">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 p-0 col-form-label">{{'PAGE.NSPACKAGE.NSCOMPOSE.MGMTNETWORK' | translate}}</label>
+                <div class="col-sm-8 p-0">
+                  <select class="form-control custom-select" name="mgmt-network" [(ngModel)]="vlDetails['mgmt-network']">
+                    <option [value]="true">True</option>
+                    <option [value]="false">False</option>
+                  </select>
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 p-0 col-form-label">{{'PAGE.NSPACKAGE.NSCOMPOSE.VIMNETWORKNAME' | translate}}</label>
+                <div class="col-sm-8 p-0">
+                  <input type="text" class="form-control" placeholder="Vim network name" name="vim-network-name"
+                    [(ngModel)]="vlDetails['vim-network-name']">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 p-0 col-form-label">{{'TYPE' | translate}}</label>
+                <div class="col-sm-8 p-0">
+                  <input type="text" class="form-control" placeholder="Type" name="type" [(ngModel)]="vlDetails.type">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 p-0 col-form-label">{{ 'ID' | translate }}</label>
+                <div class="col-sm-8 p-0">
+                  <input type="text" class="form-control" placeholder="{{ 'ID' | translate }}" name="id"
+                    [(ngModel)]="vlDetails.id">
+                </div>
+              </div>
+              <button type="button" class="btn btn-primary" placement="top" ngbTooltip="Save"
+                (click)="saveVL(vlDetails.id)">
+                <i class="fas fa-save"></i> {{'SAVE' | translate}}
+              </button>
+            </form>
+          </div>
+        </div>
+      </div>
+      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="isShowVNFDetails">
+        <div class="row">
+          <div class="col-12 p-0">
+            <table class="table table-bordered text-dark custom-table">
+              <tbody>
+                <tr>
+                  <td>{{'PAGE.NSPACKAGE.NSCOMPOSE.MEMBER-VNF-INDEX' | translate}}</td>
+                  <td>{{ vnfData['member-vnf-index'] }}</td>
+                </tr>
+                <tr>
+                  <td>{{'PAGE.NSPACKAGE.NSCOMPOSE.VNFD-ID-REF' | translate}}</td>
+                  <td>{{ vnfData['vnfd-id-ref'] }}</td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </div>
+      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="isShowCPDetails">
+        <div class="row">
+          <div class="col-12 p-0">
+            <table class="table table-bordered text-dark custom-table">
+              <tbody>
+                <tr>
+                  <td>{{'PAGE.NSPACKAGE.NSCOMPOSE.VLD-ID' | translate}}</td>
+                  <td>{{ vlDetails['name'] }}</td>
+                </tr>
+                <tr>
+                  <td>{{'PAGE.NSPACKAGE.NSCOMPOSE.VNFD-CP-REF' | translate}}</td>
+                  <td>{{ cpData['vnfd-connection-point-ref'] }}</td>
+                </tr>
+                <tr>
+                  <td>{{'MEMBERINDEX' | translate}}</td>
+                  <td>{{ cpData['member-vnf-index-ref'] }}</td>
+                </tr>
+                <tr>
+                  <td>{{'PAGE.NSPACKAGE.NSCOMPOSE.VNFD-ID-REF' | translate}}</td>
+                  <td>{{ cpData['vnfd-id-ref'] }}</td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </div>
+    </div>
+  </ng-sidebar>
+  <!-- Page content -->
+  <div ng-sidebar-content>
+    <button (click)="toggleSidebar()" class="btn btn-default" placement="right" ngbTooltip="{{'OPEN' | translate }}">
+      <i class="fa fa-arrow-right detail-sidebar" aria-hidden="true"></i>
+    </button>
+  </div>
+</ng-sidebar-container>
+<div class="container-fluid text-dark">
+  <div class="row bg-white ns-composer-form">
+    <div class="col-xs-3 col-sm-3 col-md-3 col-lg-3 pl-0 px-0">
+      <div class="row">
+        <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2">
+          <fieldset class="p-2">
+            <legend class="vl-legend">
+              {{'PAGE.TOPOLOGY.SELECTELEMENT' | translate}}
+            </legend>
+            <ul class="list-group list-group-flush dragable">
+              <li class="list-group-item" draggable="true" (dragstart)="drag($event)" id="vl">
+                <img src="assets/images/VL.svg" class="ns-svg" draggable="false"/>
+                &nbsp;<span class="span-overflow-text font-weight-bold">{{'PAGE.TOPOLOGY.VL' | translate}}</span>
+                <span class="drag-icon pull-right"><i class="fas fa-arrows-alt"></i></span>
+              </li>
+            </ul>
+          </fieldset>
+        </div>
+      </div>
+      <div class="row">
+        <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
+          <fieldset class="p-2">
+            <legend class="vnfd-legend">
+              {{'PAGE.TOPOLOGY.VNFD' | translate}}
+            </legend>
+            <ul class="list-group list-group-flush dragable scroll-box">
+              <li id="list['id']" class="list-group-item" draggable="true" (dragstart)="drag($event)"
+                [attr.data-id]="list['id']" *ngFor="let list of vnfList" placement="top"
+              container="body" ngbTooltip="{{ list['short-name'] }}">
+                <img src="assets/images/VNFD.svg" class="ns-svg" draggable="false"/>
+                &nbsp;<span class="span-overflow-text font-weight-bold">{{ list['short-name'] }}</span>
+                <span class="drag-icon pull-right"><i class="fas fa-arrows-alt"></i></span>
+              </li>
+            </ul>
+          </fieldset>
+        </div>
+      </div>
+    </div>
+    <div class="col-xs-9 col-sm-9 col-md-9 col-lg-9">
+      <div class="row">
+        <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 pl-0">
+          <div class="btn-group list" role="group" aria-label="Basic example">
+            <button type="button" class="btn btn-primary topology-btn" (click)="onFreeze()"
+              [class.pinned]="classApplied" placement="top" container="body" ngbTooltip="{{(classApplied ? 'UNFREEZE' : 'FREEZE') | translate}}">
+              <i class="fas fa-thumbtack"></i>
+            </button>
+            <button type="button" class="btn btn-primary topology-btn" (click)="onEdit()" placement="top"
+              container="body" ngbTooltip="{{'EDIT' | translate}}">
+              <i class="fa fa-edit"></i>
+            </button>
+            <button type="button" class="btn btn-primary topology-btn" (click)="showInfo()" placement="top"
+              container="body" ngbTooltip="{{'PAGE.TOPOLOGY.HELP' | translate}}">
+              <i class="fas fa-info"></i>
+            </button>
+          </div>
+        </div>
+        <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 text-right pr-0 badgegroup">
+          <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+            <img src="assets/images/VNFD.svg" class="ns-svg" draggable="false"/>
+            <br>{{'PAGE.TOPOLOGY.VNF' | translate}}</span>
+          <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+            <img src="assets/images/VL.svg" class="ns-svg" draggable="false"/>
+            <br>{{'PAGE.TOPOLOGY.VL' | translate}}</span>
+          <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+            <img src="assets/images/CP.svg" class="ns-svg" draggable="false"/>
+            <br>{{'PAGE.TOPOLOGY.CP' | translate}}</span>
+        </div>
+      </div>
+      <div class="row border-all">
+        <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 svg-container">
+          <svg preserveAspectRatio="xMidYMin slice" (drop)="drop($event)" (dragover)="allowDrop($event)"
+            id="graphContainer" #graphContainer>
+          </svg>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/packages/ns-packages/ns-composer/NSComposerComponent.scss b/src/app/packages/ns-packages/ns-composer/NSComposerComponent.scss
new file mode 100644 (file)
index 0000000..d750ccc
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/packages/ns-packages/ns-composer/NSComposerComponent.ts b/src/app/packages/ns-packages/ns-composer/NSComposerComponent.ts
new file mode 100644 (file)
index 0000000..082496e
--- /dev/null
@@ -0,0 +1,1089 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file NS Compose Component
+ */
+// tslint:disable: no-increment-decrement
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, CONSTANTNUMBER, ERRORDATA, MODALCLOSERESPONSEDATA, MODALCLOSERESPONSEWITHCP } from 'CommonModel';
+import { ConfirmationTopologyComponent } from 'ConfirmationTopology';
+import * as d3 from 'd3';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import * as HttpStatus from 'http-status-codes';
+import * as jsyaml from 'js-yaml';
+import { COMPOSERNODES, CONSTITUENTVNFD, GRAPHDETAILS, NSDDetails, Tick, TickPath, VLD, VNFDCONNECTIONPOINTREF } from 'NSDModel';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+import { VNFData, VNFDDetails } from 'VNFDModel';
+
+/**
+ * Creating component
+ * @Component takes NSComposerComponent.html as template url
+ */
+@Component({
+  selector: 'app-ns-composer',
+  templateUrl: './NSComposerComponent.html',
+  styleUrls: ['./NSComposerComponent.scss'],
+  encapsulation: ViewEncapsulation.None
+})
+/** Exporting a class @exports NSComposerComponent */
+export class NSComposerComponent {
+  /** To inject services @public */
+  public injector: Injector;
+  /** View child contains graphContainer ref @public  */
+  @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef;
+  /** dataService to pass the data from one component to another @public */
+  public dataService: DataService;
+  /** Contains VNFD Informations @public */
+  public vnfdPackageDetails: VNFData = { identifier: '', shortName: '', vendor: '', description: '', version: '', id: '', name: '' };
+  /** Contains VL Details @public */
+  public vlDetails: VLD = {
+    name: '',
+    'mgmt-network': true,
+    'vim-network-name': '',
+    type: '',
+    id: ''
+  };
+  /** Contains the information of the type of modification @public  */
+  public putType: string;
+  /** Conatins mousedown action @public */
+  public mousedownNode: COMPOSERNODES = null;
+  /** Conatins mouseup action @public */
+  public mouseupNode: COMPOSERNODES = null;
+  /** Conatins mousedownLink action @public */
+  public mousedownLink: COMPOSERNODES = null;
+  /** Conatins current Selection node action @public */
+  public currentSelectedNode: COMPOSERNODES = null;
+  /** Conatins current Selection node action @public */
+  public currentSelectedLink: COMPOSERNODES = null;
+  /** Need to show the NSD Details @public */
+  public isShowNSDDetails: boolean = true;
+  /** Contains the node information of VL @public */
+  public vlNodes: {}[] = [];
+  /** Need to show the VL Details @public */
+  public isShowVLDetails: boolean = false;
+  /** Contains the node information of VNF @public */
+  public vnfNodes: {}[] = [];
+  /** contains the VNF Details @public */
+  public vnfData: CONSTITUENTVNFD;
+  /** Need to show the VNF Details @public */
+  public isShowVNFDetails: boolean = false;
+  /** Contains the node information of CP @public */
+  public cpNodes: {}[] = [];
+  /** Need to show the CP Details */
+  public cpData: VNFDCONNECTIONPOINTREF;
+  /** Need to show the VNF Details @public */
+  public isShowCPDetails: boolean = false;
+  /** random number count @public */
+  public randomNumberLength: number;
+  /** Contains the vnfd information @public */
+  public vnfList: VNFDDetails[] = [];
+  /** Add the activeclass for the selected @public */
+  public activeClass: string = 'active';
+  /** Add the fixed class for the freeze @public */
+  public fixedClass: string = 'fixed';
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = true;
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+  /** Get VNF selected node @public */
+  public getVNFSelectedData: VNFDDetails[];
+  /** Assign the forcesimulation active @public */
+  public forceSimulationActive: boolean = false;
+  /** Assign pinned class for the button when freezed @public */
+  public classApplied: boolean = false;
+  /** Contains sidebar open status @public */
+  public sideBarOpened: boolean = false;
+  /** Contains SVG attributes @private */
+  // tslint:disable-next-line:no-any
+  private svg: any;
+  /** Contains the Drag line */
+  // tslint:disable-next-line: no-any
+  private dragLine: any;
+  /** Contains VL node @private */
+  // tslint:disable-next-line:no-any
+  private vlNode: any;
+  /** Contains VNFD node @private */
+  // tslint:disable-next-line:no-any
+  private vnfdnode: any;
+  /** Contains CP node @private */
+  // tslint:disable-next-line:no-any
+  private cpnode: any;
+  /** Rendered nodes represent VL @private */
+  // tslint:disable-next-line:no-any
+  private gvlNode: any;
+  /** Rendered nodes represent VL @private */
+  // tslint:disable-next-line:no-any
+  private gvnfdNode: any;
+  /** Rendered nodes represent VL @private */
+  // tslint:disable-next-line:no-any
+  private gcpNode: any;
+  /** Contains forced node animations @private */
+  // tslint:disable-next-line:no-any
+  private force: any;
+  /** Contains all the selected node @private */
+  private selectedNode: COMPOSERNODES[] = [];
+  /** variables used for CP @private */
+  private iConnectionPointRef: number = 0;
+  /** Contains the connected point @private */
+  private connectionPoint: string;
+  /** Contains all the NSD information @private */
+  private nsd: string;
+  /** Contains all the VNFD information @private */
+  private vnfd: string;
+  /** Contains id of the node @private */
+  private identifier: string;
+  /** Variables used for cp @private */
+  private jConnectionPointRef: number = 0;
+  /** Contains copy of NSD information @private */
+  private nsdCopy: string;
+  /** Contains the VNFD copy @private */
+  private vnfdCopy: string;
+  /** Contains name of the node @private */
+  private name: string;
+  /** Contains member vnf index value of the node @private */
+  private memberVnfIndexValue: number = 0;
+  /** Contains path information of the node */
+  // tslint:disable-next-line:no-any
+  private path: any;
+  /** Contains the node information @private */
+  private nodes: COMPOSERNODES[] = [];
+  /** Contains the link information of nodes @private */
+  private links: {}[] = [];
+  /** Contains the NS information @private */
+  private nsData: NSDDetails;
+  /** Instance of the rest service @private */
+  private restService: RestService;
+  /** Service holds the router information @private */
+  private router: Router;
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private activatedRoute: ActivatedRoute;
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+  /** Contains lastkeypressed instance @private */
+  private lastKeyDown: number = -1;
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+  /** Setting the Value of connection point refrence of the CP @private */
+  private setVnfdConnectionPointRef: string;
+  /** Setting the Value of VL name for confirmation @private */
+  private vlName: string;
+  /** Setting the Value of VNFD name for confirmation @private */
+  private setVnfdName: string;
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+  /** Contains selected node VLD objects @private */
+  private selectedVLDResult: VLD;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.dataService = this.injector.get(DataService);
+    this.router = this.injector.get(Router);
+    this.activatedRoute = this.injector.get(ActivatedRoute);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.modalService = this.injector.get(NgbModal);
+    this.sharedService = this.injector.get(SharedService);
+  }
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    // tslint:disable-next-line:no-backbone-get-set-outside-model
+    this.identifier = this.activatedRoute.snapshot.paramMap.get('id');
+    this.generateData();
+    this.headers = new HttpHeaders({
+      'Content-Type': 'application/zip',
+      Accept: 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+  }
+  /** Events handles at drag on D3 region @public */
+  // tslint:disable-next-line:no-any
+  public drag(ev: any): void {
+    if (ev.target.id === 'vl') {
+      ev.dataTransfer.setData('text', ev.target.id);
+    } else {
+      ev.dataTransfer.setData('text', ev.target.attributes['data-id'].value);
+    }
+  }
+  /** On clicking redirect to NS edit page @public */
+  public onEdit(): void {
+    this.router.navigate(['/packages/ns/edit/', this.identifier]).catch(() => {
+      // Catch Navigation Error
+    });
+  }
+  /** Events handles drop at D3 region @public */
+  public drop(ev: DragEvent): void {
+    event.preventDefault();
+    this.name = ev.dataTransfer.getData('text');
+    if (this.name === 'vl') {
+      this.svg.selectAll('*').remove();
+      this.vldropComposer();
+    } else {
+      this.svg.selectAll('*').remove();
+      this.vnfd = ev.dataTransfer.getData('text');
+      this.vnfdropComposer();
+    }
+  }
+  /** Drop VL Composer Data @public */
+  public vldropComposer(): void {
+    this.randomNumberLength = CONSTANTNUMBER.randomNumber;
+    const generateId: string = 'ns_vl_' + this.randomString(
+      this.randomNumberLength,
+      '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+    );
+    if (this.nsData.vld !== undefined) {
+      this.nsData.vld.push({
+        'vim-network-name': 'PUBLIC',
+        name: generateId,
+        'mgmt-network': true,
+        type: 'ELAN',
+        id: generateId
+      });
+    } else {
+      Object.assign(this.nsData, {
+        vld: [{
+          'vim-network-name': 'PUBLIC',
+          name: generateId,
+          'mgmt-network': true,
+          type: 'ELAN',
+          id: generateId
+        }]
+      });
+    }
+    this.putType = 'nsdadd';
+    this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
+  }
+  /** Drop VNFD Composer Data @public */
+  public vnfdropComposer(): void {
+    if (this.nsData['constituent-vnfd'] !== undefined) {
+      this.nsData['constituent-vnfd'].push({
+        'vnfd-id-ref': this.vnfd,
+        'member-vnf-index': ++this.memberVnfIndexValue
+      });
+    } else {
+      Object.assign(this.nsData, {
+        'constituent-vnfd': [{
+          'vnfd-id-ref': this.vnfd,
+          'member-vnf-index': ++this.memberVnfIndexValue
+        }]
+      });
+    }
+    this.putType = 'vnfdadd';
+    this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
+  }
+  /** Events handles allow drop on D3 region @public */
+  public allowDrop(ev: DragEvent): void {
+    ev.preventDefault();
+  }
+  /** Save NSD Information @public */
+  public saveNSD(): void {
+    if (this.vnfdPackageDetails.shortName !== undefined) {
+      this.nsData['short-name'] = this.vnfdPackageDetails.shortName;
+    }
+    if (this.vnfdPackageDetails.vendor !== undefined) {
+      this.nsData.vendor = this.vnfdPackageDetails.vendor;
+    }
+    if (this.vnfdPackageDetails.description !== undefined) {
+      this.nsData.description = this.vnfdPackageDetails.description;
+    }
+    if (this.vnfdPackageDetails.version !== undefined) {
+      this.nsData.version = this.vnfdPackageDetails.version;
+    }
+    if (this.vnfdPackageDetails.id !== undefined) {
+      this.nsData.id = this.vnfdPackageDetails.id;
+    }
+    if (this.vnfdPackageDetails.name !== undefined) {
+      this.nsData.name = this.vnfdPackageDetails.name;
+    }
+    this.putType = 'nsdUpdate';
+    this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
+  }
+  /** Save Virtual Link @public */
+  public saveVL(vlid: string): void {
+    this.nsData.vld.forEach((result: VLD) => {
+      if (result.id === vlid) {
+        result.name = this.vlDetails.name;
+        result['mgmt-network'] = !isNullOrUndefined(this.vlDetails['mgmt-network']) ? this.vlDetails['mgmt-network'] : true;
+        result['vim-network-name'] = !isNullOrUndefined(this.vlDetails['vim-network-name']) ? this.vlDetails['vim-network-name'] : '';
+        result.type = this.vlDetails.type;
+        result.id = this.vlDetails.id;
+      }
+    });
+    this.putType = 'vlUpdate';
+    this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
+  }
+  /** Add the new Data @public */
+  public addData(apiURL: string, identifier: string, data: NSDDetails, putType: string): void {
+    this.isLoadingResults = true;
+    let successMessage: string = '';
+    if (putType === 'nsdadd') {
+      successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNSD';
+    } else if (putType === 'vnfdadd') {
+      successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDVNFD';
+    } else if (putType === 'cpAdded') {
+      successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNS';
+    } else if (putType === 'nsdUpdate') {
+      successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY';
+    } else if (putType === 'vlUpdate') {
+      successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY';
+    } else if (putType === 'nsddelete') {
+      successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENSD';
+    } else if (putType === 'vnfddelete') {
+      successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETEVNFD';
+    } else if (putType === 'nsdelete') {
+      successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENS';
+    } else if (putType === 'linkdelete') {
+      successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETELINK';
+    }
+    /** Below hide for conflicts with light weight UI */
+    const apiURLHeader: APIURLHEADER = {
+      url: apiURL + '/' + identifier + '/nsd_content',
+      httpOptions: { headers: this.headers }
+    };
+    const nsData: {} = {};
+    nsData['nsd:nsd-catalog'] = {};
+    nsData['nsd:nsd-catalog'].nsd = [];
+    nsData['nsd:nsd-catalog'].nsd.push(data);
+    const descriptorInfo: string = jsyaml.dump(nsData, {sortKeys: true});
+    this.sharedService.targzFile({ packageType: 'nsd', id: this.identifier, descriptor: descriptorInfo })
+      .then((content: ArrayBuffer): void => {
+        this.restService.putResource(apiURLHeader, content).subscribe((res: {}) => {
+          this.generateData();
+          this.notifierService.notify('success', this.translateService.instant(successMessage));
+          this.isLoadingResults = false;
+        }, (error: ERRORDATA) => {
+          this.generateData();
+          this.restService.handleError(error, 'put');
+          this.isLoadingResults = false;
+        });
+      }).catch((): void => {
+        this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        this.isLoadingResults = false;
+      });
+  }
+  /** Show Info @public */
+  public showInfo(): void {
+    const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
+    modalRef.componentInstance.topologyType = 'Info';
+    modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO');
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        // empty
+      }
+    }).catch();
+  }
+  /** Event to freeze the animation @public */
+  public onFreeze(): void {
+    this.classApplied = !this.classApplied;
+    const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
+    d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
+    if (alreadyFixedIsActive) {
+      this.force.stop();
+    }
+    this.forceSimulationActive = alreadyFixedIsActive;
+    this.nodes.forEach((d: COMPOSERNODES) => {
+      d.fx = (alreadyFixedIsActive) ? null : d.x;
+      d.fy = (alreadyFixedIsActive) ? null : d.y;
+    });
+    if (alreadyFixedIsActive) {
+      this.force.restart();
+    }
+  }
+  /** Events handles when dragended @public */
+  public toggleSidebar(): void {
+    this.sideBarOpened = !this.sideBarOpened;
+    this.deselectAllNodes();
+    this.showRightSideInfo(true, false, false, false);
+  }
+  /** Prepare information for node creation of VNFD @private */
+  private generateData(): void {
+    this.generateVNFData();
+    this.generateDataNSDTopology();
+    this.sideBarOpened = false;
+  }
+  /** Prepare the information of the VNFD @private */
+  private generateVNFData(): void {
+    this.restService.getResource(environment.VNFPACKAGESCONTENT_URL).subscribe((vnfdPackageData: VNFDDetails[]) => {
+      this.vnfList = vnfdPackageData;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+    });
+  }
+  /** Prepare information for node creation of NSD Topology @private */
+  private generateDataNSDTopology(): void {
+    this.nodes = [];
+    this.links = [];
+    this.iConnectionPointRef = 0;
+    this.jConnectionPointRef = 0;
+    this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL + '/' + this.identifier).subscribe((nsData: NSDDetails) => {
+      delete nsData._admin;
+      delete nsData._id;
+      this.nsData = nsData;
+      this.vnfdPackageDetails.shortName = nsData['short-name'];
+      this.vnfdPackageDetails.vendor = nsData.vendor;
+      this.vnfdPackageDetails.description = nsData.description;
+      this.vnfdPackageDetails.version = nsData.version;
+      this.vnfdPackageDetails.id = nsData.id;
+      this.vnfdPackageDetails.name = nsData.name;
+      if (nsData.vld !== undefined) {
+        /** Details of the VL */
+        this.nsDataVLD(nsData);
+      }
+      if (nsData['constituent-vnfd'] !== undefined) {
+        /** Details of the VNFD */
+        this.nsDataConstituentVNFD(nsData);
+      }
+      if (nsData.vld !== undefined) {
+        this.nsDataVLDLinkCreation(nsData);
+      }
+      this.separateAndCreatenode();
+    }, (error: ERRORDATA) => {
+      if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
+        this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
+      } else {
+        this.restService.handleError(error, 'get');
+      }
+      this.isLoadingResults = false;
+      this.isShowNSDDetails = false;
+    });
+  }
+  /** nsData-vld undefined Call this function @private */
+  private nsDataVLD(nsData: NSDDetails): void {
+    nsData.vld.forEach((res: VLD) => {
+      this.nodes.push({ id: res.id, reflexive: false, type: 'vld', name: res.id, selectorId: res.id });
+      this.nsd = res.id;
+      if (res['vnfd-connection-point-ref'] !== undefined) {
+        res['vnfd-connection-point-ref'].forEach((result: VNFDCONNECTIONPOINTREF) => {
+          this.nodes.push(
+            {
+              id: this.nsd + ++this.iConnectionPointRef + ':' + result['vnfd-connection-point-ref'],
+              reflexive: false,
+              type: 'ns',
+              name: result['vnfd-connection-point-ref'],
+              nodeIndex: result['member-vnf-index-ref'],
+              selectorId: result['vnfd-connection-point-ref'] + '_' + result['member-vnf-index-ref'] + '-osm-' + this.nsd
+            });
+        });
+      }
+    });
+  }
+  /** nsData constituent-vnfd undefined Call this function @private */
+  private nsDataConstituentVNFD(nsData: NSDDetails): void {
+    nsData['constituent-vnfd'].forEach((res: CONSTITUENTVNFD) => {
+      this.nodes.push(
+        {
+          id: res['vnfd-id-ref'] + ':' + res['member-vnf-index'],
+          reflexive: false,
+          type: 'vnfd',
+          name: res['vnfd-id-ref'],
+          nodeIndex: res['member-vnf-index'],
+          selectorId: res['vnfd-id-ref'] + '_' + res['member-vnf-index']
+        });
+      this.vnfd = res['vnfd-id-ref'];
+      this.memberVnfIndexValue = res['member-vnf-index'];
+    });
+  }
+
+  /** nsData-vld undefined Call this function @private */
+  private nsDataVLDLinkCreation(nsData: NSDDetails): void {
+    nsData.vld.forEach((res: VLD) => {
+      this.nsdCopy = res.id;
+      if (res['vnfd-connection-point-ref'] !== undefined) {
+        this.nsDataVNFDConnectionPointRefrence(res);
+      }
+    });
+  }
+  /** nsData-vnfd-connection-point-ref undefined Call this function @private */
+  private nsDataVNFDConnectionPointRefrence(res: VLD): void {
+    res['vnfd-connection-point-ref'].forEach((result: VNFDCONNECTIONPOINTREF) => {
+      this.connectionPoint = this.nsdCopy + ++this.jConnectionPointRef + ':' + result['vnfd-connection-point-ref'];
+      this.vnfdCopy = result['vnfd-id-ref'] + ':' + result['member-vnf-index-ref'];
+      const connectionPointPos: number = this.nodes.map((e: COMPOSERNODES) => { return e.id; }).indexOf(this.connectionPoint);
+      const nsdPos: number = this.nodes.map((e: COMPOSERNODES) => { return e.id; }).indexOf(this.nsdCopy);
+      const vnfdPos: number = this.nodes.map((e: COMPOSERNODES) => { return e.id; }).indexOf(this.vnfdCopy);
+      this.links.push(
+        {
+          source: this.nodes[connectionPointPos],
+          target: this.nodes[nsdPos]
+        },
+        {
+          source: this.nodes[connectionPointPos],
+          target: this.nodes[vnfdPos]
+        });
+    });
+  }
+  /** Generate random string @private  */
+  private randomString(length: number, chars: string): string {
+    let result: string = '';
+    for (let randomStringRef: number = length; randomStringRef > 0; --randomStringRef) {
+      result += chars[Math.floor(Math.random() * chars.length)];
+    }
+    return result;
+  }
+  /** Separate and create node @private */
+  private separateAndCreatenode(): void {
+    this.seprateNodes(this.nodes);
+    this.createnode(this.nodes);
+    this.isLoadingResults = false;
+  }
+  /** Get the default Configuration of containers @private */
+  private getGraphContainerAttr(): GRAPHDETAILS {
+    return {
+      width: 700,
+      height: 400,
+      nodeHeight: 50,
+      nodeWidth: 35,
+      textX: -35,
+      textY: 30,
+      radius: 5,
+      distance: 50,
+      strength: -500,
+      forcex: 2,
+      forcey: 2,
+      sourcePaddingYes: 17,
+      sourcePaddingNo: 12,
+      targetPaddingYes: 4,
+      targetPaddingNo: 3,
+      alphaTarget: 0.3,
+      imageX: -25,
+      imageY: -25,
+      shiftKeyCode: 17
+    };
+  }
+  /** Separate the nodes along with its tyep @private */
+  private seprateNodes(node: COMPOSERNODES[]): void {
+    this.vlNodes = []; this.vnfNodes = []; this.cpNodes = [];
+    node.forEach((nodeList: COMPOSERNODES) => {
+      if (nodeList.type === 'vld') {
+        this.vlNodes.push(nodeList);
+      } else if (nodeList.type === 'vnfd') {
+        this.vnfNodes.push(nodeList);
+      } else if (nodeList.type === 'ns') {
+        this.cpNodes.push(nodeList);
+      }
+    });
+  }
+  /** Node is created and render at D3 region @private */
+  private createnode(node: COMPOSERNODES[]): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    d3.selectAll('svg#graphContainer > *').remove();
+    d3.select(window).on('keydown', () => { this.keyDown(); });
+    d3.select(window).on('keyup', () => { this.keyUp(); });
+    this.svg = d3.select('#graphContainer')
+      .attr('oncontextmenu', 'return false;')
+      .attr('width', graphContainerAttr.width)
+      .attr('height', graphContainerAttr.height)
+      .on('mousemove', () => { this.mousemove(); });
+    this.force = d3.forceSimulation()
+      .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
+      .force('link', d3.forceLink().id((d: TickPath) => d.id).distance(graphContainerAttr.distance))
+      .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex,
+        graphContainerAttr.height / graphContainerAttr.forcey))
+      .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
+      .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
+      .on('tick', () => { this.tick(); });
+    this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0');
+    this.path = this.svg.append('svg:g').selectAll('path');
+    this.vlNode = this.svg.append('svg:g').selectAll('vlnode');
+    this.vnfdnode = this.svg.append('svg:g').selectAll('vnfdnode');
+    this.cpnode = this.svg.append('svg:g').selectAll('cpnode');
+    // app starts here
+    this.restart(node);
+  }
+  /** update force layout (called automatically each iteration) @private */
+  private tick(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    // draw directed edges with proper padding from node centers
+    this.path.attr('class', 'link').attr('d', (d: Tick) => {
+      const deltaX: number = d.target.x - d.source.x;
+      const deltaY: number = d.target.y - d.source.y;
+      const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+      const normX: number = deltaX / dist;
+      const normY: number = deltaY / dist;
+      const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
+      const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
+      const sourceX: number = d.source.x + (sourcePadding * normX);
+      const sourceY: number = d.source.y + (sourcePadding * normY);
+      const targetX: number = d.target.x - (targetPadding * normX);
+      const targetY: number = d.target.y - (targetPadding * normY);
+      return `M${sourceX},${sourceY}L${targetX},${targetY}`;
+    }).on('dblclick', (d: Tick) => { this.getDeleteLinkConfirmation(d); });
+    this.vlNode.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`);
+    this.vnfdnode.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`);
+    this.cpnode.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`);
+  }
+  /** Update graph (called when needed) at D3 region @private */
+  private restart(node: COMPOSERNODES[]): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.path = this.path.data(this.links);
+    this.vlNode = this.vlNode.data(this.vlNodes, (d: COMPOSERNODES) => d.id);
+    this.vnfdnode = this.vnfdnode.data(this.vnfNodes, (d: COMPOSERNODES) => d.id);
+    this.cpnode = this.cpnode.data(this.cpNodes, (d: COMPOSERNODES) => d.id);
+    this.resetAndCreateNodes();
+    this.force.nodes(node).force('link').links(this.links);
+    this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
+  }
+  /** Rest and create nodes @private */
+  private resetAndCreateNodes(): void {
+    this.path.exit().remove();
+    this.vlNode.exit().remove();
+    this.vnfdnode.exit().remove();
+    this.cpnode.exit().remove();
+    this.getPathNodes();
+    this.getVLNodes();
+    this.getVNFDNodes();
+    this.getCPNodes();
+    this.path.merge(this.path);
+    this.vlNode = this.gvlNode.merge(this.vlNode);
+    this.vnfdnode = this.gvnfdNode.merge(this.vnfdnode);
+    this.cpnode = this.gcpNode.merge(this.cpnode);
+  }
+  /** setting the Path @private */
+  private getPathNodes(): void {
+    this.path = this.path.enter().append('svg:path');
+  }
+  /** Setting all the VL nodes @private */
+  private getVLNodes(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gvlNode = this.vlNode.enter().append('svg:g');
+    this.gvlNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gvlNode.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('id', (d: COMPOSERNODES) => { return d.selectorId; })
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/VL.svg')
+      .on('mousedown', (d: COMPOSERNODES) => { this.mouseDown(d); })
+      .on('mouseup', (d: COMPOSERNODES) => { this.mouseUp(d); })
+      .on('click', (d: COMPOSERNODES) => { this.singleClick(this.vlNode, d); this.onNodeClickToggleSidebar(); })
+      .on('dblclick', (d: COMPOSERNODES) => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
+    this.gvlNode.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: COMPOSERNODES) => d.id);
+  }
+  /** Setting all the VNFD nodes @private */
+  private getVNFDNodes(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gvnfdNode = this.vnfdnode.enter().append('svg:g');
+    this.gvnfdNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gvnfdNode.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('id', (d: COMPOSERNODES) => { return d.selectorId; })
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/VNFD.svg')
+      .on('mousedown', (d: COMPOSERNODES) => { this.mouseDown(d); })
+      .on('mouseup', (d: COMPOSERNODES) => { this.mouseUp(d); })
+      .on('click', (d: COMPOSERNODES) => { this.singleClick(this.vnfdnode, d); this.onNodeClickToggleSidebar(); })
+      .on('dblclick', (d: COMPOSERNODES) => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
+    this.gvnfdNode.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: COMPOSERNODES) => d.id);
+  }
+  /** Setting all the CP nodes @private */
+  private getCPNodes(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gcpNode = this.cpnode.enter().append('svg:g');
+    this.gcpNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gcpNode.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('id', (d: COMPOSERNODES) => { return d.selectorId; })
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/CP.svg')
+      .on('mousedown', (d: COMPOSERNODES) => { this.mouseDown(d); })
+      .on('mouseup', (d: COMPOSERNODES) => { this.mouseUp(d); })
+      .on('click', (d: COMPOSERNODES) => { this.singleClick(this.cpnode, d); this.onNodeClickToggleSidebar(); })
+      .on('dblclick', (d: COMPOSERNODES) => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
+    this.gcpNode.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: COMPOSERNODES) => d.id);
+  }
+  /** Events handles when mousemove it will capture the selected node data @private */
+  private mousemove(): void {
+    if (!this.mousedownNode) { return; }
+    this.dragLine.attr('d',
+      `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`);
+  }
+  /** Get confirmation Before Deleting the Link in Topology @private */
+  private getAddConfirmation(mouseData: COMPOSERNODES, getNsData: NSDDetails, addType: string, getVLDIndex: number): void {
+    let findVNFName: string = '';
+    let findVLDID: string = '';
+    if (mouseData.type === 'vld') {
+      findVNFName = this.mouseupNode.name;
+      findVLDID = this.mousedownNode.id;
+    } else {
+      findVNFName = this.mousedownNode.name;
+      findVLDID = this.mouseupNode.id;
+    }
+    getNsData.vld.forEach((result: VLD) => {
+      if (result.id === findVLDID) {
+        this.vlName = result.name;
+        this.getVNFSelectedData = this.vnfList.filter((vnfList: VNFDDetails) => vnfList.id === findVNFName);
+        this.setVnfdConnectionPointRef = this.getVNFSelectedData[0]['mgmt-interface'].cp;
+        this.setVnfdName = this.getVNFSelectedData[0].name;
+        this.selectedVLDResult = result;
+      }
+    });
+    if (this.vlName !== undefined && this.setVnfdName !== undefined && this.setVnfdConnectionPointRef !== undefined) {
+      const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
+      modalRef.componentInstance.topologyType = 'Add';
+      modalRef.componentInstance.cpDetails = this.getVNFSelectedData[0]['connection-point'];
+      this.translateService.get('PAGE.TOPOLOGY.ADDINGCP', {
+        vlname: '<b>' + this.vlName + '</b>',
+        vnfdname: '<b>' + this.setVnfdName + '</b>',
+        cpname: '<b>' + this.setVnfdConnectionPointRef + '</b>'
+      }).subscribe((res: string) => {
+        modalRef.componentInstance.topologyname = res;
+      });
+      modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.CONNECTIONPOINT');
+      modalRef.result.then((result: MODALCLOSERESPONSEWITHCP) => {
+        if (result) {
+          this.nsData = getNsData;
+          this.generateCPForVNF(this.selectedVLDResult, result.connection_point, getVLDIndex);
+          this.addData(environment.NSDESCRIPTORS_URL, this.identifier, getNsData, addType);
+        } else {
+          this.deselectPath();
+        }
+      }).catch();
+    } else {
+      this.deselectPath();
+      this.notifierService.notify('error', this.translateService.instant('ERROR'));
+    }
+  }
+
+  /** Generate connection point for vnf using vld @private */
+  private generateCPForVNF(result: VLD, cp: string, getVLDIndex: number): void {
+    if (result['vnfd-connection-point-ref'] !== undefined) {
+      result['vnfd-connection-point-ref'].push({
+        'member-vnf-index-ref': getVLDIndex,
+        'vnfd-connection-point-ref': cp,
+        'vnfd-id-ref': this.getVNFSelectedData[0].name
+      });
+    } else {
+      Object.assign(result, {
+        'vnfd-connection-point-ref': [{
+          'member-vnf-index-ref': getVLDIndex,
+          'vnfd-connection-point-ref': cp,
+          'vnfd-id-ref': this.getVNFSelectedData[0].name
+        }]
+      });
+    }
+  }
+
+  /** Events handles when mousedown click it will capture the selected node data @private */
+  private mouseDown(d: COMPOSERNODES): void {
+    event.preventDefault();
+    if (d3.event.ctrlKey) { return; }
+    if (d3.event.shiftKey) {
+      if (d.type === 'vnfd') {
+        this.selectedNode.push(d);
+      }
+      this.mousedownNode = d;
+      this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode;
+      this.currentSelectedLink = null;
+      this.dragLine.style('marker-end', 'url(#end-arrow)').classed('hidden', false)
+        .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`);
+    }
+  }
+  /** Event handles when mouseup event occures @private */
+  private mouseUp(d: COMPOSERNODES): void {
+    if (!this.mousedownNode) { return; }
+    this.dragLine.classed('hidden', true).style('marker-end', '');
+    this.mouseupNode = d;
+    if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vnfd') {
+      const getOldVLDIndex: string[] = this.mouseupNode.id.split(':');
+      const setOldVLDindex: number = +getOldVLDIndex[1];
+      this.putType = 'cpAdded';
+      this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex);
+    } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vld') {
+      const getOldVLDIndex: string[] = this.mousedownNode.id.split(':');
+      const setOldVLDindex: number = +getOldVLDIndex[1];
+      this.putType = 'cpAdded';
+      this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex);
+    } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'ns') {
+      this.deselectPath();
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
+    } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'ns') {
+      this.deselectPath();
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
+    } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vld') {
+      this.deselectPath();
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVL'));
+    } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vnfd') {
+      this.deselectPath();
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNF'));
+    } else if (this.mousedownNode.type === 'ns' && this.mouseupNode.type === 'ns') {
+      this.deselectPath();
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKCP'));
+    } else {
+      this.deselectPath();
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVLVNF'));
+    }
+    this.resetMouseVars();
+    // select new link
+    this.currentSelectedLink = d;
+    this.currentSelectedNode = null;
+  }
+  /** Mosue Drag Line false if it is not satisfied @private */
+  private deselectPath(): void {
+    this.dragLine.classed('hidden', true).style('marker-end', '').attr('d', 'M0,0L0,0');
+  }
+  /** reset Mouse varaibles @private */
+  private resetMouseVars(): void {
+    this.mousedownNode = null;
+    this.mouseupNode = null;
+    this.mousedownLink = null;
+  }
+  /** De-select all the selected nodes @private */
+  private deselectAllNodes(): void {
+    this.vlNode.select('image').classed(this.activeClass, false);
+    this.vnfdnode.select('image').classed(this.activeClass, false);
+    this.cpnode.select('image').classed(this.activeClass, false);
+  }
+  /** Show the right-side information @private */
+  private showRightSideInfo(nsdDetails: boolean, vldDetails: boolean, vnfDeails: boolean, cpDetails: boolean): void {
+    this.isShowNSDDetails = nsdDetails;
+    this.isShowVLDetails = vldDetails;
+    this.isShowVNFDetails = vnfDeails;
+    this.isShowCPDetails = cpDetails;
+  }
+  /** Events handles when Shift Click to perform create cp @private */
+  // tslint:disable-next-line: no-any
+  private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
+    this.selectNodeExclusive(nodeSelected, d);
+  }
+  /** Selected nodes @private */
+  // tslint:disable-next-line: no-any
+  private selectNodeExclusive(nodeSeleced: any, d: COMPOSERNODES): void {
+    const alreadyIsActive: boolean = nodeSeleced.select('#' + d.selectorId).classed(this.activeClass);
+    this.deselectAllNodes();
+    nodeSeleced.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive);
+    if (d.type === 'vld' && !alreadyIsActive) {
+      this.nsData.vld.forEach((result: VLD) => {
+        if (result.id === d.id) {
+          this.showRightSideInfo(false, true, false, false);
+          this.vlDetails = result;
+        }
+      });
+    } else if (d.type === 'vnfd' && !alreadyIsActive) {
+      this.nsData['constituent-vnfd'].forEach((result: CONSTITUENTVNFD) => {
+        if (result['member-vnf-index'] === d.nodeIndex && result['vnfd-id-ref'] === d.name) {
+          this.showRightSideInfo(false, false, true, false);
+          this.vnfData = result;
+        }
+      });
+    } else if (d.type === 'ns' && !alreadyIsActive) {
+      this.nsData.vld.forEach((result: VLD) => {
+        if (result['vnfd-connection-point-ref'] !== undefined) {
+          result['vnfd-connection-point-ref'].forEach((resultCP: VNFDCONNECTIONPOINTREF) => {
+            if (resultCP['member-vnf-index-ref'] === d.nodeIndex && resultCP['vnfd-connection-point-ref'] === d.name) {
+              this.cpData = resultCP;
+              this.vlDetails = result;
+              this.showRightSideInfo(false, false, false, true);
+            }
+          });
+        }
+      });
+    } else {
+      this.showRightSideInfo(true, false, false, false);
+    }
+  }
+  /** Get confirmation Before Deleting the Link in Topology @private */
+  private getDeleteLinkConfirmation(d: Tick): void {
+    const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
+    modalRef.componentInstance.topologyType = 'Delete';
+    modalRef.componentInstance.topologyname = this.translateService.instant('PAGE.TOPOLOGY.LINK');
+    modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.LINK';
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.doubleClickLink(d);
+      }
+    }).catch();
+  }
+  /** Events handles when Double Click to Delete the link @private */
+  private doubleClickLink(d: Tick): void {
+    let getID: string = '';
+    if (d.target.type === 'vld') {
+      getID = d.target.id;
+    } else if (d.source.type === 'vld') {
+      getID = d.source.id;
+    }
+    this.nodes.forEach((res: COMPOSERNODES) => {
+      if (res.id === getID) {
+        if (this.nsData.vld !== undefined) {
+          this.nsData.vld.forEach((vldresult: VLD) => {
+            if (vldresult.id === getID) {
+              delete vldresult['vnfd-connection-point-ref'];
+            }
+          });
+        }
+      }
+    });
+    this.putType = 'linkdelete';
+    this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
+  }
+  /** Get confirmation Before Deleting the Node in Topology @private */
+  private getDeleteConfirmation(d: COMPOSERNODES): void {
+    const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
+    modalRef.componentInstance.topologyType = 'Delete';
+    modalRef.componentInstance.topologyname = d.name;
+    if (d.type === 'vld') {
+      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VIRTUALLINK';
+    } else if (d.type === 'vnfd') {
+      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VNF';
+    } else if (d.type === 'ns') {
+      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT';
+    }
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.doubleClick(d);
+      }
+    }).catch();
+  }
+  /** Events handles when Double Click to Delete @private */
+  private doubleClick(d: COMPOSERNODES): void {
+    const deletedNode: COMPOSERNODES = d;
+    this.nodes.forEach((res: COMPOSERNODES) => {
+      if (res.id === d.id) {
+        if (deletedNode.type === 'vld') {
+          const pos: number = this.nsData.vld.map((e: VLD) => { return e.id; }).indexOf(d.id);
+          this.nsData.vld.splice(pos, 1);
+          this.putType = 'nsddelete';
+        } else if (deletedNode.type === 'vnfd') {
+          const constituentVNFD: string[] = [];
+          if (this.nsData['constituent-vnfd'] !== undefined) {
+            this.nsData['constituent-vnfd'].forEach((ref: CONSTITUENTVNFD) => {
+              constituentVNFD.push(ref['vnfd-id-ref'] + ':' + ref['member-vnf-index']);
+            });
+          }
+          const pos: number = constituentVNFD.map((e: string) => { return e; }).indexOf(d.id);
+          this.nsData['constituent-vnfd'].splice(pos, 1);
+          const getCP: string[] = d.id.split(':');
+          const memberVnfIndexRef: number = +getCP[1];
+          const vnfdIDRef: string = getCP[0];
+          if (this.nsData.vld !== undefined) {
+            this.nsData.vld.forEach((resf: VLD) => {
+              if (resf['vnfd-connection-point-ref'] !== undefined) {
+                resf['vnfd-connection-point-ref'].forEach((connectionPoint: VNFDCONNECTIONPOINTREF, index: number) => {
+                  if (+connectionPoint['member-vnf-index-ref'] === memberVnfIndexRef && connectionPoint['vnfd-id-ref'] === vnfdIDRef) {
+                    resf['vnfd-connection-point-ref'].splice(index, 1);
+                  }
+                });
+              }
+            });
+          }
+          this.putType = 'vnfddelete';
+        } else if (deletedNode.type === 'ns') {
+          const getCP: string[] = d.selectorId.split('-osm-');
+          const memberVnfIndexRef: number = d.nodeIndex;
+          const vnfdIDRef: string = getCP[getCP.length - 1];
+          if (this.nsData.vld !== undefined) {
+            this.nsData.vld.forEach((resf: VLD) => {
+              if (resf['vnfd-connection-point-ref'] !== undefined && resf.id === vnfdIDRef) {
+                resf['vnfd-connection-point-ref'].forEach((connectionPoint: VNFDCONNECTIONPOINTREF, index: number) => {
+                  if (connectionPoint['member-vnf-index-ref'] === memberVnfIndexRef) {
+                    resf['vnfd-connection-point-ref'].splice(index, 1);
+                  }
+                });
+              }
+            });
+          }
+          this.putType = 'nsdelete';
+        }
+        this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
+      }
+    });
+  }
+  /** Key press event @private */
+  private keyDown(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    if (this.lastKeyDown !== -1) { return; }
+    this.lastKeyDown = d3.event.keyCode;
+    if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
+      this.gvlNode.call(d3.drag()
+        .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
+      );
+      this.gvnfdNode.call(d3.drag()
+        .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
+      );
+      this.gcpNode.call(d3.drag()
+        .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
+      );
+      this.svg.classed('ctrl', true);
+    }
+  }
+  /** Key realse event @private */
+  private keyUp(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.lastKeyDown = -1;
+    if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
+      this.gvlNode.on('.drag', null);
+      this.gvnfdNode.on('.drag', null);
+      this.gcpNode.on('.drag', null);
+      this.svg.classed('ctrl', false);
+    }
+  }
+  /** Events handles when dragstarted @private */
+  private dragstarted(d: COMPOSERNODES): void {
+    d.fx = d.x;
+    d.fy = d.y;
+  }
+  /** Events handles when dragged @private */
+  private dragged(d: COMPOSERNODES): void {
+    d.fx = d.x = d3.event.x;
+    d.fy = d.y = d3.event.y;
+  }
+  /** Events handles when dragended @private */
+  private dragended(d: COMPOSERNODES): void {
+    if (this.forceSimulationActive) {
+      d.fx = null;
+      d.fy = null;
+    } else {
+      d.fx = d.x;
+      d.fy = d.y;
+      this.forceSimulationActive = false;
+    }
+  }
+  /** Events handles when node double click   @private */
+  private onNodedblClickToggleSidebar(): void {
+    this.sideBarOpened = false;
+  }
+  /** Events handles when node single click   @private */
+  private onNodeClickToggleSidebar(): void {
+    this.sideBarOpened = true;
+  }
+}
diff --git a/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.html b/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.html
new file mode 100644 (file)
index 0000000..2aa8f12
--- /dev/null
@@ -0,0 +1,312 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<ng-sidebar-container class="vnf-topology-sidebar-container">
+  <!-- A sidebar -->
+  <ng-sidebar [(opened)]="sideBarOpened" position="left">
+    <div class="sidebar-header">
+      <span class="topology_title" *ngIf="showRightSideInfo === 'vnfdInfo'">{{'PAGE.TOPOLOGY.VNFD' | translate}}</span>
+      <span class="topology_title" *ngIf="showRightSideInfo === 'vduInfo'">{{'PAGE.TOPOLOGY.VDU' | translate}}</span>
+      <span class="topology_title" *ngIf="showRightSideInfo === 'intvlInfo'">{{'PAGE.TOPOLOGY.VIRTUALLINK' | translate}}</span>
+      <span class="topology_title" *ngIf="showRightSideInfo === 'cpInfo'">{{'PAGE.TOPOLOGY.CONNECTIONPOINT' | translate}}</span>
+      <span class="topology_title" *ngIf="showRightSideInfo === 'intcpInfo'">{{'PAGE.TOPOLOGY.INTCONNECTIONPOINT' | translate}}</span>
+      <button (click)="toggleSidebar()" class="close" type="button">
+        <i class="fas fa-times-circle text-danger" aria-hidden="true"></i>
+      </button>
+    </div>
+    <div class="sidebar-body">
+      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="showRightSideInfo === 'vnfdInfo'">
+        <div class="row">
+          <div class="col-12 p-0">
+            <form>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'SHORTNAME' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'SHORTNAME' | translate }}" name="shortName"
+                    [(ngModel)]="vnfdInfo.shortName">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'DESCRIPTION' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'DESCRIPTION' | translate }}" name="description"
+                    [(ngModel)]="vnfdInfo.description">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'VERSION' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'VERSION' | translate }}" name="version"
+                    [(ngModel)]="vnfdInfo.version">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'ID' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'ID' | translate }}" name="id"
+                    [(ngModel)]="vnfdInfo.id">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'NAME' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'NAME' | translate }}" name="name"
+                    [(ngModel)]="vnfdInfo.name">
+                </div>
+              </div>
+              <button type="button" class="btn btn-primary btn-sm pull-right" (click)="saveVNFD()" placement="top" ngbTooltip="Save">
+                <i class="fas fa-save"></i> {{'SAVE' | translate}}
+              </button>
+            </form>
+          </div>
+        </div>
+      </div>
+      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="showRightSideInfo === 'vduInfo'">
+        <div class="row">
+          <div class="col-12 p-0">
+            <form>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'COUNT' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'COUNT' | translate }}" name="count"
+                    [(ngModel)]="vduInfo.count">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'DESCRIPTION' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'DESCRIPTION' | translate }}" name="description"
+                    [(ngModel)]="vduInfo.description">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'IMAGE' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'IMAGE' | translate }}" name="image"
+                    [(ngModel)]="vduInfo.image">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'ID' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'ID' | translate }}" name="id"
+                    [(ngModel)]="vduInfo.id">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'NAME' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'NAME' | translate }}" name="name"
+                    [(ngModel)]="vduInfo.name">
+                </div>
+              </div>
+              <button type="button" class="btn btn-primary btn-sm pull-right" (click)="saveVDU(vduInfo.id)" placement="top"
+                ngbTooltip="Save">
+                <i class="fas fa-save"></i> {{'SAVE' | translate}}
+              </button>
+            </form>
+          </div>
+        </div>
+      </div>
+      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="showRightSideInfo === 'intvlInfo'">
+        <div class="row">
+          <div class="col-12 p-0">
+            <form>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'SHORTNAME' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'SHORTNAME' | translate }}" name="shortName"
+                    [(ngModel)]="intvlInfo.shortName">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'NAME' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'NAME' | translate }}" name="name"
+                    [(ngModel)]="intvlInfo.name">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'TYPE' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'TYPE' | translate }}" name="type"
+                    [(ngModel)]="intvlInfo.type">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'IPPROFILEREF' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'IP Profile Ref' | translate }}"
+                    name="ipProfileRef" [(ngModel)]="intvlInfo.ipProfileRef">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'ID' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'ID' | translate }}" name="id"
+                    [(ngModel)]="intvlInfo.id">
+                </div>
+              </div>
+              <button type="button" class="btn btn-primary btn-sm pull-right" (click)="saveIntVL(intvlInfo.id)" placement="top"
+                ngbTooltip="Save">
+                <i class="fas fa-save"></i> {{'SAVE' | translate}}
+              </button>
+            </form>
+          </div>
+        </div>
+      </div>
+      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="showRightSideInfo === 'cpInfo'">
+        <div class="row">
+          <div class="col-12 p-0">
+            <form>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'TYPE' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'TYPE' | translate }}" name="type"
+                    [(ngModel)]="cpInfo.type">
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'NAME' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" placeholder="{{ 'NAME' | translate }}" name="name"
+                    [(ngModel)]="cpInfo.name">
+                </div>
+              </div>
+              <button type="button" class="btn btn-primary btn-sm pull-right" (click)="saveCP(cpInfo.name)" placement="top"
+                ngbTooltip="Save">
+                <i class="fas fa-save"></i> {{'SAVE' | translate}}
+              </button>
+            </form>
+          </div>
+        </div>
+      </div>
+      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2" *ngIf="showRightSideInfo === 'intcpInfo'">
+        <div class="row">
+          <div class="col-12 p-0">
+            <form>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'SHORTNAME' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" name="shortName" [(ngModel)]="intcpInfo.shortName" disabled>
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'TYPE' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" name="type" [(ngModel)]="intcpInfo.type" disabled>
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'ID' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" name="id" [(ngModel)]="intcpInfo.id" disabled>
+                </div>
+              </div>
+              <div class="form-group row">
+                <label class="col-sm-4 col-form-label">{{ 'NAME' | translate }}</label>
+                <div class="col-sm-8">
+                  <input type="text" class="form-control" name="name" [(ngModel)]="intcpInfo.name" disabled>
+                </div>
+              </div>
+            </form>
+          </div>
+        </div>
+      </div>
+    </div>
+  </ng-sidebar>
+  <!-- Page content -->
+  <div ng-sidebar-content>
+    <button (click)="toggleSidebar()" class="btn btn-default" placement="right" ngbTooltip="{{'OPEN' | translate }}">
+      <i class="fa fa-arrow-right detail-sidebar" aria-hidden="true"></i>
+    </button>
+  </div>
+</ng-sidebar-container>
+<div class="container-fluid text-dark">
+  <div class="row bg-white vnf-composer-form">
+    <div class="col-xs-3 col-sm-3 col-md-3 col-lg-3 pl-0 px-0">
+      <div class="row">
+        <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 mb-2">
+          <fieldset class="p-2">
+            <legend class="element-legend">
+              {{'PAGE.TOPOLOGY.SELECTELEMENT' | translate}}
+            </legend>
+            <ul class="list-group list-group-flush dragable">
+              <li class="list-group-item" draggable="true" (dragstart)="drag($event)" id="vdu">
+                <img src="assets/images/VDU.svg" class="vnf-svg" draggable="false"/>
+                &nbsp;<span class="span-overflow-text font-weight-bold">{{'PAGE.TOPOLOGY.VDU' | translate}}</span>
+                <span class="drag-icon pull-right"><i class="fas fa-arrows-alt"></i></span>
+              </li>
+              <li class="list-group-item" draggable="true" (dragstart)="drag($event)" id="cp">
+                <img src="assets/images/CP-VNF.svg" class="vnf-svg" draggable="false"/>
+                &nbsp;<span class="span-overflow-text font-weight-bold">{{'PAGE.TOPOLOGY.CP' | translate}}</span>
+                <span class="drag-icon pull-right"><i class="fas fa-arrows-alt"></i></span>
+              </li>
+              <li class="list-group-item" draggable="true" (dragstart)="drag($event)" id="intvl">
+                <img src="assets/images/INTVL.svg" class="vnf-svg" draggable="false"/>
+                &nbsp;<span class="span-overflow-text font-weight-bold">{{'PAGE.TOPOLOGY.INTVL' | translate}}</span>
+                <span class="drag-icon pull-right"><i class="fas fa-arrows-alt"></i></span>
+              </li>
+            </ul>
+          </fieldset>
+        </div>
+      </div>
+    </div>
+    <div class="col-xs-9 col-sm-9 col-md-9 col-lg-9">
+      <div class="row">
+        <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 pl-0">
+          <div class="btn-group list" role="group" aria-label="Basic example">
+            <button type="button" class="btn btn-primary topology-btn" (click)="onFreeze()"
+              [class.pinned]="classApplied" placement="top" container="body" ngbTooltip="{{(classApplied ? 'UNFREEZE' : 'FREEZE') | translate}}">
+              <i class="fas fa-thumbtack"></i>
+            </button>
+            <button type="button" class="btn btn-primary topology-btn" (click)="onEdit()" placement="top"
+              container="body" ngbTooltip="{{'EDIT' | translate}}">
+              <i class="fas fa-edit"></i>
+            </button>
+            <button type="button" class="btn btn-primary topology-btn" (click)="showInfo()" placement="top"
+              container="body" ngbTooltip="{{'PAGE.TOPOLOGY.HELP' | translate}}">
+              <i class="fas fa-info"></i>
+            </button>
+          </div>
+        </div>
+        <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 text-right pr-0 badgegroup">
+          <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+            <img src="assets/images/VDU.svg" class="vnf-svg" draggable="false"/>
+            <br>{{'PAGE.TOPOLOGY.VDU' | translate}}</span>
+          <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+            <img src="assets/images/CP-VNF.svg" class="vnf-svg" draggable="false"/>
+            <br>{{'PAGE.TOPOLOGY.CP' | translate}}</span>
+          <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+            <img src="assets/images/INTVL.svg" class="vnf-svg" draggable="false"/>
+            <br>{{'PAGE.TOPOLOGY.INTVL' | translate}}</span>
+          <span class="badge badge-primary badge-pill bg-white text-body font-weight-bold">
+            <img src="assets/images/INTCP.svg" class="vnf-svg" draggable="false"/>
+            <br>{{'PAGE.TOPOLOGY.INTCP' | translate}}</span>
+        </div>
+      </div>
+      <div class="row border-all">
+        <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 svg-container">
+          <svg preserveAspectRatio="xMidYMin slice" (drop)="drop($event)" (dragover)="allowDrop($event)"
+            id="graphContainer" #graphContainer>
+          </svg>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.scss b/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.scss
new file mode 100644 (file)
index 0000000..4473c67
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.ts b/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.ts
new file mode 100644 (file)
index 0000000..21aad71
--- /dev/null
@@ -0,0 +1,1020 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file VNFComposerComponent
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, GETAPIURLHEADER, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { ConfirmationTopologyComponent } from 'ConfirmationTopology';
+import * as d3 from 'd3';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import * as HttpStatus from 'http-status-codes';
+import * as jsyaml from 'js-yaml';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+import {
+  COMPOSERNODES, CONNECTIONPOINT, GRAPHDETAILS, InternalVLD, Tick, TickPath,
+  VDU, VDUInternalConnectionPoint, VLDInternalConnectionPoint, VNFDInterface, VNFDNODE
+} from 'VNFDModel';
+
+/**
+ * Creating component
+ * @Component takes VNFComposerComponent.html as template url
+ */
+@Component({
+  templateUrl: './VNFComposerComponent.html',
+  styleUrls: ['./VNFComposerComponent.scss'],
+  encapsulation: ViewEncapsulation.None
+})
+/** Exporting a class @exports VNFComposerComponent */
+export class VNFComposerComponent {
+  /** To inject services @public */
+  public injector: Injector;
+  /** View child contains graphContainer ref @public  */
+  @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef;
+  /** dataService to pass the data from one component to another @public */
+  public dataService: DataService;
+  /** random number count @public */
+  public randomNumberLength: number;
+  /** Contains the vnfd information @public */
+  public vnfList: string[] = [];
+  /** Contains node type @public */
+  public nodeTypeRef: string;
+  /** Contains VNFD Information @public */
+  public vnfdInfo: VNFDNODE = { shortName: '', description: '', version: '', id: '', name: '' };
+  /** Contains right panel box information @public */
+  public showRightSideInfo: string = '';
+  /** Add the fixed class for the freeze @public */
+  public fixedClass: string = 'fixed';
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = true;
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+  /** Assign the forcesimulation active @public */
+  public forceSimulationActive: boolean = false;
+  /** Assign pinned class for the button when freezed @public */
+  public classApplied: boolean = false;
+  /** Contains sidebar open status @public */
+  public sideBarOpened: boolean = false;
+
+  /** Contains SVG attributes @private */
+  // tslint:disable-next-line:no-any
+  private svg: any;
+  /** Contains forced node animations @private */
+  // tslint:disable-next-line:no-any
+  private force: any;
+  /** Contains the Drag line */
+  // tslint:disable-next-line: no-any
+  private dragLine: any;
+  /** Contains id of the node @private */
+  private identifier: string;
+  /** Contains path information of the node */
+  // tslint:disable-next-line:no-any
+  private path: any;
+  /** Contains node network @private */
+  // tslint:disable-next-line:no-any
+  private network: any;
+  /** Contains node network @private */
+  // tslint:disable-next-line:no-any
+  private virutualDeploymentUnit: any;
+  /** Contains node connectionPoint @private */
+  // tslint:disable-next-line:no-any
+  private connectionPoint: any;
+  /** Contains node intConnectionPoint @private */
+  // tslint:disable-next-line:no-any
+  private intConnectionPoint: any;
+  /** Contains the node information @private */
+  private nodes: VNFDNODE[] = [];
+  /** Contains the link information of nodes @private */
+  private links: {}[] = [];
+  /** Instance of the rest service @private */
+  private restService: RestService;
+  /** Service holds the router information @private */
+  private router: Router;
+  /** Service contails all the shared service information @private */
+  private sharedService: SharedService;
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private activatedRoute: ActivatedRoute;
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+  /** Rendered nodes represent network @private */
+  // tslint:disable-next-line:no-any
+  private gNetwork: any;
+  /** Rendered nodes represent VDU @private */
+  // tslint:disable-next-line:no-any
+  private gVirutualDeploymentUnit: any;
+  /** Rendered nodes represent connection point @private */
+  // tslint:disable-next-line:no-any
+  private gConnectionPoint: any;
+  /** Rendered nodes represent internal connection point @private */
+  // tslint:disable-next-line:no-any
+  private gIntConnectionPoint: any;
+  /** Contains all the information about VNF Details @private */
+  private vnfdPackageDetails: VNFDNODE;
+  /** Conatins mousedown action @private */
+  private mousedownNode: COMPOSERNODES = null;
+  /** Conatins mouseup action @private */
+  private mouseupNode: COMPOSERNODES = null;
+  /** Conatins current Selection node action @private */
+  private currentSelectedNode: COMPOSERNODES = null;
+  /** Add the activeNode for the selected @private */
+  private activeNode: string = 'active';
+  /** Contains lastkeypressed instance @private */
+  private lastKeyDown: number = -1;
+  /** Contains VDU Information @private */
+  private vduInfo: VDU;
+  /** Contains Internal VL Information @private */
+  private intvlInfo: InternalVLD;
+  /** Contains Connection Point Information @private */
+  private cpInfo: CONNECTIONPOINT;
+  /** Contains Internal Connection Point Information @private */
+  private intcpInfo: VLDInternalConnectionPoint;
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.dataService = this.injector.get(DataService);
+    this.router = this.injector.get(Router);
+    this.activatedRoute = this.injector.get(ActivatedRoute);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+    this.modalService = this.injector.get(NgbModal);
+  }
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    // tslint:disable-next-line:no-backbone-get-set-outside-model
+    this.identifier = this.activatedRoute.snapshot.paramMap.get('id');
+    this.generateData();
+    this.headers = new HttpHeaders({
+      'Content-Type': 'application/zip',
+      Accept: 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+  }
+
+  /** Prepare information for node creation of VNFD @public */
+  public generateData(): void {
+    this.nodes = []; this.links = []; this.vnfdPackageDetails = null;
+    this.showRightSideInfo = 'vnfdInfo';
+    const httpOptions: GETAPIURLHEADER = {
+      headers: new HttpHeaders({
+        'Content-Type': 'application/zip',
+        Accept: 'text/plain',
+        'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+      }),
+      responseType: 'text'
+    };
+    this.restService.getResource(environment.VNFPACKAGES_URL + '/' + this.identifier + '/vnfd', httpOptions)
+      .subscribe((vnfdPackageDetails: VNFDNODE) => {
+        try {
+          const getJson: string = jsyaml.load(vnfdPackageDetails.toString(), { json: true });
+          if (getJson.hasOwnProperty('vnfd-catalog')) {
+            this.vnfdPackageDetails = getJson['vnfd-catalog'].vnfd[0];
+          } else if (getJson.hasOwnProperty('vnfd:vnfd-catalog')) {
+            this.vnfdPackageDetails = getJson['vnfd:vnfd-catalog'].vnfd[0];
+          } else if (getJson.hasOwnProperty('vnfd')) {
+            // tslint:disable-next-line: no-string-literal
+            this.vnfdPackageDetails = getJson['vnfd'][0];
+          }
+          this.generateCPPoint(this.vnfdPackageDetails);
+          this.generateVDU(this.vnfdPackageDetails);
+          this.generateInternalVLD(this.vnfdPackageDetails);
+          this.generateInternalCP(this.vnfdPackageDetails);
+          this.generateIntVLCPLinks(this.vnfdPackageDetails);
+          this.generateVDUCPLinks(this.vnfdPackageDetails);
+          this.createNode(this.nodes);
+          this.vnfdInfo.shortName = this.vnfdPackageDetails['short-name'];
+          this.vnfdInfo.description = this.vnfdPackageDetails.description;
+          this.vnfdInfo.version = this.vnfdPackageDetails.version;
+          this.vnfdInfo.id = this.vnfdPackageDetails.id;
+          this.vnfdInfo.name = this.vnfdPackageDetails.name;
+        } catch (e) {
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        }
+        this.isLoadingResults = false;
+      }, (error: ERRORDATA) => {
+        error.error = typeof error.error === 'string' ? jsyaml.load(error.error) : error.error;
+        if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
+          this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
+        } else {
+          this.restService.handleError(error, 'get');
+        }
+        this.isLoadingResults = false;
+        this.showRightSideInfo = '';
+      });
+  }
+  /** Events handles at drag on D3 region @public */
+  // tslint:disable-next-line:no-any
+  public drag(ev: any): void {
+    ev.dataTransfer.setData('text', ev.target.id);
+  }
+  /** Events handles drop at D3 region @public */
+  public drop(ev: DragEvent): void {
+    ev.preventDefault();
+    this.nodeTypeRef = ev.dataTransfer.getData('text');
+    if (this.nodeTypeRef === 'vdu') {
+      this.svg.selectAll('*').remove();
+      this.vduDropCompose();
+    } else if (this.nodeTypeRef === 'cp') {
+      this.svg.selectAll('*').remove();
+      this.cpDropCompose();
+    } else if (this.nodeTypeRef === 'intvl') {
+      this.svg.selectAll('*').remove();
+      this.intvlDropCompose();
+    }
+  }
+  /** Events handles allow drop on D3 region @public */
+  public allowDrop(ev: DragEvent): void {
+    ev.preventDefault();
+  }
+  /** Generate and list CP points @public */
+  public generateCPPoint(vnfdPackageDetails: VNFDNODE): void {
+    if (vnfdPackageDetails['connection-point'] !== undefined) {
+      vnfdPackageDetails['connection-point'].forEach((cp: CONNECTIONPOINT) => {
+        this.nodes.push({ id: cp.name, nodeTypeRef: 'cp', name: cp.name, type: cp.type });
+      });
+    }
+  }
+  /** Generate and list VDU @public */
+  public generateVDU(vnfdPackageDetails: VNFDNODE): void {
+    if (vnfdPackageDetails.vdu !== undefined) {
+      vnfdPackageDetails.vdu.forEach((vdu: VDU) => {
+        this.nodes.push({
+          id: vdu.name, nodeTypeRef: 'vdu', 'cloud-init-file': vdu['cloud-init-file'], count: vdu.count, description: vdu.description,
+          vduID: vdu.id, name: vdu.name, interface: vdu.interface, 'vm-flavor': vdu['vm-flavor']
+        });
+      });
+    }
+  }
+  /** Generate and list Internal VLD @public */
+  public generateInternalVLD(vnfdPackageDetails: VNFDNODE): void {
+    if (vnfdPackageDetails['internal-vld'] !== undefined) {
+      vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => {
+        this.nodes.push({
+          id: internalVLD.name, nodeTypeRef: 'intvl', intVLID: internalVLD.id,
+          'internal-connection-point': internalVLD['internal-connection-point'],
+          'ip-profile-ref': internalVLD['ip-profile-ref'], name: internalVLD.name, 'short-name': internalVLD['short-name'],
+          type: internalVLD.type
+        });
+      });
+    }
+  }
+  /** Generate and list Internal CP @public */
+  public generateInternalCP(vnfdPackageDetails: VNFDNODE): void {
+    if (vnfdPackageDetails.vdu !== undefined) {
+      vnfdPackageDetails.vdu.forEach((intCP: VDUInternalConnectionPoint) => {
+        if (intCP['internal-connection-point'] !== undefined) {
+          intCP['internal-connection-point'].forEach((internalCP: VDUInternalConnectionPoint) => {
+            this.nodes.push({
+              id: internalCP.name, nodeTypeRef: 'intcp', name: internalCP.name,
+              'short-name': internalCP['short-name'], type: internalCP.type
+            });
+          });
+        }
+      });
+    }
+  }
+  /** Generate VDU External and Internal CP Links @public */
+  public generateVDUCPLinks(vnfdPackageDetails: VNFDNODE): void {
+    if (vnfdPackageDetails.vdu !== undefined) {
+      vnfdPackageDetails.vdu.forEach((vdu: VDU) => {
+        const vduLink: string = vdu.name;
+        if (vdu.interface !== undefined) {
+          vdu.interface.forEach((interfaceDetails: VNFDInterface) => {
+            if (interfaceDetails['external-connection-point-ref'] !== undefined) {
+              this.links.push({ source: vduLink, target: interfaceDetails['external-connection-point-ref'] });
+            }
+            if (interfaceDetails['internal-connection-point-ref'] !== undefined) {
+              this.links.push({ source: vduLink, target: interfaceDetails['internal-connection-point-ref'] });
+            }
+          });
+        }
+      });
+    }
+  }
+  /** Generate Network/VLD/Internal VirtualLink, CP Links @public */
+  public generateIntVLCPLinks(vnfdPackageDetails: VNFDNODE): void {
+    if (vnfdPackageDetails['internal-vld'] !== undefined) {
+      vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => {
+        const vldName: string = internalVLD.name;
+        if (internalVLD['internal-connection-point'] !== undefined) {
+          internalVLD['internal-connection-point'].forEach((intCP: VLDInternalConnectionPoint) => {
+            this.links.push({ source: vldName, target: intCP['id-ref'] });
+          });
+        }
+      });
+    }
+  }
+  /** VNFD details can be saved on users inputs @public */
+  public saveVNFD(): void {
+    this.vnfdPackageDetails['short-name'] = this.vnfdInfo.shortName;
+    this.vnfdPackageDetails.description = this.vnfdInfo.description;
+    this.vnfdPackageDetails.version = this.vnfdInfo.version;
+    this.vnfdPackageDetails.id = this.vnfdInfo.id;
+    this.vnfdPackageDetails.name = this.vnfdInfo.name;
+    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+    delete this.vnfdPackageDetails.shortName;
+  }
+  /** VDU details can be saved on users inputs @public */
+  public saveVDU(vduID: string): void {
+    this.vnfdPackageDetails.vdu.forEach((ref: VDU) => {
+      if (ref.id === vduID) {
+        ref.count = this.vduInfo.count;
+        ref.description = this.vduInfo.description;
+        ref.image = this.vduInfo.image;
+        ref.id = this.vduInfo.id;
+        ref.name = this.vduInfo.name;
+      }
+    });
+    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+  }
+  /** IntVL details can be saved on users inputs @public */
+  public saveIntVL(intVLID: string): void {
+    this.vnfdPackageDetails['internal-vld'].forEach((ref: InternalVLD) => {
+      if (ref.id === intVLID) {
+        ref['short-name'] = this.intvlInfo.shortName;
+        ref.name = this.intvlInfo.name;
+        ref.type = this.intvlInfo.type;
+        ref['ip-profile-ref'] = !isNullOrUndefined(this.intvlInfo.ipProfileRef) ? this.intvlInfo.ipProfileRef : '';
+        ref.id = this.intvlInfo.id;
+        delete ref.shortName;
+        delete ref.ipProfileRef;
+      }
+    });
+    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+  }
+  /** IntVL details can be saved on users inputs @public */
+  public saveCP(cpName: string): void {
+    this.vnfdPackageDetails['connection-point'].forEach((ref: CONNECTIONPOINT) => {
+      if (ref.name === cpName) {
+        if (!isNullOrUndefined(this.cpInfo.type)) {
+          ref.type = this.cpInfo.type;
+        }
+        ref.name = this.cpInfo.name;
+      }
+    });
+    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+  }
+  /** Edit topology @public */
+  public onEdit(): void {
+    this.router.navigate(['/packages/vnf/edit/', this.identifier]).catch();
+  }
+  /** Show Info @public */
+  public showInfo(): void {
+    const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
+    modalRef.componentInstance.topologyType = 'Info';
+    modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO');
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        // empty
+      }
+    }).catch();
+  }
+  /** Event to freeze the animation @public */
+  public onFreeze(): void {
+    this.classApplied = !this.classApplied;
+    const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
+    d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
+    if (alreadyFixedIsActive) {
+      this.force.stop();
+    }
+    this.forceSimulationActive = alreadyFixedIsActive;
+    this.nodes.forEach((d: COMPOSERNODES) => {
+      d.fx = (alreadyFixedIsActive) ? null : d.x;
+      d.fy = (alreadyFixedIsActive) ? null : d.y;
+    });
+    if (alreadyFixedIsActive) {
+      this.force.restart();
+    }
+  }
+  /** Events handles when dragended @public */
+  public toggleSidebar(): void {
+    this.sideBarOpened = !this.sideBarOpened;
+    this.deselectAllNodes();
+    this.showRightSideInfo = 'vnfdInfo';
+  }
+  /** Get the default Configuration of containers @private */
+  private getGraphContainerAttr(): GRAPHDETAILS {
+    return {
+      width: 700,
+      height: 400,
+      nodeHeight: 50,
+      nodeWidth: 35,
+      textX: -35,
+      textY: 30,
+      radius: 5,
+      distance: 50,
+      strength: -500,
+      forcex: 2,
+      forcey: 2,
+      sourcePaddingYes: 17,
+      sourcePaddingNo: 12,
+      targetPaddingYes: 4,
+      targetPaddingNo: 3,
+      alphaTarget: 0.3,
+      imageX: -25,
+      imageY: -25,
+      shiftKeyCode: 17
+    };
+  }
+  /** Node is created and render at D3 region @private */
+  private createNode(nodes: VNFDNODE[]): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    d3.selectAll('svg#graphContainer > *').remove();
+    d3.select(window).on('keydown', () => { this.keyDown(); });
+    d3.select(window).on('keyup', () => { this.keyUp(); });
+    this.svg = d3.select('#graphContainer').attr('oncontextmenu', 'return false;').attr('width', graphContainerAttr.width)
+      .attr('height', graphContainerAttr.height).on('mousemove', () => { this.mousemove(); });
+    this.force = d3.forceSimulation()
+      .force('link', d3.forceLink().id((d: TickPath) => d.id).distance(graphContainerAttr.distance))
+      .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
+      .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
+      .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
+      .on('tick', () => { this.tick(); });
+    this.path = this.svg.append('svg:g').selectAll('path');
+    this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0');
+    this.network = this.svg.append('svg:g').selectAll('network');
+    this.virutualDeploymentUnit = this.svg.append('svg:g').selectAll('virutualDeploymentUnit');
+    this.connectionPoint = this.svg.append('svg:g').selectAll('connectionPoint');
+    this.intConnectionPoint = this.svg.append('svg:g').selectAll('intConnectionPoint');
+    this.restart(nodes);
+  }
+  /** Update force layout (called automatically each iteration) @private */
+  private tick(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.path.attr('d', (d: Tick) => {
+      const deltaX: number = d.target.x - d.source.x; const deltaY: number = d.target.y - d.source.y;
+      const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+      const normX: number = deltaX / dist; const normY: number = deltaY / dist;
+      const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
+      const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
+      const sourceX: number = d.source.x + (sourcePadding * normX); const sourceY: number = d.source.y + (sourcePadding * normY);
+      const targetX: number = d.target.x - (targetPadding * normX); const targetY: number = d.target.y - (targetPadding * normY);
+      return `M${sourceX},${sourceY}L${targetX},${targetY}`;
+    }).on('dblclick', (d: Tick) => { this.getDeleteLinkConfirmation(d); });
+    this.network.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`);
+    this.virutualDeploymentUnit.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`);
+    this.connectionPoint.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`);
+    this.intConnectionPoint.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`);
+  }
+  /** Update graph (called when needed) @private */
+  private restart(nodes: VNFDNODE[]): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.path = this.path.data(this.links);
+    const cpNodes: {}[] = []; const vduNodes: {}[] = []; const vlNodes: {}[] = []; const intcpNodes: {}[] = []; //Nodes are known by id
+    nodes.forEach((nodeList: VNFDNODE) => {
+      if (nodeList.nodeTypeRef === 'cp') { cpNodes.push(nodeList); }
+      else if (nodeList.nodeTypeRef === 'vdu') { vduNodes.push(nodeList); }
+      else if (nodeList.nodeTypeRef === 'intvl') { vlNodes.push(nodeList); }
+      else if (nodeList.nodeTypeRef === 'intcp') { intcpNodes.push(nodeList); }
+    });
+    this.network = this.network.data(vlNodes, (d: { id: number }) => d.id);
+    this.virutualDeploymentUnit = this.virutualDeploymentUnit.data(vduNodes, (d: { id: number }) => d.id);
+    this.connectionPoint = this.connectionPoint.data(cpNodes, (d: { id: number }) => d.id);
+    this.intConnectionPoint = this.intConnectionPoint.data(intcpNodes, (d: { id: number }) => d.id);
+    this.resetAndCreateNodes();
+    this.force.nodes(nodes).force('link').links(this.links); //Set the graph in motion
+    this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
+  }
+  /** Rest and create nodes @private */
+  private resetAndCreateNodes(): void {
+    this.path.exit().remove();
+    this.network.exit().remove();
+    this.virutualDeploymentUnit.exit().remove();
+    this.connectionPoint.exit().remove();
+    this.intConnectionPoint.exit().remove();
+    this.getPathNodes();
+    this.getgNetwork();
+    this.getgVirutualDeploymentUnit();
+    this.getgConnectionPoint();
+    this.getgIntConnectionPoint();
+    this.network = this.gNetwork.merge(this.network);
+    this.virutualDeploymentUnit = this.gVirutualDeploymentUnit.merge(this.virutualDeploymentUnit);
+    this.connectionPoint = this.gConnectionPoint.merge(this.connectionPoint);
+    this.intConnectionPoint = this.gIntConnectionPoint.merge(this.intConnectionPoint);
+    this.path.merge(this.path);
+  }
+  /** Setting the Path @private */
+  private getPathNodes(): void {
+    this.path = this.path.enter().append('svg:path').attr('class', 'link');
+  }
+  /** Settings all the network attributes of nodes @private */
+  private getgNetwork(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gNetwork = this.network.enter().append('svg:g');
+    this.gNetwork.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gNetwork.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('id', (d: VNFDNODE) => { return d.id; })
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/INTVL.svg')
+      .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); })
+      .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); })
+      .on('click', (d: VNFDNODE) => { this.singleClick(this.network, d); this.onNodeClickToggleSidebar(); })
+      .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
+    this.gNetwork.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: { id: number }) => d.id);
+  }
+  /** Settings all the connection point attributes of nodes @private */
+  private getgVirutualDeploymentUnit(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gVirutualDeploymentUnit = this.virutualDeploymentUnit.enter().append('svg:g');
+    this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gVirutualDeploymentUnit.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('id', (d: VNFDNODE) => { return d.id; })
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/VDU.svg')
+      .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); })
+      .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); })
+      .on('click', (d: VNFDNODE) => { this.singleClick(this.virutualDeploymentUnit, d); this.onNodeClickToggleSidebar(); })
+      .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
+    this.gVirutualDeploymentUnit.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: { id: string }) => d.id);
+  }
+  /** Settings all the connection point attributes of nodes @private */
+  private getgConnectionPoint(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gConnectionPoint = this.connectionPoint.enter().append('svg:g');
+    this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gConnectionPoint.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('id', (d: VNFDNODE) => { return d.id; })
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/CP-VNF.svg')
+      .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); })
+      .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); })
+      .on('click', (d: VNFDNODE) => { this.singleClick(this.connectionPoint, d); this.onNodeClickToggleSidebar(); })
+      .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
+    this.gConnectionPoint.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: { id: string }) => d.id);
+  }
+  /** Settings all the internal connection point attributes of nodes @private */
+  private getgIntConnectionPoint(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.gIntConnectionPoint = this.intConnectionPoint.enter().append('svg:g');
+    this.gIntConnectionPoint.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
+    this.gIntConnectionPoint.append('svg:image')
+      .style('opacity', 1)
+      .attr('x', graphContainerAttr.imageX)
+      .attr('y', graphContainerAttr.imageY)
+      .attr('id', (d: VNFDNODE) => { return d.id; })
+      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
+      .attr('xlink:href', 'assets/images/INTCP.svg')
+      .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); })
+      .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); })
+      .on('click', (d: VNFDNODE) => { this.singleClick(this.intConnectionPoint, d); this.onNodeClickToggleSidebar(); })
+      .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
+    this.gIntConnectionPoint.append('svg:text')
+      .attr('class', 'node_text')
+      .attr('y', graphContainerAttr.textY)
+      .text((d: { id: string }) => d.id);
+  }
+  /** Drop VDU Composer Data @private */
+  private vduDropCompose(): void {
+    const randomID: string = this.sharedService.randomString();
+    const vduNode: VNFDNODE[] = [{
+      nodeTypeRef: 'vdu', id: 'vdu_' + randomID, count: 1, description: '', name: 'vdu_' + randomID, image: 'ubuntu',
+      interface: [], 'internal-connection-point': [], 'monitoring-param': [], 'vm-flavor': {}
+    }];
+    const nodeCopy: VNFDNODE[] = this.nodes;
+    Array.prototype.push.apply(vduNode, nodeCopy);
+    this.nodes = vduNode;
+    if (this.vnfdPackageDetails.vdu === undefined) { this.vnfdPackageDetails.vdu = []; }
+    this.vnfdPackageDetails.vdu.push({
+      id: 'vdu_' + randomID, count: 1, description: '', name: 'vdu_' + randomID, image: 'ubuntu',
+      interface: [], 'internal-connection-point': [], 'monitoring-param': [], 'vm-flavor': {}
+    });
+    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+  }
+  /** Drop CP Composer Data @private */
+  private cpDropCompose(): void {
+    const randomID: string = this.sharedService.randomString();
+    const cpNode: VNFDNODE[] = [{ nodeTypeRef: 'cp', id: 'cp_' + randomID, name: 'cp_' + randomID }];
+    const nodeCopy: VNFDNODE[] = this.nodes;
+    Array.prototype.push.apply(cpNode, nodeCopy);
+    this.nodes = cpNode;
+    if (this.vnfdPackageDetails['connection-point'] === undefined) {
+      this.vnfdPackageDetails['connection-point'] = [];
+    }
+    this.vnfdPackageDetails['connection-point'].push({
+      id: 'cp_' + randomID, name: 'cp_' + randomID, type: 'VPORT'
+    });
+    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+  }
+  /** Drop IntVL Composer Data @private */
+  private intvlDropCompose(): void {
+    const randomID: string = this.sharedService.randomString();
+    const intvlNode: VNFDNODE[] = [{
+      nodeTypeRef: 'intvl', id: 'vnf_vl_' + randomID, name: 'vnf_vl_' + randomID, 'short-name': 'vnf_vl_' + randomID, 'ip-profile-ref': '',
+      type: 'ELAN'
+    }];
+    const nodeCopy: VNFDNODE[] = this.nodes;
+    Array.prototype.push.apply(intvlNode, nodeCopy);
+    this.nodes = intvlNode;
+    if (this.vnfdPackageDetails['internal-vld'] === undefined) { this.vnfdPackageDetails['internal-vld'] = []; }
+    this.vnfdPackageDetails['internal-vld'].push({
+      id: 'vnf_vl_' + randomID, name: 'vnf_vl_' + randomID, 'short-name': 'vnf_vl_' + randomID,
+      'ip-profile-ref': '', type: 'ELAN', 'internal-connection-point': []
+    });
+    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+  }
+  /** Add the Add Nodes Data @private */
+  private addNodes(apiURL: string, identifier: string, data: VNFDNODE): void {
+    this.isLoadingResults = true;
+    const apiURLHeader: APIURLHEADER = {
+      url: apiURL + '/' + identifier + '/package_content',
+      httpOptions: { headers: this.headers }
+    };
+    const vnfData: {} = {};
+    vnfData['vnfd:vnfd-catalog'] = {};
+    vnfData['vnfd:vnfd-catalog'].vnfd = [];
+    vnfData['vnfd:vnfd-catalog'].vnfd.push(data);
+    const descriptorInfo: string = jsyaml.dump(vnfData, { sortKeys: true });
+    this.sharedService.targzFile({ packageType: 'vnfd', id: this.identifier, descriptor: descriptorInfo })
+      .then((content: ArrayBuffer): void => {
+        this.restService.putResource(apiURLHeader, content).subscribe((res: {}) => {
+          this.generateData();
+          this.notifierService.notify('success', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.UPDATEDSUCCESSFULLY'));
+          this.isLoadingResults = false;
+        }, (error: ERRORDATA) => {
+          this.generateData();
+          this.restService.handleError(error, 'put');
+          this.isLoadingResults = false;
+        });
+      }).catch((): void => {
+        this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        this.isLoadingResults = false;
+      });
+  }
+  /** Events handles when mousedown click it will capture the selected node data @private */
+  private mouseDown(d: VNFDNODE): void {
+    event.preventDefault();
+    if (d3.event.ctrlKey) { return; }
+    if (d3.event.shiftKey) {
+      this.mousedownNode = d;
+      this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode;
+      this.dragLine.classed('hidden', false)
+        .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`);
+    }
+  }
+  /** Event handles when mouseup event occures @private */
+  private mouseUp(d: VNFDNODE): void {
+    if (!this.mousedownNode) { return; }
+    this.dragLine.classed('hidden', true);
+    this.mouseupNode = d;
+    if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'intcp') {
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDINTCP'));
+      this.deselectPath();
+    }
+    else if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'vdu') {
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDVDU'));
+      this.deselectPath();
+    }
+    else if (this.mousedownNode.nodeTypeRef === 'intcp' && this.mouseupNode.nodeTypeRef === 'vdu') {
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDVDU'));
+      this.deselectPath();
+    }
+    else if (this.mousedownNode.nodeTypeRef === 'cp' && this.mouseupNode.nodeTypeRef === 'intvl') {
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDVNFVL'));
+      this.deselectPath();
+    }
+    else if (this.mousedownNode.nodeTypeRef === 'intvl' && this.mouseupNode.nodeTypeRef === 'cp') {
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDCP'));
+      this.deselectPath();
+    }
+    else if (this.mousedownNode.nodeTypeRef === 'intcp' && this.mouseupNode.nodeTypeRef === 'cp') {
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDCP'));
+      this.deselectPath();
+    }
+    else if (this.mousedownNode.nodeTypeRef === 'cp' && this.mouseupNode.nodeTypeRef === 'intcp') {
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDINTCP'));
+      this.deselectPath();
+    } else if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'cp') {
+      this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => {
+        if (vduDetails.id === this.mousedownNode.id) {
+          if (vduDetails.interface === undefined) { vduDetails.interface = []; }
+          vduDetails.interface.push({
+            'external-connection-point-ref': this.mouseupNode.id, 'mgmt-interface': true,
+            name: 'eth_' + this.sharedService.randomString(),
+            'virtual-interface': { type: 'VIRTIO' },
+            type: 'EXTERNAL'
+          });
+          if (vduDetails['internal-connection-point'] === undefined) {
+            vduDetails['internal-connection-point'] = [];
+          }
+          if (vduDetails['monitoring-param'] === undefined) {
+            vduDetails['monitoring-param'] = [];
+          }
+          if (vduDetails['vm-flavor'] === undefined) {
+            vduDetails['vm-flavor'] = {};
+          }
+        }
+      });
+      this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+      this.deselectPath();
+    } else if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'intvl') {
+      const setIntCP: string = 'intcp_' + this.sharedService.randomString();
+      this.vnfdPackageDetails['internal-vld'].forEach((vldInternal: InternalVLD) => {
+        if (vldInternal.id === this.mouseupNode.id) {
+          if (vldInternal['internal-connection-point'] === undefined) { vldInternal['internal-connection-point'] = []; }
+          vldInternal['internal-connection-point'].push({ 'id-ref': setIntCP });
+        }
+      });
+      this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => {
+        if (vduDetails.id === this.mousedownNode.id) {
+          if (vduDetails.interface === undefined) {
+            vduDetails.interface = [];
+          }
+          vduDetails.interface.push({
+            'internal-connection-point-ref': setIntCP, name: 'int_' + setIntCP, type: 'INTERNAL', 'virtual-interface': { type: 'VIRTIO' }
+          });
+          if (vduDetails['internal-connection-point'] === undefined) {
+            vduDetails['internal-connection-point'] = [];
+          }
+          vduDetails['internal-connection-point'].push({
+            id: setIntCP, name: setIntCP, 'short-name': setIntCP, type: 'VPORT'
+          });
+        }
+      });
+      this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+      this.deselectPath();
+    }
+    else {
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION'));
+      this.deselectPath();
+    }
+    this.resetMouseActions();
+    this.currentSelectedNode = null;
+  }
+  /** Events handles when mousemove it will capture the selected node data @private */
+  private mousemove(): void {
+    if (!this.mousedownNode) { return; }
+    this.dragLine.attr('d',
+      `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`);
+  }
+  /** reset Mouse varaibles @private */
+  private resetMouseActions(): void {
+    this.mousedownNode = null;
+    this.mouseupNode = null;
+  }
+  /** Key press event @private */
+  private keyDown(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    if (this.lastKeyDown !== -1) { return; }
+    this.lastKeyDown = d3.event.keyCode;
+    if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
+      this.gNetwork.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended));
+      this.gVirutualDeploymentUnit.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended));
+      this.gConnectionPoint.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended));
+      this.gIntConnectionPoint.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended));
+      this.svg.classed('ctrl', true);
+    }
+  }
+  /** Key realse event @private */
+  private keyUp(): void {
+    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
+    this.lastKeyDown = -1;
+    if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
+      this.gNetwork.on('.drag', null);
+      this.gVirutualDeploymentUnit.on('.drag', null);
+      this.gConnectionPoint.on('.drag', null);
+      this.gIntConnectionPoint.on('.drag', null);
+      this.svg.classed('ctrl', false);
+    }
+  }
+  /** Mosue Drag Line false if it is not satisfied @private */
+  private deselectPath(): void {
+    this.dragLine.classed('hidden', true).attr('d', 'M0,0L0,0');
+  }
+  /** Events handles when Shift Click to perform create cp @private */
+  // tslint:disable-next-line: no-any
+  private singleClick(nodeSelected: any, d: VNFDNODE): void {
+    this.selectedNode(nodeSelected, d);
+  }
+  /** Get confirmation Before Deleting the Node in Topology @private */
+  private getDeleteNodeConfirmation(d: VNFDNODE): void {
+    const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
+    modalRef.componentInstance.topologyType = 'Delete';
+    modalRef.componentInstance.topologyname = d.name;
+    if (d.nodeTypeRef === 'vdu') {
+      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VDU';
+    } else if (d.nodeTypeRef === 'intvl') {
+      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTVL';
+    } else if (d.nodeTypeRef === 'cp') {
+      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT';
+    } else if (d.nodeTypeRef === 'intcp') {
+      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTCP';
+    }
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.deleteNode(d);
+      }
+    }).catch();
+  }
+  /** Delete nodes @private */
+  private deleteNode(d: VNFDNODE): void {
+    const deletedNode: VNFDNODE = d;
+    this.nodes.forEach((node: VNFDNODE) => {
+      if (node.id === d.id) {
+        if (deletedNode.nodeTypeRef === 'cp') {
+          if (this.vnfdPackageDetails.vdu !== undefined) {
+            this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => {
+              if (vduDetails.interface !== undefined) {
+                const interfacePos: number = vduDetails.interface.map((e: VNFDInterface) => { return e['external-connection-point-ref']; })
+                  .indexOf(d.id);
+                if (interfacePos >= 0) {
+                  vduDetails.interface.splice(interfacePos, 1);
+                }
+              }
+            });
+          }
+          const cpPos: number = this.vnfdPackageDetails['connection-point'].map((e: CONNECTIONPOINT) => { return e.name; })
+            .indexOf(d.id);
+          if (cpPos >= 0) {
+            this.vnfdPackageDetails['connection-point'].splice(cpPos, 1);
+          }
+        } else if (deletedNode.nodeTypeRef === 'intcp') {
+          this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => {
+            // Delete Interface
+            const interfacePos: number = vduDetails.interface.map((e: VNFDInterface) => { return e['internal-connection-point-ref']; })
+              .indexOf(d.id);
+            if (interfacePos >= 0) {
+              vduDetails.interface.splice(interfacePos, 1);
+            }
+            // Delete Internal CP
+            const interCPPos: number = vduDetails['internal-connection-point']
+              .map((e: VDUInternalConnectionPoint) => { return e.id; })
+              .indexOf(d.id);
+            if (interCPPos >= 0) {
+              vduDetails['internal-connection-point'].splice(interCPPos, 1);
+            }
+          });
+          if (this.vnfdPackageDetails['internal-vld'] !== undefined && this.vnfdPackageDetails['internal-vld'].length > 0) {
+            this.vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => {
+              const interfacePos: number = internalVLD['internal-connection-point']
+                .map((e: VLDInternalConnectionPoint) => { return e['id-ref']; }).indexOf(d.id);
+              if (interfacePos >= 0) {
+                internalVLD['internal-connection-point'].splice(interfacePos, 1);
+              }
+            });
+          }
+        } else if (deletedNode.nodeTypeRef === 'intvl') {
+          const intvlPos: number = this.vnfdPackageDetails['internal-vld']
+            .map((e: InternalVLD) => { return e.name; }).indexOf(d.id);
+          if (intvlPos >= 0) {
+            this.vnfdPackageDetails['internal-vld'].splice(intvlPos, 1);
+          }
+        } else if (deletedNode.nodeTypeRef === 'vdu') {
+          const internalCPList: string[] = [];
+          if (deletedNode.interface !== undefined && deletedNode.interface.length > 0) {
+            deletedNode.interface.forEach((interfaceNode: InternalVLD) => {
+              if (interfaceNode['internal-connection-point-ref'] !== undefined) {
+                internalCPList.push(interfaceNode['internal-connection-point-ref']);
+              }
+            });
+          }
+          internalCPList.forEach((list: string) => {
+            if (this.vnfdPackageDetails['internal-vld'] !== undefined && this.vnfdPackageDetails['internal-vld'].length > 0) {
+              this.vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => {
+                const interfacePos: number = internalVLD['internal-connection-point']
+                  .map((e: VLDInternalConnectionPoint) => { return e['id-ref']; }).indexOf(list);
+                if (interfacePos >= 0) {
+                  internalVLD['internal-connection-point'].splice(interfacePos, 1);
+                }
+              });
+            }
+          });
+          const vduPos: number = this.vnfdPackageDetails.vdu.map((e: VDU) => { return e.id; }).indexOf(d.id);
+          if (vduPos >= 0) {
+            this.vnfdPackageDetails.vdu.splice(vduPos, 1);
+          }
+        } else {
+          this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION'));
+        }
+        this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
+      }
+    });
+  }
+  /** Get confirmation before deleting the ink in Topology @private */
+  private getDeleteLinkConfirmation(d: Tick): void {
+    this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.YOUCANNOTDELETELINK'));
+  }
+  /** Selected nodes @private */
+  // tslint:disable-next-line: no-any
+  private selectedNode(nodeSeleced: any, d: VNFDNODE): void {
+    const alreadyIsActive: boolean = nodeSeleced.select('#' + d.id).classed(this.activeNode);
+    this.deselectAllNodes();
+    nodeSeleced.select('#' + d.id).classed(this.activeNode, !alreadyIsActive);
+    if (d.nodeTypeRef === 'vdu' && !alreadyIsActive) {
+      this.vnfdPackageDetails.vdu.forEach((res: VDU) => {
+        if (res.name === d.id) {
+          this.showRightSideInfo = 'vduInfo';
+          this.vduInfo = res;
+        }
+      });
+    } else if (d.nodeTypeRef === 'intvl' && !alreadyIsActive) {
+      this.vnfdPackageDetails['internal-vld'].forEach((res: InternalVLD) => {
+        if (res.name === d.id) {
+          this.showRightSideInfo = 'intvlInfo';
+          this.intvlInfo = res;
+          this.intvlInfo.shortName = res['short-name'];
+          this.intvlInfo.ipProfileRef = res['ip-profile-ref'];
+        }
+      });
+    } else if (d.nodeTypeRef === 'cp' && !alreadyIsActive) {
+      this.vnfdPackageDetails['connection-point'].forEach((res: CONNECTIONPOINT) => {
+        if (res.name === d.id) {
+          this.showRightSideInfo = 'cpInfo';
+          this.cpInfo = res;
+        }
+      });
+    }
+    else if (d.nodeTypeRef === 'intcp' && !alreadyIsActive) {
+      this.intcpInfo = d;
+      this.showRightSideInfo = 'intcpInfo';
+      this.intcpInfo.shortName = d['short-name'];
+    } else {
+      this.showRightSideInfo = 'vnfdInfo';
+    }
+  }
+  /** De-select all the selected nodes @private */
+  private deselectAllNodes(): void {
+    this.network.select('image').classed(this.activeNode, false);
+    this.virutualDeploymentUnit.select('image').classed(this.activeNode, false);
+    this.connectionPoint.select('image').classed(this.activeNode, false);
+    this.intConnectionPoint.select('image').classed(this.activeNode, false);
+  }
+  /** Events handles when dragstarted @private */
+  private dragstarted(d: COMPOSERNODES): void {
+    d.fx = d.x;
+    d.fy = d.y;
+  }
+  /** Events handles when dragged @private */
+  private dragged(d: COMPOSERNODES): void {
+    d.fx = d.x = d3.event.x;
+    d.fy = d.y = d3.event.y;
+  }
+  /** Events handles when dragended @private */
+  private dragended(d: COMPOSERNODES): void {
+    if (this.forceSimulationActive) {
+      d.fx = null;
+      d.fy = null;
+    } else {
+      d.fx = d.x;
+      d.fy = d.y;
+      this.forceSimulationActive = false;
+    }
+  }
+  /** Events handles when node double click   @private */
+  private onNodedblClickToggleSidebar(): void {
+    this.sideBarOpened = false;
+  }
+  /** Events handles when node single click   @private */
+  private onNodeClickToggleSidebar(): void {
+    this.sideBarOpened = true;
+  }
+}
diff --git a/src/app/packages/show-content/ShowContentComponent.html b/src/app/packages/show-content/ShowContentComponent.html
new file mode 100644 (file)
index 0000000..dbb0935
--- /dev/null
@@ -0,0 +1,44 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="modal-header">
+  <h4 class="modal-title" id="modal-basic-title">{{'FILES' | translate}} {{'IN' | translate}}
+    {{(params.id)?params.id:'-'}}</h4>
+  <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
+    <i class="fas fa-times-circle text-danger"></i>
+  </button>
+</div>
+<div class="modal-body">
+  <table class="table table-bored show-content" *ngIf="contents else noData">
+    <tr>
+      <th># {{'FILES' | translate}} {{'NAME' | translate}}</th>
+      <th>{{'ACTIONS' | translate }}</th>
+    </tr>
+    <tr *ngFor="let data of contents">
+      <td>- {{(data)?data:'-'}}</td>
+      <td>
+        <button class="btn btn-xs">
+          <i class="far fa-folder-open icons"></i>
+        </button>
+      </td>
+    </tr>
+  </table>
+  <ng-template #noData>{{'NODATAERROR' | translate}}</ng-template>
+</div>
+<div class="modal-footer">
+  <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+</div>
\ No newline at end of file
diff --git a/src/app/packages/show-content/ShowContentComponent.scss b/src/app/packages/show-content/ShowContentComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/packages/show-content/ShowContentComponent.ts b/src/app/packages/show-content/ShowContentComponent.ts
new file mode 100644 (file)
index 0000000..e2431e8
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Show content modal
+ */
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { ERRORDATA, URLPARAMS } from 'CommonModel';
+import { environment } from 'environment';
+import { RestService } from 'RestService';
+
+/** Shows json data in the information modal */
+const defaults: {} = { 'text/json': '' };
+
+/**
+ * Creating component
+ * @Component takes ShowContentComponent.html as template url
+ */
+@Component({
+  selector: 'app-show-content',
+  templateUrl: './ShowContentComponent.html',
+  styleUrls: ['./ShowContentComponent.scss']
+})
+/** Exporting a class @exports ShowContentComponent */
+export class ShowContentComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Contains files information @public */
+  public contents: {}[];
+
+  /** Input contains component objects @public */
+  @Input() public params: URLPARAMS;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate @public
+   */
+  public ngOnInit(): void {
+    if (this.params.page === 'nsd') {
+      this.restService.getResource(environment.NSDESCRIPTORS_URL + '/' + this.params.id + '/artifacts/artifactPath')
+        .subscribe((nsd: {}[]) => {
+          this.contents = nsd;
+        }, (error: ERRORDATA) => {
+          this.restService.handleError(error, 'get');
+        });
+    } else if (this.params.page === 'vnfd') {
+      this.restService.getResource(environment.VNFPACKAGES_URL + '/' + this.params.id + '/artifacts/artifactPath')
+        .subscribe((vnfd: {}[]) => {
+          this.contents = vnfd;
+        }, (error: ERRORDATA) => {
+          this.restService.handleError(error, 'get');
+        });
+    }
+  }
+}
diff --git a/src/app/packages/vnf-packages/VNFPackagesComponent.html b/src/app/packages/vnf-packages/VNFPackagesComponent.html
new file mode 100644 (file)
index 0000000..2d7298d
--- /dev/null
@@ -0,0 +1,44 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">VNF {{'PACKAGES' | translate}}</div>
+    <span class="button">
+        <button class="btn btn-primary" type="button" placement="top" container="body" ngbTooltip="{{'PAGE.VNFPACKAGE.ADDVNFPACKAGE' | translate}}"
+            (click)="composeVNFPackage()">
+            <i class="fas fa-plus-circle" aria-hidden="true"></i>&nbsp; {{'PAGE.VNFPACKAGE.ADDVNFPACKAGE' | translate}}
+        </button>
+    </span>
+</div>
+<div class="row">
+    <div class="dropzone mt-2" appDrag (click)="fileInput.click()" (files)="filesDropped($event)">
+        <input hidden type="file" #fileInput (change)="filesDropped($event.target.files)">
+        <div class="text-wrapper">
+            <div class="text-center file-drop-title">
+                <i class="fas fa-upload"></i> {{'DROPFILES' | translate}}</div>
+        </div>
+    </div>
+</div>
+<div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/packages/vnf-packages/VNFPackagesComponent.scss b/src/app/packages/vnf-packages/VNFPackagesComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/packages/vnf-packages/VNFPackagesComponent.ts b/src/app/packages/vnf-packages/VNFPackagesComponent.ts
new file mode 100644 (file)
index 0000000..13707e1
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file VNF Package details Component.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA } from 'CommonModel';
+import { ComposePackages } from 'ComposePackages';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+import { VNFData, VNFDDetails } from 'VNFDModel';
+import { VNFPackagesActionComponent } from 'VNFPackagesAction';
+
+/**
+ * Creating component
+ * @Component takes VNFPackagesComponent.html as template url
+ */
+@Component({
+    selector: 'app-vnf-packages',
+    templateUrl: './VNFPackagesComponent.html',
+    styleUrls: ['./VNFPackagesComponent.scss']
+})
+/** Exporting a class @exports VNFPackagesComponent */
+export class VNFPackagesComponent implements OnInit {
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Data of smarttable populate through LocalDataSource @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** handle translate @public */
+    public translateService: TranslateService;
+
+    /** Columns list of the smart table @public */
+    public columnLists: object = {};
+
+    /** Settings for smarttable to populate the table with columns @public */
+    public settings: object = {};
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+
+    /** Element ref for fileInput @public */
+    @ViewChild('fileInput', { static: true }) public fileInput: ElementRef;
+
+    /** Instance of the rest service @private */
+    private restService: RestService;
+
+    /** dataService to pass the data from one component to another @private */
+    private dataService: DataService;
+
+    /** Formation of appropriate Data for LocalDatasource @private */
+    private vnfData: VNFData[] = [];
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** variables contains file information */
+    private fileData: string | ArrayBuffer;
+
+    /** Controls the header form @private */
+    private headers: HttpHeaders;
+
+    /** Notifier service to popup notification @private */
+    private notifierService: NotifierService;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.sharedService = this.injector.get(SharedService);
+        this.translateService = this.injector.get(TranslateService);
+        this.notifierService = this.injector.get(NotifierService);
+        this.modalService = this.injector.get(NgbModal);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.generateColumns();
+        this.generateSettings();
+        this.generateData();
+        this.headers = new HttpHeaders({
+            'Content-Type': 'application/gzip',
+            Accept: 'application/json',
+            'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+        });
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** smart table Header Colums @public */
+    public generateColumns(): void {
+        this.columnLists = {
+            shortName: { title: this.translateService.instant('SHORTNAME'), width: '15%', sortDirection: 'asc' },
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' },
+            type: {
+                title: this.translateService.instant('TYPE'),
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: [
+                            { value: 'vnfd', title: 'VNF' },
+                            { value: 'pnfd', title: 'PNF' },
+                            { value: 'hnfd', title: 'HNF' }
+                        ]
+                    }
+                },
+                width: '10%'
+            },
+            description: { title: this.translateService.instant('DESCRIPTION'), width: '20%' },
+            vendor: { title: this.translateService.instant('VENDOR'), width: '10%' },
+            version: { title: this.translateService.instant('VERSION'), width: '10%' },
+            Actions: {
+                name: 'Action', width: '15%', filter: false, sort: false, type: 'custom',
+                title: this.translateService.instant('ACTIONS'),
+                valuePrepareFunction: (cell: VNFData, row: VNFData): VNFData => row, renderComponent: VNFPackagesActionComponent
+            }
+        };
+    }
+
+    /** smart table Data Settings @public */
+    public generateSettings(): void {
+        this.settings = {
+            edit: {
+                editButtonContent: '<i class="fa fa-edit" title="Edit"></i>',
+                confirmSave: true
+            },
+            delete: {
+                deleteButtonContent: '<i class="far fa-trash-alt" title="delete"></i>',
+                confirmDelete: true
+            },
+            columns: this.columnLists,
+            actions: {
+                add: false,
+                edit: false,
+                delete: false,
+                position: 'right'
+            },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** smart table listing manipulation @public */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** OnUserRowSelect Function @public */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'vnf-package' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** Drag and drop feature and fetchind the details of files  @public */
+    public filesDropped(files: FileList): void {
+        if (files && files.length === 1) {
+            this.isLoadingResults = true;
+            this.sharedService.getFileString(files, 'gz').then((fileContent: ArrayBuffer): void => {
+                const apiURLHeader: APIURLHEADER = {
+                    url: environment.VNFPACKAGESCONTENT_URL,
+                    httpOptions: { headers: this.headers }
+                };
+                this.saveFileData(apiURLHeader, fileContent);
+            }).catch((err: string): void => {
+                this.isLoadingResults = false;
+                if (err === 'typeError') {
+                    this.notifierService.notify('error', this.translateService.instant('GZFILETYPEERRROR'));
+                } else {
+                    this.notifierService.notify('error', this.translateService.instant('ERROR'));
+                }
+            });
+        } else if (files && files.length > 1) {
+            this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+        }
+    }
+
+    /** Post the droped files and reload the page @public */
+    public saveFileData(urlHeader: APIURLHEADER, fileData: {}): void {
+        this.fileInput.nativeElement.value = null;
+        this.restService.postResource(urlHeader, fileData).subscribe((result: {}) => {
+            this.notifierService.notify('success', this.translateService.instant('PAGE.VNFPACKAGE.CREATEDSUCCESSFULLY'));
+            this.generateData();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'post');
+            this.isLoadingResults = false;
+        });
+    }
+
+    /** Generate nsData object from loop and return for the datasource @public */
+    public generatevnfdData(vnfdpackagedata: VNFDDetails): VNFData {
+        return {
+            shortName: vnfdpackagedata['short-name'],
+            identifier: vnfdpackagedata._id,
+            type: vnfdpackagedata._admin.type,
+            description: vnfdpackagedata.description,
+            vendor: vnfdpackagedata.vendor,
+            version: vnfdpackagedata.version
+        };
+    }
+    /** Handle compose new ns package method  @public */
+    public composeVNFPackage(): void {
+        this.modalService.open(ComposePackages, { backdrop: 'static' }).componentInstance.params = { page: 'vnf-package' };
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+
+    /** Fetching the data from server to Load in the smarttable @protected */
+    protected generateData(): void {
+        this.isLoadingResults = true;
+        this.restService.getResource(environment.VNFPACKAGESCONTENT_URL).subscribe((vnfdPackageData: VNFDDetails[]) => {
+            this.vnfData = [];
+            vnfdPackageData.forEach((vnfdpackagedata: VNFDDetails) => {
+                const vnfDataObj: VNFData = this.generatevnfdData(vnfdpackagedata);
+                this.vnfData.push(vnfDataObj);
+            });
+            if (this.vnfData.length > 0) {
+                this.checkDataClass = 'dataTables_present';
+            } else {
+                this.checkDataClass = 'dataTables_empty';
+            }
+            this.dataSource.load(this.vnfData).then((data: boolean) => {
+                this.isLoadingResults = false;
+            }).catch(() => {
+                this.isLoadingResults = false;
+            });
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+}
diff --git a/src/app/page-not-found/PageNotFoundComponent.html b/src/app/page-not-found/PageNotFoundComponent.html
new file mode 100644 (file)
index 0000000..f546e3d
--- /dev/null
@@ -0,0 +1,27 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="d-flex flex-column align-items-center flex-grow-1 text-dark font-weight-bold page-not-found">
+    <img src="../../assets/images/page-not-found.jpg">
+    <h1>{{'PAGENOTFOUND.OOPS' | translate}}</h1>
+    <span>
+        {{'PAGENOTFOUND.CONTENT' | translate}}
+    </span>
+    <span>
+        {{'PAGENOTFOUND.MEAN' | translate}} <a routerLink="/">{{'PAGE.DASHBOARD.DASHBOARD' | translate}}</a>
+    </span>
+</div>
\ No newline at end of file
diff --git a/src/app/page-not-found/PageNotFoundComponent.scss b/src/app/page-not-found/PageNotFoundComponent.scss
new file mode 100644 (file)
index 0000000..0e81f2b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import "../../assets/scss/mixins/mixin";
+@import "../../assets/scss/variable";
+.page-not-found {
+  @include padding-percentage-value(10rem, 10rem, 10rem, 10rem);
+  .four-not-four {
+    @include font(null, 5rem, bold);
+  }
+  a:hover {
+    color: $primary;
+    text-decoration: underline;
+  }
+}
\ No newline at end of file
diff --git a/src/app/page-not-found/PageNotFoundComponent.ts b/src/app/page-not-found/PageNotFoundComponent.ts
new file mode 100644 (file)
index 0000000..ef515ec
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Page not found component
+ */
+import { Component, OnInit } from '@angular/core';
+
+/**
+ * Creating component
+ * @Component takes PageNotFoundComponent.html as template url
+ */
+@Component({
+    selector: 'app-page-not-found',
+    templateUrl: './PageNotFoundComponent.html',
+    styleUrls: ['./PageNotFoundComponent.scss']
+})
+/** Exporting a class @exports PageNotFoundComponent */
+export class PageNotFoundComponent implements OnInit {
+    constructor() {
+        //donothing
+    }
+
+    public ngOnInit(): void {
+        //donothing
+    }
+
+}
diff --git a/src/app/projects/ProjectsComponent.html b/src/app/projects/ProjectsComponent.html
new file mode 100644 (file)
index 0000000..ec15861
--- /dev/null
@@ -0,0 +1,35 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'PAGE.DASHBOARD.PROJECTS' | translate}}</div>
+    <span class="button">
+        <button class="btn btn-primary" type="button" (click)="projectAdd()" placement="top" container="body" ngbTooltip="{{'PAGE.PROJECT.NEWPROJECT' | translate}}">
+            <i class="fas fa-plus-circle" aria-hidden="true"></i>
+            {{'PAGE.PROJECT.NEWPROJECT' | translate}}
+        </button>
+    </span>
+</div>
+<div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/projects/ProjectsComponent.scss b/src/app/projects/ProjectsComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/projects/ProjectsComponent.ts b/src/app/projects/ProjectsComponent.ts
new file mode 100644 (file)
index 0000000..7524994
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Project details Component.
+ */
+import { Component, Injector, OnDestroy, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { LocalDataSource } from 'ng2-smart-table';
+import { ProjectCreateUpdateComponent } from 'ProjectCreateUpdate';
+import { ProjectLinkComponent } from 'ProjectLinkComponent';
+import { ProjectData, ProjectDetails } from 'ProjectModel';
+import { ProjectsActionComponent } from 'ProjectsAction';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes ProjectsComponent.html as template url
+ */
+@Component({
+    selector: 'app-projects',
+    templateUrl: './ProjectsComponent.html',
+    styleUrls: ['./ProjectsComponent.scss']
+})
+/** Exporting a class @exports ProjectsComponent */
+export class ProjectsComponent implements OnInit, OnDestroy {
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** handle translate @public */
+    public translateService: TranslateService;
+
+    /** Data of smarttable populate through LocalDataSource @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** Columns list of the smart table @public */
+    public columnLists: object = {};
+
+    /** Settings for smarttable to populate the table with columns @public */
+    public settings: object = {};
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Instance of the rest service @private */
+    private restService: RestService;
+
+    /** dataService to pass the data from one component to another @private */
+    private dataService: DataService;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Formation of appropriate Data for LocalDatasource @private */
+    private projectData: ProjectData[] = [];
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.sharedService = this.injector.get(SharedService);
+        this.modalService = this.injector.get(NgbModal);
+        this.translateService = this.injector.get(TranslateService);
+    }
+
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.generateColumns();
+        this.generateSettings();
+        this.generateData();
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** smart table Header Colums @public */
+    public generateColumns(): void {
+        this.columnLists = {
+            projectName: {
+                title: this.translateService.instant('NAME'), width: '55%', sortDirection: 'asc', type: 'custom',
+                valuePrepareFunction: (cell: ProjectData, row: ProjectData): ProjectData => row,
+                renderComponent: ProjectLinkComponent
+            },
+            modificationDate: { title: this.translateService.instant('MODIFIED'), width: '20%' },
+            creationDate: { title: this.translateService.instant('CREATED'), width: '20%' },
+            Actions: {
+                name: 'Action', width: '5%', filter: false, sort: false, type: 'custom',
+                title: this.translateService.instant('ACTIONS'),
+                valuePrepareFunction: (cell: ProjectData, row: ProjectData): ProjectData => row,
+                renderComponent: ProjectsActionComponent
+            }
+        };
+    }
+
+    /** smart table Data Settings @public */
+    public generateSettings(): void {
+        this.settings = {
+            edit: {
+                editButtonContent: '<i class="fa fa-edit" title="Edit"></i>',
+                confirmSave: true
+            },
+            delete: {
+                deleteButtonContent: '<i class="far fa-trash-alt" title="Delete"></i>',
+                confirmDelete: true
+            },
+            columns: this.columnLists,
+            actions: {
+                add: false,
+                edit: false,
+                delete: false,
+                position: 'right'
+            },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** Modal service to initiate the project add @private */
+    public projectAdd(): void {
+        const modalRef: NgbModalRef = this.modalService.open(ProjectCreateUpdateComponent, { backdrop: 'static' });
+        modalRef.componentInstance.projectType = 'Add';
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.generateData();
+            }
+        }).catch();
+    }
+
+    /** smart table listing manipulation @private */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** convert UserRowSelect Function @private */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'projects' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** Generate Projects object from loop and return for the datasource @public */
+    public generateProjectData(projectData: ProjectDetails): ProjectData {
+        return {
+            projectName: projectData.name,
+            modificationDate: this.sharedService.convertEpochTime(projectData._admin.modified),
+            creationDate: this.sharedService.convertEpochTime(projectData._admin.created),
+            id: projectData._id,
+            project: projectData._id
+        };
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+
+    /** Fetching the data from server to Load in the smarttable @protected */
+    protected generateData(): void {
+        this.isLoadingResults = true;
+        this.restService.getResource(environment.PROJECTS_URL).subscribe((projectsData: ProjectDetails[]) => {
+            this.projectData = [];
+            projectsData.forEach((projectData: ProjectDetails) => {
+                const projectDataObj: ProjectData = this.generateProjectData(projectData);
+                this.projectData.push(projectDataObj);
+            });
+            this.dataSource.load(this.projectData).then((data: boolean) => {
+                this.isLoadingResults = false;
+            }).catch();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+}
diff --git a/src/app/projects/ProjectsModule.ts b/src/app/projects/ProjectsModule.ts
new file mode 100644 (file)
index 0000000..16147b9
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file SDN Controller module.
+ */
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { NgModule } from '@angular/core';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { FormsModule } from '@angular/forms';
+import { ReactiveFormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgSelectModule } from '@ng-select/ng-select';
+import { TranslateModule } from '@ngx-translate/core';
+import { DataService } from 'DataService';
+import { LoaderModule } from 'LoaderModule';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { PagePerRowModule } from 'PagePerRowModule';
+import { PageReloadModule } from 'PageReloadModule';
+import { ProjectCreateUpdateComponent } from 'ProjectCreateUpdate';
+import { ProjectsComponent } from 'ProjectsComponent';
+
+/**
+ * configures  routers
+ */
+const routes: Routes = [
+    {
+        path: '',
+        data: {
+            breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: null }]
+        },
+        component: ProjectsComponent
+    }
+];
+
+/**
+ * Creating @NgModule component for Modules
+ */
+// tslint:disable-next-line: no-stateless-class
+@NgModule({
+    imports: [
+        FormsModule,
+        CommonModule,
+        HttpClientModule,
+        Ng2SmartTableModule,
+        FlexLayoutModule,
+        TranslateModule,
+        RouterModule.forChild(routes),
+        NgbModule,
+        PagePerRowModule,
+        ReactiveFormsModule,
+        LoaderModule,
+        PageReloadModule,
+        NgSelectModule
+    ],
+    declarations: [
+        ProjectsComponent,
+        ProjectCreateUpdateComponent
+    ],
+    providers: [
+        DataService
+    ],
+    entryComponents: [
+        ProjectCreateUpdateComponent
+    ]
+})
+/** Exporting a class @exports ProjectsModule */
+export class ProjectsModule {
+    // empty module
+}
diff --git a/src/app/projects/project-create-update/ProjectCreateUpdateComponent.html b/src/app/projects/project-create-update/ProjectCreateUpdateComponent.html
new file mode 100644 (file)
index 0000000..c327119
--- /dev/null
@@ -0,0 +1,51 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="projectForm" (ngSubmit)="projectAction(getProjectType)">
+  <div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{ (getProjectType == 'Add' ? 'NEW' : 'EDIT') | translate}} {{'PROJECT' | translate}}</h4>
+    <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+      <i class="fas fa-times-circle text-danger"></i>
+    </button>
+  </div>
+  <div class="modal-body project-create-update">
+    <div class="form-group row">
+      <label class="col-sm-12 col-form-label mandatory-label" [ngClass]="{'text-danger': projectForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+      <label class="col-sm-4 col-form-label">{{'PROJECT' | translate}} {{'NAME' | translate}}*</label>
+      <div class="col-sm-8">
+        <input placeholder="{{'PROJECT' | translate}} {{'NAME' | translate}}" type="text" class="form-control" formControlName="project_name" [(ngModel)]="projectName" [ngClass]="{ 'is-invalid': submitted && f.project_name.errors }" required>
+      </div>
+    </div>
+    <div class="form-group row" *ngIf="getProjectType === 'Add'">
+      <label class="col-sm-4 col-form-label">{{'DOMAIN' | translate}} {{'NAME' | translate}}</label>
+      <div class="col-sm-8">
+        <ng-select [clearable]="false" placeholder="{{'SELECT' | translate}}"
+        [items]="domains" bindLabel="text" bindValue="id" formControlName="domain_name" id="domain_name"
+        [ngClass]="{ 'is-invalid': submitted && f.domain_name.errors }"></ng-select>      </div>
+    </div>
+    <div class="form-group row" *ngIf="getProjectType === 'Add'">
+      <label class="col-xs-10 col-sm-10 col-md-10 col-lg-10 col-xl-10">{{'RECENTLY' | translate}} {{'CREATED' | translate}} {{'PROJECT' | translate}}:
+        <b>{{(recentProject)?recentProject.name:''}}</b>
+      </label>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+    <button type="submit" class="btn btn-primary">{{(getProjectType == 'Add' ? 'CREATE' : 'APPLY') | translate}}</button>
+  </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
diff --git a/src/app/projects/project-create-update/ProjectCreateUpdateComponent.scss b/src/app/projects/project-create-update/ProjectCreateUpdateComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/projects/project-create-update/ProjectCreateUpdateComponent.ts b/src/app/projects/project-create-update/ProjectCreateUpdateComponent.ts
new file mode 100644 (file)
index 0000000..ea0bb8a
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Project Add Modal
+ */
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { ProjectData, ProjectDetails } from 'ProjectModel';
+import { ProjectService } from 'ProjectService';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes ProjectCreateUpdateComponent.html as template url
+ */
+@Component({
+  selector: 'app-project-create-update',
+  templateUrl: './ProjectCreateUpdateComponent.html',
+  styleUrls: ['./ProjectCreateUpdateComponent.scss']
+})
+/** Exporting a class @exports ProjectCreateUpdateComponent */
+export class ProjectCreateUpdateComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Instance of the rest service @public */
+  public restService: RestService;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Contains the recently created project details @public */
+  public recentProject: ProjectDetails;
+
+  /** Contains project name @public */
+  public projectName: string;
+
+  /** Contains project create or edit @public */
+  public getProjectType: string;
+
+  /** To inject input type services @public */
+  @Input() public projectType: string;
+
+  /** FormGroup user Edit Account added to the form @ html @public */
+  public projectForm: FormGroup;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Holds list of domains @public */
+  public domains: {}[] = [];
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** DataService to pass the data from one component to another @private */
+  private dataService: DataService;
+
+  /** Contains project name ref @private */
+  private projectRef: string;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** ModalData instance of modal @private  */
+  private modalData: MODALCLOSERESPONSEDATA;
+
+  /** Holds all project details @private */
+  private projectService: ProjectService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.dataService = this.injector.get(DataService);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+    this.projectService = this.injector.get(ProjectService);
+    /** Initializing Form Action */
+    this.projectForm = this.formBuilder.group({
+      project_name: ['', Validators.required],
+      domain_name: [null]
+    });
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.projectForm.controls; }
+
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.getProjectType = this.projectType;
+    if (this.getProjectType === 'Edit') {
+      this.dataService.currentMessage.subscribe((data: ProjectData) => {
+        if (data.projectName !== undefined || data.projectName !== '' || data.projectName !== null) {
+          this.projectName = data.projectName;
+          this.projectRef = data.id;
+        }
+      });
+    } else {
+      this.getProjects();
+    }
+  }
+
+  /** Get the last project name @public */
+  public getProjects(): void {
+    this.isLoadingResults = true;
+    this.restService.getResource(environment.PROJECTS_URL).subscribe((projects: ProjectDetails[]) => {
+      this.recentProject = projects.slice(-1).pop();
+      this.getDomainName();
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+    });
+  }
+
+  /** On modal submit users acction will called @public */
+  public projectAction(userType: string): void {
+    this.submitted = true;
+    this.modalData = {
+      message: 'Done'
+    };
+    this.sharedService.cleanForm(this.projectForm);
+    if (!this.projectForm.invalid) {
+      if (userType === 'Add') {
+        this.createProject();
+      } else if (userType === 'Edit') {
+        this.editProject();
+      }
+    }
+  }
+
+  /** Create project @public */
+  public createProject(): void {
+    this.isLoadingResults = true;
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.PROJECTS_URL
+    };
+    const projectPayload: {} = {
+      name: this.projectForm.value.project_name,
+      domain_name: !isNullOrUndefined(this.projectForm.value.domain_name) ? this.projectForm.value.domain_name : undefined
+    };
+    this.restService.postResource(apiURLHeader, projectPayload).subscribe(() => {
+      this.activeModal.close(this.modalData);
+      this.isLoadingResults = false;
+      this.notifierService.notify('success', this.translateService.instant('PAGE.PROJECT.CREATEDSUCCESSFULLY'));
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'post');
+      this.isLoadingResults = false;
+    });
+  }
+  /** Edit project @public */
+  public editProject(): void {
+    this.isLoadingResults = true;
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.PROJECTS_URL + '/' + this.projectRef
+    };
+    this.restService.patchResource(apiURLHeader, { name: this.projectForm.value.project_name }).subscribe(() => {
+      this.activeModal.close(this.modalData);
+      this.isLoadingResults = false;
+      this.projectService.setHeaderProjects();
+      this.notifierService.notify('success', this.translateService.instant('PAGE.PROJECT.UPDATEDSUCCESSFULLY'));
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'patch');
+      this.isLoadingResults = false;
+    });
+  }
+  /** Get domain name @private */
+  private getDomainName(): void {
+    this.restService.getResource(environment.DOMAIN_URL).subscribe((domains: { project_domain_name: string, user_domain_name: string }) => {
+      let domainNames: string[] = [];
+      if (!isNullOrUndefined(domains.project_domain_name)) {
+        domainNames = domainNames.concat(domains.project_domain_name.split(','));
+      }
+      if (!isNullOrUndefined(domains.user_domain_name)) {
+        domainNames = domainNames.concat(domains.user_domain_name.split(','));
+      }
+      domainNames = Array.from(new Set(domainNames));
+      this.checkDomainNames(domainNames);
+      this.isLoadingResults = false;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+    });
+  }
+
+  /** Check the domain names and create modal for domain select @private */
+  private checkDomainNames(domainNames: string[]): void {
+    if (domainNames.length > 0) {
+      domainNames.forEach((domainName: string) => {
+        if (!domainName.endsWith(':ro')) {
+          this.domains.push({ id: domainName, text: domainName });
+        }
+      });
+    }
+  }
+}
diff --git a/src/app/roles/RolesComponent.html b/src/app/roles/RolesComponent.html
new file mode 100644 (file)
index 0000000..da59906
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<router-outlet></router-outlet>
\ No newline at end of file
diff --git a/src/app/roles/RolesComponent.scss b/src/app/roles/RolesComponent.scss
new file mode 100644 (file)
index 0000000..f6cb0fe
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
diff --git a/src/app/roles/RolesComponent.ts b/src/app/roles/RolesComponent.ts
new file mode 100644 (file)
index 0000000..82f20b4
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Roles component.
+ */
+import { Component, Injector } from '@angular/core';
+import { Router, RouterEvent } from '@angular/router';
+
+/**
+ * Creating component
+ * @Component takes RolesComponent.html as template url
+ */
+@Component({
+  selector: 'app-roles',
+  templateUrl: './RolesComponent.html',
+  styleUrls: ['./RolesComponent.scss']
+})
+
+/** Exporting a class @exports RolesComponent */
+export class RolesComponent {
+  /** Invoke service injectors @public */
+  public injector: Injector;
+
+  /** Holds teh instance of router service @private */
+  private router: Router;
+
+  // creates role datails component
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.router = this.injector.get(Router);
+    this.router.events.subscribe((event: RouterEvent) => {
+      this.redirectToList(event.url);
+    });
+  }
+
+  /** Return to role datails list */
+  public redirectToList(getURL: string): void {
+    if (getURL === '/roles') {
+      this.router.navigate(['/roles/details']).catch();
+    }
+  }
+
+}
diff --git a/src/app/roles/RolesModule.ts b/src/app/roles/RolesModule.ts
new file mode 100644 (file)
index 0000000..88e1225
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+
+/**
+ * @file Roles Module
+ */
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { ReactiveFormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateModule } from '@ngx-translate/core';
+import { LoaderModule } from 'LoaderModule';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { PagePerRowModule } from 'PagePerRowModule';
+import { PageReloadModule } from 'PageReloadModule';
+import { RolesComponent } from 'Roles';
+import { RolesActionComponent } from 'RolesAction';
+import { RolesCreateEditComponent } from 'RolesCreateEdit';
+import { RolesDetailsComponent } from 'RolesDetails';
+
+/** const values for Roles Routes */
+const routes: Routes = [
+    {
+        path: '',
+        component: RolesComponent,
+        children: [
+            {
+                path: 'details',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'ROLES', url: null }]
+                },
+                component: RolesDetailsComponent
+            },
+            {
+                path: 'create',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'ROLES', url: '/roles/details' },
+                    { title: 'PAGE.ROLES.CREATEROLE', url: null }]
+                },
+                component: RolesCreateEditComponent
+            },
+            {
+                path: 'edit/:id',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'ROLES', url: '/roles/details' },
+                    { title: '{id}', url: null }]
+                },
+                component: RolesCreateEditComponent
+            }
+        ]
+    }
+];
+/**
+ * An NgModule is a class adorned with the @NgModule decorator function.
+ * @NgModule takes a metadata object that tells Angular how to compile and run module code.
+ */
+@NgModule({
+    imports: [FormsModule, ReactiveFormsModule, CommonModule, HttpClientModule, TranslateModule,
+        RouterModule.forChild(routes), NgbModule, PagePerRowModule, Ng2SmartTableModule, LoaderModule, PageReloadModule],
+    declarations: [RolesComponent, RolesDetailsComponent, RolesActionComponent, RolesCreateEditComponent],
+    entryComponents: [RolesActionComponent]
+})
+/**
+ * AppModule is the Root module for application
+ */
+export class RolesModule {
+    /** Variables declared to avoid state-less class */
+    private rolesModule: string;
+}
diff --git a/src/app/roles/roles-create-edit/RolesCreateEditComponent.html b/src/app/roles/roles-create-edit/RolesCreateEditComponent.html
new file mode 100644 (file)
index 0000000..7bb2a1f
--- /dev/null
@@ -0,0 +1,92 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+  <div class="d-flex align-items-center header-style">
+    {{ (getRoleType == 'Add' ? 'PAGE.ROLES.CREATEROLE' : 'PAGE.ROLES.EDITROLE') | translate}}</div>
+  <span class="button">
+    <button class="btn btn-primary" type="button" (click)="viewSelection()" placement="top" container="body"
+      ngbTooltip="{{ (viewMode == 'text' ? 'PAGE.ROLES.PREVIEW' : 'PAGE.ROLES.TEXTVIEW') | translate}}"> <i
+        [ngClass]="{ 'fa': 'true', 'fa-comment': viewMode == 'text', 'fa-edit': viewMode == 'preview' }"></i>&nbsp;{{ (viewMode == 'text' ? 'PAGE.ROLES.PREVIEW' : 'PAGE.ROLES.TEXTVIEW') | translate}}
+    </button>
+  </span>
+</div>
+<form [formGroup]="roleForm" (ngSubmit)="roleCheck()" autocomplete="off">
+  <div class="form-group row">
+    <label class="col-sm-12 col-form-label mandatory-label"
+      [ngClass]="{'text-danger': roleForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+    <label class="col-sm-2 col-form-label">{{'NAME' | translate}}*</label>
+    <div class="col-sm-5">
+      <input placeholder="{{'NAME' | translate}}" type="text" class="form-control" maxlength="30"
+        formControlName="roleName" [ngClass]="{ 'is-invalid': submitted && f.roleName.errors }" required>
+    </div>
+  </div>
+  <div class="form-group row" *ngIf="viewMode == 'text'">
+    <label class="col-sm-2 col-form-label">{{'PAGE.ROLES.PERMISSIONS' | translate}}</label>
+    <div class="col-sm-5">
+      <textarea placeholder="{{'PAGE.ROLES.YAMLPERMISSIONS' | translate}}" rows="10" cols="50" type="text"
+        class="form-control" formControlName="permissions"></textarea>
+    </div>
+  </div>
+  <div class="form-group row" [ngClass]="{ 'justify-content-end': viewMode == 'text' }">
+    <div class="col-sm-6">
+      <button type="button" class="btn btn-danger" routerLink="/roles/details">{{'CANCEL' | translate}}</button>
+      <button class="btn btn-primary ml-3"
+        type="submit">{{ (getRoleType == 'Add' ? 'CREATE' : 'APPLY') | translate}}</button>
+    </div>
+  </div>
+</form>
+<ngb-accordion class="roles-section" [closeOthers]="true" type="secondary" *ngIf="rolePermissions && viewMode == 'preview'">
+  <ngb-panel *ngFor="let permissionGroup of rolePermissions; let i = index">
+    <ng-template ngbPanelHeader let-opened="opened">
+      <div class="d-flex align-items-center justify-content-between">
+        <button ngbPanelToggle class="btn text-dark container-fluid text-left pl-0"><i
+          [ngClass]="{ 'fas': true, 'fa-angle-down': opened, 'fa-angle-right': !opened }"></i> {{permissionGroup.title}}</button>
+      </div>
+    </ng-template>
+    <ng-template ngbPanelContent>
+      <div class="row">
+        <div class="col-lg-4 col-md-6 col-sm-12" *ngFor="let permission of permissionGroup.permissions">
+          <div class="row">
+            <div class="col-md-6 col-sm-6 p-2">{{permission.operation}}</div>
+            <div class="btn-group btn-group-toggle custom-button col-md-6 col-sm-6" ngbRadioGroup name="permission"
+              [(ngModel)]="permission.value">
+              <label ngbButtonLabel ngbTooltip="true">
+                <input ngbButton type="radio" [value]="true">
+                <span class="bg-success"><img src="assets/images/TICK.svg" alt="Checked Icon" /></span>
+              </label>
+              <label ngbButtonLabel ngbTooltip="NA">
+                <input ngbButton type="radio" value="NA">
+                <span class="bg-warning"><img src="assets/images/TICK.svg" alt="Checked Icon" /></span>
+              </label>
+              <label ngbButtonLabel ngbTooltip="false">
+                <input ngbButton type="radio" [value]="false">
+                <span class="bg-danger"><img src="assets/images/TICK.svg" alt="Checked Icon" /></span>
+              </label>
+            </div>
+          </div>
+        </div>
+      </div>
+    </ng-template>
+  </ngb-panel>
+</ngb-accordion>
+<div class="float-right" *ngIf="viewMode == 'preview'">
+  <button type="button" class="btn btn-danger" routerLink="/roles/details">{{'CANCEL' | translate}}</button>
+  <button class="btn btn-primary ml-3"
+    (click)="roleCheck()">{{ (getRoleType == 'Add' ? 'CREATE' : 'APPLY') | translate}}</button>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/roles/roles-create-edit/RolesCreateEditComponent.scss b/src/app/roles/roles-create-edit/RolesCreateEditComponent.scss
new file mode 100644 (file)
index 0000000..362973a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import '../../../assets/scss/mixins/mixin';
+@import '../../../assets/scss/variable';
+ .custom-button{
+  label {
+    @include padding-value(2,2,2,2);
+    &.active {
+      @include background(null, $white, null, null, null);
+      span{
+        img {
+          opacity: 1;
+        }
+      }
+    }
+    input[type="radio"] {
+      display: none;
+    }
+    span {
+      display: inline-block;
+      @include wh-value(30px,30px);
+      cursor: pointer;
+      border-radius: 50%;
+      @include border(all,2,solid, $white);
+      @include box-shadow(0px, 1px, 3px, 0px, $dark);
+      @include background(null, null, null, no-repeat, center);
+      text-align: center;
+      @include line-height(25px);
+      img {
+        width:50%;
+        opacity: 0;
+        @include transition(all, 0.3, null, ease);
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/app/roles/roles-create-edit/RolesCreateEditComponent.ts b/src/app/roles/roles-create-edit/RolesCreateEditComponent.ts
new file mode 100644 (file)
index 0000000..0419c5f
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Roles Create and Edit Component
+ */
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA } from 'CommonModel';
+import { environment } from 'environment';
+import * as jsonpath from 'jsonpath';
+import { RestService } from 'RestService';
+import { Permission, PermissionGroup, RoleConfig, RoleData } from 'RolesModel';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes RolesCreateEditComponent.html as template url
+ */
+@Component({
+  selector: 'app-roles-create-edit',
+  templateUrl: './RolesCreateEditComponent.html',
+  styleUrls: ['./RolesCreateEditComponent.scss']
+})
+/** Exporting a class @exports RolesCreateEditComponent */
+export class RolesCreateEditComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** contains role permissions from config file @public */
+  public rolePermissions: {}[];
+
+  /** contains role form group information @public */
+  public roleForm: FormGroup;
+
+  /** Instance of the rest service @public */
+  public restService: RestService;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Instance to check role form submitted status @public */
+  public submitted: boolean = false;
+
+  /** Contains role create or edit value @public */
+  public getRoleType: string;
+
+  /** Contains view selection value either text or preview @public */
+  public viewMode: string = 'text';
+
+  /** Contains role id value @private */
+  private roleRef: string;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** contians form builder module @private */
+  private formBuilder: FormBuilder;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Varaibles to hold http client @private */
+  private httpClient: HttpClient;
+
+  /** Holds the instance of activatedRoute of router service @private */
+  private activatedRoute: ActivatedRoute;
+
+  /** Holds the instance of roter service @private */
+  private router: Router;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.sharedService = this.injector.get(SharedService);
+    this.httpClient = this.injector.get(HttpClient);
+    this.activatedRoute = this.injector.get(ActivatedRoute);
+    this.router = this.injector.get(Router);
+  }
+
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.headers = new HttpHeaders({
+      'Content-Type': 'application/json',
+      Accept: 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    this.roleForm = this.formBuilder.group({
+      roleName: ['', [Validators.required]],
+      permissions: ['']
+    });
+    this.getRolePermissions();
+  }
+
+  /** Get role permission information based on action @public */
+  public getRolePermissions(): void {
+    this.isLoadingResults = true;
+    this.loadPermissions().then((response: RoleConfig) => {
+      this.rolePermissions = response.rolePermissions;
+      if (this.activatedRoute.snapshot.url[0].path === 'create') {
+        this.getRoleType = 'Add';
+        this.isLoadingResults = false;
+      } else {
+        this.getRoleType = 'Edit';
+        this.getRoleData();
+      }
+    }).catch(() => {
+      // Empty Block
+    });
+  }
+
+  /** Check Role Create or Edit and proceed action @public */
+  public roleCheck(): void {
+    this.submitted = true;
+    if (!this.roleForm.valid) {
+      const errorIp: Element = document.querySelector('.ng-invalid[formControlName]');
+      if (errorIp) {
+        errorIp.scrollIntoView({ behavior: 'smooth', block: 'center' });
+      }
+    } else {
+      if (this.getRoleType === 'Add') {
+        this.createRole();
+      } else {
+        this.editRole();
+      }
+    }
+  }
+
+  /** Convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.roleForm.controls; }
+
+  /** Create role @private  */
+  public createRole(): void {
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.ROLES_URL,
+      httpOptions: { headers: this.headers }
+    };
+    let permissionData: Object = {};
+    this.sharedService.cleanForm(this.roleForm);
+    if (!this.roleForm.invalid) {
+      if (this.viewMode === 'preview') {
+        this.isLoadingResults = true;
+        permissionData = this.generatePermissions();
+        this.roleCreateAPI(apiURLHeader, permissionData);
+      } else {
+        if (this.checkPermission()) {
+          this.isLoadingResults = true;
+          permissionData = this.roleForm.value.permissions !== '' ? JSON.parse(this.roleForm.value.permissions) : {};
+          this.roleCreateAPI(apiURLHeader, permissionData);
+        }
+      }
+    }
+  }
+
+  /** Method to handle role create API call @public */
+  public roleCreateAPI(apiURLHeader: APIURLHEADER, permissionData: {}): void {
+    const postData: {} = {
+      name: this.roleForm.value.roleName,
+      permissions: !isNullOrUndefined(permissionData) ? permissionData : {}
+    };
+    this.restService.postResource(apiURLHeader, postData).subscribe(() => {
+      this.notifierService.notify('success', this.translateService.instant('PAGE.ROLES.CREATEDSUCCESSFULLY'));
+      this.router.navigate(['/roles/details']).catch();
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      this.restService.handleError(error, 'post');
+    });
+  }
+
+  /** Edit role  @private  */
+  public editRole(): void {
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.ROLES_URL + '/' + this.roleRef,
+      httpOptions: { headers: this.headers }
+    };
+    let permissionData: Object = {};
+    this.sharedService.cleanForm(this.roleForm);
+    if (!this.roleForm.invalid) {
+      if (this.viewMode === 'preview') {
+        this.isLoadingResults = true;
+        permissionData = this.generatePermissions();
+        this.roleEditAPI(apiURLHeader, permissionData);
+      } else {
+        if (this.checkPermission()) {
+          this.isLoadingResults = true;
+          permissionData = this.roleForm.value.permissions !== '' ? JSON.parse(this.roleForm.value.permissions) : {};
+          this.roleEditAPI(apiURLHeader, permissionData);
+        }
+      }
+    }
+  }
+
+  /** Method to handle role edit API call */
+  public roleEditAPI(apiURLHeader: APIURLHEADER, permissionData: {}): void {
+    const postData: {} = {
+      name: this.roleForm.value.roleName,
+      permissions: !isNullOrUndefined(permissionData) ? permissionData : {}
+    };
+    this.restService.patchResource(apiURLHeader, postData).subscribe(() => {
+      this.notifierService.notify('success', this.translateService.instant('PAGE.ROLES.UPDATEDSUCCESSFULLY'));
+      this.router.navigate(['/roles/details']).catch();
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      this.restService.handleError(error, 'patch');
+    });
+  }
+
+  /** Method to handle toggle role view selection @public */
+  public viewSelection(): void {
+    if (this.viewMode === 'text' && this.checkPermission()) {
+      this.loadPermissions().then((response: RoleConfig) => {
+        this.rolePermissions = response.rolePermissions;
+        const permissions: {} = this.roleForm.value.permissions !== '' ? JSON.parse(this.roleForm.value.permissions) : {};
+        this.filterRoleData(permissions);
+        this.viewMode = 'preview';
+      }).catch(() => {
+        // Empty Block
+      });
+    } else {
+      const rolePermission: {} = this.generatePermissions();
+      if (Object.keys(rolePermission).length !== 0) {
+        this.roleForm.patchValue({ permissions: JSON.stringify(rolePermission, null, '\t') });
+      }
+      this.viewMode = 'text';
+    }
+
+  }
+
+  /** Generate role permission post data @private */
+  private generatePermissions(): Object {
+    const permissions: Object = {};
+    this.rolePermissions.forEach((permissionGroup: PermissionGroup) => {
+      if (!isNullOrUndefined(permissionGroup)) {
+        permissionGroup.permissions.forEach((permission: Permission) => {
+          if (!isNullOrUndefined(permission.value) && permission.value !== 'NA') {
+            permissions[permission.operation] = permission.value;
+          }
+        });
+      }
+    });
+    return permissions;
+  }
+
+  /** Validation method for check permission json string @private */
+  private checkPermission(): boolean {
+    if (this.roleForm.value.permissions) {
+      if (!this.sharedService.checkJson(this.roleForm.value.permissions)) {
+        this.notifierService.notify('error', this.translateService.instant('PAGE.ROLES.ROLEJSONERROR'));
+        return false;
+      } else {
+        this.roleForm.value.permissions = this.roleForm.value.permissions.replace(/'/g, '"');
+        const rolePermission: {} = JSON.parse(this.roleForm.value.permissions);
+        for (const key of Object.keys(rolePermission)) {
+          if (typeof rolePermission[key] !== 'boolean') {
+            this.notifierService.notify('error', this.translateService.instant('PAGE.ROLES.ROLEKEYERROR', { roleKey: key }));
+            return false;
+          }
+        }
+      }
+    }
+    return true;
+  }
+
+  /** Get role data from NBI based on ID and apply filter @private */
+  private getRoleData(): void {
+    // tslint:disable-next-line: no-backbone-get-set-outside-model
+    this.roleRef = this.activatedRoute.snapshot.paramMap.get('id');
+    if (!isNullOrUndefined(this.roleRef)) {
+      this.restService.getResource(environment.ROLES_URL + '/' + this.roleRef).subscribe((data: RoleData) => {
+        this.roleForm.setValue({ roleName: data.name, permissions: JSON.stringify(data.permissions, null, '\t') });
+        this.filterRoleData(data.permissions);
+        this.isLoadingResults = false;
+      }, (error: ERRORDATA) => {
+        this.router.navigate(['/roles/details']).catch();
+        this.restService.handleError(error, 'get');
+      });
+    }
+  }
+
+  /** Method to filter role data @private */
+  private filterRoleData(permissions: {}): void {
+    Object.keys(permissions).forEach((permission: string) => {
+      jsonpath.apply(this.rolePermissions, '$..permissions[?(@.operation == "' + permission + '")]', (response: Permission) => {
+        if (response.operation === permission) {
+          response.value = permissions[permission];
+        }
+        return response;
+      });
+    });
+  }
+
+  /** Method to load the role permission Json file @private */
+  private async loadPermissions(): Promise<Object> {
+    const jsonFile: string = environment.PERMISSIONS_CONFIG_FILE + '?cb=' + new Date().getTime();
+    return new Promise<Object>((resolve: Function, reject: Function): void => {
+      this.httpClient.get(jsonFile).subscribe((response: Response) => {
+        resolve(response);
+      }, (error: {}) => {
+        reject();
+      });
+    });
+  }
+
+}
diff --git a/src/app/roles/roles-details/RolesDetailsComponent.html b/src/app/roles/roles-details/RolesDetailsComponent.html
new file mode 100644 (file)
index 0000000..28a3fe7
--- /dev/null
@@ -0,0 +1,36 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'ROLES' | translate}}</div>
+    <span class="button">
+        <button class="btn btn-primary" type="button" (click)="createRole()" placement="top"
+            container="body" ngbTooltip="{{'PAGE.ROLES.CREATEROLE' | translate}}">
+            <i class="fas fa-plus-circle" aria-hidden="true"></i>
+            {{'PAGE.ROLES.CREATEROLE' | translate}}
+        </button>
+    </span>
+</div>
+<div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/roles/roles-details/RolesDetailsComponent.scss b/src/app/roles/roles-details/RolesDetailsComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/roles/roles-details/RolesDetailsComponent.ts b/src/app/roles/roles-details/RolesDetailsComponent.ts
new file mode 100644 (file)
index 0000000..2568f5a
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Roles Deatils component.
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { TranslateService } from '@ngx-translate/core';
+import { ERRORDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { RolesActionComponent } from 'RolesAction';
+import { RoleData, RoleDetails } from 'RolesModel';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes RolesComponent.html as template url
+ */
+@Component({
+  selector: 'app-roles-details',
+  templateUrl: './RolesDetailsComponent.html',
+  styleUrls: ['./RolesDetailsComponent.scss']
+})
+export class RolesDetailsComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Formation of appropriate Data for LocalDatasource @public */
+  public dataSource: LocalDataSource = new LocalDataSource();
+
+  /** handle translate @public */
+  public translateService: TranslateService;
+
+  /** Columns list of the smart table @public */
+  public columnLists: object = {};
+
+  /** Settings for smarttable to populate the table with columns @public */
+  public settings: object = {};
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = true;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** dataService to pass the data from one component to another @private */
+  private dataService: DataService;
+
+  /** Contains role details data @private */
+  private roleData: RoleData[] = [];
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+   /** Instance of subscriptions @private */
+  private generateDataSub: Subscription;
+
+  /** Holds the instance of roter service @private */
+  private router: Router;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.dataService = this.injector.get(DataService);
+    this.sharedService = this.injector.get(SharedService);
+    this.translateService = this.injector.get(TranslateService);
+    this.router = this.injector.get(Router);
+  }
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.generateColumns();
+    this.generateSettings();
+    this.generateData();
+    this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+  }
+  /** smart table Header Colums @public */
+  public generateColumns(): void {
+    this.columnLists = {
+      name: { title: this.translateService.instant('NAME'), width: '30%', sortDirection: 'asc' },
+      identifier: { title: this.translateService.instant('IDENTIFIER'), width: '35%' },
+      modified: { title: this.translateService.instant('MODIFIED'), width: '15%' },
+      created: { title: this.translateService.instant('CREATED'), width: '15%' },
+      Actions: {
+        name: 'Actions', width: '5%', filter: false, sort: false, type: 'custom',
+        title: this.translateService.instant('ACTIONS'),
+        valuePrepareFunction: (cell: RoleData, row: RoleData): RoleData => row,
+        renderComponent: RolesActionComponent
+      }
+    };
+  }
+
+  /** smart table Data Settings @public */
+  public generateSettings(): void {
+    this.settings = {
+      edit: {
+        editButtonContent: '<i class="fa fa-edit" title="Edit"></i>',
+        confirmSave: true
+      },
+      delete: {
+        deleteButtonContent: '<i class="far fa-trash-alt" title="delete"></i>',
+        confirmDelete: true
+      },
+      columns: this.columnLists,
+      actions: {
+        add: false,
+        edit: false,
+        delete: false,
+        topology: false,
+        position: 'right'
+      },
+      attr: this.sharedService.tableClassConfig(),
+      pager: this.sharedService.paginationPagerConfig(),
+      noDataMessage: this.translateService.instant('NODATAMSG')
+    };
+  }
+
+  /** smart table listing manipulation @public */
+  public onChange(perPageValue: number): void {
+    this.dataSource.setPaging(1, perPageValue, true);
+  }
+
+  /** convert UserRowSelect Function @private */
+  public onUserRowSelect(event: MessageEvent): void {
+    Object.assign(event.data, { page: 'roles' });
+    this.dataService.changeMessage(event.data);
+  }
+
+  /** Fetching the role data from API and Load it in the smarttable @public */
+  public generateData(): void {
+    this.isLoadingResults = true;
+    this.roleData = [];
+    this.restService.getResource(environment.ROLES_URL).subscribe((roleList: RoleDetails[]) => {
+      roleList.forEach((role: RoleDetails) => {
+        const roleDataObj: RoleData = this.generateRoleData(role);
+        this.roleData.push(roleDataObj);
+      });
+      this.dataSource.load(this.roleData).then((data: boolean) => {
+        this.isLoadingResults = false;
+      }).catch();
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+    });
+  }
+
+  /** Generate role data object and return for the datasource @public */
+  public generateRoleData(roleData: RoleDetails): RoleData {
+    return {
+      name: roleData.name,
+      identifier: roleData._id,
+      modified: this.sharedService.convertEpochTime(Number(roleData._admin.modified)),
+      created: this.sharedService.convertEpochTime(Number(roleData._admin.created)),
+      permissions: roleData.permissions
+    };
+  }
+
+  /** Create role click handler @public */
+  public createRole(): void {
+    this.router.navigate(['/roles/create']).catch(() => {
+      // Catch Navigation Error
+    });
+  }
+
+  /** Lifecyle hook which get trigger on component destruction @private */
+  public ngOnDestroy(): void {
+    this.generateDataSub.unsubscribe();
+  }
+
+}
diff --git a/src/app/sdn-controller/SDNControllerComponent.html b/src/app/sdn-controller/SDNControllerComponent.html
new file mode 100644 (file)
index 0000000..3f96ff8
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<router-outlet></router-outlet>
\ No newline at end of file
diff --git a/src/app/sdn-controller/SDNControllerComponent.scss b/src/app/sdn-controller/SDNControllerComponent.scss
new file mode 100644 (file)
index 0000000..5a72947
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
diff --git a/src/app/sdn-controller/SDNControllerComponent.ts b/src/app/sdn-controller/SDNControllerComponent.ts
new file mode 100644 (file)
index 0000000..661882c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file SDN Controller Component.
+ */
+import { Component, Injector } from '@angular/core';
+import { Router, RouterEvent } from '@angular/router';
+
+/**
+ * Creating component
+ * @Component takes SDNControllerComponent.html as template url
+ */
+@Component({
+    templateUrl: './SDNControllerComponent.html',
+    styleUrls: ['./SDNControllerComponent.scss']
+})
+/** Exporting a class @exports SDNControllerComponent */
+export class SDNControllerComponent {
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** Holds teh instance of AuthService class of type AuthService @private */
+    private router: Router;
+
+    // creates packages component
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.router = this.injector.get(Router);
+        this.router.events.subscribe((event: RouterEvent) => {
+            this.redirectToList(event.url);
+        });
+    }
+
+    /** Return to list NS Package List */
+    public redirectToList(getURL: string): void {
+        if (getURL === '/sdn') {
+            this.router.navigate(['/sdn/details']).catch();
+        }
+    }
+}
diff --git a/src/app/sdn-controller/SDNControllerModule.ts b/src/app/sdn-controller/SDNControllerModule.ts
new file mode 100644 (file)
index 0000000..6da4a5c
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file SDN Controller module.
+ */
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgSelectModule } from '@ng-select/ng-select';
+import { TranslateModule } from '@ngx-translate/core';
+import { DataService } from 'DataService';
+import { LoaderModule } from 'LoaderModule';
+import { NewSDNControllerComponent } from 'NewSDNControllerComponent';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { PagePerRowModule } from 'PagePerRowModule';
+import { PageReloadModule } from 'PageReloadModule';
+import { SDNControllerComponent } from 'SDNControllerComponent';
+import { SDNControllerDetailsComponent } from 'SDNControllerDetailsComponent';
+import { SDNControllerInfoComponent } from 'SDNControllerInfoComponent';
+
+/** To halndle project information */
+const projectInfo: {} = localStorage.getItem('project') !== null ? { title: localStorage.getItem('project'), url: '/' } : {};
+
+/**
+ * configures  routers
+ */
+const routes: Routes = [
+    {
+        path: '',
+        component: SDNControllerComponent,
+        children: [
+            {
+                path: 'details',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'SDNCONTROLLER', url: null }]
+                },
+                component: SDNControllerDetailsComponent
+            }
+        ]
+    }
+];
+
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+    imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, CommonModule,
+        HttpClientModule, NgSelectModule, Ng2SmartTableModule, TranslateModule, RouterModule.forChild(routes), NgbModule,
+        PagePerRowModule, LoaderModule, PageReloadModule],
+    declarations: [SDNControllerComponent, SDNControllerDetailsComponent, SDNControllerInfoComponent, NewSDNControllerComponent],
+    providers: [DataService],
+    entryComponents: [SDNControllerInfoComponent, NewSDNControllerComponent],
+    schemas: [CUSTOM_ELEMENTS_SCHEMA]
+})
+/** Exporting a class @exports SDNControllerModule */
+export class SDNControllerModule {
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        //Empty Class
+    }
+}
diff --git a/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.html b/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.html
new file mode 100644 (file)
index 0000000..7b909b1
--- /dev/null
@@ -0,0 +1,104 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="sdnControllerForm" (ngSubmit)="sdnControllerFormSubmit()" autocomplete="off">
+    <div class="modal-header">
+        <h4 class="modal-title" id="modal-basic-title">{{'PAGE.SDNCONTROLLER.NEWSDNCONTROLLER' | translate}}</h4>
+        <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+            <i class="fas fa-times-circle text-danger"></i>
+        </button>
+    </div>
+    <div class="modal-body modal-body-custom-height">
+        <div class="form-group row">
+            <label class="col-sm-12 col-form-label mandatory-label"
+                [ngClass]="{'text-danger': sdnControllerForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+            <label class="col-sm-4 col-form-label" for="name">{{'NAME' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'NAME' | translate}}" type="text"
+                    formControlName="name" id="name" [ngClass]="{ 'is-invalid': submitted && f.name.errors }" required>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="sdn_type">{{'TYPE' | translate}}*</label>
+            <div class="col-sm-8">
+                <ng-select [items]="sdnType" placeholder="{{'SELECT' | translate}}" bindLabel="title" bindValue="value"
+                    formControlName="type" id="sdn_type" [(ngModel)]="sdnTypeMod"
+                    [ngClass]="{ 'is-invalid': submitted && f.type.errors }" required>
+                </ng-select>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="username">{{'USERNAME' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'USERNAME' | translate}}" type="text"
+                    formControlName="user" id="username" [ngClass]="{ 'is-invalid': submitted && f.user.errors }"
+                    required>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="password">{{'PASSWORD' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'PASSWORD' | translate}}" type="password"
+                    formControlName="password" id="password"
+                    [ngClass]="{ 'is-invalid': submitted && f.password.errors }" required>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="ip">{{'IP' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'IP' | translate}}" type="text"
+                    formControlName="ip" id="ip" [ngClass]="{ 'is-invalid': submitted && f.ip.errors }" required>
+                <div *ngIf="sdnControllerForm.invalid" class="invalid-feedback">
+                    <div *ngIf="f.ip.errors && f.ip.value">{{'DOMVALIDATIONS.INVALIDIPADDRESS' | translate}}</div>
+                </div>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="port">{{'PORT' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'PORT' | translate}}" type="text"
+                    formControlName="port" id="port" [ngClass]="{ 'is-invalid': submitted && f.port.errors }" required>
+                <div *ngIf="sdnControllerForm.invalid" class="invalid-feedback">
+                    <div *ngIf="f.port.errors && f.port.value">{{'DOMVALIDATIONS.INVALIDPORTADDRESS' | translate}}</div>
+                </div>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="dpid">{{'PAGE.SDNCONTROLLER.DPID' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control"
+                    placeholder="{{'PAGE.SDNCONTROLLER.DPIDPLACEHOLDER' | translate}}" type="text"
+                    formControlName="dpid" id="dpid" [ngClass]="{ 'is-invalid': submitted && f.dpid.errors }" required>
+                <div *ngIf="sdnControllerForm.invalid" class="invalid-feedback">
+                    <div *ngIf="f.dpid.errors && f.dpid.value">{{'DOMVALIDATIONS.INVALIDDPID' | translate}}</div>
+                </div>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="version">{{'VERSION' | translate}}</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'VERSION' | translate}}" type="text"
+                    formControlName="version" id="version">
+            </div>
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+        <button type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+    </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
diff --git a/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.scss b/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.ts b/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.ts
new file mode 100644 (file)
index 0000000..75fc854
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file SDN Controller Component.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, Injector, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA, SDN_TYPES, TYPESECTION } from 'CommonModel';
+import { environment } from 'environment';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes NewSDNControllerComponent.html as template url
+ */
+@Component({
+  templateUrl: './NewSDNControllerComponent.html',
+  styleUrls: ['./NewSDNControllerComponent.scss']
+})
+/** Exporting a class @exports NewSDNControllerComponent */
+export class NewSDNControllerComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Set SDN Type select to empty @public */
+  public sdnTypeMod: string = null;
+
+  /** Setting SDN types in array @public */
+  public sdnType: TYPESECTION[];
+
+  /** New SDN controller form controls using formgroup @public */
+  public sdnControllerForm: FormGroup;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.sharedService = this.injector.get(SharedService);
+
+    /** Initializing Form Action */
+    this.sdnControllerForm = this.formBuilder.group({
+      name: ['', Validators.required],
+      type: ['', Validators.required],
+      user: ['', Validators.required],
+      password: ['', Validators.required],
+      ip: ['', Validators.pattern(this.sharedService.REGX_IP_PATTERN)],
+      port: ['', Validators.pattern(this.sharedService.REGX_PORT_PATTERN)],
+      dpid: ['', Validators.pattern(this.sharedService.REGX_DPID_PATTERN)],
+      version: ['']
+    });
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.sdnControllerForm.controls; }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.sdnType = SDN_TYPES;
+    this.headers = new HttpHeaders({
+      Accept: 'application/json',
+      'Content-Type': 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+  }
+
+  /** On modal submit sdnControllerFormSubmit will called @public */
+  public sdnControllerFormSubmit(): void {
+    this.submitted = true;
+    const modalData: MODALCLOSERESPONSEDATA = {
+      message: 'Done'
+    };
+    this.sharedService.cleanForm(this.sdnControllerForm);
+    if (!this.sdnControllerForm.invalid) {
+      this.isLoadingResults = true;
+      const apiURLHeader: APIURLHEADER = {
+        url: environment.SDNCONTROLLER_URL,
+        httpOptions: { headers: this.headers }
+      };
+      if (this.sdnControllerForm.value.port) {
+        this.sdnControllerForm.value.port = +this.sdnControllerForm.value.port;
+      }
+      if (this.sdnControllerForm.value.version === '') {
+        this.sdnControllerForm.value.version = undefined;
+      }
+      this.restService.postResource(apiURLHeader, this.sdnControllerForm.value)
+        .subscribe((result: {}) => {
+          this.activeModal.close(modalData);
+          this.isLoadingResults = false;
+          this.notifierService.notify('success', this.translateService.instant('PAGE.SDNCONTROLLER.CREATEDSUCCESSFULLY'));
+        }, (error: ERRORDATA) => {
+          this.restService.handleError(error, 'post');
+          this.isLoadingResults = false;
+        });
+    }
+  }
+}
diff --git a/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.html b/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.html
new file mode 100644 (file)
index 0000000..c316942
--- /dev/null
@@ -0,0 +1,43 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'PAGE.SDNCONTROLLER.REGISTEREDSDNCONTROLLER' | translate}}</div>
+    <span class="button">
+        <button class="btn btn-primary" type="button" placement="top" container="body" ngbTooltip="{{'PAGE.SDNCONTROLLER.NEWSDNCONTROLLER' | translate}}"
+            (click)="composeSDN()">
+            <i class="fas fa-plus-circle" aria-hidden="true"></i>
+            {{'PAGE.SDNCONTROLLER.NEWSDNCONTROLLER' | translate}}
+        </button>
+    </span>
+</div>
+<div class="row mt-2 mb-0 list-utilites-actions">
+    <div class="col-auto mr-auto">
+        <nav class="custom-items-config">
+            <span><i class="fas fa-clock text-warning"></i>{{operationalStateFirstStep}}</span>
+            <span><i class="fas fa-check-circle text-success"></i>{{operationalStateSecondStep}}</span>
+            <span><i class="fas fa-times-circle text-danger"></i>{{operationalStateThirdStep}}</span>
+        </nav>
+    </div>
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.scss b/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.scss
new file mode 100644 (file)
index 0000000..8c2b739
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
diff --git a/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.ts b/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.ts
new file mode 100644 (file)
index 0000000..125d0f4
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file SDN Controller details Component.
+ */
+import { Component, Injector, OnDestroy, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA, SDN_TYPES } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { NewSDNControllerComponent } from 'NewSDNControllerComponent';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SDNControllerActionComponent } from 'SDNControllerActionComponent';
+import { SDNControllerList, SDNControllerModel } from 'SDNControllerModel';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes SDNControllerDetailsComponent.html as template url
+ */
+@Component({
+    templateUrl: './SDNControllerDetailsComponent.html',
+    styleUrls: ['./SDNControllerDetailsComponent.scss']
+})
+/** Exporting a class @exports SDNControllerDetailsComponent */
+export class SDNControllerDetailsComponent implements OnInit, OnDestroy {
+    /** Injector to invoke other services @public */
+    public injector: Injector;
+
+    /** Selected list array @public */
+    public selectList: object[] = [];
+
+    /** Instance component are stored in settings @public */
+    public settings: {} = {};
+
+    /** Contains objects for menu settings @public */
+    public columnList: {} = {};
+
+    /** Data of smarttable populate through LocalDataSource @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+
+    /** operational State init data @public */
+    public operationalStateFirstStep: string = CONFIGCONSTANT.sdnOperationalStateFirstStep;
+
+    /** operational State running data @public */
+    public operationalStateSecondStep: string = CONFIGCONSTANT.sdnOperationalStateStateSecondStep;
+
+    /** operational State failed data @public */
+    public operationalStateThirdStep: string = CONFIGCONSTANT.sdnOperationalStateThirdStep;
+
+    /** Instance of the rest service @private */
+    private restService: RestService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** dataService to pass the data from one component to another @private */
+    private dataService: DataService;
+
+    /** Contains tranlsate instance @private */
+    private translateService: TranslateService;
+
+    /** Formation of appropriate Data for LocalDatasource @private */
+    private sdnData: {}[] = [];
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.translateService = this.injector.get(TranslateService);
+        this.sharedService = this.injector.get(SharedService);
+        this.dataService = this.injector.get(DataService);
+        this.modalService = this.injector.get(NgbModal);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.generateTableColumn();
+        this.generateTableSettings();
+        this.generateData();
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableSettings(): void {
+        this.settings = {
+            columns: this.columnList,
+            actions: { add: false, edit: false, delete: false, position: 'right' },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** Generate smart table row title and filters @public  */
+    public generateTableColumn(): void {
+        this.columnList = {
+            name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' },
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' },
+            type: {
+                title: this.translateService.instant('TYPE'), width: '15%',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: SDN_TYPES
+                    }
+                }
+            },
+            operationalState: {
+                title: this.translateService.instant('OPERATIONALSTATUS'), width: '15%', type: 'html',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: [
+                            { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep },
+                            { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep },
+                            { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep }
+                        ]
+                    }
+                },
+                valuePrepareFunction: (cell: SDNControllerList, row: SDNControllerList): string => {
+                    if (row.operationalState === this.operationalStateFirstStep) {
+                        return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-clock text-warning"></i>
+                        </span>`;
+                    } else if (row.operationalState === this.operationalStateSecondStep) {
+                        return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-check-circle text-success"></i>
+                        </span>`;
+                    } else if (row.operationalState === this.operationalStateThirdStep) {
+                        return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-times-circle text-danger"></i>
+                        </span>`;
+                    } else {
+                        return `<span>${row.operationalState}</span>`;
+                    }
+                }
+            },
+            ip: { title: this.translateService.instant('IP'), width: '15%' },
+            port: { title: this.translateService.instant('PORT'), width: '15%' },
+            Actions: {
+                name: 'Action', width: '5%', filter: false, sort: false, type: 'custom',
+                title: this.translateService.instant('ACTIONS'),
+                valuePrepareFunction: (cell: SDNControllerList, row: SDNControllerList): SDNControllerList => row,
+                renderComponent: SDNControllerActionComponent
+            }
+        };
+    }
+
+    /** smart table listing manipulation @public */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** smart table listing manipulation @public */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'sdn-controller' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** Generate generateSDNData object from loop and return for the datasource @public */
+    public generateSDNList(sdn: SDNControllerModel): SDNControllerList {
+        return {
+            name: sdn.name,
+            identifier: sdn._id,
+            type: sdn.type,
+            operationalState: sdn._admin.operationalState,
+            ip: sdn.ip,
+            port: sdn.port
+        };
+    }
+
+    /** Compose new SDN Controller @public */
+    public composeSDN(): void {
+        const modalRef: NgbModalRef = this.modalService.open(NewSDNControllerComponent, { backdrop: 'static' });
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+
+    /** Fetching the data from server to Load in the smarttable @protected */
+    protected generateData(): void {
+        this.isLoadingResults = true;
+        this.sdnData = [];
+        this.restService.getResource(environment.SDNCONTROLLER_URL).subscribe((sdnDetails: {}[]) => {
+            sdnDetails.forEach((res: SDNControllerModel) => {
+                const sdnDataObj: SDNControllerList = this.generateSDNList(res);
+                this.sdnData.push(sdnDataObj);
+            });
+            if (this.sdnData.length > 0) {
+                this.checkDataClass = 'dataTables_present';
+            } else {
+                this.checkDataClass = 'dataTables_empty';
+            }
+            this.dataSource.load(this.sdnData).then((data: {}) => {
+                this.isLoadingResults = false;
+            }).catch();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+
+}
diff --git a/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.html b/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.html
new file mode 100644 (file)
index 0000000..842d101
--- /dev/null
@@ -0,0 +1,90 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="modal-header">
+  <h4 class="modal-title" id="modal-basic-title">{{'PAGE.SDNCONTROLLER.DETAILS' | translate}}</h4>
+  <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+    <i class="fas fa-times-circle text-danger"></i>
+  </button>
+</div>
+<div class="modal-body modal-body-custom-height p-0">
+  <table class="table table-striped table-layout-fixed mb-0" *ngIf="sdnDetails else noData">
+    <tr>
+      <td colspan="2">
+        <b>{{'ID' | translate}}:</b> {{(sdnDetails._id)?sdnDetails._id:''}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <b>{{'OPERATIONALSTATE' | translate}}:</b>
+        <span class="badge ml-1" [ngClass]="{'badge-info':sdnDetails._admin.operationalState === operationalStateFirstStep,
+          'badge-success':sdnDetails._admin.operationalState === operationalStateSecondStep,
+          'badge-danger':sdnDetails._admin.operationalState === operationalStateThirdStep}">
+          {{(sdnDetails._admin.operationalState)?sdnDetails._admin.operationalState:''}}</span>
+      </td>
+      <td>
+        <b>{{'IP' | translate}}:</b> {{(sdnDetails.ip)?sdnDetails.ip:''}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <b>{{'NAME' | translate}}:</b> {{(sdnDetails.name)?sdnDetails.name:''}}
+      </td>
+      <td>
+        <b>{{'PORT' | translate}}:</b> {{(sdnDetails.port)?sdnDetails.port:''}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <b>{{'TYPE' | translate}}:</b> {{(sdnDetails.type)?sdnDetails.type:''}}
+      </td>
+      <td>
+        <b>{{'VERSION' | translate}}:</b> {{(sdnDetails.version)?sdnDetails.version:''}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <b>{{'USER' | translate}}:</b> {{(sdnDetails.user)?sdnDetails.user:''}}
+      </td>
+      <td>
+        <b>{{'CREATED' | translate}}:</b>
+        {{(sdnDetails._admin.created)?this.sharedService.convertEpochTime(sdnDetails._admin.created):''}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <b>{{'PAGE.SDNCONTROLLER.DPID' | translate}}:</b> {{(sdnDetails.dpid)?sdnDetails.dpid:''}}
+      </td>
+      <td>
+        <b>{{'MODIFIED' | translate}}:</b>
+        {{(sdnDetails._admin.modified)?this.sharedService.convertEpochTime(sdnDetails._admin.modified):''}}
+      </td>
+    </tr>
+    <tr>
+      <td colspan="2">
+        <b>{{'DEPLOYED' | translate}}</b> <br>
+        <b>{{'PAGE.SDNCONTROLLER.RO' | translate}}:</b> {{(sdnDetails._admin.deployed.RO)?sdnDetails._admin.deployed.RO:''}}
+        <br>
+      </td>
+    </tr>
+  </table>
+  <ng-template #noData>{{'NODATAERROR' | translate}}</ng-template>
+</div>
+<div class="modal-footer">
+  <button (click)="activeModal.close()" class="btn btn-danger">{{'CANCEL' | translate}}</button>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.scss b/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.scss
new file mode 100644 (file)
index 0000000..c68960c
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.ts b/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.ts
new file mode 100644 (file)
index 0000000..8c23d1d
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Info SDN Controller Info Component
+ */
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { CONFIGCONSTANT, ERRORDATA, URLPARAMS } from 'CommonModel';
+import { environment } from 'environment';
+import { RestService } from 'RestService';
+import { SDNControllerModel } from 'SDNControllerModel';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes SDNControllerInfoComponent.html as template url
+ */
+@Component({
+  templateUrl: './SDNControllerInfoComponent.html',
+  styleUrls: ['./SDNControllerInfoComponent.scss']
+})
+/** Exporting a class @exports SDNControllerInfoComponent */
+export class SDNControllerInfoComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Input contains component objects @public */
+  @Input() public params: URLPARAMS;
+
+  /** Contains sdn details @public */
+  public sdnDetails: SDNControllerModel;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingResults: boolean = true;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** operational State init data @public */
+  public operationalStateFirstStep: string = CONFIGCONSTANT.sdnOperationalStateFirstStep;
+
+  /** operational State running data @public */
+  public operationalStateSecondStep: string = CONFIGCONSTANT.sdnOperationalStateStateSecondStep;
+
+  /** operational State failed data @public */
+  public operationalStateThirdStep: string = CONFIGCONSTANT.sdnOperationalStateThirdStep;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.generateData();
+  }
+
+  /** Generate Data function @public */
+  public generateData(): void {
+    this.restService.getResource(environment.SDNCONTROLLER_URL + '/' + this.params.id).subscribe((sdnDetails: SDNControllerModel) => {
+      this.sdnDetails = sdnDetails;
+      this.isLoadingResults = false;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+  });
+  }
+}
diff --git a/src/app/user-settings/UserSettingsComponent.html b/src/app/user-settings/UserSettingsComponent.html
new file mode 100644 (file)
index 0000000..2f878a3
--- /dev/null
@@ -0,0 +1,44 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="usersettingsForm" (ngSubmit)="usersettingsSubmit();">
+    <div class="modal-header">
+        <h4 class="modal-title" id="modal-basic-title">{{'PAGE.DASHBOARD.USERSETTINGS' | translate}}</h4>
+        <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+            <i class="fas fa-times-circle text-danger"></i>
+        </button>
+    </div>
+    <div class="modal-body user-settings">
+        <label class="col-sm-12 col-form-label mandatory-label" [ngClass]="{'text-danger': usersettingsForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+        <div class="row form-group">
+            <div class="col-sm-3">
+                <label for="selectedLanguage">{{'PAGE.USERSETTINGS.LANGUAGE' | translate}}* </label>
+            </div>
+            <div class="col-sm-9">
+                <ng-select [items]="languageList" bindLabel="language" bindValue="code"
+                    placeholder="{{'SELECT' | translate}} {{'PAGE.USERSETTINGS.LANGUAGE' | translate}}"
+                    formControlName="selectedLanguage" id="selectedLanguage"
+                    [ngClass]="{ 'is-invalid': submitted && f.selectedLanguage.errors }" required>
+                </ng-select>
+            </div>
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+        <button type="submit" class="btn btn-primary">{{'SAVE' | translate}}</button>
+    </div>
+</form>
\ No newline at end of file
diff --git a/src/app/user-settings/UserSettingsComponent.scss b/src/app/user-settings/UserSettingsComponent.scss
new file mode 100644 (file)
index 0000000..bdfb8f2
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import '../../assets/scss/mixins/mixin';
+.user-settings{
+    form label{
+        @include margin-value-percentage(0.5rem, auto, auto, auto);
+    }
+}
\ No newline at end of file
diff --git a/src/app/user-settings/UserSettingsComponent.ts b/src/app/user-settings/UserSettingsComponent.ts
new file mode 100644 (file)
index 0000000..19b525f
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file User Settings Modal Component.
+ */
+
+import { Component, Injector, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes UserSettingsComponent.html as template url
+ */
+@Component({
+    templateUrl: './UserSettingsComponent.html',
+    styleUrls: ['./UserSettingsComponent.scss']
+})
+/** Exporting a class @exports UserSettingsComponent */
+export class UserSettingsComponent implements OnInit {
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** Supported language list for the dropdown */
+    public languageList: {}[];
+
+    /** FormGroup instance added to the form @ html @public */
+    public usersettingsForm: FormGroup;
+
+    /** Instance for active modal service @public */
+    public activeModal: NgbActiveModal;
+
+    /** Form submission Add */
+    public submitted: boolean = false;
+
+    /** FormBuilder instance added to the formBuilder @private */
+    private formBuilder: FormBuilder;
+
+    /** Instance for translate service @private */
+    private translateService: TranslateService;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.formBuilder = this.injector.get(FormBuilder);
+        this.activeModal = this.injector.get(NgbActiveModal);
+        this.translateService = this.injector.get(TranslateService);
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.initializeSettings();
+    }
+
+    /** Initialize user's settings */
+    public initializeSettings(): void {
+        this.languageList = this.sharedService.languageCodeList();
+        /** Initializing Form Action */
+        this.usersettingsForm = this.formBuilder.group({
+            selectedLanguage: [null, [Validators.required]]
+        });
+        const setLanguage: string = localStorage.getItem('languageCode');
+        if (setLanguage !== null && this.validateLanguageList(setLanguage)) {
+            // tslint:disable-next-line:no-backbone-get-set-outside-model
+            this.usersettingsForm.get('selectedLanguage').setValue(setLanguage);
+        } else {
+            // tslint:disable-next-line:no-backbone-get-set-outside-model
+            this.usersettingsForm.get('selectedLanguage').setValue('en');
+        }
+    }
+
+    /** convenience getter for easy access to form fields */
+    get f(): FormGroup['controls'] { return this.usersettingsForm.controls; }
+
+    /** On modal submit UserSettingsSubmit will called @public */
+    public usersettingsSubmit(): void {
+        this.submitted = true;
+        if (!this.usersettingsForm.invalid) {
+            const selectedLanguage: string = this.usersettingsForm.value.selectedLanguage;
+            localStorage.setItem('languageCode', this.usersettingsForm.value.selectedLanguage);
+            this.translateService.use(selectedLanguage);
+            location.reload();
+        }
+    }
+    /** Validate language code in the language list @private */
+    private validateLanguageList(setLanguage: string): boolean {
+        return this.languageList.some((item: { code: string }) => item.code === setLanguage);
+    }
+}
diff --git a/src/app/users/UsersComponent.html b/src/app/users/UsersComponent.html
new file mode 100644 (file)
index 0000000..3f96ff8
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<router-outlet></router-outlet>
\ No newline at end of file
diff --git a/src/app/users/UsersComponent.scss b/src/app/users/UsersComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/users/UsersComponent.ts b/src/app/users/UsersComponent.ts
new file mode 100644 (file)
index 0000000..178b979
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file users details Component.
+ */
+import { Component, Injector } from '@angular/core';
+import { Router, RouterEvent } from '@angular/router';
+
+/**
+ * Creating component
+ * @Component takes UsersComponent.html as template url
+ */
+@Component({
+    templateUrl: './UsersComponent.html',
+    styleUrls: ['./UsersComponent.scss']
+})
+/** Exporting a class @exports UsersComponent */
+export class UsersComponent {
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** Holds teh instance of AuthService class of type AuthService @private */
+    private router: Router;
+
+    // creates packages component
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.router = this.injector.get(Router);
+        this.router.events.subscribe((event: RouterEvent) => {
+            this.redirectToList(event.url);
+        });
+    }
+
+    /** Return to list NS Package List */
+    public redirectToList(getURL: string): void {
+        if (getURL === '/users') {
+            this.router.navigate(['/users/details']).catch();
+        }
+    }
+}
diff --git a/src/app/users/UsersModule.ts b/src/app/users/UsersModule.ts
new file mode 100644 (file)
index 0000000..2014c48
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Users module.
+ */
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { NgModule } from '@angular/core';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { FormsModule } from '@angular/forms';
+import { ReactiveFormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgSelectModule } from '@ng-select/ng-select';
+import { TranslateModule } from '@ngx-translate/core';
+import { AddEditUserComponent } from 'AddEditUserComponent';
+import { DataService } from 'DataService';
+import { LoaderModule } from 'LoaderModule';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { PagePerRowModule } from 'PagePerRowModule';
+import { PageReloadModule } from 'PageReloadModule';
+import { ProjectRoleComponent } from 'ProjectRoleComponent';
+import { UserDetailsComponent } from 'UserDetailsComponent';
+import { UsersComponent } from 'UsersComponent';
+
+/** const values for dashboard Routes */
+const routes: Routes = [
+    {
+        path: '',
+        component: UsersComponent,
+        children: [
+            {
+                path: 'details',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.USERS', url: null }]
+                },
+                component: UserDetailsComponent
+            }
+        ]
+    }
+];
+
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+    imports: [ReactiveFormsModule, FormsModule, CommonModule, HttpClientModule, Ng2SmartTableModule, TranslateModule,
+        FlexLayoutModule, NgSelectModule, NgbModule, RouterModule.forChild(routes), PagePerRowModule, LoaderModule, PageReloadModule],
+    declarations: [UsersComponent, UserDetailsComponent, AddEditUserComponent, ProjectRoleComponent],
+    providers: [DataService],
+    entryComponents: [AddEditUserComponent, ProjectRoleComponent]
+})
+/** Exporting a class @exports UsersModule */
+export class UsersModule {
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        // Empty Block
+    }
+}
diff --git a/src/app/users/add-user/AddEditUserComponent.html b/src/app/users/add-user/AddEditUserComponent.html
new file mode 100644 (file)
index 0000000..b4d9d28
--- /dev/null
@@ -0,0 +1,89 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="userForm" (ngSubmit)="userAction(userType)" autocomplete="off">
+  <div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{userTitle}}</h4>
+    <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+      <i class="fas fa-times-circle text-danger"></i>
+    </button>
+  </div>
+  <div class="modal-body">
+    <label class="col-sm-12 col-form-label mandatory-label"
+      [ngClass]="{'text-danger': userForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+    <div class="row form-group" *ngIf="userType === 'add' || userType === 'editUserName'">
+      <div class="col-sm-4">
+        <label for="userName">{{'PAGE.USERS.USERNAME' | translate}} *</label>
+      </div>
+      <div class="col-sm-8">
+        <input class="form-control" placeholder="{{'PAGE.USERS.USERNAME' | translate}}" type="text"
+          formControlName="userName" id="userName" [ngClass]="{ 'is-invalid': submitted && f.userName.errors }"
+          required>
+      </div>
+      <div *ngIf="submitted && f.userName.errors" class="input-validation-msg">
+        <div *ngIf="f.userName.errors.minlength">
+          {{'PAGE.LOGIN.USERNAMEMINLENGTHVALIDMESSAGE' | translate}} </div>
+      </div>
+    </div>
+    <ng-container *ngIf="userType === 'add' || userType === 'editPassword'">
+      <div class="row form-group">
+        <div class="col-sm-4">
+          <label for="password">{{'PAGE.USERS.PASSWORD' | translate}} *</label>
+        </div>
+        <div class="col-sm-8">
+          <input class="form-control" placeholder="{{'PAGE.USERS.PASSWORD' | translate}}" minlength="8" maxlength="50"
+            type="password" formControlName="password" id="password" autocomplete="new-password"
+            [ngClass]="{ 'is-invalid': submitted && f.password.errors }" required>
+        </div>
+        <div class="input-validation-msg">
+          <div *ngIf="userForm?.controls.password.hasError('minlength') || userForm?.controls.password.errors?.pattern">
+            {{'PAGE.LOGIN.PASSWORDMINLENGTHVALIDMESSAGE' | translate}} </div>
+        </div>
+      </div>
+      <div class="row form-group">
+        <div class="col-sm-4">
+          <label for="password2">{{'PAGE.USERS.CONFPASSWORD' | translate}} *</label>
+        </div>
+        <div class="col-sm-8">
+          <input class="form-control" placeholder="{{'PAGE.USERS.CONFPASSWORD' | translate}}" type="password"
+            formControlName="password2" id="password2" autocomplete="new-password"
+            [ngClass]="{ 'is-invalid': submitted && f.password2.errors }" required>
+          <div class="mr-top-5" *ngIf="userForm?.controls.password.value && userForm?.controls.password2.value">
+            <i class="far"
+              [ngClass]="{'fa-times-circle text-danger':userForm?.controls.password.value !== userForm?.controls.password2.value,
+            'fa-check-circle text-success':userForm?.controls.password.value === userForm?.controls.password2.value}"></i>
+            {{'PAGE.USERS.PASSWORDMATCH' | translate}}
+          </div>
+        </div>
+      </div>
+    </ng-container>
+    <div class="form-group row" *ngIf="userType === 'add'">
+      <label class="col-sm-4 col-form-label">{{'DOMAIN' | translate}} {{'NAME' | translate}}</label>
+      <div class="col-sm-8">
+        <ng-select [clearable]="false" placeholder="{{'SELECT' | translate}}" [items]="domains" bindLabel="text"
+          bindValue="id" formControlName="domain_name" id="domain_name"
+          [ngClass]="{ 'is-invalid': submitted && f.domain_name.errors }"></ng-select>
+      </div>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+    <button *ngIf="userType==='add'" type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+    <button *ngIf="userType!=='add'" type="submit" class="btn btn-primary">{{'APPLY' | translate}}</button>
+  </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/users/add-user/AddEditUserComponent.scss b/src/app/users/add-user/AddEditUserComponent.scss
new file mode 100644 (file)
index 0000000..05f2819
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import '../../../assets/scss/mixins/mixin';
+@import '../../../assets/scss/variable';
+.input-validation-msg{
+    color:$red;
+    text-align:left;
+    @include padding-value(0, 0, 0, 10);
+    @include font(null, 11px, null);
+}
\ No newline at end of file
diff --git a/src/app/users/add-user/AddEditUserComponent.ts b/src/app/users/add-user/AddEditUserComponent.ts
new file mode 100644 (file)
index 0000000..61540e8
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Add Edit Component.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { AuthenticationService } from 'AuthenticationService';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { environment } from 'environment';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes AddEditUserComponent.html as template url
+ */
+@Component({
+  templateUrl: './AddEditUserComponent.html',
+  styleUrls: ['./AddEditUserComponent.scss']
+})
+/** Exporting a class @exports AddEditUserComponent */
+export class AddEditUserComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** FormGroup user Edit Account added to the form @ html @public */
+  public userForm: FormGroup;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Input contains Modal dialog component Instance @public */
+  @Input() public userTitle: string;
+
+  /** Input contains Modal dialog component Instance @public */
+  @Input() public userType: string;
+
+  /** Input contains Modal dialog component Instance @public */
+  @Input() public userID: string;
+
+  /** Input contains Modal dialog component Instance @public */
+  @Input() public userName: string;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Holds list of domains @public */
+  public domains: {}[] = [];
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** ModalData instance of modal @private  */
+  private modalData: MODALCLOSERESPONSEDATA;
+
+  /** Utilizes auth service for any auth operations @private */
+  private authService: AuthenticationService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+    this.authService = this.injector.get(AuthenticationService);
+
+    /** Initializing Form Action */
+    this.userForm = this.formBuilder.group({
+      userName: ['', Validators.required],
+      password: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_PASSWORD_PATTERN)]],
+      password2: [null, Validators.required],
+      domain_name: [null]
+    });
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.userForm.controls; }
+
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.headers = new HttpHeaders({
+      'Content-Type': 'application/json',
+      Accept: 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    if (this.userType === 'add') {
+      this.getDomainName();
+    } else if (this.userType === 'editUserName') {
+      this.userForm.patchValue({ userName: this.userName });
+    }
+  }
+
+  /** On modal submit users acction will called @public */
+  public userAction(userType: string): void {
+    if (userType === 'editPassword') {
+      this.getFormControl('userName').setValidators([]);
+      this.getFormControl('userName').updateValueAndValidity();
+    } else if (userType === 'editUserName') {
+      this.getFormControl('password').setValidators([]);
+      this.getFormControl('password').updateValueAndValidity();
+      this.getFormControl('password2').setValidators([]);
+      this.getFormControl('password2').updateValueAndValidity();
+    }
+    this.submitted = true;
+    this.modalData = {
+      message: 'Done'
+    };
+    this.sharedService.cleanForm(this.userForm);
+    if (!this.userForm.invalid) {
+      if (this.userForm.value.password !== this.userForm.value.password2) {
+        this.notifierService.notify('error', this.translateService.instant('PAGE.USERS.PASSWORDCONFLICT'));
+        return;
+      }
+      if (userType === 'add') {
+        this.addUser();
+      } else if (userType === 'editUserName' || userType === 'editPassword') {
+        this.editUser();
+      }
+    }
+  }
+
+  /** Add user @public */
+  public addUser(): void {
+    this.isLoadingResults = true;
+    const payLoad: {} = JSON.stringify({
+      username: (this.userForm.value.userName).toLowerCase(),
+      password: (this.userForm.value.password),
+      domain_name: !isNullOrUndefined(this.userForm.value.domain_name) ? this.userForm.value.domain_name : undefined
+    });
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.USERS_URL,
+      httpOptions: { headers: this.headers }
+    };
+    this.restService.postResource(apiURLHeader, payLoad).subscribe((result: {}) => {
+      this.activeModal.close(this.modalData);
+      this.isLoadingResults = false;
+      this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.CREATEDSUCCESSFULLY'));
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'post');
+      this.isLoadingResults = false;
+    });
+  }
+
+  /** Edit user @public */
+  public editUser(): void {
+    this.isLoadingResults = true;
+    const payLoad: { username?: string, password?: string } = {};
+    if (this.userType === 'editPassword') {
+      payLoad.password = (this.userForm.value.password);
+    } else {
+      payLoad.username = this.userForm.value.userName.toLowerCase();
+    }
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.USERS_URL + '/' + this.userID,
+      httpOptions: { headers: this.headers }
+    };
+    this.restService.patchResource(apiURLHeader, payLoad).subscribe((result: {}) => {
+      this.checkUsername(payLoad);
+      this.activeModal.close(this.modalData);
+      this.isLoadingResults = false;
+      this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.EDITEDSUCCESSFULLY'));
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'put');
+      this.isLoadingResults = false;
+    });
+  }
+  /** Get domain name @private */
+  private getDomainName(): void {
+    this.isLoadingResults = true;
+    this.restService.getResource(environment.DOMAIN_URL).subscribe((domains: { project_domain_name: string, user_domain_name: string }) => {
+      let domainNames: string[] = [];
+      if (!isNullOrUndefined(domains.project_domain_name)) {
+        domainNames = domainNames.concat(domains.project_domain_name.split(','));
+      }
+      if (!isNullOrUndefined(domains.user_domain_name)) {
+        domainNames = domainNames.concat(domains.user_domain_name.split(','));
+      }
+      domainNames = Array.from(new Set(domainNames));
+      this.checkDomainNames(domainNames);
+      this.isLoadingResults = false;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+    });
+  }
+
+  /** Check the domain names and create modal for domain select @private */
+  private checkDomainNames(domainNames: string[]): void {
+    if (domainNames.length > 0) {
+      domainNames.forEach((domainName: string) => {
+        if (!domainName.endsWith(':ro')) {
+          this.domains.push({ id: domainName, text: domainName });
+        }
+      });
+    }
+  }
+
+  /** Used to get the AbstractControl of controlName passed @private */
+  private getFormControl(controlName: string): AbstractControl {
+    return this.userForm.controls[controlName];
+  }
+
+  /** Method to check loggedin username and update  @private */
+  private checkUsername(payLoad: { username?: string }): void {
+    const logUsername: string = localStorage.getItem('username');
+    if (this.userType === 'editUserName' && logUsername === this.userName) {
+      this.authService.userName.next(payLoad.username);
+      localStorage.setItem('username', payLoad.username);
+    }
+  }
+}
diff --git a/src/app/users/project-role/ProjectRoleComponent.html b/src/app/users/project-role/ProjectRoleComponent.html
new file mode 100644 (file)
index 0000000..c093f37
--- /dev/null
@@ -0,0 +1,60 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{userTitle}}</h4>
+    <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+        <i class="fas fa-times-circle text-danger"></i>
+    </button>
+</div>
+<form [formGroup]="projectRoleForm" (ngSubmit)="addProjectRole()">
+    <div class="modal-body" *ngIf="userDetails" formArrayName="project_role_mappings">
+        <div class="form-group row p-2 bg-light text-white projects-roles-head text-white justify-content-end">
+            <div class="col-4">
+                <button type="button" class="btn btn-primary" (click)="addMapping()">
+                    <i class="fas fa-plus-circle"></i> {{'PAGE.USERS.ADDMAPPINGS' | translate}}</button>
+            </div>
+        </div>
+        <label class="col-sm-12 col-form-label mandatory-label" [ngClass]="{'text-danger': projectRoleForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+        <div *ngFor="let params of getControls(); let i = index;" [formGroupName]="i">
+            <div class="form-group row">
+                <label class="col-sm-2 col-form-label" for="project_{{i}}">{{'PROJECT' | translate}}*</label>
+                <div class="col-sm-3">
+                    <ng-select placeholder="{{'SELECT' | translate}}" [items]="projects" bindLabel="name"
+                        bindValue="name" formControlName="project_name" id="project_{{i}}"
+                        [ngClass]="{ 'is-invalid': submitted && params.controls.project_name.errors }"></ng-select>
+                </div>
+                <label class="col-sm-2 col-form-label" for="roles_{{i}}">{{'ROLES' | translate}}*</label>
+                <div class="col-sm-4">
+                    <ng-select placeholder="{{'SELECT' | translate}}" [items]="roles" bindLabel="name" bindValue="name"
+                        formControlName="role_name" id="roles_{{i}}"
+                        [ngClass]="{ 'is-invalid': submitted && params.controls.role_name.errors }"></ng-select>
+                </div>
+                <div class="col-sm-1">
+                    <button type="button" class="btn btn-sm btn-danger remove-mapping" (click)="removeMapping(i)">
+                        <i class="fas fa-times-circle"></i>
+                    </button>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+        <button type="submit" class="btn btn-primary">{{'APPLY' | translate}}</button>
+    </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/users/project-role/ProjectRoleComponent.scss b/src/app/users/project-role/ProjectRoleComponent.scss
new file mode 100644 (file)
index 0000000..031e56e
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/users/project-role/ProjectRoleComponent.ts b/src/app/users/project-role/ProjectRoleComponent.ts
new file mode 100644 (file)
index 0000000..f5bb772
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Project Role Component.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { environment } from 'environment';
+import { ProjectData } from 'ProjectModel';
+import { ProjectService } from 'ProjectService';
+import { RestService } from 'RestService';
+import { RoleData } from 'RolesModel';
+import { ProjectRoleMappings, UserDetail, UserRoleMap } from 'UserModel';
+
+/**
+ * Creating component
+ * @Component takes ProjectRole.html as template url
+ */
+@Component({
+  templateUrl: './ProjectRoleComponent.html',
+  styleUrls: ['./ProjectRoleComponent.scss']
+})
+/** Exporting a class @exports ProjectRoleComponent */
+export class ProjectRoleComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** FormGroup user Edit Account added to the form @ html @public */
+  public projectRoleForm: FormGroup;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Input contains Modal dialog component Instance @private */
+  @Input() public userTitle: string;
+
+  /** Input contains Modal dialog component Instance @private */
+  @Input() public userID: string;
+
+  /** Contains user details information @public */
+  public userDetails: UserDetail;
+
+  /** Project Role Mapping @public */
+  public projectRoleMap: UserRoleMap = {};
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Contains project information @public */
+  public projects: ProjectData[] = [];
+
+  /** Contains roles information @public */
+  public roles: RoleData[] = [];
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Project Role Form array @private */
+  private projectRoleFormArray: FormArray;
+
+  /** Holds all project details @private */
+  private projectService: ProjectService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.projectService = this.injector.get(ProjectService);
+    this.initializeForm();
+  }
+
+  /** Generate primitive params @public */
+  get projectRoleParamsBuilder(): FormGroup {
+    return this.formBuilder.group({
+      project_name: [null, [Validators.required]],
+      role_name: [null, [Validators.required]]
+    });
+  }
+
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.headers = new HttpHeaders({
+      'Content-Type': 'application/json',
+      Accept: 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    this.getProjects();
+    this.generateData();
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.projectRoleForm.controls; }
+
+  /** Initializing Form Action  @public */
+  public initializeForm(): void {
+    this.projectRoleForm = this.formBuilder.group({
+      project_role_mappings: this.formBuilder.array([])
+    });
+  }
+
+  /** Handle FormArray Controls @public */
+  public getControls(): AbstractControl[] {
+    // tslint:disable-next-line:no-backbone-get-set-outside-model
+    return (this.projectRoleForm.get('project_role_mappings') as FormArray).controls;
+  }
+
+  /** Fetching the data from server to Load in the smarttable @public */
+  public generateData(): void {
+    if (this.userID !== '') {
+      this.isLoadingResults = true;
+      this.restService.getResource(environment.USERS_URL + '/' + this.userID).subscribe((userDetails: UserDetail) => {
+        this.userDetails = userDetails;
+        this.loadMapping();
+        this.isLoadingResults = false;
+      }, (error: ERRORDATA) => {
+        this.isLoadingResults = false;
+        this.restService.handleError(error, 'get');
+      });
+    }
+  }
+  /** Fetching the projects information @public */
+  public getProjects(): void {
+    this.isLoadingResults = true;
+    this.restService.getResource(environment.PROJECTS_URL).subscribe((projectsData: ProjectData[]) => {
+      this.projects = projectsData;
+      this.getRoles();
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      this.restService.handleError(error, 'get');
+    });
+  }
+
+  /** Fetching the Roles information @public */
+  public getRoles(): void {
+    this.restService.getResource(environment.ROLES_URL).subscribe((rolesData: RoleData[]) => {
+      this.roles = rolesData;
+      this.isLoadingResults = false;
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      this.restService.handleError(error, 'get');
+    });
+  }
+
+  /** Set all roles and project values to the form @public */
+  public loadMapping(): void {
+    this.userDetails.project_role_mappings.forEach((data: ProjectRoleMappings) => {
+      // tslint:disable-next-line:no-backbone-get-set-outside-model
+      this.projectRoleFormArray = this.projectRoleForm.get('project_role_mappings') as FormArray;
+      this.projectRoleFormArray.push(this.projectRoleParamsBuilder);
+    });
+    this.projectRoleForm.patchValue(this.userDetails);
+  }
+
+  /** Remove project and roles from the list @public */
+  public removeMapping(index: number): void {
+    this.projectRoleFormArray.removeAt(index);
+  }
+
+  /** Submit project and roles @public */
+  public addProjectRole(): void {
+    this.submitted = true;
+    const modalData: MODALCLOSERESPONSEDATA = {
+      message: 'Done'
+    };
+    if (this.projectRoleForm.invalid) { return; }
+    const apiURLHeader: APIURLHEADER = {
+      url: environment.USERS_URL + '/' + this.userID
+    };
+    this.projectRoleMap.project_role_mappings = [];
+    this.projectRoleForm.value.project_role_mappings.forEach((res: ProjectRoleMappings) => {
+      this.projectRoleMap.project_role_mappings.push({ project: res.project_name, role: res.role_name });
+    });
+    if (this.projectRoleMap.project_role_mappings.length !== 0) {
+      this.isLoadingResults = true;
+      this.restService.patchResource(apiURLHeader, this.projectRoleMap).subscribe((result: {}) => {
+        this.isLoadingResults = false;
+        this.activeModal.close(modalData);
+        this.projectService.setHeaderProjects();
+        this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.EDITEDSUCCESSFULLY'));
+      }, (error: ERRORDATA) => {
+        this.isLoadingResults = false;
+        this.restService.handleError(error, 'patch');
+      });
+    } else {
+      this.notifierService.notify('error', this.translateService.instant('PAGE.USERS.EDITPROJECTROLEERROR'));
+    }
+  }
+
+  /** Add extra mapping and set empty project and roles @public */
+  public addMapping(): void {
+    // tslint:disable-next-line:no-backbone-get-set-outside-model
+    this.projectRoleFormArray = this.projectRoleForm.get('project_role_mappings') as FormArray;
+    this.projectRoleFormArray.push(this.projectRoleParamsBuilder);
+  }
+}
diff --git a/src/app/users/user-details/UserDetailsComponent.html b/src/app/users/user-details/UserDetailsComponent.html
new file mode 100644 (file)
index 0000000..9d11186
--- /dev/null
@@ -0,0 +1,36 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+  <div class="d-flex align-items-center header-style">{{'PAGE.DASHBOARD.USERS' | translate}}</div>
+  <span class="button">
+    <button class="btn btn-primary" type="button" (click)="composeUser()" placement="top" container="body"
+      ngbTooltip="{{'PAGE.USERS.CREATEUSER' | translate}}">
+      <i class="fas fa-plus-circle" aria-hidden="true"></i>
+      {{'PAGE.USERS.CREATEUSER' | translate}}
+    </button>
+  </span>
+</div>
+<div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+  <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+  <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+  <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+  </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/users/user-details/UserDetailsComponent.scss b/src/app/users/user-details/UserDetailsComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/users/user-details/UserDetailsComponent.ts b/src/app/users/user-details/UserDetailsComponent.ts
new file mode 100644 (file)
index 0000000..a4bedd5
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file users details Component.
+ */
+import { Component, Injector, OnDestroy, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { AddEditUserComponent } from 'AddEditUserComponent';
+import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { LocalDataSource } from 'ng2-smart-table';
+import { ProjectService } from 'ProjectService';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+import { UserData, UserDetail } from 'UserModel';
+import { UsersActionComponent } from 'UsersActionComponent';
+
+/**
+ * Creating component
+ * @Component takes UserDetailsComponent.html as template url
+ */
+@Component({
+  templateUrl: './UserDetailsComponent.html',
+  styleUrls: ['./UserDetailsComponent.scss']
+})
+/** Exporting a class @exports UserDetailsComponent */
+export class UserDetailsComponent implements OnInit, OnDestroy {
+  /** Data of smarttable populate through LocalDataSource @public */
+  public dataSource: LocalDataSource = new LocalDataSource();
+
+  /** handle translate @public */
+  public translateService: TranslateService;
+
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Settings for smarttable to populate the table with columns @public */
+  public settings: object = {};
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = true;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Class for empty and present data @public */
+  public checkDataClass: string;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** dataService to pass the data from one component to another @private */
+  private dataService: DataService;
+
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  /** Formation of appropriate Data for LocalDatasource @private */
+  private userData: {}[] = [];
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Holds all project details */
+  private projectService: ProjectService;
+
+  /** holds the project information @private */
+  private projectList: {}[] = [];
+
+  /** Columns list of the smart table @public */
+  private columnLists: object = {};
+
+  /** Instance of subscriptions @private */
+  private generateDataSub: Subscription;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.dataService = this.injector.get(DataService);
+    this.sharedService = this.injector.get(SharedService);
+    this.modalService = this.injector.get(NgbModal);
+    this.projectService = this.injector.get(ProjectService);
+    this.translateService = this.injector.get(TranslateService);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.projectService.getAllProjects().subscribe((projects: {}[]) => {
+      this.projectList = projects;
+    });
+    this.generateColumns();
+    this.generateSettings();
+    this.generateData();
+    this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+  }
+
+  /** smart table Header Colums @public */
+  public generateColumns(): void {
+    this.columnLists = {
+      username: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' },
+      projects: { title: this.translateService.instant('PAGE.DASHBOARD.PROJECTS'), width: '25%' },
+      identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' },
+      modified: { title: this.translateService.instant('MODIFIED'), width: '15%' },
+      created: { title: this.translateService.instant('CREATED'), width: '15%' },
+      Actions: {
+        name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom',
+        valuePrepareFunction: (cell: UserData, row: UserData): UserData => row,
+        renderComponent: UsersActionComponent
+      }
+    };
+  }
+
+  /** smart table Data Settings @public */
+  public generateSettings(): void {
+    this.settings = {
+      edit: { editButtonContent: '<i class="fa fa-edit" title="Edit"></i>', confirmSave: true },
+      delete: { deleteButtonContent: '<i class="far fa-trash-alt" title="delete"></i>', confirmDelete: true },
+      columns: this.columnLists,
+      actions: { add: false, edit: false, delete: false, position: 'right' },
+      attr: this.sharedService.tableClassConfig(),
+      pager: this.sharedService.paginationPagerConfig(),
+      noDataMessage: this.translateService.instant('NODATAMSG')
+    };
+  }
+
+  /** on Navigate to Composer Page @public */
+  public composeUser(): void {
+    const modalRef: NgbModalRef = this.modalService.open(AddEditUserComponent, { backdrop: 'static' });
+    modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.NEWUSER');
+    modalRef.componentInstance.userType = 'add';
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+
+  /** smart table listing manipulation @private */
+  public onChange(perPageValue: number): void {
+    this.dataSource.setPaging(1, perPageValue, true);
+  }
+
+  /** OnUserRowSelect function @private */
+  public onUserRowSelect(event: MessageEvent): void {
+    Object.assign(event.data, { page: 'users' });
+    this.dataService.changeMessage(event.data);
+  }
+
+  /** Set up user details @public */
+  public setUserDetails(userData: UserDetail): void {
+    const userDataObj: UserData = {
+      username: userData.username,
+      modified: this.sharedService.convertEpochTime(userData._admin.modified),
+      created: this.sharedService.convertEpochTime(userData._admin.created),
+      projects: userData.projectListName,
+      identifier: userData._id
+    };
+    this.userData.push(userDataObj);
+  }
+
+  /**
+   * Lifecyle hook which get trigger on component destruction
+   */
+  public ngOnDestroy(): void {
+    this.generateDataSub.unsubscribe();
+  }
+
+  /** Fetching the data from server to Load in the smarttable @protected */
+  protected generateData(): void {
+    this.isLoadingResults = true;
+    this.restService.getResource(environment.USERS_URL).subscribe((usersData: UserDetail[]) => {
+      this.userData = [];
+      usersData.forEach((userData: UserDetail) => {
+        if (userData.projects.length > 0) {
+          userData.projectListName = userData.projects.join(', ');
+        } else {
+          userData.projectListName = '';
+        }
+        this.setUserDetails(userData);
+      });
+      if (this.userData.length > 0) {
+        this.checkDataClass = 'dataTables_present';
+      } else {
+        this.checkDataClass = 'dataTables_empty';
+      }
+      this.dataSource.load(this.userData).then((data: {}) => {
+        this.isLoadingResults = false;
+      }).catch();
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+    });
+  }
+}
diff --git a/src/app/utilities/clone-package/ClonePackageComponent.html b/src/app/utilities/clone-package/ClonePackageComponent.html
new file mode 100644 (file)
index 0000000..0a75c3a
--- /dev/null
@@ -0,0 +1,33 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="modal-header">
+  <h4 class="modal-title" id="modal-clone-title">
+    {{'CLONE' | translate}}
+  </h4>
+  <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+    <i class="fas fa-times-circle text-danger"></i>
+  </button>
+</div>
+<div class="modal-body">
+  <span>{{'CLONECONFIRMPOPUPMESSAGE' | translate}} <b>{{ params.name }}</b> ?</span>
+</div>
+<div class="modal-footer">
+  <button (click)="activeModal.close()" class="btn btn-danger">{{'CANCEL' | translate}}</button>
+  <button (click)="clonePackageInfo();" class="btn btn-primary">{{'OK' | translate }}</button>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/utilities/clone-package/ClonePackageComponent.scss b/src/app/utilities/clone-package/ClonePackageComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/clone-package/ClonePackageComponent.ts b/src/app/utilities/clone-package/ClonePackageComponent.ts
new file mode 100644 (file)
index 0000000..94e0920
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Clone Package  Model
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, GETAPIURLHEADER, MODALCLOSERESPONSEDATA, URLPARAMS } from 'CommonModel';
+import { environment } from 'environment';
+import * as jsyaml from 'js-yaml';
+import { NSDDetails } from 'NSDModel';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes ClonePackageComponent.html as template url
+ */
+
+@Component({
+  selector: 'app-clone-package',
+  templateUrl: './ClonePackageComponent.html',
+  styleUrls: ['./ClonePackageComponent.scss']
+})
+/** Exporting a class @exports ClonePackageComponent */
+export class ClonePackageComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Input contains component objects @public */
+  @Input() public params: URLPARAMS;
+
+  /** To handle loader status for API call @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains cloned package name instance @private */
+  private packageName: string = '';
+
+  /** Contains API end point for package creation @private */
+  private endPoint: string;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.sharedService = this.injector.get(SharedService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+  }
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    // Empty Block
+  }
+  /**
+   * Get package information based on type
+   */
+  public clonePackageInfo(): void {
+    let apiUrl: string = '';
+    const httpOptions: GETAPIURLHEADER = this.getHttpoptions();
+    apiUrl = this.params.page === 'nsd' ? apiUrl = environment.NSDESCRIPTORS_URL + '/' + this.params.id + '/nsd' :
+      apiUrl = environment.VNFPACKAGES_URL + '/' + this.params.id + '/vnfd';
+    this.isLoadingResults = true;
+    this.restService.getResource(apiUrl, httpOptions)
+      .subscribe((nsData: NSDDetails[]) => {
+        this.modifyContent(nsData);
+      }, (error: ERRORDATA) => {
+        this.isLoadingResults = false;
+        error.error = typeof error.error === 'string' ? jsyaml.load(error.error) : error.error;
+        this.restService.handleError(error, 'get');
+      });
+  }
+  /**
+   * Get HTTP header options
+   */
+  private getHttpoptions(): GETAPIURLHEADER {
+    const apiHeaders: HttpHeaders = new HttpHeaders({
+      'Content-Type': 'application/json',
+      Accept: 'text/plain',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    return {
+      headers: apiHeaders,
+      responseType: 'text'
+    };
+  }
+  /**
+   * Get and modify package information based on type
+   */
+  private modifyContent(packageInfo: NSDDetails[]): void {
+    const packageContent: string = jsyaml.load(packageInfo.toString());
+    if (this.params.page === 'nsd') {
+      this.packageName = 'clone_' + packageContent['nsd:nsd-catalog'].nsd[0].name;
+      this.endPoint = environment.NSDESCRIPTORSCONTENT_URL;
+      packageContent['nsd:nsd-catalog'].nsd.forEach((nsd: NSDDetails) => {
+        nsd.id = 'clone_' + nsd.id;
+        nsd.name = 'clone_' + nsd.name;
+        nsd['short-name'] = 'clone_' + nsd['short-name'];
+      });
+    } else {
+      this.packageName = 'clone_' + packageContent['vnfd:vnfd-catalog'].vnfd[0].name;
+      this.endPoint = environment.VNFPACKAGESCONTENT_URL;
+      packageContent['vnfd:vnfd-catalog'].vnfd.forEach((vnfd: NSDDetails) => {
+        vnfd.id = 'clone_' + vnfd.id;
+        vnfd.name = 'clone_' + vnfd.name;
+        vnfd['short-name'] = 'clone_' + vnfd['short-name'];
+      });
+    }
+    this.clonePackage(packageContent);
+  }
+  /**
+   * Create clone package and upload as TAR.GZ file
+   */
+  private clonePackage(packageContent: string): void {
+    const descriptorInfo: string = jsyaml.dump(packageContent);
+    const apiHeader: HttpHeaders = new HttpHeaders({
+      'Content-Type': 'application/gzip',
+      Accept: 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    const modalData: MODALCLOSERESPONSEDATA = {
+      message: 'Done'
+    };
+    this.sharedService.targzFile({ packageType: this.params.page, id: this.params.id, descriptor: descriptorInfo })
+      .then((content: ArrayBuffer): void => {
+        const apiURLHeader: APIURLHEADER = {
+          url: this.endPoint,
+          httpOptions: { headers: apiHeader }
+        };
+        this.restService.postResource(apiURLHeader, content).subscribe((result: { id: string }) => {
+          this.activeModal.close(modalData);
+          this.isLoadingResults = false;
+          this.notifierService.notify('success', this.translateService.instant('CLONESUCCESSFULLY'));
+        }, (error: ERRORDATA) => {
+          this.isLoadingResults = false;
+          this.restService.handleError(error, 'post');
+        });
+      }).catch((): void => {
+        this.isLoadingResults = false;
+        this.notifierService.notify('error', this.translateService.instant('ERROR'));
+      });
+  }
+}
diff --git a/src/app/utilities/compose-packages/ComposePackages.html b/src/app/utilities/compose-packages/ComposePackages.html
new file mode 100644 (file)
index 0000000..0d66e0f
--- /dev/null
@@ -0,0 +1,40 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="packagesForm" (ngSubmit)="createPackages()" autocomplete="off">
+  <div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{'CREATEPACKAGE' | translate}}</h4>
+    <button class="button-xs" type="button" class="close" (click)="activeModal.close()">
+      <i class="fas fa-times-circle text-danger"></i>
+    </button>
+  </div>
+  <div class="modal-body">
+    <div class="form-group row">
+      <label class="col-sm-12 col-form-label mandatory-label" [ngClass]="{'text-danger': packagesForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+      <label class="col-sm-6 col-form-label">{{'PACKAGE' | translate}} {{'NAME' | translate}}*</label>
+      <div class="col-sm-6">
+        <input type="text" class="form-control" placeholder="{{'PACKAGE' | translate}} {{'NAME' | translate}}"
+          formControlName="name" id="name" [ngClass]="{ 'is-invalid': submitted && f.name.errors }" required>
+      </div>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+    <button type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+  </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/utilities/compose-packages/ComposePackages.scss b/src/app/utilities/compose-packages/ComposePackages.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/compose-packages/ComposePackages.ts b/src/app/utilities/compose-packages/ComposePackages.ts
new file mode 100644 (file)
index 0000000..9567b43
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Info Compose Package Model
+ */
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { Router } from '@angular/router';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, URLPARAMS } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import * as jsyaml from 'js-yaml';
+import * as pako from 'pako';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+
+/** This is added globally by the tar.js library */
+// tslint:disable-next-line: no-any
+declare const Tar: any;
+
+/**
+ * Creating component
+ * @Component takes ComposePackages.html as template url
+ */
+@Component({
+  templateUrl: './ComposePackages.html',
+  styleUrls: ['./ComposePackages.scss']
+})
+/** Exporting a class @exports ComposePackages */
+export class ComposePackages implements OnInit {
+  /** Invoke service injectors @public */
+  public injector: Injector;
+
+  /** dataService to pass the data from one component to another @public */
+  public dataService: DataService;
+
+  /** Varaibles to hold http client @public */
+  public httpClient: HttpClient;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** FormGroup instance added to the form @ html @public */
+  public packagesForm: FormGroup;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** To handle loader status for API call @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Create URL holds the end point of any packages @private */
+  private createURL: string;
+
+  /** Input contains component objects @private */
+  @Input() private params: URLPARAMS;
+
+  /** Holds the end point @private */
+  private endPoint: string;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private router: Router;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.dataService = this.injector.get(DataService);
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.notifierService = this.injector.get(NotifierService);
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.router = this.injector.get(Router);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.headers = new HttpHeaders({
+      'Content-Type': 'application/gzip',
+      Accept: 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    this.initializeForm();
+  }
+
+  /** initialize Forms @public */
+  public initializeForm(): void {
+    this.packagesForm = this.formBuilder.group({
+      name: ['', [Validators.required]]
+    });
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.packagesForm.controls; }
+
+  /** Create packages @public */
+  public createPackages(): void {
+    this.submitted = true;
+    this.sharedService.cleanForm(this.packagesForm);
+    if (!this.packagesForm.invalid) {
+      this.isLoadingResults = true;
+      if (this.params.page === 'ns-package') {
+        this.endPoint = environment.NSDESCRIPTORSCONTENT_URL;
+      } else if (this.params.page === 'vnf-package') {
+        this.endPoint = environment.VNFPACKAGESCONTENT_URL;
+      }
+      const descriptor: string = this.packageYaml(this.params.page);
+      try {
+        // tslint:disable-next-line: no-any
+        const tar: any = new Tar();
+        const out: Uint8Array = tar.append(this.packagesForm.value.name + '/' + this.packagesForm.value.name + '.yaml',
+          descriptor, { type: '0' });
+        const gzipContent: Uint8Array = pako.gzip(out);
+        this.createPackageApi(gzipContent.buffer);
+      } catch (e) {
+        this.isLoadingResults = false;
+        this.notifierService.notify('error', this.translateService.instant('ERROR'));
+      }
+    }
+  }
+  /** Create packages @public */
+  private createPackageApi(packageContent: ArrayBuffer | SharedArrayBuffer): void {
+    const apiURLHeader: APIURLHEADER = {
+      url: this.endPoint,
+      httpOptions: { headers: this.headers }
+    };
+    this.restService.postResource(apiURLHeader, packageContent).subscribe((result: { id: string }) => {
+      this.isLoadingResults = false;
+      this.activeModal.close();
+      this.composeNSPackages(result.id);
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      this.restService.handleError(error, 'post');
+    });
+  }
+  /** Compose NS Packages @private */
+  private composeNSPackages(id: string): void {
+    let packageUrl: string;
+    if (this.params.page === 'ns-package') {
+      packageUrl = '/packages/ns/compose/';
+      this.notifierService.notify('success', this.packagesForm.value.name + ' ' +
+        this.translateService.instant('PAGE.NSPACKAGE.CREATEDSUCCESSFULLY'));
+    } else if (this.params.page === 'vnf-package') {
+      packageUrl = '/packages/vnf/compose/';
+      this.notifierService.notify('success', this.packagesForm.value.name + ' ' +
+        this.translateService.instant('PAGE.VNFPACKAGE.CREATEDSUCCESSFULLY'));
+    }
+    this.router.navigate([packageUrl, id]).catch(() => {
+      // Catch Navigation Error
+    });
+  }
+  /** Deafult template for NS and VNF Packages @private */
+  private packageYaml(descriptorType: string): string {
+    let packageYaml: {} = {};
+    if (descriptorType === 'ns-package') {
+      packageYaml = {
+        'nsd:nsd-catalog': {
+          nsd: [
+            {
+              'short-name': this.packagesForm.value.name,
+              vendor: 'OSM Composer',
+              description: this.packagesForm.value.name + ' descriptor',
+              vld: [],
+              'constituent-vnfd': [],
+              version: '1.0',
+              id: this.packagesForm.value.name,
+              name: this.packagesForm.value.name
+            }
+          ]
+        }
+      };
+    } else {
+      packageYaml = {
+        'vnfd:vnfd-catalog': {
+          vnfd: [
+            {
+              'short-name': this.packagesForm.value.name,
+              vdu: [],
+              description: '',
+              'mgmt-interface': {
+                cp: ''
+              },
+              id: this.packagesForm.value.name,
+              version: '1.0',
+              'internal-vld': [],
+              'connection-point': [],
+              name: this.packagesForm.value.name
+            }
+          ]
+        }
+      };
+    }
+    return jsyaml.dump(packageYaml);
+  }
+}
diff --git a/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.html b/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.html
new file mode 100644 (file)
index 0000000..03f5564
--- /dev/null
@@ -0,0 +1,81 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div *ngIf="topologyType === 'Add'">
+  <form [formGroup]="addConfirmationForm" (ngSubmit)="addConfirmation()" autocomplete="off">
+    <div class="modal-header">
+      <h4 class="modal-title" id="modal-basic-title">
+        {{'CREATE' | translate}}
+        {{ topologytitle | translate}}
+      </h4>
+      <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+        <i class="fas fa-times-circle text-danger"></i>
+      </button>
+    </div>
+    <div class="modal-body">
+      <div *ngIf="topologyType === 'Add'">
+        <p [innerHTML]="topologyname"></p>
+        <ng-select placeholder="{{'SELECT' | translate}}" formControlName="cpName" [items]="cpDetails" bindLabel="name"
+          bindValue="name" [(ngModel)]="connectionPointInput"
+          [ngClass]="{ 'is-invalid': submitted && f.cpName.errors }"></ng-select>
+      </div>
+    </div>
+    <div class="modal-footer">
+      <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+      <button type="submit" class="btn btn-primary">{{'OK' | translate }}</button>
+    </div>
+  </form>
+</div>
+<div *ngIf="topologyType !== 'Add'">
+  <div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">
+      {{(topologyType === 'Delete' ? 'DELETE' : (topologyType === 'Add' ? 'CREATE' : '')) | translate}}
+      {{ topologytitle | translate}}
+    </h4>
+    <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+      <i class="fas fa-times-circle text-danger"></i>
+    </button>
+  </div>
+  <div class="modal-body">
+    <span *ngIf="topologyType === 'Delete'">{{'DELETECONFIRMPOPUPMESSAGE' | translate}} {{ topologyname }} ?</span>
+    <ul *ngIf="topologyType === 'Info'">
+      <li>
+        <p><b>{{'PAGE.TOPOLOGY.HELPINFO.CREATEEDGE' | translate}}</b>:
+          {{'PAGE.TOPOLOGY.HELPINFO.CREATEEDGEFIRSTSETENCE' | translate}} <span class="help-key">Shift</span> + <span
+            class="help-key">Drag</span> {{'PAGE.TOPOLOGY.HELPINFO.CREATEEDGESECONDSETENCE' | translate}}</p>
+      </li>
+      <li>
+        <p><b>{{'PAGE.TOPOLOGY.HELPINFO.DELETEEDGEVERTEX' | translate}}</b>:
+          {{'PAGE.TOPOLOGY.HELPINFO.DELETEEDGEVERTEXSENTENCE' | translate}}</p>
+      </li>
+      <li>
+        <p><b>{{'PAGE.TOPOLOGY.HELPINFO.SPREADEDGE' | translate}}</b>:
+          {{'PAGE.TOPOLOGY.HELPINFO.SPREADEDGESENTENCE' | translate}} <span class="help-key">ctrl</span> + <span
+            class="help-key">Drag</span></p>
+      </li>
+      <li>
+        <p><b>{{'PAGE.TOPOLOGY.HELPINFO.EDGEINFO' | translate}}</b>:
+          {{'PAGE.TOPOLOGY.HELPINFO.EDGEINFOSENTENCE' | translate}}</p>
+      </li>
+    </ul>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+    <button type="button" *ngIf="topologyType !== 'Info'" (click)="confirmation();"
+      class="btn btn-primary">{{'OK' | translate }}</button>
+  </div>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.scss b/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.scss
new file mode 100644 (file)
index 0000000..1ff404c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+.help-key {
+    border: 1px solid #ddd;
+    padding: 4px;
+    border-radius: 3px;
+    background: #f6f6f6;
+    box-shadow: #999 1px 1px 1px;
+}
\ No newline at end of file
diff --git a/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.ts b/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.ts
new file mode 100644 (file)
index 0000000..a1a79b9
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Delete Topology Model
+ */
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { MODALCLOSERESPONSEWITHCP } from 'CommonModel';
+/**
+ * Creating component
+ * @Component takes ConfirmationTopologyComponent.html as template url
+ */
+@Component({
+  selector: 'app-confirmation-topology',
+  templateUrl: './ConfirmationTopologyComponent.html',
+  styleUrls: ['./ConfirmationTopologyComponent.scss']
+})
+/** Exporting a class @exports ConfirmationTopologyComponent */
+export class ConfirmationTopologyComponent implements OnInit {
+  /** Form valid on submit trigger @public */
+  public submitted: boolean = false;
+  /** To inject services @public */
+  public injector: Injector;
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+  /** FormGroup instance added to the form @ html @public */
+  public addConfirmationForm: FormGroup;
+  /** Input contains Modal dialog componentInstance @private */
+  @Input() public topologytitle: string;
+  /** Input contains Modal dialog componentInstance @private */
+  @Input() public topologyname: string;
+  /** Input contains Modal dialog componentInstance @private */
+  @Input() public topologyType: string;
+  /** Input contains Modal dialog componentInstance @private */
+  @Input() public cpDetails: {}[];
+
+  /** Contains connectionpoint @public */
+  public connectionPointInput: string;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.translateService = this.injector.get(TranslateService);
+    this.formBuilder = this.injector.get(FormBuilder);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.initializeForm();
+  }
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.addConfirmationForm.controls; }
+
+  /** initialize Forms @public */
+  public initializeForm(): void {
+    this.addConfirmationForm = this.formBuilder.group({
+      cpName: [null, [Validators.required]]
+    });
+  }
+
+  /** add confirmation to be handled in this function @public */
+  public addConfirmation(): void {
+    this.submitted = true;
+    if (this.addConfirmationForm.invalid) { return; } // Proceed, onces form is valid
+    const modalData: MODALCLOSERESPONSEWITHCP = {
+      message: 'Done',
+      connection_point: this.connectionPointInput
+    };
+    this.activeModal.close(modalData);
+  }
+  /** confirmation to be handled in this function @public */
+  public confirmation(): void {
+    const modalData: MODALCLOSERESPONSEWITHCP = {
+      message: 'Done'
+    };
+    this.activeModal.close(modalData);
+  }
+
+}
diff --git a/src/app/utilities/delete/DeleteComponent.html b/src/app/utilities/delete/DeleteComponent.html
new file mode 100644 (file)
index 0000000..a39cb61
--- /dev/null
@@ -0,0 +1,33 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="modal-header">
+  <h4 class="modal-title" id="modal-basic-title">
+    {{'DELETE' | translate}}
+  </h4>
+  <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+    <i class="fas fa-times-circle text-danger"></i>
+  </button>
+</div>
+<div class="modal-body">
+  <span>{{'DELETECONFIRMPOPUPMESSAGE' | translate}} <b>{{ this.title }}</b> ?</span>
+</div>
+<div class="modal-footer">
+  <button (click)="activeModal.close()" class="btn btn-danger">{{'CANCEL' | translate}}</button>
+  <button (click)="deleteData();" class="btn btn-primary">{{'OK' | translate }}</button>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/utilities/delete/DeleteComponent.scss b/src/app/utilities/delete/DeleteComponent.scss
new file mode 100644 (file)
index 0000000..cdd37f2
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+.loadermessage-column {
+    min-height: 150px;
+}
\ No newline at end of file
diff --git a/src/app/utilities/delete/DeleteComponent.ts b/src/app/utilities/delete/DeleteComponent.ts
new file mode 100644 (file)
index 0000000..4baee64
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Delete Model
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, Injector, Input } from '@angular/core';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { DELETEPARAMS, ERRORDATA, MODALCLOSERESPONSEDATA, URLPARAMS } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { RestService } from 'RestService';
+
+/**
+ * Creating component
+ * @Component takes DeleteComponent.html as template url
+ */
+@Component({
+  selector: 'app-delete',
+  templateUrl: './DeleteComponent.html',
+  styleUrls: ['./DeleteComponent.scss']
+})
+/** Exporting a class @exports DeleteComponent */
+export class DeleteComponent {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Instance of the modal service @public */
+  public title: string;
+
+  /** Show the Delete Ok button to trigger the terminate and delete */
+  public forceDelete: boolean = false;
+
+  /** Check the loading results @public */
+  public isLoadingResults: Boolean = false;
+
+  /** Give the message for the loading @public */
+  public notifyMessage: string = 'DELETELOADERMESSAGE';
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** DataService to pass the data from one component to another @private */
+  private dataService: DataService;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Instance of the modal service @private */
+  private id: string;
+
+  /** Variables holds url to be delete @private */
+  private deleteURL: string;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Input contains component objects @private */
+  @Input() private params: URLPARAMS;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.dataService = this.injector.get(DataService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.headers = new HttpHeaders({
+      'Content-Type': 'application/json',
+      Accept: 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    this.dataService.currentMessage.subscribe((data: DELETEPARAMS) => {
+      if (data.identifier !== undefined || data.identifier !== '' || data.identifier !== null) {
+        this.id = data.identifier;
+      }
+      this.createTitleandID(data);
+      this.createDeleteUrl(data);
+    });
+  }
+  /** Generate Title and Id from data @public */
+  public createTitleandID(data: DELETEPARAMS): void {
+    this.title = '';
+    if (data.name !== undefined) {
+      this.title = data.name;
+    } else if (data.shortName !== undefined) {
+      this.title = data.shortName;
+    } else if (data.projectName !== undefined) {
+      this.title = data.projectName;
+      this.id = this.title;
+    } else if (data.userName !== undefined) {
+      this.title = data.userName;
+    } else if (data.username !== undefined) {
+      this.title = data.username;
+    }
+  }
+  /** Generate Delete url from data @public */
+  public createDeleteUrl(data: DELETEPARAMS): void {
+    this.deleteURL = '';
+    if (data.page === 'ns-instance') {
+      this.deleteURL = environment.NSINSTANCESCONTENT_URL;
+      this.forceDelete = this.params.forceDeleteType;
+    } else if (data.page === 'ns-package') {
+      this.deleteURL = environment.NSDESCRIPTORSCONTENT_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else if (data.page === 'vnf-package') {
+      this.deleteURL = environment.VNFPACKAGESCONTENT_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else if (data.page === 'vim-account') {
+      this.deleteURL = environment.VIMACCOUNTS_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else if (data.page === 'wim-account') {
+      this.deleteURL = environment.WIMACCOUNTS_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else if (data.page === 'projects') {
+      this.deleteURL = environment.PROJECTS_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+      this.id = data.id;
+    } else if (data.page === 'users') {
+      this.deleteURL = environment.USERS_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else if (data.page === 'network-slice') {
+      this.deleteURL = environment.NETWORKSLICETEMPLATECONTENT_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else if (data.page === 'net-slice-instance') {
+      this.deleteURL = environment.NETWORKSLICEINSTANCESCONTENT_URL;
+      this.forceDelete = this.params.forceDeleteType;
+    } else if (data.page === 'roles') {
+      this.deleteURL = environment.ROLES_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else if (data.page === 'pdu-instances') {
+      this.deleteURL = environment.PDUINSTANCE_URL;
+    } else if (data.page === 'sdn-controller') {
+      this.deleteURL = environment.SDNCONTROLLER_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else if (data.page === 'k8-cluster') {
+      this.deleteURL = environment.K8SCLUSTER_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else if (data.page === 'k8-repo') {
+      this.deleteURL = environment.K8REPOS_URL;
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    }
+  }
+  /** Generate Data function @public */
+  public deleteData(): void {
+    this.isLoadingResults = true;
+    const modalData: MODALCLOSERESPONSEDATA = {
+      message: 'Done'
+    };
+    let deletingURl: string = '';
+    if (this.forceDelete) {
+      deletingURl = this.deleteURL + '/' + this.id + '?FORCE=true';
+      this.notifyMessage = 'DELETEDSUCCESSFULLY';
+    } else {
+      deletingURl = this.deleteURL + '/' + this.id;
+    }
+    this.restService.deleteResource(deletingURl).subscribe((res: {}) => {
+      this.activeModal.close(modalData);
+      this.notifierService.notify('success', this.translateService.instant(this.notifyMessage, { title: this.title}));
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      this.restService.handleError(error, 'delete');
+    }, () => {
+      this.isLoadingResults = false;
+    });
+  }
+}
diff --git a/src/app/utilities/dragDropUpload/DragDirective.ts b/src/app/utilities/dragDropUpload/DragDirective.ts
new file mode 100644 (file)
index 0000000..735ac7c
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Drag and Drop feature.
+ */
+import { Directive, EventEmitter, HostBinding, HostListener, Output } from '@angular/core';
+import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
+
+/** Interface for FileHandle */
+export interface FileHandle {
+  file: File;
+  url: SafeUrl;
+}
+
+/**
+ * Creating Directive
+ * @Directive for handling the files.
+ */
+// tslint:disable-next-line:export-name
+@Directive({
+  selector: '[appDrag]'
+})
+/** Exporting a class @exports DragDirective */
+export class DragDirective {
+  /** To publish the details of files @public */
+  @Output() public files: EventEmitter<FileList> = new EventEmitter();
+
+  /** To set the background of drag and drop region @public */
+  @HostBinding('style.background') private background: string = '#e6f3fe';
+
+  /** To set the background of drag and drop region @public */
+  @HostBinding('style.color') private color: string = '#6a7a8c';
+
+  /** To trust the SecurityURL @public */
+  private sanitizer: DomSanitizer;
+
+  constructor(sanitizer: DomSanitizer) {
+    this.sanitizer = sanitizer;
+  }
+
+  /** To handle the Drag over Event @public */
+  @HostListener('dragover', ['$event']) public onDragOver(evt: DragEvent): void {
+    evt.preventDefault();
+    evt.stopPropagation();
+    this.background = '#087add';
+    this.color = '#fff';
+  }
+  /** To handle Drag leave Event @public */
+  @HostListener('dragleave', ['$event']) public onDragLeave(evt: DragEvent): void {
+    evt.preventDefault();
+    evt.stopPropagation();
+    this.background = '#e6f3fe';
+    this.color = '#6a7a8c';
+  }
+  /** To handle Drop Event @public */
+  @HostListener('drop', ['$event']) public onDrop(evt: DragEvent): void {
+    evt.preventDefault();
+    evt.stopPropagation();
+    this.background = '#e6f3fe';
+    this.color = '#6a7a8c';
+
+    const files: FileHandle[] = [];
+    Array.from(evt.dataTransfer.files).forEach((listFiles: File, index: number) => {
+      const file: File = listFiles;
+      const url: SafeUrl = this.sanitizer.bypassSecurityTrustUrl(window.URL.createObjectURL(file));
+      files.push({ file, url });
+    });
+    if (files.length > 0) {
+      this.files.emit(evt.dataTransfer.files);
+    }
+  }
+}
diff --git a/src/app/utilities/edit-packages/EditPackagesComponent.html b/src/app/utilities/edit-packages/EditPackagesComponent.html
new file mode 100644 (file)
index 0000000..2defc33
--- /dev/null
@@ -0,0 +1,61 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="form-group row">
+  <div class="d-flex align-items-center header-style">{{'EDIT' | translate}}&nbsp;<span
+      class="text-uppercase">{{pacakgeType}}&nbsp;</span>{{'DESCRIPTOR' | translate}}</div>
+</div>
+<form *ngIf="defaults[mode]">
+  <div class="row">
+    <div class="col-2">
+      <div class="form-group">
+        <select class="form-control custom-select" name="state" [(ngModel)]="mode" (ngModelChange)="changeMode()">
+          <option *ngFor="let types of fileTypes;" [value]="types.value">
+            {{types.viewValue}}</option>
+        </select>
+      </div>
+    </div>
+    <div class="col-4">
+      <div class="btn-group-toggle mb-1 mr-1 float-left">
+        <label class="btn btn-light" [class.active]="readOnly">
+          <input type="checkbox" [(ngModel)]="readOnly" name="readOnly" autocomplete="off">
+          {{'READONLYMODE' | translate}} ({{'CURRENTLY' | translate}} {{ (readOnly ? 'ON' : 'OFF') | translate }})
+        </label>
+      </div>
+    </div>
+    <div class="col-6 text-right">
+      <button type="button" class="btn btn-primary mr-2" routerLink="/packages/{{navigatePath}}/compose/{{paramsID}}"
+        [hidden]="navigatePath==='netslice'">
+        <i class="fa fa-sitemap" aria-hidden="true"></i>&nbsp;{{'SHOWGRAPH' | translate}}
+      </button>
+      <button type="button" class="btn btn-primary mr-2" (click)="update(true)" [hidden]="navigatePath==='netslice'">
+        <i class="fa fa-save" aria-hidden="true"></i>&nbsp;{{'UPDATESHOWGRAPH' | translate}}
+      </button>
+      <button type="button" class="btn btn-primary" (click)="update(false)">
+        <i class="fa fa-save" aria-hidden="true"></i>&nbsp;{{'UPDATE' | translate}}
+      </button>
+    </div>
+  </div>
+</form>
+<div class="ngx-codemirror" *ngIf="defaults[mode] else noData">
+  <ngx-codemirror [options]="options" [ngModel]="defaults[mode]" [disabled]="readOnly" [autoFocus]="true"
+    (ngModelChange)="handleChange($event)"></ngx-codemirror>
+</div>
+<ng-template #noData>
+  {{'NODATAERROR' | translate}}
+</ng-template>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/utilities/edit-packages/EditPackagesComponent.scss b/src/app/utilities/edit-packages/EditPackagesComponent.scss
new file mode 100644 (file)
index 0000000..5a9c483
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+.ngx-codemirror {
+    font-size: 14px;
+}
\ No newline at end of file
diff --git a/src/app/utilities/edit-packages/EditPackagesComponent.ts b/src/app/utilities/edit-packages/EditPackagesComponent.ts
new file mode 100644 (file)
index 0000000..befafb8
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Edit Actions Component
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, Injector, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import 'codemirror/addon/dialog/dialog';
+import 'codemirror/addon/display/autorefresh';
+import 'codemirror/addon/display/fullscreen';
+import 'codemirror/addon/edit/closebrackets';
+import 'codemirror/addon/edit/matchbrackets';
+import 'codemirror/addon/fold/brace-fold';
+import 'codemirror/addon/fold/foldcode';
+import 'codemirror/addon/fold/foldgutter';
+import 'codemirror/addon/search/search';
+import 'codemirror/addon/search/searchcursor';
+import 'codemirror/keymap/sublime';
+import 'codemirror/lib/codemirror';
+import 'codemirror/mode/javascript/javascript';
+import 'codemirror/mode/markdown/markdown';
+import 'codemirror/mode/yaml/yaml';
+import { APIURLHEADER, ERRORDATA, GETAPIURLHEADER } from 'CommonModel';
+import { environment } from 'environment';
+import * as HttpStatus from 'http-status-codes';
+import * as jsyaml from 'js-yaml';
+import { NSDDetails } from 'NSDModel';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes EditPackagesComponent.html as template url
+ */
+@Component({
+  selector: 'app-edit-packages',
+  templateUrl: './EditPackagesComponent.html',
+  styleUrls: ['./EditPackagesComponent.scss']
+})
+
+/** Exporting a class @exports EditPackagesComponent */
+export class EditPackagesComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** dataService to pass the data from one component to another @public */
+  public identifier: {} = {};
+
+  /** readOnly @public */
+  public readOnly: boolean = false;
+
+  /** Handle the formate Change @public */
+  public defaults: {} = {
+    'text/x-yaml': '',
+    'text/json': ''
+  };
+
+  /** Get & Update URL VNFD & NSD */
+  public getUpdateURL: string;
+
+  /** Pass the type of VNFD & NSD for fetching text */
+  public getFileContentType: string;
+
+  /** Pass the type of VNFD & NSD for fileUpdate */
+  public updateFileContentType: string;
+
+  /** To Set Mode @public */
+  public mode: string = 'text/x-yaml';
+
+  /** To Set Mode @public */
+  public modeDefault: string = 'yaml';
+
+  /** options @public */
+  public options: {} = {
+    mode: this.modeDefault,
+    showCursorWhenSelecting: true,
+    autofocus: true,
+    autoRefresh: true,
+    lineNumbers: true,
+    lineWrapping: true,
+    foldGutter: true,
+    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
+    autoCloseBrackets: true,
+    matchBrackets: true,
+    theme: 'neat',
+    keyMap: 'sublime'
+  };
+
+  /** Ymal Url for the VNFD & NSD */
+  public ymalUrl: string;
+
+  /** json Url for the VNFD & NSD */
+  public jsonUrl: string;
+
+  /** Navigation Path for the VNFD & NSD */
+  public navigatePath: string;
+
+  /** Package type */
+  public pacakgeType: string;
+
+  /** variables contains paramsID @public */
+  public paramsID: string;
+
+  /** Controls the File Type List form @public */
+  public fileTypes: { value: string; viewValue: string; }[] = [];
+
+  /** Check the loading results @public */
+  public isLoadingResults: boolean = true;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private router: Router;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private activatedRoute: ActivatedRoute;
+
+  /** Data @private */
+  private data: string = '';
+
+  /** contains http options @private */
+  private httpOptions: HttpHeaders;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.activatedRoute = this.injector.get(ActivatedRoute);
+    this.router = this.injector.get(Router);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.headers = new HttpHeaders({
+      'Content-Type': 'application/json',
+      Accept: 'text/plain',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    // tslint:disable-next-line: no-backbone-get-set-outside-model
+    this.paramsID = this.activatedRoute.snapshot.paramMap.get('id');
+    // tslint:disable-next-line: no-backbone-get-set-outside-model
+    this.pacakgeType = this.activatedRoute.snapshot.paramMap.get('type');
+    this.generateURLPath();
+  }
+
+  /** generate ymalURL, JSONURL, navigation Path */
+  public generateURLPath(): void {
+    if (this.pacakgeType === 'vnf') {
+      this.getUpdateURL = environment.VNFPACKAGES_URL;
+      this.getFileContentType = 'vnfd';
+      this.updateFileContentType = 'package_content';
+      this.navigatePath = 'vnf';
+      this.fileTypes = [{ value: 'text/x-yaml', viewValue: 'yaml' }, { value: 'text/json', viewValue: 'json' }];
+      this.httpOptions = this.getHeadersWithContentAccept('application/zip', 'application/json');
+      this.getEditFileData();
+    } else if (this.pacakgeType === 'netslice') {
+      this.getUpdateURL = environment.NETWORKSLICETEMPLATE_URL;
+      this.getFileContentType = 'nst';
+      this.updateFileContentType = 'nst_content';
+      this.navigatePath = 'netslice';
+      this.fileTypes = [{ value: 'text/x-yaml', viewValue: 'yaml' }];
+      this.httpOptions = this.getHeadersWithContentAccept('application/yaml', 'application/json');
+      this.getEditFileData();
+    } else {
+      this.getUpdateURL = environment.NSDESCRIPTORS_URL;
+      this.getFileContentType = 'nsd';
+      this.updateFileContentType = 'nsd_content';
+      this.pacakgeType = 'nsd';
+      this.navigatePath = 'ns';
+      this.fileTypes = [{ value: 'text/x-yaml', viewValue: 'yaml' }, { value: 'text/json', viewValue: 'json' }];
+      this.httpOptions = this.getHeadersWithContentAccept('application/zip', 'application/json');
+      this.getEditFileData();
+    }
+  }
+
+  /** Get the headers based on the type @public */
+  public getHeadersWithContentAccept(contentType: string, acceptType: string): HttpHeaders {
+    this.headers = new HttpHeaders({
+      'Content-Type': contentType,
+      Accept: acceptType,
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    return this.headers;
+  }
+
+  /** ChangeMode function @public */
+  public changeMode(): void {
+    if (this.mode === 'text/x-yaml') {
+      this.modeDefault = 'yaml';
+    } else {
+      this.modeDefault = 'javascript';
+    }
+    this.options = {
+      ...this.options,
+      mode: this.modeDefault
+    };
+    this.data = '';
+  }
+
+  /** HandleChange function @public */
+  public handleChange($event: string): void {
+    this.data = $event;
+  }
+
+  /** Update function @public */
+  public update(showgraph: boolean): void {
+    if (this.data === '') {
+      this.notifierService.notify('warning', this.translateService.instant('PAGE.TOPOLOGY.DATAEMPTY'));
+    } else {
+      this.updateCheck(showgraph);
+    }
+  }
+  /** Update the file Data @public */
+  public updateFileData(urlHeader: APIURLHEADER, fileData: string | ArrayBuffer, showgraph: boolean, packageType: string): void {
+    this.restService.putResource(urlHeader, fileData).subscribe(() => {
+      this.isLoadingResults = false;
+      this.notifierService.notify('success', this.translateService.instant(
+        (packageType !== 'netslice') ? 'PAGE.NSPACKAGE.EDITPACKAGES.UPDATEDSUCCESSFULLY' : 'PAGE.NETSLICE.UPDATEDSUCCESSFULLY'));
+      if (showgraph) {
+        if (packageType === 'nsd') {
+          this.router.navigate(['/packages/ns/compose/' + this.paramsID]).catch();
+        } else if (packageType === 'vnf') {
+          this.router.navigate(['/packages/vnf/compose/' + this.paramsID]).catch();
+        }
+      }
+      this.getEditFileData();
+    }, (error: ERRORDATA) => {
+      this.isLoadingResults = false;
+      this.restService.handleError(error, 'put');
+    });
+  }
+  /** Update method for NS, VNF and net-slice template */
+  private updateCheck(showgraph: boolean): void {
+    this.isLoadingResults = true;
+    const apiURLHeader: APIURLHEADER = {
+      url: this.getUpdateURL + '/' + this.paramsID + '/' + this.updateFileContentType,
+      httpOptions: { headers: this.httpOptions }
+    };
+    let descriptorInfo: string = '';
+    if (this.mode === 'text/json') {
+      descriptorInfo = jsyaml.dump(JSON.parse(this.data), {sortKeys: true});
+    } else {
+      descriptorInfo = this.data;
+    }
+    if (this.getFileContentType !== 'nst') {
+      this.sharedService.targzFile({ packageType: this.pacakgeType, id: this.paramsID, descriptor: descriptorInfo })
+        .then((content: ArrayBuffer): void => {
+          this.updateFileData(apiURLHeader, content, showgraph, this.pacakgeType);
+        }).catch((): void => {
+          this.isLoadingResults = false;
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        });
+    } else {
+      this.updateFileData(apiURLHeader, descriptorInfo, showgraph, this.pacakgeType);
+    }
+  }
+  /** Get the YAML content response as a plain/text and convert to JSON Format @private */
+  private getEditFileData(): void {
+    this.isLoadingResults = true;
+    const gethttpOptions: HttpHeaders = this.getHeadersWithContentAccept('application/json', 'text/plain');
+    const httpOptions: GETAPIURLHEADER = {
+      headers: gethttpOptions,
+      responseType: 'text'
+    };
+    this.restService.getResource(this.getUpdateURL + '/' + this.paramsID + '/' + this.getFileContentType, httpOptions)
+      .subscribe((nsData: NSDDetails[]) => {
+        const getJson: string = jsyaml.load(nsData.toString(), { json: true });
+        //tslint:disable-next-line:no-string-literal
+        this.defaults['text/x-yaml'] = nsData.toString();
+        this.defaults['text/json'] = JSON.stringify(getJson, null, '\t');
+        this.isLoadingResults = false;
+      }, (error: ERRORDATA) => {
+        error.error = typeof error.error === 'string' ? jsyaml.load(error.error) : error.error;
+        if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED  ) {
+          this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
+        } else {
+          this.restService.handleError(error, 'get');
+        }
+        this.isLoadingResults = false;
+      });
+  }
+}
diff --git a/src/app/utilities/loader/LoaderComponent.html b/src/app/utilities/loader/LoaderComponent.html
new file mode 100644 (file)
index 0000000..30ce264
--- /dev/null
@@ -0,0 +1,27 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="loader-overlay">
+  <div class="loader-content loader-center text-center">
+    <div class="loader">{{'LOADING' | translate}}...</div>
+    <p class="loader-text">
+      <strong>{{getMessage | translate}}
+        <span class="loader__dot" *ngFor="let index of [0,1,2]">.</span>
+      </strong>
+    </p>
+  </div>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/loader/LoaderComponent.scss b/src/app/utilities/loader/LoaderComponent.scss
new file mode 100644 (file)
index 0000000..6bfd321
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import '../../../assets/scss/mixins/mixin';
+@import '../../../assets/scss/variable';
+.loader-overlay {
+  -ms-opacity: 0.9;
+  @include background(null, $white, null, null, null);
+  @include position_value(absolute, 0, null, null, 0);
+  @include wh-value(100%, 100%);
+  opacity: 0.9;
+  vertical-align: middle;
+  z-index: 100000;
+  .loader-content {
+    @include wh-value(50%, null);
+    margin-left: auto;
+    margin-top: auto;
+    .loader-text {
+      color: $body-color;
+    }
+  }
+  .loader-center {
+    @include position_value(absolute, 50%, null, null, 50%);
+    @include flexbox(block, null, null, null, null, null);
+    -moz-transform: translate(-50%, -50%);
+    -ms-transform: translate(-50%, -50%);
+    -o-transform: translate(-50%, -50%);
+    -webkit-transform: translate(-50%, -50%);
+    transform: translate(-50%, -55%);
+  }
+}
+.loader,
+.loader:after {
+  @include roundedCornersPercentage(50%);
+  @include wh-value(10em, 10em);
+}
+.loader {
+  @include font(null, 3px, null);
+  @include position_value(relative, null, null, null, null);
+  @include border(top, 2, solid, rgba(5, 76, 140, 0.28));
+  @include border(right, 2, solid, rgba(5, 76, 140, 0.28));
+  @include border(bottom, 2, solid, rgba(5, 76, 140, 0.28));
+  @include border(left, 2, solid, $primary);
+  margin: 0 auto;
+  text-indent: -9999em;
+  -webkit-transform: translateZ(0);
+  -ms-transform: translateZ(0);
+  transform: translateZ(0);
+  -webkit-animation: load8 1.1s infinite linear;
+  animation: load8 1.1s infinite linear;
+}
+@-webkit-keyframes load8 {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
+}
+@keyframes load8 {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
+}
+@keyframes blink {50% { color: transparent }}
+.loader__dot { animation: 1s blink infinite }
+.loader__dot:nth-child(2) { animation-delay: 250ms }
+.loader__dot:nth-child(3) { animation-delay: 500ms }
\ No newline at end of file
diff --git a/src/app/utilities/loader/LoaderComponent.ts b/src/app/utilities/loader/LoaderComponent.ts
new file mode 100644 (file)
index 0000000..ee8cab8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Delete Model
+ */
+import { Component, Input, OnInit } from '@angular/core';
+/**
+ * Creating component
+ * @Component takes LoaderComponent.html as template url
+ */
+@Component({
+  selector: 'app-loader',
+  templateUrl: './LoaderComponent.html',
+  styleUrls: ['./LoaderComponent.scss']
+})
+/** Exporting a class @exports LoaderComponent */
+export class LoaderComponent implements OnInit {
+  /** Variables declared to get the message from parents @public */
+  @Input() public waitingMessage: string;
+  /** Variables declared to get the message of loader @public */
+  public getMessage: string;
+
+  constructor() {
+    // Empty block
+  }
+
+  public ngOnInit(): void {
+    if (this.waitingMessage !== '') {
+      this.getMessage = this.waitingMessage;
+    } else {
+      this.getMessage = '';
+    }
+  }
+
+}
diff --git a/src/app/utilities/loader/LoaderModule.ts b/src/app/utilities/loader/LoaderModule.ts
new file mode 100644 (file)
index 0000000..ba81b6a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Loader Module.
+ */
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { TranslateModule } from '@ngx-translate/core';
+import { LoaderComponent } from 'LoaderComponent';
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+  imports: [CommonModule, TranslateModule],
+  declarations: [LoaderComponent],
+  exports: [LoaderComponent]
+})
+/** Exporting a class @exports LoaderModule */
+export class LoaderModule {
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    // Empty Block
+  }
+}
diff --git a/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.html b/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.html
new file mode 100644 (file)
index 0000000..7fcc812
--- /dev/null
@@ -0,0 +1,42 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <button type="button" class="btn btn-primary" (click)="infoNetSliceInstance()" placement="top" container="body"
+        ngbTooltip="{{'INFO' | translate}}">
+        <i class="fas fa-info icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" (click)="deleteNetSliceInstance(false)" placement="top"
+        container="body" ngbTooltip="{{'DELETE' | translate}}">
+        <i class="far fa-trash-alt icons"></i>
+    </button>
+    <div ngbDropdown class="btn-group">
+        <button type="button" class="btn btn-primary dropdown-toggle action-button" ngbDropdownToggle>
+            {{'ACTION' | translate}}
+        </button>
+        <div class="dropdown-menu" ngbDropdownMenu>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="historyOfOperations()" placement="left"
+                container="body" ngbTooltip="{{'HISTORYOFOPERATIONS' | translate}}">
+                <i class="fas fa-history"></i> {{'HISTORYOFOPERATIONS' | translate}}
+            </button>
+            <button type="button" class="btn btn-primary dropdown-item text-danger" (click)="deleteNetSliceInstance(true)" placement="left"
+                container="body" ngbTooltip="{{'FORCEDELETE' | translate}}">
+                <i class="fas fa-trash-alt icons text-danger"></i> {{'FORCEDELETE' | translate}}
+            </button>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.scss b/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.ts b/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.ts
new file mode 100644 (file)
index 0000000..0e528a8
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Netslice InstancesAction Component
+ */
+import { Component, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { NSTInstanceData } from 'NetworkSliceModel';
+import { SharedService } from 'SharedService';
+import { ShowInfoComponent } from 'ShowInfoComponent';
+/**
+ * Creating component
+ * @Component takes NetsliceInstancesActionComponent.html as template url
+ */
+@Component({
+    templateUrl: './NetsliceInstancesActionComponent.html',
+    styleUrls: ['./NetsliceInstancesActionComponent.scss']
+})
+/** Exporting a class @exports NetsliceInstancesActionComponent */
+export class NetsliceInstancesActionComponent {
+    /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */
+    public value: NSTInstanceData;
+
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Contains instance ID @private */
+    private instanceID: string;
+
+    /** Service holds the router information @private */
+    private router: Router;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.modalService = this.injector.get(NgbModal);
+        this.router = this.injector.get(Router);
+        this.sharedService = this.injector.get(SharedService);
+    }
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.instanceID = this.value.identifier;
+    }
+
+    /** Shows information using modalservice @public */
+    public infoNetSliceInstance(): void {
+        this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = {
+            id: this.instanceID,
+            page: 'net-slice-instance',
+            titleName: 'PAGE.NETSLICETEMPLATE.NETSLICETEMPLATEDETAILS'
+        };
+    }
+
+    /** Delete NetSlice Instance packages @public */
+    public deleteNetSliceInstance(forceAction: boolean): void {
+        const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+        modalRef.componentInstance.params = {forceDeleteType: forceAction};
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+    /** History of operations for an Instanace @public */
+    public historyOfOperations(): void {
+        this.router.navigate(['/instances/netslice/history-operations/', this.instanceID]).catch(() => {
+            // Catch Navigation Error
+        });
+    }
+}
diff --git a/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.html b/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.html
new file mode 100644 (file)
index 0000000..d47d65e
--- /dev/null
@@ -0,0 +1,34 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <button type="button" class="btn btn-primary" (click)="instantiateNetSlice()" placement="top" container="body"
+        ngbTooltip="{{'INSTANTIATE' | translate}} NS">
+        <i class="fa fa-paper-plane icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" (click)="infoNetSlice()" placement="top" container="body"
+        ngbTooltip="{{'INFO' | translate}}">
+        <i class="fas fa-info icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" (click)="netSliceEdit()" placement="top" container="body" ngbTooltip="{{'EDIT' | translate}}">
+        <i class="fa fa-edit icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" (click)="deleteNetSliceTemplate()" placement="top" container="body"
+        ngbTooltip="{{'DELETE' | translate}}">
+        <i class="far fa-trash-alt icons"></i>
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.scss b/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.ts b/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.ts
new file mode 100644 (file)
index 0000000..8be5f50
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Netslice-packagesAction Component
+ */
+import { Component, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { InstantiateNetSliceTemplateComponent } from 'InstantiateNetSliceTemplate';
+import { NetworkSliceData } from 'NetworkSliceModel';
+import { SharedService } from 'SharedService';
+import { ShowInfoComponent } from 'ShowInfoComponent';
+
+/**
+ * Creating component
+ * @Component takes NetslicePackagesActionComponent.html as template url
+ */
+@Component({
+    selector: 'app-netslice-packages-action',
+    templateUrl: './NetslicePackagesActionComponent.html',
+    styleUrls: ['./NetslicePackagesActionComponent.scss']
+})
+/** Exporting a class @exports NetslicePackagesActionComponent */
+export class NetslicePackagesActionComponent {
+    /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */
+    public value: NetworkSliceData;
+
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Contains instance ID @private */
+    private instanceID: string;
+
+    /** Service holds the router information @private */
+    private router: Router;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.modalService = this.injector.get(NgbModal);
+        this.router = this.injector.get(Router);
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.instanceID = this.value.identifier;
+    }
+
+    /** Delete NetSliceTemplate packages @public */
+    public deleteNetSliceTemplate(): void {
+        const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, {backdrop: 'static'});
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+
+    /** Shows information using modalservice @public */
+    public infoNetSlice(): void {
+        this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = {
+            id: this.instanceID,
+            page: 'net-slice-package',
+            titleName: 'PAGE.NETSLICETEMPLATE.NETSLICETEMPLATEDETAILS'
+        };
+    }
+
+    /** Set Edit for the  @public */
+    public netSliceEdit(): void {
+        this.router.navigate(['/packages/netslice/edit/', this.instanceID]).catch(() => {
+            // Catch Navigation Error
+        });
+    }
+
+    /** Instantiate Net Slice using modalservice @public */
+    public instantiateNetSlice(): void {
+        this.modalService.open(InstantiateNetSliceTemplateComponent, { backdrop: 'static' });
+    }
+}
diff --git a/src/app/utilities/ns-instances-action/NSInstancesActionComponent.html b/src/app/utilities/ns-instances-action/NSInstancesActionComponent.html
new file mode 100644 (file)
index 0000000..41a58f5
--- /dev/null
@@ -0,0 +1,56 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <button type="button" class="btn btn-primary" (click)="metrics()" placement="top" container="body"
+        [disabled]="operationalStatus == 'failed' || configStatus == 'failed'" ngbTooltip="{{'METRICS' | translate}}">
+        <i class="fas fa-chart-bar icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" [disabled]="operationalStatus != 'running'" (click)="nsTopology()"
+        placement="top" container="body" ngbTooltip="{{'TOPOLOGY' | translate}}">
+        <i class="fa fa-sitemap fa-fw icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" (click)="deleteNSInstance(false)" placement="top" container="body"
+        ngbTooltip="{{'DELETE' | translate}}">
+        <i class="far fa-trash-alt icons"></i>
+    </button>
+    <div ngbDropdown class="btn-group">
+        <button type="button" class="btn btn-primary dropdown-toggle action-button" ngbDropdownToggle>
+            {{'ACTION' | translate}}
+        </button>
+        <div class="dropdown-menu" ngbDropdownMenu>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="infoNs()" placement="left"
+                container="body" ngbTooltip="{{'INFO' | translate}}">
+                <i class="fas fa-info icons list" title="info"></i> {{'INFO' | translate}}
+            </button>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="execNSPrimitiveModal()"
+                placement="left" container="body" ngbTooltip="{{'EXECNSPRIMITIVE' | translate}}"
+                [disabled]="operationalStatus == 'failed' || configStatus == 'failed'">
+                <i class="fas fa-magic"></i> {{'EXECNSPRIMITIVE' | translate}}
+            </button>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="historyOfOperations()" placement="left"
+                container="body" ngbTooltip="{{'HISTORYOFOPERATIONS' | translate}}">
+                <i class="fas fa-history"></i> {{'HISTORYOFOPERATIONS' | translate}}
+            </button>
+            <button type="button" class="btn btn-primary dropdown-item text-danger" (click)="deleteNSInstance(true)"
+                placement="left" container="body" ngbTooltip="{{'FORCEDELETE' | translate}}">
+                <i class="fas fa-trash-alt icons text-danger"></i> {{'FORCEDELETE' | translate}}
+            </button>
+        </div>
+    </div>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingMetricsResult"></app-loader>
\ No newline at end of file
diff --git a/src/app/utilities/ns-instances-action/NSInstancesActionComponent.scss b/src/app/utilities/ns-instances-action/NSInstancesActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/ns-instances-action/NSInstancesActionComponent.ts b/src/app/utilities/ns-instances-action/NSInstancesActionComponent.ts
new file mode 100644 (file)
index 0000000..8bf43ce
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file NS InstancesAction Component
+ */
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { environment } from 'environment';
+import { NSDDetails } from 'NSDModel';
+import { NSDInstanceData } from 'NSInstanceModel';
+import { NSPrimitiveComponent } from 'NSPrimitiveComponent';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { ShowInfoComponent } from 'ShowInfoComponent';
+/**
+ * Creating component
+ * @Component takes NSInstancesActionComponent.html as template url
+ */
+@Component({
+  templateUrl: './NSInstancesActionComponent.html',
+  styleUrls: ['./NSInstancesActionComponent.scss'],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+/** Exporting a class @exports NSInstancesActionComponent */
+export class NSInstancesActionComponent {
+  /** To get the value from the nspackage via valuePrepareFunction default Property of ng-smarttable @public */
+  public value: NSDInstanceData;
+
+  /** Invoke service injectors @public */
+  public injector: Injector;
+
+  /** Instance of the modal service @public */
+  public restService: RestService;
+
+  /** Config Status Check @public */
+  public configStatus: string;
+
+  /** Operational Status Check @public */
+  public operationalStatus: string;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingMetricsResult: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private router: Router;
+
+  /** Contains instance ID @private */
+  private instanceID: string;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Detect changes for the User Input */
+  private cd: ChangeDetectorRef;
+
+  /** Set timeout @private */
+  private timeOut: number = 1000;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.modalService = this.injector.get(NgbModal);
+    this.restService = this.injector.get(RestService);
+    this.router = this.injector.get(Router);
+    this.sharedService = this.injector.get(SharedService);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.cd = this.injector.get(ChangeDetectorRef);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.configStatus = this.value.ConfigStatus;
+    this.operationalStatus = this.value.OperationalStatus;
+    this.instanceID = this.value.identifier;
+  }
+
+  /** Shows information using modalservice @public */
+  public infoNs(): void {
+    this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = {
+      id: this.instanceID,
+      page: 'ns-instance',
+      titleName: 'INSTANCEDETAILS'
+    };
+  }
+
+  /** Delete NS Instanace @public */
+  public deleteNSInstance(forceAction: boolean): void {
+    const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+    modalRef.componentInstance.params = { forceDeleteType: forceAction };
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+
+  /** History of operations for an Instanace @public */
+  public historyOfOperations(): void {
+    this.router.navigate(['/instances/ns/history-operations/', this.instanceID]).catch(() => {
+      // Catch Navigation Error
+    });
+  }
+
+  /** NS Topology */
+  public nsTopology(): void {
+    this.router.navigate(['/instances/ns/', this.instanceID]).catch(() => {
+      // Catch Navigation Error
+    });
+  }
+
+  /** Exec NS Primitive @public */
+  public execNSPrimitiveModal(): void {
+    this.modalService.open(NSPrimitiveComponent).componentInstance.params = {
+      memberIndex: this.value.memberIndex,
+      nsConfig: this.value.nsConfig
+    };
+  }
+
+  /** Redirect to Grafana Metrics @public */
+  public metrics(): void {
+    this.isLoadingMetricsResult = true;
+    this.restService.getResource(environment.NSDINSTANCES_URL + '/' + this.instanceID).subscribe((nsData: NSDDetails[]) => {
+      nsData['vnfd-id'].forEach((vnfdID: string[]) => {
+        this.restService.getResource(environment.VNFPACKAGES_URL + '/' + vnfdID)
+          .subscribe((vnfd: {}[]) => {
+            if (vnfd['monitoring-param'] !== undefined && vnfd['monitoring-param'].length > 0) {
+              this.isLoadingMetricsResult = false;
+              const location: string = environment.GRAFANA_URL + '/' + this.instanceID + '/osm-ns-metrics-metrics';
+              window.open(location);
+            } else {
+              this.isLoadingMetricsResult = false;
+              this.notifierService.notify('error', this.translateService.instant('GRAFANA.METRICSERROR'));
+            }
+            setTimeout(() => {
+              this.cd.detectChanges();
+            }, this.timeOut);
+          }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingMetricsResult = false;
+          });
+      });
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingMetricsResult = false;
+    });
+  }
+}
diff --git a/src/app/utilities/ns-packages-action/NsPackagesActionComponent.html b/src/app/utilities/ns-packages-action/NsPackagesActionComponent.html
new file mode 100644 (file)
index 0000000..6e33d0d
--- /dev/null
@@ -0,0 +1,55 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+  <button type="button" class="btn btn-primary" (click)="instantiateNS()" placement="top" container="body"
+    ngbTooltip="{{'INSTANTIATE' | translate}} NS">
+    <i class="fa fa-paper-plane icons"></i>
+  </button>
+  <button type="button" class="btn btn-primary" (click)="composeNSPackages()" placement="top" container="body"
+    ngbTooltip="{{'TOPOLOGY' | translate}}">
+    <i class="fa fa-sitemap fa-fw Icon"></i>
+  </button>
+  <button type="button" class="btn btn-primary" (click)="deleteNSPackage()" placement="top" container="body"
+    ngbTooltip="{{'DELETE' | translate}}">
+    <i class="far fa-trash-alt icons"></i>
+  </button>
+  <div ngbDropdown class="btn-group">
+    <button type="button" class="btn btn-primary dropdown-toggle action-button" ngbDropdownToggle>
+      {{'ACTION' | translate}}
+    </button>
+    <div class="dropdown-menu" ngbDropdownMenu>
+      <button type="button" class="btn btn-primary dropdown-item" (click)="nsdEdit()" placement="left"
+        container="body" ngbTooltip="{{'EDIT' | translate}}">
+        <i class="fa fa-edit icons"></i> {{'EDIT' | translate}}
+      </button>
+      <button type="button" class="btn btn-primary dropdown-item" (click)="downloadNSPackage()" placement="left"
+        container="body" ngbTooltip="{{'DOWNLOAD' | translate}}">
+        <i class="fas fa-download icons"></i> {{'DOWNLOAD' | translate}}
+      </button>
+      <button type="button" class="btn btn-primary dropdown-item" (click)="cloneNSPackage()" placement="left"
+        container="body" ngbTooltip="{{'CLONE' | translate}}">
+        <i class="fa fa-clone icons"></i> {{'CLONE' | translate}}
+      </button>
+      <button type="button" class="btn btn-primary dropdown-item" (click)="showContent()" placement="left"
+        container="body" ngbTooltip="{{'CONTENT' | translate}}">
+        <i class="far fa-folder-open icons"></i> {{'CONTENT' | translate}}
+      </button>
+    </div>
+  </div>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingDownloadResult"></app-loader>
\ No newline at end of file
diff --git a/src/app/utilities/ns-packages-action/NsPackagesActionComponent.scss b/src/app/utilities/ns-packages-action/NsPackagesActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/ns-packages-action/NsPackagesActionComponent.ts b/src/app/utilities/ns-packages-action/NsPackagesActionComponent.ts
new file mode 100644 (file)
index 0000000..6e7fbfb
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file NS PackagesAction Component
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { ChangeDetectorRef, Component, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { ClonePackageComponent } from 'ClonePackage';
+import { ERRORDATA, GETAPIURLHEADER, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { environment } from 'environment';
+import { InstantiateNsComponent } from 'InstantiateNs';
+import { NSData } from 'NSDModel';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { ShowContentComponent } from 'ShowContent';
+
+/**
+ * Creating component
+ * @Component takes NsPackagesActionComponent.html as template url
+ */
+@Component({
+  selector: 'app-ns-packages-action',
+  templateUrl: './NsPackagesActionComponent.html',
+  styleUrls: ['./NsPackagesActionComponent.scss']
+})
+
+/** Exporting a class @exports NsPackagesActionComponent */
+export class NsPackagesActionComponent {
+  /** To get the value from the nspackage via valuePrepareFunction default Property of ng-smarttable @public */
+  public value: NSData;
+
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingDownloadResult: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private router: Router;
+
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  /** Variables holds NS ID @private */
+  private nsdID: string;
+
+  /** Variables holds NS name @private */
+  private nsdName: string;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Detect changes for the User Input */
+  private cd: ChangeDetectorRef;
+
+  /** Set timeout @private */
+  private timeOut: number = 1000;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.sharedService = this.injector.get(SharedService);
+    this.modalService = this.injector.get(NgbModal);
+    this.router = this.injector.get(Router);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.cd = this.injector.get(ChangeDetectorRef);
+  }
+
+  /** Lifecyle Hooks the trigger before component is instantiate @public */
+  public ngOnInit(): void {
+    this.headers = new HttpHeaders({
+      Accept: 'application/zip, application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    this.nsdID = this.value.identifier;
+    this.nsdName = this.value.shortName;
+  }
+
+  /** Instantiate NS using modalservice @public */
+  public instantiateNS(): void {
+    this.modalService.open(InstantiateNsComponent, { backdrop: 'static' });
+  }
+
+  /** Delete NS Package @public */
+  public deleteNSPackage(): void {
+    const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+
+  /** Set instance for NSD Edit @public */
+  public nsdEdit(): void {
+    this.router.navigate(['/packages/ns/edit/', this.nsdID]).catch(() => {
+      // Catch Navigation Error
+    });
+  }
+
+  /** list out all the file content of a descriptors @public */
+  public showContent(): void {
+    this.modalService.open(ShowContentComponent, { backdrop: 'static' }).componentInstance.params = { id: this.nsdID, page: 'nsd' };
+  }
+
+  /** Download NS Package @public */
+  public downloadNSPackage(): void {
+    this.isLoadingDownloadResult = true;
+    const httpOptions: GETAPIURLHEADER = {
+      headers: this.headers,
+      responseType: 'blob'
+    };
+    this.restService.getResource(environment.NSDESCRIPTORS_URL + '/' + this.nsdID + '/nsd_content', httpOptions)
+      .subscribe((response: Blob) => {
+        const binaryData: Blob[] = [];
+        binaryData.push(response);
+        this.sharedService.downloadFiles(this.nsdName, binaryData, response.type);
+        this.isLoadingDownloadResult = false;
+        this.changeDetactionforDownload();
+      }, (error: ERRORDATA) => {
+        this.isLoadingDownloadResult = false;
+        this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        this.changeDetactionforDownload();
+        if (typeof error.error === 'object') {
+          error.error.text().then((data: string): void => {
+            error.error = JSON.parse(data);
+            this.restService.handleError(error, 'getBlob');
+          });
+        }
+      });
+  }
+
+  /** Compose NS Packages @public */
+  public composeNSPackages(): void {
+    this.router.navigate(['/packages/ns/compose/', this.nsdID]).catch(() => {
+      // Catch Navigation Error
+    });
+  }
+
+  /** Change the detaction @public */
+   public changeDetactionforDownload(): void {
+    setTimeout(() => {
+      this.cd.detectChanges();
+    }, this.timeOut);
+  }
+
+  /** Clone NS Packages @public */
+  public cloneNSPackage(): void {
+    const cloneModal: NgbModalRef = this.modalService.open(ClonePackageComponent, { backdrop: 'static' });
+    cloneModal.componentInstance.params = { id: this.nsdID, page: 'nsd', name: this.nsdName };
+    cloneModal.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+}
diff --git a/src/app/utilities/page-per-row/PagePerRow.html b/src/app/utilities/page-per-row/PagePerRow.html
new file mode 100644 (file)
index 0000000..a63ebb4
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="page-per-row">
+  <label class="mr-2 mt-2">
+    <b>{{'ENTRIES' | translate}}</b>
+  </label>
+  <select class="form-control custom-select" (change)="onSelectRow($event.target.value)">
+    <option *ngFor="let count of pageCount; let i = index" [value]="count.value" [selected]="count.value === getDefaultSelected">{{count.viewValue}}
+    </option>
+  </select>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/page-per-row/PagePerRow.scss b/src/app/utilities/page-per-row/PagePerRow.scss
new file mode 100644 (file)
index 0000000..06c069e
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+.page-per-row {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+}
\ No newline at end of file
diff --git a/src/app/utilities/page-per-row/PagePerRow.ts b/src/app/utilities/page-per-row/PagePerRow.ts
new file mode 100644 (file)
index 0000000..6794bfc
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+
+/**
+ * @file PagePerRow Model
+ */
+import { Component, EventEmitter, Injector, Output } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { PAGERSMARTTABLE } from 'CommonModel';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes PagePerRow.html as template url
+ */
+@Component({
+  selector: 'page-per-row',
+  templateUrl: './PagePerRow.html',
+  styleUrls: ['./PagePerRow.scss']
+})
+/** Exporting a class @exports PagePerRow */
+export class PagePerRow {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** handle translate @public */
+  public translateService: TranslateService;
+
+  /** get the pagaintion default select value @public */
+  public getDefaultSelected: number;
+
+  /** Controls the pagination List Count form @public */
+  public pageCount: { value: number; viewValue: number; }[] =
+    [
+      { value: 10, viewValue: 10 },
+      { value: 25, viewValue: 25 },
+      { value: 50, viewValue: 50 },
+      { value: 100, viewValue: 100 }
+    ];
+
+  /** Contains all methods related to shared @private */
+  public sharedService: SharedService;
+
+  /** Event emitter to emit selected page number @public */
+  @Output() public pagePerRow: EventEmitter<number> = new EventEmitter();
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    const getPaginationValues: PAGERSMARTTABLE = this.sharedService.paginationPagerConfig();
+    this.getDefaultSelected = getPaginationValues.perPage;
+  }
+
+  /** Handles select event @public */
+  public onSelectRow(e: number): void {
+    this.pagePerRow.emit(e);
+  }
+}
diff --git a/src/app/utilities/page-per-row/PagePerRowModule.ts b/src/app/utilities/page-per-row/PagePerRowModule.ts
new file mode 100644 (file)
index 0000000..e5b8a29
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Page Per Row Module.
+ */
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { TranslateModule } from '@ngx-translate/core';
+import { PagePerRow } from 'PagePerRow';
+
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+    imports: [CommonModule, TranslateModule],
+    declarations: [PagePerRow],
+    exports: [PagePerRow]
+})
+/** Exporting a class @exports PagePerRowModule */
+export class PagePerRowModule {
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        // Empty Block
+    }
+}
diff --git a/src/app/utilities/page-reload/PageReload.html b/src/app/utilities/page-reload/PageReload.html
new file mode 100644 (file)
index 0000000..7d03e52
--- /dev/null
@@ -0,0 +1,21 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<button class="btn btn-sm btn-primary border border-radius-default" placement="top" container="body"
+            ngbTooltip="{{'REFRESH' | translate}}" (click)="reloadPage()">
+    <i class="fas fa-sync"></i>
+</button>
\ No newline at end of file
diff --git a/src/app/utilities/page-reload/PageReload.scss b/src/app/utilities/page-reload/PageReload.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/page-reload/PageReload.ts b/src/app/utilities/page-reload/PageReload.ts
new file mode 100644 (file)
index 0000000..0ea3c3c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Page Reload Component
+ */
+import { Component, Injector } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { SharedService } from 'SharedService';
+/**
+ * Creating component
+ * @Component takes PageReload.html as template url
+ */
+@Component({
+  selector: 'page-reload',
+  templateUrl: './PageReload.html',
+  styleUrls: ['./PageReload.scss']
+})
+/** Exporting a class @exports PageReload */
+export class PageReload {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** handle translate @public */
+  public translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    // Empty Block
+  }
+
+  /** Handles select event @public */
+  public reloadPage(): void {
+    this.sharedService.dataEvent.emit();
+  }
+}
diff --git a/src/app/utilities/page-reload/PageReloadModule.ts b/src/app/utilities/page-reload/PageReloadModule.ts
new file mode 100644 (file)
index 0000000..56c35fd
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Page Per Row Module.
+ */
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateModule } from '@ngx-translate/core';
+import { PageReload } from 'PageReload';
+
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+    imports: [CommonModule, TranslateModule, NgbModule],
+    declarations: [PageReload],
+    exports: [PageReload]
+})
+/** Exporting a class @exports PageReloadModule */
+export class PageReloadModule {
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        // Empty Block
+    }
+}
diff --git a/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.html b/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.html
new file mode 100644 (file)
index 0000000..351cf9a
--- /dev/null
@@ -0,0 +1,25 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <button type="button" class="btn btn-primary" (click)="showInfo()" placement="top" container="body" ngbTooltip="{{'INFO' | translate}}">
+        <i class="fas fa-info icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" (click)="deletePDUInstance()" placement="top" container="body" ngbTooltip="{{'DELETE' | translate}}">
+        <i class="far fa-trash-alt icons"></i>
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.scss b/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.ts b/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.ts
new file mode 100644 (file)
index 0000000..8cfb6cf
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file PDUInstancesActionComponent Component
+ */
+import { Component, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { PDUInstanceDetails } from 'PDUInstanceModel';
+import { SharedService } from 'SharedService';
+import { ShowInfoComponent } from 'ShowInfoComponent';
+
+/**
+ * Creating component
+ * @Component takes PDUInstancesActionComponent.html as template url
+ */
+@Component({
+    templateUrl: './PDUInstancesActionComponent.html',
+    styleUrls: ['./PDUInstancesActionComponent.scss']
+})
+/** Exporting a class @exports PDUInstancesActionComponent */
+export class PDUInstancesActionComponent {
+    /** To get the value from the PDU Instances via valuePrepareFunction default Property of ng-smarttable @public */
+    public value: PDUInstanceDetails;
+
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Contains PDU Instance ID @private */
+    private pduInstanceID: string;
+
+    /** Service holds the router information @private */
+    private router: Router;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.modalService = this.injector.get(NgbModal);
+        this.router = this.injector.get(Router);
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.pduInstanceID = this.value.identifier;
+    }
+
+    /** Delete PDU Instances @public */
+    public deletePDUInstance(): void {
+        const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, {backdrop: 'static'});
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+
+    /** Shows PDU Instances information using modalservice @public */
+    public showInfo(): void {
+        this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = {
+            id: this.pduInstanceID,
+            page: 'pdu-instances',
+            titleName: 'INSTANCEDETAILS'
+        };
+    }
+}
diff --git a/src/app/utilities/project-link/ProjectLinkComponent.html b/src/app/utilities/project-link/ProjectLinkComponent.html
new file mode 100644 (file)
index 0000000..6d29f0b
--- /dev/null
@@ -0,0 +1,25 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<a *ngIf="isPresent" class="link" [ngClass]="value.projectName === selectedProject ? 'activeProject' : ''"
+  href="javascript:void(0);"
+  (click)="value.projectName === selectedProject ? '' : this.projectService.switchProjectModal(value)"  placement="right" container="body" ngbTooltip="{{ (value.projectName === selectedProject ? 'CURRENTPROJECT' : 'SWITCHPROJECT') | translate}}">
+  <span>{{value.projectName}}</span>&nbsp;
+  <i *ngIf="value.projectName === selectedProject" class="fas fa-check-circle text-success"></i>
+  <i *ngIf="value.projectName !== selectedProject" class="fas fa-exchange-alt text-danger"></i>
+</a>
+<span *ngIf="!isPresent">{{value.projectName}}</span>
\ No newline at end of file
diff --git a/src/app/utilities/project-link/ProjectLinkComponent.scss b/src/app/utilities/project-link/ProjectLinkComponent.scss
new file mode 100644 (file)
index 0000000..152cf8d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import '../../../assets/scss/mixins/mixin';
+@import '../../../assets/scss/variable';
+.link{
+    text-decoration: none !important;
+    &.activeProject{
+        border-radius: 3px;
+        @include padding-value(2, 2, 2, 2);
+        text-decoration: none !important;
+        cursor: default;
+    }
+}
\ No newline at end of file
diff --git a/src/app/utilities/project-link/ProjectLinkComponent.ts b/src/app/utilities/project-link/ProjectLinkComponent.ts
new file mode 100644 (file)
index 0000000..35c5b2c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Project Link Component.
+ */
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Injector, OnInit } from '@angular/core';
+import { environment } from 'environment';
+import { ProjectData } from 'ProjectModel';
+import { ProjectService } from 'ProjectService';
+import { RestService } from 'RestService';
+import { UserDetail } from 'UserModel';
+/**
+ * Creating component
+ * @Component takes ProjectLinkComponent.html as template url
+ */
+@Component({
+  selector: 'app-project-link',
+  templateUrl: './ProjectLinkComponent.html',
+  styleUrls: ['./ProjectLinkComponent.scss'],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+/** Exporting a class @exports ProjectLinkComponent */
+export class ProjectLinkComponent implements OnInit {
+  /** Invoke service injectors @public */
+  public injector: Injector;
+  /** Variables holds the selected project @public */
+  public selectedProject: string;
+  /** To get the value from the nspackage via valuePrepareFunction default Property of ng-smarttable @public */
+  public value: ProjectData;
+  /** Variables holds all the projects @public */
+  public projectList: {}[] = [];
+  /** Check the project is present for the user @public */
+  public isPresent: boolean = false;
+  /** Set timeout @private */
+  private timeOut: number = 10;
+  /** Instance of the rest service @private */
+  private restService: RestService;
+  /** Holds all project details @private */
+  private projectService: ProjectService;
+  /** Detect changes for the User Input */
+  private cd: ChangeDetectorRef;
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.projectService = this.injector.get(ProjectService);
+    this.restService = this.injector.get(RestService);
+    this.cd = this.injector.get(ChangeDetectorRef);
+  }
+
+  public ngOnInit(): void {
+    this.selectedProject = localStorage.getItem('project');
+    this.getAdminProjects();
+  }
+
+  /** Get the admin projects to be selectable @public */
+  public getAdminProjects(): void {
+    const username: string = localStorage.getItem('username');
+    this.restService.getResource(environment.USERS_URL + '/' + username).subscribe((projects: UserDetail) => {
+      this.projectList = projects.project_role_mappings;
+      this.isPresent = this.projectList.some((item: ProjectData) => item.project === this.value.project);
+      setTimeout(() => {
+        this.cd.detectChanges();
+      }, this.timeOut);
+    });
+  }
+
+}
diff --git a/src/app/utilities/projects-action/ProjectsActionComponent.html b/src/app/utilities/projects-action/ProjectsActionComponent.html
new file mode 100644 (file)
index 0000000..a5d4d4e
--- /dev/null
@@ -0,0 +1,34 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <div ngbDropdown class="btn-group">
+        <button type="button" class="btn btn-primary dropdown-toggle action-button" ngbDropdownToggle>
+            {{'ACTION' | translate}}
+        </button>
+        <div class="dropdown-menu" ngbDropdownMenu>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="projectEdit()" placement="left"
+                container="body" ngbTooltip="{{'RENAME' | translate}}">
+                <i class="fa fa-edit icons"></i> {{'RENAME' | translate}}
+            </button>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="projectDelete()" placement="left"
+                container="body" ngbTooltip="{{'DELETE' | translate}}">
+                <i class="fas fa-trash-alt icons"></i> {{'DELETE' | translate}}
+            </button>
+        </div>
+    </div>
+</div>
diff --git a/src/app/utilities/projects-action/ProjectsActionComponent.scss b/src/app/utilities/projects-action/ProjectsActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/projects-action/ProjectsActionComponent.ts b/src/app/utilities/projects-action/ProjectsActionComponent.ts
new file mode 100644 (file)
index 0000000..4ac0051
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Projects Action Component
+ */
+import { Component, Injector } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { ProjectCreateUpdateComponent } from 'ProjectCreateUpdate';
+import { ProjectData } from 'ProjectModel';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes ProjectsActionComponent.html as template url
+ */
+@Component({
+    selector: 'app-projects-action',
+    templateUrl: './ProjectsActionComponent.html',
+    styleUrls: ['./ProjectsActionComponent.scss']
+})
+/** Exporting a class @exports ProjectsActionComponent */
+export class ProjectsActionComponent {
+    /** To get the value from the nspackage via valuePrepareFunction default Property of ng-smarttable @public */
+    public value: ProjectData;
+
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.modalService = this.injector.get(NgbModal);
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /** Delete project @public */
+    public projectDelete(): void {
+        const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+
+    /** Edit project @public */
+    public projectEdit(): void {
+        const modalRef: NgbModalRef = this.modalService.open(ProjectCreateUpdateComponent, { backdrop: 'static' });
+        modalRef.componentInstance.projectType = 'Edit';
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+}
diff --git a/src/app/utilities/roles-action/RolesActionComponent.html b/src/app/utilities/roles-action/RolesActionComponent.html
new file mode 100644 (file)
index 0000000..5a7453d
--- /dev/null
@@ -0,0 +1,34 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+  <div ngbDropdown class="btn-group">
+      <button type="button" class="btn btn-primary dropdown-toggle action-button" ngbDropdownToggle>
+          {{'ACTION' | translate}}
+      </button>
+      <div class="dropdown-menu" ngbDropdownMenu>
+          <button type="button" class="btn btn-primary dropdown-item" (click)="editRole()" placement="left"
+              container="body" ngbTooltip="{{'EDIT' | translate}}">
+              <i class="fa fa-edit icons"></i> {{'EDIT' | translate}}
+          </button>
+          <button type="button" class="btn btn-primary dropdown-item" (click)="deleteRole()" placement="left"
+              container="body" ngbTooltip="{{'DELETE' | translate}}">
+              <i class="fas fa-trash-alt icons"></i> {{'DELETE' | translate}}
+          </button>
+      </div>
+  </div>
+</div>
diff --git a/src/app/utilities/roles-action/RolesActionComponent.scss b/src/app/utilities/roles-action/RolesActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/roles-action/RolesActionComponent.ts b/src/app/utilities/roles-action/RolesActionComponent.ts
new file mode 100644 (file)
index 0000000..5b4d85b
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Roles Action Component
+ */
+import { Component, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { RoleData } from 'RolesModel';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes RolesActionComponent.html as template url
+ */
+@Component({
+  selector: 'app-roles-action',
+  templateUrl: './RolesActionComponent.html',
+  styleUrls: ['./RolesActionComponent.scss']
+})
+/** Exporting a class @exports RolesActionComponent */
+export class RolesActionComponent {
+  /** To get the role data via valuePrepareFunction default Property of ng-smarttable @public */
+  public value: RoleData;
+
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Holds the instance of roter service @private */
+  private router: Router;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.modalService = this.injector.get(NgbModal);
+    this.sharedService = this.injector.get(SharedService);
+    this.router = this.injector.get(Router);
+  }
+
+  /** Delete Role click handler @public */
+  public deleteRole(): void {
+    const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+
+  /** Edit Role click handler @public */
+  public editRole(): void {
+    this.router.navigate(['/roles/edit', this.value.identifier]).catch(() => {
+      // Catch Navigation Error
+    });
+  }
+
+}
diff --git a/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.html b/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.html
new file mode 100644 (file)
index 0000000..454527e
--- /dev/null
@@ -0,0 +1,27 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <button type="button" class="btn btn-primary" (click)="showSDNControllerInfo()" placement="top" container="body"
+        ngbTooltip="{{'INFO' | translate}}">
+        <i class="fas fa-info icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" (click)="deleteSDNController()" placement="top" container="body"
+        ngbTooltip="{{'DELETE' | translate}}">
+        <i class="far fa-trash-alt icons"></i>
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.scss b/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.ts b/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.ts
new file mode 100644 (file)
index 0000000..cbf3fc1
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file SDN Controller Action Component
+ */
+import { Component, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { SDNControllerInfoComponent } from 'SDNControllerInfoComponent';
+import { SDNControllerList } from 'SDNControllerModel';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating component
+ * @Component takes SDNControllerActionComponent.html as template url
+ */
+@Component({
+    templateUrl: './SDNControllerActionComponent.html',
+    styleUrls: ['./SDNControllerActionComponent.scss']
+})
+/** Exporting a class @exports SDNControllerActionComponent */
+export class SDNControllerActionComponent {
+    /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */
+    public value: SDNControllerList;
+
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Variables holds SDN ID @private */
+    private sdnID: string;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.modalService = this.injector.get(NgbModal);
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.sdnID = this.value.identifier;
+    }
+
+    /** Show SDN Controller Information @public */
+    public showSDNControllerInfo(): void {
+        this.modalService.open(SDNControllerInfoComponent, { backdrop: 'static' }).componentInstance.params = {
+            id: this.sdnID,
+            page: 'sdn-controller'
+        };
+    }
+
+    /** Delete SDN Controller @public */
+    public deleteSDNController(): void {
+        const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+}
diff --git a/src/app/utilities/show-info/ShowInfoComponent.html b/src/app/utilities/show-info/ShowInfoComponent.html
new file mode 100644 (file)
index 0000000..7fff58d
--- /dev/null
@@ -0,0 +1,35 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="modal-header">
+  <h4 class="modal-title" id="modal-basic-title">{{titleName | translate}}</h4>
+  <button class="button-xs" type="button" class="close" (click)="activeModal.close()">
+    <i class="fas fa-times-circle text-danger"></i>
+  </button>
+</div>
+<div class="modal-body">
+  <div class="ngx-codemirror mb-2" *ngIf="defaults[mode] else noData">
+    <ngx-codemirror [options]="options" [ngModel]="defaults[mode]" [disabled]="readOnly" [autoFocus]="true">
+    </ngx-codemirror>
+  </div>
+  <ng-template #noData>{{'NODATAERROR' | translate}}
+  </ng-template>
+</div>
+<div class="modal-footer">
+  <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/utilities/show-info/ShowInfoComponent.scss b/src/app/utilities/show-info/ShowInfoComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/show-info/ShowInfoComponent.ts b/src/app/utilities/show-info/ShowInfoComponent.ts
new file mode 100644 (file)
index 0000000..0fb22e7
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Info Ns Model
+ */
+import { HttpClient } from '@angular/common/http';
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import 'codemirror/addon/dialog/dialog';
+import 'codemirror/addon/display/autorefresh';
+import 'codemirror/addon/display/fullscreen';
+import 'codemirror/addon/edit/closebrackets';
+import 'codemirror/addon/edit/matchbrackets';
+import 'codemirror/addon/fold/brace-fold';
+import 'codemirror/addon/fold/foldcode';
+import 'codemirror/addon/fold/foldgutter';
+import 'codemirror/addon/search/search';
+import 'codemirror/addon/search/searchcursor';
+import 'codemirror/keymap/sublime';
+import 'codemirror/lib/codemirror';
+import 'codemirror/mode/javascript/javascript';
+import 'codemirror/mode/markdown/markdown';
+import 'codemirror/mode/yaml/yaml';
+import { ERRORDATA, URLPARAMS } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { NSDDetails } from 'NSDModel';
+import { RestService } from 'RestService';
+/** Set defaults json as type in information modal @constant */
+const defaults: {} = {
+  'text/json': ''
+};
+/**
+ * Creating component
+ * @Component takes ShowInfoComponent.html as template url
+ */
+@Component({
+  templateUrl: './ShowInfoComponent.html',
+  styleUrls: ['./ShowInfoComponent.scss']
+})
+/** Exporting a class @exports ShowInfoComponent */
+export class ShowInfoComponent implements OnInit {
+  /** Invoke service injectors @public */
+  public injector: Injector;
+
+  /** dataService to pass the data from one component to another @public */
+  public dataService: DataService;
+
+  /** Default variables holds NS data @public */
+  public defaults: {} = defaults;
+
+  /** Varaibles to hold http client @public */
+  public httpClient: HttpClient;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** variables readOnly holds boolean @public */
+  public readOnly: boolean = true;
+
+  /** variables to hold mode changes of editor @public */
+  public mode: string = 'text/json';
+
+  /** To Set Mode @public */
+  public modeDefault: string = 'javascript';
+
+  /** variables to hold options of editor @public */
+  public options: {} = {
+    mode: this.modeDefault,
+    showCursorWhenSelecting: true,
+    autofocus: true,
+    lineNumbers: true,
+    lineWrapping: true,
+    foldGutter: true,
+    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
+    autoCloseBrackets: true,
+    matchBrackets: true,
+    theme: 'neat',
+    keyMap: 'sublime'
+  };
+
+  /** Reading the page Name @public */
+  public titleName: string;
+
+  /** Check the loading results @public */
+  public isLoadingResults: Boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Input contains component objects @private */
+  @Input() private params: URLPARAMS;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.dataService = this.injector.get(DataService);
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.isLoadingResults = true;
+    this.defaults['text/json'] = '';
+    this.titleName = this.params.titleName;
+    // Checks page and assign URL
+    if (this.params.page === 'ns-instance') {
+      this.restService.getResource(environment.NSINSTANCESCONTENT_URL + '/' + this.params.id).subscribe((nsData: NSDDetails[]) => {
+        this.defaults['text/json'] = JSON.stringify(nsData, null, '\t');
+      }, (error: ERRORDATA) => {
+        this.isLoadingResults = false;
+        this.restService.handleError(error, 'get');
+      }, () => {
+        this.isLoadingResults = false;
+      });
+    } else if (this.params.page === 'ns-history-operation') {
+      this.restService.getResource(environment.NSHISTORYOPERATIONS_URL + '/' +
+        this.params.id).subscribe((nsHistoryOpn: {}[]) => {
+          this.defaults['text/json'] = JSON.stringify(nsHistoryOpn, null, '\t');
+        }, (error: ERRORDATA) => {
+          this.isLoadingResults = false;
+          this.restService.handleError(error, 'get');
+        }, () => {
+          this.isLoadingResults = false;
+        });
+    } else if (this.params.page === 'vnf-instance') {
+      this.restService.getResource(environment.VNFINSTANCES_URL + '/' + this.params.id).subscribe((vnfData: {}[]) => {
+        this.defaults['text/json'] = JSON.stringify(vnfData, null, '\t');
+      }, (error: ERRORDATA) => {
+        this.isLoadingResults = false;
+        this.restService.handleError(error, 'get');
+      }, () => {
+        this.isLoadingResults = false;
+      });
+    } else if (this.params.page === 'net-slice-package') {
+      this.restService.getResource(environment.NETWORKSLICETEMPLATECONTENT_URL + '/' + this.params.id).subscribe((netSliceData: {}[]) => {
+        this.defaults['text/json'] = JSON.stringify(netSliceData, null, '\t');
+      }, (error: ERRORDATA) => {
+        this.isLoadingResults = false;
+        this.restService.handleError(error, 'get');
+      }, () => {
+        this.isLoadingResults = false;
+      });
+    } else if (this.params.page === 'net-slice-instance') {
+      this.restService.getResource(environment.NETWORKSLICEINSTANCESCONTENT_URL + '/' + this.params.id)
+        .subscribe((netSliceInstanceData: {}[]) => {
+          this.defaults['text/json'] = JSON.stringify(netSliceInstanceData, null, '\t');
+        }, (error: ERRORDATA) => {
+          this.isLoadingResults = false;
+          this.restService.handleError(error, 'get');
+        }, () => {
+          this.isLoadingResults = false;
+        });
+    } else if (this.params.page === 'nst-history-operation') {
+      this.restService.getResource(environment.NSTHISTORYOPERATIONS_URL + '/' +
+        this.params.id).subscribe((nstHistoryOpn: {}[]) => {
+          this.defaults['text/json'] = JSON.stringify(nstHistoryOpn, null, '\t');
+        }, (error: ERRORDATA) => {
+          this.isLoadingResults = false;
+          this.restService.handleError(error, 'get');
+        }, () => {
+          this.isLoadingResults = false;
+        });
+    } else if (this.params.page === 'pdu-instances') {
+      this.restService.getResource(environment.PDUINSTANCE_URL + '/' +
+        this.params.id).subscribe((pduInstanceOpn: {}[]) => {
+          this.defaults['text/json'] = JSON.stringify(pduInstanceOpn, null, '\t');
+        }, (error: ERRORDATA) => {
+          this.isLoadingResults = false;
+          this.restService.handleError(error, 'get');
+        }, () => {
+          this.isLoadingResults = false;
+        });
+    } else if (this.params.page === 'k8s-cluster') {
+      this.restService.getResource(environment.K8SCLUSTER_URL + '/' +
+        this.params.id).subscribe((k8sclusterOpn: {}[]) => {
+          this.defaults['text/json'] = JSON.stringify(k8sclusterOpn, null, '\t');
+        }, (error: ERRORDATA) => {
+          this.isLoadingResults = false;
+          this.restService.handleError(error, 'get');
+        }, () => {
+          this.isLoadingResults = false;
+        });
+    } else if (this.params.page === 'k8s-repo') {
+      this.restService.getResource(environment.K8REPOS_URL + '/' +
+        this.params.id).subscribe((k8srepoOpn: {}[]) => {
+          this.defaults['text/json'] = JSON.stringify(k8srepoOpn, null, '\t');
+        }, (error: ERRORDATA) => {
+          this.isLoadingResults = false;
+          this.restService.handleError(error, 'get');
+        }, () => {
+          this.isLoadingResults = false;
+        });
+    }
+  }
+}
diff --git a/src/app/utilities/switch-project/SwitchProjectComponent.html b/src/app/utilities/switch-project/SwitchProjectComponent.html
new file mode 100644 (file)
index 0000000..948591a
--- /dev/null
@@ -0,0 +1,40 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="switchProjectForm" (ngSubmit)="switchProject()" autocomplete="off">
+  <div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">{{'SWITCHPROJECT' | translate}}</h4>
+    <button class="button-xs" type="button" class="close" (click)="activeModal.close()">
+      <i class="fas fa-times-circle text-danger"></i>
+    </button>
+  </div>
+  <div class="modal-body">
+    <div class="form-group row">
+      <label class="col-sm-12 col-form-label mandatory-label" [ngClass]="{'text-danger': switchProjectForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+      <label class="col-sm-6 col-form-label">{{'ENTER' | translate}} {{'PASSWORD' | translate}}*</label>
+      <div class="col-sm-6">
+        <input autocomplete="off" type="password" class="form-control" placeholder="{{'ENTER' | translate}} {{'PASSWORD' | translate}}" formControlName="password"
+          id="password" [ngClass]="{ 'is-invalid': submitted && f.password.errors }" required>
+      </div>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+    <button type="submit" class="btn btn-primary">{{'SUBMIT' | translate}}</button>
+  </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/utilities/switch-project/SwitchProjectComponent.scss b/src/app/utilities/switch-project/SwitchProjectComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/switch-project/SwitchProjectComponent.ts b/src/app/utilities/switch-project/SwitchProjectComponent.ts
new file mode 100644 (file)
index 0000000..1df6a16
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Switch Project Component
+ */
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { APIURLHEADER, ERRORDATA, LOCALSTORAGE, URLPARAMS } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { RestService } from 'RestService';
+
+/**
+ * Creating component
+ * @Component takes SwitchProjectComponent.html as template url
+ */
+@Component({
+  templateUrl: './SwitchProjectComponent.html',
+  styleUrls: ['./SwitchProjectComponent.scss']
+})
+/** Exporting a class @exports SwitchProjectComponent */
+export class SwitchProjectComponent implements OnInit {
+  /** Invoke service injectors @public */
+  public injector: Injector;
+
+  /** dataService to pass the data from one component to another @public */
+  public dataService: DataService;
+
+  /** Varaibles to hold http client @public */
+  public httpClient: HttpClient;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** FormGroup instance added to the form @ html @public */
+  public switchProjectForm: FormGroup;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Check the Projects loading results @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Input contains component objects @private */
+  @Input() private params: URLPARAMS;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.dataService = this.injector.get(DataService);
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.formBuilder = this.injector.get(FormBuilder);
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.switchProjectForm.controls; }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.initializeForm();
+  }
+
+  /** initialize Forms @public */
+  public initializeForm(): void {
+    this.switchProjectForm = this.formBuilder.group({
+      password: ['', [Validators.required]]
+    });
+  }
+
+  /** Switch project @public */
+  public switchProject(): void {
+    this.submitted = true;
+    if (!this.switchProjectForm.invalid) {
+      this.isLoadingResults = true;
+      this.headers = new HttpHeaders({
+        'Content-Type': 'application/json',
+        Accept: 'application/json',
+        'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+      });
+      const payLoad: {} = JSON.stringify({
+        username: this.params.username,
+        password: this.switchProjectForm.value.password,
+        project_id: this.params.projectID
+      });
+      const apiURLHeader: APIURLHEADER = {
+        url: environment.GENERATETOKEN_URL,
+        httpOptions: { headers: this.headers }
+      };
+      this.restService.postResource(apiURLHeader, payLoad).subscribe((data: LOCALSTORAGE) => {
+        if (data) {
+          localStorage.setItem('id_token', data.id);
+          localStorage.setItem('project_id', this.params.projectID);
+          localStorage.setItem('expires', data.expires.toString());
+          localStorage.setItem('username', data.username);
+          localStorage.setItem('project', data.project_name);
+          localStorage.setItem('token_state', data.id);
+          this.activeModal.close();
+          location.reload();
+          this.isLoadingResults = false;
+        }
+      }, (error: ERRORDATA) => {
+        this.isLoadingResults = false;
+        this.restService.handleError(error, 'post');
+        this.activeModal.close();
+      });
+    }
+  }
+}
diff --git a/src/app/utilities/users-action/UsersActionComponent.html b/src/app/utilities/users-action/UsersActionComponent.html
new file mode 100644 (file)
index 0000000..9ce546e
--- /dev/null
@@ -0,0 +1,42 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <div ngbDropdown class="btn-group">
+        <button type="button" class="btn btn-primary dropdown-toggle action-button" ngbDropdownToggle>
+            {{'ACTION' | translate}}
+        </button>
+        <div class="dropdown-menu" ngbDropdownMenu>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="editUserModal('editPassword')" placement="left" container="body"
+                ngbTooltip="{{'PAGE.USERS.EDITCREDENTIALS' | translate}}">
+                <i class="fa fa-edit icons"></i> {{'PAGE.USERS.EDITCREDENTIALS' | translate}}
+            </button>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="editUserModal('editUserName')" placement="left" container="body"
+                ngbTooltip="{{'PAGE.USERS.EDITUSERNAME' | translate}}">
+                <i class="fas fa-user-edit"></i> {{'PAGE.USERS.EDITUSERNAME' | translate}}
+            </button>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="projectRolesModal()" placement="left" container="body"
+                ngbTooltip="{{'PAGE.USERS.PROJECTSROLES' | translate}}">
+                <i class="fas fa-user-check"></i> {{'PAGE.USERS.PROJECTSROLES' | translate}}
+            </button>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="deleteUser()" placement="left" container="body"
+                ngbTooltip="{{'DELETE' | translate}}">
+                <i class="far fa-trash-alt icons" title="delete"></i> {{'DELETE' | translate}}
+            </button>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/users-action/UsersActionComponent.scss b/src/app/utilities/users-action/UsersActionComponent.scss
new file mode 100644 (file)
index 0000000..fdec4ed
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
diff --git a/src/app/utilities/users-action/UsersActionComponent.ts b/src/app/utilities/users-action/UsersActionComponent.ts
new file mode 100644 (file)
index 0000000..1d8e895
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Users Action Component
+ */
+import { Component, Injector } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { AddEditUserComponent } from 'AddEditUserComponent';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { ProjectRoleComponent } from 'ProjectRoleComponent';
+import { SharedService } from 'SharedService';
+import { UserData } from 'UserModel';
+/**
+ * Creating component
+ * @Component takes UsersActionComponent.html as template url
+ */
+@Component({
+    templateUrl: './UsersActionComponent.html',
+    styleUrls: ['./UsersActionComponent.scss']
+})
+/** Exporting a class @exports UsersActionComponent */
+export class UsersActionComponent {
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** To get the value from the Users action via valuePrepareFunction default Property of ng-smarttable @public */
+    public value: UserData;
+
+    /** handle translate @public */
+    public translateService: TranslateService;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.modalService = this.injector.get(NgbModal);
+        this.sharedService = this.injector.get(SharedService);
+        this.translateService = this.injector.get(TranslateService);
+    }
+
+    /** Delete User Account @public */
+    public deleteUser(): void {
+        const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+
+    /** Edit User Account @public */
+    public editUserModal(editType: string): void {
+        const modalRef: NgbModalRef = this.modalService.open(AddEditUserComponent, { backdrop: 'static' });
+        modalRef.componentInstance.userID = this.value.identifier;
+        if (editType === 'editPassword') {
+            modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.EDITCREDENTIALS');
+        } else {
+            modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.EDITUSERNAME');
+        }
+        modalRef.componentInstance.userType = editType;
+        modalRef.componentInstance.userName = this.value.username;
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+
+    /** Edit User Account @public */
+    public projectRolesModal(): void {
+        const modalRef: NgbModalRef = this.modalService.open(ProjectRoleComponent, { backdrop: 'static' });
+        modalRef.componentInstance.userID = this.value.identifier;
+        modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.EDITPROJECTROLEMAPPING');
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+}
diff --git a/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.html b/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.html
new file mode 100644 (file)
index 0000000..7491d59
--- /dev/null
@@ -0,0 +1,46 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <ng-template #popTitle>
+        <span class="text-primary"><strong>{{'PAGE.DASHBOARD.RUNNINGINSTANCES' | translate}}</strong></span>
+        <button class="button-xs close" type="button" (click)="p.close()">
+            <i class="fas fa-times-circle text-danger"></i>
+        </button>
+    </ng-template>
+    <ng-template #popContent>
+        <ul class="list-group">
+            <li class="list-group-item text-left p-1 border-0" *ngFor="let instanceDetails of showInstanceDetails">
+                <a class="d-block text-truncate" target="_parent"
+                    routerLink="/instances/ns/{{instanceDetails._id}}"><i class="fa-sitemap fas icons"></i> {{instanceDetails.name}}</a>
+            </li>
+        </ul>
+    </ng-template>
+    <button type="button" class="btn btn-primary" (click)="vimInfo()" placement="top" container="body"
+        ngbTooltip="{{'INFO' | translate}}">
+        <i class="fas fa-info icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" (click)="deleteVIMAccount()" placement="top" container="body"
+        ngbTooltip="{{'DELETE' | translate}}">
+        <i class="far fa-trash-alt icons"></i>
+    </button>
+    <button type="button" placement="left" container="body" [ngbPopover]="popContent" triggers="manual" #p="ngbPopover"
+        (click)="p.open()" [autoClose]="'outside'" [popoverTitle]="popTitle" class="btn btn-primary"
+        popoverClass="runninginstances" [disabled]="!showMapIcon">
+        <i class="fas fa-layer-group"></i>
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.scss b/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.ts b/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.ts
new file mode 100644 (file)
index 0000000..57f1f64
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Vim AccountsAction Component
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { NSInstanceDetails } from 'NSInstanceModel';
+import { SharedService } from 'SharedService';
+import { VIMData } from 'VimAccountModel';
+
+/**
+ * Creating component
+ * @Component takes VimAccountsActionComponent.html as template url
+ */
+@Component({
+    selector: 'app-vim-accounts-action',
+    templateUrl: './VimAccountsActionComponent.html',
+    styleUrls: ['./VimAccountsActionComponent.scss']
+})
+/** Exporting a class @exports VimAccountsActionComponent */
+export class VimAccountsActionComponent implements OnInit {
+    /** To get the value from the vimAccounts via valuePrepareFunction default Property of ng-smarttable @public */
+    public value: VIMData;
+
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** To show Instances running @public */
+    public showMapIcon: boolean =  false;
+
+    /** To show Details Instances running @public */
+    public showInstanceDetails: {}[];
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Holds teh instance of AuthService class of type AuthService @private */
+    private router: Router;
+
+    /** Variables holds NS ID @private */
+    private vimID: string;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.modalService = this.injector.get(NgbModal);
+        this.router = this.injector.get(Router);
+        this.sharedService = this.injector.get(SharedService);
+    }
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.getInstancesDetails();
+    }
+
+    /** Delete VIM Account @public */
+    public deleteVIMAccount(): void {
+        const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, {backdrop: 'static'});
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+
+    /** On navigate to Info VimAccount @public */
+    public vimInfo(): void {
+        this.vimID = this.value.identifier;
+        this.router.navigate(['/vim/info', this.vimID]).catch(() => {
+            // Catch Navigation Error
+          });
+    }
+
+    /** To show the Instances Info for the particular VimAccount @public */
+    public getInstancesDetails(): void {
+        this.showInstanceDetails = [];
+        this.value.instancesData.filter((item: NSInstanceDetails) => {
+            if (item.datacenter === this.value.identifier) {
+                this.showMapIcon = true;
+                this.showInstanceDetails.push(item);
+            }
+        });
+    }
+}
diff --git a/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.html b/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.html
new file mode 100644 (file)
index 0000000..333beea
--- /dev/null
@@ -0,0 +1,23 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <button type="button" (click)="infoVNF()" class="btn btn-primary" placement="top" container="body"
+    ngbTooltip="{{'VNFR' | translate}}">
+    <i class="fas fa-info icons"></i>
+  </button>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.scss b/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.scss
new file mode 100644 (file)
index 0000000..8c2b739
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
diff --git a/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.ts b/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.ts
new file mode 100644 (file)
index 0000000..d3a95f2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file VNF-instancesAction Component
+ */
+import { Component, Injector } from '@angular/core';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { ShowInfoComponent } from 'ShowInfoComponent';
+import { VNFInstanceData } from 'VNFInstanceModel';
+/**
+ * Creating component
+ * @Component takes VNFInstancesActionComponent.html as template url
+ */
+@Component({
+    templateUrl: './VNFInstancesActionComponent.html',
+    styleUrls: ['./VNFInstancesActionComponent.scss']
+})
+/** Exporting a class @exports VNFInstancesActionComponent */
+export class VNFInstancesActionComponent {
+    /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */
+    public value: VNFInstanceData;
+
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Contains instance ID @private */
+    private instanceID: string;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.modalService = this.injector.get(NgbModal);
+    }
+
+    /**
+     * Lifecyle Hooks the trigger before component is instantiate
+     */
+    public ngOnInit(): void {
+        this.instanceID = this.value.identifier;
+    }
+
+    /** Shows information using modalservice @public */
+    public infoVNF(): void {
+        this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = {
+            id: this.instanceID,
+            page: 'vnf-instance',
+            titleName: 'INSTANCEDETAILS'
+        };
+    }
+}
diff --git a/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.html b/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.html
new file mode 100644 (file)
index 0000000..df3aa52
--- /dev/null
@@ -0,0 +1,51 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+  <button type="button" class="btn btn-primary" placement="top" container="body" (click)="composeVNFPackages()"
+    ngbTooltip="{{'TOPOLOGY' | translate}}">
+    <i class="fa fa-sitemap fa-fw Icon"></i>
+  </button>
+  <button type="button" class="btn btn-primary" (click)="deleteVNFPackage()" placement="top" container="body"
+    ngbTooltip="{{'DELETE' | translate}}">
+    <i class="far fa-trash-alt icons"></i>
+  </button>
+  <div ngbDropdown class="btn-group">
+    <button type="button" class="btn btn-primary dropdown-toggle action-button" ngbDropdownToggle>
+      {{'ACTION' | translate}}
+    </button>
+    <div class="dropdown-menu" ngbDropdownMenu>
+      <button type="button" class="btn btn-primary dropdown-item" (click)="vnfdEdit()" placement="left"
+        container="body" ngbTooltip="{{'EDIT' | translate}}">
+        <i class="fa fa-edit icons"></i> {{'EDIT' | translate}}
+      </button>
+      <button type="button" class="btn btn-primary dropdown-item" (click)="downloadVNFPackage()" placement="left"
+        container="body" ngbTooltip="{{'DOWNLOAD' | translate}}">
+        <i class="fas fa-download icons"></i> {{'DOWNLOAD' | translate}}
+      </button>
+      <button type="button" class="btn btn-primary dropdown-item" (click)="cloneVNFPackage()" placement="left"
+        container="body" ngbTooltip="{{'CLONE' | translate}}">
+        <i class="fa fa-clone icons"></i> {{'CLONE' | translate}}
+      </button>
+      <button type="button" class="btn btn-primary dropdown-item" (click)="showContent()" placement="left"
+        container="body" ngbTooltip="{{'CONTENT' | translate}}">
+        <i class="far fa-folder-open icons"></i> {{'CONTENT' | translate}}
+      </button>
+    </div>
+  </div>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingDownloadResult"></app-loader>
\ No newline at end of file
diff --git a/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.scss b/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.ts b/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.ts
new file mode 100644 (file)
index 0000000..f9d1955
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file VNF-packagesAction Component
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { ChangeDetectorRef, Component, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { ClonePackageComponent } from 'ClonePackage';
+import { ERRORDATA, GETAPIURLHEADER, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { environment } from 'environment';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { ShowContentComponent } from 'ShowContent';
+import { VNFData } from 'VNFDModel';
+
+/**
+ * Creating component
+ * @Component takes VNFPackagesActionComponent.html as template url
+ */
+@Component({
+  templateUrl: './VNFPackagesActionComponent.html',
+  styleUrls: ['./VNFPackagesActionComponent.scss']
+})
+/** Exporting a class @exports VNFPackagesActionComponent */
+export class VNFPackagesActionComponent {
+  /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */
+  public value: VNFData;
+
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingDownloadResult: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private router: Router;
+
+  /** Instance of the modal service @private */
+  private modalService: NgbModal;
+
+  /** Variables holds NS ID @private */
+  private vnfID: string;
+
+  /** Variables holds NS name @private */
+  private vnfName: string;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Detect changes for the User Input */
+  private cd: ChangeDetectorRef;
+
+  /** Set timeout @private */
+  private timeOut: number = 1000;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.sharedService = this.injector.get(SharedService);
+    this.modalService = this.injector.get(NgbModal);
+    this.router = this.injector.get(Router);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.cd = this.injector.get(ChangeDetectorRef);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.headers = new HttpHeaders({
+      Accept: 'application/zip, application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+    this.vnfID = this.value.identifier;
+    this.vnfName = this.value.shortName;
+  }
+
+  /** Delete VNF packages @public */
+  public deleteVNFPackage(): void {
+    const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+    modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+
+  /** Set instance for NSD Edit @public */
+  public vnfdEdit(): void {
+    this.router.navigate(['/packages/vnf/edit/', this.vnfID]).then((nav: {}) => {
+      // Navigated Successfully
+    }, (error: Error) => {
+      // Navigation Error Handler
+    });
+  }
+
+  /** list out all the file content of a descriptors @public */
+  public showContent(): void {
+    this.modalService.open(ShowContentComponent, { backdrop: 'static' }).componentInstance.params = { id: this.vnfID, page: 'vnfd' };
+  }
+
+  /** Download VNF Package @public */
+  public downloadVNFPackage(): void {
+    this.isLoadingDownloadResult = true;
+    const httpOptions: GETAPIURLHEADER = {
+      headers: this.headers,
+      responseType: 'blob'
+    };
+    this.restService.getResource(environment.VNFPACKAGES_URL + '/' + this.vnfID + '/package_content', httpOptions)
+      .subscribe((response: Blob) => {
+        this.isLoadingDownloadResult = false;
+        this.changeDetactionforDownload();
+        const binaryData: Blob[] = [];
+        binaryData.push(response);
+        this.sharedService.downloadFiles(this.vnfName, binaryData, response.type);
+      }, (error: ERRORDATA) => {
+        this.isLoadingDownloadResult = false;
+        this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        this.changeDetactionforDownload();
+        if (typeof error.error === 'object') {
+          error.error.text().then((data: string): void => {
+            error.error = JSON.parse(data);
+            this.restService.handleError(error, 'getBlob');
+          });
+        }
+      });
+  }
+
+  /** Compose VNF Packages @public */
+  public composeVNFPackages(): void {
+    this.router.navigate(['/packages/vnf/compose/', this.vnfID]).catch();
+  }
+
+  /** Change the detaction @public */
+  public changeDetactionforDownload(): void {
+    setTimeout(() => {
+      this.cd.detectChanges();
+    }, this.timeOut);
+  }
+
+  /** Clone NS Packages @public */
+  public cloneVNFPackage(): void {
+    const cloneModal: NgbModalRef = this.modalService.open(ClonePackageComponent, { backdrop: 'static' });
+    cloneModal.componentInstance.params = { id: this.vnfID, page: 'vnfd', name: this.vnfName };
+    cloneModal.result.then((result: MODALCLOSERESPONSEDATA) => {
+      if (result) {
+        this.sharedService.callData();
+      }
+    }).catch();
+  }
+}
diff --git a/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.html b/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.html
new file mode 100644 (file)
index 0000000..902bb42
--- /dev/null
@@ -0,0 +1,27 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="btn-group list action" role="group">
+    <button type="button" class="btn btn-primary" (click)="showWIMAccountInfo()" placement="top" container="body"
+        ngbTooltip="{{'INFO' | translate}}">
+        <i class="fas fa-info icons"></i>
+    </button>
+    <button type="button" class="btn btn-primary" (click)="deleteWIMAccount()" placement="top" container="body"
+        ngbTooltip="{{'DELETE' | translate}}">
+        <i class="far fa-trash-alt icons"></i>
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.scss b/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.scss
new file mode 100644 (file)
index 0000000..031e56e
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.ts b/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.ts
new file mode 100644 (file)
index 0000000..0769863
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file WIM AccountsAction Component
+ */
+import { Component, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DeleteComponent } from 'DeleteComponent';
+import { SharedService } from 'SharedService';
+import { WIMAccountInfoComponent } from 'WIMAccountInfo';
+import { WIMValue } from 'WIMAccountModel';
+
+/**
+ * Creating component
+ * @Component takes WIMAccountsActionComponent.html as template url
+ */
+@Component({
+    templateUrl: './WIMAccountsActionComponent.html',
+    styleUrls: ['./WIMAccountsActionComponent.scss']
+})
+/** Exporting a class @exports WIMAccountsActionComponent */
+export class WIMAccountsActionComponent {
+    /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */
+    public value: WIMValue;
+
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Variables holds WIM ID @private */
+    private wimID: string;
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.modalService = this.injector.get(NgbModal);
+        this.sharedService = this.injector.get(SharedService);
+    }
+
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.wimID = this.value.identifier;
+    }
+
+    /** Show WIM account information @public */
+    public showWIMAccountInfo(): void {
+        this.modalService.open(WIMAccountInfoComponent, { backdrop: 'static' }).componentInstance.params = {
+            id: this.wimID,
+            page: 'wim-accounts'
+        };
+    }
+
+    /** Delete WIM Account @public */
+    public deleteWIMAccount(): void {
+        const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' });
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+}
diff --git a/src/app/vim-accounts/VimAccountsComponent.html b/src/app/vim-accounts/VimAccountsComponent.html
new file mode 100644 (file)
index 0000000..3f96ff8
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<router-outlet></router-outlet>
\ No newline at end of file
diff --git a/src/app/vim-accounts/VimAccountsComponent.scss b/src/app/vim-accounts/VimAccountsComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/vim-accounts/VimAccountsComponent.ts b/src/app/vim-accounts/VimAccountsComponent.ts
new file mode 100644 (file)
index 0000000..9951cfc
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Vim Account Component.
+ */
+import { Component, Injector } from '@angular/core';
+import { Router, RouterEvent } from '@angular/router';
+
+/**
+ * Creating component
+ * @Component takes VimAccountsComponent.html as template url
+ */
+@Component({
+    selector: 'app-vim-accounts',
+    templateUrl: './VimAccountsComponent.html',
+    styleUrls: ['./VimAccountsComponent.scss']
+})
+/** Exporting a class @exports VimAccountsComponent */
+export class VimAccountsComponent {
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** Holds teh instance of AuthService class of type AuthService @private */
+    private router: Router;
+
+    // creates packages component
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.router = this.injector.get(Router);
+        this.router.events.subscribe((event: RouterEvent) => {
+            this.redirectToList(event.url);
+        });
+    }
+
+    /** Return to list NS Package List */
+    public redirectToList(getURL: string): void {
+        if (getURL === '/vim') {
+            this.router.navigate(['/vim/details']).catch();
+        }
+    }
+}
diff --git a/src/app/vim-accounts/VimAccountsModule.ts b/src/app/vim-accounts/VimAccountsModule.ts
new file mode 100644 (file)
index 0000000..3424bc4
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Vim Account module.
+ */
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { ReactiveFormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgSelectModule } from '@ng-select/ng-select';
+import { TranslateModule } from '@ngx-translate/core';
+import { DataService } from 'DataService';
+import { InfoVimComponent } from 'InfoVim';
+import { LoaderModule } from 'LoaderModule';
+import { NewVimaccountComponent } from 'NewVimaccount';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { PagePerRowModule } from 'PagePerRowModule';
+import { PageReloadModule } from 'PageReloadModule';
+import { VimAccountDetailsComponent } from 'VimAccountDetails';
+import { VimAccountsComponent } from 'VimAccountsComponent';
+
+/** To halndle project information */
+const projectInfo: {} = { title: '{project}', url: '/' };
+
+/** const values for dashboard Routes */
+const routes: Routes = [
+    {
+        path: '',
+        component: VimAccountsComponent,
+        children: [
+            {
+                path: 'details',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'VIMACCOUNTS', url: null }]
+                },
+                component: VimAccountDetailsComponent
+            },
+            {
+                path: 'info/:id',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'VIMACCOUNTS', url: '/vim/details' }, { title: '{id}', url: null }]
+                },
+                component: InfoVimComponent
+            },
+            {
+                path: 'new',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'VIMACCOUNTS', url: '/vim/details' }, { title: 'PAGE.VIMDETAILS.NEWVIM', url: null }]
+                },
+                component: NewVimaccountComponent
+            }
+        ]
+    }
+];
+
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+    imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, CommonModule,
+        HttpClientModule, NgSelectModule, Ng2SmartTableModule, TranslateModule, RouterModule.forChild(routes), NgbModule,
+        PagePerRowModule, LoaderModule, PageReloadModule],
+    declarations: [VimAccountsComponent, InfoVimComponent, VimAccountDetailsComponent, NewVimaccountComponent],
+    providers: [DataService],
+    entryComponents: [InfoVimComponent]
+})
+/** Exporting a class @exports VimAccountsModule */
+export class VimAccountsModule {
+    /** Variables declared to avoid state-less class */
+    private vimModule: string;
+}
diff --git a/src/app/vim-accounts/info-vim/InfoVimComponent.html b/src/app/vim-accounts/info-vim/InfoVimComponent.html
new file mode 100644 (file)
index 0000000..2eac832
--- /dev/null
@@ -0,0 +1,47 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+  <div class="d-flex align-items-center header-style">{{'PAGE.VIMDETAILS.VIMACCOUNTDETAILS' | translate}}</div>
+</div>
+<div class="context-style bg-white mt-2 vim-details">
+  <div class="row">
+    <div class="col-sm-6 text-dark mb-2 font-weight-bold" *ngFor="let details of vimDetails">
+      <label class="col-sm-5 col-form-label">{{ details.title | translate}}</label>
+      <span class="col-sm-5">{{details.value}}</span>
+    </div>
+  </div>
+</div>
+<div class="col-12">
+  <button type="button" class="btn btn-block border-0 bg-light text-dark" (click)="isCollapsed = !isCollapsed"
+    [attr.aria-expanded]="!isCollapsed">
+    {{'PAGE.VIMDETAILS.CONFIGPARAMETERS' | translate}}
+  </button>
+</div>
+<div id="demo" class="collapse context-style p-2" [ngbCollapse]="isCollapsed">
+  <div class="row">
+    <div class="col-sm-6 text-dark mb-2 font-weight-bold" *ngFor="let details of configParams">
+      <label class="col-sm-5 col-form-label">{{ details.title | translate}}:</label>
+      <span class="col-sm-5"> {{(details.value !== undefined)?details.value : '--'}} </span>
+    </div>
+  </div>
+</div>
+<div class="modal-footer list">
+  <button (click)="onVimAccountBack()"
+    class="btn btn-danger pull-right">{{'PAGE.VIMDETAILS.BACKTOVIMACCOUNTS' | translate}}</button>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/vim-accounts/info-vim/InfoVimComponent.scss b/src/app/vim-accounts/info-vim/InfoVimComponent.scss
new file mode 100644 (file)
index 0000000..8c2b739
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
diff --git a/src/app/vim-accounts/info-vim/InfoVimComponent.ts b/src/app/vim-accounts/info-vim/InfoVimComponent.ts
new file mode 100644 (file)
index 0000000..d40b696
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Info VIM Page
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { ERRORDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import * as HttpStatus from 'http-status-codes';
+import { RestService } from 'RestService';
+import { isNullOrUndefined } from 'util';
+import { CONFIG, VimAccountDetails, VIMData } from 'VimAccountModel';
+
+/**
+ * Creating component
+ * @Component InfoVimComponent.html as template url
+ */
+@Component({
+  selector: 'app-info-vim',
+  templateUrl: './InfoVimComponent.html',
+  styleUrls: ['./InfoVimComponent.scss']
+})
+/** Exporting a class @exports InfoVimComponent */
+export class InfoVimComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** vimAccountDetails to populate in InfoVIM Page @private */
+  public vimAccountDetails: VimAccountDetails;
+
+  /** Information Top Left @public */
+  public configParams: {}[] = [];
+
+  /** Showing more details of collapase */
+  public isCollapsed: boolean = true;
+
+  /** Contains vim details @public */
+  public vimDetails: {}[];
+
+  /** Check the Projects loading results @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** variables contains paramsID @private */
+  private paramsID: string;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Holds the instance of router class @private */
+  private router: Router;
+
+  /** dataService to pass the data from one component to another @private */
+  private dataService: DataService;
+
+  /** vimId to populate in InfoVIM Page @private */
+  private vimId: string;
+
+  /** Holds teh instance of AuthService class of type AuthService @private */
+  private activatedRoute: ActivatedRoute;
+
+  /** Utilizes modal service for any modal operations @private */
+  private modalService: NgbModal;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.dataService = this.injector.get(DataService);
+    this.activatedRoute = this.injector.get(ActivatedRoute);
+    this.modalService = this.injector.get(NgbModal);
+    this.router = this.injector.get(Router);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    // tslint:disable-next-line:no-backbone-get-set-outside-model
+    this.paramsID = this.activatedRoute.snapshot.paramMap.get('id');
+    this.dataService.currentMessage.subscribe((data: VIMData) => {
+      this.vimId = data.identifier;
+    });
+    this.generateData();
+  }
+
+  /** Routing to VIM Account Details Page @public */
+  public onVimAccountBack(): void {
+    this.router.navigate(['vim/details']).catch(() => {
+      // Error Cached
+    });
+  }
+
+  /** Generate Data function @public */
+  public generateData(): void {
+    this.isLoadingResults = true;
+    this.restService.getResource(environment.VIMACCOUNTS_URL + '/' + this.paramsID)
+      .subscribe((vimAccountsData: VimAccountDetails) => {
+        this.showDetails(vimAccountsData);
+        if (vimAccountsData.config !== undefined) {
+          if (vimAccountsData.vim_type === 'openstack') {
+            this.showOpenstackConfig(vimAccountsData.config);
+          } else if (vimAccountsData.vim_type === 'aws') {
+            this.awsConfig(vimAccountsData.config);
+          } else if (vimAccountsData.vim_type === 'openvim' || vimAccountsData.vim_type === 'opennebula') {
+            this.openVIMOpenNebulaConfig(vimAccountsData.config);
+          } else if (vimAccountsData.vim_type === 'vmware') {
+            this.vmwareConfig(vimAccountsData.config);
+          } else if (vimAccountsData.vim_type === 'azure') {
+            this.azureConfig(vimAccountsData.config);
+          }
+        }
+        this.isLoadingResults = false;
+      }, (error: ERRORDATA) => {
+        this.isLoadingResults = false;
+        if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
+          this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
+        } else {
+          this.restService.handleError(error, 'get');
+        }
+      });
+  }
+
+  /** show general vim detailed information @public */
+  public showDetails(vimAccountsData: VimAccountDetails): void {
+    this.vimDetails = [
+      {
+        title: 'PAGE.VIMDETAILS.NAME',
+        value: vimAccountsData.name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VIMUSERNAME',
+        value: vimAccountsData.vim_user
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VIMURL',
+        value: vimAccountsData.vim_url
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VIMTYPE',
+        value: vimAccountsData.vim_type
+      },
+      {
+        title: 'PAGE.VIMDETAILS.TENANTNAME',
+        value: vimAccountsData.vim_tenant_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.DESCRIPTION',
+        value: vimAccountsData.description
+      },
+      {
+        title: 'PAGE.VIMDETAILS.SCHEMATYPE',
+        value: vimAccountsData.schema_type
+      },
+      {
+        title: 'PAGE.VIMDETAILS.SCHEMAVERSION',
+        value: vimAccountsData.schema_version
+      }
+    ];
+  }
+
+  /** Openstack Config @public */
+  public showOpenstackConfig(config: CONFIG): void {
+    if (!isNullOrUndefined(config)) {
+      Object.keys(config).forEach((key: string) => {
+        if (Array.isArray(config[key])) {
+          config[key] = JSON.stringify(config[key]);
+        }
+      });
+    }
+    let location: string = config.location;
+    if (!isNullOrUndefined(location)) {
+      const locationArr: string[] = config.location.split(',');
+      if (Array.isArray(locationArr)) {
+        location = locationArr[0];
+      }
+    }
+
+    this.configParams = [
+      {
+        title: 'PAGE.VIMDETAILS.SDNCONTROLLER',
+        value: config.sdn_controller
+      },
+      {
+        title: 'PAGE.VIMDETAILS.SDNPORTMAPPING',
+        value: config.sdn_port_mapping
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VIMNETWORKNAME',
+        value: config.vim_network_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.SECURITYGROUPS',
+        value: config.security_groups
+      },
+      {
+        title: 'PAGE.VIMDETAILS.AVAILABILITYZONE',
+        value: config.availabilityZone
+      },
+      {
+        title: 'PAGE.VIMDETAILS.REGIONALNAME',
+        value: config.region_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.INSECURE',
+        value: config.insecure
+      },
+      {
+        title: 'PAGE.VIMDETAILS.USEEXISTINGFLAVOURS',
+        value: config.use_existing_flavors
+      },
+      {
+        title: 'PAGE.VIMDETAILS.USEINTERNALENDPOINT',
+        value: config.use_internal_endpoint
+      },
+      {
+        title: 'PAGE.VIMDETAILS.ADDITIONALCONFIG',
+        value: config.additional_conf
+      },
+      {
+        title: 'PAGE.VIMDETAILS.APIVERSION',
+        value: config.APIversion
+      },
+      {
+        title: 'PAGE.VIMDETAILS.PROJECTDOMAINID',
+        value: config.project_domain_id
+      },
+      {
+        title: 'PAGE.VIMDETAILS.PROJECTDOMAINNAME',
+        value: config.project_domain_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.USERDOMAINID',
+        value: config.user_domain_id
+      },
+      {
+        title: 'PAGE.VIMDETAILS.USERDOMAINUSER',
+        value: config.user_domain_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.KEYPAIR',
+        value: config.keypair
+      },
+      {
+        title: 'PAGE.VIMDETAILS.DATAPLANEPHYSICALNET',
+        value: config.dataplane_physical_net
+      },
+      {
+        title: 'PAGE.VIMDETAILS.USEFLOATINGIP',
+        value: config.use_floating_ip
+      },
+      {
+        title: 'PAGE.VIMDETAILS.MICROVERSION',
+        value: config.microversion
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VIMLOCATION',
+        value: location
+      }
+    ];
+  }
+
+  /** AWS Config @public */
+  public awsConfig(config: CONFIG): void {
+    this.configParams = [
+      {
+        title: 'PAGE.VIMDETAILS.SDNCONTROLLER',
+        value: config.sdn_controller
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VPCCIDRBLOCK',
+        value: config.vpc_cidr_block
+      },
+      {
+        title: 'PAGE.VIMDETAILS.SDNPORTMAPPING',
+        value: config.sdn_port_mapping
+      },
+      {
+        title: 'PAGE.VIMDETAILS.SECURITYGROUPS',
+        value: config.security_groups
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VIMNETWORKNAME',
+        value: config.vim_network_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.KEYPAIR',
+        value: config.keypair
+      },
+      {
+        title: 'PAGE.VIMDETAILS.REGIONALNAME',
+        value: config.region_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.FLAVORIINFO',
+        value: config.flavor_info
+      },
+      {
+        title: 'PAGE.VIMDETAILS.ADDITIONALCONFIG',
+        value: config.additional_conf
+      }
+    ];
+  }
+
+  /** Open vim and open nebula config @public */
+  public openVIMOpenNebulaConfig(config: CONFIG): void {
+    this.configParams = [
+      {
+        title: 'PAGE.VIMDETAILS.SDNCONTROLLER',
+        value: config.sdn_controller
+      },
+      {
+        title: 'PAGE.VIMDETAILS.SDNPORTMAPPING',
+        value: config.sdn_port_mapping
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VIMNETWORKNAME',
+        value: config.vim_network_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.ADDITIONALCONFIG',
+        value: config.additional_conf
+      }
+    ];
+  }
+
+  /** vmware config @public */
+  public vmwareConfig(config: CONFIG): void {
+    this.configParams = [
+      {
+        title: 'PAGE.VIMDETAILS.SDNCONTROLLER',
+        value: config.sdn_controller
+      },
+      {
+        title: 'PAGE.VIMDETAILS.ORGNAME',
+        value: config.orgname
+      },
+      {
+        title: 'PAGE.VIMDETAILS.SDNPORTMAPPING',
+        value: config.sdn_port_mapping
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VCENTERIP',
+        value: config.vcenter_ip
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VIMNETWORKNAME',
+        value: config.vim_network_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VCENTERPORT',
+        value: config.vcenter_port
+      },
+      {
+        title: 'PAGE.VIMDETAILS.ADMINUSERNAME',
+        value: config.admin_username
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VCENTERUSER',
+        value: config.vcenter_user
+      },
+      {
+        title: 'PAGE.VIMDETAILS.ADMINPASSWORD',
+        value: config.admin_password
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VCENTERPASSWORD',
+        value: config.vcenter_password
+      },
+      {
+        title: 'PAGE.VIMDETAILS.NSXMANAGER',
+        value: config.nsx_manager
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VROPSSITE',
+        value: config.vrops_site
+      },
+      {
+        title: 'PAGE.VIMDETAILS.NSXUSER',
+        value: config.nsx_user
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VROPSUSER',
+        value: config.vrops_user
+      },
+      {
+        title: 'PAGE.VIMDETAILS.NSXPASSWORD',
+        value: config.nsx_password
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VROPSPASSWORD',
+        value: config.vrops_password
+      },
+      {
+        title: 'PAGE.VIMDETAILS.ADDITIONALCONFIG',
+        value: config.additional_conf
+      }
+    ];
+  }
+
+  /** Azure Config @public */
+  public azureConfig(config: CONFIG): void {
+    this.configParams = [
+      {
+        title: 'PAGE.VIMDETAILS.SUBSCRIPTIONID',
+        value: config.subscription_id
+      },
+      {
+        title: 'PAGE.VIMDETAILS.REGIONALNAME',
+        value: config.region_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.RESOURCEGROUP',
+        value: config.resource_group
+      },
+      {
+        title: 'PAGE.VIMDETAILS.VNETNAME',
+        value: config.vnet_name
+      },
+      {
+        title: 'PAGE.VIMDETAILS.FLAVORSPATTERN',
+        value: config.flavors_pattern
+      }
+    ];
+  }
+}
diff --git a/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.html b/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.html
new file mode 100644 (file)
index 0000000..cc56017
--- /dev/null
@@ -0,0 +1,661 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="vimNewAccountForm" (ngSubmit)="newVimAccountSubmit()" autocomplete="off">
+    <div class="row d-flex flex-row justify-content-between">
+        <div class="d-flex align-items-center header-style">{{'PAGE.VIMDETAILS.NEWVIMACCOUNT' | translate}} </div>
+    </div>
+    <div class="context-style bg-white p-3">
+        <div class="row form-group content-style">
+            <label class="col-sm-12 col-form-label mandatory-label"
+                [ngClass]="{'text-danger': vimNewAccountForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+            <div class="col-sm-3">
+                <label for="name">{{'PAGE.VIMDETAILS.NAME' | translate}}*</label>
+            </div>
+            <div class="col-sm-3">
+                <input autocomplete="off" class="form-control" placeholder="{{'PAGE.VIMDETAILS.NAME' | translate}}"
+                    type="text" formControlName="name" id="name"
+                    [ngClass]="{ 'is-invalid': submitted && f.name.errors }">
+            </div>
+            <div class="col-sm-3">
+                <label for="vim_tenant_name">{{'PAGE.VIMDETAILS.TENANTNAME' | translate}}*</label>
+            </div>
+            <div class="col-sm-3">
+                <input autocomplete="off" class="form-control"
+                    placeholder="{{'PAGE.VIMDETAILS.TENANTNAME' | translate}}" type="text"
+                    formControlName="vim_tenant_name" id="vim_tenant_name"
+                    [ngClass]="{ 'is-invalid': submitted && f.vim_tenant_name.errors }">
+            </div>
+        </div>
+        <div class="row form-group content-style">
+            <div class="col-sm-3">
+                <label for="vim_type">{{'PAGE.VIMDETAILS.VIMTYPE' | translate}}*</label>
+            </div>
+            <div class="col-sm-3">
+                <ng-select bindLabel="title" bindValue="value" [items]="vimType" placeholder="{{'SELECT' | translate}}"
+                    formControlName="vim_type" id="vim_type" [(ngModel)]="selectedVimType"
+                    [ngClass]="{ 'is-invalid': submitted && f.vim_type.errors }">
+                </ng-select>
+            </div>
+            <div class="col-sm-3">
+                <label for="description">{{'PAGE.VIMDETAILS.DESCRIPTION' | translate}}</label>
+            </div>
+            <div class="col-sm-3">
+                <textarea class="form-control" placeholder="{{'PAGE.VIMDETAILS.DESCRIPTION' | translate}}" type="text"
+                    formControlName="description" id="description"></textarea>
+            </div>
+        </div>
+        <div class="row form-group content-style">
+            <div class="col-sm-3">
+                <label for="vim_url">{{'PAGE.VIMDETAILS.VIMURL' | translate}}*</label>
+            </div>
+            <div class="col-sm-3">
+                <input autocomplete="off" class="form-control" placeholder="{{'PAGE.VIMDETAILS.VIMURL' | translate}}"
+                    type="url" formControlName="vim_url" id="vim_url"
+                    [ngClass]="{ 'is-invalid': submitted && f.vim_url.errors }">
+                <div *ngIf="vimNewAccountForm.invalid" class="invalid-feedback">
+                    <div *ngIf="f.vim_url.errors && f.vim_url.value">{{'DOMVALIDATIONS.INVALIDURL' | translate}}</div>
+                </div>
+            </div>
+            <div class="col-sm-3">
+                <label for="schema_type">{{'PAGE.VIMDETAILS.SCHEMATYPE' | translate}}</label>
+            </div>
+            <div class="col-sm-3">
+                <input autocomplete="off" class="form-control"
+                    placeholder="{{'PAGE.VIMDETAILS.SCHEMATYPE' | translate}}" type="text" formControlName="schema_type"
+                    id="schema_type">
+            </div>
+        </div>
+        <div class="row form-group content-style">
+            <div class="col-sm-3">
+                <label for="vim_user">{{'PAGE.VIMDETAILS.VIMUSERNAME' | translate}}*</label>
+            </div>
+            <div class="col-sm-3">
+                <input autocomplete="off" class="form-control"
+                    placeholder="{{'PAGE.VIMDETAILS.VIMUSERNAME' | translate}}" type="text" formControlName="vim_user"
+                    id="vim_user" [ngClass]="{ 'is-invalid': submitted && f.vim_user.errors }">
+            </div>
+        </div>
+        <div class="row form-group content-style">
+            <div class="col-sm-3">
+                <label for="vim_password">{{'PAGE.VIMDETAILS.VIMPASSWORD' | translate}}*</label>
+            </div>
+            <div class="col-sm-3">
+                <input autocomplete="off" class="form-control" placeholder="VIM Password" type="password"
+                    formControlName="vim_password" id="vim_password"
+                    [ngClass]="{ 'is-invalid': submitted && f.vim_password.errors }">
+            </div>
+        </div>
+        <div class="row" [hidden]="!selectedVimType">
+            <div class="col-12">
+                <button type="button" class="btn btn-block border-0 bg-light text-dark"
+                    (click)="isCollapsed = !isCollapsed"
+                    [attr.aria-expanded]="!isCollapsed">{{'PAGE.VIMDETAILS.CONFIGPARAMETERS' | translate}}</button>
+            </div>
+        </div>
+        <div formGroupName="vimconfig" id="configurationparameters" class="collapse mt-3" [ngbCollapse]="isCollapsed">
+            <div class="row" [hidden]="!selectedVimType">
+                <div class="col-sm-3">
+                    <label>{{'UPLOADCONFIG' | translate}}</label>
+                </div>
+                <div class="col-sm-3 form-group">
+                    <div class="custom-file">
+                        <input type="file" #fileInput class="custom-file-input"
+                            (change)="filesDropped($event.target.files)" id="customFile">
+                        <label class="custom-file-label" #fileInputLabel
+                            for="customFile">{{'CHOOSEFILE' | translate}}</label>
+                    </div>
+                </div>
+            </div>
+            <div *ngIf="selectedVimType == 'openstack'">
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="sdn_controller">{{'PAGE.VIMDETAILS.SDNCONTROLLER' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SDNCONTROLLER' | translate}}" type="text"
+                            formControlName="sdn_controller" id="sdn_controller">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="APIversion">{{'PAGE.VIMDETAILS.APIVERSION' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.APIVERSION' | translate}}" type="text"
+                            formControlName="APIversion" id="APIversion">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="sdn_port_mapping">{{'PAGE.VIMDETAILS.SDNPORTMAPPING' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SDNPORTMAPPING' | translate}}" type="text"
+                            formControlName="sdn_port_mapping" id="sdn_port_mapping">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="project_domain_id">{{'PAGE.VIMDETAILS.PROJECTDOMAINID' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.PROJECTDOMAINID' | translate}}" type="text"
+                            formControlName="project_domain_id" id="project_domain_id">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="vim_network_name">{{'PAGE.VIMDETAILS.VIMNETWORKNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VIMNETWORKNAME' | translate}}" type="text"
+                            formControlName="vim_network_name" id="vim_network_name">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="project_domain_name">{{'PAGE.VIMDETAILS.PROJECTDOMAINNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.PROJECTDOMAINNAME' | translate}}" type="text"
+                            formControlName="project_domain_name" id="project_domain_name">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="config_vim_ype">{{'PAGE.VIMDETAILS.VIMTYPE' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VIM_TYPE' | translate}}" type="text"
+                            formControlName="config_vim_ype" id="config_vim_ype">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="user_domain_id">{{'PAGE.VIMDETAILS.USERDOMAINID' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.USERDOMAINID' | translate}}" type="text"
+                            formControlName="user_domain_id" id="user_domain_id">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="security_groups">{{'PAGE.VIMDETAILS.SECURITYGROUPS' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SECURITYGROUPS' | translate}}" type="text"
+                            formControlName="security_groups" id="security_groups">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="user_domain_name">{{'PAGE.VIMDETAILS.USERDOMAINUSER' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.USERDOMAINUSER' | translate}}" type="text"
+                            formControlName="user_domain_name" id="user_domain_name">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="availabilityZone">{{'PAGE.VIMDETAILS.AVAILABILITYZONE' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.AVAILABILITYZONE' | translate}}" type="text"
+                            formControlName="availabilityZone" id="availabilityZone">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="keypair">{{'PAGE.VIMDETAILS.KEYPAIR' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.KEYPAIR' | translate}}" type="text"
+                            formControlName="keypair" id="keypair">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="region_name">{{'PAGE.VIMDETAILS.REGIONALNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.REGIONALNAME' | translate}}" type="text"
+                            formControlName="region_name" id="region_name">
+                    </div>
+                    <div class="col-sm-3">
+                        <label
+                            for="dataplane_physical_net">{{'PAGE.VIMDETAILS.DATAPLANEPHYSICALNET' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.DATAPLANEPHYSICALNET' | translate}}" type="text"
+                            formControlName="dataplane_physical_net" id="dataplane_physical_net">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="insecure">{{'PAGE.VIMDETAILS.INSECURE' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <ng-select [items]="boolValue" bindLabel="name" bindValue="id"
+                            placeholder="{{'PAGE.VIMDETAILS.INSECURE' | translate}}" formControlName="insecure"
+                            id="insecure">
+                        </ng-select>
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="use_floating_ip">{{'PAGE.VIMDETAILS.USEFLOATINGIP' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <ng-select [items]="boolValue" bindLabel="name" bindValue="id" id="use_floating_ip"
+                            placeholder="{{'PAGE.VIMDETAILS.USEFLOATINGIP' | translate}}"
+                            formControlName="use_floating_ip">
+                        </ng-select>
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="use_internal_endpoint">{{'PAGE.VIMDETAILS.USEINTERNALENDPOINT' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <ng-select [items]="boolValue" bindLabel="name" bindValue="id"
+                            placeholder="{{'PAGE.VIMDETAILS.USEINTERNALENDPOINT' | translate}}"
+                            formControlName="use_internal_endpoint" id="use_internal_endpoint">
+                        </ng-select>
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="microversion">{{'PAGE.VIMDETAILS.MICROVERSION' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.MICROVERSION' | translate}}" type="text"
+                            formControlName="microversion" id="microversion">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="additional_conf">{{'PAGE.VIMDETAILS.ADDITIONALCONFIG' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.ADDITIONALCONFIGPLACEHOLDER' | translate}}" type="text"
+                            formControlName="additional_conf" id="additional_conf">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="use_existing_flavors">{{'PAGE.VIMDETAILS.USEEXISTINGFLAVOURS' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <ng-select [items]="boolValue" bindLabel="name" bindValue="id"
+                            placeholder="{{'PAGE.VIMDETAILS.USEEXISTINGFLAVOURS' | translate}}"
+                            formControlName="use_existing_flavors" id="use_existing_flavors">
+                        </ng-select>
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="location">{{'PAGE.VIMDETAILS.VIMLOCATION' | translate}}</label>
+                    </div>
+                    <div class="col-sm-9">
+                        <ng-select [items]="getVIMLocation" bindLabel="label" bindValue="value"
+                            placeholder="{{'PAGE.VIMDETAILS.VIMLOCATION' | translate}}" formControlName="location"
+                            id="location" (keydown.enter)="fetchLocationLatLong($event.target.value)">
+                        </ng-select>
+                        <small>{{'PAGE.VIM.LOACTIONINFO' | translate}}</small>
+                    </div>
+                </div>
+            </div>
+            <div *ngIf="selectedVimType == 'openvim' || selectedVimType == 'opennebula'">
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="sdn_controller">{{'PAGE.VIMDETAILS.SDNCONTROLLER' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SDNCONTROLLER' | translate}}" type="text"
+                            formControlName="sdn_controller" id="sdn_controller">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="sdn_port_mapping">{{'PAGE.VIMDETAILS.SDNPORTMAPPING' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SDNPORTMAPPING' | translate}}" type="text"
+                            formControlName="sdn_port_mapping" id="sdn_port_mapping">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="vim_network_name">{{'PAGE.VIMDETAILS.VIMNETWORKNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VIMNETWORKNAME' | translate}}" type="text"
+                            formControlName="vim_network_name" id="vim_network_name">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="additional_conf">{{'PAGE.VIMDETAILS.ADDITIONALCONFIG' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.ADDITIONALCONFIGPLACEHOLDER' | translate}}" type="text"
+                            formControlName="additional_conf" id="additional_conf">
+                    </div>
+                </div>
+            </div>
+            <div *ngIf="selectedVimType == 'vmware'">
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="sdn_controller">{{'PAGE.VIMDETAILS.SDNCONTROLLER' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SDNCONTROLLER' | translate}}" type="text"
+                            formControlName="sdn_controller" id="sdn_controller">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="orgname">{{'PAGE.VIMDETAILS.ORGNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.ORGNAME' | translate}}" type="text"
+                            formControlName="orgname" id="orgname">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="sdn_port_mapping">{{'PAGE.VIMDETAILS.SDNPORTMAPPING' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SDNPORTMAPPING' | translate}}" type="text"
+                            formControlName="sdn_port_mapping" id="sdn_port_mapping">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="vcenter_ip">{{'PAGE.VIMDETAILS.VCENTERIP' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VCENTERIP' | translate}}" type="text"
+                            formControlName="vcenter_ip" id="vcenter_ip">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="vim_network_name">{{'PAGE.VIMDETAILS.VIMNETWORKNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VIMNETWORKNAME' | translate}}" type="text"
+                            formControlName="vim_network_name" id="vim_network_name">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="vcenter_port">{{'PAGE.VIMDETAILS.VCENTERPORT' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VCENTERPORT' | translate}}" type="text"
+                            formControlName="vcenter_port" id="vcenter_port">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="admin_username">{{'PAGE.VIMDETAILS.ADMINUSERNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.ADMINUSERNAME' | translate}}" type="text"
+                            formControlName="admin_username" id="admin_username">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="vcenter_user">{{'PAGE.VIMDETAILS.VCENTERUSER' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VCENTERUSER' | translate}}" type="text"
+                            formControlName="vcenter_user" id="vcenter_user">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="admin_password">{{'PAGE.VIMDETAILS.ADMINPASSWORD' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.ADMINPASSWORD' | translate}}" type="text"
+                            formControlName="admin_password" id="admin_password">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="vcenter_password">{{'PAGE.VIMDETAILS.VCENTERPASSWORD' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VCENTERPASSWORD' | translate}}" type="text"
+                            formControlName="vcenter_password" id="vcenter_password">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="nsx_manager">{{'PAGE.VIMDETAILS.NSXMANAGER' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.NSXMANAGER' | translate}}" type="text"
+                            formControlName="nsx_manager" id="nsx_manager">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="vrops_site">{{'PAGE.VIMDETAILS.VROPSSITE' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VROPSSITE' | translate}}" type="text"
+                            formControlName="vrops_site" id="vrops_site">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="nsx_user">{{'PAGE.VIMDETAILS.NSXUSER' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.NSXUSER' | translate}}" type="text"
+                            formControlName="nsx_user" id="nsx_user">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="vrops_user">{{'PAGE.VIMDETAILS.VROPSUSER' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VROPSUSER' | translate}}" type="text"
+                            formControlName="vrops_user" id="vrops_user">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="nsx_password">{{'PAGE.VIMDETAILS.NSXPASSWORD' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.NSXPASSWORD' | translate}}" type="text"
+                            formControlName="nsx_password" id="nsx_password">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="vrops_password">{{'PAGE.VIMDETAILS.VROPSPASSWORD' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VROPSPASSWORD' | translate}}" type="text"
+                            formControlName="vrops_password" id="vrops_password">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="additional_conf">{{'PAGE.VIMDETAILS.ADDITIONALCONFIG' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.ADDITIONALCONFIGPLACEHOLDER' | translate}}" type="text"
+                            formControlName="additional_conf" id="additional_conf">
+                    </div>
+                </div>
+            </div>
+            <div *ngIf="selectedVimType == 'aws'">
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="sdn_controller">{{'PAGE.VIMDETAILS.SDNCONTROLLER' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SDNCONTROLLER' | translate}}" type="text"
+                            formControlName="sdn_controller" id="sdn_controller">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="vpc_cidr_block">{{'PAGE.VIMDETAILS.VPCCIDRBLOCK' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VPCCIDRBLOCK' | translate}}" type="text"
+                            formControlName="vpc_cidr_block" id="vpc_cidr_block">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="sdn_port_mapping">{{'PAGE.VIMDETAILS.SDNPORTMAPPING' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SDNPORTMAPPING' | translate}}" type="text"
+                            formControlName="sdn_port_mapping" id="sdn_port_mapping">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="security_groups">{{'PAGE.VIMDETAILS.SECURITYGROUPS' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SECURITYGROUPS' | translate}}" type="text"
+                            formControlName="security_groups" id="security_groups">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="vim_network_name">{{'PAGE.VIMDETAILS.VIMNETWORKNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VIMNETWORKNAME' | translate}}" type="text"
+                            formControlName="vim_network_name" id="vim_network_name">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="keypair">{{'PAGE.VIMDETAILS.KEYPAIR' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.KEYPAIR' | translate}}" type="text"
+                            formControlName="keypair" id="keypair">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="region_name">{{'PAGE.VIMDETAILS.REGIONALNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.REGIONALNAME' | translate}}" type="text"
+                            formControlName="region_name" id="region_name">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="flavor_info">{{'PAGE.VIMDETAILS.FLAVORIINFO' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.FLAVORIINFO' | translate}}" type="text"
+                            formControlName="flavor_info" id="flavor_info">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="additional_conf">{{'PAGE.VIMDETAILS.ADDITIONALCONFIG' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.ADDITIONALCONFIGPLACEHOLDER' | translate}}" type="text"
+                            formControlName="additional_conf" id="additional_conf">
+                    </div>
+                </div>
+            </div>
+            <div *ngIf="selectedVimType == 'azure'">
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="subscription_id">{{'PAGE.VIMDETAILS.SUBSCRIPTIONID' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.SUBSCRIPTIONID' | translate}}" type="text"
+                            formControlName="subscription_id" id="subscription_id">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="region_name">{{'PAGE.VIMDETAILS.REGIONALNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.REGIONALNAME' | translate}}" type="text"
+                            formControlName="region_name" id="region_name">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="resource_group">{{'PAGE.VIMDETAILS.RESOURCEGROUP' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.RESOURCEGROUP' | translate}}" type="text"
+                            formControlName="resource_group" id="resource_group">
+                    </div>
+                    <div class="col-sm-3">
+                        <label for="vnet_name">{{'PAGE.VIMDETAILS.VNETNAME' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.VNETNAME' | translate}}" type="text"
+                            formControlName="vnet_name" id="vnet_name">
+                    </div>
+                </div>
+                <div class="row form-group content-style">
+                    <div class="col-sm-3">
+                        <label for="flavors_pattern">{{'PAGE.VIMDETAILS.FLAVORSPATTERN' | translate}}</label>
+                    </div>
+                    <div class="col-sm-3">
+                        <input autocomplete="off" class="form-control"
+                            placeholder="{{'PAGE.VIMDETAILS.FLAVORSPATTERN' | translate}}" type="text"
+                            formControlName="flavors_pattern" id="flavors_pattern">
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button type="button" (click)="onVimAccountBack()"
+            class="btn btn-danger">{{'PAGE.VIMDETAILS.BACKTOVIMACCOUNTS' | translate}}</button>
+        <button type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+    </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLocationLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.scss b/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.scss
new file mode 100644 (file)
index 0000000..d750ccc
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.ts b/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.ts
new file mode 100644 (file)
index 0000000..bc6fd1e
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Vim Account Component.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { Router } from '@angular/router';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, TYPESECTION, VIM_TYPES } from 'CommonModel';
+import { environment } from 'environment';
+import * as jsyaml from 'js-yaml';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+import { FEATURES, VIMLOCATION, VIMLOCATIONDATA } from 'VimAccountModel';
+
+/**
+ * Creating component
+ * @Component takes NewVimaccountComponent.html as template url
+ */
+@Component({
+  selector: 'app-new-vimaccount',
+  templateUrl: './NewVimaccountComponent.html',
+  styleUrls: ['./NewVimaccountComponent.scss']
+})
+/** Exporting a class @exports NewVimaccountComponent */
+export class NewVimaccountComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** FormGroup vim New Account added to the form @ html @public */
+  public vimNewAccountForm: FormGroup;
+
+  /** Supported Vim type for the dropdown */
+  public vimType: TYPESECTION[];
+
+  /** Supported Vim type for the dropdown */
+  public selectedVimType: string;
+
+  /** Supported true and false value for the dropdown */
+  public boolValue: {}[];
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Showing more details of collapase */
+  public isCollapsed: boolean = false;
+
+  /** Vim location values @public */
+  public getVIMLocation: VIMLOCATIONDATA[] = [];
+
+  /** Check the Projects loading results @public */
+  public isLocationLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** set the longitude value of the selected place @public */
+  public setLong: number;
+
+  /** set the latitude value of the selected place @public */
+  public setLat: number;
+
+  /** Element ref for fileInput @public */
+  @ViewChild('fileInput', { static: true }) public fileInput: ElementRef;
+
+  /** Element ref for fileInput @public */
+  @ViewChild('fileInputLabel', { static: true }) public fileInputLabel: ElementRef;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Holds the instance of router class @private */
+  private router: Router;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  /** Contains configuration key variables @private */
+  private configKeys: string[] = [];
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.router = this.injector.get(Router);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.sharedService = this.injector.get(SharedService);
+
+    /** Initializing Form Action */
+    this.vimNewAccountForm = this.formBuilder.group({
+      name: [null, Validators.required],
+      vim_type: [null, Validators.required],
+      vim_tenant_name: [null, Validators.required],
+      description: [null],
+      vim_url: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]],
+      schema_type: [''],
+      vim_user: [null, Validators.required],
+      vim_password: [null, Validators.required],
+      vimconfig: this.paramsBuilder()
+    });
+  }
+
+  /** Generate params for config @public */
+  public paramsBuilder(): FormGroup {
+    return this.formBuilder.group({
+      use_existing_flavors: [null],
+      location: [null],
+      sdn_controller: [null],
+      APIversion: [null],
+      sdn_port_mapping: [null],
+      project_domain_id: [null],
+      vim_network_name: [null],
+      project_domain_name: [null],
+      config_vim_ype: [null],
+      user_domain_id: [null],
+      security_groups: [null],
+      user_domain_name: [null],
+      availabilityZone: [null],
+      keypair: [null],
+      region_name: [null],
+      dataplane_physical_net: [null],
+      insecure: [null],
+      use_floating_ip: [null],
+      microversion: [null],
+      use_internal_endpoint: [null],
+      additional_conf: [null],
+      orgname: [null],
+      vcenter_ip: [null],
+      vcenter_port: [null],
+      admin_username: [null],
+      vcenter_user: [null],
+      admin_password: [null],
+      vcenter_password: [null],
+      nsx_manager: [null],
+      vrops_site: [null],
+      nsx_user: [null],
+      vrops_user: [null],
+      nsx_password: [null],
+      vrops_password: [null],
+      vpc_cidr_block: [null],
+      flavor_info: [null],
+      subscription_id: [null],
+      resource_group: [null],
+      vnet_name: [null],
+      flavors_pattern: [null]
+    });
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.vimNewAccountForm.controls; }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.vimType = VIM_TYPES;
+    this.boolValue = [
+      { id: '', name: 'None' },
+      { id: true, name: 'True' },
+      { id: false, name: 'False' }
+    ];
+    this.headers = new HttpHeaders({
+      Accept: 'application/json',
+      'Content-Type': 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+  }
+
+  /** On modal submit newVimAccountSubmit will called @public */
+  public newVimAccountSubmit(): void {
+    this.submitted = true;
+    if (!this.vimNewAccountForm.invalid) {
+      this.isLocationLoadingResults = true;
+      this.configKeys.forEach((key: string) => {
+        this.vimNewAccountForm.controls.vimconfig.get(key).setValue(JSON.parse(this.vimNewAccountForm.controls.vimconfig.get(key).value));
+      });
+      this.sharedService.cleanForm(this.vimNewAccountForm);
+      Object.keys(this.vimNewAccountForm.value.vimconfig).forEach((key: string) => {
+        if (this.vimNewAccountForm.value.vimconfig[key] === undefined || this.vimNewAccountForm.value.vimconfig[key] === null ||
+          this.vimNewAccountForm.value.vimconfig[key] === '') {
+          delete this.vimNewAccountForm.value.vimconfig[key];
+        }
+      });
+      this.vimNewAccountForm.value.config = this.vimNewAccountForm.value.vimconfig;
+      delete this.vimNewAccountForm.value.vimconfig;
+      const apiURLHeader: APIURLHEADER = {
+        url: environment.VIMACCOUNTS_URL,
+        httpOptions: { headers: this.headers }
+      };
+      this.restService.postResource(apiURLHeader, this.vimNewAccountForm.value)
+        .subscribe((result: {}) => {
+          this.notifierService.notify('success', this.translateService.instant('PAGE.VIM.CREATEDSUCCESSFULLY'));
+          this.isLocationLoadingResults = false;
+          this.router.navigate(['vim/details']).catch(() => {
+            // Error Cached;
+          });
+          // Post the New Vim data and reflect in the VIM Details Page.
+        }, (error: ERRORDATA) => {
+          this.configKeys.forEach((key: string) => {
+            this.vimNewAccountForm.controls.vimconfig.get(key)
+              .setValue(JSON.stringify(this.vimNewAccountForm.controls.vimconfig.get(key).value));
+          });
+          this.restService.handleError(error, 'post');
+          this.isLocationLoadingResults = false;
+        });
+    }
+  }
+
+  /** Routing to VIM Account Details Page @public */
+  public onVimAccountBack(): void {
+    this.router.navigate(['vim/details']).catch(() => {
+      // Error Cached
+    });
+  }
+
+  /** Fetching the location with name,latitude,longitude @public */
+  public fetchLocationLatLong(value: string): void {
+    this.isLocationLoadingResults = true;
+    const newVIMLocation: VIMLOCATIONDATA[] = [];
+    const locationTrack: string = environment.MAPLATLONGAPI_URL;
+    const locationAPIURL: string = locationTrack.replace('{value}', value);
+    this.restService.getResource(locationAPIURL).subscribe((result: VIMLOCATION) => {
+      result.features.forEach((getFeturesResult: FEATURES) => {
+        if ('extent' in getFeturesResult.properties) {
+          getFeturesResult.properties.extent.forEach((extentResult: number, index: number) => {
+            if (index === 0) {
+              this.setLong = extentResult;
+            }
+            if (index === 1) {
+              this.setLat = extentResult;
+            }
+          });
+        } else {
+          getFeturesResult.geometry.coordinates.forEach((coordinateResult: number, index: number) => {
+            if (index === 0) {
+              this.setLong = coordinateResult;
+            }
+            if (index === 1) {
+              this.setLat = coordinateResult;
+            }
+          });
+        }
+        newVIMLocation.push({
+          label: getFeturesResult.properties.name + ',' + getFeturesResult.properties.state + ', ' + getFeturesResult.properties.country,
+          value: getFeturesResult.properties.name + ',' + this.setLong + ',' + this.setLat
+        });
+      });
+      this.getVIMLocation = newVIMLocation;
+      this.isLocationLoadingResults = false;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLocationLoadingResults = false;
+    });
+  }
+
+  /** Drag and drop feature and fetchind the details of files  @private */
+  public filesDropped(files: FileList): void {
+    this.configKeys = [];
+    if (files && files.length === 1) {
+      this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
+        const getJson: string = jsyaml.load(fileContent, { json: true });
+        Object.keys(getJson).forEach((item: string) => {
+          if (!isNullOrUndefined(this.vimNewAccountForm.controls.vimconfig.get(item))) {
+            if (typeof getJson[item] === 'object') {
+              // tslint:disable-next-line: no-backbone-get-set-outside-model
+              this.vimNewAccountForm.controls.vimconfig.get(item).setValue(JSON.stringify(getJson[item]));
+              this.configKeys.push(item);
+            } else {
+              // tslint:disable-next-line: no-backbone-get-set-outside-model
+              this.vimNewAccountForm.controls.vimconfig.get(item).setValue(getJson[item]);
+            }
+          }
+        });
+      }).catch((err: string): void => {
+        if (err === 'typeError') {
+          this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
+        } else {
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        }
+        this.fileInputLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+        this.fileInput.nativeElement.value = null;
+      });
+    } else if (files && files.length > 1) {
+      this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+    }
+    this.fileInputLabel.nativeElement.innerText = files[0].name;
+    this.fileInput.nativeElement.value = null;
+  }
+}
diff --git a/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.html b/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.html
new file mode 100644 (file)
index 0000000..7feabe2
--- /dev/null
@@ -0,0 +1,67 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex align-items-center justify-content-between">
+    <div class="col-sm-4">
+        <div class="d-flex align-items-center header-style">{{'VIMACCOUNTS' | translate}}</div>
+    </div>
+    <div class="col-sm-8 text-right">
+        <div class="btn-group list mr-2" role="group">
+            <button class="btn btn-primary" type="button" (click)="mapView()" placement="top" container="body"
+                ngbTooltip="{{'MAPVIEW' | translate}}" [hidden]="showList" [disabled]="vimData.length == 0">
+                <i class="fas fa-map-marker-alt"></i>&nbsp;
+                {{'MAPVIEW' | translate}}
+            </button>
+            <button class="btn btn-primary" type="button" (click)="listView()" placement="top" container="body"
+                ngbTooltip="{{'LISTVIEW' | translate}}" [hidden]="showMap">
+                <i class="fas fa-list"></i>&nbsp;
+                {{'LISTVIEW' | translate}}
+            </button>
+        </div>
+        <span class="button">
+            <button class="btn btn-primary" type="button" placement="top" container="body"
+                ngbTooltip="{{'PAGE.VIMDETAILS.NEWVIM' | translate}}" (click)="composeVIM()">
+                <i class="fas fa-plus-circle" aria-hidden="true"></i>&nbsp;
+                {{'PAGE.VIMDETAILS.NEWVIM' | translate}}
+            </button>
+        </span>
+    </div>
+</div>
+<div class="row mt-2 mb-0 list-utilites-actions" [hidden]="showList">
+    <div class="col-auto mr-auto">
+        <nav class="custom-items-config">
+            <span><i class="fas fa-clock text-warning"></i>{{operationalStateFirstStep}}</span>
+            <span><i class="fas fa-check-circle text-success"></i>{{operationalStateSecondStep}}</span>
+            <span><i class="fas fa-times-circle text-danger"></i>{{operationalStateThirdStep}}</span>
+        </nav>
+    </div>
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1" [hidden]="showList">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<br>
+<div id="map" class="row map" [hidden]="showMap"></div>
+<div id="popup" class="ol-popup" [hidden]="!popupShow">
+    <button id="popup-closer" class="button-xs close m-1" type="button" aria-label="Close">
+        <i class="fas fa-times-circle text-danger"></i>
+    </button>
+    <div id="popup-content" [innerHTML]="popupData"></div>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.scss b/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.scss
new file mode 100644 (file)
index 0000000..aeb086e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+@import '../../../assets/scss/mixins/mixin';
+@import '../../../assets/scss/variable';
+.map {
+    height: 60vh;
+    width: 100%;
+    .ol-popup {
+        @include background(null, $white, null, null, null);
+        -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
+        filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
+        @include border(all, 1, solid, $gray-80);
+        @include position_value(absolute, $top: null, $right: null, $bottom: 12px, $left: -50px);
+        @include wh-value(280px, null);
+        @include font-style(normal);
+        @include font(null, .765625rem, 400);
+        @include line-height(1.5);
+        text-align: start;
+        text-decoration: none;
+        letter-spacing: normal;
+        word-break: normal;
+        word-spacing: normal;
+        white-space: normal;
+        line-break: auto;
+        word-wrap: break-word;
+        @include roundedCorners(2px);
+        &:after, &:before{
+            top: 100%;
+            @include border(all, 1, solid, transparent);
+            content: " ";
+            height: 0;
+            width: 0;
+            position: absolute;
+            pointer-events: none;
+        }
+        &:after {
+            border-top-color: $white;
+            border-width: 10px;
+            left: 48px;
+            margin-left: -10px;
+        }
+        &:before {
+            border-top-color: $gray-80;
+            border-width: 11px;
+            left: 48px;
+            margin-left: -11px;
+        }
+    }
+    .ol-popup-closer {
+        text-decoration: none;
+        position: absolute;
+        top: 2px;
+        right: 8px;
+        &:after {
+            content: "✖";
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.ts b/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.ts
new file mode 100644 (file)
index 0000000..71455f5
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Vim Account Component.
+ */
+import { Component, Injector, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { TranslateService } from '@ngx-translate/core';
+import { CONFIGCONSTANT, CONSTANTNUMBER, ERRORDATA, VIM_TYPES } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { LocalDataSource } from 'ng2-smart-table';
+import { NSInstanceDetails } from 'NSInstanceModel';
+import Feature from 'ol/Feature';
+import Point from 'ol/geom/Point';
+import { defaults as defaultInteractions } from 'ol/interaction';
+import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
+import Map from 'ol/Map';
+import Overlay from 'ol/Overlay';
+import { fromLonLat } from 'ol/proj.js';
+import OSM from 'ol/source/OSM';
+import VectorSource from 'ol/source/Vector';
+import { Icon, Style } from 'ol/style';
+import View from 'ol/View';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+import { VimAccountDetails, VIMData } from 'VimAccountModel';
+import { VimAccountsActionComponent } from 'VimAccountsAction';
+/**
+ * Creating component
+ * @Component takes VimAccountDetailsComponent.html as template url
+ */
+@Component({
+    selector: 'app-vim-account-details',
+    templateUrl: './VimAccountDetailsComponent.html',
+    styleUrls: ['./VimAccountDetailsComponent.scss']
+})
+/** Exporting a class @exports VimAccountDetailsComponent */
+export class VimAccountDetailsComponent implements OnInit {
+    /** To inject services @public */
+    public injector: Injector;
+    /** handle translate @public */
+    public translateService: TranslateService;
+    /** initially show the map container@public */
+    public showMap: boolean;
+    /**  hide and show popup @public */
+    public popupShow: boolean = false;
+    /** Data of smarttable populate through LocalDataSource @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+    /** Columns list of the smart table @public */
+    public columnLists: object = {};
+    /** Settings for smarttable to populate the table with columns @public */
+    public settings: object = {};
+    /** initially hide the list@private */
+    public showList: boolean;
+    /** to store locations name @public */
+    public getLocation: GetLocation[];
+    /** Contains content for map popup @public */
+    public popupData: string;
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+    /** Formation of appropriate Data for LocalDatasource @public */
+    public vimData: VIMData[];
+    /** operational State init data @public */
+    public operationalStateFirstStep: string = CONFIGCONSTANT.vimOperationalStateFirstStep;
+    /** operational State running data @public */
+    public operationalStateSecondStep: string = CONFIGCONSTANT.vimOperationalStateStateSecondStep;
+    /** operational State failed data @public */
+    public operationalStateThirdStep: string = CONFIGCONSTANT.vimOperationalStateThirdStep;
+    /** NS Instances operational State failed data @public */
+    public nsinstancesoperationalStateRunning: string = CONFIGCONSTANT.operationalStateSecondStep;
+    /** Instance of the rest service @private */
+    private restService: RestService;
+    /** dataService to pass the data from one component to another @private */
+    private dataService: DataService;
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+    /** Holds the instance of router class @private */
+    private router: Router;
+    /** ns INstance Data @private */
+    private nsData: NSInstanceDetails[];
+    /** map object @private */
+    private map: Map;
+    /**  used to bind marker @private */
+    private vectorSource: VectorSource;
+    /** used to bind vectorSource @private */
+    private vectorLayer: VectorLayer;
+    /** marker @private */
+    private marker: Feature;
+    /** latitude @private */
+    private lat: number;
+    /** longitude @private */
+    private lng: number;
+    /**  each vector layer of marker is pushed to layers array @private */
+    private layers: VectorLayer[] = [];
+    /** locationData @private */
+    private locationData: VimAccountDetails[];
+    /** popup array @private */
+    private overLay: Overlay[] = [];
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.sharedService = this.injector.get(SharedService);
+        this.router = this.injector.get(Router);
+        this.translateService = this.injector.get(TranslateService);
+    }
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.osmMapView();
+        this.listView();
+        this.generateColumns();
+        this.generateSettings();
+        this.generateData();
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** smart table Header Colums @public */
+    public generateColumns(): void {
+        this.columnLists = {
+            name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' },
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '25%' },
+            type: {
+                title: this.translateService.instant('TYPE'), width: '15%',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: VIM_TYPES
+                    }
+                }
+            },
+            operationalState: {
+                title: this.translateService.instant('OPERATIONALSTATUS'), width: '15%', type: 'html',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: [
+                            { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep },
+                            { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep },
+                            { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep }
+                        ]
+                    }
+                },
+                valuePrepareFunction: (cell: VIMData, row: VIMData): string => {
+                    if (row.operationalState === this.operationalStateFirstStep) {
+                        return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-clock text-warning"></i>
+                        </span>`;
+                    } else if (row.operationalState === this.operationalStateSecondStep) {
+                        return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-check-circle text-success"></i>
+                        </span>`;
+                    } else if (row.operationalState === this.operationalStateThirdStep) {
+                        return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-times-circle text-danger"></i>
+                        </span>`;
+                    } else {
+                        return `<span>${row.operationalState}</span>`;
+                    }
+                }
+            },
+            description: { title: this.translateService.instant('DESCRIPTION'), width: '25%' },
+            Actions: {
+                name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom',
+                valuePrepareFunction: (cell: VIMData, row: VIMData): VIMData => row,
+                renderComponent: VimAccountsActionComponent
+            }
+        };
+    }
+
+    /** smart table Data Settings @public */
+    public generateSettings(): void {
+        this.settings = {
+            edit: {
+                editButtonContent: '<i class="fa fa-edit" title="Edit"></i>',
+                confirmSave: true
+            },
+            delete: {
+                deleteButtonContent: '<i class="far fa-trash-alt" title="delete"></i>',
+                confirmDelete: true
+            },
+            columns: this.columnLists,
+            actions: {
+                add: false,
+                edit: false,
+                delete: false,
+                position: 'right'
+            },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** smart table listing manipulation @public */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** smart table listing manipulation @public */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'vim-account' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** on Navigate to Composer Page @public */
+    public composeVIM(): void {
+        this.router.navigate(['vim/new']).catch(() => {
+            //empty block
+        });
+    }
+
+    /** To show map conatainer @public */
+    public mapView(): void {
+        this.showList = true;
+        this.showMap = false;
+    }
+    /** To show listview @public */
+    public listView(): void {
+        this.showMap = true;
+        this.showList = false;
+    }
+    /** Load the datasource appropriatetype @public */
+    public loadDatasource(getdata: VIMData[]): void {
+        if (getdata.length > 0) {
+            this.checkDataClass = 'dataTables_present';
+        } else {
+            this.checkDataClass = 'dataTables_empty';
+        }
+        this.dataSource.load(getdata).then((data: boolean) => {
+            //empty block
+        }).catch(() => {
+            //empty block
+        });
+    }
+
+    /** Generate generateVIMData object from loop and return for the datasource @public */
+    public generateVIMData(vimAccountData: VimAccountDetails): VIMData {
+        return {
+            name: vimAccountData.name,
+            identifier: vimAccountData._id,
+            type: vimAccountData.vim_type,
+            operationalState: vimAccountData._admin.operationalState,
+            description: vimAccountData.description,
+            instancesData: this.nsData
+        };
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+
+    /** Fetching the data from server to Load in the smarttable @protected */
+    private generateData(): void {
+        this.isLoadingResults = true;
+        this.vimData = [];
+        this.getNSData().then((): void => {
+            this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimAccountsData: VimAccountDetails[]) => {
+                this.locationData = vimAccountsData;
+                vimAccountsData.forEach((vimAccountData: VimAccountDetails) => {
+                    const vimDataObj: VIMData = this.generateVIMData(vimAccountData);
+                    this.vimData.push(vimDataObj);
+                });
+                this.loadDatasource(this.vimData);
+                this.removeLayersOverLay();
+                this.arrayOfLocation();
+                this.isLoadingResults = false;
+            }, (error: ERRORDATA) => {
+                this.restService.handleError(error, 'get');
+                this.isLoadingResults = false;
+            });
+        }).catch((error: ERRORDATA): void => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+
+    /** fetching the nsdata @private */
+    private async getNSData(): Promise<Boolean> {
+        return new Promise<Boolean>((resolve: Function, reject: Function): void => {
+            this.nsData = [];
+            this.restService.getResource(environment.NSDINSTANCES_URL).subscribe((nsdInstancesData: NSInstanceDetails[]) => {
+                const nsRunningInstancesData: NSInstanceDetails[] = nsdInstancesData.filter((instancesData: NSInstanceDetails) =>
+                instancesData['operational-status'] === this.nsinstancesoperationalStateRunning);
+                this.nsData = nsRunningInstancesData;
+                resolve(true);
+            }, (error: ERRORDATA) => {
+                this.restService.handleError(error, 'get');
+                resolve(true);
+            });
+        });
+    }
+
+    /** create map view @private */
+    private osmMapView(): void {
+        this.map = new Map({
+            target: 'map',
+            layers: [new TileLayer({
+                source: new OSM()
+            })],
+            interactions: defaultInteractions({
+                mouseWheelZoom: true
+            }),
+            view: new View({
+                center: fromLonLat([CONSTANTNUMBER.osmapviewlong, CONSTANTNUMBER.osmapviewlat]),
+                zoom: 3
+            })
+        });
+    }
+
+    /** remove the layers and overlay @private */
+    private removeLayersOverLay(): void {
+        this.layers.forEach((layer: VectorLayer) => {
+            this.map.removeLayer(layer);
+        });
+        this.overLay.forEach((lay: Overlay) => {
+            this.map.removeOverlay(lay);
+        });
+    }
+
+    /** filter locations from vimaccounts @private */
+    private arrayOfLocation(): void {
+        this.getLocation = [];
+        this.locationData.filter((item: VimAccountDetails) => {
+            if (item.hasOwnProperty('config')) {
+                if (item.config.hasOwnProperty('location')) {
+                    this.getLocation.push({ name: item.name, location: item.config.location, id: item._id });
+                }
+            }
+        });
+        if (this.getLocation !== []) {
+            this.getLocation.filter((loc: GetLocation) => {
+                if (loc.location !== '') {
+                    const getLatLong: string[] = loc.location.split(',');
+                    this.lng = +getLatLong[CONSTANTNUMBER.splitLongitude];
+                    this.lat = +getLatLong[CONSTANTNUMBER.splitLatitude];
+                    this.addMarker(getLatLong[0], loc.id, loc.name);
+                }
+            });
+        }
+    }
+    /** add markers on map @private */
+    private addMarker(loc: string, id: string, name: string): void {
+        const container: HTMLElement = document.getElementById('popup');
+        const closer: HTMLElement = document.getElementById('popup-closer');
+        this.popupShow = true;
+        const overlay: Overlay = this.addOverlay(container);
+        this.marker = this.addFeature(loc, id, name);
+        this.setStyleMarker();
+        this.setVectorSource();
+        this.setVectorLayer();
+        this.map.addLayer(this.vectorLayer);
+        this.layers.push(this.vectorLayer);
+        if (this.layers.length === 1) {
+            this.markerClickEvent(closer, overlay);
+        }
+    }
+    /** Create an overlay to anchor the popup to the map @private */
+    private addOverlay(container: HTMLElement): Overlay {
+        return new Overlay({
+            element: container,
+            autoPan: true,
+            autoPanAnimation: {
+                duration: 250
+            }
+        });
+    }
+    /** Return the Feature of creating a marker in the map @private */
+    private addFeature(loc: string, id: string, name: string): Feature {
+        return new Feature({
+            geometry: new Point(fromLonLat([this.lng, this.lat])),
+            location: loc,
+            Id: id,
+            vimName: name
+        });
+    }
+    /** Set the style of the marker @private */
+    private setStyleMarker(): void {
+        this.marker.setStyle(new Style({
+            image: new Icon(({
+                crossOrigin: 'anonymous',
+                src: 'assets/images/map-icon.png'
+            }))
+        }));
+    }
+    /** Set the map vector source @private */
+    private setVectorSource(): void {
+        this.vectorSource = new VectorSource({
+            features: [this.marker]
+        });
+    }
+    /** Set the map vector layer @private */
+    private setVectorLayer(): void {
+        this.vectorLayer = new VectorLayer({
+            source: this.vectorSource
+        });
+    }
+    /** Add a click handler to the map to render the popup. @private */
+    private markerClickEvent(closer: HTMLElement, overlay: Overlay): void {
+        // tslint:disable-next-line: no-any
+        this.map.on('singleclick', (evt: any) => {
+            const feature: Feature = this.map.forEachFeatureAtPixel(evt.pixel,
+                (f: Feature) => {
+                    return f;
+                });
+            if (feature) {
+                this.setCoordinates(feature, overlay);
+            } else {
+                this.map.removeOverlay(overlay);
+            }
+        });
+        /** Handle close event for overlay */
+        closer.onclick = (): boolean => {
+            overlay.setPosition(undefined);
+            closer.blur();
+            return false;
+        };
+    }
+    /** Set the coordinates point if the feature is available @private */
+    // tslint:disable-next-line: no-any
+    private setCoordinates(feature: any, overlay: Overlay): void {
+        this.popupData = '';
+        this.popupData += '<h3 class="popover-header">' + feature.values_.vimName + '</h3>';
+        this.popupData += '<ul class="list-unstyled m-2">';
+        const instnaceData: NSInstanceDetails[] = this.nsData.filter((item: NSInstanceDetails) => {
+            if (item.datacenter === feature.values_.Id) {
+                this.popupData += '<li class="m-2"><a class="d-block text-truncate" target="_parent" href="instances/ns/' + item._id + '">'
+                    + item.name + '</a></li>';
+                return item;
+            }
+        });
+        if (instnaceData.length === 0) {
+            this.popupData += '<li class="m-2">' + this.translateService.instant('PAGE.DASHBOARD.NOINSTANCES') + '</li>';
+        }
+        this.popupData += '</ul>';
+        const coordinates: number[] = feature.getGeometry().getCoordinates();
+        overlay.setPosition(coordinates);
+        this.overLay.push(overlay);
+        this.map.addOverlay(overlay);
+    }
+}
+
+/** interface for get location */
+interface GetLocation {
+    location: string;
+    id: string;
+    name?: string;
+}
diff --git a/src/app/wim-accounts/WIMAccountsComponent.html b/src/app/wim-accounts/WIMAccountsComponent.html
new file mode 100644 (file)
index 0000000..3f96ff8
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<router-outlet></router-outlet>
\ No newline at end of file
diff --git a/src/app/wim-accounts/WIMAccountsComponent.scss b/src/app/wim-accounts/WIMAccountsComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/wim-accounts/WIMAccountsComponent.ts b/src/app/wim-accounts/WIMAccountsComponent.ts
new file mode 100644 (file)
index 0000000..5914f30
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file WIM Account Component.
+ */
+import { Component, Injector } from '@angular/core';
+import { Router, RouterEvent } from '@angular/router';
+
+/**
+ * Creating component
+ * @Component takes WIMAccountsComponent.html as template url
+ */
+@Component({
+    templateUrl: './WIMAccountsComponent.html',
+    styleUrls: ['./WIMAccountsComponent.scss']
+})
+/** Exporting a class @exports WIMAccountsComponent */
+export class WIMAccountsComponent {
+    /** Invoke service injectors @public */
+    public injector: Injector;
+
+    /** Holds teh instance of AuthService class of type AuthService @private */
+    private router: Router;
+
+    // creates packages component
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.router = this.injector.get(Router);
+        this.router.events.subscribe((event: RouterEvent) => {
+            this.redirectToList(event.url);
+        });
+    }
+
+    /** Return to list NS Package List */
+    public redirectToList(getURL: string): void {
+        if (getURL === '/wim') {
+            this.router.navigate(['/wim/details']).catch();
+        }
+    }
+}
diff --git a/src/app/wim-accounts/WIMAccountsModule.ts b/src/app/wim-accounts/WIMAccountsModule.ts
new file mode 100644 (file)
index 0000000..088502f
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file WIM Account module.
+ */
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { ReactiveFormsModule } from '@angular/forms';
+import { RouterModule, Routes } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgSelectModule } from '@ng-select/ng-select';
+import { TranslateModule } from '@ngx-translate/core';
+import { DataService } from 'DataService';
+import { LoaderModule } from 'LoaderModule';
+import { NewWIMAccountComponent } from 'NewWIMAccount';
+import { Ng2SmartTableModule } from 'ng2-smart-table';
+import { PagePerRowModule } from 'PagePerRowModule';
+import { PageReloadModule } from 'PageReloadModule';
+import { WIMAccountDetailsComponent } from 'WIMAccountDetails';
+import { WIMAccountInfoComponent } from 'WIMAccountInfo';
+import { WIMAccountsComponent } from 'WIMAccountsComponent';
+
+/** To halndle project information */
+const projectInfo: {} = { title: '{project}', url: '/' };
+
+/** const values for dashboard Routes */
+const routes: Routes = [
+    {
+        path: '',
+        component: WIMAccountsComponent,
+        children: [
+            {
+                path: 'details',
+                data: {
+                    breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' },
+                        projectInfo, { title: 'WIMACCOUNTS', url: null }]
+                },
+                component: WIMAccountDetailsComponent
+            }
+        ]
+    }
+];
+
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+    imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, CommonModule,
+        HttpClientModule, NgSelectModule, Ng2SmartTableModule, TranslateModule, RouterModule.forChild(routes), NgbModule,
+        PagePerRowModule, LoaderModule, PageReloadModule],
+    declarations: [WIMAccountsComponent, WIMAccountInfoComponent, WIMAccountDetailsComponent, NewWIMAccountComponent],
+    providers: [DataService],
+    schemas: [CUSTOM_ELEMENTS_SCHEMA],
+    entryComponents: [WIMAccountInfoComponent, NewWIMAccountComponent]
+})
+/** Exporting a class @exports WIMAccountsModule */
+export class WIMAccountsModule {
+    /** Variables declared to avoid state-less class */
+    private wimModule: string;
+}
diff --git a/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.html b/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.html
new file mode 100644 (file)
index 0000000..a97107f
--- /dev/null
@@ -0,0 +1,97 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<form [formGroup]="wimNewAccountForm" (ngSubmit)="newWimAccountSubmit()" autocomplete="off">
+    <div class="modal-header">
+        <h4 class="modal-title" id="modal-basic-title">{{'PAGE.WIMACCOUNTS.NEWWIM' | translate}}</h4>
+        <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+            <i class="fas fa-times-circle text-danger"></i>
+        </button>
+    </div>
+    <div class="modal-body modal-body-custom-height">
+        <div class="form-group row">
+            <label class="col-sm-12 col-form-label mandatory-label"
+                [ngClass]="{'text-danger': wimNewAccountForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
+            <label class="col-sm-4 col-form-label" for="name">{{'NAME' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'NAME' | translate}}" type="text"
+                    formControlName="name" id="name" [ngClass]="{ 'is-invalid': submitted && f.name.errors }" required>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="wim_type">{{'TYPE' | translate}}*</label>
+            <div class="col-sm-8">
+                <ng-select bindLabel="title" bindValue="value" [items]="wimType" placeholder="{{'SELECT' | translate}}"
+                    formControlName="wim_type" id="wim_type" [(ngModel)]="wimTypeMod"
+                    [ngClass]="{ 'is-invalid': submitted && f.wim_type.errors }" required>
+                </ng-select>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="wim_url">{{'URL' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'URL' | translate}}" type="url"
+                    formControlName="wim_url" id="wim_url" [ngClass]="{ 'is-invalid': submitted && f.wim_url.errors }"
+                    required>
+                <div *ngIf="wimNewAccountForm.invalid" class="invalid-feedback">
+                    <div *ngIf="f.wim_url.errors && f.wim_url.value">{{'DOMVALIDATIONS.INVALIDURL' | translate}}</div>
+                </div>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="user">{{'PAGE.WIMACCOUNTS.USERNAME' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'PAGE.WIMACCOUNTS.USERNAME' | translate}}"
+                    type="text" formControlName="user" id="user"
+                    [ngClass]="{ 'is-invalid': submitted && f.user.errors }" required>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="password">{{'PAGE.WIMACCOUNTS.PASSWORD' | translate}}*</label>
+            <div class="col-sm-8">
+                <input autocomplete="off" class="form-control" placeholder="{{'PAGE.WIMACCOUNTS.PASSWORD' | translate}}"
+                    type="password" formControlName="password" id="password"
+                    [ngClass]="{ 'is-invalid': submitted && f.password.errors }" required>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="description">{{'DESCRIPTION' | translate}}</label>
+            <div class="col-sm-8">
+                <textarea class="form-control" placeholder="{{'DESCRIPTION' | translate}}" type="text"
+                    formControlName="description" id="description"></textarea>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label class="col-sm-4 col-form-label" for="config">{{'CONFIG' | translate}}</label>
+            <div class="col-sm-8">
+                <textarea class="form-control" placeholder="{{'YAMLCONFIG' | translate}}" formControlName="config"
+                    id="config"></textarea>
+                <div class="fileupload-text mt-1 mb-1">{{'FILEUPLOADLABEL' | translate}}</div>
+                <div class="custom-file">
+                    <input type="file" #fileInputConfig class="custom-file-input"
+                        (change)="configFile($event.target.files)" id="customFile">
+                    <label class="custom-file-label" #fileInputConfigLabel for="customFile">{{'CHOOSEFILE' | translate}}</label>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+        <button type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+    </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.scss b/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.ts b/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.ts
new file mode 100644 (file)
index 0000000..7587b58
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file WIM Account Component.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
+import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA, TYPESECTION, WIM_TYPES } from 'CommonModel';
+import { environment } from 'environment';
+import * as jsyaml from 'js-yaml';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { isNullOrUndefined } from 'util';
+
+/**
+ * Creating component
+ * @Component takes NewWIMAccountComponent.html as template url
+ */
+@Component({
+  templateUrl: './NewWIMAccountComponent.html',
+  styleUrls: ['./NewWIMAccountComponent.scss']
+})
+/** Exporting a class @exports NewWIMAccountComponent */
+export class NewWIMAccountComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Setting wim types in array @public */
+  public wimType: TYPESECTION[];
+
+  /** Set WIM Type select to empty @public */
+  public wimTypeMod: string = null;
+
+  /** New WIM account form controls using formgroup @public */
+  public wimNewAccountForm: FormGroup;
+
+  /** Form submission Add */
+  public submitted: boolean = false;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingResults: boolean = false;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Element ref for fileInputConfig @public */
+  @ViewChild('fileInputConfig', { static: true }) public fileInputConfig: ElementRef;
+
+  /** Element ref for fileInputConfig @public */
+  @ViewChild('fileInputConfigLabel', { static: true }) public fileInputConfigLabel: ElementRef;
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Controls the header form @private */
+  private headers: HttpHeaders;
+
+  /** FormBuilder instance added to the formBuilder @private */
+  private formBuilder: FormBuilder;
+
+  /** Notifier service to popup notification @private */
+  private notifierService: NotifierService;
+
+  /** Contains tranlsate instance @private */
+  private translateService: TranslateService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.formBuilder = this.injector.get(FormBuilder);
+    this.notifierService = this.injector.get(NotifierService);
+    this.translateService = this.injector.get(TranslateService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.sharedService = this.injector.get(SharedService);
+
+    /** Initializing Form Action */
+    this.wimNewAccountForm = this.formBuilder.group({
+      name: ['', Validators.required],
+      wim_type: ['', Validators.required],
+      wim_url: ['', [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]],
+      user: ['', Validators.required],
+      password: ['', Validators.required],
+      description: [null],
+      config: [null]
+    });
+  }
+
+  /** convenience getter for easy access to form fields */
+  get f(): FormGroup['controls'] { return this.wimNewAccountForm.controls; }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.wimType = WIM_TYPES;
+    this.headers = new HttpHeaders({
+      Accept: 'application/json',
+      'Content-Type': 'application/json',
+      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+    });
+  }
+
+  /** On modal submit newWimAccountSubmit will called @public */
+  public newWimAccountSubmit(): void {
+    this.submitted = true;
+    const modalData: MODALCLOSERESPONSEDATA = {
+      message: 'Done'
+    };
+    this.sharedService.cleanForm(this.wimNewAccountForm);
+    if (this.wimNewAccountForm.value.description === '') {
+      this.wimNewAccountForm.value.description = null;
+    }
+    if (isNullOrUndefined(this.wimNewAccountForm.value.config) || this.wimNewAccountForm.value.config === '') {
+      delete this.wimNewAccountForm.value.config;
+    } else {
+      const validJSON: boolean = this.sharedService.checkJson(this.wimNewAccountForm.value.config);
+      if (validJSON) {
+        this.wimNewAccountForm.value.config = JSON.parse(this.wimNewAccountForm.value.config);
+      } else {
+        this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG'));
+        return;
+      }
+    }
+    if (!this.wimNewAccountForm.invalid) {
+      this.isLoadingResults = true;
+      const apiURLHeader: APIURLHEADER = {
+        url: environment.WIMACCOUNTS_URL,
+        httpOptions: { headers: this.headers }
+      };
+      this.restService.postResource(apiURLHeader, this.wimNewAccountForm.value)
+        .subscribe((result: {}) => {
+          this.activeModal.close(modalData);
+          this.isLoadingResults = false;
+          this.notifierService.notify('success', this.translateService.instant('PAGE.WIMACCOUNTS.CREATEDSUCCESSFULLY'));
+        }, (error: ERRORDATA) => {
+          this.restService.handleError(error, 'post');
+          this.isLoadingResults = false;
+        });
+    }
+  }
+
+  /** Config file process @private */
+  public configFile(files: FileList): void {
+    if (files && files.length === 1) {
+      this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
+        const getConfigJson: string = jsyaml.load(fileContent, { json: true });
+        // tslint:disable-next-line: no-backbone-get-set-outside-model
+        this.wimNewAccountForm.get('config').setValue(JSON.stringify(getConfigJson));
+      }).catch((err: string): void => {
+        if (err === 'typeError') {
+          this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
+        } else {
+          this.notifierService.notify('error', this.translateService.instant('ERROR'));
+        }
+        this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+        this.fileInputConfig.nativeElement.value = null;
+      });
+    } else if (files && files.length > 1) {
+      this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+    }
+    this.fileInputConfigLabel.nativeElement.innerText = files[0].name;
+    this.fileInputConfig.nativeElement.value = null;
+  }
+}
diff --git a/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.html b/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.html
new file mode 100644 (file)
index 0000000..2c2d839
--- /dev/null
@@ -0,0 +1,42 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="row d-flex flex-row justify-content-between">
+    <div class="d-flex align-items-center header-style">{{'WIMACCOUNTS' | translate}}</div>
+    <span class="button">
+        <button class="btn btn-primary" type="button" placement="top" container="body" ngbTooltip="{{'PAGE.WIMACCOUNTS.NEWWIM' | translate}}"
+            (click)="composeWIM()">
+            <i class="fas fa-plus-circle" aria-hidden="true"></i>&nbsp; {{'PAGE.WIMACCOUNTS.NEWWIM' | translate}}
+        </button>
+    </span>
+</div>
+<div class="row mt-2 mb-0 list-utilites-actions">
+    <div class="col-auto mr-auto">
+        <nav class="custom-items-config">
+            <span><i class="fas fa-clock text-warning"></i>{{operationalStateFirstStep}}</span>
+            <span><i class="fas fa-check-circle text-success"></i>{{operationalStateSecondStep}}</span>
+            <span><i class="fas fa-times-circle text-danger"></i>{{operationalStateThirdStep}}</span>
+        </nav>
+    </div>
+    <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
+    <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+    <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource" (userRowSelect)="onUserRowSelect($event)">
+    </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.scss b/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.ts b/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.ts
new file mode 100644 (file)
index 0000000..b1d16f7
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file WIM Account Component.
+ */
+import { Component, Injector, OnDestroy, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA, WIM_TYPES } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { NewWIMAccountComponent } from 'NewWIMAccount';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+import { WIMAccountData, WIMAccountModel } from 'WIMAccountModel';
+import { WIMAccountsActionComponent } from 'WIMAccountsAction';
+/**
+ * Creating component
+ * @Component takes WIMAccountDetailsComponent.html as template url
+ */
+@Component({
+    templateUrl: './WIMAccountDetailsComponent.html',
+    styleUrls: ['./WIMAccountDetailsComponent.scss']
+})
+/** Exporting a class @exports WIMAccountDetailsComponent */
+export class WIMAccountDetailsComponent implements OnInit, OnDestroy {
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** handle translate @public */
+    public translateService: TranslateService;
+
+    /** Data of smarttable populate through LocalDataSource @public */
+    public dataSource: LocalDataSource = new LocalDataSource();
+
+    /** Columns list of the smart table @public */
+    public columnLists: object = {};
+
+    /** Settings for smarttable to populate the table with columns @public */
+    public settings: object = {};
+
+    /** Check the loading results @public */
+    public isLoadingResults: boolean = true;
+
+    /** Give the message for the loading @public */
+    public message: string = 'PLEASEWAIT';
+
+    /** Class for empty and present data @public */
+    public checkDataClass: string;
+
+    /** operational State init data @public */
+    public operationalStateFirstStep: string = CONFIGCONSTANT.wimOperationalStateFirstStep;
+
+    /** operational State running data @public */
+    public operationalStateSecondStep: string = CONFIGCONSTANT.wimOperationalStateStateSecondStep;
+
+    /** operational State failed data @public */
+    public operationalStateThirdStep: string = CONFIGCONSTANT.wimOperationalStateThirdStep;
+
+    /** Instance of the rest service @private */
+    private restService: RestService;
+
+    /** dataService to pass the data from one component to another @private */
+    private dataService: DataService;
+
+    /** Formation of appropriate Data for LocalDatasource @private */
+    private wimData: {}[] = [];
+
+    /** Contains all methods related to shared @private */
+    private sharedService: SharedService;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Instance of subscriptions @private */
+    private generateDataSub: Subscription;
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.dataService = this.injector.get(DataService);
+        this.sharedService = this.injector.get(SharedService);
+        this.translateService = this.injector.get(TranslateService);
+        this.modalService = this.injector.get(NgbModal);
+    }
+    /** Lifecyle Hooks the trigger before component is instantiate @public */
+    public ngOnInit(): void {
+        this.generateColumns();
+        this.generateSettings();
+        this.generateData();
+        this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+    }
+
+    /** smart table Header Colums @public */
+    public generateColumns(): void {
+        this.columnLists = {
+            name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' },
+            identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' },
+            type: {
+                title: this.translateService.instant('TYPE'), width: '15%',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: WIM_TYPES
+                    }
+                }
+            },
+            operationalState: {
+                title: this.translateService.instant('OPERATIONALSTATUS'), width: '15%', type: 'html',
+                filter: {
+                    type: 'list',
+                    config: {
+                        selectText: 'Select',
+                        list: [
+                            { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep },
+                            { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep },
+                            { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep }
+                        ]
+                    }
+                },
+                valuePrepareFunction: (cell: WIMAccountData, row: WIMAccountData): string => {
+                    if (row.operationalState === this.operationalStateFirstStep) {
+                        return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-clock text-warning"></i>
+                        </span>`;
+                    } else if (row.operationalState === this.operationalStateSecondStep) {
+                        return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-check-circle text-success"></i>
+                        </span>`;
+                    } else if (row.operationalState === this.operationalStateThirdStep) {
+                        return `<span class="icon-label" title="${row.operationalState}">
+                        <i class="fas fa-times-circle text-danger"></i>
+                        </span>`;
+                    } else {
+                        return `<span>${row.operationalState}</span>`;
+                    }
+                }
+            },
+            description: { title: this.translateService.instant('DESCRIPTION'), width: '25%' },
+            Actions: {
+                name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom',
+                valuePrepareFunction: (cell: WIMAccountData, row: WIMAccountData): WIMAccountData => row,
+                renderComponent: WIMAccountsActionComponent
+            }
+        };
+    }
+
+    /** smart table Data Settings @public */
+    public generateSettings(): void {
+        this.settings = {
+            edit: {
+                editButtonContent: '<i class="fa fa-edit" title="Edit"></i>', confirmSave: true
+            },
+            delete: {
+                deleteButtonContent: '<i class="far fa-trash-alt" title="delete"></i>', confirmDelete: true
+            },
+            columns: this.columnLists,
+            actions: {
+                add: false, edit: false, delete: false, position: 'right'
+            },
+            attr: this.sharedService.tableClassConfig(),
+            pager: this.sharedService.paginationPagerConfig(),
+            noDataMessage: this.translateService.instant('NODATAMSG')
+        };
+    }
+
+    /** smart table listing manipulation @public */
+    public onChange(perPageValue: number): void {
+        this.dataSource.setPaging(1, perPageValue, true);
+    }
+
+    /** smart table listing manipulation @public */
+    public onUserRowSelect(event: MessageEvent): void {
+        Object.assign(event.data, { page: 'wim-account' });
+        this.dataService.changeMessage(event.data);
+    }
+
+    /** Compose new WIM Accounts @public */
+    public composeWIM(): void {
+        const modalRef: NgbModalRef = this.modalService.open(NewWIMAccountComponent, { backdrop: 'static' });
+        modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+            if (result) {
+                this.sharedService.callData();
+            }
+        }).catch();
+    }
+
+    /** Generate generateWIMData object from loop and return for the datasource @public */
+    public generateWIMData(wimAccountData: WIMAccountModel): WIMAccountData {
+        return {
+            name: wimAccountData.name,
+            identifier: wimAccountData._id,
+            type: wimAccountData.wim_type,
+            operationalState: wimAccountData._admin.operationalState,
+            description: wimAccountData.description
+        };
+    }
+
+    /**
+     * Lifecyle hook which get trigger on component destruction
+     */
+    public ngOnDestroy(): void {
+        this.generateDataSub.unsubscribe();
+    }
+
+    /** Fetching the data from server to Load in the smarttable @protected */
+    protected generateData(): void {
+        this.isLoadingResults = true;
+        this.wimData = [];
+        this.restService.getResource(environment.WIMACCOUNTS_URL).subscribe((wimAccountsDetails: {}[]) => {
+            wimAccountsDetails.forEach((wimAccountsData: WIMAccountModel) => {
+                const wimDataObj: WIMAccountData = this.generateWIMData(wimAccountsData);
+                this.wimData.push(wimDataObj);
+            });
+            if (this.wimData.length > 0) {
+                this.checkDataClass = 'dataTables_present';
+            } else {
+                this.checkDataClass = 'dataTables_empty';
+            }
+            this.dataSource.load(this.wimData).then((data: {}) => {
+                this.isLoadingResults = false;
+            }).catch();
+        }, (error: ERRORDATA) => {
+            this.restService.handleError(error, 'get');
+            this.isLoadingResults = false;
+        });
+    }
+}
diff --git a/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.html b/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.html
new file mode 100644 (file)
index 0000000..25126b8
--- /dev/null
@@ -0,0 +1,84 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<div class="modal-header">
+  <h4 class="modal-title" id="modal-basic-title">{{'PAGE.WIMACCOUNTS.WIMDETAILS' | translate}}</h4>
+  <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+    <i class="fas fa-times-circle text-danger"></i>
+  </button>
+</div>
+<div class="modal-body modal-body-custom-height p-0">
+  <table class="table table-striped table-layout-fixed mb-0" *ngIf="wimDetails">
+    <tr>
+      <td colspan="2">
+        <b>{{'ID' | translate}}:</b> {{(wimDetails._id)?wimDetails._id:''}}
+      </td>
+    </tr>
+    <tr>
+      <td colspan="2">
+        <b>{{'DETAILEDSTATUS' | translate}}:</b> {{(wimDetails._admin['detailed-status'])?wimDetails._admin['detailed-status']:''}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <b>{{'OPERATIONALSTATE' | translate}}:</b><span class="ml-1 badge" [ngClass]="{'badge-info':wimDetails._admin.operationalState === operationalStateFirstStep,
+        'badge-success':wimDetails._admin.operationalState === operationalStateSecondStep,
+        'badge-danger':wimDetails._admin.operationalState === operationalStateThirdStep}">
+          {{(wimDetails._admin.operationalState)?wimDetails._admin.operationalState:''}}
+        </span>
+      </td>
+      <td>
+        <b>{{'PAGE.WIMACCOUNTS.SCHEMAVERSION' | translate}}:</b> {{(wimDetails.schema_version)?wimDetails.schema_version:''}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <b>{{'NAME' | translate}}:</b> {{(wimDetails.name)?wimDetails.name:''}}
+      </td>
+      <td>
+        <b>{{'TYPE' | translate}}:</b> {{(wimDetails.wim_type)?wimDetails.wim_type:''}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <b>{{'URL' | translate}}:</b> {{(wimDetails.wim_url)?wimDetails.wim_url:''}}
+      </td>
+      <td>
+        <b>{{'DESCRIPTION' | translate}}:</b> {{(wimDetails.description)?wimDetails.description:''}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <b>{{'CREATED' | translate}}:</b> {{(wimDetails._admin.created)?this.sharedService.convertEpochTime(wimDetails._admin.created):''}}
+      </td>
+      <td>
+        <b>{{'MODIFIED' | translate}}:</b> {{(wimDetails._admin.modified)?this.sharedService.convertEpochTime(wimDetails._admin.modified):''}}
+      </td>
+    </tr>
+    <tr>
+      <td colspan="2">
+        <b>{{'DEPLOYED' | translate}}</b> <br>
+        <b>{{'PAGE.WIMACCOUNTS.RO' | translate}}:</b> {{(wimDetails._admin.deployed.RO)?wimDetails._admin.deployed.RO:''}} <br>
+        <b>{{'PAGE.WIMACCOUNTS.ROACCOUNT' | translate}}:</b> {{(wimDetails._admin.deployed['RO-account'])?wimDetails._admin.deployed['RO-account']:''}}
+      </td>
+    </tr>
+  </table>
+</div>
+<div class="modal-footer">
+  <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
diff --git a/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.scss b/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.scss
new file mode 100644 (file)
index 0000000..021d205
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.ts b/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.ts
new file mode 100644 (file)
index 0000000..1e7be9f
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+*/
+/**
+ * @file Info WIM Page
+ */
+import { Component, Injector, Input, OnInit } from '@angular/core';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { CONFIGCONSTANT, ERRORDATA, URLPARAMS } from 'CommonModel';
+import { environment } from 'environment';
+import { RestService } from 'RestService';
+import { SharedService } from 'SharedService';
+import { WIMAccountModel } from 'WIMAccountModel';
+
+/**
+ * Creating component
+ * @Component takes WIMAccountInfoComponent.html as template url
+ */
+@Component({
+  templateUrl: './WIMAccountInfoComponent.html',
+  styleUrls: ['./WIMAccountInfoComponent.scss']
+})
+/** Exporting a class @exports WIMAccountInfoComponent */
+export class WIMAccountInfoComponent implements OnInit {
+  /** To inject services @public */
+  public injector: Injector;
+
+  /** Input contains component objects @public */
+  @Input() public params: URLPARAMS;
+
+  /** Contains WIM details @public */
+  public wimDetails: WIMAccountModel;
+
+  /** Instance for active modal service @public */
+  public activeModal: NgbActiveModal;
+
+  /** Check the loading results for loader status @public */
+  public isLoadingResults: boolean = true;
+
+  /** operational State init data @public */
+  public operationalStateFirstStep: string = CONFIGCONSTANT.wimOperationalStateFirstStep;
+
+  /** operational State running data @public */
+  public operationalStateSecondStep: string = CONFIGCONSTANT.wimOperationalStateStateSecondStep;
+
+  /** operational State failed data @public */
+  public operationalStateThirdStep: string = CONFIGCONSTANT.wimOperationalStateThirdStep;
+
+  /** Give the message for the loading @public */
+  public message: string = 'PLEASEWAIT';
+
+  /** Instance of the rest service @private */
+  private restService: RestService;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  constructor(injector: Injector) {
+    this.injector = injector;
+    this.restService = this.injector.get(RestService);
+    this.activeModal = this.injector.get(NgbActiveModal);
+    this.sharedService = this.injector.get(SharedService);
+  }
+
+  /**
+   * Lifecyle Hooks the trigger before component is instantiate
+   */
+  public ngOnInit(): void {
+    this.generateData();
+  }
+
+  /** Generate Data function @public */
+  public generateData(): void {
+    this.restService.getResource(environment.WIMACCOUNTS_URL + '/' + this.params.id).subscribe((wimDetails: WIMAccountModel) => {
+      this.wimDetails = wimDetails;
+      this.isLoadingResults = false;
+    }, (error: ERRORDATA) => {
+      this.restService.handleError(error, 'get');
+      this.isLoadingResults = false;
+    });
+  }
+}
diff --git a/src/assets/config/rolePermissions.json b/src/assets/config/rolePermissions.json
new file mode 100644 (file)
index 0000000..7111144
--- /dev/null
@@ -0,0 +1,692 @@
+{
+    "rolePermissions": [
+        {
+            "title": "Default",
+            "permissions": [
+                {
+                    "operation": "default",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "Admin",
+            "permissions": [
+                {
+                    "operation": "admin",
+                    "value": "NA"
+                },
+                {
+                    "operation": "admin:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "admin:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "admin:patch",
+                    "value": "NA"
+                },
+                {
+                    "operation": "admin:put",
+                    "value": "NA"
+                },
+                {
+                    "operation": "admin:delete",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "NS Descriptors",
+            "permissions": [
+                {
+                    "operation": "nsds",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:id:put",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:id:patch",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:content:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:id:content:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:id:content:put",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:id:nsd:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "nsds:id:nsd_artifact:get",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "VNF Descriptors",
+            "permissions": [
+                {
+                    "operation": "vnfds",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:content:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:id:put",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:id:patch",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:id:content:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:id:content:put",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:id:vnfd:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:id:vnfd_artifact:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:id:action:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:vnfpkgops:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnfds:vnfpkgops:id:get",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "NS Instances",
+            "permissions": [
+                {
+                    "operation": "ns_instances",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:content:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:id:instantiate:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:id:terminate:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:id:action:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:id:scale:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:opps:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "ns_instances:opps:id:get",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "VNF Instances",
+            "permissions": [
+                {
+                    "operation": "vnf_instances",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnf_instances:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vnf_instances:id:get",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "VIMs",
+            "permissions": [
+                {
+                    "operation": "vims",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vims:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vims:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vims:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vims:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vims:id:patch",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "VIMs Accounts",
+            "permissions": [
+                {
+                    "operation": "vim_accounts",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vim_accounts:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vim_accounts:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vim_accounts:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vim_accounts:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "vim_accounts:id:patch",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "SDN Controllers",
+            "permissions": [
+                {
+                    "operation": "sdn_controllers",
+                    "value": "NA"
+                },
+                {
+                    "operation": "sdn_controllers:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "sdn_controllers:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "sdn_controllers:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "sdn_controllers:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "sdn_controllers:id:patch",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "WIMs",
+            "permissions": [
+                {
+                    "operation": "wims",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wims:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wims:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wims:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wims:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wims:id:patch",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "WIMs Accounts",
+            "permissions": [
+                {
+                    "operation": "wim_accounts",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wim_accounts:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wim_accounts:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wim_accounts:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wim_accounts:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "wim_accounts:id:patch",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "PDUDs",
+            "permissions": [
+                {
+                    "operation": "pduds",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:put",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:patch",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:id:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:id:put",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "pduds:id:patch",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "Network Slice Templates",
+            "permissions": [
+                {
+                    "operation": "slice_templates",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:content:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:id:put",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:id:patch",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:content:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:content:put",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:id:nst:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_templates:id:nst_artifact:get",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "Network Slice Instances",
+            "permissions": [
+                {
+                    "operation": "slice_instances",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:content:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:id:instantiate:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:id:terminate:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:id:action:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:opps:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "slice_instances:opps:id:get",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "K8 Clusters",
+            "permissions": [
+                {
+                    "operation": "k8sclusters",
+                    "value": "NA"
+                },
+                {
+                    "operation": "k8sclusters:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "k8sclusters:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "k8sclusters:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "k8sclusters:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "k8sclusters:id:patch",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "K8 Repos",
+            "permissions": [
+                {
+                    "operation": "k8srepos",
+                    "value": "NA"
+                },
+                {
+                    "operation": "k8srepos:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "k8srepos:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "k8srepos:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "k8srepos:id:delete",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "Users",
+            "permissions": [
+                {
+                    "operation": "users",
+                    "value": "NA"
+                },
+                {
+                    "operation": "users:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "users:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "users:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "users:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "users:id:patch",
+                    "value": "NA"
+                },
+                {
+                    "operation": "domains:get",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "Projects",
+            "permissions": [
+                {
+                    "operation": "projects",
+                    "value": "NA"
+                },
+                {
+                    "operation": "projects:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "projects:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "projects:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "projects:id:patch",
+                    "value": "NA"
+                },
+                {
+                    "operation": "projects:id:delete",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "Roles",
+            "permissions": [
+                {
+                    "operation": "roles",
+                    "value": "NA"
+                },
+                {
+                    "operation": "roles:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "roles:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "roles:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "roles:id:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "roles:id:patch",
+                    "value": "NA"
+                }
+            ]
+        },
+        {
+            "title": "Tokens",
+            "permissions": [
+                {
+                    "operation": "tokens",
+                    "value": "NA"
+                },
+                {
+                    "operation": "tokens:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "tokens:post",
+                    "value": "NA"
+                },
+                {
+                    "operation": "tokens:delete",
+                    "value": "NA"
+                },
+                {
+                    "operation": "tokens:id:get",
+                    "value": "NA"
+                },
+                {
+                    "operation": "tokens:id:delete",
+                    "value": "NA"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
new file mode 100644 (file)
index 0000000..6c80bf8
--- /dev/null
@@ -0,0 +1,479 @@
+{
+    "OSM": "OSM",
+    "APPVERSION": "App Version",
+    "OSMVERSION": "OSM Version",
+    "OSMSOURCEMANO": "Open Source MANO",
+    "ADMIN": "Admin",
+    "ENTRIES": "Einträge",
+    "COMPOSE": "Komponieren a",
+    "CREATE": "Erstellen",
+    "SELECT": "Wählen",
+    "CANCEL": "Stornieren",
+    "SAVE": "speichern",
+    "COUNT": "Anzahl",
+    "IMAGE": "Bild",
+    "IPPROFILEREF": "IP-Profil Ref",
+    "ACTION": "Aktion",
+    "ADD": "Hinzufügen",
+    "EDIT": "Bearbeiten",
+    "APPLY": "Sich bewerben",
+    "FORCE": "Macht",
+    "DOWNLOAD": "Herunterladen",
+    "CONTENT": "Inhalt",
+    "DELETE": "Löschen",
+    "FORCEDELETE": "Löschen erzwingen",
+    "RENAME": "Umbenennen",
+    "INFO": "Info",
+    "NSPACKAGES": "NS Pakete",
+    "VNFPACKAGES": "VNF Pakete",
+    "INSTANCES": "Instanzen",
+    "INSTANTIATE": "Instanziieren",
+    "NSINSTANCES": "NS Instanzen",
+    "VNFINSTANCES": "VNF Instanzen",
+    "PDUINSTANCES": "PDU Instanzen",
+    "VIMACCOUNTS": "VIM Konten",
+    "WIMACCOUNTS": "WIM-Konten",
+    "SDNCONTROLLER": "SDN Reglerin",
+    "NETSLICE": "Netslice",
+    "PROJECT": "Projekt",
+    "DOMAIN": "Domain",
+    "PACKAGES": "Pakete",
+    "MODIFIED": "Geändert",
+    "NODATAMSG": "Keine Daten in der Tabelle verfügbar",
+    "SHORTNAME": "Kurzer Name",
+    "IDENTIFIER": "Kennung",
+    "DESCRIPTION": "Beschreibung",
+    "VENDOR": "Verkäuferin",
+    "VERSION": "Ausführung",
+    "ACTIONS": "Aktionen",
+    "NAME": "Name",
+    "USAGESTATE": "Nutzungsstatus",
+    "MODIFICATIONDATE": "Änderungsdatum",
+    "CREATEDDATE": "Erstellungsdatum",
+    "OPERATIONALSTATUS": "Betriebs Status",
+    "OPERATIONALSTATE": "Betriebszustand",
+    "CONFIGSTATUS": "Konfigurations Status",
+    "DETAILEDSTATUS": "Detaillierter Status",
+    "NSDNAME": "Nsd name",
+    "NSTNAME": "Nst name",
+    "TYPE": "Art",
+    "VNFD": "VNFD",
+    "VNF": "VNF",
+    "MEMBERINDEX": "Mitglieds  Index",
+    "NS": "NS",
+    "CREATEDAT": "Hergestellt in",
+    "CREATED": "Erstellt",
+    "ALL": "Alle",
+    "ID": "Id",
+    "OPERATIONSTATE": "Betriebszustand",
+    "STARTTIME": "Startzeit",
+    "STATUSENTEREDTIME": "Status Eingegebene Zeit",
+    "HISTORYOFOPERATIONS": "Geschichte der Operationen",
+    "UPDATE": "Aktualisieren",
+    "READONLYMODE": "Nur-Lese-Modus",
+    "CURRENTLY": "Zur Zeit",
+    "ON": "Auf",
+    "OFF": "aus",
+    "IN": "im",
+    "FILES": "Dateien",
+    "NEW": "Neu",
+    "RECENTLY": "Vor kurzem",
+    "TOPOLOGY": "Topologie",
+    "PLEASEWAIT": "Warten Sie mal",
+    "LOADING": "Wird geladen",
+    "RESOURCEORCHESTRATOR": "Ressource Orchestrator",
+    "VIEW": "Aussicht",
+    "DROP": "Fallen",
+    "HERE": "Here",
+    "MAPVIEW": "Kartenansicht",
+    "LISTVIEW": "Listenansicht",
+    "OK": "Okay",
+    "DELETEDSUCCESSFULLY": "Erfolgreich gelöscht",
+    "SESSIONEXPIRY": "Sitzung abgelaufen, bitte erneut anmelden",
+    "DELETECONFIRMPOPUPMESSAGE": "Möchten Sie wirklich löschen?",
+    "DELETELOADERMESSAGE": "Bitte warten Sie, während der Löschvorgang ausgeführt wird",
+    "VALUE": "Wert",
+    "PERFORMACTION": "Aktion ausführen",
+    "EXECUTE": "Execute",
+    "EXECNSPRIMITIVE": "Exec NS Primitive",
+    "PRIMITIVETYPE": "Primitiver Typ",
+    "VNFPRIMITIVE": "VNF Level Primitive",
+    "NSPRIMITIVE": "NS Level Primitive",
+    "DESCRIPTOR": "Deskriptor",
+    "ERROR": "Etwas ist schief gelaufen. Bitte versuche es erneut",
+    "SHOWGRAPH": "Grafik anzeigen",
+    "UPDATESHOWGRAPH": "Grafik aktualisieren und anzeigen",
+    "CREATEPACKAGE": "Neues Paket erstellen",
+    "GZFILETYPEERRROR": "Laden Sie nur eine tar.gz-Datei hoch und die Größe sollte 15 MB nicht überschreiten",
+    "YAMLFILETYPEERRROR": "Laden Sie nur YAML-Dateien hoch und die Größe sollte 15 MB nicht überschreiten",
+    "JSONFILETYPEERRROR": "Laden Sie nur JSON-Dateien hoch und die Größe sollte 15 MB nicht überschreiten",
+    "PUBFILETYPEERRROR": "Laden Sie nur PUB-Dateien hoch und die Größe sollte 15 MB nicht überschreiten",
+    "PACKAGE": "Paket",
+    "URL": "URL",
+    "DEPLOYED": "Bereitgestellt",
+    "ROLES": "Rollen",
+    "INSTANCEDETAILS": "Instanzdetails",
+    "IPADDRESS": "IP Adresse",
+    "MGMT": "Mgmt",
+    "NETNAME": "Netzname",
+    "USER": "Benutzerin",
+    "PORT": "Hafen",
+    "USERNAME": "Nutzername",
+    "PASSWORD": "Passwort",
+    "NODATAERROR": "Beim Abrufen der Informationen ist ein Fehler aufgetreten",
+    "FREEZE": "Bevriezen",
+    "UNFREEZE": "Auftauen",
+    "CLONE": "Klon",
+    "CLONECONFIRMPOPUPMESSAGE": "Möchten Sie wirklich klonen",
+    "CLONESUCCESSFULLY": "Paket erfolgreich geklont",
+    "DROPFILES": "Ziehen Sie die Dateien einfach hierher oder klicken Sie hier, um sie hochzuladen",
+    "DROPFILESVALIDATION": "Bitte wählen Sie eine zu verarbeitende Datei aus",
+    "METRICS": "Metriken",
+    "NOOFHOURS": "Anzahl der Stunden",
+    "MANDATORYCHECK": "Verplichte velden zijn gemarkeerd met een sterretje (*)",
+    "K8VERSION": "K8-versie",
+    "ENTER": "Eingeben",
+    "SWITCHPROJECT": "Projekt wechseln",
+    "CURRENTPROJECT": "Derzeitiges Projekt",
+    "SUBMIT": "Submit",
+    "REFRESH": "Aktualisierung",
+    "OPEN": "Öffnen",
+    "UPLOADCONFIG": "Upload Config",
+    "FILEUPLOADLABEL": "Oder aus Datei laden",
+    "CONFIG": "Konfig",
+    "YAMLCONFIG": "Yaml Konfig",
+    "CHOOSEFILE": "Datei wählen",
+    "INVALIDCONFIG": "Ungültige Konfiguration",
+    "PAGE": {
+        "DASHBOARD": {
+            "DASHBOARD": "Instrumententafel",
+            "RECENTUSERLOG": "Letztes Benutzerprotokoll",
+            "LOGS": "Protokolle",
+            "FAILEDINSTANCES": "Fehlgeschlagene Instanzen",
+            "NOINSTANCES": "Keine Instanzen verfügbar",
+            "UPTIME": "Betriebszeit",
+            "RUNNINGINSTANCES": "Laufende Instanzen",
+            "NETSLICETEMPLATE": "NetSlice Vorlage",
+            "NETSLICEINSTANCE": "NetSlice Instanzen",
+            "USERS": "Benutzer",
+            "PROJECTS": "Projekte",
+            "USERSETTINGS": "Benutzereinstellungen",
+            "LOGOUT": "Ausloggen"
+        },
+        "LOGIN": {
+            "USERNAME": "Nutzername",
+            "PASSWORD": "Passwort",
+            "SIGNUP": "Anmelden",
+            "ACCOUNTCREATEMESSAGE": "Sie haben noch keinen Account?",
+            "LOGIN": "Anmeldung",
+            "PASSWORDVALIDMESSAGE": "Passwort wird benötigt",
+            "USERNAMEVALIDMESSAGE": "Ein Benutzername wird benötigt",
+            "SIGNINMSG": "Melden Sie sich an, um Ihre Sitzung zu starten",
+            "PASSWORDMINLENGTHVALIDMESSAGE": "Das Passwort muss aus 8 Zeichen bestehen und mindestens ein Groß-, Klein-, Ziffern- und Sonderzeichen enthalten",
+            "USERNAMEMINLENGTHVALIDMESSAGE": "Der Benutzername muss aus mindestens 5 Zeichen bestehen"
+        },
+        "INSTANCEINSTANTIATE": {
+            "NEWINSTANCE": "Neue Instanz",
+            "NSNAME": "Ns Name",
+            "DESCRIPTION": "Beschrijving",
+            "NSID": "Nsd Id",
+            "SSHKEY": "SSH-Schlüssel",
+            "VIMACCOUNT": "VIM-Konto",
+            "SSHKEYMSG": "Fügen Sie hier Ihren Schlüssel ein"
+        },
+        "NSMETRIC": {
+            "INSTANCESMETRIC": "Instanzmetrik",
+            "METRICERROR": "Daten in Metriken nicht verfügbar"
+        },
+        "USERSETTINGS": {
+            "LANGUAGE": "Sprache"
+        },
+        "VIM": {
+            "CREATEDSUCCESSFULLY": "VIM erfolgreich erstellt",
+            "LOACTIONINFO": "Geben Sie den Standortnamen ein und klicken Sie auf die Eingabetaste, um den Standort aus der Liste auszuwählen"
+        },
+        "VIMDETAILS": {
+            "NEWVIM": "Nieuwe VIM",
+            "VIMACCOUNTDETAILS": "VIM-Kontodetails",
+            "NAME": "Name",
+            "VIMUSERNAME": "VIM-Benutzername",
+            "VIMURL": "VIM-URL",
+            "VIMTYPE": "Art",
+            "TENANTNAME": "Name des Mieters",
+            "DESCRIPTION": "Beschreibung",
+            "SCHEMATYPE": "Schematyp",
+            "SCHEMAVERSION": "Schema-Version",
+            "CONFIGPARAMETERS": "KONFIG-PARAMETER",
+            "SDNCONTROLLER": "SDN-Controller",
+            "SDNPORTMAPPING": "SDN-Port-Zuordnung",
+            "VIMNETWORKNAME": "VIM-Netzwerkname",
+            "SECURITYGROUPS": "Sicherheitsgruppen",
+            "AVAILABILITYZONE": "Verfügbarkeitszone",
+            "REGIONALNAME": "Name der Region",
+            "INSECURE": "Unsicher",
+            "USEEXISTINGFLAVOURS": "Verwenden Sie vorhandene Aromen",
+            "USEINTERNALENDPOINT": "Verwenden Sie den internen Endpunkt",
+            "APIVERSION": "API-Version",
+            "PROJECTDOMAINID": "Projektdomänen-ID",
+            "PROJECTDOMAINNAME": "Projektdomänenname",
+            "USERDOMAINID": "Benutzer-Domain-ID",
+            "USERDOMAINUSER": "Benutzer-Domainname",
+            "KEYPAIR": "Schlüsselpaar",
+            "DATAPLANEPHYSICALNET": "Dataplane physikalisches Netz",
+            "USEFLOATINGIP": "Verwenden Sie Floating IP",
+            "DATAPLANENETVLANRANGE": "Dataplane Net VLAN-Bereich",
+            "MICROVERSION": "Mikroversion",
+            "BACKTOVIMACCOUNTS": "Zurück zu VimAccounts",
+            "VIMPASSWORD": "VIM-Passwort",
+            "ADDITIONALCONFIG": "Zusätzliche Konfiguration",
+            "ADDITIONALCONFIGPLACEHOLDER": "{'key1':[...],'key2':{},'key3':''}",
+            "NEWVIMACCOUNT": "Neues VIM-Konto",
+            "ORGNAME": "Orgname",
+            "VCENTERIP": "Vcenter ip",
+            "VCENTERPORT": "Vcenter-Anschluss",
+            "ADMINUSERNAME": "Admin-Benutzername",
+            "VCENTERUSER": "Vcenter-Benutzer",
+            "ADMINPASSWORD": "Administrator-Passwort",
+            "VCENTERPASSWORD": "Vcenter Passwort",
+            "NSXMANAGER": "Nsx Manager",
+            "VROPSSITE": "Vrops Seite",
+            "NSXUSER": "Nsx Benutzer",
+            "VROPSUSER": "Vrops Benutzer",
+            "NSXPASSWORD": "Nsx Passwort",
+            "VROPSPASSWORD": "Vrops Passwort",
+            "VPCCIDRBLOCK": "VPC-CIDR-Block",
+            "FLAVORIINFO": "Geschmacksinfo",
+            "VIM_TYPE": "VIM-Typ",
+            "VIMLOCATION": "VIM-Speicherort",
+            "SUBSCRIPTIONID": "Abonnement-ID",
+            "RESOURCEGROUP": "Ressourcengruppe",
+            "VNETNAME": "VNet Name",
+            "FLAVORSPATTERN": "Geschmacksmuster"
+        },
+        "WIMACCOUNTS": {
+            "CREATEDSUCCESSFULLY": "WIM erfolgreich erstellt",
+            "WIMDETAILS": "WIM-Details",
+            "NEWWIM": "Neuer WIM",
+            "SCHEMAVERSION": "Schema-Version",
+            "RO": "RO",
+            "ROACCOUNT": "RO-Konto",
+            "USERNAME": "WIM-Benutzername",
+            "PASSWORD": "WIM-Passwort"
+        },
+        "NSINSTANCE": {
+            "NEWNSINSTANCE": "Nieuwe NS",
+            "CREATEDSUCCESSFULLY": "NS-Instanz erfolgreich erstellt"
+        },
+        "VNFINSTANCE": {
+            "ADDVNFINSTANCE": "VNF-Instanz hinzufügen"
+        },
+        "PDUINSTANCE": {
+            "NEWPDUINSTANCE": "Nieuwe PDU",
+            "PDUTYPE": "PDU-Typ",
+            "PARAMETERS": "PDU-Instanzparameter",
+            "ADDINSTANCEPARAMS": "Instanzparameter hinzufügen",
+            "CREATEDSUCCESSFULLY": "PDU-Instanzen erfolgreich erstellt"
+        },
+        "NETSLICEINSTANCE": {
+            "CREATENETSLICEINSTANCE": "Maak NSI"
+        },
+        "SDNCONTROLLER": {
+            "NEWSDNCONTROLLER": "Nieuwe SDN-controller",
+            "REGISTEREDSDNCONTROLLER": "Registrierte SDN Controller",
+            "RO": "RO",
+            "DPID": "DPID",
+            "CREATEDSUCCESSFULLY": "SDN erfolgreich registriert",
+            "DPIDPLACEHOLDER": "xx:xx:xx:xx:xx:xx:xx:xx",
+            "DETAILS": "SDN-Controller-Details"
+        },
+        "USERS": {
+            "CREATEUSER": "Gebruiker aanmaken",
+            "NEWUSER": "Neuer Benutzer",
+            "USERNAME": "Nutzername",
+            "PASSWORD": "Passwort",
+            "CONFPASSWORD": "Passwort bestätigen",
+            "EDITUSER": "Benutzer bearbeiten",
+            "NEWPASSWORD": "Neues Kennwort",
+            "DEFAULTPROJECT": "Standardprojekt",
+            "PASSWORDCONFLICT": "Passwort und Passwort bestätigen stimmen nicht überein",
+            "PASSWORDMATCH": "Passwort-Übereinstimmung",
+            "CREATEDSUCCESSFULLY": "Benutzer erfolgreich erstellt",
+            "EDITEDSUCCESSFULLY": "Benutzer erfolgreich bearbeiten",
+            "EDITCREDENTIALS": "Passwort ändern",
+            "EDITUSERNAME": "Benutzernamen ändern",
+            "PROJECTSROLES": "Projekte Rollen",
+            "EDITPROJECTROLEMAPPING": "Projektrollenzuordnung bearbeiten",
+            "ADDMAPPINGS": "Mappings hinzufügen",
+            "EDITPROJECTROLEERROR": "Bitte geben Sie mindestens eine Projektrollenzuordnung an, um fortzufahren"
+        },
+        "TOPOLOGY": {
+            "SELECTELEMENT": "Element auswählen",
+            "VL": "VL",
+            "VNF": "VNF",
+            "VNFD": "VNFD",
+            "CP": "CP",
+            "NSD": "NSD",
+            "NS": "NS",
+            "VIRTUALLINK": "Virtueller Link",
+            "CONNECTIONPOINT": "Verbindungspunkt",
+            "INTCONNECTIONPOINT": "Int Verbindungspunkt",
+            "LINK": "Verknüpfung",
+            "ADDINGCP": "Bitte wählen Sie einen Verbindungspunkt von {{vnfdname}}, um {{vlname}} zu verknüpfen?",
+            "INFO": "Info",
+            "HELP": "Hilfe",
+            "HELPINFO": {
+                "CREATEEDGE": "Kante erstellen",
+                "CREATEEDGEFIRSTSETENCE": "Wählen Sie den ersten Scheitelpunkt aus, indem Sie mit darauf klicken",
+                "CREATEEDGESECONDSETENCE": "auf einem anderen Scheitelpunkt (anders als der ausgewählte).",
+                "DELETEEDGEVERTEX": "Kante / Scheitelpunkt löschen",
+                "DELETEEDGEVERTEXSENTENCE": "Doppelklicken Sie auf Kante / Scheitelpunkt.",
+                "SPREADEDGE": "Kante spreizen",
+                "SPREADEDGESENTENCE": "Wählen Sie den Scheitelpunkt aus, indem Sie mit darauf klicken",
+                "EDGEINFO": "Kanteninformationen anzeigen",
+                "EDGEINFOSENTENCE": "Wählen Sie die Kante durch Klicken aus. Die Informationen werden auf der linken Seite angezeigt."
+            },
+            "VDU": "VDU",
+            "INTVL": "IntVL",
+            "INTCP": "IntCP",
+            "DATAEMPTY": "Bitte ändere etwas"
+        },
+        "PROJECT": {
+            "NEWPROJECT": "Nieuw project",
+            "CREATEDSUCCESSFULLY": "Projekt erfolgreich erstellt",
+            "UPDATEDSUCCESSFULLY": "Projekt erfolgreich aktualisiert"
+        },
+        "NSPACKAGE": {
+            "ADDNSPACKAGE": "Verfassen Sie eine neue NS",
+            "CREATEDSUCCESSFULLY": "NS-Paket erfolgreich erstellt",
+            "NSCOMPOSE": {
+                "UPDATEDSUCCESSFULLY": "Erfolgreich geupdated",
+                "CONFIRMCONNECTIONPOINT": "Bitte bestätigen Sie, um den Verbindungspunkt hinzuzufügen",
+                "CANNOTLINKVNF": "Sie können einen VNF nicht mit einem VNF verknüpfen",
+                "CANNOTLINKVL": "Sie können eine VL nicht mit einer VL verknüpfen",
+                "CANNOTLINKVLVNF": "Sie können eine VL nicht mit einer VNF verknüpfen",
+                "CANNOTLINKVNFCP": "Sie können einen VNF nicht mit einem CP verknüpfen",
+                "CANNOTLINKVLCP": "Sie können eine VL nicht mit einem CP verknüpfen",
+                "CANNOTLINKCP": "Sie können einen CP nicht mit einem CP verknüpfen",
+                "ADDNSD": "Virtueller Link wurde erfolgreich hinzugefügt",
+                "ADDVNFD": "VNFD wurde erfolgreich hinzugefügt",
+                "ADDNS": "Der Verbindungslink wurde erfolgreich hinzugefügt",
+                "DELETENSD": "Der virtuelle Link wurde erfolgreich gelöscht",
+                "DELETEVNFD": "VNF erfolgreich gelöscht",
+                "DELETENS": "Der Verbindungspunkt wurde erfolgreich gelöscht",
+                "DELETELINK": "Der Link wurde erfolgreich gelöscht",
+                "MGMTNETWORK": "Mgmt Network",
+                "VIMNETWORKNAME": "Vim Network Name",
+                "MEMBER-VNF-INDEX": "member-vnf-index",
+                "VNFD-ID-REF": "vnfd-id-ref",
+                "VLD-ID": "vld-id",
+                "VNFD-CP-REF": "vnfd-Verbindungspunkt-ref"
+            },
+            "EDITPACKAGES": {
+                "UPDATEDSUCCESSFULLY": "Erfolgreich geupdated"
+            }
+        },
+        "VNFPACKAGE": {
+            "ADDVNFPACKAGE": "Erstellen Sie eine neue VNF",
+            "CREATEDSUCCESSFULLY": "VNF-Paket erfolgreich erstellt",
+            "VNFCOMPOSE": {
+                "UPDATEDSUCCESSFULLY": "Erfolgreich geupdated",
+                "INVALIDSELECTION": "Ungültige Auswahl",
+                "YOUCANNOTDELETELINK": "Sie können den Link nicht löschen",
+                "CANNOTLINKVDUANDINTCP": "Sie können vdu nicht mit int_cp verknüpfen",
+                "CANNOTLINKINTCPANDVDU": "Sie können int_cp nicht mit vdu verknüpfen",
+                "CANNOTLINKCPANDVNFVL": "Sie können cp nicht mit vnf_vl verknüpfen",
+                "CANNOTLINKVNFVLANDCP": "Sie können vnf_vl nicht mit cp verknüpfen",
+                "CANNOTLINKINTCPANDCP": "Sie können intcp nicht mit cp verknüpfen",
+                "CANNOTLINKCPANDINTCP": "Sie können cp nicht mit int_cp verknüpfen",
+                "CANNOTLINKVDUANDVDU": "Sie können ein vdu nicht mit einem vdu verknüpfen"
+            }
+        },
+        "NETSLICE": {
+            "CREATEDSUCCESSFULLY": "Netslice erfolgreich erstellt",
+            "TEMPLATECREATEDSUCCESSFULLY": "Netslice-Vorlage erfolgreich erstellt",
+            "UPDATEDSUCCESSFULLY": "Vorlage erfolgreich aktualisiert"
+        },
+        "NETSLICETEMPLATE": {
+            "NETSLICETEMPLATEDETAILS": "Netzwerk-Slices-Vorlagendetails"
+        },
+        "NSTINSTANCEINSTANTIATE": {
+            "NEWINSTANCE": "Neue Instanz",
+            "NSNAME": "Ns Name",
+            "DESCRIPTION": "Beschrijving",
+            "NSTID": "Nst Id",
+            "SSHKEY": "SSH-Schlüssel",
+            "VIMACCOUNT": "VIM-Konto",
+            "SSHKEYMSG": "Fügen Sie Ihren Schlüssel hier ein ..."
+        },
+        "NSPRIMITIVE": {
+            "PRIMITIVE": "Primitive",
+            "PRIMITIVEPARAMETERS": "Primitive Parameter",
+            "ADDPRIMITIVEPARAMS": "Primitive Parameter hinzufügen",
+            "EXECUTEDSUCCESSFULLY": "NS Primitive Configuration ausgeführt"
+        },
+        "ROLES": {
+            "CREATEROLE": "Rolle erstellen",
+            "ROLE": "Rolle",
+            "PERMISSIONS": "Berechtigungen",
+            "YAMLPERMISSIONS": "YAML Berechtigungen",
+            "CREATEDSUCCESSFULLY": "Rolle erfolgreich erstellt",
+            "UPDATEDSUCCESSFULLY": "Rolle erfolgreich aktualisiert",
+            "ROLEJSONERROR": "Rollenberechtigungen sollten in einer Schlüsselwertweise bereitgestellt werden",
+            "ROLEKEYERROR": "Der Wert von '{{roleKey}}' in Rollenberechtigungen sollte boolesch sein",
+            "EDITROLE": "Rolle bearbeiten",
+            "PREVIEW": "Vorschau",
+            "TEXTVIEW": "Textvorschau"
+        },
+        "K8S": {
+            "MENUK8S": "K8s",
+            "MENUK8SCLUSTER": "K8s Clusters",
+            "MENUK8SREPO": "K8s Repos",
+            "REGISTERK8CLUSTER": "Geregistreerde K8s-clusters",
+            "ADDK8CLUSTER": "K8s-cluster toevoegen",
+            "K8SCLUSTERDETAILS": "K8s Clusterdetails",
+            "REGISTERK8REPO": "Geregistreerde K8s-repository",
+            "ADDK8REPO": "K8s Repository toevoegen",
+            "K8SREPODETAILS": "K8s Repository Details",
+            "CREATEDSUCCESSFULLY": "K8s met succes gemaakt",
+            "NEWK8SCLUSTER": "Nieuw K8s-cluster",
+            "NAME": "Naam",
+            "K8SVERSION": "K8s-versie",
+            "VIMACCOUNT": "Vim-account",
+            "DESCRIPTION": "Beschrijving",
+            "NETS": "Nets",
+            "NETSPLACEHOLDER": "example: {'net1': 'osm-ext'}",
+            "CREDENTIALS": "Inloggegevens",
+            "NEWK8SREPO": "Nieuwe K8s Repository",
+            "TYPE": "Type",
+            "URL": "URL"
+        }
+    },
+    "HTTPERROR": {
+        "401": "Zugriff verweigert",
+        "400": "Bitte überprüfen Sie die Anfrage und versuchen Sie es erneut",
+        "404": "Erwarteter Dienst nicht verfügbar. Bitte versuchen Sie es später erneut.",
+        "500": "Serverfehler, Bitte versuchen Sie es später noch einmal",
+        "502": "Slechte gateway, probeer het later opnieuw",
+        "503": "Dienst vorübergehend nicht verfügbar. Bitte versuchen Sie es später erneut.",
+        "504": "Gateway timeout fehler. Bitte versuchen Sie es später erneut",
+        "409": "Bitte versuchen Sie es später noch einmal."
+    },
+    "PAGENOTFOUND": {
+        "OOPS": "Hoppla!",
+        "NOTFOUND": "404 Nicht gefunden",
+        "CONTENT": "Die Seite kann nicht gefunden oder nicht autorisiert werden, ist möglicherweise nicht mehr relevant oder hat ihren Namen geändert",
+        "MEAN": "In der Zwischenzeit können Sie zu zurückkehren",
+        "HOME": "Zuhause"
+    },
+    "DOMVALIDATIONS": {
+        "INVALIDURL": "Geben Sie eine gültige URL ein",
+        "INVALIDIPADDRESS": "Geben Sie eine gültige IP-Adresse ein",
+        "INVALIDPORTADDRESS": "Geben Sie eine gültige PORT-Adresse ein",
+        "INVALIDDPID": "Geben Sie eine gültige DPID ein",
+        "INVALIDJSON": "Geben Sie ein gültiges JSON-Format ein",
+        "INVALIDYAML": "Geben Sie ein gültiges YAML-Format ein"
+    },
+    "GRAFANA": {
+        "METRICSERROR": "Keine gültigen Metriken"
+    }
+}
\ No newline at end of file
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
new file mode 100644 (file)
index 0000000..d22cbae
--- /dev/null
@@ -0,0 +1,479 @@
+{
+    "OSM": "OSM",
+    "APPVERSION": "App Version",
+    "OSMVERSION": "OSM Version",
+    "OSMSOURCEMANO": "Open Source MANO",
+    "ADMIN": "Admin",
+    "ENTRIES": "Entries",
+    "COMPOSE": "Compose a",
+    "CREATE": "Create",
+    "SELECT": "Select",
+    "CANCEL": "Cancel",
+    "SAVE": "Save",
+    "ACTION": "Action",
+    "COUNT": "Count",
+    "IMAGE": "Image",
+    "IPPROFILEREF": "IP Profile Ref",
+    "ADD": "Add",
+    "EDIT": "Edit",
+    "APPLY": "Apply",
+    "FORCE": "Force",
+    "DOWNLOAD": "Download",
+    "CONTENT": "Content",
+    "DELETE": "Delete",
+    "FORCEDELETE": "Force Delete",
+    "RENAME": "Rename",
+    "INFO": "Info",
+    "NSPACKAGES": "NS Packages",
+    "VNFPACKAGES": "VNF Packages",
+    "INSTANCES": "Instances",
+    "INSTANTIATE": "Instantiate",
+    "NSINSTANCES": "NS Instances",
+    "VNFINSTANCES": "VNF Instances",
+    "PDUINSTANCES": "PDU Instances",
+    "VIMACCOUNTS": "VIM Accounts",
+    "WIMACCOUNTS": "WIM Accounts",
+    "SDNCONTROLLER": "SDN Controller",
+    "NETSLICE": "Netslice",
+    "PROJECT": "Project",
+    "DOMAIN": "Domain",
+    "PACKAGES": "Packages",
+    "MODIFIED": "Modified",
+    "NODATAMSG": "No data available in table",
+    "SHORTNAME": "Short Name",
+    "IDENTIFIER": "Identifier",
+    "DESCRIPTION": "Description",
+    "VENDOR": "Vendor",
+    "VERSION": "Version",
+    "ACTIONS": "Actions",
+    "NAME": "Name",
+    "USAGESTATE": "UsageState",
+    "MODIFICATIONDATE": "Modification Date",
+    "CREATEDDATE": "Creation Date",
+    "OPERATIONALSTATUS": "Operational Status",
+    "OPERATIONALSTATE": "Operational State",
+    "CONFIGSTATUS": "Config Status",
+    "DETAILEDSTATUS": "Detailed Status",
+    "NSDNAME": "Nsd name",
+    "NSTNAME": "Nst name",
+    "TYPE": "Type",
+    "VNFD": "VNFD",
+    "VNF": "VNF",
+    "MEMBERINDEX": "Member Index",
+    "NS": "NS",
+    "CREATEDAT": "Created At",
+    "CREATED": "Created",
+    "ALL": "All",
+    "ID": "Id",
+    "OPERATIONSTATE": "Operation State",
+    "STARTTIME": "Start Time",
+    "STATUSENTEREDTIME": "Status Entered Time",
+    "HISTORYOFOPERATIONS": "History Of Operations",
+    "UPDATE": "Update",
+    "READONLYMODE": "Read only mode",
+    "CURRENTLY": "Currently",
+    "ON": "On",
+    "OFF": "Off",
+    "IN": "in",
+    "FILES": "Files",
+    "NEW": "New",
+    "RECENTLY": "Recently",
+    "TOPOLOGY": "Topology",
+    "PLEASEWAIT": "Please Wait",
+    "LOADING": "Loading",
+    "RESOURCEORCHESTRATOR": "Resource Orchestrator",
+    "VIEW": "View",
+    "DROP": "Drop",
+    "HERE": "Here",
+    "MAPVIEW": "Map View",
+    "LISTVIEW": "List View",
+    "OK": "Ok",
+    "DELETEDSUCCESSFULLY": "{{title}} deleted successfully",
+    "SESSIONEXPIRY": "Session expired, please login again",
+    "DELETECONFIRMPOPUPMESSAGE": "Are you sure want to delete",
+    "DELETELOADERMESSAGE": "Please wait while {{title}} deletion is in progress",
+    "VALUE": "Value",
+    "PERFORMACTION": "Perform Action",
+    "EXECUTE": "Execute",
+    "EXECNSPRIMITIVE": "Exec NS Primitive",
+    "PRIMITIVETYPE": "Primitive Type",
+    "VNFPRIMITIVE": "VNF Level Primitive",
+    "NSPRIMITIVE": "NS Level Primitive",
+    "DESCRIPTOR": "Descriptor",
+    "ERROR": "Something Went wrong please try again",
+    "SHOWGRAPH": "Show Graph",
+    "UPDATESHOWGRAPH": "Update and Show Graph",
+    "CREATEPACKAGE": "Create New Package",
+    "GZFILETYPEERRROR": "Upload only tar.gz file and size should not exceed 15 MB",
+    "YAMLFILETYPEERRROR": "Upload only YAML file and size should not exceed 15 MB",
+    "JSONFILETYPEERRROR": "Upload only JSON file and size should not exceed 15 MB",
+    "PUBFILETYPEERRROR": "Upload only PUB file and size should not exceed 15 MB",
+    "PACKAGE": "Package",
+    "URL": "URL",
+    "DEPLOYED": "Deployed",
+    "ROLES": "Roles",
+    "INSTANCEDETAILS": "Instance Details",
+    "IPADDRESS": "IP Address",
+    "MGMT": "Mgmt",
+    "NETNAME": "Net Name",
+    "USER": "User",
+    "PORT": "Port",
+    "USERNAME": "Username",
+    "PASSWORD": "Password",
+    "NODATAERROR": "An error occurred while retrieving the information",
+    "FREEZE": "Freeze",
+    "UNFREEZE": "Unfreeze",
+    "CLONE": "Clone",
+    "CLONECONFIRMPOPUPMESSAGE": "Are you sure want to clone",
+    "CLONESUCCESSFULLY": "Package cloned successfully",
+    "DROPFILES": "Just drag and drop files or click here to upload files",
+    "DROPFILESVALIDATION": "Please select one file to process",
+    "METRICS": "Metrics",
+    "NOOFHOURS": "No Of Hours",
+    "MANDATORYCHECK": "Mandatory fields are marked with an asterisk (*)",
+    "K8VERSION": "K8 Version",
+    "ENTER": "Enter",
+    "SWITCHPROJECT": "Switch Project",
+    "CURRENTPROJECT": "Current Project",
+    "SUBMIT": "Submit",
+    "REFRESH": "Refresh",
+    "OPEN": "Open",
+    "UPLOADCONFIG": "Upload Config",
+    "FILEUPLOADLABEL": "Or load from file",
+    "CONFIG": "Config",
+    "YAMLCONFIG": "Yaml Config",
+    "CHOOSEFILE": "Choose File",
+    "INVALIDCONFIG": "Invalid configuration",
+    "PAGE": {
+        "DASHBOARD": {
+            "DASHBOARD": "Dashboard",
+            "RECENTUSERLOG": "Recent User Log",
+            "LOGS": "Logs",
+            "FAILEDINSTANCES": "Failed Instances",
+            "NOINSTANCES": "No Instances Available",
+            "UPTIME": "Uptime",
+            "RUNNINGINSTANCES": "Running Instances",
+            "NETSLICETEMPLATE": "NetSlice Template",
+            "NETSLICEINSTANCE": "NetSlice Instances",
+            "USERS": "Users",
+            "PROJECTS": "Projects",
+            "USERSETTINGS": "User Settings",
+            "LOGOUT": "Logout"
+        },
+        "LOGIN": {
+            "USERNAME": "Username",
+            "PASSWORD": "Password",
+            "SIGNUP": "Sign Up",
+            "ACCOUNTCREATEMESSAGE": "Don't have an account?",
+            "LOGIN": "Log In",
+            "PASSWORDVALIDMESSAGE": "Password is required",
+            "USERNAMEVALIDMESSAGE": "Username is required",
+            "SIGNINMSG": "Sign in to start your session",
+            "PASSWORDMINLENGTHVALIDMESSAGE": "Password must be 8 characters and contains at least one upper case, lower case, numeric & special character",
+            "USERNAMEMINLENGTHVALIDMESSAGE": "Username must be at least 5 characters"
+        },
+        "INSTANCEINSTANTIATE": {
+            "NEWINSTANCE": "New Instance",
+            "NSNAME": "Ns Name",
+            "DESCRIPTION": "Description",
+            "NSID": "Nsd Id",
+            "SSHKEY": "SSH Key",
+            "VIMACCOUNT": "VIM Account",
+            "SSHKEYMSG": "Paste your key here"
+        },
+        "NSMETRIC": {
+            "INSTANCESMETRIC": "Instances Metric",
+            "METRICERROR": "Data not available in metrics"
+        },
+        "USERSETTINGS": {
+            "LANGUAGE": "Language"
+        },
+        "VIM": {
+            "CREATEDSUCCESSFULLY": "VIM Created Successfully",
+            "LOACTIONINFO": "Type the location name and click enter button to select the location from the list"
+        },
+        "VIMDETAILS": {
+            "NEWVIM": "New VIM",
+            "VIMACCOUNTDETAILS": "VIM Account details",
+            "NAME": "Name",
+            "VIMUSERNAME": "VIM Username",
+            "VIMURL": "VIM URL",
+            "VIMTYPE": "Type",
+            "TENANTNAME": "Tenant name",
+            "DESCRIPTION": "Description",
+            "SCHEMATYPE": "Schema Type",
+            "SCHEMAVERSION": "Schema Version",
+            "CONFIGPARAMETERS": "CONFIG PARAMETERS",
+            "SDNCONTROLLER": "SDN Controller",
+            "SDNPORTMAPPING": "SDN Port Mapping",
+            "VIMNETWORKNAME": "VIM Network Name",
+            "SECURITYGROUPS": "Security Groups",
+            "AVAILABILITYZONE": "Availability Zone",
+            "REGIONALNAME": "Region Name",
+            "INSECURE": "Insecure",
+            "USEEXISTINGFLAVOURS": "Use existing flavors",
+            "USEINTERNALENDPOINT": "Use internal endpoint",
+            "APIVERSION": "API version",
+            "PROJECTDOMAINID": "Project domain id",
+            "PROJECTDOMAINNAME": "Project domain name",
+            "USERDOMAINID": "User domain id",
+            "USERDOMAINUSER": "User domain name",
+            "KEYPAIR": "Keypair",
+            "DATAPLANEPHYSICALNET": "Dataplane physical net",
+            "USEFLOATINGIP": "Use floating ip",
+            "DATAPLANENETVLANRANGE": "Dataplane net vlan range",
+            "MICROVERSION": "Microversion",
+            "BACKTOVIMACCOUNTS": "Back to VimAccounts",
+            "VIMPASSWORD": "VIM Password",
+            "ADDITIONALCONFIG": "Additional configuration",
+            "ADDITIONALCONFIGPLACEHOLDER": "{'key1':[...],'key2':{},'key3':''}",
+            "NEWVIMACCOUNT": "New VIM Account",
+            "ORGNAME": "Orgname",
+            "VCENTERIP": "Vcenter ip",
+            "VCENTERPORT": "Vcenter port",
+            "ADMINUSERNAME": "Admin username",
+            "VCENTERUSER": "Vcenter user",
+            "ADMINPASSWORD": "Admin password",
+            "VCENTERPASSWORD": "Vcenter password",
+            "NSXMANAGER": "Nsx manager",
+            "VROPSSITE": "Vrops site",
+            "NSXUSER": "Nsx user",
+            "VROPSUSER": "Vrops user",
+            "NSXPASSWORD": "Nsx password",
+            "VROPSPASSWORD": "Vrops password",
+            "VPCCIDRBLOCK": "VPC cidr block",
+            "FLAVORIINFO": "Flavor info",
+            "VIM_TYPE": "VIM Type",
+            "VIMLOCATION": "VIM Location",
+            "SUBSCRIPTIONID": "Subscription ID",
+            "RESOURCEGROUP": "Resource Group",
+            "VNETNAME": "VNet Name",
+            "FLAVORSPATTERN": "Flavors Pattern"
+        },
+        "WIMACCOUNTS": {
+            "CREATEDSUCCESSFULLY": "WIM Created Successfully",
+            "WIMDETAILS": "WIM Details",
+            "NEWWIM": "New WIM",
+            "SCHEMAVERSION": "Schema Version",
+            "RO": "RO",
+            "ROACCOUNT": "RO Account",
+            "USERNAME": "WIM Username",
+            "PASSWORD": "WIM Password"
+        },
+        "NSINSTANCE": {
+            "NEWNSINSTANCE": "New NS",
+            "CREATEDSUCCESSFULLY": "NS Instance Created Successfully"
+        },
+        "VNFINSTANCE": {
+            "ADDVNFINSTANCE": "Add VNF Instance"
+        },
+        "PDUINSTANCE": {
+            "NEWPDUINSTANCE": "New PDU",
+            "PDUTYPE": "PDU Type",
+            "PARAMETERS": "PDU Instances Parameters",
+            "ADDINSTANCEPARAMS": "Add Params",
+            "CREATEDSUCCESSFULLY": "PDU Instances Created Successfully"
+        },
+        "NETSLICEINSTANCE": {
+            "CREATENETSLICEINSTANCE": "Create NSI"
+        },
+        "SDNCONTROLLER": {
+            "NEWSDNCONTROLLER": "New SDN Controller",
+            "REGISTEREDSDNCONTROLLER": "Registered SDN Controllers",
+            "RO": "RO",
+            "DPID": "DPID",
+            "CREATEDSUCCESSFULLY": "SDN Registered Successfully",
+            "DPIDPLACEHOLDER": "xx:xx:xx:xx:xx:xx:xx:xx",
+            "DETAILS": "SDN Controller Details"
+        },
+        "USERS": {
+            "CREATEUSER": "Create User",
+            "NEWUSER": "New User",
+            "USERNAME": "User Name",
+            "PASSWORD": "Password",
+            "CONFPASSWORD": "Confirm Password",
+            "EDITUSER": "Edit User",
+            "NEWPASSWORD": "New Password",
+            "DEFAULTPROJECT": "Default Project",
+            "PASSWORDCONFLICT": "Password and confirm password are not matched",
+            "PASSWORDMATCH": "Password Match",
+            "CREATEDSUCCESSFULLY": "User Created Successfully",
+            "EDITEDSUCCESSFULLY": "User Edit Successfully",
+            "EDITCREDENTIALS": "Change Password",
+            "EDITUSERNAME": "Change Username",
+            "PROJECTSROLES": "Projects Roles",
+            "EDITPROJECTROLEMAPPING": "Edit Project Role Mapping",
+            "ADDMAPPINGS": "Add Mappings",
+            "EDITPROJECTROLEERROR": "Please provide at least one project role mapping to continue"
+        },
+        "TOPOLOGY": {
+            "SELECTELEMENT": "Select Element",
+            "VL": "VL",
+            "VNF": "VNF",
+            "VNFD": "VNFD",
+            "CP": "CP",
+            "NSD": "NSD",
+            "NS": "NS",
+            "VIRTUALLINK": "Virtual Link",
+            "CONNECTIONPOINT": "Connection Point",
+            "INTCONNECTIONPOINT": "Int Connection Point",
+            "LINK": "Link",
+            "ADDINGCP": "Please select a connection point of {{vnfdname}} to link {{vlname}}?",
+            "INFO": "Info",
+            "HELP": "Help",
+            "HELPINFO": {
+                "CREATEEDGE": "Create edge",
+                "CREATEEDGEFIRSTSETENCE": "Select the first vertex by clicking on it using",
+                "CREATEEDGESECONDSETENCE": "on another vertex (different than the selected one).",
+                "DELETEEDGEVERTEX": "Delete edge/vertex",
+                "DELETEEDGEVERTEXSENTENCE": "Double clicking on edge/vertex.",
+                "SPREADEDGE": "Spread edge",
+                "SPREADEDGESENTENCE": "Select the vertex by clicking on it using",
+                "EDGEINFO": "Show edge information",
+                "EDGEINFOSENTENCE": "Select the edge by clicking. The information will be shown on the left side."
+            },
+            "VDU": "VDU",
+            "INTVL": "IntVL",
+            "INTCP": "IntCP",
+            "DATAEMPTY": "Please change something"
+        },
+        "PROJECT": {
+            "NEWPROJECT": "New Project",
+            "CREATEDSUCCESSFULLY": "Project Created Successfully",
+            "UPDATEDSUCCESSFULLY": "Project Updated Successfully"
+        },
+        "NSPACKAGE": {
+            "ADDNSPACKAGE": "Compose a new NS",
+            "CREATEDSUCCESSFULLY": "NS Package Created Successfully",
+            "NSCOMPOSE": {
+                "UPDATEDSUCCESSFULLY": "Descriptor Updated Successfully",
+                "CONFIRMCONNECTIONPOINT": "Please confirm to add connection point",
+                "CANNOTLINKVNF": "You can't link a vnf with a vnf",
+                "CANNOTLINKVL": "You can't link a VL with a VL",
+                "CANNOTLINKVLVNF": "You can't link a VL with a vnf",
+                "CANNOTLINKVNFCP": "You can't link a VNF with a CP",
+                "CANNOTLINKVLCP": "You can't link a VL with a CP",
+                "CANNOTLINKCP": "You can't link a CP with a CP",
+                "ADDNSD": "Virtual Link is added succesfully",
+                "ADDVNFD": "VNFD is added succesfully",
+                "ADDNS": "Connection Link is added succesfully",
+                "DELETENSD": "Successfully Deleted the Virtual Link",
+                "DELETEVNFD": "Successfully Deleted the VNF",
+                "DELETENS": "Successfully Deleted the Connection point",
+                "DELETELINK": "Successfully Deleted the Link",
+                "MGMTNETWORK": "Mgmt Network",
+                "VIMNETWORKNAME": "Vim Network Name",
+                "MEMBER-VNF-INDEX": "member-vnf-index",
+                "VNFD-ID-REF": "vnfd-id-ref",
+                "VLD-ID": "vld-id",
+                "VNFD-CP-REF": "vnfd-connection-point-ref"
+            },
+            "EDITPACKAGES": {
+                "UPDATEDSUCCESSFULLY": "Descriptor Updated Successfully"
+            }
+        },
+        "VNFPACKAGE": {
+            "ADDVNFPACKAGE": "Compose a new VNF",
+            "CREATEDSUCCESSFULLY": "VNF Package Created Successfully",
+            "VNFCOMPOSE": {
+                "UPDATEDSUCCESSFULLY": "Descriptor Updated Successfully",
+                "INVALIDSELECTION": "Invalid Selection",
+                "YOUCANNOTDELETELINK": "You cannot delete link",
+                "CANNOTLINKVDUANDINTCP": "You cant link vdu with int_cp",
+                "CANNOTLINKINTCPANDVDU": "You cant link int_cp with vdu",
+                "CANNOTLINKCPANDVNFVL": "You cant link cp with vnf_vl",
+                "CANNOTLINKVNFVLANDCP": "You cant link vnf_vl with cp",
+                "CANNOTLINKINTCPANDCP": "You cant link intcp with cp",
+                "CANNOTLINKCPANDINTCP": "You cant link cp with int_cp",
+                "CANNOTLINKVDUANDVDU": "You can't link a vdu with a vdu"
+            }
+        },
+        "NETSLICE": {
+            "CREATEDSUCCESSFULLY": "Netslice Created Successfully",
+            "TEMPLATECREATEDSUCCESSFULLY": "Netslice Template Created Successfully",
+            "UPDATEDSUCCESSFULLY": "Template Updated Successfully"
+        },
+        "NETSLICETEMPLATE": {
+            "NETSLICETEMPLATEDETAILS": "Network Slices Template Details"
+        },
+        "NSTINSTANCEINSTANTIATE": {
+            "NEWINSTANCE": "New Instance",
+            "NSNAME": "Ns Name",
+            "DESCRIPTION": "Description",
+            "NSTID": "Nst Id",
+            "SSHKEY": "SSH Key",
+            "VIMACCOUNT": "VIM Account",
+            "SSHKEYMSG": "Paste your key here ..."
+        },
+        "NSPRIMITIVE": {
+            "PRIMITIVE": "Primitive",
+            "PRIMITIVEPARAMETERS": "Primitive Parameters",
+            "ADDPRIMITIVEPARAMS": "Add Primitive Params",
+            "EXECUTEDSUCCESSFULLY": "Executed NS Primitive Configuration"
+        },
+        "ROLES": {
+            "CREATEROLE": "Create Role",
+            "ROLE": "Role",
+            "PERMISSIONS": "Permissions",
+            "YAMLPERMISSIONS": "YAML Permissions",
+            "CREATEDSUCCESSFULLY": "Role Created Successfully",
+            "UPDATEDSUCCESSFULLY": "Role Updated Successfully",
+            "ROLEJSONERROR": "Role permissions should be provided in a key-value fashion",
+            "ROLEKEYERROR": "Value of '{{roleKey}}' in a role permissions should be boolean",
+            "EDITROLE": "Edit Role",
+            "PREVIEW": "Preview",
+            "TEXTVIEW": "Text View"
+        },
+        "K8S": {
+            "MENUK8S": "K8s",
+            "MENUK8SCLUSTER": "K8s Clusters",
+            "MENUK8SREPO": "K8s Repos",
+            "REGISTERK8CLUSTER": "Registered K8s clusters",
+            "ADDK8CLUSTER": "Add K8s Cluster",
+            "K8SCLUSTERDETAILS": "K8s Cluster Details",
+            "REGISTERK8REPO": "Registered K8s repository",
+            "ADDK8REPO": "Add K8s Repository",
+            "K8SREPODETAILS": "K8s Repository Details",
+            "CREATEDSUCCESSFULLY": "K8s Created Successfully",
+            "NEWK8SCLUSTER": "New K8s Cluster",
+            "NAME": "Name",
+            "K8SVERSION": "K8s Version",
+            "VIMACCOUNT": "Vim Account",
+            "DESCRIPTION": "Description",
+            "NETS": "Nets",
+            "NETSPLACEHOLDER": "example: {'net1': 'osm-ext'}",
+            "CREDENTIALS": "Credentials",
+            "NEWK8SREPO": "New K8s Repository",
+            "TYPE": "Type",
+            "URL": "URL"
+        }
+    },
+    "HTTPERROR": {
+        "401": "Access denied, Lack of permissions",
+        "400": "Please check the request and try again",
+        "404": "Expected service not avilable, Please try again later",
+        "500": "Server error, Please try again later",
+        "502": "Bad Gateway, Please try again later",
+        "503": "Service temporarily unavailable, Please try again later",
+        "504": "Gateway timeout error, Please try again later",
+        "409": "Please try again later"
+    },
+    "PAGENOTFOUND": {
+        "OOPS": "Oops!",
+        "NOTFOUND": "404 Not Found",
+        "CONTENT": "The page cannot be found or unauthorized, it might be no longer relevant or had its name changed",
+        "MEAN": "Meanwhile, you may return to",
+        "HOME": "Home"
+    },
+    "DOMVALIDATIONS": {
+        "INVALIDURL": "Enter a valid URL",
+        "INVALIDIPADDRESS": "Enter a valid IP Address",
+        "INVALIDPORTADDRESS": "Enter a valid PORT Address",
+        "INVALIDDPID": "Enter a valid DPID",
+        "INVALIDJSON": "Enter a valid JSON Format",
+        "INVALIDYAML": "Enter a valid JSON Format"
+    },
+    "GRAFANA": {
+        "METRICSERROR": "Not a valid metrics"
+    }
+}
\ No newline at end of file
diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json
new file mode 100644 (file)
index 0000000..0cd37b1
--- /dev/null
@@ -0,0 +1,479 @@
+{
+    "OSM": "OSM",
+    "APPVERSION": "Versión de la aplicación",
+    "OSMVERSION": "Versión OSM",
+    "OSMSOURCEMANO": "Fuente abierta MANO",
+    "ADMIN": "Admin",
+    "ENTRIES": "entradas",
+    "COMPOSE": "Componer un",
+    "CREATE": "Crear",
+    "SELECT": "Seleccionar",
+    "CANCEL": "Cancelar",
+    "SAVE": "Salvar",
+    "COUNT": "contar",
+    "IMAGE": "Imagen",
+    "IPPROFILEREF": "IP Profile Ref",
+    "ACTION": "Acción",
+    "ADD": "Añadir",
+    "EDIT": "Editar",
+    "APPLY": "Aplicar",
+    "FORCE": "Fuerza",
+    "DOWNLOAD": "Descargar",
+    "CONTENT": "contenido",
+    "DELETE": "Borrar",
+    "FORCEDELETE": "Eliminar forzado",
+    "RENAME": "Rebautizar",
+    "INFO": "Info",
+    "NSPACKAGES": "NS Paquetes",
+    "VNFPACKAGES": "VNF Paquetes",
+    "INSTANCES": "Instancias",
+    "INSTANTIATE": "Instanciar",
+    "NSINSTANCES": "Instancias de NS",
+    "VNFINSTANCES": "Instancias VNF",
+    "PDUINSTANCES": "Instancias PDU",
+    "VIMACCOUNTS": "Cuentas VIM",
+    "WIMACCOUNTS": "Cuentas WIM",
+    "SDNCONTROLLER": "Controlador SDN",
+    "NETSLICE": "Netslice",
+    "PROJECT": "Proyecto",
+    "DOMAIN": "Dominio",
+    "PACKAGES": "Paquetes",
+    "MODIFIED": "Modificado",
+    "NODATAMSG": "No hay datos disponibles en la tabla",
+    "SHORTNAME": "Nombre corto",
+    "IDENTIFIER": "Identificador",
+    "DESCRIPTION": "Descripción",
+    "VENDOR": "Vendedor",
+    "VERSION": "Versión",
+    "ACTIONS": "Comportamiento",
+    "NAME": "NOMBRE",
+    "USAGESTATE": "Estado de uso",
+    "MODIFICATIONDATE": "Fecha de modificación",
+    "CREATEDDATE": "Fecha de creación",
+    "OPERATIONALSTATUS": "Estado operativo",
+    "OPERATIONALSTATE": "Estado operacional",
+    "CONFIGSTATUS": "Estado de configuración",
+    "DETAILEDSTATUS": "Estado detallado",
+    "NSDNAME": "Nombre nsd",
+    "NSTNAME": "Nst name",
+    "TYPE": "Tipo",
+    "VNFD": "VNFD",
+    "VNF": "VNF",
+    "MEMBERINDEX": "Índice de miembros",
+    "NS": "NS",
+    "CREATEDAT": "Creado en",
+    "CREATED": "Creado",
+    "ALL": "Todas",
+    "ID": "Id",
+    "OPERATIONSTATE": "Estado de la operación",
+    "STARTTIME": "Hora de inicio",
+    "STATUSENTEREDTIME": "Tiempo ingresado estado",
+    "HISTORYOFOPERATIONS": "Historia de operaciones",
+    "UPDATE": "Actualizar",
+    "READONLYMODE": "Modo de solo lectura",
+    "CURRENTLY": "Actualmente",
+    "ON": "En",
+    "OFF": "APAGADA",
+    "IN": "en",
+    "FILES": "Archivos",
+    "NEW": "Nueva",
+    "RECENTLY": "Recientemente",
+    "TOPOLOGY": "Topología",
+    "PLEASEWAIT": "Por favor espera",
+    "LOADING": "Cargando",
+    "RESOURCEORCHESTRATOR": "Orquestador de recursos",
+    "VIEW": "Ver",
+    "DROP": "soltar",
+    "HERE": "aquí",
+    "MAPVIEW": "Vista del mapa",
+    "LISTVIEW": "Vista de la lista",
+    "OK": "Okay",
+    "DELETEDSUCCESSFULLY": "Eliminada Exitosamente",
+    "SESSIONEXPIRY": "Sesión expirada, por favor ingrese nuevamente",
+    "DELETECONFIRMPOPUPMESSAGE": "¿Seguro que quieres eliminar?",
+    "DELETELOADERMESSAGE": "Por favor espere mientras la eliminación está en progreso",
+    "VALUE": "Valor",
+    "PERFORMACTION": "Realizar una acción",
+    "EXECUTE": "Ejecutar",
+    "EXECNSPRIMITIVE": "Ejecutar NS Primitiva",
+    "PRIMITIVETYPE": "Tipo primitivo",
+    "VNFPRIMITIVE": "Nivel VNF Primitivo",
+    "NSPRIMITIVE": "NS Level Primitive",
+    "DESCRIPTOR": "Descriptora",
+    "ERROR": "Algo salió mal. Por favor, vuelva a intentarlo",
+    "SHOWGRAPH": "Mostrar gráfico",
+    "UPDATESHOWGRAPH": "Actualizar y mostrar gráfico",
+    "CREATEPACKAGE": "Crear nuevo paquete",
+    "GZFILETYPEERRROR": "Cargue solo el archivo tar.gz y el tamaño no debe exceder los 15 MB",
+    "YAMLFILETYPEERRROR": "Cargue solo el archivo YAML y el tamaño no debe exceder los 15 MB",
+    "JSONFILETYPEERRROR": "Cargue solo el archivo JSON y el tamaño no debe exceder los 15 MB",
+    "PUBFILETYPEERRROR": "Cargue solo el archivo PUB y el tamaño no debe exceder los 15 MB",
+    "PACKAGE": "Paquete",
+    "URL": "URL",
+    "DEPLOYED": "Desplegada",
+    "ROLES": "Roles",
+    "INSTANCEDETAILS": "Detalles de instancia",
+    "IPADDRESS": "Dirección IP",
+    "MGMT": "Mgmt",
+    "NETNAME": "Nombre neto",
+    "USER": "Usuaria",
+    "PORT": "Puerto",
+    "USERNAME": "Nombre de usuario",
+    "PASSWORD": "Contraseña",
+    "NODATAERROR": "Se produjo un error al recuperar la información",
+    "FREEZE": "Congelar",
+    "UNFREEZE": "Descongelar",
+    "CLONE": "Clon",
+    "CLONECONFIRMPOPUPMESSAGE": "Estás seguro de querer clonar",
+    "CLONESUCCESSFULLY": "Paquete clonado exitosamente",
+    "DROPFILES": "Simplemente arrastre y suelte archivos aquí o haga clic aquí para cargar archivos",
+    "DROPFILESVALIDATION": "Por favor seleccione un archivo para procesar",
+    "METRICS": "Métrica",
+    "NOOFHOURS": "No de horas",
+    "MANDATORYCHECK": "Los campos obligatorios están marcados con un asterisco (*)",
+    "K8VERSION": "Versión K8",
+    "ENTER": "Entrar",
+    "SWITCHPROJECT": "Cambiar proyecto",
+    "CURRENTPROJECT": "Proyecto actual",
+    "SUBMIT": "Entrar",
+    "REFRESH": "Actualizar",
+    "OPEN": "Abierta",
+    "UPLOADCONFIG": "Subir configuración",
+    "FILEUPLOADLABEL": "O cargar desde el archivo",
+    "CONFIG": "Config",
+    "YAMLCONFIG": "Yaml Config",
+    "CHOOSEFILE": "Elija el archivo",
+    "INVALIDCONFIG": "Configuración inválida",
+    "PAGE": {
+        "DASHBOARD": {
+            "DASHBOARD": "Tablero",
+            "RECENTUSERLOG": "Registro de usuario reciente",
+            "LOGS": "Troncos",
+            "FAILEDINSTANCES": "Instancias fallidas",
+            "NOINSTANCES": "Keine Instanzen verfügbar",
+            "UPTIME": "Tiempodeactividad",
+            "RUNNINGINSTANCES": "Corriendo Instancias",
+            "NETSLICETEMPLATE": "Plantilla NetSlice",
+            "NETSLICEINSTANCE": "NetSlice Instancias",
+            "USERS": "Usuarios",
+            "PROJECTS": "Proyectos",
+            "USERSETTINGS": "Usuarios Ajustes",
+            "LOGOUT": "Cerrar sesión"
+        },
+        "LOGIN": {
+            "USERNAME": "Nombre de usuario",
+            "PASSWORD": "Contraseña",
+            "SIGNUP": "Regístrate",
+            "ACCOUNTCREATEMESSAGE": "¿No tienes una cuenta?",
+            "LOGIN": "iniciar sesión",
+            "PASSWORDVALIDMESSAGE": "se requiere contraseña",
+            "USERNAMEVALIDMESSAGE": "Se requiere nombre de usuario",
+            "SIGNINMSG": "Inicia sesión para iniciar tu sesión.",
+            "PASSWORDMINLENGTHVALIDMESSAGE": "La contraseña debe tener 8 caracteres y contiene al menos un carácter en mayúscula, minúscula, numérico y especial",
+            "USERNAMEMINLENGTHVALIDMESSAGE": "El nombre de usuario debe tener al menos 5 caracteres"
+        },
+        "INSTANCEINSTANTIATE": {
+            "NEWINSTANCE": "Nueva instancia",
+            "NSNAME": "Nombre de Ns",
+            "DESCRIPTION": "Descripción",
+            "NSID": "Nsd Id",
+            "SSHKEY": "SSH Key",
+            "VIMACCOUNT": "Cuenta VIM",
+            "SSHKEYMSG": "Pega tu llave aquí"
+        },
+        "NSMETRIC": {
+            "INSTANCESMETRIC": "Instancia métrica",
+            "METRICERROR": "Datos no disponibles en métricas"
+        },
+        "USERSETTINGS": {
+            "LANGUAGE": "Idioma"
+        },
+        "VIM": {
+            "CREATEDSUCCESSFULLY": "VIM Creada Exitosamente",
+            "LOACTIONINFO": "Escriba el nombre de la ubicación y haga clic en el botón Intro para seleccionar la ubicación de la lista"
+        },
+        "VIMDETAILS": {
+            "NEWVIM": "Nuevo VIM",
+            "VIMACCOUNTDETAILS": "VIM Account detalles",
+            "NAME": "Nombre",
+            "VIMUSERNAME": "VIM Nombre de usuario",
+            "VIMURL": "VIM URL",
+            "VIMTYPE": "Tipo",
+            "TENANTNAME": "Tenant Nombre",
+            "DESCRIPTION": "Descripción",
+            "SCHEMATYPE": "Tipo de esquema",
+            "SCHEMAVERSION": "Versión de esquema",
+            "CONFIGPARAMETERS": "CONFIGURAR PARÁMETROS",
+            "SDNCONTROLLER": "SDN Controladora",
+            "SDNPORTMAPPING": "SDN La asignación de puertos",
+            "VIMNETWORKNAME": "VIM Nombre de red",
+            "SECURITYGROUPS": "Grupos de seguridad",
+            "AVAILABILITYZONE": "Zona de disponibilidad",
+            "REGIONALNAME": "Nombre de región",
+            "INSECURE": "Insegura",
+            "USEEXISTINGFLAVOURS": "Usa sabores existentes",
+            "USEINTERNALENDPOINT": "Usar punto final interno",
+            "APIVERSION": "Versión API   ",
+            "PROJECTDOMAINID": "Proyecto dominio id",
+            "PROJECTDOMAINNAME": "Proyecto dominio name",
+            "USERDOMAINID": "Usuaria dominio id",
+            "USERDOMAINUSER": "Usuaria dominio nombre",
+            "KEYPAIR": "Par de claves",
+            "DATAPLANEPHYSICALNET": "Plano de datos physical net",
+            "USEFLOATINGIP": "Utilizar flotante ip",
+            "DATAPLANENETVLANRANGE": "Plano de datos net vlan range",
+            "MICROVERSION": "Microversión",
+            "BACKTOVIMACCOUNTS": "Atrás a VimAccounts",
+            "VIMPASSWORD": "VIM Contraseña",
+            "ADDITIONALCONFIG": "Adicional configuración",
+            "ADDITIONALCONFIGPLACEHOLDER": "{'key1': [...], 'key2': {}, 'key3': ''}",
+            "NEWVIMACCOUNT": "Nueva VIM Cuenta",
+            "ORGNAME": "Orgnombre",
+            "VCENTERIP": "Vcenter ip",
+            "VCENTERPORT": "Vcenter Puerto",
+            "ADMINUSERNAME": "Administración nombre de usuario",
+            "VCENTERUSER": "Vcenter usuaria",
+            "ADMINPASSWORD": "Administración contraseña",
+            "VCENTERPASSWORD": "Vcenter contraseña",
+            "NSXMANAGER": "Nsx gerente",
+            "VROPSSITE": "Vrops sitio",
+            "NSXUSER": "Nsx usuaria",
+            "VROPSUSER": "Vrops usuaria",
+            "NSXPASSWORD": "Nsx contraseña",
+            "VROPSPASSWORD": "Vrops contraseña",
+            "VPCCIDRBLOCK": "VPC cidr bloquear",
+            "FLAVORIINFO": "Flavor informacion",
+            "VIM_TYPE": "VIM Tipo",
+            "VIMLOCATION": "VIM Ubicación",
+            "SUBSCRIPTIONID": "ID de suscripción",
+            "RESOURCEGROUP": "Grupo de recursos",
+            "VNETNAME": "Nombre de red virtual",
+            "FLAVORSPATTERN": "Patrón de sabores"
+        },
+        "WIMACCOUNTS": {
+            "CREATEDSUCCESSFULLY": "WIM Creado Exitosamente",
+            "WIMDETAILS": "Detalles de WIM",
+            "NEWWIM": "Nuevo WIM",
+            "SCHEMAVERSION": "Versión de esquema",
+            "RO": "RO",
+            "ROACCOUNT": "Cuenta RO",
+            "USERNAME": "Nombre de usuario de WIM",
+            "PASSWORD": "Contraseña WIM"
+        },
+        "NSINSTANCE": {
+            "NEWNSINSTANCE": "Nueva NS",
+            "CREATEDSUCCESSFULLY": "NS Ejemplo Creado Exitosamente"
+        },
+        "VNFINSTANCE": {
+            "ADDVNFINSTANCE": "Agregar instancia VNF"
+        },
+        "PDUINSTANCE": {
+            "NEWPDUINSTANCE": "Nueva PDU",
+            "PDUTYPE": "Tipo de PDU",
+            "PARAMETERS": "Parámetros de instancias de PDU",
+            "ADDINSTANCEPARAMS": "Agregar parámetros",
+            "CREATEDSUCCESSFULLY": "Instancias de PDU creadas con éxito"
+        },
+        "NETSLICEINSTANCE": {
+            "CREATENETSLICEINSTANCE": "Crear NSI"
+        },
+        "SDNCONTROLLER": {
+            "NEWSDNCONTROLLER": "Nuevo controlador SDN",
+            "REGISTEREDSDNCONTROLLER": "Controladores SDN registrados",
+            "RO": "RO",
+            "DPID": "DPID",
+            "CREATEDSUCCESSFULLY": "SDN registrado con éxito",
+            "DPIDPLACEHOLDER": "xx:xx:xx:xx:xx:xx:xx:xx",
+            "DETAILS": "Detalles del controlador SDN"
+        },
+        "USERS": {
+            "CREATEUSER": "Crear usuario",
+            "NEWUSER": "Nuevo usuario",
+            "USERNAME": "Nombre de usuario",
+            "PASSWORD": "Contraseña",
+            "CONFPASSWORD": "confirmar Contraseña",
+            "EDITUSER": "editar usuario",
+            "NEWPASSWORD": "Nueva contraseña",
+            "DEFAULTPROJECT": "Proyecto predeterminado",
+            "PASSWORDCONFLICT": "La contraseña y la contraseña de confirmación no coinciden",
+            "PASSWORDMATCH": "Contraseña",
+            "CREATEDSUCCESSFULLY": "Usuario Creada Exitosamente",
+            "EDITEDSUCCESSFULLY": "Usuario editado correctamente",
+            "EDITCREDENTIALS": "Cambia la contraseña",
+            "EDITUSERNAME": "Cambie el nombre de usuario",
+            "PROJECTSROLES": "Roles de proyectos",
+            "EDITPROJECTROLEMAPPING": "Editar asignación de roles de proyecto",
+            "ADDMAPPINGS": "Agregar asignaciones",
+            "EDITPROJECTROLEERROR": "Proporcione al menos un mapeo de roles del proyecto para continuar"
+        },
+        "TOPOLOGY": {
+            "SELECTELEMENT": "Seleccionar elemento",
+            "VL": "VL",
+            "VNF": "VNF",
+            "VNFD": "VNFD",
+            "CP": "CP",
+            "NSD": "NSD",
+            "NS": "NS",
+            "VIRTUALLINK": "Enlace virtual",
+            "CONNECTIONPOINT": "Punto de conexión",
+            "INTCONNECTIONPOINT": "Int Punto de conexión",
+            "LINK": "Enlazar",
+            "ADDINGCP": "Seleccione un punto de conexión de {{vnfdname}} para vincular {{vlname}}?",
+            "INFO": "Informacion",
+            "HELP": "Ayuda",
+            "HELPINFO": {
+                "CREATEEDGE": "Crear borde",
+                "CREATEEDGEFIRSTSETENCE": "Seleccione el primer vértice haciendo clic en él usando",
+                "CREATEEDGESECONDSETENCE": "en otro vértice (diferente al seleccionado).",
+                "DELETEEDGEVERTEX": "Eliminar borde/vértice",
+                "DELETEEDGEVERTEXSENTENCE": "Doble clic en borde / vértice.",
+                "SPREADEDGE": "Borde extendido",
+                "SPREADEDGESENTENCE": "Seleccione el vértice haciendo clic en él usando",
+                "EDGEINFO": "Mostrar información de borde",
+                "EDGEINFOSENTENCE": "Seleccione el borde haciendo clic. La información se mostrará en el lado izquierdo."
+            },
+            "VDU": "VDU",
+            "INTVL": "IntVL",
+            "INTCP": "IntCP",
+            "DATAEMPTY": "Por favor cambia algo"
+        },
+        "PROJECT": {
+            "NEWPROJECT": "Nuevo proyecto",
+            "CREATEDSUCCESSFULLY": "Proyecto Creada Exitosamente",
+            "UPDATEDSUCCESSFULLY": "Proyecto Actualizada Exitosamente"
+        },
+        "NSPACKAGE": {
+            "ADDNSPACKAGE": "Componer un nuevo NS",
+            "CREATEDSUCCESSFULLY": "NS Paquetes Creada Exitosamente",
+            "NSCOMPOSE": {
+                "UPDATEDSUCCESSFULLY": "Actualizada Exitosamente",
+                "CONFIRMCONNECTIONPOINT": "Confirme para agregar un punto de conexión",
+                "CANNOTLINKVNF": "No puedes vincular un vnf con un vnf",
+                "CANNOTLINKVL": "No puedes vincular un VL con un VL",
+                "CANNOTLINKVLVNF": "No puedes vincular un VL con un vnf",
+                "CANNOTLINKVNFCP": "No puedes vincular un VNF con un CP",
+                "CANNOTLINKVLCP": "No puedes vincular un VL con un CP",
+                "CANNOTLINKCP": "No puedes vincular un CP con un CP",
+                "ADDNSD": "Enlace virtual se agrega con éxito",
+                "ADDVNFD": "VNFD se agrega con éxito",
+                "ADDNS": "El enlace de conexión se agregó con éxito",
+                "DELETENSD": "Se eliminó con éxito el enlace virtual",
+                "DELETEVNFD": "Eliminado con éxito el VNF",
+                "DELETENS": "Se eliminó correctamente el punto de conexión",
+                "DELETELINK": "Se eliminó el enlace correctamente",
+                "MGMTNETWORK": "Mgmt Network",
+                "VIMNETWORKNAME": "Vim Network Name",
+                "MEMBER-VNF-INDEX": "member-vnf-index",
+                "VNFD-ID-REF": "vnfd-id-ref",
+                "VLD-ID": "vld-id",
+                "VNFD-CP-REF": "vnfd-punto de conexión-ref"
+            },
+            "EDITPACKAGES": {
+                "UPDATEDSUCCESSFULLY": "Descriptor actualizado exitosamente"
+            }
+        },
+        "VNFPACKAGE": {
+            "ADDVNFPACKAGE": "Componer un nuevo VNF",
+            "CREATEDSUCCESSFULLY": "VNF Paquetes Creada Exitosamente",
+            "VNFCOMPOSE": {
+                "UPDATEDSUCCESSFULLY": "Actualizada Exitosamente",
+                "INVALIDSELECTION": "Selección invalida",
+                "YOUCANNOTDELETELINK": "No puedes eliminar el enlace",
+                "CANNOTLINKVDUANDINTCP": "No puedes vincular vdu con int_cp",
+                "CANNOTLINKINTCPANDVDU": "No puedes vincular int_cp con vdu",
+                "CANNOTLINKCPANDVNFVL": "No puedes vincular cp con vnf_vl",
+                "CANNOTLINKVNFVLANDCP": "No puedes vincular vnf_vl con cp",
+                "CANNOTLINKINTCPANDCP": "No puedes vincular intcp con cp",
+                "CANNOTLINKCPANDINTCP": "No puedes vincular cp con int_cp",
+                "CANNOTLINKVDUANDVDU": "No puedes vincular un vdu con un vdu"
+            }
+        },
+        "NETSLICE": {
+            "CREATEDSUCCESSFULLY": "Netslice Creada Exitosamente",
+            "TEMPLATECREATEDSUCCESSFULLY": "Netslice Modelo Created Successfully",
+            "UPDATEDSUCCESSFULLY": "Plantilla actualizada con éxito"
+        },
+        "NETSLICETEMPLATE": {
+            "NETSLICETEMPLATEDETAILS": "Red Rebanadas Modelo Detalles"
+        },
+        "NSTINSTANCEINSTANTIATE": {
+            "NEWINSTANCE": "Nueva instancia",
+            "NSNAME": "Nombre de Ns",
+            "DESCRIPTION": "Descripción",
+            "NSTID": "Nsd Id",
+            "SSHKEY": "SSH Key",
+            "VIMACCOUNT": "Cuenta VIM",
+            "SSHKEYMSG": "Pega tu llave aquí ..."
+        },
+        "NSPRIMITIVE": {
+            "PRIMITIVE": "Primitiva",
+            "PRIMITIVEPARAMETERS": "Primitiva Parámetros",
+            "ADDPRIMITIVEPARAMS": "Añadir Parámetros primitivos",
+            "EXECUTEDSUCCESSFULLY": "Ejecutada NS Configuración primitiva"
+        },
+        "ROLES": {
+            "CREATEROLE": "Crear rol",
+            "ROLE": "Papel",
+            "PERMISSIONS": "Permisos",
+            "YAMLPERMISSIONS": "YAML Permisos",
+            "CREATEDSUCCESSFULLY": "Rol creado con éxito",
+            "UPDATEDSUCCESSFULLY": "Rol actualizado exitosamente",
+            "ROLEJSONERROR": "Los permisos de rol deben proporcionarse de manera clave-valor",
+            "ROLEKEYERROR": "El valor de '{{roleKey}}' en los permisos de un rol debe ser booleano",
+            "EDITROLE": "Editar rol",
+            "PREVIEW": "Avance",
+            "TEXTVIEW": "Vista de texto"
+        },
+        "K8S": {
+            "MENUK8S": "K8s",
+            "MENUK8SCLUSTER": "Clusters K8s",
+            "MENUK8SREPO": "K8s Repos",
+            "REGISTERK8CLUSTER": "Grupos de K8 registrados",
+            "ADDK8CLUSTER": "Agregar clúster K8s",
+            "K8SCLUSTERDETAILS": "Detalles del clúster K8s",
+            "REGISTERK8REPO": "Repositorio K8 registrado",
+            "ADDK8REPO": "Agregar repositorio K8s",
+            "K8SREPODETAILS": "Detalles del repositorio de K8s",
+            "CREATEDSUCCESSFULLY": "K8 creados con éxito",
+            "NEWK8SCLUSTER": "Nuevo clúster K8s",
+            "NAME": "Nombre",
+            "K8SVERSION": "Versión K8s",
+            "VIMACCOUNT": "Cuenta Vim",
+            "DESCRIPTION": "Descripción",
+            "NETS": "Nets",
+            "NETSPLACEHOLDER": "example: {'net1': 'osm-ext'}",
+            "CREDENTIALS": "Cartas credenciales",
+            "NEWK8SREPO": "Nuevo repositorio K8s",
+            "TYPE": "Tipo",
+            "URL": "URL"
+        }
+    },
+    "HTTPERROR": {
+        "401": "Acceso denegado",
+        "400": "Por favor revise la solicitud e intente nuevamente",
+        "404": "El servicio esperado no está disponible. Vuelve a intentarlo más tarde.",
+        "500": "Error del servidor. Vuelve a intentarlo más tarde",
+        "502": "Bad Gateway, por favor intente nuevamente más tarde",
+        "503": "El servicio no está disponible temporalmente. Vuelve a intentarlo más tarde",
+        "504": "Error de tiempo de espera de la puerta de enlace. Vuelva a intentarlo más tarde",
+        "409": "Por favor, inténtelo de nuevo más tarde"
+    },
+    "PAGENOTFOUND": {
+        "OOPS": "¡Uy!",
+        "NOTFOUND": "404 No encontrado",
+        "CONTENT": "La página no se puede encontrar o no está autorizada, puede que ya no sea relevante o se haya cambiado su nombre.",
+        "MEAN": "Mientras tanto, puede volver a",
+        "HOME": "Hogar"
+    },
+    "DOMVALIDATIONS": {
+        "INVALIDURL": "Ingrese una URL válida",
+        "INVALIDIPADDRESS": "Ingrese una dirección IP válida",
+        "INVALIDPORTADDRESS": "Ingrese una dirección de puerto válida",
+        "INVALIDDPID": "Ingrese un DPID válido",
+        "INVALIDJSON": "Ingrese un formato JSON válido",
+        "INVALIDYAML": "Ingrese un formato YAML válido"
+    },
+    "GRAFANA": {
+        "METRICSERROR": "No es una métrica válida"
+    }
+}
\ No newline at end of file
diff --git a/src/assets/i18n/pt.json b/src/assets/i18n/pt.json
new file mode 100644 (file)
index 0000000..3c948ac
--- /dev/null
@@ -0,0 +1,479 @@
+{
+    "OSM": "OSM",
+    "APPVERSION": "Versão da aplicação",
+    "OSMVERSION": "Versão OSM",
+    "OSMSOURCEMANO": "Código aberto MANO",
+    "ADMIN": "Admin",
+    "ENTRIES": "Entradas",
+    "COMPOSE": "Componha um",
+    "CREATE": "Crio",
+    "SELECT": "Selecione",
+    "CANCEL": "Cancelar",
+    "SAVE": "Salve",
+    "COUNT": "contagem",
+    "IMAGE": "Imagem",
+    "IPPROFILEREF": "Ref do perfil IP",
+    "ACTION": "Açao",
+    "ADD": "Adicionar",
+    "EDIT": "Editar",
+    "APPLY": "Aplique",
+    "FORCE": "Força",
+    "DOWNLOAD": "Baixar",
+    "CONTENT": "Conteúdo",
+    "DELETE": "Excluir",
+    "FORCEDELETE": "Forçar exclusão",
+    "RENAME": "Renomear",
+    "INFO": "Info",
+    "NSPACKAGES": "Pacotes NS",
+    "VNFPACKAGES": "Pacotes VNF",
+    "INSTANCES": "Instâncias",
+    "INSTANTIATE": "Instanciar",
+    "NSINSTANCES": "Instâncias NS",
+    "VNFINSTANCES": "Instâncias VNF",
+    "PDUINSTANCES": "Instâncias da PDU",
+    "VIMACCOUNTS": "Contas VIM",
+    "WIMACCOUNTS": "Contas WIM",
+    "SDNCONTROLLER": "Controlador SDN",
+    "NETSLICE": "Netslice",
+    "PROJECT": "Projeto",
+    "DOMAIN": "Domínio",
+    "MODIFIED": "Modificada",
+    "PACKAGES": "Pacotes",
+    "NODATAMSG": "Sem dados disponíveis na tabela",
+    "SHORTNAME": "Nome curto",
+    "IDENTIFIER": "Identificador",
+    "DESCRIPTION": "Descrição",
+    "VENDOR": "Fornecedor",
+    "VERSION": "Versão",
+    "ACTIONS": "Ações",
+    "NAME": "Nome",
+    "USAGESTATE": "UsageState",
+    "MODIFICATIONDATE": "Modificação de data",
+    "CREATEDDATE": "Data de criação",
+    "OPERATIONALSTATUS": "Estado operacional",
+    "OPERATIONALSTATE": "Estado operacional",
+    "CONFIGSTATUS": "Status da configuração",
+    "DETAILEDSTATUS": "Status detalhado",
+    "NSDNAME": "Nome nsd",
+    "NSTNAME": "Nst name",
+    "TYPE": "Tipo",
+    "VNFD": "VNFD",
+    "VNF": "VNF",
+    "MEMBERINDEX": "Índice de membros",
+    "NS": "NS",
+    "CREATEDAT": "Criado em",
+    "CREATED": "Criada",
+    "ALL": "Todos",
+    "ID": "Identidade",
+    "OPERATIONSTATE": "Estado da operação",
+    "STARTTIME": "Hora de início",
+    "STATUSENTEREDTIME": "Horário de entrada do status",
+    "HISTORYOFOPERATIONS": "História das Operações",
+    "UPDATE": "Atualizar",
+    "READONLYMODE": "Modo somente leitura",
+    "CURRENTLY": "Atualmente",
+    "ON": "Em",
+    "OFF": "Fora",
+    "IN": "em",
+    "FILES": "arquivos",
+    "NEW": "Nova",
+    "RECENTLY": "Recentemente",
+    "TOPOLOGY": "Topologia",
+    "PLEASEWAIT": "Por favor, espere",
+    "LOADING": "Carregando",
+    "RESOURCEORCHESTRATOR": "Orquestrador de Recursos",
+    "VIEW": "Visão",
+    "DROP": "Solta",
+    "HERE": "Aqui",
+    "MAPVIEW": "Visão do mapa",
+    "LISTVIEW": "Exibição de lista",
+    "OK": "Está bem",
+    "DELETEDSUCCESSFULLY": "Apagado com sucesso",
+    "SESSIONEXPIRY": "Sessão expirada, faça o login novamente",
+    "DELETECONFIRMPOPUPMESSAGE": "Tem certeza de que deseja excluir",
+    "DELETELOADERMESSAGE": "Aguarde enquanto a exclusão está em andamento",
+    "VALUE": "Valor",
+    "PERFORMACTION": "Executar a ação",
+    "EXECUTE": "Executar",
+    "EXECNSPRIMITIVE": "Exec NS Primitive",
+    "PRIMITIVETYPE": "Tipo primitivo",
+    "VNFPRIMITIVE": "Primitivo de nível VNF",
+    "NSPRIMITIVE": "NS Level Primitive",
+    "DESCRIPTOR": "Descritora",
+    "ERROR": "Alguma coisa deu errado. Por favor tente outra vez",
+    "SHOWGRAPH": "Mostrar gráfico",
+    "UPDATESHOWGRAPH": "Atualizar e mostrar gráfico",
+    "CREATEPACKAGE": "Criar novo pacote",
+    "GZFILETYPEERRROR": "Carregue apenas o arquivo tar.gz e o tamanho não deve exceder 15 MB",
+    "YAMLFILETYPEERRROR": "Carregar apenas arquivo YAML e o tamanho não deve exceder 15 MB",
+    "JSONFILETYPEERRROR": "Carregar apenas arquivo JSON e o tamanho não deve exceder 15 MB",
+    "PUBFILETYPEERRROR": "Carregar apenas arquivo PUB e o tamanho não deve exceder 15 MB",
+    "PACKAGE": "Pacote",
+    "URL": "URL",
+    "DEPLOYED": "Deployed",
+    "ROLES": "Funções",
+    "INSTANCEDETAILS": "Detalhes da Instância",
+    "IPADDRESS": "Endereço de IP",
+    "MGMT": "Mgmt",
+    "NETNAME": "Nome líquido",
+    "USER": "Do utilizador",
+    "PORT": "Porta",
+    "USERNAME": "Nome de usuário",
+    "PASSWORD": "Senha",
+    "NODATAERROR": "Ocorreu um erro ao recuperar as informações",
+    "FREEZE": "Congelar",
+    "UNFREEZE": "Descongelar",
+    "CLONE": "Clone",
+    "CLONECONFIRMPOPUPMESSAGE": "Tem certeza de que deseja clonar",
+    "CLONESUCCESSFULLY": "Pacote clonado com sucesso",
+    "DROPFILES": "Basta arrastar e soltar arquivos aqui ou clique aqui para fazer upload de arquivos",
+    "DROPFILESVALIDATION": "Selecione um arquivo para processar",
+    "METRICS": "Métricas",
+    "NOOFHOURS": "Não de horas",
+    "MANDATORYCHECK": "Os campos obrigatórios estão marcados com um asterisco (*)",
+    "K8VERSION": "Versão K8",
+    "ENTER": "Entrar",
+    "SWITCHPROJECT": "Switch Project",
+    "CURRENTPROJECT": "Projeto atual",
+    "SUBMIT": "Enviar",
+    "REFRESH": "Atualizar",
+    "OPEN": "Aberto",
+    "UPLOADCONFIG": "Upload Config",
+    "FILEUPLOADLABEL": "Ou carregue do arquivo",
+    "CONFIG": "Config",
+    "YAMLCONFIG": "Yaml Config",
+    "CHOOSEFILE": "Escolher arquivo",
+    "INVALIDCONFIG": "Configuração inválida",
+    "PAGE": {
+        "DASHBOARD": {
+            "DASHBOARD": "painel de controle",
+            "RECENTUSERLOG": "Registro recente do usuário",
+            "LOGS": "Logs",
+            "FAILEDINSTANCES": "Instâncias com falha",
+            "NOINSTANCES": "Keine Instanzen verfügbar",
+            "UPTIME": "Tempo de atividade",
+            "RUNNINGINSTANCES": "Instâncias em execução",
+            "NETSLICETEMPLATE": "Modelo de fatia líquida",
+            "NETSLICEINSTANCE": "Instâncias de fatia líquida",
+            "USERS": "Comercial",
+            "PROJECTS": "Projetos",
+            "USERSETTINGS": "Configurações do usuário",
+            "LOGOUT": "Sair"
+        },
+        "LOGIN": {
+            "USERNAME": "Nome de usuário",
+            "PASSWORD": "Senha",
+            "SIGNUP": "Inscrever-se",
+            "ACCOUNTCREATEMESSAGE": "Não possui uma conta?",
+            "LOGIN": "entrar",
+            "PASSWORDVALIDMESSAGE": "Senha requerida",
+            "USERNAMEVALIDMESSAGE": "Nome de usuário é requerido",
+            "SIGNINMSG": "Faça login para iniciar sua sessão",
+            "PASSWORDMINLENGTHVALIDMESSAGE": "A senha deve ter 8 caracteres e conter pelo menos um caractere maiúsculo, minúsculo, numérico e especial",
+            "USERNAMEMINLENGTHVALIDMESSAGE": "O nome de usuário deve ter pelo menos 5 caracteres"
+        },
+        "INSTANCEINSTANTIATE": {
+            "NEWINSTANCE": "Nova Instância",
+            "NSNAME": "Ns Name",
+            "DESCRIPTION": "Descrição",
+            "NSID": "ID Nsd",
+            "SSHKEY": "Chave SSH",
+            "VIMACCOUNT": "Conta VIM",
+            "SSHKEYMSG": "Cole sua chave aqui"
+        },
+        "NSMETRIC": {
+            "INSTANCESMETRIC": "Métrica de Instâncias",
+            "METRICERROR": "Dados não disponíveis em métricas"
+        },
+        "USERSETTINGS": {
+            "LANGUAGE": "Língua"
+        },
+        "VIM": {
+            "CREATEDSUCCESSFULLY": "VIM criado com sucesso",
+            "LOACTIONINFO": "Digite o nome do local e clique no botão Enter para selecionar o local na lista"
+        },
+        "VIMDETAILS": {
+            "NEWVIM": "Novo VIM",
+            "VIMACCOUNTDETAILS": "Detalhes da conta VIM",
+            "NAME": "Nome",
+            "VIMUSERNAME": "Nome de usuário do VIM",
+            "VIMURL": "URL do VIM",
+            "VIMTYPE": "Tipo",
+            "TENANTNAME": "Nome do inquilino",
+            "DESCRIPTION": "Descrição",
+            "SCHEMATYPE": "Tipo de esquema",
+            "SCHEMAVERSION": "Versão do esquema",
+            "CONFIGPARAMETERS": "PARÂMETROS CONFIG",
+            "SDNCONTROLLER": "Controlador SDN",
+            "SDNPORTMAPPING": "Mapeamento de porta SDN",
+            "VIMNETWORKNAME": "Nome da rede VIM",
+            "SECURITYGROUPS": "Grupos de Segurança",
+            "AVAILABILITYZONE": "Zona de disponibilidade",
+            "REGIONALNAME": "Nome da região",
+            "INSECURE": "Insegura",
+            "USEEXISTINGFLAVOURS": "Use sabores existentes",
+            "USEINTERNALENDPOINT": "Usar terminal interno",
+            "APIVERSION": "Versão da API",
+            "PROJECTDOMAINID": "ID do domínio do projeto",
+            "PROJECTDOMAINNAME": "Nome de domínio do projeto",
+            "USERDOMAINID": "ID do domínio do usuário",
+            "USERDOMAINUSER": "Nome de domínio do usuário",
+            "KEYPAIR": "Par de chaves",
+            "DATAPLANEPHYSICALNET": "Rede física do plano de dados",
+            "USEFLOATINGIP": "Use ip flutuante",
+            "DATAPLANENETVLANRANGE": "Dataplane net vlan range",
+            "MICROVERSION": "Microversão",
+            "BACKTOVIMACCOUNTS": "Voltar para VimAccounts",
+            "VIMPASSWORD": "Senha do VIM",
+            "ADDITIONALCONFIG": "Configuração adicional",
+            "ADDITIONALCONFIGPLACEHOLDER": "{'key1':[...],'key2':{},'key3':''}",
+            "NEWVIMACCOUNT": "Nova conta VIM",
+            "ORGNAME": "Orgnome",
+            "VCENTERIP": "Vcenter ip",
+            "VCENTERPORT": "Porta Vcenter",
+            "ADMINUSERNAME": "Nome de usuário do administrador",
+            "VCENTERUSER": "Usuário do Vcenter",
+            "ADMINPASSWORD": "senha do administrador",
+            "VCENTERPASSWORD": "Senha do Vcenter",
+            "NSXMANAGER": "Gerente Nsx",
+            "VROPSSITE": "Site Vrops",
+            "NSXUSER": "Usuário Nsx",
+            "VROPSUSER": "Usuário Vrops",
+            "NSXPASSWORD": "Senha Nsx",
+            "VROPSPASSWORD": "Senha Vrops",
+            "VPCCIDRBLOCK": "Bloco cidr VPC",
+            "FLAVORIINFO": "Informação do sabor",
+            "VIM_TYPE": "Tipo VIM",
+            "VIMLOCATION": "Localização do VIM",
+            "SUBSCRIPTIONID": "ID de Inscrição",
+            "RESOURCEGROUP": "Grupo de Recursos",
+            "VNETNAME": "Nome da VNet",
+            "FLAVORSPATTERN": "Padrão de sabores"
+        },
+        "WIMACCOUNTS": {
+            "CREATEDSUCCESSFULLY": "WIM criado com sucesso",
+            "WIMDETAILS": "Detalhes do WIM",
+            "NEWWIM": "Novo WIM",
+            "SCHEMAVERSION": "Versão do esquema",
+            "RO": "RO",
+            "ROACCOUNT": "Conta RO",
+            "USERNAME": "Nome de usuário WIM",
+            "PASSWORD": "Senha WIM"
+        },
+        "NSINSTANCE": {
+            "NEWNSINSTANCE": "Nova NS",
+            "CREATEDSUCCESSFULLY": "Instância NS criada com êxito"
+        },
+        "VNFINSTANCE": {
+            "ADDVNFINSTANCE": "Adicionar instância VNF"
+        },
+        "PDUINSTANCE": {
+            "NEWPDUINSTANCE": "Nova PDU",
+            "PDUTYPE": "Tipo de PDU",
+            "PARAMETERS": "Parâmetros de instâncias da PDU",
+            "ADDINSTANCEPARAMS": "Adicionar parâmetros",
+            "CREATEDSUCCESSFULLY": "Instâncias da PDU criadas com êxito"
+        },
+        "NETSLICEINSTANCE": {
+            "CREATENETSLICEINSTANCE": "Criar NSI"
+        },
+        "SDNCONTROLLER": {
+            "NEWSDNCONTROLLER": "Novo controlador SDN",
+            "REGISTEREDSDNCONTROLLER": "Controladores SDN registrados",
+            "RO": "RO",
+            "DPID": "DPID",
+            "CREATEDSUCCESSFULLY": "SDN Registrado com Sucesso",
+            "DPIDPLACEHOLDER": "xx:xx:xx:xx:xx:xx:xx:xx",
+            "DETAILS": "Detalhes do Controlador SDN"
+        },
+        "USERS": {
+            "CREATEUSER": "Criar usuário",
+            "NEWUSER": "Novo usuário",
+            "USERNAME": "Nome de Usuário",
+            "PASSWORD": "Senha",
+            "CONFPASSWORD": "Confirme a Senha",
+            "EDITUSER": "Editar usuário",
+            "NEWPASSWORD": "Nova senha",
+            "DEFAULTPROJECT": "Projeto Padrão",
+            "PASSWORDCONFLICT": "Senha e confirmação de senha não correspondem",
+            "PASSWORDMATCH": "Correspondência de senha",
+            "CREATEDSUCCESSFULLY": "Usuário criado com sucesso",
+            "EDITEDSUCCESSFULLY": "Edição do Usuário com Sucesso",
+            "EDITCREDENTIALS": "Mudar senha",
+            "EDITUSERNAME": "Mudar nome de usuário",
+            "PROJECTSROLES": "Funções dos Projetos",
+            "EDITPROJECTROLEMAPPING": "Editar mapeamento de função do projeto",
+            "ADDMAPPINGS": "Adicionar mapeamentos",
+            "EDITPROJECTROLEERROR": "Forneça pelo menos um mapeamento de função do projeto para continuar"
+        },
+        "TOPOLOGY": {
+            "SELECTELEMENT": "Selecionar elemento",
+            "VL": "VL",
+            "VNF": "VNF",
+            "VNFD": "VNFD",
+            "CP": "CP",
+            "NSD": "NSD",
+            "NS": "NS",
+            "VIRTUALLINK": "Link virtual",
+            "CONNECTIONPOINT": "Ponto de conexão",
+            "INTCONNECTIONPOINT": "Ponto de conexão int",
+            "LINK": "Ligação",
+            "ADDINGCP": "Por favor, selecione um ponto de conexão {{vnfdname}} para vincular {{vlname}}?",
+            "INFO": "Info",
+            "HELP": "Socorro",
+            "HELPINFO": {
+                "CREATEEDGE": "Criar aresta",
+                "CREATEEDGEFIRSTSETENCE": "Selecione o primeiro vértice clicando nele usando",
+                "CREATEEDGESECONDSETENCE": "em outro vértice (diferente do selecionado).",
+                "DELETEEDGEVERTEX": "Excluir aresta / vértice",
+                "DELETEEDGEVERTEXSENTENCE": "Clicar duas vezes na aresta / vértice.",
+                "SPREADEDGE": "Espalhe a borda",
+                "SPREADEDGESENTENCE": "Selecione o vértice clicando nele usando",
+                "EDGEINFO": "Mostrar informações da aresta",
+                "EDGEINFOSENTENCE": "Selecione a aresta clicando. A informação será mostrada no lado esquerdo."
+            },
+            "VDU": "VDU",
+            "INTVL": "IntVL",
+            "INTCP": "IntCP",
+            "DATAEMPTY": "Por favor mude algo"
+        },
+        "PROJECT": {
+            "NEWPROJECT": "Novo projeto",
+            "CREATEDSUCCESSFULLY": "Projeto criado com sucesso",
+            "UPDATEDSUCCESSFULLY": "Projeto atualizado com sucesso"
+        },
+        "NSPACKAGE": {
+            "ADDNSPACKAGE": "Componha um novo NS",
+            "CREATEDSUCCESSFULLY": "Pacote NS criado com sucesso",
+            "NSCOMPOSE": {
+                "UPDATEDSUCCESSFULLY": "Atualizado com sucesso",
+                "CONFIRMCONNECTIONPOINT": "Confirme para adicionar o ponto de conexão",
+                "CANNOTLINKVNF": "Você não pode vincular um vnf a um vnf",
+                "CANNOTLINKVL": "Você não pode vincular uma VL a uma VL",
+                "CANNOTLINKVLVNF": "Você não pode vincular um VL a um vnf",
+                "CANNOTLINKVNFCP": "Você não pode vincular um VNF a um CP",
+                "CANNOTLINKVLCP": "Você não pode vincular uma VL a um CP",
+                "CANNOTLINKCP": "Você não pode vincular um CP a um CP",
+                "ADDNSD": "Link virtual adicionado com sucesso",
+                "ADDVNFD": "VNFD é adicionado com sucesso",
+                "ADDNS": "Link de conexão adicionado com sucesso",
+                "DELETENSD": "O link virtual foi excluído com sucesso",
+                "DELETEVNFD": "O VNF foi excluído com sucesso",
+                "DELETENS": "Excluído com êxito o ponto de conexão",
+                "DELETELINK": "O link foi excluído com sucesso",
+                "MGMTNETWORK": "Mgmt Network",
+                "VIMNETWORKNAME": "Vim Network Name",
+                "MEMBER-VNF-INDEX": "member-vnf-index",
+                "VNFD-ID-REF": "vnfd-id-ref",
+                "VLD-ID": "vld-id",
+                "VNFD-CP-REF": "vnfd-ponto de conexão-ref"
+            },
+            "EDITPACKAGES": {
+                "UPDATEDSUCCESSFULLY": "Atualizado com sucesso"
+            }
+        },
+        "VNFPACKAGE": {
+            "ADDVNFPACKAGE": "Componha um novo VNF",
+            "CREATEDSUCCESSFULLY": "Pacote VNF criado com sucesso",
+            "VNFCOMPOSE": {
+                "UPDATEDSUCCESSFULLY": "Atualizado com sucesso",
+                "INVALIDSELECTION": "Seleção inválida",
+                "YOUCANNOTDELETELINK": "Você não pode excluir o link",
+                "CANNOTLINKVDUANDINTCP": "Você não pode vincular o vdu ao int_cp",
+                "CANNOTLINKINTCPANDVDU": "Você não pode vincular int_cp ao vdu",
+                "CANNOTLINKCPANDVNFVL": "Você não pode vincular o cp ao vnf_vl",
+                "CANNOTLINKVNFVLANDCP": "Você não pode vincular vnf_vl ao cp",
+                "CANNOTLINKINTCPANDCP": "Você não pode vincular o intcp ao cp",
+                "CANNOTLINKCPANDINTCP": "Você não pode vincular o cp ao int_cp",
+                "CANNOTLINKVDUANDVDU": "Você não pode vincular um vdu a um vdu"
+            }
+        },
+        "NETSLICE": {
+            "CREATEDSUCCESSFULLY": "Netslice criado com sucesso",
+            "TEMPLATECREATEDSUCCESSFULLY": "Modelo Netslice criado com sucesso",
+            "UPDATEDSUCCESSFULLY": "Modelo atualizado com sucesso"
+        },
+        "NETSLICETEMPLATE": {
+            "NETSLICETEMPLATEDETAILS": "Detalhes do modelo de fatias de rede"
+        },
+        "NSTINSTANCEINSTANTIATE": {
+            "NEWINSTANCE": "Nova Instância",
+            "NSNAME": "Ns Name",
+            "DESCRIPTION": "Descrição",
+            "NSTID": "Nst Id",
+            "SSHKEY": "Chave SSH",
+            "VIMACCOUNT": "Conta VIM",
+            "SSHKEYMSG": "Cole sua chave aqui ..."
+        },
+        "NSPRIMITIVE": {
+            "PRIMITIVE": "Primitiva",
+            "PRIMITIVEPARAMETERS": "Parâmetros primitivos",
+            "ADDPRIMITIVEPARAMS": "Adicionar Parâmetros Primitivos",
+            "EXECUTEDSUCCESSFULLY": "Configuração primitiva do NS executada"
+        },
+        "ROLES": {
+            "CREATEROLE": "Criar função",
+            "ROLE": "Função",
+            "PERMISSIONS": "Permissões",
+            "YAMLPERMISSIONS": "YAML Permissões",
+            "CREATEDSUCCESSFULLY": "Função criada com sucesso",
+            "UPDATEDSUCCESSFULLY": "Função atualizada com sucesso",
+            "ROLEJSONERROR": "As permissões de função devem ser fornecidas de maneira com valor-chave",
+            "ROLEKEYERROR": "O valor de '{{roleKey}}' nas permissões de uma função deve ser booleano",
+            "EDITROLE": "Editar função",
+            "PREVIEW": "Pré-visualização",
+            "TEXTVIEW": "Visualização de texto"
+        },
+        "K8S": {
+            "MENUK8S": "K8s",
+            "MENUK8SCLUSTER": "Clusters do K8s",
+            "MENUK8SREPO": "Repos do K8s",
+            "REGISTERK8CLUSTER": "Clusters K8s registrados",
+            "ADDK8CLUSTER": "Adicionar cluster do K8s",
+            "K8SCLUSTERDETAILS": "Detalhes do cluster K8s",
+            "REGISTERK8REPO": "Repositório registrado do K8s",
+            "ADDK8REPO": "Adicionar repositório K8s",
+            "K8SREPODETAILS": "Detalhes do Repositório do K8s",
+            "CREATEDSUCCESSFULLY": "K8s criado com sucesso",
+            "NEWK8SCLUSTER": "Novo Cluster K8s",
+            "NAME": "Nome",
+            "K8SVERSION": "Versão do K8s",
+            "VIMACCOUNT": "Conta Vim",
+            "DESCRIPTION": "Descrição",
+            "NETS": "Nets",
+            "NETSPLACEHOLDER": "example: {'net1': 'osm-ext'}",
+            "CREDENTIALS": "Credenciais",
+            "NEWK8SREPO": "Novo Repositório do K8s",
+            "TYPE": "Tipo",
+            "URL": "URL"
+        }
+    },
+    "HTTPERROR": {
+        "401": "Acesso negado",
+        "400": "Verifique a solicitação e tente novamente",
+        "404": "Serviço esperado não disponível, tente novamente mais tarde",
+        "500": "Erro no servidor, tente novamente mais tarde",
+        "502": "Gateway incorreto. Tente novamente mais tarde",
+        "503": "Serviço temporariamente indisponível. Tente novamente mais tarde",
+        "504": "Erro de tempo limite do gateway. Tente novamente mais tarde",
+        "409": "Por favor, tente novamente mais tarde"
+    },
+    "PAGENOTFOUND": {
+        "OOPS": "Opa!",
+        "NOTFOUND": "404 não encontrado",
+        "CONTENT": "A página não pode ser encontrada ou não autorizada, pode não ser mais relevante ou seu nome foi alterado",
+        "MEAN": "Enquanto isso, você pode voltar para",
+        "HOME": "Casa"
+    },
+    "DOMVALIDATIONS": {
+        "INVALIDURL": "Digite um URL válido",
+        "INVALIDIPADDRESS": "Digite um endereço IP válido",
+        "INVALIDPORTADDRESS": "Digite um endereço PORT válido",
+        "INVALIDDPID": "Digite um DPID válido",
+        "INVALIDJSON": "Digite um formato JSON válido",
+        "INVALIDYAML": "Digite um formato YAML válido"
+    },
+    "GRAFANA": {
+        "METRICSERROR": "Métricas não válidas"
+    }
+}
\ No newline at end of file
diff --git a/src/assets/images/CP-VNF.svg b/src/assets/images/CP-VNF.svg
new file mode 100644 (file)
index 0000000..26163da
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg version="1.1" id="IconsRepoEditor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="-106.14 -106.14 654.53 654.53" style="enable-background:new 0 0 442.246 442.246;" xml:space="preserve" fill="#ffffff" stroke="#ffffff" stroke-width="0">
+
+<g id="IconsRepo_bgCarrier">
+
+<rect x="-106.14" y="-106.14" width="654.53" height="654.53" rx="327.265" fill="#c6b63f" stroke-width="0"/>
+
+</g> <path d="M409.657,32.474c-43.146-43.146-113.832-43.146-156.978,0l-84.763,84.762c29.07-8.262,60.589-6.12,88.129,6.732 l44.063-44.064c17.136-17.136,44.982-17.136,62.118,0c17.136,17.136,17.136,44.982,0,62.118l-55.386,55.386l-36.414,36.414 c-17.136,17.136-44.982,17.136-62.119,0l-47.43,47.43c11.016,11.017,23.868,19.278,37.332,24.48 c36.415,14.382,78.643,8.874,110.467-16.219c3.06-2.447,6.426-5.201,9.18-8.262l57.222-57.222l34.578-34.578 C453.109,146.306,453.109,75.926,409.657,32.474z"/> <path d="M184.135,320.114l-42.228,42.228c-17.136,17.137-44.982,17.137-62.118,0c-17.136-17.136-17.136-44.981,0-62.118 l91.8-91.799c17.136-17.136,44.982-17.136,62.119,0l47.43-47.43c-11.016-11.016-23.868-19.278-37.332-24.48 c-38.25-15.3-83.232-8.262-115.362,20.502c-1.53,1.224-3.06,2.754-4.284,3.978l-91.8,91.799 c-43.146,43.146-43.146,113.832,0,156.979c43.146,43.146,113.832,43.146,156.978,0l82.927-83.845 C230.035,335.719,220.243,334.496,184.135,320.114z"/> </svg>
\ No newline at end of file
diff --git a/src/assets/images/CP.svg b/src/assets/images/CP.svg
new file mode 100644 (file)
index 0000000..7ed1b03
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg version="1.1" id="IconsRepoEditor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="-154.79 -154.79 751.83 751.83" style="enable-background:new 0 0 442.246 442.246;" xml:space="preserve" fill="#ffffff" stroke="#ffffff" stroke-width="0" transform="rotate(0)">
+
+<g id="IconsRepo_bgCarrier">
+
+<rect x="-154.79" y="-154.79" width="751.83" height="751.83" rx="375.915" fill="#3c8dbc" stroke-width="0"/>
+
+</g> <path d="M409.657,32.474c-43.146-43.146-113.832-43.146-156.978,0l-84.763,84.762c29.07-8.262,60.589-6.12,88.129,6.732 l44.063-44.064c17.136-17.136,44.982-17.136,62.118,0c17.136,17.136,17.136,44.982,0,62.118l-55.386,55.386l-36.414,36.414 c-17.136,17.136-44.982,17.136-62.119,0l-47.43,47.43c11.016,11.017,23.868,19.278,37.332,24.48 c36.415,14.382,78.643,8.874,110.467-16.219c3.06-2.447,6.426-5.201,9.18-8.262l57.222-57.222l34.578-34.578 C453.109,146.306,453.109,75.926,409.657,32.474z"/> <path d="M184.135,320.114l-42.228,42.228c-17.136,17.137-44.982,17.137-62.118,0c-17.136-17.136-17.136-44.981,0-62.118 l91.8-91.799c17.136-17.136,44.982-17.136,62.119,0l47.43-47.43c-11.016-11.016-23.868-19.278-37.332-24.48 c-38.25-15.3-83.232-8.262-115.362,20.502c-1.53,1.224-3.06,2.754-4.284,3.978l-91.8,91.799 c-43.146,43.146-43.146,113.832,0,156.979c43.146,43.146,113.832,43.146,156.978,0l82.927-83.845 C230.035,335.719,220.243,334.496,184.135,320.114z"/> </svg>
\ No newline at end of file
diff --git a/src/assets/images/INTCP.svg b/src/assets/images/INTCP.svg
new file mode 100644 (file)
index 0000000..773134a
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg version="1.1" id="IconsRepoEditor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-72.81 -72.81 448.99 448.99" style="enable-background:new 0 0 303.374 303.374;" xml:space="preserve" width="64px" height="64px" fill="#ffffff" stroke="#ffffff" stroke-width="0">
+
+<g id="IconsRepo_bgCarrier">
+
+<rect x="-72.81" y="-72.81" width="448.99" height="448.99" rx="224.495" fill="#605ca8" stroke-width="0"/>
+
+</g> <path d="M268.291,177.313c-4.144,0-8.12,0.727-11.814,2.052l-17.319-27.524c10.331-10.171,16.751-24.302,16.751-39.91 c0-30.899-25.138-56.037-56.037-56.037s-56.037,25.138-56.037,56.037c0,12.226,3.947,23.54,10.617,32.762l-33.742,33.954 c-4.438-2.404-9.515-3.771-14.907-3.771c-5.323,0-10.339,1.336-14.736,3.684l-19.721-20.688c5.93-7.037,9.514-16.113,9.514-26.014 c0-22.293-18.137-40.43-40.43-40.43S0,109.565,0,131.858s18.136,40.43,40.429,40.43c5.854,0,11.416-1.261,16.444-3.509 l21.387,22.436c-2.456,4.474-3.856,9.606-3.856,15.06c0,17.313,14.085,31.398,31.398,31.398s31.398-14.085,31.398-31.398 c0-5.388-1.365-10.462-3.766-14.897l33.756-33.969c9.207,6.635,20.491,10.559,32.68,10.559c8.815,0,17.157-2.052,24.584-5.694 l17.197,27.329c-5.258,6.136-8.446,14.097-8.446,22.793c0,19.345,15.739,35.084,35.084,35.084s35.083-15.739,35.083-35.084 S287.636,177.313,268.291,177.313z M161.834,111.931c0-20.974,17.063-38.037,38.037-38.037s38.037,17.063,38.037,38.037 s-17.063,38.037-38.037,38.037S161.834,132.904,161.834,111.931z M105.802,219.673c-7.388,0-13.398-6.011-13.398-13.398 s6.011-13.398,13.398-13.398s13.398,6.011,13.398,13.398S113.19,219.673,105.802,219.673z M18,131.858 c0-12.368,10.062-22.43,22.429-22.43s22.43,10.062,22.43,22.43s-10.062,22.43-22.43,22.43S18,144.226,18,131.858z M268.291,229.48 c-9.42,0-17.084-7.664-17.084-17.084s7.664-17.084,17.084-17.084s17.083,7.664,17.083,17.084S277.71,229.48,268.291,229.48z"/> </svg>
\ No newline at end of file
diff --git a/src/assets/images/INTVL.svg b/src/assets/images/INTVL.svg
new file mode 100644 (file)
index 0000000..33fcce3
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg version="1.1" id="IconsRepoEditor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-153.6 -153.6 819.20 819.20" style="enable-background:new 0 0 512 512;" xml:space="preserve" width="64px" height="64px" fill="#ffffff" stroke="#ffffff" stroke-width="0">
+
+<g id="IconsRepo_bgCarrier">
+
+<rect x="-153.6" y="-153.6" width="819.20" height="819.20" rx="409.6" fill="#f8a800" stroke-width="0"/>
+
+</g> <path d="M362.665,170.667V192c0,11.776,9.557,21.333,21.333,21.333s21.333-9.557,21.333-21.333v-21.333 c0-11.776-9.557-21.333-21.333-21.333S362.665,158.891,362.665,170.667z"/> <path d="M341.331,128h21.333c11.776,0,21.333-9.557,21.333-21.333s-9.557-21.333-21.333-21.333h-21.333 c-11.776,0-21.333,9.557-21.333,21.333S329.555,128,341.331,128z"/> <path d="M149.331,341.333V320c0-11.776-9.557-21.333-21.333-21.333s-21.333,9.557-21.333,21.333v21.333 c0,11.776,9.557,21.333,21.333,21.333S149.331,353.109,149.331,341.333z"/> <path d="M170.665,384h-21.333c-11.776,0-21.333,9.557-21.333,21.333s9.557,21.333,21.333,21.333h21.333 c11.776,0,21.333-9.557,21.333-21.333S182.441,384,170.665,384z"/> <path d="M469.397,298.667h-64.066v-21.333c0-11.776-9.557-21.333-21.333-21.333s-21.333,9.557-21.333,21.333v21.333h-64.062 c-23.488,0-42.603,19.115-42.603,42.603V384h-0.002c-11.776,0-21.333,9.557-21.333,21.333s9.557,21.333,21.333,21.333H256v42.731 C256,492.885,275.115,512,298.603,512h170.795C492.885,512,512,492.885,512,469.397V341.269 C512,317.781,492.885,298.667,469.397,298.667z M298.603,320v21.333h-0.021L298.603,320z M298.667,469.397l-0.011-63.895 c0-0.057,0.009-0.112,0.009-0.169c0-0.057-0.008-0.112-0.009-0.17l-0.011-63.83l170.688-0.064l0.064,128.064L298.667,469.397z"/> <path d="M256,170.731V128c11.775-0.001,21.331-9.558,21.331-21.333S267.775,85.335,256,85.333V42.603 C256,19.115,236.885,0,213.397,0H42.603C19.115,0,0,19.115,0,42.603v128.128c0,23.488,19.115,42.603,42.603,42.603h64.062v21.333 c0,11.776,9.557,21.333,21.333,21.333s21.333-9.557,21.333-21.333v-21.333h64.066C236.885,213.333,256,194.219,256,170.731z M42.603,42.667h-0.021l0.021-21.333V42.667z M42.667,170.731L42.645,42.667l170.688-0.064l0.032,63.395 c-0.007,0.224-0.034,0.443-0.034,0.669c0,0.23,0.027,0.454,0.034,0.682l0.032,63.318L42.667,170.731z"/> </svg>
\ No newline at end of file
diff --git a/src/assets/images/TICK.svg b/src/assets/images/TICK.svg
new file mode 100644 (file)
index 0000000..4675aad
--- /dev/null
@@ -0,0 +1,29 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg width="18px" height="13px" viewBox="0 0 18 13" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Ecommerce" transform="translate(-844.000000, -3389.000000)" fill="#FFFFFF">
+            <g id="Product-Card-#1" transform="translate(150.000000, 2942.000000)">
+                <g id="Color" transform="translate(683.000000, 399.000000)">
+                    <path d="M28.8443688,48.9224987 L28.095269,48.1585481 C27.8879809,47.9471506 27.5523969,47.9471506 27.3451088,48.1585481 L17.6752,58.0207009 C17.4673818,58.2320984 17.1317978,58.2320984 16.9255701,58.0207009 L12.6546937,53.6656962 C12.4474056,53.4542987 12.1118216,53.4542987 11.9055938,53.6656962 L11.1554337,54.4301874 C10.9481456,54.6415849 10.9481456,54.9838218 11.1554337,55.1946786 L16.5369712,60.6834443 C16.950487,61.105158 17.6211249,61.1056986 18.0351709,60.6839849 L28.8438387,49.6875305 C29.0516569,49.4766737 29.052187,49.1338962 28.8443688,48.9224987" id="Icon"></path>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/src/assets/images/VDU.svg b/src/assets/images/VDU.svg
new file mode 100644 (file)
index 0000000..7dc6540
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg version="1.1" id="IconsRepoEditor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="-45.25 -45.25 279.05 279.05" style="enable-background:new 0 0 188.547 188.547;" xml:space="preserve" fill="#ffffff" stroke="#ffffff" stroke-width="0">
+
+<g id="IconsRepo_bgCarrier">
+
+<rect x="-45.25" y="-45.25" width="279.05" height="279.05" rx="139.525" fill="#cf1c24" stroke-width="0"/>
+
+</g> <path d="M94.589,145.478v13.019h46.765l6.235,6.235v6.235H29.118v-6.235l6.235-6.235h46.765v-13.025H15.281 C6.884,145.471,0,138.584,0,130.188V32.861c0-8.397,6.877-15.281,15.281-15.281h146.143c8.415,0,15.284,6.875,15.284,15.281V64.05 c-1.925-2.125-3.964-4.125-6.235-5.849v-25.34c0-4.987-4.056-9.045-9.049-9.045H15.281c-4.993,0-9.045,4.058-9.045,9.045v78.626 c0,4.993,4.052,9.049,9.045,9.049h90.184c8.476,12.124,22.426,19.57,37.405,19.57c2.49,0,4.957-0.268,7.398-0.676l3.508,6.053 H94.589V145.478z M176.951,74.77c10.863,18.816,4.396,42.977-14.432,53.822c-18.815,10.863-42.965,4.415-53.828-14.425 c-10.859-18.804-4.396-42.953,14.42-53.813C141.919,49.491,166.082,55.951,176.951,74.77z M171.3,78.043 c-9.073-15.707-29.222-21.099-44.926-12.054c-15.704,9.073-21.111,29.216-12.026,44.92c9.066,15.704,29.21,21.136,44.907,12.062 C174.965,113.887,180.355,93.744,171.3,78.043z M172.42,126.162l-16.94,9.792l13.056,22.566l16.94-9.792L172.42,126.162z M187.229,151.834l-16.952,9.779c2.716,4.689,8.695,6.284,13.378,3.593S189.939,156.523,187.229,151.834z M108.058,45.64H26v6.235 h82.058V45.64z M86.795,60.366H26v6.235h60.794V60.366z M86.795,75.099H26v6.235h60.794V75.099z M26,96.063h60.794v-6.235H26 V96.063z"/> </svg>
\ No newline at end of file
diff --git a/src/assets/images/VL.svg b/src/assets/images/VL.svg
new file mode 100644 (file)
index 0000000..6361c01
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg version="1.1" id="IconsRepoEditor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-68.96 -68.96 482.71 482.71" style="enable-background:new 0 0 344.789 344.789;" xml:space="preserve" width="64px" height="64px" fill="#ffffff" stroke="#ffffff" stroke-width="0">
+
+<g id="IconsRepo_bgCarrier">
+
+<rect x="-68.96" y="-68.96" width="482.71" height="482.71" rx="241.355" fill="#e4397c" stroke-width="0"/>
+
+</g> <path d="M259.395,64.283h-40c-4.142,0-7.5,3.357-7.5,7.5v38c0,4.143,3.358,7.5,7.5,7.5h8.5v32.745l-44,20.653V55.303h17.777 c2.82,0,5.402-1.582,6.683-4.095c1.28-2.513,1.043-5.531-0.615-7.813L178.462,3.092C177.051,1.149,174.795,0,172.395,0 c-2.401,0-4.657,1.149-6.068,3.092l-29.277,40.303c-1.658,2.282-1.895,5.301-0.615,7.813c1.281,2.513,3.862,4.095,6.683,4.095 h17.777v138.674l-44-20.653v-38.569c9.435-4.363,16-13.912,16-24.971c0-15.163-12.336-27.5-27.5-27.5 c-15.164,0-27.5,12.337-27.5,27.5c0,11.059,6.565,20.607,16,24.971v45.875c0,4.459,2.577,8.516,6.614,10.41l60.386,28.345v45.032 c-17.032,4.986-29.512,20.738-29.512,39.361c0,22.614,18.398,41.012,41.012,41.012c22.615,0,41.014-18.397,41.014-41.012 c0-18.623-12.48-34.376-29.514-39.361v-68.327l60.386-28.345c4.037-1.895,6.614-5.951,6.614-10.41v-40.051h8.5 c4.142,0,7.5-3.357,7.5-7.5v-38C266.895,67.641,263.537,64.283,259.395,64.283z"/> </svg>
\ No newline at end of file
diff --git a/src/assets/images/VNFD.svg b/src/assets/images/VNFD.svg
new file mode 100644 (file)
index 0000000..86b7fc8
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg version="1.1" id="IconsRepoEditor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-76.05 -76.05 468.99 468.99" style="enable-background:new 0 0 316.89 316.89;" xml:space="preserve" width="64px" height="64px" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="0">
+
+<g id="IconsRepo_bgCarrier">
+
+<rect x="-76.05" y="-76.05" width="468.99" height="468.99" rx="234.495" fill="#605ca8" stroke-width="0"/>
+
+</g> <path d="M182.47,212.195c0-0.754,0.036-1.5,0.057-2.25H38.5c-21.229,0-38.5,17.271-38.5,38.5s17.271,38.5,38.5,38.5h199.493 C205.905,277.24,182.47,247.408,182.47,212.195z M81.5,258.445h-35c-5.514,0-10-4.486-10-10c0-5.514,4.486-10,10-10h35 c5.514,0,10,4.486,10,10C91.5,253.959,87.014,258.445,81.5,258.445z"/> <path d="M38.5,196.945h145.476c7.114-35.78,38.743-62.837,76.581-62.837c9.54,0,18.682,1.727,27.139,4.872 c-6.697-11.378-19.066-19.035-33.196-19.035h-216c-21.229,0-38.5,17.271-38.5,38.5S17.271,196.945,38.5,196.945z M46.5,148.445h35 c5.514,0,10,4.486,10,10c0,5.514-4.486,10-10,10h-35c-5.514,0-10-4.486-10-10C36.5,152.931,40.986,148.445,46.5,148.445z"/> <path d="M38.5,106.945h216c21.228,0,38.5-17.271,38.5-38.5s-17.272-38.5-38.5-38.5h-216c-21.229,0-38.5,17.271-38.5,38.5 S17.271,106.945,38.5,106.945z M237.5,55.695c7.03,0,12.75,5.72,12.75,12.75s-5.72,12.75-12.75,12.75 c-7.03,0-12.75-5.72-12.75-12.75S230.47,55.695,237.5,55.695z M46.5,58.445h35c5.514,0,10,4.486,10,10s-4.486,10-10,10h-35 c-5.514,0-10-4.486-10-10S40.986,58.445,46.5,58.445z"/> <path d="M260.557,155.862c-31.112,0-56.333,25.221-56.333,56.333s25.221,56.333,56.333,56.333s56.332-25.221,56.332-56.333 S291.669,155.862,260.557,155.862z M290.653,200.261l-35.654,35.653c-0.754,0.755-1.759,1.172-2.828,1.172 c-1.069,0-2.074-0.416-2.829-1.172l-17.88-17.88c-0.756-0.755-1.172-1.76-1.172-2.828c0-1.068,0.416-2.073,1.172-2.829l3.535-3.535 c0.754-0.755,1.759-1.172,2.828-1.172c1.068,0,2.073,0.416,2.828,1.171l11.518,11.517l29.291-29.289 c0.754-0.755,1.759-1.172,2.828-1.172c1.069,0,2.074,0.417,2.829,1.172l3.535,3.535c0.755,0.754,1.172,1.759,1.172,2.828 C291.825,198.501,291.409,199.506,290.653,200.261z"/> </svg>
\ No newline at end of file
diff --git a/src/assets/images/login_background.jpg b/src/assets/images/login_background.jpg
new file mode 100644 (file)
index 0000000..dc1411d
Binary files /dev/null and b/src/assets/images/login_background.jpg differ
diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png
new file mode 100644 (file)
index 0000000..7de447c
Binary files /dev/null and b/src/assets/images/logo.png differ
diff --git a/src/assets/images/map-icon.png b/src/assets/images/map-icon.png
new file mode 100644 (file)
index 0000000..e2e9f75
Binary files /dev/null and b/src/assets/images/map-icon.png differ
diff --git a/src/assets/images/page-not-found.jpg b/src/assets/images/page-not-found.jpg
new file mode 100644 (file)
index 0000000..794c0fc
Binary files /dev/null and b/src/assets/images/page-not-found.jpg differ
diff --git a/src/assets/js/tar.js b/src/assets/js/tar.js
new file mode 100644 (file)
index 0000000..058d1ee
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+var Tar =
+/******/ (function(modules) { // webpackBootstrap
+/******/       // The module cache
+/******/       var installedModules = {};
+/******/
+/******/       // The require function
+/******/       function __webpack_require__(moduleId) {
+/******/
+/******/               // Check if module is in cache
+/******/               if(installedModules[moduleId]) {
+/******/                       return installedModules[moduleId].exports;
+/******/               }
+/******/               // Create a new module (and put it into the cache)
+/******/               var module = installedModules[moduleId] = {
+/******/                       i: moduleId,
+/******/                       l: false,
+/******/                       exports: {}
+/******/               };
+/******/
+/******/               // Execute the module function
+/******/               modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/               // Flag the module as loaded
+/******/               module.l = true;
+/******/
+/******/               // Return the exports of the module
+/******/               return module.exports;
+/******/       }
+/******/
+/******/
+/******/       // expose the modules object (__webpack_modules__)
+/******/       __webpack_require__.m = modules;
+/******/
+/******/       // expose the module cache
+/******/       __webpack_require__.c = installedModules;
+/******/
+/******/       // identity function for calling harmony imports with the correct context
+/******/       __webpack_require__.i = function(value) { return value; };
+/******/
+/******/       // define getter function for harmony exports
+/******/       __webpack_require__.d = function(exports, name, getter) {
+/******/               if(!__webpack_require__.o(exports, name)) {
+/******/                       Object.defineProperty(exports, name, {
+/******/                               configurable: false,
+/******/                               enumerable: true,
+/******/                               get: getter
+/******/                       });
+/******/               }
+/******/       };
+/******/
+/******/       // getDefaultExport function for compatibility with non-harmony modules
+/******/       __webpack_require__.n = function(module) {
+/******/               var getter = module && module.__esModule ?
+/******/                       function getDefault() { return module['default']; } :
+/******/                       function getModuleExports() { return module; };
+/******/               __webpack_require__.d(getter, 'a', getter);
+/******/               return getter;
+/******/       };
+/******/
+/******/       // Object.prototype.hasOwnProperty.call
+/******/       __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/       // __webpack_public_path__
+/******/       __webpack_require__.p = "";
+/******/
+/******/       // Load entry module and return exports
+/******/       return __webpack_require__(__webpack_require__.s = 2);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports) {
+
+/*
+ * tar-js
+ * MIT (c) 2011 T. Jameson Little
+ */
+
+(function () {
+       "use strict";
+
+       var lookup = [
+                       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+                       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+                       'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+                       'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+                       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+                       'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+                       'w', 'x', 'y', 'z', '0', '1', '2', '3',
+                       '4', '5', '6', '7', '8', '9', '+', '/'
+               ];
+       function clean(length) {
+               var i, buffer = new Uint8Array(length);
+               for (i = 0; i < length; i += 1) {
+                       buffer[i] = 0;
+               }
+               return buffer;
+       }
+
+       function extend(orig, length, addLength, multipleOf) {
+               var newSize = length + addLength,
+                       buffer = clean((parseInt(newSize / multipleOf) + 1) * multipleOf);
+
+               buffer.set(orig);
+
+               return buffer;
+       }
+
+       function pad(num, bytes, base) {
+               num = num.toString(base || 8);
+               return "000000000000".substr(num.length + 12 - bytes) + num;
+       }       
+       
+       function stringToUint8 (input, out, offset) {
+               var i, length;
+
+               out = out || clean(input.length);
+
+               offset = offset || 0;
+               for (i = 0, length = input.length; i < length; i += 1) {
+                       out[offset] = input.charCodeAt(i);
+                       offset += 1;
+               }
+
+               return out;
+       }
+
+       function uint8ToBase64(uint8) {
+               var i,
+                       extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
+                       output = "",
+                       temp, length;
+
+               function tripletToBase64 (num) {
+                       return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
+               };
+
+               // go through the array every three bytes, we'll deal with trailing stuff later
+               for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
+                       temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
+                       output += tripletToBase64(temp);
+               }
+
+               // this prevents an ERR_INVALID_URL in Chrome (Firefox okay)
+               switch (output.length % 4) {
+                       case 1:
+                               output += '=';
+                               break;
+                       case 2:
+                               output += '==';
+                               break;
+                       default:
+                               break;
+               }
+
+               return output;
+       }
+
+       module.exports.clean = clean;
+       module.exports.pad = pad;
+       module.exports.extend = extend;
+       module.exports.stringToUint8 = stringToUint8;
+       module.exports.uint8ToBase64 = uint8ToBase64;
+}());
+
+
+/***/ }),
+/* 1 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/*
+ * tar-js
+ * MIT (c) 2011 T. Jameson Little
+ */
+
+(function () {
+       "use strict";
+       
+/*
+struct posix_header {             // byte offset
+       char name[100];               //   0
+       char mode[8];                 // 100
+       char uid[8];                  // 108
+       char gid[8];                  // 116
+       char size[12];                // 124
+       char mtime[12];               // 136
+       char chksum[8];               // 148
+       char typeflag;                // 156
+       char linkname[100];           // 157
+       char magic[6];                // 257
+       char version[2];              // 263
+       char uname[32];               // 265
+       char gname[32];               // 297
+       char devmajor[8];             // 329
+       char devminor[8];             // 337
+       char prefix[155];             // 345
+                                  // 500
+};
+*/
+
+       var utils = __webpack_require__(0),
+               headerFormat;
+       
+       headerFormat = [
+               {
+                       'field': 'fileName',
+                       'length': 100
+               },
+               {
+                       'field': 'fileMode',
+                       'length': 8
+               },
+               {
+                       'field': 'uid',
+                       'length': 8
+               },
+               {
+                       'field': 'gid',
+                       'length': 8
+               },
+               {
+                       'field': 'fileSize',
+                       'length': 12
+               },
+               {
+                       'field': 'mtime',
+                       'length': 12
+               },
+               {
+                       'field': 'checksum',
+                       'length': 8
+               },
+               {
+                       'field': 'type',
+                       'length': 1
+               },
+               {
+                       'field': 'linkName',
+                       'length': 100
+               },
+               {
+                       'field': 'ustar',
+                       'length': 8
+               },
+               {
+                       'field': 'owner',
+                       'length': 32
+               },
+               {
+                       'field': 'group',
+                       'length': 32
+               },
+               {
+                       'field': 'majorNumber',
+                       'length': 8
+               },
+               {
+                       'field': 'minorNumber',
+                       'length': 8
+               },
+               {
+                       'field': 'filenamePrefix',
+                       'length': 155
+               },
+               {
+                       'field': 'padding',
+                       'length': 12
+               }
+       ];
+
+       function formatHeader(data, cb) {
+               var buffer = utils.clean(512),
+                       offset = 0;
+
+               headerFormat.forEach(function (value) {
+                       var str = data[value.field] || "",
+                               i, length;
+
+                       for (i = 0, length = str.length; i < length; i += 1) {
+                               buffer[offset] = str.charCodeAt(i);
+                               offset += 1;
+                       }
+
+                       offset += value.length - i; // space it out with nulls
+               });
+
+               if (typeof cb === 'function') {
+                       return cb(buffer, offset);
+               }
+               return buffer;
+       }
+       
+       module.exports.structure = headerFormat;
+       module.exports.format = formatHeader;
+}());
+
+
+/***/ }),
+/* 2 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/*
+ * tar-js
+ * MIT (c) 2011 T. Jameson Little
+ */
+
+(function () {
+       "use strict";
+
+       var header = __webpack_require__(1),
+               utils = __webpack_require__(0),
+               recordSize = 512,
+               blockSize;
+       
+       function Tar(recordsPerBlock) {
+               this.written = 0;
+               blockSize = (recordsPerBlock || 20) * recordSize;
+               this.out = utils.clean(blockSize);
+       }
+
+       Tar.prototype.append = function (filepath, input, opts, callback) {
+               var data,
+                       checksum,
+                       mode,
+                       mtime,
+                       uid,
+                       gid,
+                       headerArr;
+
+               if (typeof input === 'string') {
+                       input = utils.stringToUint8(input);
+               } else if (input.constructor !== Uint8Array.prototype.constructor) {
+                       throw 'Invalid input type. You gave me: ' + input.constructor.toString().match(/function\s*([$A-Za-z_][0-9A-Za-z_]*)\s*\(/)[1];
+               }
+
+               if (typeof opts === 'function') {
+                       callback = opts;
+                       opts = {};
+               }
+
+               opts = opts || {};
+
+               mode = opts.mode || parseInt('777', 8) & 0xfff;
+               mtime = opts.mtime || Math.floor(+new Date() / 1000);
+               uid = opts.uid || 0;
+               gid = opts.gid || 0;
+
+               data = {
+                       fileName: filepath,
+                       fileMode: utils.pad(mode, 7),
+                       uid: utils.pad(uid, 7),
+                       gid: utils.pad(gid, 7),
+                       fileSize: utils.pad(input.length, 11),
+                       mtime: utils.pad(mtime, 11),
+                       checksum: '        ',
+                       type: opts.type || '0',
+                       ustar: 'ustar  ',
+                       owner: opts.owner || '',
+                       group: opts.group || ''
+               };
+
+               // calculate the checksum
+               checksum = 0;
+               Object.keys(data).forEach(function (key) {
+                       var i, value = data[key], length;
+
+                       for (i = 0, length = value.length; i < length; i += 1) {
+                               checksum += value.charCodeAt(i);
+                       }
+               });
+
+               data.checksum = utils.pad(checksum, 6) + "\u0000 ";
+
+               headerArr = header.format(data);
+
+               var i, offset, length;
+
+               this.out.set(headerArr, this.written);
+
+               this.written += headerArr.length;
+
+               // If there is not enough space in this.out, we need to expand it to
+               // fit the new input.
+               if (this.written + input.length > this.out.length) {
+                       this.out = utils.extend(this.out, this.written, input.length, blockSize);
+               }
+
+               this.out.set(input, this.written);
+
+               // to the nearest multiple of recordSize
+               this.written += input.length + (recordSize - (input.length % recordSize || recordSize));
+
+               // make sure there's at least 2 empty records worth of extra space
+               if (this.out.length - this.written < recordSize * 2) {
+                       this.out = utils.extend(this.out, this.written, recordSize * 2, blockSize);
+               }
+
+               if (typeof callback === 'function') {
+                       callback(this.out);
+               }
+
+               return this.out;
+       };
+
+       Tar.prototype.clear = function () {
+               this.written = 0;
+               this.out = utils.clean(blockSize);
+       };
+       
+       module.exports = Tar;
+}());
+
+
+/***/ })
+/******/ ]);
\ No newline at end of file
diff --git a/src/assets/scss/app.scss b/src/assets/scss/app.scss
new file mode 100644 (file)
index 0000000..bc8a216
--- /dev/null
@@ -0,0 +1,688 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/** Styles for the application **/
+@import "../../assets/scss/mixins/mixin";
+@import "../../assets/scss/variable";
+$customnavbar-padding-x: ($spacer / 0.5) !default;
+* {
+  outline: 0;
+}
+button[type=submit]:focus, .sidebar-body button[type=button]:focus {
+  @include box-shadow(0, 0, 0, 0.2rem, lighten($primary, 50%) !important);
+}
+.btn-danger:focus{
+  @include box-shadow(0, 0, 0, 0.2rem, lighten($danger, 30%) !important);
+}
+body,
+.list-overflow,
+.scroll-box,
+.smarttable-style,
+.modal-body-custom-height,
+.layout-wrapper, .CodeMirror-vscrollbar, .ng-sidebar, .runninginstances .popover-body {
+  &::-webkit-scrollbar {
+    @include wh-value(10px, null);
+  }
+  &::-webkit-scrollbar-thumb {
+    background-clip: content-box;
+    @include border(all, 3, solid, transparent);
+    @include roundedCorners(7);
+    @include box-shadow(0, 0, 0, 10px, rgba($black, 0.8), inset);
+  }
+  &::-webkit-scrollbar-button {
+    @include wh-value(0, 0);
+    @include flexbox(none, null, null, null, null, null);
+  }
+  &::-webkit-scrollbar-corner {
+    @include background(null, transparent, null, null, null);
+  }
+}
+body {
+  @include font-family("Roboto");
+  @include background(null, $theme-bg-color, null, null, null);
+  overflow-x: hidden;
+  .osm-logo {
+    @include wh-value(100px, auto);
+  }
+  .bg-light {
+    @include background(null, $theme-bg-color !important, null, null, null);
+  }
+  a {
+    color: $primary;
+    &:hover,
+    &:focus {
+      text-decoration: none;
+    }
+  }
+  .badge {
+    @include line-height(normal);
+    &.badge-pill {
+      @include padding-percentage-value(0.2em, 0.6em, 0.2em, 0.6em);
+    }
+  }
+  button {
+    outline: none;
+    @include box-shadow(0, 0, 0, 0, transparent);
+    &:hover,
+    &:focus,
+    &:active {
+      outline: none;
+      @include box-shadow(0, 0, 0, 0, transparent !important);
+    }
+    &.btn-primary,
+    &.btn-default,
+    &.btn-warning,
+    &.btn-outline-primary:hover,
+    &.btn-outline-warning:hover {
+      color: $white;
+      &:hover,
+      &:focus,
+      &:not(:disabled):not(.disabled):active {
+        color: $white;
+        @include background(null, $primary, null, null, null);
+        border-color: $primary;
+      }
+      &:disabled {
+        cursor: not-allowed;
+      }
+    }
+  }
+  .row {
+    margin-left: 0;
+    margin-right: 0;
+  }
+  .navbar {
+    @include padding-percentage-value(
+      $navbar-padding-y,
+      $customnavbar-padding-x,
+      $navbar-padding-y,
+      $customnavbar-padding-x
+    );
+  }
+  .form-control {
+    @include roundedCorners(4);
+    @include font(null, 12px, null);
+    &::placeholder {
+      color: $gray-400;
+    }
+  }
+  .modal-dialog {
+    max-width: 600px;
+  }
+  .header-style {
+    @include font(null, 1.2rem, 700);
+    color: $primary;
+    @include line-height(1.25);
+  }
+  .cursor-default {
+    cursor: default;
+  }
+  .cursor-pointer {
+    cursor: pointer;
+  }
+  .mr-top-5 {
+    @include margin-value-percentage(5px, auto, auto, auto);
+  }
+  .padLeft0 {
+    padding-left: 0px;
+  }
+  .padRight0 {
+    padding-right: 0px;
+  }
+  .mandatory-label {
+    @include font(null, 10px, null);
+  }
+  .dropzone {
+    min-height: 50px;
+    @include flexbox(table, null, null, null, null, null);
+    @include wh-value(100%, 50px);
+    @include border(all, 1, dashed, $secondary);
+    cursor: pointer;
+    .text-wrapper {
+      @include padding-value(5, 5, 5, 5);
+      @include flexbox(table-cell, null, null, null, null, null);
+      vertical-align: middle;
+    }
+    .file-drop-title {
+      @include font(null, 16px, null);
+    }
+  }
+  .close {
+    opacity: 1 !important;
+  }
+  .roles-section {
+    .card {
+      .bg-secondary {
+        @include background(null, $gray-400 !important, null, null, null);
+      }
+    }
+  }
+  .card {
+    margin-bottom: 1rem;
+  }
+  .custom-card {
+    @include border(top, 3, solid, $primary);
+    @include roundedCorners(3);
+    .custom-card-body {
+      @include padding-value(15, 15, 15, 15);
+    }
+  }
+  table-cell-default-editor select-editor select {
+    @include wh-value(null, calc(2rem + 8px) !important);
+    @include padding-value(0, 10, 0, 10);
+  }
+  .CodeMirror {
+    min-height: 400px !important;
+  }
+  .table-layout-fixed {
+    table-layout: fixed;
+    word-wrap: break-word;
+  }
+  .border-radius-default {
+    @include roundedCorners(3);
+  }
+  /** Model Popup-Design **/
+  .modal-body-custom-height {
+    max-height: 65vh;
+    overflow-y: auto;
+  }
+  /** Hide input clear icon in IE */
+  input::-ms-clear {
+    @include flexbox(none, null, null, null, null, null);
+  }
+  /** Overwrite the tooltip z-index */
+  .tooltip {
+    z-index: 1010;
+  }
+  /** Popover Header **/
+  .popover-header {
+    color: $primary;
+    @include background(null, $theme-bg-color, null, null, null);
+  }
+  /** Vim Show running instance Details **/
+  .runninginstances{
+     width:200px;
+     .popover-body{
+      max-height: 200px;
+      overflow-y: scroll;
+     }
+  }
+  /****************************************************************************/
+  /************************** Smart table custom design ***********************/
+  /****************************************************************************/
+  ng2-smart-table {
+    @include font(null, 15px, null);
+    color: $gray-700;
+    .form-control {
+      @include wh-value(null, auto);
+    }
+    &.dataTables_empty td {
+      text-align: center;
+    }
+    ng2-smart-table-title {
+      * {
+        @include font(null, 12px, null);
+      }
+      a {
+        color: $gray-700 !important;
+        @include flexbox(block, null, null, null, null, null);
+        text-decoration: none;
+        &::after {
+          content: "\f0dc" !important;
+          @include font-family("Font Awesome 5 Free");
+          float: right;
+          color: $gray-500;
+          @include wh-value(0, 0);
+        }
+        &.asc::after {
+          content: "\f0de" !important;
+          @include font-family("Font Awesome 5 Free");
+          float: right;
+          color: $gray-500;
+        }
+        &.desc::after {
+          content: "\f0dd" !important;
+          @include font-family("Font Awesome 5 Free");
+          float: right;
+          color: $gray-500;
+        }
+        &:hover {
+          text-decoration: none !important;
+        }
+        &.sort.desc::after {
+          transform: none !important;
+          margin-bottom: 0;
+        }
+        &.sort.asc::after,
+        &.sort.desc::after {
+          content: "";
+          @include flexbox(inline-block, null, null, null, null, null);
+          @include wh-value(0, 0);
+          @include border(all, 0, solid, transparent !important);
+          margin-bottom: 0 !important;
+        }
+      }
+      span {
+        color: $gray-700;
+      }
+    }
+    ng2-smart-table-cell {
+      word-break: break-word;
+      table-cell-view-mode {
+        @include font(null, 12px, null);
+        .icon-label {
+          @include font(null, 20px, null);
+          @include flexbox(inline-block, null, null, null, null, null);
+          @include wh-value(100px, 0);
+          text-align: center;
+          cursor: default;
+        }
+      }
+    }
+    .ng2-smart-filter {
+      @include wh-value(null, calc(2rem + 2px) !important);
+      @include font(null, 12px, null);
+      margin-top: 6px;
+    }
+    table.list-data {
+      tr td,
+      tr th {
+        @include padding-value(2, 10, 2, 10);
+        vertical-align: middle !important;
+      }
+      tbody {
+        tr.selected {
+          background: none !important;
+        }
+      }
+    }
+    default-table-filter {
+      select-filter {
+        select.form-control {
+          @include flexbox(inline-block, null, null, null, null, null);
+          @include wh-value(null, calc(1.5rem + 2px) !important);
+          vertical-align: middle;
+          background: $white
+            url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E")
+            no-repeat right 0.75rem center;
+          background-size: 8px 10px;
+          @include border(all, 1, solid, $gray-200);
+          @include roundedCorners(2);
+          -webkit-appearance: none;
+          -moz-appearance: none;
+          appearance: none;
+          &::-ms-expand {
+            visibility: hidden;
+          }
+        }
+      }
+      select-filter {
+        select {
+          @include roundedCorners(4);
+        }
+      }
+      input-filter {
+        input[type="text"] {
+          @include position_value(relative, null, null, null, null);
+        }
+        &:after {
+          @include position_value(relative, -26px, null, null, 100%);
+          content: "\f002";
+          @include font("Font Awesome 5 Free", 10px, null);
+          @include padding-value(0, 0, 0, 2);
+          color: $gray-500;
+        }
+      }
+    }
+    ng2-smart-table-pager {
+      @include flexbox(null, null, row-reverse, null, null, null);
+      @include padding-value(5, 20, 5, 20);
+      .ng2-smart-pagination {
+        .ng2-smart-page-item {
+          @include font(null, 10px, null);
+          a {
+            &:hover {
+              text-decoration: none;
+            }
+          }
+          .ng2-smart-page-link {
+            @include font(null, 12px !important, null);
+            &.page-link {
+              text-align: center;
+              vertical-align: middle;
+              color: $primary;
+              @include border(all, 1, solid, $primary !important);
+              &:hover {
+                @include background(null, $primary !important, null, null, null);
+                color: $white;
+              }
+            }
+          }
+          span.ng2-smart-page-link.page-link {
+            color: $white;
+            @include background(null, $primary !important, null, null, null);
+            @include border(all, 1, solid, $primary !important);
+          }
+        }
+      }
+    }
+  }
+  /****************************************************************************/
+  /*********************** Button styles under list class *********************/
+  /****************************************************************************/
+  .list {
+    &.action {
+      button.btn.btn-primary {
+        @include padding-value(2, 8, 2, 8);
+      }
+    }
+    button:focus {
+      outline: 0;
+      @include box-shadow(0, 0, 0, 0, transparent);
+    }
+    button.btn.btn-primary {
+      color: $primary;
+      @include background(null, $white, null, null, null);
+      &:not(.active:hover) {
+        @include background(null, $white, null, null, null);
+      }
+      &:active {
+        color: $primary;
+        @include background(null, $white, null, null, null);
+      }
+      &.action-button {
+        color: $white;
+        @include background(null, $primary !important, null, null, null);
+        &:hover {
+          @include background(null, $primary, null, null, null);
+        }
+      }
+    }
+    .dropdown-menu {
+      @include border(all, 1, solid, $primary);
+      @include padding-value(0, 0, 0, 0);
+      button.btn.btn-primary {
+        @include background(null, transparent, null, null, null);
+        @include padding-value(8, 8, 8, 8);
+        @include roundedCorners(0);
+        &:hover {
+          @include background(null, $primary, null, null, null);
+          color: $white;
+        }
+        &:not(:last-child) {
+          @include border(bottom, 1, solid, $primary);
+        }
+      }
+    }
+  }
+  /****************************************************************************/
+  /*********************** Custom tabel design in topology ********************/
+  /****************************************************************************/
+  .custom-table {
+    td:first-child {
+      @include font(null, null, bold);
+      text-align: right;
+    }
+    th,
+    td {
+      @include padding-value(5, 7, 5, 7);
+      @include font(null, 10px, null);
+      @include line-height(15px);
+    }
+  }
+  /****************************************************************************/
+  /************************** Ng select custom design *************************/
+  /****************************************************************************/
+  .ng-select {
+    &.is-invalid .ng-select-container {
+      @include border(all, 1, solid, $red);
+    }
+    .ng-select-container {
+      @include border(all, 1, solid, $gray-200);
+      .ng-value-container .ng-placeholder {
+        color: $gray-80;
+      }
+    }
+  }
+  /****************************************************************************/
+  /******************** Custom nav section for default status *****************/
+  /****************************************************************************/
+  .list-utilites-actions {
+    @include flexbox(flex, null, row, null, center, null);
+    nav.custom-items-config {
+      @include position_value(relative, null, null, null, null);
+      @include roundedCorners(3);
+      span {
+        @include font(null, 13px, 600);
+        @include flexbox(inline-block, null, null, null, null, null);
+        @include position_value(relative, null, null, null, null);
+        text-decoration: none;
+        text-align: center;
+        @include margin-value(0, 0, 0, 10);
+        &:first-child {
+          @include margin-value(0, 0, 0, 0);
+        }
+        i {
+          @include font(null, 14px, null);
+          @include margin-value(0, 5, 0, 0);
+        }
+      }
+    }
+  }
+  /****************************************************************************/
+  /************************* File upload custom design ************************/
+  /****************************************************************************/
+  .custom-file-label {
+    color: $primary;
+    @include roundedCorners(4);
+    @include border(all, 1, solid, $primary);
+    overflow: hidden;
+    @include margin-value(0, 0, 0, 0);
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    padding-right: 80px;
+    &::after {
+      color: $white;
+      @include background(null, $primary, null, null, null);
+    }
+  }
+  /****************************************************************************/
+  /************************* Notifier Container Design ************************/
+  /****************************************************************************/
+  .notifier__container {
+    ul {
+      @include margin-value(0, 0, 0, 0);
+    }
+  }
+  /***************************************************************************/
+  /************************* Topology Common Design **************************/
+  /****************************************************************************/
+  .ns-composer-form,
+  .vnf-composer-form,
+  .ns-instance-form {
+    @include font(null, 12px, null);
+    .ns-svg,
+    .vnf-svg {
+      @include wh-value(30px, 25px);
+    }
+    .svg-container {
+      min-height: 60vh;
+    }
+    .form-control {
+      @include font(null, 10px, null);
+    }
+    .scroll-box {
+      max-height: 285px;
+      overflow-y: scroll;
+    }
+    .border-all {
+      @include border(all, 1, solid, $primary);
+    }
+    .list-group {
+      &.inside-svg {
+        .list-group-item {
+          @include padding-value(3.2, 8, 3.2, 8);
+        }
+      }
+      &.dragable {
+        .list-group-item {
+          cursor: move;
+          @include padding-value(4.8, 4.8, 4.8, 4.8);
+          @include margin-value(0, 0, 5, 0);
+          @include background(null, $gray-200, null, null, null);
+          @include flexbox(flex, null, null, null, center, null);
+          border: none;
+          .span-overflow-text {
+            @include wh-value(90%, null);
+            white-space: nowrap;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            @include line-height(25px);
+          }
+        }
+      }
+    }
+    .drag-icon {
+      color: $gray-600;
+      @include font(null, 15px, null);
+    }
+    .ctrl {
+      cursor: move;
+    }
+    svg {
+      -webkit-user-select: none;
+      -moz-user-select: none;
+      -ms-user-select: none;
+      -o-user-select: none;
+      user-select: none;
+      image.node:hover,
+      circle.node:hover {
+        opacity: 0.7 !important;
+      }
+      image.active,
+      circle.active {
+        opacity: 0.7 !important;
+      }
+      path.link {
+        stroke: $dark-gray;
+        stroke-width: 2px;
+        fill: none;
+        &:hover {
+          stroke-width: 4px;
+        }
+        .dragline {
+          pointer-events: none;
+        }
+      }
+      .node_text {
+        text-anchor: middle;
+        pointer-events: none;
+      }
+      :not(.ctrl) {
+        cursor: pointer;
+      }
+    }
+    fieldset {
+      @include border(all, 1, solid, $primary);
+      legend {
+        @include padding-value(0, 5, 0, 5);
+        @include font(null, 15px, null);
+        color: $primary;
+        &.vl-legend,
+        &.element-legend {
+          @include wh-value(55%, null);
+        }
+        &.vnfd-legend {
+          @include wh-value(25%, null);
+        }
+      }
+    }
+    .btn-icon {
+      @include wh-value(36px, 36px);
+      text-align: center;
+      @include margin-value(0, 10, 10, 0);
+    }
+    .topology-btn {
+      color: $primary;
+      border-color: $primary;
+      &:hover,
+      &.pinned {
+        color: $white !important;
+        @include background(null, $primary !important, null, null, null);
+      }
+    }
+    .badgegroup {
+      @include flexbox(flex, flex-end, row, center, center, null);
+    }
+  }
+  .ns-topology-sidebar-container,
+  .vnf-topology-sidebar-container,
+  .ns-instance-topology-sidebar-container {
+    @include position_value(absolute !important, 0px, null, null, 0px);
+    .ng-sidebar {
+      @include wh-value(27%, null);
+      @include background(null, $white, null, null, null);
+      @include border(all, 1, solid, $gray-300);
+      .sidebar-header {
+        @include background(null, $modalheader-gray, null, null, null);
+        @include padding-value(5, 10, 5, 10);
+        @include border(bottom, 1, solid, $gray-300);
+        @include flexbox(flex, space-between, null, center, center, null);
+        .topology_title {
+          color: $primary;
+        }
+      }
+      .sidebar-body {
+        @include padding-value(10, 5, 10, 5);
+      }
+    }
+    .ng-sidebar__content {
+      button {
+        @include position_value(absolute, 45%, null, null, 0px);
+        @include background(null, $primary, null, null, null);
+      }
+      .detail-sidebar {
+        @include flexbox(inline-block, null, null, null, null, null);
+        @include position_value(relative, null, null, null, null);
+        animation: push 0.5s infinite linear;
+      }
+    }
+    @keyframes push {
+      0% {
+        right: 0;
+      }
+      50% {
+        right: -0.2em;
+      }
+      70% {
+        right: -0.3em;
+      }
+      100% {
+        right: 0;
+      }
+    }
+  }
+}
+/****************************************************************************/
+/************************** MEDIA QUERIES ***********************************/
+/****************************************************************************/
+@media (max-width: map-get($grid-breakpoints, md)) {
+  .smarttable-style {
+    overflow-x: auto;
+    white-space: nowrap;
+  }
+}
\ No newline at end of file
diff --git a/src/assets/scss/mixins/_animation.scss b/src/assets/scss/mixins/_animation.scss
new file mode 100644 (file)
index 0000000..ff1d0d5
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for animation property
+ * example for animation: @include animation(rotate 1s linear);
+ * example for keyframes: @include keyframes(rotate) {
+        0% { @include rotate(0); }
+        100% { @include rotate(359); }
+    }
+ */
+
+// @mixin for animation properties
+@mixin animation ($animation) {
+    -webkit-animation: #{$animation};
+    -moz-animation: #{$animation};
+    -ms-animation: #{$animation};
+    -o-animation: #{$animation};
+    animation: #{$animation};
+}
+
+// @mixin for keyframes properties
+@mixin keyframes ($animation) {
+    @-webkit-keyframes #{$animation} {
+        @content;
+    }
+    @-moz-keyframes #{$animation} {
+        @content;
+    }
+    @-o-keyframes #{$animation} {
+        @content;
+    }
+    @keyframes #{$animation} {
+        @content;
+    }
+}
\ No newline at end of file
diff --git a/src/assets/scss/mixins/_background.scss b/src/assets/scss/mixins/_background.scss
new file mode 100644 (file)
index 0000000..4eefcef
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for background property
+ * example: @include background(url, orange, 20px, repeat, center);
+ */
+
+// @mixin for background properties
+@mixin background($url, $color, $size, $repeat, $position) {
+    background-image: $url;
+    background-color: $color;
+    background-size : $size;
+    background-repeat: $repeat;
+    background-position: $position;
+}
\ No newline at end of file
diff --git a/src/assets/scss/mixins/_border.scss b/src/assets/scss/mixins/_border.scss
new file mode 100644 (file)
index 0000000..7ec370e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for border
+ * example: @include border(top, 1, solid, #000);
+ */
+
+// @mixin for border size and color
+@mixin border($side, $size, $type, $color){
+   @if ($side == top) {
+       border-top: $size+px $type $color;
+   } @else if ($side == right) {
+       border-right: $size+px $type $color;
+   } @else if ($side == left) {
+       border-left: $size+px $type $color;
+   } @else if ($side == bottom ) {
+       border-bottom: $size+px $type $color;
+   } @else if($side == all ){
+        border: $size+px $type $color;
+   }@else {
+       @if ($size == thin){
+        border: $size $type $color;
+       }
+       @else {
+       border: $size+px $type $color;
+       }
+   }
+}
diff --git a/src/assets/scss/mixins/_box-shadow.scss b/src/assets/scss/mixins/_box-shadow.scss
new file mode 100644 (file)
index 0000000..d520e84
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for box-shadow
+ * example: @include box-shadow(1px, 2px, 2px, 2px, #000);
+ */
+
+// @mixin for box shadow
+@mixin box-shadow($hoff: false, $voff: false, $blur: false, $spread: false, $color: false, $inset: false) {
+  @if $inset {
+    -webkit-box-shadow:inset $hoff $voff $blur $spread $color;
+    -moz-box-shadow:inset $hoff $voff $blur $spread $color;
+    box-shadow:inset $hoff $voff $blur $spread $color;
+  } @else {
+    -webkit-box-shadow: $hoff $voff $blur $spread $color;
+    -moz-box-shadow: $hoff $voff $blur $spread $color;
+    box-shadow: $hoff $voff $blur $spread $color;
+  }
+}
\ No newline at end of file
diff --git a/src/assets/scss/mixins/_custom.scss b/src/assets/scss/mixins/_custom.scss
new file mode 100644 (file)
index 0000000..c7424de
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains custom @mixin functions
+ */
+
+// @mixin for container width and height
+@mixin wh-value($width, $height) {
+    width: $width;
+    height: $height;
+}
+
+// @mixin for padding values
+@mixin padding-value($top, $right, $bottom, $left) {
+    padding: $top+px $right+px $bottom+px $left+px;
+}
+
+// @mixin for any padding values
+@mixin padding-percentage-value($top: null, $right: null, $bottom: null, $left: null) {
+    padding: $top $right $bottom $left;
+}
+
+// @mixin for margin values
+@mixin margin-value($top, $right, $bottom, $left) {
+    margin: $top+px $right+px $bottom+px $left+px;
+}
+
+// @mixin for margin values in percentage
+@mixin margin-value-percentage($top: null, $right: null, $bottom: null, $left: null) {
+    margin: $top $right $bottom $left;
+}
+
+// @mixin for center-align element/container
+@mixin align-center($topbottom, $width) {
+    margin: $topbottom auto;
+    width: $width;
+}
+
+// @mixin for center-align with top and bottom margin element/container
+@mixin tband-align-center($topbottom, $width, $bottommargin) {
+    margin: $topbottom auto $bottommargin;
+    width: $width;
+}
+
+// @mixin for transform style
+@mixin transform($x, $y, $z)
+{
+    transform: translate3d($x+px, $y+px, $z+px);
+    -webkit-transform: translate3d($x+px, $y+px, $z+px);
+}
+
+// @mixin for font-family setting
+@mixin font-family($font){
+    font-family: $font;
+}
+
+// @mixin for font-style setting
+@mixin font-style($font-style){
+    font-style: $font-style;
+}
+
+// Mixin for font & its attributes
+@mixin font($family, $size, $weight) {
+    font-family: $family;
+    font-size: $size;
+    font-weight: $weight;
+}
+
+// @mixin for line-height setting
+@mixin line-height($line-height){
+    line-height: $line-height;
+}
+
+// @mixin for letter-spacing setting
+@mixin letter-spacing($letter-spacing){
+    letter-spacing: $letter-spacing;
+}
+
+// @mixin to manipulate placeholder attribute in input element
+@mixin placeholder {
+  ::-webkit-input-placeholder {@content}
+  :-moz-placeholder           {@content}
+  ::-moz-placeholder          {@content}
+  :-ms-input-placeholder      {@content}
+}
+
+// mixins for user-select
+@mixin user-select($select) {
+    @each $pre in -webkit-, -moz-, -ms-, -o- {
+      #{$pre + user-select}: #{$select};
+    } 
+    #{user-select}: #{$select};
+  }
diff --git a/src/assets/scss/mixins/_flex.scss b/src/assets/scss/mixins/_flex.scss
new file mode 100644 (file)
index 0000000..faf870e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin function for flex properties
+ * example: @include flexbox(flex, flex-start, row-reverse, center, center, flex-end);
+ * 1. display: flex | inline-flex
+ * 2. justify-content : flex-start | flex-end | center | space-between | space-around
+ * 3. flex-direction: row | row-reverse | column | column-reverse
+ * 4. align-content: flex-start | flex-end | center | space-between | space-around | stretch
+ * 5. align-items: flex-start | flex-end | center | baseline | stretch
+ * 6. align-self: auto | flex-start | flex-end | center | baseline | stretch
+ */
+
+@mixin flexbox($display: null, $justify: null, $direction: null, $aligncontent: null, $alignitems: null, $alignself: null) {
+display: $display;
+justify-content: $justify;
+flex-direction: $direction;
+align-content: $aligncontent;
+align-items: $alignitems;
+align-self: $alignself;
+}
+
+/** To set flexible length for items
+ * flex-grow: how much an item will grow relative to the rest of the flexible items
+   flex-shrink: how much an item will shrink relative to the rest of the flexible items
+   flex-basis: The length of the item. Legal values: "auto", "inherit", or a number followed by "%", "px", "em"
+ */
+@mixin flex($flex-grow: null, $flex-shrink: null, $flex-basis: null){
+    flex-grow: $flex-grow;
+    flex-shrink: $flex-shrink;
+    flex-basis: $flex-basis;
+}
\ No newline at end of file
diff --git a/src/assets/scss/mixins/_font-weight.scss b/src/assets/scss/mixins/_font-weight.scss
new file mode 100644 (file)
index 0000000..2210f08
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for font-weight
+ * example: @include fontWeight(600); (OR) @include fontWeight(semi-bold);
+ */
+
+// @mixin for font weight
+@mixin fontWeight($weight){
+    $weights: (
+        thin: 100,
+        extra-light: 200,
+        light: 300,
+        regular: 400,
+        medium: 500,
+        semi-bold: 600,
+        bold: 700,
+        extra-bold: 800,
+        ultra-bold: 900
+    );
+
+    $output: $weight;
+    @if map-has-key($weights, $weight) {
+        $output: map-get($weights, $weight);
+    }
+
+    font-weight: $output;
+ }
\ No newline at end of file
diff --git a/src/assets/scss/mixins/_position.scss b/src/assets/scss/mixins/_position.scss
new file mode 100644 (file)
index 0000000..420f93d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for offset position
+ * @param {String} $position - Either `relative`, `absolute` or `fixed`
+ * @param {Length} $top [null] - Top offset
+ * @param {Length} $right [null] - Right offset
+ * @param {Length} $bottom [null] - Bottom offset
+ * @param {Length} $left [null] - Left offset
+ */
+
+@mixin position_value($position, $top: null, $right: null, $bottom: null, $left: null) {
+  position: $position;
+  top: $top;
+  right: $right;
+  bottom: $bottom;
+  left: $left;
+}
\ No newline at end of file
diff --git a/src/assets/scss/mixins/_rem.scss b/src/assets/scss/mixins/_rem.scss
new file mode 100644 (file)
index 0000000..960132a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for font
+ * example: @include rem("font-size", 14);
+ */
+
+@mixin rem($property, $values...) {
+    $n: length($values);
+    $i: 1;
+    $pxlist: ();
+    $remlist: ();
+    @while $i <=$n {
+        $itemVal: (nth($values, $i));
+        @if $itemVal !="auto" {
+            $pxlist: append($pxlist, $itemVal + px);
+            $remlist: append($remlist, ($itemVal / 16) + rem);
+        }
+        @else {
+            $pxlist: append($pxlist, auto);
+            $remlist: append($remlist, auto);
+        }
+        $i: $i+1;
+    }
+    #{$property}: $pxlist;
+    #{$property}: $remlist;
+}
\ No newline at end of file
diff --git a/src/assets/scss/mixins/_rounded-corners.scss b/src/assets/scss/mixins/_rounded-corners.scss
new file mode 100644 (file)
index 0000000..dc8f77c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for border radius
+ * example: @include roundedCorners(10);
+ */
+
+// Rounded Corner has equal radius
+@mixin roundedCorners($size) {
+    border-radius: $size + px;
+}
+
+// Rounded Corner for percentage values
+@mixin roundedCornersPercentage($size) {
+    border-radius: $size;
+}
+
+// Rounded Corner for Top left/right
+@mixin roundedTop($size) {
+    border-radius: $size + px $size + px 0 0;
+}
+
+// Rounded Corner for Top Left alone
+@mixin roundedTopLeft($size) {
+    border-radius: $size + px 0 0 0;
+}
+
+// Rounded Corner for Top Right alone
+@mixin roundedTopRight($size) {
+    border-radius: 0 $size + px 0 0;
+}
+
+// Rounded Corner for Bottom left/right
+@mixin roundedBottom($size) {
+    border-radius: 0 0 $size + px $size + px;
+}
+
+// Rounded Corner  for Bottom Left alone
+@mixin roundedBottomLeft($size) {
+    border-radius: 0 0 0 $size + px;
+}
+
+// Rounded Corner for Bottom Right alone
+@mixin roundedBottomRight($size) {
+    border-radius: 0 0 $size + px 0;
+}
+
+// Rounded Corner for Left Top/Bottom
+@mixin roundedLeft($size) {
+    border-radius: $size + px 0 0 $size + px;
+}
+
+// Rounded Corner for Right Top/Bottom
+@mixin roundedRight($size) {
+    border-radius: 0 $size + px $size + px 0;
+}
+
+// Shorthand for all four corners rounded equally
+@mixin circularCorners($size) {
+    border-radius: $size;
+}
+
+// Border bottom left radius
+@mixin roundedBottomLeftRadius($sive) {
+    border-bottom-left-radius: $sive + px;
+}
+
+// Border bottom right radius
+@mixin roundedBottomRightRadius($sive) {
+    border-bottom-right-radius: $sive + px;
+}
+
+// Border top left radius
+@mixin roundedTopLeftRadius($sive) {
+    border-top-left-radius: $sive + px;
+}
+
+// Border top right radius
+@mixin roundedTopRightRadius($sive) {
+    border-top-right-radius: $sive + px;
+}
\ No newline at end of file
diff --git a/src/assets/scss/mixins/_transform.scss b/src/assets/scss/mixins/_transform.scss
new file mode 100644 (file)
index 0000000..927ddae
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for transform
+ */
+
+// @mixin for 3d transform
+@mixin transform_style($txsize, $tysize, $tzsize) {
+   transform: translate3d($txsize, $tysize, $tzsize);
+}
+
+// @mixin for rotate transform
+@mixin rotate($deg){
+    transform: rotate($deg+deg);
+    -webkit-transform: rotate($deg+deg);
+}
diff --git a/src/assets/scss/mixins/_transition.scss b/src/assets/scss/mixins/_transition.scss
new file mode 100644 (file)
index 0000000..743c8fb
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @ file contains @mixin functions for transition property
+ * example: @include transition(background, 1s, ease-in-out, 0);
+ */
+
+// @mixin for transition properties
+@mixin transition($property: null, $duration: null, $timing-function: null, $delay: null) {
+    transition-property: $property;
+    transition-duration: $duration;
+    transition-timing-function: $timing-function;
+    transition-delay: $delay;
+}
\ No newline at end of file
diff --git a/src/assets/scss/mixins/mixin.scss b/src/assets/scss/mixins/mixin.scss
new file mode 100644 (file)
index 0000000..e5488e1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/** All mixins are imported here */
+@import '_animation';
+@import '_background';
+@import '_border';
+@import '_box-shadow';
+@import '_custom';
+@import '_flex';
+@import '_font-weight';
+@import '_position';
+@import '_rem';
+@import '_rounded-corners';
+@import '_transform';
+@import '_transition';
\ No newline at end of file
diff --git a/src/assets/scss/style.scss b/src/assets/scss/style.scss
new file mode 100644 (file)
index 0000000..d39843b
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/*Roboto Fonts*/
+$roboto-font-path: "~roboto-fontface/fonts" !default;
+@import "~roboto-fontface/css/roboto/sass/roboto-fontface-regular";
+/*Custom mixin*/
+@import "mixins/mixin.scss";
+/*Theme setup color*/
+@import "variable";
+/*bootstrap styles*/
+@import "~bootstrap/scss/bootstrap";
+/*Custom theme styles*/
+@import "app.scss";
+/*Code Mirror styles*/
+@import "~codemirror/lib/codemirror";
+@import "~codemirror/addon/fold/foldgutter";
+@import "~codemirror/theme/neat";
+@import "~codemirror/theme/material";
+@import "~codemirror/addon/dialog/dialog";
+@import "~codemirror/addon/display/fullscreen";
+/*ng-select styles*/
+@import "~@ng-select/ng-select/themes/default.theme.css";
+/*Angular notifier styles*/
+@import "~angular-notifier/styles/core.scss";
+@import "~angular-notifier/styles/themes/theme-material.scss";
+@import "~angular-notifier/styles/themes/theme-material.scss";
+@import "~angular-notifier/styles/types/type-success.scss";
+@import "~angular-notifier/styles/types/type-error.scss";
+@import "~angular-notifier/styles/types/type-warning.scss";
+@import "~angular-notifier/styles/types/type-default.scss";
+@import "~angular-notifier/styles/types/type-info.scss";
\ No newline at end of file
diff --git a/src/assets/scss/variable.scss b/src/assets/scss/variable.scss
new file mode 100644 (file)
index 0000000..6a274ce
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+// Custom Variables
+$themecolor: #2962ff;
+$theme-light: #fff;
+
+/*Topbar Colors*/
+
+$topbar: $theme-light;
+$topbar-height: 64px;
+$topbar-navlink-padding: 0px 15px;
+$topbar-navlink-font-size: 0.875rem;
+$topbar-navlink-height: 64px;
+$topbar-navbrand-padding: 0 10px 0 10px;
+/*Sidebar Colors*/
+
+$sidebar: $theme-light;
+$sidebar-text: #fff;
+$sidebar-icons: #fff;
+$sidebar-width-full: 100px;
+$sidebar-width-mini: 65px;
+/*Boxed layout width*/
+
+$boxed-width: 1200px;
+/*Shadow*/
+
+$shadow: 1px 0px 20px rgba(0, 0, 0, 0.08);
+/*transitions*/
+
+$transitions: 0.2s ease-in;
+/*Dark transparent bg*/
+
+$transparent-dark-bg: rgba(0, 0, 0, 0.05);
+$lft: left;
+$rgt: right;
+$card-alt: #e4e9ef;
+%square {
+  border-radius: 0px;
+}
+
+%rotate45 {
+  transform: rotate(45deg);
+  -ms-transform: rotate(45deg);
+  -webkit-transform: rotate(45deg);
+  -o-transform: rotate(45deg);
+  -moz-transform: rotate(45deg);
+}
+
+/*******************************/
+
+// Bootstrap overrides
+/*******************************/
+
+/**
+ * Table Of Content
+ *
+ *  1. Color system
+ *  2. Options
+ *  3. Body
+ *  4. Typography
+ *  5. Breadcrumbs
+ *  6. Cards
+ *  7. Dropdowns
+ *  8. Buttons
+ *  9. Typography
+ *  10. Progress bars
+ *  11. Tables
+ *  12. Forms
+ *  14. Component
+ */
+
+//
+// Color system
+//
+$primary: #054c8c;
+$secondary: #065fac;
+$theme-bg-color: #eef5f9;
+$breadcrumb-after-color: #002a6a;
+
+$white: #fff !default;
+$gray-100: #f6fafe !default;
+$gray-200: #e9ecef !default;
+$gray-300: #dee2e6 !default;
+$gray-400: #ced4da !default;
+$gray-500: #afb5c1 !default;
+$gray-600: #6c757d !default;
+$gray-700: #4f5467 !default;
+$gray-800: #343a40 !default;
+$gray-900: #212529 !default;
+$gray-80: #cccccc !default;
+$gray-97: #f7f7f7 !default;
+$medium-pink: #fb6ca4 !default;
+$black-coral: #5a5c69 !default;
+$cerise-pink: #e4397c !default;
+$pure-red: #ff0000 !default;
+$denim: #1467b3 !default;
+$black: #000 !default;
+$blue: #137eff !default;
+$dark-gray: #aaaaaa;
+$indigo: #6610f2 !default;
+$purple: #8b5edd !default;
+$pink: #e83e8c !default;
+$red: #dd4b39 !default;
+$orange: #fb8c00 !default;
+$yellow: #f39c12 !default;
+$green: #00a65a !default;
+$teal: #20c997 !default;
+$cyan: #4fc3f7 !default;
+$grayish-red: #c1bfbf !default;
+$white-smoke: #f1f1f1 !default;
+$text-muted: $gray-500 !default;
+$colors: (
+  blue: $blue,
+  indigo: $indigo,
+  purple: $purple,
+  pink: $pink,
+  red: $red,
+  orange: $orange,
+  yellow: $yellow,
+  green: $green,
+  teal: $teal,
+  cyan: $cyan,
+  white: $white,
+  gray: $gray-600,
+  gray-dark: $gray-800
+);
+$primary: $blue !default;
+$secondary: $gray-400 !default;
+$success: $green !default;
+$info: $blue !default;
+$warning: $yellow !default;
+$danger: $red !default;
+$light: $gray-100 !default;
+$dark: $gray-800 !default;
+$cyan: $cyan !default;
+$orange: $orange !default;
+$theme-colors: () !default;
+$theme-colors: map-merge(
+  (
+    "primary": $primary,
+    "secondary": $secondary,
+    "success": $success,
+    "info": $info,
+    "warning": $warning,
+    "danger": $danger,
+    "light": $light,
+    "dark": $dark,
+    "cyan": $cyan,
+    "orange": $orange,
+    "purple": $purple
+  ),
+  $theme-colors
+);
+$modalheader-gray: #f8f9fa;
+//
+// Quickly modify global styling by enabling or disabling optional features.
+$enable-caret: true !default;
+$enable-rounded: true !default;
+$enable-shadows: false !default;
+$enable-gradients: false !default;
+$enable-transitions: true !default;
+$enable-hover-media-query: false !default;
+$enable-grid-classes: true !default;
+$enable-print-styles: true !default;
+// Body
+//
+// Settings for the  element.
+$main-body-bg: #fff !default;
+$body-bg: #f2f4f5;
+$body-color: #6a7a8c !default;
+$grid-gutter-width: 20px !default;
+// Typography
+//
+// Font, line-height, and color for body text, headings, and more.
+$font-size-base: 0.875rem;
+$font-family-open-sans: "Open Sans";
+$font-weight-light: 300 !default;
+$font-weight-normal: 400 !default;
+$font-weight-medium: 500 !default;
+$font-weight-bold: 700 !default;
+$h1-font-size: 36px !default;
+$h2-font-size: 30px !default;
+$h3-font-size: 24px !default;
+$h4-font-size: 18px !default;
+$h5-font-size: 16px !default;
+$h6-font-size: 14px !default;
+$headings-margin-bottom: (1rem / 2) !default;
+$headings-font-weight: 400 !default;
+$headings-color: inherit !default;
+// Breadcrumbs
+$breadcrumb-bg: $body-bg;
+$breadcrumb-margin-bottom: 1.5rem;
+// Cards
+$card-border-width: 0px !default;
+$card-border-color: transparent !default;
+$card-border-radius: 0px !default;
+// Dropdowns
+$dropdown-item-padding-x: 1rem !default;
+$dropdown-item-padding-y: 0.65rem !default;
+$dropdown-border-color: $gray-200;
+$dropdown-divider-bg: $gray-100;
+// Buttons
+$btn-secondary-border: $gray-300;
+// Progress bars
+$progress-bg: $gray-100;
+// Tables
+$table-bg-accent: $gray-100;
+$table-bg-hover: $gray-100;
+$table-hover-bg: $gray-100 !default;
+$table-cell-padding: 1rem !default;
+$table-bg-level: -10 !default;
+$table-bg-level2: 1 !default;
+$table-bg-level3: -5 !default;
+// Components
+$component-active-color: $white !default;
+$component-active-bg: $themecolor !default;
+$badge-pill-padding-x: 0.2em !default;
+$badge-pill-padding-y: 1em !default;
+// Forms
+$input-group-addon-bg: $gray-100;
+$input-border-color: $gray-200;
+$input-group-addon-border-color: $gray-200;
+$input-btn-focus-color: rgba(0, 0, 0, 0.25) !default;
+$input-focus-border-color: rgba(0, 0, 0, 0.25) !default;
+$custom-control-indicator-active-bg: rgba(0, 0, 0, 35%) !default;
+$input-btn-focus-box-shadow: transparent !default;
+$custom-select-focus-box-shadow: transparent !default;
+$custom-select-border-width: 1px !default;
+//
+// Define common padding and border radius sizes and more.
+$border-width: 1px !default;
+$border-color: rgba(0, 0, 0, 0.1) !default;
+$border-radius: 2px !default;
+$border-radius-lg: 2px !default;
+$border-radius-sm: 1px !default;
+// Progress bars
+$progress-height: 5px !default;
+//Tabs
+$nav-tabs-link-active-bg: $white !default;
+// Grid breakpoints
+//
+// Define the minimum dimensions at which your layout will change,
+// adapting to different screen sizes, for use in media queries.
+$grid-breakpoints: (
+  xs: 0,
+  sm: 576px,
+  md: 768px,
+  lg: 992px,
+  xl: 1600px
+) !default;
\ No newline at end of file
diff --git a/src/directive/GoToTopDirective.ts b/src/directive/GoToTopDirective.ts
new file mode 100644 (file)
index 0000000..67cdc96
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file Directive for go to top button.
+ */
+import { Directive, HostListener } from '@angular/core';
+import { SharedService } from 'SharedService';
+
+/**
+ * Creating Directive for handling go to top button
+ * @Directive appGottoTop selector
+ */
+@Directive({
+  selector: '[appGottoTop]'
+})
+/** Exporting a class @exports GoToTopDirective */
+export class GoToTopDirective {
+  /** To set scroll top position @private */
+  private topPosToStartShowing: number = 100;
+
+  /** Contains all methods related to shared @private */
+  private sharedService: SharedService;
+
+  constructor(sharedService: SharedService) {
+    this.sharedService = sharedService;
+  }
+  /**
+   * to listen the scroll event in DOM @public
+   */
+  @HostListener('window:scroll') public enableGotoTop(): void {
+    const scrollPosition: number = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop);
+    if (scrollPosition >= this.topPosToStartShowing) {
+      this.sharedService.showGotoTop = true;
+    } else {
+      this.sharedService.showGotoTop = false;
+    }
+  }
+
+}
diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts
new file mode 100644 (file)
index 0000000..6592b10
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file environment variables
+ * This file can be replaced during build by using the `fileReplacements` array.
+ * `npm run build` replaces `environment.ts` with `environment.prod.ts`.
+ * The list of file replacements can be found in `angular.json`.
+ */
+
+import { version } from 'PACKAGEJSON';
+
+/** OSM_Admin URL @constant */
+const OSM_ADMIN_ENDPOINT: string = 'osm/admin/v1/';
+/** OSM_NS LCM URL @constant */
+const OSM_NSLCM_ENDPOINT: string = 'osm/nslcm/v1/';
+/** OSM_NST URL @constant */
+const OSM_NST_ENDPOINT: string = 'osm/nst/v1/';
+/** OSM_NSI LCM URL @constant */
+const OSM_NSILCM_ENDPOINT: string = 'osm/nsilcm/v1/';
+/** OSM_VNFD PACKAGES URL @constant */
+const OSM_VNFDPACKAGE_ENDPOINT: string = 'osm/vnfpkgm/v1/';
+/** OSM_PDU URL @constant */
+const OSM_PDU_ENDPOINT: string = 'osm/pdu/v1/';
+/** OSM_NSD URL @constant */
+const OSM_NSD_ENDPOINT: string = 'osm/nsd/v1/';
+/** Assets root path @constant */
+const ASSETS_PATH: string = 'assets/';
+/** OSM Version @constant */
+const OSM_VERSION: string = 'osm/version';
+/** Grafana End-Point @constant */
+// tslint:disable-next-line: no-http-string
+const GRAFANA_ENDPOINT: string = 'http://' + window.location.hostname + ':3000';
+
+/** Exporting a const @exports environment */
+// tslint:disable-next-line: typedef
+export const environment = {
+    production: true,
+    packageSize: 15,
+    paginationNumber: 10, //Possible values are 10, 25, 50, 100
+    packageVersion: version,
+    // tslint:disable-next-line: no-http-string
+    MAPLATLONGAPI_URL: 'http://photon.komoot.de/api/?q={value}&limit=5',
+    GENERATETOKEN_URL: OSM_ADMIN_ENDPOINT + 'tokens',
+    PROJECTS_URL: OSM_ADMIN_ENDPOINT + 'projects',
+    USERS_URL: OSM_ADMIN_ENDPOINT + 'users',
+    ROLES_URL: OSM_ADMIN_ENDPOINT + 'roles',
+    VIMACCOUNTS_URL: OSM_ADMIN_ENDPOINT + 'vim_accounts',
+    WIMACCOUNTS_URL: OSM_ADMIN_ENDPOINT + 'wim_accounts',
+    SDNCONTROLLER_URL: OSM_ADMIN_ENDPOINT + 'sdns',
+    K8SCLUSTER_URL: OSM_ADMIN_ENDPOINT + 'k8sclusters',
+    K8REPOS_URL: OSM_ADMIN_ENDPOINT + 'k8srepos',
+    NETWORKSLICETEMPLATE_URL: OSM_NST_ENDPOINT + 'netslice_templates',
+    NETWORKSLICETEMPLATECONTENT_URL: OSM_NST_ENDPOINT + 'netslice_templates_content',
+    NSDINSTANCES_URL: OSM_NSLCM_ENDPOINT + 'ns_instances',
+    VNFINSTANCES_URL: OSM_NSLCM_ENDPOINT + 'vnfrs',
+    NSINSTANCESCONTENT_URL: OSM_NSLCM_ENDPOINT + 'ns_instances_content',
+    NSHISTORYOPERATIONS_URL: OSM_NSLCM_ENDPOINT + 'ns_lcm_op_occs',
+    NETWORKSLICEINSTANCESCONTENT_URL: OSM_NSILCM_ENDPOINT + 'netslice_instances_content',
+    NSTHISTORYOPERATIONS_URL: OSM_NSILCM_ENDPOINT + '/nsi_lcm_op_occs',
+    NSDESCRIPTORSCONTENT_URL: OSM_NSD_ENDPOINT + 'ns_descriptors_content',
+    NSDESCRIPTORS_URL: OSM_NSD_ENDPOINT + 'ns_descriptors',
+    VNFPACKAGESCONTENT_URL: OSM_VNFDPACKAGE_ENDPOINT + 'vnf_packages_content',
+    VNFPACKAGES_URL: OSM_VNFDPACKAGE_ENDPOINT + 'vnf_packages',
+    PDUINSTANCE_URL: OSM_PDU_ENDPOINT + 'pdu_descriptors',
+    PERMISSIONS_CONFIG_FILE: ASSETS_PATH + 'config/rolePermissions.json',
+    GRAFANA_URL: GRAFANA_ENDPOINT + '/d',
+    DOMAIN_URL: OSM_ADMIN_ENDPOINT + 'domains',
+    OSM_VERSION_URL: OSM_VERSION
+};
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
new file mode 100644 (file)
index 0000000..dbc2c98
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file environment variables
+ * This file can be replaced during build by using the `fileReplacements` array.
+ * `npm run build` replaces `environment.ts` with `environment.prod.ts`.
+ * The list of file replacements can be found in `angular.json`.
+ */
+
+import { version } from 'PACKAGEJSON';
+
+/** OSM Admin URL @constant */
+const OSM_ADMIN_ENDPOINT: string = 'osm/admin/v1/';
+/** OSM NS LCM URL @constant */
+const OSM_NSLCM_ENDPOINT: string = 'osm/nslcm/v1/';
+/** OSM NST URL @constant */
+const OSM_NST_ENDPOINT: string = 'osm/nst/v1/';
+/** OSM NSI LCM URL @constant */
+const OSM_NSILCM_ENDPOINT: string = 'osm/nsilcm/v1/';
+/** OSM VNFD PACKAGES URL @constant */
+const OSM_VNFDPACKAGE_ENDPOINT: string = 'osm/vnfpkgm/v1/';
+/** OSM PDU URL @constant */
+const OSM_PDU_ENDPOINT: string = 'osm/pdu/v1/';
+/** OSM NSD URL @constant */
+const OSM_NSD_ENDPOINT: string = 'osm/nsd/v1/';
+/** Assets root path @constant */
+const ASSETS_PATH: string = 'assets/';
+/** OSM Version @constant */
+const OSM_VERSION: string = 'osm/version';
+/** Grafana End-Point @constant */
+// tslint:disable-next-line: no-http-string
+const GRAFANA_ENDPOINT: string = 'http://' + window.location.hostname + ':3000';
+
+/** Exporting a const @exports environment */
+// tslint:disable-next-line: typedef
+export const environment = {
+    production: false,
+    packageSize: 15,
+    paginationNumber: 10, //Possible values are 10, 25, 50, 100
+    packageVersion: version,
+    // tslint:disable-next-line: no-http-string
+    MAPLATLONGAPI_URL: 'http://photon.komoot.de/api/?q={value}&limit=5',
+    GENERATETOKEN_URL: OSM_ADMIN_ENDPOINT + 'tokens',
+    PROJECTS_URL: OSM_ADMIN_ENDPOINT + 'projects',
+    USERS_URL: OSM_ADMIN_ENDPOINT + 'users',
+    ROLES_URL: OSM_ADMIN_ENDPOINT + 'roles',
+    VIMACCOUNTS_URL: OSM_ADMIN_ENDPOINT + 'vim_accounts',
+    WIMACCOUNTS_URL: OSM_ADMIN_ENDPOINT + 'wim_accounts',
+    SDNCONTROLLER_URL: OSM_ADMIN_ENDPOINT + 'sdns',
+    K8SCLUSTER_URL: OSM_ADMIN_ENDPOINT + 'k8sclusters',
+    K8REPOS_URL: OSM_ADMIN_ENDPOINT + 'k8srepos',
+    NETWORKSLICETEMPLATE_URL: OSM_NST_ENDPOINT + 'netslice_templates',
+    NETWORKSLICETEMPLATECONTENT_URL: OSM_NST_ENDPOINT + 'netslice_templates_content',
+    NSDINSTANCES_URL: OSM_NSLCM_ENDPOINT + 'ns_instances',
+    VNFINSTANCES_URL: OSM_NSLCM_ENDPOINT + 'vnfrs',
+    NSINSTANCESCONTENT_URL: OSM_NSLCM_ENDPOINT + 'ns_instances_content',
+    NSHISTORYOPERATIONS_URL: OSM_NSLCM_ENDPOINT + 'ns_lcm_op_occs',
+    NETWORKSLICEINSTANCESCONTENT_URL: OSM_NSILCM_ENDPOINT + 'netslice_instances_content',
+    NSTHISTORYOPERATIONS_URL: OSM_NSILCM_ENDPOINT + 'nsi_lcm_op_occs',
+    NSDESCRIPTORSCONTENT_URL: OSM_NSD_ENDPOINT + 'ns_descriptors_content',
+    NSDESCRIPTORS_URL: OSM_NSD_ENDPOINT + 'ns_descriptors',
+    VNFPACKAGESCONTENT_URL: OSM_VNFDPACKAGE_ENDPOINT + 'vnf_packages_content',
+    VNFPACKAGES_URL: OSM_VNFDPACKAGE_ENDPOINT + 'vnf_packages',
+    PDUINSTANCE_URL: OSM_PDU_ENDPOINT + 'pdu_descriptors',
+    PERMISSIONS_CONFIG_FILE: ASSETS_PATH + 'config/rolePermissions.json',
+    GRAFANA_URL: GRAFANA_ENDPOINT + '/d',
+    DOMAIN_URL: OSM_ADMIN_ENDPOINT + 'domains',
+    OSM_VERSION_URL: OSM_VERSION
+};
diff --git a/src/favicon.ico b/src/favicon.ico
new file mode 100644 (file)
index 0000000..c588094
Binary files /dev/null and b/src/favicon.ico differ
diff --git a/src/index.html b/src/index.html
new file mode 100644 (file)
index 0000000..ea9b726
--- /dev/null
@@ -0,0 +1,34 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+-->
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>OSM</title>
+    <base href="/">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <!-- <meta http-equiv="Content-Security-Policy"
+    content="base-uri 'self';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline' fonts.googleapis.com cdnjs.cloudflare.com;media-src 'self';form-action 'self';child-src 'none';"> -->
+    <link rel="icon" type="image/x-icon" href="favicon.ico">
+</head>
+
+<body>
+    <app-root></app-root>
+</body>
+
+</html>
diff --git a/src/karma.conf.js b/src/karma.conf.js
new file mode 100644 (file)
index 0000000..7dda620
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+
+module.exports = function (config) {
+    config.set({
+        basePath: '',
+        frameworks: ['jasmine', '@angular-devkit/build-angular'],
+        plugins: [
+            require('karma-jasmine'),
+            require('karma-chrome-launcher'),
+            require('karma-jasmine-html-reporter'),
+            require('karma-coverage-istanbul-reporter'),
+            require('@angular-devkit/build-angular/plugins/karma')
+        ],
+        client: {
+            clearContext: false // leave Jasmine Spec Runner output visible in browser
+        },
+        coverageIstanbulReporter: {
+            dir: require('path').join(__dirname, '../coverage/osm'),
+            reports: ['html', 'lcovonly', 'text-summary'],
+            fixWebpackSourcePaths: true
+        },
+        reporters: ['progress', 'kjhtml'],
+        port: 9876,
+        colors: true,
+        logLevel: config.LOG_INFO,
+        autoWatch: true,
+        browsers: ['Chrome'],
+        singleRun: false
+    });
+};
diff --git a/src/main.ts b/src/main.ts
new file mode 100644 (file)
index 0000000..fd921a3
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Main for the application.
+ */
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/AppModule';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+    enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule)
+    .catch((err: Error): void => { console.error(err); });
diff --git a/src/models/CommonModel.ts b/src/models/CommonModel.ts
new file mode 100644 (file)
index 0000000..e3d44e2
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+import { HttpHeaders } from '@angular/common/http';
+
+/**
+ * @file  Model for Commonly used information.
+ */
+/**
+ * handle count @enum
+ */
+export enum CONSTANTNUMBER {
+    randomNumber = 4,
+    osmapviewlong = 77.673,
+    osmapviewlat = 19.166,
+    chennailong = 80.2809,
+    chennailat = 13.0781,
+    bangalorelong = 77.5868,
+    bangalorelat = 12.9718,
+    mumbailong = 72.8342,
+    mumbailat = 18.9394,
+    tirvandrumlong = 76.9544,
+    tirvandrumlat = 8.5009,
+    oneMB = 1048576,
+    paginationDefaultValue = 10,
+    splitLongitude = 1,
+    splitLatitude = 2
+}
+/**
+ * handle count @enum
+ */
+export enum CONFIGCONSTANT {
+    operationalStateFirstStep = 'init',
+    operationalStateSecondStep = 'running',
+    operationalStateThirdStep = 'failed',
+    configStateFirstStep = 'init',
+    configStateSecondStep = 'configured',
+    configStateThirdStep = 'failed',
+    historyStateFirstStep = 'PROCESSING',
+    historyStateSecondStep = 'COMPLETED',
+    historyStateThirdStep = 'FAILED',
+    wimOperationalStateFirstStep = 'PROCESSING',
+    wimOperationalStateStateSecondStep = 'ENABLED',
+    wimOperationalStateThirdStep = 'ERROR',
+    vimOperationalStateFirstStep = 'PROCESSING',
+    vimOperationalStateStateSecondStep = 'ENABLED',
+    vimOperationalStateThirdStep = 'ERROR',
+    sdnOperationalStateFirstStep = 'PROCESSING',
+    sdnOperationalStateStateSecondStep = 'ENABLED',
+    sdnOperationalStateThirdStep = 'ERROR',
+    k8OperationalStateFirstStep = 'PROCESSING',
+    k8OperationalStateStateSecondStep = 'ENABLED',
+    k8OperationalStateThirdStep = 'ERROR'
+}
+/** Interface for Post options */
+export interface POSTAPIRESOURCE {
+    apiURLHeader: APIURLHEADER;
+    payload?: object;
+}
+/** Interface for ApiURL Header */
+export interface APIURLHEADER {
+    url: string;
+    httpOptions?: APIHEADERS;
+}
+/** Interface for the Get Method with response type */
+export interface GETAPIURLHEADER {
+    headers: HttpHeaders;
+    responseType: string;
+}
+/** Interface for Httpoptions Header */
+interface APIHEADERS {
+    headers: HttpHeaders;
+}
+/** Interface for the Error */
+export interface ERRORDATA {
+    error: ERRORDETAILSDATA;
+}
+/** Interface for the Error Details */
+interface ERRORDETAILSDATA {
+    detail: string;
+    code?: string;
+    status?: number;
+    text?: Function;
+}
+/** Handle the URL params */
+export interface URLPARAMS {
+    page: string;
+    id: string;
+    titleName?: string;
+    forceDeleteType?: boolean;
+    name?: string;
+    memberIndex?: object;
+    nsConfig?: object;
+    projectID?: string;
+    username?: string;
+}
+/** Handle the Delete params */
+export interface DELETEPARAMS {
+    identifier: string;
+    name?: string;
+    shortName: string;
+    projectName?: string;
+    userName?: string;
+    username?: string;
+    page?: string;
+    id?: string;
+}
+
+/** Interface for the Delete Details */
+export interface MODALCLOSERESPONSEDATA {
+    message: string;
+}
+
+/** Interface for the modal closer */
+export interface MODALCLOSERESPONSEWITHCP {
+    message: string;
+    connection_point?: string;
+}
+
+/** Interface for local storage settings */
+export interface LOCALSTORAGE {
+    id_token?: string;
+    project_id?: string;
+    expires?: string;
+    username?: string;
+    project?: string;
+    project_name?: string;
+    id?: string;
+    admin?: boolean;
+    isAdmin?: string;
+    token_state?: string;
+}
+/** Interface for Tar settings */
+export interface TARSETTINGS {
+    name?: string;
+    'type'?: string;
+    readAsString?: Function;
+    buffer: ArrayBuffer;
+}
+/** Interface for Package information */
+export interface PACKAGEINFO {
+    id?: string;
+    packageType?: string;
+    descriptor: string;
+}
+
+/** Interface For the Pagination pager in ng-smarttable */
+export interface PAGERSMARTTABLE {
+    display: boolean;
+    perPage: number;
+}
+/** Interface for breadcrumb item */
+export interface BREADCRUMBITEM {
+    title: string;
+    url: string;
+}
+/** Interface For the Pagination pager in ng-smarttable */
+export interface SMARTTABLECLASS {
+    // tslint:disable-next-line: no-reserved-keywords
+    class: string;
+}
+/** Constants of the VIM Types */
+export const VIM_TYPES: TYPESECTION[] = [
+    { value: 'openstack', title: 'Openstack' },
+    { value: 'aws', title: 'AWS' },
+    { value: 'vmware', title: 'VMware vCD' },
+    { value: 'openvim', title: 'OpenVIM' },
+    { value: 'opennebula', title: 'OpenNebula' },
+    { value: 'azure', title: 'Azure' }
+];
+/** Constants of the SDN Types */
+export const SDN_TYPES: TYPESECTION[] = [
+    { value: 'arista', title: 'Arista' },
+    { value: 'floodlightof', title: 'Floodlight openflow' },
+    { value: 'odlof', title: 'OpenDaylight openflow' },
+    { value: 'onosof', title: 'ONOS openflow' },
+    { value: 'onos_vpls', title: 'ONOS vpls' }
+];
+/** Constants of the WIM Types */
+export const WIM_TYPES: TYPESECTION[] = [
+    { value: 'arista', title: 'Arista' },
+    { value: 'dynpac', title: 'DynPac' },
+    { value: 'floodlightof', title: 'Floodlight openflow' },
+    { value: 'odlof', title: 'OpenDaylight openflow' },
+    { value: 'onosof', title: 'ONOS openflow' },
+    { value: 'onos_vpls', title: 'ONOS vpls' },
+    { value: 'tapi', title: 'TAPI' }
+];
+/** Interface for List, Add WIM & SDN Types */
+export interface TYPESECTION {
+    value: string;
+    title: string;
+}
diff --git a/src/models/K8sModel.ts b/src/models/K8sModel.ts
new file mode 100644 (file)
index 0000000..4e83483
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for K8s related information.
+ */
+
+/** Interface for K8SCLUSTERDATA */
+export interface K8SCLUSTERDATA {
+    credentials: Credentials;
+    description: string;
+    k8s_version: number;
+    name: string;
+    namespace: string;
+    nets: Nets;
+    schema_version: string;
+    vim_account: string;
+    _admin: Admin;
+    _id: string;
+}
+/** Interface for K8SCLUSTERDATA */
+export interface K8SREPODATA {
+    description: string;
+    name: string;
+    schema_version: string;
+    'type': string;
+    url: string;
+    vim_account: string;
+    _admin: Admin;
+    _id: string;
+}
+/** Interface for the Credentials */
+interface Credentials{
+    apiVersion: string;
+    clusters: Clusters[];
+    contexts: Contexts[];
+    'current-context': string;
+    kind: string;
+    preferences: {};
+    users: Users[];
+}
+/** Interface for the Clusters */
+interface Clusters {
+    cluster: Cluster;
+    name: string;
+}
+/** Interface for the Cluster */
+interface Cluster {
+    'certificate-authority-data': string;
+    server: string;
+}
+/** Interface for the Contexts */
+interface Contexts{
+    context: Context;
+    name: string;
+}
+/** Interface for the Contexts */
+interface Context {
+    cluster: string;
+    user: string;
+}
+/** Interface for the Users */
+interface Users{
+    name: string;
+    user: User;
+}
+/** Interface for the Users */
+interface User {
+    'client-certificate-data': string;
+    'client-key-data': string;
+}
+/** Interface for the K8SCLUSTERDATA nets */
+interface Nets{
+    net1: string;
+}
+/** Interface for the K8SCLUSTERDATA _admin */
+interface Admin{
+    created: string;
+    current_operation: number;
+    'helm-chart': HelmChart;
+    'juju-bundle': JujuBundle;
+    operationalState: string;
+    modified: string;
+}
+/** Interface for the K8SCLUSTERDATA _admin Helm chart */
+interface HelmChart {
+    created: boolean;
+    id: string;
+}
+/** Interface for the K8SCLUSTERDATA _admin Juju Bundle */
+interface JujuBundle {
+    error_msg: string;
+}
+/** Interface for the K8SCLUSTERDATA Return to Display */
+export interface K8SCLUSTERDATADISPLAY{
+    name: string;
+    identifier: string;
+    operationalState: string;
+    version: number;
+    created: string;
+    modified: string;
+    pageType: string;
+}
+/** Interface for the K8SCLUSTERDATA Return to Display */
+export interface K8SREPODATADISPLAY {
+    name: string;
+    identifier: string;
+    url: string;
+    'type': string;
+    created: string;
+    modified: string;
+    pageType: string;
+}
diff --git a/src/models/MenuModel.ts b/src/models/MenuModel.ts
new file mode 100644 (file)
index 0000000..dd77e0d
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for Commonly used information.
+ */
+/** Constants of the Menu child active class */
+const childActiveClass: string[] = ['active'];
+/** Constants of the Menu Items */
+export const MENU_ITEMS: MENUITEMS[] = [
+    {
+        liClass: 'round-edge-top-3',
+        anchorTagClass: 'link round-edge-top-3 individual',
+        clickFunction: 'nosubmenu',
+        routerLink: '/',
+        routerLinkActive: ['parentactive'],
+        routerLinkActiveOptions: true,
+        icon: 'fas fa-th-large',
+        menuName: 'PAGE.DASHBOARD.DASHBOARD',
+        isChildExists: false
+    },
+    {
+        liClass: 'header-menu',
+        anchorTagClass: 'heading text-uppercase',
+        menuName: 'PROJECT',
+        isChildExists: false
+    },
+    {
+        liClass: 'round-edge-top-3',
+        anchorTagClass: 'parentlink round-edge-top-3 mr-top-5',
+        clickFunction: 'packages',
+        routerLink: '/packages',
+        routerLinkActive: ['menu-open', 'parentactive'],
+        routerLinkActiveOptions: false,
+        icon: 'fas fa-box',
+        menuName: 'PACKAGES',
+        isChildExists: true,
+        ulClass: 'sidebar-submenu',
+        childItems: [
+            {
+                liClass: '',
+                anchorTagClass: 'link',
+                routerLink: '/packages/ns',
+                routerLinkActive: childActiveClass,
+                routerLinkActiveOptions: false,
+                icon: 'fas fa-box-open',
+                menuName: 'NSPACKAGES',
+                isChildExists: false
+            },
+            {
+                liClass: '',
+                anchorTagClass: 'link',
+                routerLink: '/packages/vnf',
+                routerLinkActive: childActiveClass,
+                routerLinkActiveOptions: false,
+                icon: 'fas fa-box-open',
+                menuName: 'VNFPACKAGES',
+                isChildExists: false
+            },
+            {
+                liClass: '',
+                anchorTagClass: 'link',
+                routerLink: '/packages/netslice',
+                routerLinkActive: childActiveClass,
+                routerLinkActiveOptions: false,
+                icon: 'fas fa-layer-group',
+                menuName: 'PAGE.DASHBOARD.NETSLICETEMPLATE',
+                isChildExists: false
+            }
+        ]
+    },
+    {
+        liClass: 'mt-1 round-edge-bottom-3 border-bottom-none',
+        anchorTagClass: 'parentlink round-edge-bottom-3 border-bottom-none',
+        clickFunction: 'instances',
+        routerLink: '/instances',
+        routerLinkActive: ['menu-open', 'parentactive'],
+        routerLinkActiveOptions: false,
+        icon: 'fa fa-paper-plane',
+        menuName: 'INSTANCES',
+        isChildExists: true,
+        ulClass: 'sidebar-submenu',
+        childItems: [
+            {
+                liClass: '',
+                anchorTagClass: 'link',
+                routerLink: '/instances/ns',
+                routerLinkActive: childActiveClass,
+                routerLinkActiveOptions: false,
+                icon: 'fas fa-sitemap',
+                menuName: 'NSINSTANCES',
+                isChildExists: false
+            },
+            {
+                liClass: '',
+                anchorTagClass: 'link',
+                routerLink: '/instances/vnf',
+                routerLinkActive: childActiveClass,
+                routerLinkActiveOptions: false,
+                icon: 'fas fa-hdd',
+                menuName: 'VNFINSTANCES',
+                isChildExists: false
+            },
+            {
+                liClass: '',
+                anchorTagClass: 'link',
+                routerLink: '/instances/pdu',
+                routerLinkActive: childActiveClass,
+                routerLinkActiveOptions: false,
+                icon: 'fas fa-hdd',
+                menuName: 'PDUINSTANCES',
+                isChildExists: false
+            },
+            {
+                liClass: '',
+                anchorTagClass: 'link',
+                routerLink: '/instances/netslice',
+                routerLinkActive: childActiveClass,
+                routerLinkActiveOptions: false,
+                icon: 'fas fa-layer-group',
+                menuName: 'PAGE.DASHBOARD.NETSLICEINSTANCE',
+                isChildExists: false
+            }
+        ]
+    },
+    {
+        liClass: 'round-edge-top-3 round-edge-bottom-3 mr-top-5',
+        anchorTagClass: 'link round-edge-top-3 round-edge-bottom-3 individual',
+        clickFunction: 'nosubmenu',
+        routerLink: '/sdn/details',
+        routerLinkActive: ['parentactive'],
+        routerLinkActiveOptions: true,
+        icon: 'fas fa-globe',
+        menuName: 'SDNCONTROLLER',
+        isChildExists: false
+    },
+    {
+        liClass: 'round-edge-top-3 round-edge-bottom-3 mr-top-5',
+        anchorTagClass: 'link round-edge-top-3 round-edge-bottom-3 individual',
+        clickFunction: 'nosubmenu',
+        routerLink: '/vim',
+        routerLinkActive: ['parentactive'],
+        routerLinkActiveOptions: false,
+        icon: 'fas fa-server',
+        menuName: 'VIMACCOUNTS',
+        isChildExists: false
+    },
+    {
+        liClass: 'round-edge-top-3 round-edge-bottom-3 mr-top-5',
+        anchorTagClass: 'parentlink round-edge-top-3 round-edge-bottom-3',
+        clickFunction: 'k8s',
+        routerLink: '/k8s',
+        routerLinkActive: ['menu-open', 'parentactive'],
+        routerLinkActiveOptions: false,
+        icon: 'fas fa-asterisk',
+        menuName: 'PAGE.K8S.MENUK8S',
+        isChildExists: true,
+        ulClass: 'sidebar-submenu',
+        childItems: [
+            {
+                liClass: '',
+                anchorTagClass: 'link',
+                routerLink: '/k8s/cluster',
+                routerLinkActive: childActiveClass,
+                routerLinkActiveOptions: false,
+                icon: 'fas fa-project-diagram',
+                menuName: 'PAGE.K8S.MENUK8SCLUSTER',
+                isChildExists: false
+            },
+            {
+                liClass: '',
+                anchorTagClass: 'link',
+                routerLink: '/k8s/repo',
+                routerLinkActive: childActiveClass,
+                routerLinkActiveOptions: false,
+                icon: 'fas fa-flag',
+                menuName: 'PAGE.K8S.MENUK8SREPO',
+                isChildExists: false
+            }
+        ]
+    },
+    {
+        liClass: 'round-edge-top-3 round-edge-bottom-3 mr-top-5',
+        anchorTagClass: 'link round-edge-top-3 round-edge-bottom-3 individual',
+        clickFunction: 'nosubmenu',
+        routerLink: '/wim/details',
+        routerLinkActive: ['parentactive'],
+        routerLinkActiveOptions: true,
+        icon: 'fas fa-sitemap',
+        menuName: 'WIMACCOUNTS',
+        isChildExists: false
+    },
+    {
+        liClass: 'header-menu',
+        anchorTagClass: 'heading text-uppercase',
+        menuName: 'ADMIN',
+        isChildExists: false
+    },
+    {
+        liClass: 'mt-1 round-edge-top-3',
+        anchorTagClass: 'link round-edge-top-3 individual',
+        clickFunction: 'nosubmenu',
+        routerLink: '/projects',
+        routerLinkActive: ['parentactive'],
+        routerLinkActiveOptions: true,
+        icon: 'fas fa-folder',
+        menuName: 'PAGE.DASHBOARD.PROJECTS',
+        isChildExists: false
+    },
+    {
+        liClass: 'mt-1 mb-1',
+        anchorTagClass: 'link individual',
+        clickFunction: 'nosubmenu',
+        routerLink: '/users/details',
+        routerLinkActive: ['parentactive'],
+        routerLinkActiveOptions: true,
+        icon: 'fas fa-users',
+        menuName: 'PAGE.DASHBOARD.USERS',
+        isChildExists: false
+    },
+    {
+        liClass: 'round-edge-bottom-3',
+        anchorTagClass: 'link round-edge-bottom-3 individual',
+        clickFunction: 'nosubmenu',
+        routerLink: '/roles',
+        routerLinkActive: ['parentactive'],
+        routerLinkActiveOptions: true,
+        icon: 'fas fa-user-tag',
+        menuName: 'ROLES',
+        isChildExists: false
+    }
+];
+
+/** Interface for Post options */
+export interface MENUITEMS {
+    ulClass?: string;
+    liClass: string;
+    anchorTagClass: string;
+    clickFunction?: string;
+    routerLink?: string;
+    routerLinkActive?: string[];
+    routerLinkActiveOptions?: boolean;
+    icon?: string;
+    menuName: string;
+    isChildExists: boolean;
+    childItems?: MENUITEMS[];
+}
diff --git a/src/models/NSDModel.ts b/src/models/NSDModel.ts
new file mode 100644 (file)
index 0000000..95331a2
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for NSD related information.
+ */
+
+import { VNFDAdminDetails } from './VNFDModel';
+
+/** Interface for NSData */
+export interface NSData {
+    shortName: string;
+    identifier: string;
+    description: string;
+    vendor: string;
+    version: string;
+    page?: string;
+    name?: string;
+    projectName?: string;
+    userName?: string;
+    username?: string;
+}
+
+/** Interface for the nscompose descriptors content */
+export interface NSDDetails {
+    'connection-point': CONNECTIONPOINT[];
+    'constituent-vnfd': CONSTITUENTVNFD[];
+    description: string;
+    id: string;
+    logo: string;
+    name: string;
+    'short-name': string;
+    vendor: string;
+    version: string;
+    vld: VLD[];
+    _admin: VNFDAdminDetails;
+    _id: string;
+    'constituent-vnfr-ref': string[];
+}
+
+/** Interface for the connection-point */
+export interface CONNECTIONPOINT {
+    name: string;
+    'vld-id-ref': string;
+}
+
+/** Interface for the constituent-vnfd */
+export interface CONSTITUENTVNFD {
+    'member-vnf-index': number;
+    'vnfd-id-ref': string;
+}
+
+/** Interface for the vld */
+export interface VLD {
+    id: string;
+    'mgmt-network': boolean;
+    name: string;
+    'short-name'?: string;
+    'type': string;
+    'vnfd-connection-point-ref'?: VNFDCONNECTIONPOINTREF[];
+    'vim-network-name': string;
+}
+
+/** Interface for VNFDCONNECTIONPOINTREF */
+export interface VNFDCONNECTIONPOINTREF {
+    'member-vnf-index-ref': number;
+    'vnfd-connection-point-ref': string;
+    'vnfd-id-ref': string;
+}
+/** Interface Nodes Creation */
+export interface COMPOSERNODES {
+    id: string;
+    reflexive: Boolean;
+    'type': string;
+    name?: string;
+    nodeIndex?: number;
+    selectorId?: string;
+    x?: number;
+    y?: number;
+    fx?: number;
+    fy?: number;
+}
+
+/** Interface for the Tick */
+export interface Tick {
+    target: TickPath;
+    source: TickPath;
+    left: boolean;
+    right: boolean;
+}
+
+/** Interface for the Path */
+export interface TickPath {
+    x: number;
+    y: number;
+    id: string;
+    'type'?: string;
+}
+
+/** Interface for the NSD */
+interface NSD {
+    'constituent-vnfd': CONSTITUENTVNFD[];
+    description: string;
+    id: string;
+    name: string;
+    'short-name': string;
+    vendor: string;
+    version: string;
+    vld: VLD[];
+    _admin: VNFDAdminDetails;
+    _id: string;
+}
+/** Interface for the GRAPHDETAILS */
+export interface GRAPHDETAILS {
+    width: number;
+    height: number;
+    nodeHeight: number;
+    nodeWidth: number;
+    textX: number;
+    textY: number;
+    radius: number;
+    distance: number;
+    strength: number;
+    forcex: number;
+    forcey: number;
+    sourcePaddingYes: number;
+    sourcePaddingNo: number;
+    targetPaddingYes: number;
+    targetPaddingNo: number;
+    alphaTarget: number;
+    imageX: number;
+    imageY: number;
+    shiftKeyCode: number;
+}
+
+/** Interface for the NS Create params */
+export interface NSCREATEPARAMS {
+    nsName: string;
+    nsDescription: string;
+    nsdId: string;
+    vimAccountId: string;
+    vld: string;
+    ssh_keys: string[];
+}
+
+/** Interface for the NSI Create params */
+export interface NSICREATEPARAMS {
+    nsName: string;
+    nsDescription: string;
+    nstId: string;
+    vimAccountId: string;
+    'netslice-vld': string;
+    ssh_keys: string[];
+}
diff --git a/src/models/NSInstanceModel.ts b/src/models/NSInstanceModel.ts
new file mode 100644 (file)
index 0000000..72cd42b
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for NS Instance related information.
+ */
+
+import { CONSTITUENTVNFD, VLD, VNFDCONNECTIONPOINTREF } from 'NSDModel';
+import { VNFDAdminDetails } from 'VNFDModel';
+
+/** Interface for NSInstanceDetails */
+export interface NSInstanceDetails {
+    'orchestration-progress': JSON;
+    'constituent-vnfr-ref': string[];
+    'operational-events': string[];
+    admin: Admin;
+    'ssh-authorized-key': string;
+    _admin: _Admin;
+    'admin-status': string;
+    'operational-status': string;
+    'datacenter': string;
+    nsd: NSD;
+    name: string;
+    'name-ref': string;
+    'short-name': string;
+    id: string;
+    'nsd-name-ref': string;
+    description: string;
+    'detailed-status': string;
+    'config-status': string;
+    'resource-orchestrator': string;
+    'nsd-ref': string;
+    vld: VLD[];
+    instantiate_params: InstantiateParam;
+    additionalParamsForNs: AdditionalParamForN;
+    _id?: string;
+}
+
+/** Interface for Admin */
+interface Admin {
+    deployed: DeployedAdmin;
+}
+
+/** Interface for DeployedAdmin */
+interface DeployedAdmin {
+    RO: ROAdmin;
+}
+
+/** Interface for ROAdmin */
+interface ROAdmin {
+    'nsr_status': string;
+}
+
+/** Interface for _Admin */
+// tslint:disable-next-line:class-name
+interface _Admin {
+    'projects_write': string[];
+    deployed: DeployedAdmin;
+    nslcmop: string;
+    nsState: string;
+    modified: number;
+    projects_read: string[];
+    created: string;
+}
+
+/** Interface for Deployed_Admin */
+interface DeployedAdmin {
+    VCA: string[];
+    RO: ROAdmin;
+}
+
+/** Interface for RO_Admin */
+interface ROAdmin {
+    'nsr_status': string;
+    'nsr_id': string;
+    'nsd_id': string;
+    vnfd: VNFD[];
+}
+
+/** Interface for VNFD */
+interface VNFD {
+    'member-vnf-index': number;
+    id: string;
+}
+
+/** Interface for NSD */
+export interface NSD {
+    description: string;
+    vld: NSDVLD[];
+    _admin: VNFDAdminDetails;
+    name: string;
+    version: string;
+    _id: string;
+    'short-name': string;
+    id: string;
+    'constituent-vnfd': CONSTITUENTVNFD[];
+    vendor: string;
+    vdur: string[];
+    'connection-point': CONNECTIONPOINT[];
+}
+
+/** Interface for _AdminDetails */
+// tslint:disable-next-line:class-name
+export interface _AdminDetails {
+    usageState: string;
+    projects_write: string[];
+    projects_read: string[];
+    operationalState: string;
+    modified: string;
+    storage: Storage;
+    onboardingState: string;
+    userDefinedData: JSON;
+    created: number;
+}
+
+/** Interface for Storage */
+interface Storage {
+    path: string;
+    'pkg-dir': string;
+    zipfile: string;
+    folder: string;
+    descriptor: string;
+    fs: string;
+}
+
+/** Interface for NSDVLD */
+export interface NSDVLD {
+    'vim-id': string;
+    'status-detailed': string;
+    name: string;
+    status: string;
+    'vim-network-name': string;
+    id: string;
+    'type': string;
+    'vnfd-connection-point-ref': VNFDCONNECTIONPOINTREF[];
+    'short-name': string;
+}
+
+/** Interface for InstantiateParam */
+interface InstantiateParam {
+    nsdId: string;
+    nsName: string;
+    nsDescription: string;
+    vimAccountId: string;
+}
+
+/** Interface for AdditionalParamForN */
+interface AdditionalParamForN {
+    _id: string;
+    'ns-instance-config-ref': string;
+    'crete-time': string;
+}
+
+/** interface for the History nsdInstanceData */
+export interface NSDInstanceData {
+    id?: string;
+    lcmOperationType?: string;
+    operationState?: string;
+    startTime?: number;
+    statusEnteredTime?: number;
+    identifier: string;
+    name: string;
+    NsdName: string;
+    OperationalStatus: string;
+    ConfigStatus: string;
+    DetailedStatus: string;
+    state?: string;
+    memberIndex?: object;
+    nsConfig?: object;
+}
+
+/** Interface for the nsInfo */
+export interface NSINFO {
+    nsInstanceID: string;
+    nsName: string;
+    nsOperationalStatus: string;
+    nsConfigStatus: string;
+    nsDetailedStatus: string;
+    nsResourceOrchestrator: string;
+}
+
+/** Interface for the NSINSTANCENODES */
+export interface NSINSTANCENODES {
+    id?: string;
+    nodeTypeRef?: string;
+    name?: string;
+    'type'?: string;
+    vnfdCP?: VNFDCONNECTIONPOINTREF[];
+    vimNetworkName?: string;
+    shortName?: string;
+    cp?: CONNECTIONPOINT[];
+    vdur?: string[];
+    vld?: NSDVLD[];
+    nsID?: string;
+    vnfdID?: string;
+    vimID?: string;
+    vndfrID?: string;
+    ipAddress?: string;
+    memberIndex?: string;
+    vnfdRef?: string;
+    vndfCPRef?: string;
+    selectorId?: string;
+}
+
+/** Interface for the connection-point */
+export interface CONNECTIONPOINT {
+    'connection-point-id': string;
+    name: string;
+    id: string;
+}
+
+/** Interface for Exec NS Primitive */
+export interface NSPrimitive {
+    'primitive': string;
+    'primitive_params': NSPrimitiveParams[];
+    'member_vnf_index': string;
+}
+
+/** Interface for Exec NS Primitive Params */
+export interface NSPrimitiveParams {
+    primitive_params_name: string;
+    primitive_params_value: string;
+}
+
+/** Interface Nodes Creation */
+export interface COMPOSERNODES {
+    id: string;
+    reflexive: Boolean;
+    nodeTypeRef: string;
+    name?: string;
+    nodeIndex?: number;
+    selectorId?: string;
+    x?: number;
+    y?: number;
+    fx?: number;
+    fy?: number;
+    shortName?: string;
+    vimNetworkName?: string;
+    'type'?: string;
+    vnfdRef?: string;
+    memberIndex?: string;
+    vimID?: string;
+    vndfrID?: string;
+    ipAddress?: string;
+    nsID?: string;
+    vnfdID?: string;
+}
+
+/** Interface for the Virtual Link Info */
+export interface VLINFO {
+    id: string;
+    name: string;
+    'type': string;
+    shortName: string;
+    vimNetworkName: string;
+}
+
+/** Interface for the VNFR Info */
+export interface VNFRINFO{
+    vimID: string;
+    _id: string;
+    ip: string;
+    nsrID: string;
+    id: string;
+    vnfdRef: string;
+    vnfdId: string;
+    memberIndex: string;
+}
diff --git a/src/models/NSTopologyModel.ts b/src/models/NSTopologyModel.ts
new file mode 100644 (file)
index 0000000..7a1dc62
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for NS topology related information.
+ */
+
+/** Interface for the GRAPHDETAILS */
+export interface GRAPHDETAILS {
+    width: number;
+    height: number;
+    nodeHeight: number;
+    nodeWidth: number;
+    textX: number;
+    textY: number;
+    radius: number;
+    distance: number;
+    strength: number;
+    forcex: number;
+    forcey: number;
+    sourcePaddingYes: number;
+    sourcePaddingNo: number;
+    targetPaddingYes: number;
+    targetPaddingNo: number;
+    alphaTarget: number;
+    imageX: number;
+    imageY: number;
+    shiftKeyCode: number;
+}
+/** Interface for the Path */
+export interface TickPath {
+    x: number;
+    y: number;
+    id: string;
+    'type'?: string;
+}
+/** Interface for the Tick */
+export interface Tick {
+    target: TickPath;
+    source: TickPath;
+    left: boolean;
+    right: boolean;
+}
diff --git a/src/models/NetworkSliceModel.ts b/src/models/NetworkSliceModel.ts
new file mode 100644 (file)
index 0000000..eda0b92
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for Network Slice Template related information.
+ */
+
+/** Interface for MetricModel */
+export interface NetworkSliceModel {
+    'netslice-subnet': NetsliceSubnet[];
+    id: string;
+    'SNSSAI-identifier': SNSSAIIdentifier;
+    'quality-of-service': QualityOfService;
+    name: string;
+    _id: string;
+    _admin: ADMIN;
+    'netslice-vld': NetsliceVld[];
+}
+
+/** Interface for NetsliceSubnet */
+interface NetsliceSubnet {
+    description : string;
+    id: string;
+    'is-shared-nss': string;
+    'nsd-ref': string;
+}
+
+/** Interface for SNSSAIIdentifier */
+interface SNSSAIIdentifier {
+    'slice-service-type': string;
+}
+
+/** Interface for SNSSAIIdentifier */
+interface QualityOfService {
+    id: number;
+}
+
+/** Interface for Admin */
+interface ADMIN {
+    operationalState: string;
+    created: string;
+    projects_write: string[];
+    projects_read: string[];
+    usageState: string;
+    modified: string;
+    onboardingState: string;
+    userDefinedData: {};
+    storage : Storage;
+}
+
+/** Interface for Storage */
+interface Storage {
+    fs: string;
+    folder: string;
+    descriptor: string;
+    path: string;
+}
+
+/** Interface for NetsliceVld */
+interface NetsliceVld {
+    name: string;
+    id: string;
+    'nss-connection-point-ref': NssConnectionPointRef[];
+    'mgmt-network': boolean;
+    // tslint:disable-next-line:no-reserved-keywords
+    type: string;
+}
+
+/** Interface for NssConnectionPointRef */
+interface NssConnectionPointRef {
+    'nss-ref': string;
+    'nsd-connection-point-ref': string;
+}
+
+/** Interface for NetworkSliceData */
+export interface NetworkSliceData {
+    name: string;
+    identifier: string;
+    usageState: string;
+}
+
+/** Interface for Network Slice instance Data */
+export interface NSTInstanceDetails {
+    name: string;
+    id: string;
+    'nst-ref': string;
+    'operational-status': string;
+    'config-status': string;
+    'detailed-status': string;
+}
+/** interface for the Network Slice instance Data in datasource Table */
+export interface NSTInstanceData {
+    name: string;
+    identifier: string;
+    NstName: string;
+    OperationalStatus: string;
+    ConfigStatus: string;
+    DetailedStatus: string;
+}
diff --git a/src/models/PDUInstanceModel.ts b/src/models/PDUInstanceModel.ts
new file mode 100644 (file)
index 0000000..b628bdb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for PDU Instance related information.
+ */
+
+/** Interface for PDUInstanceDetails */
+export interface PDUInstanceDetails {
+    description: string;
+    interfaces: PDUInterfaces[];
+    name: string;
+    'type': string;
+    vim_accounts: string[];
+    _admin: ADMIN;
+    _id: string;
+    identifier?: string;
+}
+
+/** Interface for PDU interfaces */
+export interface PDUInterfaces {
+    'ip-address': string;
+    mgmt: boolean;
+    name: string;
+    'vim-network-name': string;
+}
+
+/** Interface for Admin */
+interface ADMIN {
+    created: string;
+    modified: string;
+    onboardingState: string;
+    operationalState: string;
+    projects_write: string[];
+    projects_read: string[];
+    usageState: string;
+}
diff --git a/src/models/ProjectModel.ts b/src/models/ProjectModel.ts
new file mode 100644 (file)
index 0000000..878bb47
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for project related information.
+ */
+
+/** Interface for ProjectDetails */
+export interface ProjectDetails {
+    _admin?: Admin;
+    _id?: string;
+    name?: string;
+    id?: string;
+}
+
+/** Interface for Admin */
+interface Admin {
+    created: number;
+    modified: number;
+    projects_read?: string[];
+}
+/** Interface for ProjectDetails in smarttable */
+export interface ProjectData {
+    projectName: string;
+    modificationDate: string;
+    creationDate: string;
+    page?: string;
+    id?: string;
+    project?: string;
+}
diff --git a/src/models/RoleModel.ts b/src/models/RoleModel.ts
new file mode 100644 (file)
index 0000000..3629b6c
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for role related information.
+ */
+
+/** Interface for ProjectDetails */
+export interface RoleDetails {
+    _admin?: Admin;
+    _id?: string;
+    name?: string;
+    id?: string;
+    permissions?: {};
+}
+
+/** Interface for Admin */
+interface Admin {
+    created: number;
+    modified: number;
+}
+/** Interface for Role data in smarttable */
+export interface RoleData {
+    name: string;
+    identifier: string;
+    modified: string;
+    created: string;
+    permissions: {};
+}
+/** Interface for Role configuration from role config file */
+export interface RoleConfig {
+    rolePermissions: PermissionGroup[];
+}
+/** Interface for Role permission group */
+export interface PermissionGroup {
+    title: string;
+    permissions: Permission[];
+}
+/** Interface for Role permission group */
+export interface Permission {
+    operation: string;
+    value: string | boolean;
+}
diff --git a/src/models/SDNControllerModel.ts b/src/models/SDNControllerModel.ts
new file mode 100644 (file)
index 0000000..2b5ab87
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model For SDN Controller model Information.
+ */
+
+/** Interface for SDNControllerModel */
+export interface SDNControllerModel {
+    dpid: string;
+    ip: string;
+    name: string;
+    password: string;
+    port: string;
+    schema_version: string;
+    'type': string;
+    user: string;
+    version: string;
+    _admin: ADMIN;
+    _id: string;
+}
+
+/** Interface for _ADMIN */
+interface ADMIN {
+    created: number;
+    current_operation: boolean;
+    deployed: Deployed;
+    'detailed-status': string;
+    modified: number;
+    operationalState: string;
+    operations: Operation[];
+    projects_read: string[];
+    projects_write: string[];
+}
+
+/** Interface for Deployed */
+interface Deployed {
+    RO: string;
+}
+
+/** Interface for Operations */
+interface Operation {
+    'detailed-status': string;
+    lcmOperationType: string;
+    operationParams: string;
+    operationState: string;
+    startTime: number;
+    statusEnteredTime: number;
+    worker: string;
+}
+
+/** Interface for SDNControllerList */
+export interface SDNControllerList {
+    name: string;
+    id?: string;
+    identifier: string;
+    'type': string;
+    operationalState: string;
+    ip: string;
+    port: string;
+}
diff --git a/src/models/UserModel.ts b/src/models/UserModel.ts
new file mode 100644 (file)
index 0000000..83dd08b
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file  Model for user related information.
+ */
+
+/** Interface for UserDetails */
+export interface UserDetails {
+    userDetail: UserDetail[];
+}
+
+/** Interface for UserDetail */
+export interface UserDetail {
+    username: string;
+    password?: string;
+    _id?: string;
+    projects: string[];
+    _admin?: Admin;
+    modified: string;
+    created: string;
+    identifier: string;
+    projectListName?: string;
+    project_role_mappings?: ProjectRoleMappings[];
+}
+
+/** Interface for user role mappings */
+export interface UserRoleMap {
+    project_role_mappings?: ProjectRoleMappings[];
+}
+
+/** Interface for Admin */
+interface Admin {
+    salt: string;
+    created: number;
+    modified: number;
+}
+/** Interface for UserDetail */
+export interface UserData {
+    username: string;
+    projects: string;
+    modified: string;
+    created: string;
+    identifier: string;
+}
+
+/** Interface for Project Roles Mappings */
+export interface ProjectRoleMappings {
+    project?: string;
+    project_name?: string;
+    role?: string;
+    role_name?: string;
+}
diff --git a/src/models/VNFDModel.ts b/src/models/VNFDModel.ts
new file mode 100644 (file)
index 0000000..908f552
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for VNFD related information.
+ */
+
+/** Interface for Project */
+export interface ProjectModel {
+    project_id: string;
+    project?: string;
+    project_name?: string;
+    expires: number;
+    _id: string;
+    id: string;
+    issued_at: number;
+    remote_port: number;
+    username: string;
+    remote_host: string;
+    admin: boolean;
+}
+
+/** Interface for ProjectDetails */
+export interface ProjectDetails {
+    _admin: AdminDetails;
+    name: string;
+    _id: string;
+}
+
+/** Interface for AdminDetails */
+interface AdminDetails {
+    modified: string;
+    created: string;
+}
+
+/** Interface for VNFD NODE Details */
+export interface VNFDNODE {
+    nodeTypeRef?: string;
+    'connection-point'?: CONNECTIONPOINT[];
+    description?: string;
+    id: string;
+    'internal-vld'?: InternalVLD[];
+    version?: string;
+    name?: string;
+    'mgmt-interface'?: MGMT;
+    _id?: string;
+    vdu?: VDU[];
+    _admin?: VNFDAdminDetails;
+    'short-name'?: string;
+    shortName?: string;
+    vendor?: string;
+    'type'?: string;
+    'cloud-init-file'?: string;
+    count?: number;
+    vduID?: string;
+    'interface'?: VNFDInterface[];
+    'vm-flavor'?: VMFlavor;
+    intVLID?: string;
+    'internal-connection-point'?: VLDInternalConnectionPoint[];
+    'monitoring-param'?: MonitoringParam[];
+    'ip-profile-ref'?: string;
+    'id-ref'?: string;
+    'ip-address'?: string;
+    reflexive?: boolean;
+    image?: string;
+}
+
+/** Interface for VNFDDetails */
+export interface VNFDDetails {
+    'connection-point': CONNECTIONPOINT[];
+    description: string;
+    id: string;
+    'internal-vld': InternalVLD[];
+    version: string;
+    name: string;
+    'mgmt-interface': MGMT;
+    _id: string;
+    vdu: VDU[];
+    _admin: VNFDAdminDetails;
+    'short-name': string;
+    vendor: string;
+}
+
+/** Interface for MGMT */
+interface MGMT {
+    cp: string;
+}
+
+/** Interface for VDU */
+export interface VDU {
+    nodeTypeRef?: string;
+    'cloud-init-file'?: string;
+    count?: number;
+    description?: string;
+    id?: string;
+    image?: string;
+    'interface'?: VNFDInterface[];
+    'internal-connection-point'?: VDUInternalConnectionPoint[];
+    name?: string;
+    'vm-flavor'?: VMFlavor;
+    vduInterface?: string;
+    'monitoring-param'?: MonitoringParam[];
+}
+
+/** Interface for VMFlavor */
+interface VMFlavor {
+    'storage-gb'?: string;
+    'memory-mb'?: string;
+    'vcpu-count'?: string;
+}
+
+/** Interface for VNFDInterface */
+export interface VNFDInterface {
+    'external-connection-point-ref'?: string;
+    'internal-connection-point-ref'?: string;
+    'mgmt-interface'?: boolean;
+    name?: string;
+    'type'?: string;
+    position?: boolean;
+    'virtual-interface'?: VirtualInterface;
+}
+
+/** Interface for VDU Internal Connection Point */
+export interface VDUInternalConnectionPoint {
+    id: string;
+    name?: string;
+    'short-name'?: string;
+    'type'?: string;
+}
+
+/** Interface for VirutalInterface */
+interface VirtualInterface {
+    'type': string;
+}
+
+/** Interface for the connection-point */
+export interface CONNECTIONPOINT {
+    nodeTypeRef?: string;
+    'connection-point-id'?: string;
+    name?: string;
+    id: string;
+    'type'?: string;
+}
+
+/** Interface for Internal VLD */
+export interface InternalVLD {
+    nodeTypeRef?: string;
+    id?: string;
+    'internal-connection-point'?: VLDInternalConnectionPoint[];
+    'ip-profile-ref'?: string;
+    name?: string;
+    'short-name'?: string;
+    'type'?: string;
+    'shortName'?: string;
+    'ipProfileRef'?: string;
+}
+
+/** Interface for VLD Internal Connection Point */
+export interface VLDInternalConnectionPoint {
+    nodeTypeRef?: string;
+    'ip-address'?: string;
+    'id-ref'?: string;
+    'shortName'?: string;
+}
+
+/** Interface for monitoring params */
+export interface MonitoringParam {
+    id: string;
+    'nfvi-metric'?: string;
+    'interface-name-ref'?: string;
+}
+
+/** Interface for _AdminDetails */
+// tslint:disable-next-line:class-name
+export interface VNFDAdminDetails {
+    created: number;
+    modified: string;
+    onboardingState: string;
+    operationalState: string;
+    projects_read: string[];
+    projects_write: string[];
+    storage: Storage;
+    'type': string;
+    usageState: string;
+    userDefinedData: JSON;
+}
+
+/** Interface for Storage */
+interface Storage {
+    descriptor: string;
+    folder: string;
+    fs: string;
+    path: string;
+    'pkg-dir': string;
+    zipfile: string;
+}
+
+/** Interface for VNFData */
+export interface VNFData {
+    name?: string;
+    id?: string;
+    shortName: string;
+    identifier: string;
+    description: string;
+    vendor: string;
+    version: string;
+    'type'?: string;
+}
+
+/** Interface for the Tick */
+export interface Tick {
+    target: TickPath;
+    source: TickPath;
+    left: boolean;
+    right: boolean;
+}
+
+/** Interface for the Path */
+export interface TickPath {
+    x: number;
+    y: number;
+    id: string;
+    'type'?: string;
+}
+
+/** Interface Nodes Creation */
+export interface COMPOSERNODES {
+    id: string;
+    reflexive?: boolean;
+    'type'?: string;
+    name?: string;
+    nodeTypeRef?: string;
+    x?: number;
+    y?: number;
+    fx?: number;
+    fy?: number;
+}
+
+/** Interface for the GRAPHDETAILS */
+export interface GRAPHDETAILS {
+    width: number;
+    height: number;
+    nodeHeight: number;
+    nodeWidth: number;
+    textX: number;
+    textY: number;
+    radius: number;
+    distance: number;
+    strength: number;
+    forcex: number;
+    forcey: number;
+    sourcePaddingYes: number;
+    sourcePaddingNo: number;
+    targetPaddingYes: number;
+    targetPaddingNo: number;
+    alphaTarget: number;
+    imageX: number;
+    imageY: number;
+    shiftKeyCode: number;
+}
diff --git a/src/models/VNFInstanceModel.ts b/src/models/VNFInstanceModel.ts
new file mode 100644 (file)
index 0000000..37f3bf3
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for VNF Instance related information.
+ */
+
+/** Interface for VNFInstanceDetails */
+export interface VNFInstanceDetails {
+    id: string;
+    'ip-address': string;
+    'vnfd-id': string;
+    'created-time': string;
+    'vim-account-id': string;
+    vdur: VDUR[];
+    'vnfd-ref': string;
+    'member-vnf-index-ref': string;
+    _id: string;
+    additionalParamsForVnf: string;
+    _admin: Admin;
+    'connection-point': ConnectionPoint[];
+    'nsr-id-ref': string;
+}
+
+/** Interface for VDUR */
+interface VDUR {
+    'ip-address': string;
+    'vim-id': string;
+    'internal-connection-point': string[];
+    name: string;
+    'vdu-id-ref': string;
+    'status-detailed': string;
+    'count-index': number;
+    interfaces: VDURInterface[];
+    _id: string;
+    status: string;
+}
+
+/** Interface for VDURInterface */
+interface VDURInterface {
+    'mac-address': string;
+    name: string;
+    'ns-vld-id': string;
+    'mgmt-vnf': string;
+    'ip-address': string;
+}
+
+/** Interface for _Admin */
+interface Admin {
+    created: number;
+    projects_read: string[];
+    modified: string;
+    projects_write: string[];
+}
+
+/** Interface for ConnectionPoint */
+interface ConnectionPoint {
+    id: string;
+    name: string;
+    'connection-point-id': string;
+}
+/** interface for the History nsdInstanceData */
+export interface VNFInstanceData {
+    identifier: string;
+    VNFD?: string;
+    VNFID?: string;
+}
diff --git a/src/models/VimAccountModel.ts b/src/models/VimAccountModel.ts
new file mode 100644 (file)
index 0000000..ea1cb71
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model for VimAccount Details related information.
+ */
+
+import { NSInstanceDetails } from 'NSInstanceModel';
+
+/** Interface for VimAccountDetails */
+export interface VimAccountDetails {
+    description: string;
+    'vim_tenant_name': string;
+    schema_version: string;
+    schema_type: string;
+    config: CONFIG;
+    _id: string;
+    vim_password: string;
+    _admin: ADMIN;
+    vim_url: string;
+    vim_user: string;
+    vim_type: string;
+    name: string;
+}
+
+/** Interface for _ADMIN */
+interface ADMIN {
+    projects_write: string[];
+    deployed: Deployed;
+    operationalState: string;
+    modified: string;
+    projects_read: string[];
+    'detailed-status': string;
+    created: string;
+}
+
+/** Interface for Deployed */
+interface Deployed {
+    'RO-account': string;
+    RO: string;
+}
+
+/** Interface for Config */
+export interface CONFIG {
+    sdn_controller?: string;
+    use_floating_ip?: string;
+    location?: string;
+    sdn_port_mapping?: string;
+    vim_network_name?: string;
+    security_groups?: string;
+    availabilityZone?: string;
+    region_name?: string;
+    insecure?: string;
+    use_existing_flavors?: string;
+    use_internal_endpoint?: string;
+    additional_conf?: string;
+    APIversion?: string;
+    project_domain_id?: string;
+    project_domain_name?: string;
+    user_domain_id?: string;
+    user_domain_name?: string;
+    keypair?: string;
+    dataplane_physical_net?: string;
+    microversion?: string;
+    vpc_cidr_block?: string;
+    flavor_info?: string;
+    orgname?: string;
+    vcenter_ip?: string;
+    vcenter_port?: string;
+    admin_username?: string;
+    vcenter_user?: string;
+    admin_password?: string;
+    vcenter_password?: string;
+    nsx_manager?: string;
+    vrops_site?: string;
+    nsx_user?: string;
+    vrops_user?: string;
+    nsx_password?: string;
+    vrops_password?: string;
+    subscription_id?: string;
+    resource_group?: string;
+    vnet_name?: string;
+    flavors_pattern?: string;
+}
+
+/** Interface for VIMData */
+export interface VIMData {
+    name?: string;
+    identifier: string;
+    'type': string;
+    operationalState: string;
+    description: string;
+    page?: string;
+    instancesData?: NSInstanceDetails[];
+}
+/** Interface for VIMLOCATION */
+export interface VIMLOCATION {
+    features: FEATURES[];
+    'type': string;
+}
+/** Interface for FEATURES */
+export interface FEATURES {
+    geometry: GEOMETRY;
+    'type': string;
+    properties: PROPERTIES;
+}
+/** Interface for GEOMETRY */
+interface GEOMETRY {
+    coordinates: [];
+}
+/** Interface for PROPERTIES */
+interface PROPERTIES {
+    extent: [];
+    country: string;
+    name: string;
+    state: string;
+}
+/** Interface for the VIMLOCATIONDATA */
+export interface VIMLOCATIONDATA {
+    label: string;
+    value: string;
+}
diff --git a/src/models/WIMAccountModel.ts b/src/models/WIMAccountModel.ts
new file mode 100644 (file)
index 0000000..190dfcd
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file  Model For WIM Account Details Information.
+ */
+
+/** Interface for WIMAccountModel */
+export interface WIMAccountModel {
+    config: {};
+    description: string;
+    name: string;
+    password: string;
+    schema_version: string;
+    user: string;
+    wim_type: string;
+    wim_url: string;
+    _admin: ADMIN;
+    _id: string;
+}
+
+/** Interface for _ADMIN */
+interface ADMIN {
+    created: number;
+    current_operation: boolean;
+    deployed: Deployed;
+    'detailed-status': string;
+    modified: number;
+    operationalState: string;
+    operations: Operation[];
+    projects_read: string[];
+    projects_write: string[];
+}
+
+/** Interface for Deployed */
+interface Deployed {
+    'RO-account': string;
+    RO: string;
+}
+
+/** Interface for Operations */
+interface Operation {
+    'detailed-status': string;
+    lcmOperationType: string;
+    operationParams: string;
+    operationState: string;
+    startTime: number;
+    statusEnteredTime: number;
+    worker: string;
+}
+
+/** Interface for WIMAccountData */
+export interface WIMAccountData {
+    name?: string;
+    identifier: string;
+    'type': string;
+    operationalState: string;
+    description: string;
+    page?: string;
+}
+
+/** Interface for WIM Row Values */
+export interface WIMValue {
+    name: string;
+    identifier: string;
+}
diff --git a/src/polyfills.ts b/src/polyfills.ts
new file mode 100644 (file)
index 0000000..5167690
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ *      file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/guide/browser-support
+ */
+
+/***************************************************************************************************
+ * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
+ */
+import '@angular/localize/init';
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js';  // Run `npm install --save classlist.js`.
+
+/**
+ * Web Animations `@angular/platform-browser/animations`
+ * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
+ * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
+ */
+import 'web-animations-js';  // Run `npm install --save web-animations-js`.
+
+/**
+ * By default, zone.js will patch all possible macroTask and DomEvents
+ * user can disable parts of macroTask/DomEvents patch by setting following flags
+ * because those flags need to be set before `zone.js` being loaded, and webpack
+ * will put import in the top of bundle, so user need to create a separate file
+ * in this directory (for example: zone-flags.ts), and put the following flags
+ * into that file, and then add the following code before importing zone.js.
+ * import './zone-flags.ts';
+ *
+ * The flags allowed in zone-flags.ts are listed here.
+ *
+ * The following flags will work for all browsers.
+ *
+ * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
+ * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
+ * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
+ *
+ *  in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
+ *  with the following flag, it will bypass `zone.js` patch for IE/Edge
+ *
+ *  (window as any).__Zone_enable_cross_context_check = true;
+ *
+ */
+
+/***************************************************************************************************
+ * Zone JS is required by default for Angular itself.
+ */
+import 'zone.js/dist/zone';  // Included with Angular CLI.
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
diff --git a/src/services/AcessGuardService.ts b/src/services/AcessGuardService.ts
new file mode 100644 (file)
index 0000000..42d36a5
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file Auth gaurd
+ */
+import { Injectable } from '@angular/core';
+import { CanLoad, Route } from '@angular/router';
+import { Observable } from 'rxjs';
+
+/**
+ * An Injectable is a class adorned with the @Injectable decorator function.
+ * @Injectable takes a metadata object that tells Angular how to compile and run module code
+ */
+@Injectable()
+export class AcessGuardService implements CanLoad {
+    /**
+     * check if module can be loaded
+     */
+    public canLoad(route: Route): Observable<boolean> | Promise<boolean> | boolean {
+        // Need to get the Role and valid here for authorization
+        if (localStorage.getItem('role') === 'Admin') {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/src/services/AuthGuardService.ts b/src/services/AuthGuardService.ts
new file mode 100644 (file)
index 0000000..0c8d1e4
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file Auth gaurd
+ */
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
+import { AuthenticationService } from 'AuthenticationService';
+import { Observable } from 'rxjs';
+import { map, take } from 'rxjs/operators';
+
+/**
+ * An Injectable is a class adorned with the @Injectable decorator function.
+ * @Injectable takes a metadata object that tells Angular how to compile and run module code
+ */
+@Injectable()
+export class AuthGuardService implements CanActivate {
+    /** Holds teh instance of AuthService class of type AuthService @private */
+    private router: Router;
+    /** Holds teh instance of Router class of type Router @private */
+    private authService: AuthenticationService;
+
+    constructor(router: Router, authService: AuthenticationService) {
+        this.router = router;
+        this.authService = authService;
+    }
+
+    /**
+     * Returns Observable<boolean> if authorized @public
+     */
+    public canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
+        return this.authService.isLoggedIn
+            .pipe(
+                take(1),
+                map((isLoggedIn: boolean) => {
+                    if (!isLoggedIn) {
+                        this.router.navigate(['/login']).catch(() => {
+                            //TODO: Handle error notification
+                        });
+                    }
+                    return true;
+                })
+            );
+    }
+}
diff --git a/src/services/AuthInterceptorService.ts b/src/services/AuthInterceptorService.ts
new file mode 100644 (file)
index 0000000..ede10a8
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file HttpInterceptor file
+ */
+import {
+    HttpErrorResponse, HttpHandler, HttpHeaderResponse, HttpInterceptor, HttpProgressEvent,
+    HttpRequest, HttpResponse, HttpSentEvent, HttpUserEvent
+} from '@angular/common/http';
+import { Injectable, Injector } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { AuthenticationService } from 'AuthenticationService';
+import * as HttpStatus from 'http-status-codes';
+import { Observable, throwError } from 'rxjs';
+import { catchError, retry } from 'rxjs/operators';
+
+/**
+ * An Injectable is a class adorned with the @Injectable decorator function.
+ * @Injectable takes a metadata object that tells Angular how to compile and run module code
+ */
+@Injectable()
+export class AuthInterceptorService implements HttpInterceptor {
+    /** Holds header options @private */
+    private clonedReq: HttpRequest<{}>;
+
+    /** To inject services @private */
+    private injector: Injector;
+
+    /** Notifier service to popup notification @private */
+    private notifierService: NotifierService;
+
+    /** Contains tranlsate instance @private */
+    private translateService: TranslateService;
+
+    /** Utilizes auth service for any auth operations @private */
+    private authService: AuthenticationService;
+
+    /** create the instance of the component */
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.notifierService = this.injector.get(NotifierService);
+        this.authService = this.injector.get(AuthenticationService);
+        this.translateService = this.injector.get(TranslateService);
+    }
+
+    /**
+     * intercept logic
+     * @param req
+     * @param next
+     */
+    public intercept(req: HttpRequest<{}>, next: HttpHandler): Observable<HttpSentEvent |
+        // tslint:disable-next-line:no-any
+        HttpHeaderResponse | HttpProgressEvent | HttpResponse<{}> | HttpUserEvent<any> | any> {
+        const idToken: string = localStorage.getItem('id_token');
+        const excludedUrl: string[] = ['osm/admin/v1/tokens', 'assets/i18n/', 'osm/version'];
+        if (excludedUrl.some((x: string): boolean => { return req.url.includes(x); })) { return next.handle(req); }
+        if (idToken.length > 0) {
+            this.setHeader(req, idToken);
+            return next.handle(this.clonedReq).pipe(
+                catchError((err: HttpErrorResponse) => {
+                    this.errorRes(err, req, next);
+                    return throwError(err);
+                })
+            );
+        } else {
+            //TODO: Handle error via notification service
+        }
+    }
+
+    /** Set header options @public */
+    // tslint:disable-next-line:no-any
+    public setHeader(req: HttpRequest<any>, idToken: string): void {
+        if (req.body !== null && req.body.byteLength !== null) {
+            this.clonedReq = req.clone({
+                setHeaders: { Authorization: 'Bearer ' + idToken, 'Cache-Control': 'no-cache', Pragma: 'no-cache' }
+            });
+        } else {
+            this.clonedReq = req.clone({
+                setHeaders: { Authorization: 'Bearer ' + idToken, 'Content-Type': 'charset=UTF-8',
+                'Cache-Control': 'no-cache', Pragma: 'no-cache' }
+            });
+        }
+    }
+
+    /** Handles error response @public */
+    public errorRes(err: HttpErrorResponse, req: HttpRequest<{}>, next: HttpHandler): Observable<{}> {
+        if (err instanceof HttpErrorResponse) {
+            switch (err.status) {
+                case HttpStatus.UNAUTHORIZED || HttpStatus.FORBIDDEN:
+                    this.handleError(err);
+                    break;
+                default: return throwError(err);
+            }
+        } else { return throwError(err); }
+    }
+
+    /** Method to handle  401 & 403 error */
+    private handleError(err: HttpErrorResponse): void {
+        if (err.error.detail === 'Expired Token or Authorization HTTP header' ||
+            err.error.detail === 'Invalid Token or Authorization HTTP header') {
+            this.notifierService.hideAll();
+            this.authService.logoutResponse();
+            if (this.authService.handle401) {
+                this.notifierService.notify('error', this.translateService.instant('SESSIONEXPIRY'));
+                this.authService.handle401 = false;
+            }
+        }
+    }
+}
diff --git a/src/services/AuthenticationService.ts b/src/services/AuthenticationService.ts
new file mode 100644 (file)
index 0000000..728d4ac
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Auth service
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Injectable, Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { Idle } from '@ng-idle/core';
+import { APIURLHEADER, ERRORDATA } from 'CommonModel';
+import { environment } from 'environment';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { isNullOrUndefined } from 'util';
+import { ProjectModel } from '../models/VNFDModel';
+import { RestService } from './RestService';
+
+/**
+ * An Injectable is a class adorned with the @Injectable decorator function.
+ * @Injectable takes a metadata object that tells Angular how to compile and run module code
+ */
+@Injectable()
+export class AuthenticationService {
+    /**
+     * Get method for  Observable loggedIn
+     */
+    get isLoggedIn(): Observable<boolean> {
+        return this.loggedIn.asObservable();
+    }
+
+    /**
+     * Get method for Observable Username
+     */
+    get username(): Observable<string> {
+        return this.userName.asObservable();
+    }
+
+    /** Get method for project name */
+    get ProjectName(): Observable<string> {
+        return this.projectName$.asObservable();
+    }
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Instance for modal service @public */
+    public modalService: NgbModal;
+
+    /** Handle 401 response for multiple API calls */
+    public handle401: boolean = true;
+
+    /** contains return URL link @public */
+    public returnUrl: string;
+
+    /** Holds the username in condition of type BehaviorSubject<string> @public */
+    public userName: BehaviorSubject<string> = new BehaviorSubject<string>('');
+
+    /** Holds the projectname in condition of type BehaviorSubject<string> @public */
+    public projectName$: BehaviorSubject<string> = new BehaviorSubject<string>('');
+
+    /** Holds the instance of router class @private */
+    private router: Router;
+
+    /** Holds the logged in condition of type BehaviorSubject<boolean> @private */
+    private loggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
+
+    /** Hold Rest Service Objects */
+    private restService: RestService;
+
+    /** Holds auth payloads @private */
+    private payLoad: {};
+
+    /** Holds header options for auth service @private */
+    private httpOptions: HttpHeaders;
+
+    /** handle idle time out service @private */
+    private idle: Idle;
+
+    /** create the instance of the component */
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.router = this.injector.get(Router);
+        this.restService = this.injector.get(RestService);
+        this.modalService = this.injector.get(NgbModal);
+        this.idle = this.injector.get(Idle);
+        if (localStorage.getItem('id_token') !== null) {
+            this.loggedIn.next(true);
+        } else {
+            this.loggedIn.next(false);
+        }
+        this.userName.next(localStorage.getItem('username'));
+    }
+
+    /**
+     * Send request and authenticate the user
+     * @param user of type User
+     */
+    public login(username: string, password: string): Observable<{}> {
+        this.setHeader();
+        this.setPayLoad(username, password);
+        const apiURLHeader: APIURLHEADER = {
+            url: environment.GENERATETOKEN_URL,
+            httpOptions: { headers: this.httpOptions }
+        };
+        return this.restService.postResource(apiURLHeader, this.payLoad)
+            .pipe(map((data: ProjectModel) => {
+                if (data) {
+                    this.setLocalStorage(data);
+                    this.idle.watch(true);
+                    this.loggedIn.next(true);
+                    this.handle401 = true;
+                    this.userName.next(data.username);
+                    return this.loggedIn;
+                }
+            }, (error: ERRORDATA) => { this.restService.handleError(error, 'post'); }
+            ));
+    }
+
+    /** Set headers for auth session @public */
+    public setHeader(): void {
+        this.httpOptions = new HttpHeaders({
+            'Content-Type': 'application/json; charset=UTF-8',
+            Accept: 'application/json',
+            'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+        });
+    }
+
+    /** Set payloads for auth session @public  */
+    public setPayLoad(username: string, password: string): void {
+        this.payLoad = JSON.stringify({
+            username,
+            password
+        });
+    }
+
+    /** set local storage on auth process @public */
+    public setLocalStorage(data: ProjectModel): void {
+        localStorage.setItem('id_token', data.id);
+        localStorage.setItem('expires', data.expires.toString());
+        localStorage.setItem('username', data.username);
+        localStorage.setItem('isAdmin', (data.admin) ? 'true' : 'false');
+        localStorage.setItem('project_id', data.project_id);
+        localStorage.setItem('project', data.project_name);
+        localStorage.setItem('token_state', data.id);
+        this.projectName$.next(data.project_name);
+    }
+    /** Destory tokens API response handling @public */
+    public logoutResponse(): void {
+        this.loggedIn.next(false);
+        const langCode: string = localStorage.getItem('languageCode');
+        const redirecturl: string = isNullOrUndefined(localStorage.getItem('returnUrl')) ? '/' : localStorage.getItem('returnUrl');
+        localStorage.clear();
+        localStorage.setItem('languageCode', langCode);
+        localStorage.setItem('returnUrl', redirecturl);
+        localStorage.setItem('token_state', null);
+        this.idle.stop();
+        this.router.navigate(['login']).catch();
+    }
+    /**
+     * Logout the user & clearing the token.
+     */
+    public logout(): void {
+        this.returnUrl = this.router.url;
+        localStorage.setItem('returnUrl', this.returnUrl);
+        this.modalService.dismissAll();
+        this.destoryToken();
+    }
+    /** Destory tokens on logout @private */
+    private destoryToken(): void {
+        const tokenID: string = localStorage.getItem('id_token');
+        if (tokenID !== null) {
+            const deletingURl: string = environment.GENERATETOKEN_URL + '/' + tokenID;
+            this.restService.deleteResource(deletingURl).subscribe((res: {}) => {
+                this.logoutResponse();
+            }, (error: ERRORDATA) => {
+                this.restService.handleError(error, 'delete');
+            });
+        }
+    }
+}
diff --git a/src/services/DataService.ts b/src/services/DataService.ts
new file mode 100644 (file)
index 0000000..e64c34c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file Data Services for user related information.
+ */
+import { Injectable } from '@angular/core';
+import { BehaviorSubject, Observable } from 'rxjs';
+
+/**
+ * This file created during the angular project creation
+ */
+@Injectable()
+/** Exporting a class @exports DataService */
+export class DataService {
+    /** message source @public */
+    public messageSource: BehaviorSubject<{}> = new BehaviorSubject<{}>({});
+
+    /** current message @public */
+    public currentMessage:  Observable<{}> = this.messageSource.asObservable();
+    /** change message function @public */
+    public changeMessage(message: {}): void {
+        this.messageSource.next(message);
+    }
+}
diff --git a/src/services/DeviceCheckService.ts b/src/services/DeviceCheckService.ts
new file mode 100644 (file)
index 0000000..98ab2fc
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+import { Injectable } from '@angular/core';
+import { BehaviorSubject, Observable } from 'rxjs';
+/**
+ * @file Provider for Device Check Service
+ */
+/**
+ * An Injectable is a class adorned with the @Injectable decorator function.
+ * @Injectable takes a metadata object that tells Angular how to compile and run module code
+ */
+@Injectable({
+    providedIn: 'root'
+})
+/** Exporting a class @exports DeviceCheckService */
+export class DeviceCheckService {
+    /** Get method for Observable isMobile */
+    get isMobile(): Observable<boolean> {
+        return this.isMobile$.asObservable();
+    }
+    /** Holds the mobile condition of type BehaviorSubject<boolean> @private */
+    private isMobile$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
+
+    /** Return the Device type @public */
+    public checkDeviceType(): void {
+        if (navigator.userAgent.match(/Android/i)
+            || navigator.userAgent.match(/webOS/i)
+            || navigator.userAgent.match(/iPhone/i)
+            || navigator.userAgent.match(/iPod/i)
+            || navigator.userAgent.match(/BlackBerry/i)
+            || navigator.userAgent.match(/Windows Phone/i)) {
+            this.isMobile$.next(true);
+        } else {
+            this.isMobile$.next(false);
+        }
+    }
+}
diff --git a/src/services/ProjectService.ts b/src/services/ProjectService.ts
new file mode 100644 (file)
index 0000000..c22f33a
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Project Service
+ */
+import { Injectable, Injector } from '@angular/core';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { AuthenticationService } from 'AuthenticationService';
+import { environment } from 'environment';
+import { ProjectData } from 'ProjectModel';
+import { BehaviorSubject, Observable, Subscription } from 'rxjs';
+import { SwitchProjectComponent } from 'SwitchProjectComponent';
+import { ProjectRoleMappings, UserDetail } from 'UserModel';
+import { ProjectModel } from 'VNFDModel';
+import { RestService } from './RestService';
+
+/**
+ * An Injectable is a class adorned with the @Injectable decorator function.
+ * @Injectable takes a metadata object that tells Angular how to compile and run module code
+ */
+@Injectable({
+    providedIn: 'root'
+})
+/** Exporting a class @exports ProjectService */
+export class ProjectService {
+    /** Get method for project list */
+    get projectList(): Observable<{}[]> {
+        return this.projectList$.asObservable();
+    }
+    /** To inject services @public */
+    public injector: Injector;
+
+    /** Holds all the projects details */
+    public allProjectList: string[];
+
+    /** Observable holds logined value  @public */
+    public username$: Observable<string>;
+
+    /** Hold Rest Service Objects */
+    private restService: RestService;
+
+    /** Instance of the modal service @private */
+    private modalService: NgbModal;
+
+    /** Utilizes auth service for any auth operations @private */
+    private authService: AuthenticationService;
+
+    /** Holds the username in condition of type BehaviorSubject<string> @private */
+    private projectList$: BehaviorSubject<{}[]> = new BehaviorSubject<{}[]>([]);
+
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.restService = this.injector.get(RestService);
+        this.modalService = this.injector.get(NgbModal);
+        this.authService = this.injector.get(AuthenticationService);
+    }
+
+    /** List all the projects @public */
+    public getAllProjects(): Observable<{}> {
+        return this.restService.getResource(environment.PROJECTS_URL);
+    }
+
+    /** Get current project details from local storage @public */
+    public getCurrentProjectDetails(): Observable<{}> {
+        const project: string = localStorage.getItem('project_id');
+        return this.restService.getResource(environment.PROJECTS_URL + '/' + project);
+    }
+
+    /** Returns all the projects for a particular users @public */
+    public getUserProjects(): Observable<{}> {
+        const username: string = localStorage.getItem('username');
+        return this.restService.getResource(environment.USERS_URL + '/' + username);
+    }
+
+    /** Set header projects @public */
+    public setHeaderProjects(): void {
+        this.getUserProjects().subscribe((projects: UserDetail) => {
+            const projectList: {}[] = projects.project_role_mappings;
+            projectList.filter((list: ProjectModel) => {
+                if (list.project === localStorage.getItem('project_id')) {
+                    localStorage.setItem('project', list.project_name);
+                    this.authService.projectName$.next(list.project_name);
+                }
+            });
+            const projectDistinctList: {}[] = projectList.filter(
+                (thing: ProjectRoleMappings, i: number, arr: []) => arr
+                    .findIndex((t: ProjectRoleMappings) => t.project_name === thing.project_name) === i
+            );
+            this.projectList$.next(projectDistinctList);
+        });
+    }
+
+    /** Toggle projects on selection @public */
+    public switchProjectModal(list: ProjectData): void {
+        const username: string = localStorage.getItem('username');
+        this.modalService.open(SwitchProjectComponent, { backdrop: 'static' })
+            .componentInstance.params = { projectID: list.project, username };
+    }
+}
diff --git a/src/services/RestService.ts b/src/services/RestService.ts
new file mode 100644 (file)
index 0000000..d7ded6f
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file Provider for REST Service
+ */
+
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { ERRORDATA } from 'CommonModel';
+import * as HttpStatus from 'http-status-codes';
+import { Observable } from 'rxjs';
+
+/**
+ * An Injectable is a class adorned with the @Injectable decorator function.
+ * @Injectable takes a metadata object that tells Angular how to compile and run module code
+ */
+@Injectable()
+/** Exporting a class @exports RestService */
+export class RestService {
+    /** convenient way to modify request made by the http service both before they are sent and after they return */
+    private http: HttpClient;
+    /** API URL. Disabled tslint since server doesn't support https protocol */
+    private apiURL: string = '';
+    /** Notifier service to popup notification @private */
+    private notifierService: NotifierService;
+    /** Instance for active modal service @public */
+    private activeModal: NgbModal;
+    /** insatnce for translate @private */
+    private translateService: TranslateService;
+
+    constructor(http: HttpClient, notifierService: NotifierService, activeModal: NgbModal, translateService: TranslateService) {
+        this.http = http;
+        this.notifierService = notifierService;
+        this.activeModal = activeModal;
+        this.translateService = translateService;
+    }
+
+    /**
+     * Get a resource from the server which identified by a URI.
+     * @param apiURL The URL of the resource to be retrieved.
+     */
+
+    public getResource(apiURL: string, httpHeaders?: { headers: HttpHeaders }): Observable<{}> {
+        return this.http.get(apiURL, httpHeaders);
+    }
+
+    /**
+     * Create a new resource on the server.
+     * @param apiURL The URL of the resource to be created.
+     * @param payload The request data to be sent to server.
+     */
+
+    public postResource(apiURLHeader: { url: string, httpOptions?: { headers: HttpHeaders } }, payload: {}): Observable<{}> {
+        return this.http.post(apiURLHeader.url, payload, apiURLHeader.httpOptions);
+    }
+
+    /**
+     * Modify the resource on the server.
+     * @param apiURL The URL of the resource to be created.
+     * @param payload The request data to be sent to server.
+     */
+
+    public patchResource(apiURLHeader: { url: string, httpOptions?: { headers: HttpHeaders } }, payload: {}): Observable<object> {
+        return this.http.patch(apiURLHeader.url, payload, apiURLHeader.httpOptions);
+    }
+
+    /**
+     * Replace the resource on the server.
+     * @param apiName The URL of the resource to be created.
+     * @param payload The request data to be sent to server.
+     */
+
+    public putResource(apiURLHeader: { url: string, httpOptions?: { headers: HttpHeaders } }, payload: {}): Observable<object> {
+        return this.http.put(apiURLHeader.url, payload, apiURLHeader.httpOptions);
+    }
+
+    /**
+     * Delete a resource identified by a URL.
+     * @param apiURL The URL of the resource to be deleted.
+     */
+
+    public deleteResource(apiURL: string, httpHeaders?: { headers: HttpHeaders }): Observable<object> {
+        return this.http.delete(apiURL, httpHeaders);
+    }
+    /**
+     * Handle Error response based on the status.
+     * @param error The error response reecieved from API call.
+     * @param method The http request method.
+     */
+    // tslint:disable-next-line: cyclomatic-complexity
+    public handleError(err: ERRORDATA, method?: string): void {
+        if (err.error.status === HttpStatus.UNAUTHORIZED) {
+            if (method !== 'get') {
+                if (err.error.detail !== 'Expired Token or Authorization HTTP header' &&
+                    err.error.detail !== 'Invalid Token or Authorization HTTP header') {
+                    this.notifierService.notify('error', err.error.detail !== undefined ?
+                        err.error.detail : this.translateService.instant('HTTPERROR.401'));
+                }
+                this.activeModal.dismissAll();
+            }
+        } else if (err.error.status === HttpStatus.BAD_REQUEST) {
+            this.notifierService.notify('error', err.error.detail !== undefined ?
+                err.error.detail : this.translateService.instant('HTTPERROR.400'));
+        } else if (err.error.status === HttpStatus.NOT_FOUND) {
+            this.notifierService.notify('error', err.error.detail !== undefined ?
+                err.error.detail : this.translateService.instant('HTTPERROR.404'));
+        } else if (err.error.status === HttpStatus.CONFLICT) {
+            this.notifierService.notify('error', err.error.detail !== undefined ?
+                err.error.detail : this.translateService.instant('HTTPERROR.409'));
+            this.activeModal.dismissAll();
+        } else if (err.error.status === HttpStatus.INTERNAL_SERVER_ERROR) {
+            this.notifierService.notify('error', err.error.detail !== undefined ?
+                err.error.detail : this.translateService.instant('HTTPERROR.500'));
+        } else if (err.error.status === HttpStatus.BAD_GATEWAY) {
+            this.notifierService.notify('error', this.translateService.instant('HTTPERROR.502'));
+        } else if (err.error.status === HttpStatus.SERVICE_UNAVAILABLE) {
+            this.notifierService.notify('error', this.translateService.instant('HTTPERROR.503'));
+        } else if (err.error.status === HttpStatus.GATEWAY_TIMEOUT) {
+            this.notifierService.notify('error', this.translateService.instant('HTTPERROR.504'));
+        } else {
+            this.notifierService.notify('error', err.error.detail !== undefined ?
+                err.error.detail : this.translateService.instant('ERROR'));
+        }
+    }
+}
diff --git a/src/services/SharedService.ts b/src/services/SharedService.ts
new file mode 100644 (file)
index 0000000..3a138e5
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file Provider for Shared Service
+ */
+import { HttpErrorResponse, HttpHeaders } from '@angular/common/http';
+import { EventEmitter, Injectable, Output } from '@angular/core';
+import { FormArray, FormGroup } from '@angular/forms';
+import { Router } from '@angular/router';
+import { CONSTANTNUMBER, ERRORDATA, GETAPIURLHEADER, PACKAGEINFO, PAGERSMARTTABLE, SMARTTABLECLASS, TARSETTINGS } from 'CommonModel';
+import { environment } from 'environment';
+import * as HttpStatus from 'http-status-codes';
+import * as untar from 'js-untar';
+import * as pako from 'pako';
+import { RestService } from 'RestService';
+import { isNullOrUndefined } from 'util';
+
+/** This is added globally by the tar.js library */
+// tslint:disable-next-line: no-any
+declare const Tar: any;
+
+/**
+ * An Injectable is a class adorned with the @Injectable decorator function.
+ * @Injectable takes a metadata object that tells Angular how to compile and run module code
+ */
+@Injectable({
+    providedIn: 'root'
+})
+/** Exporting a class @exports SharedService */
+export class SharedService {
+    /** call the parent using event information @private */
+    @Output() public dataEvent: EventEmitter<{}> = new EventEmitter<{}>();
+
+    /** Variables to hold regexp pattern for URL */
+    // tslint:disable-next-line: max-line-length
+    public REGX_URL_PATTERN: RegExp = new RegExp(/^(http?|ftp|https):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z0-9]{2,15})(:((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4})))*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/);
+
+    /** Variables to hold regexp pattern for IP Address */
+    public REGX_IP_PATTERN: RegExp = new RegExp(/^(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(?!$)|$)){4}$/);
+
+    /** Variables to hold regexp pattern for Port Number */
+    // tslint:disable-next-line: max-line-length
+    public REGX_PORT_PATTERN: RegExp = new RegExp(/^((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4}))$/);
+
+    /** Variables to hold regexp pattern for DPID */
+    public REGX_DPID_PATTERN: RegExp = new RegExp(/^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){7}$/);
+
+    /** Variable to hold regexp pattern for password */
+    // tslint:disable-next-line: max-line-length
+    public REGX_PASSWORD_PATTERN: RegExp = new RegExp(/^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/);
+
+    /** FormGroup instance added to the form @ html @public */
+    public formGroup: FormGroup;
+
+    /** Controls the go to top button on scroll  @public */
+    public showGotoTop: boolean;
+
+    /** Holds OSM Version value @public */
+    public osmVersion: string;
+
+    /** express number for time manupulation -2 */
+    private epochTimeMinus2: number = -2;
+
+    /** express number for time manupulation 1000 */
+    private epochTime1000: number = 1000;
+
+    /** Random string generator length */
+    private randomStringLength: number = 4;
+
+    /** Instance of the rest service @private */
+    private restService: RestService;
+
+    /** Service holds the router information @private */
+    private router: Router;
+
+    /** Check for the root directory @private */
+    private directoryCount: number = 2;
+
+    constructor(restService: RestService, router: Router) {
+        this.restService = restService;
+        this.router = router;
+    }
+
+    /** convert epoch time function @public */
+    public convertEpochTime(unixtimestamp: number): string {
+        const monthsArr: string[] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+            'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+        const date: Date = new Date(unixtimestamp * this.epochTime1000);
+        const year: number = date.getFullYear();
+        const month: string = monthsArr[date.getMonth()];
+        const day: number = date.getDate();
+        const hours: number = date.getHours();
+        const minutes: string = '0' + date.getMinutes();
+        const seconds: string = '0' + date.getSeconds();
+        return month + '-' + day + '-' + year + ' ' + hours + ':' + minutes.substr(this.epochTimeMinus2) + ':'
+            + seconds.substr(this.epochTimeMinus2);
+    }
+
+    /** Download Files function @public */
+    public downloadFiles(shortName: string, binaryData: Blob[], filetype: string): void {
+        const downloadLink: HTMLAnchorElement = document.createElement('a');
+        downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: filetype }));
+        if (shortName !== undefined) {
+            if (window.navigator.msSaveOrOpenBlob) {
+                window.navigator.msSaveBlob(new Blob(binaryData, { type: filetype }), 'OSM_Export_' + shortName + '.tar.gz');
+            } else {
+                downloadLink.setAttribute('download', 'OSM_Export_' + shortName + '.tar.gz');
+                document.body.appendChild(downloadLink);
+                downloadLink.click();
+            }
+        }
+    }
+
+    /** Call this method after delete perform action is completed in the ng-smart-table data @public */
+    public callData(): void {
+        this.dataEvent.emit();
+    }
+
+    /** Generate random string @public */
+    public randomString(): string {
+        const chars: string = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+        let result: string = '';
+        // tslint:disable-next-line:no-increment-decrement
+        for (let randomStringRef: number = this.randomStringLength; randomStringRef > 0; --randomStringRef) {
+            result += chars[Math.floor(Math.random() * chars.length)];
+        }
+        return result;
+    }
+    /** Function to read uploaded file String @public */
+    public async getFileString(files: FileList, fileType: string): Promise<string | ArrayBuffer> {
+        const reader: FileReader = new FileReader();
+        return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
+            if (this.vaildataFileInfo(files[0], fileType)) {
+                this.readFileContent(reader, files[0], fileType);
+            } else {
+                reject('typeError');
+            }
+            reader.onload = (): void => {
+                if (reader.result === null) {
+                    reject('contentError');
+                }
+                resolve(reader.result);
+            };
+            reader.onerror = (event: Event): void => {
+                reject('contentError');
+            };
+        });
+    }
+    /** Method to handle tar and tar.gz file for shared YAML file content @public */
+    public async targzFile(packageInfo: PACKAGEINFO): Promise<string | ArrayBuffer> {
+        return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
+            const httpOptions: GETAPIURLHEADER = this.getHttpOptions();
+            let apiUrl: string = '';
+            apiUrl = packageInfo.packageType === 'nsd' ? environment.NSDESCRIPTORS_URL + '/' + packageInfo.id + '/nsd_content' :
+                environment.VNFPACKAGES_URL + '/' + packageInfo.id + '/package_content';
+            this.restService.getResource(apiUrl, httpOptions).subscribe((response: ArrayBuffer) => {
+                try {
+                    // tslint:disable-next-line: no-any
+                    const tar: any = new Tar();
+                    const originalInput: Uint8Array = pako.inflate(response, { to: 'Uint8Array' });
+                    untar(originalInput.buffer).then((extractedFiles: TARSETTINGS[]) => {
+                        const getFoldersFiles: {}[] = extractedFiles;
+                        const folderNameStr: string = extractedFiles[0].name;
+                        getFoldersFiles.forEach((value: TARSETTINGS) => {
+                            const getRootFolder: string[] = value.name.split('/');
+                            if (value.name.startsWith(folderNameStr) &&
+                                (value.name.endsWith('.yaml') || value.name.endsWith('.yml')) &&
+                                getRootFolder.length === this.directoryCount) {
+                                tar.append(value.name, packageInfo.descriptor, { type: value.type });
+                            } else {
+                                if (value.type !== 'L') {
+                                    tar.append(value.name, new Uint8Array(value.buffer), { type: value.type });
+                                }
+                            }
+                        });
+                        const out: Uint8Array = tar.out;
+                        const originalOutput: Uint8Array = pako.gzip(out);
+                        resolve(originalOutput.buffer);
+                    }, (err: string) => {
+                        reject('');
+                    });
+                } catch (e) {
+                    reject('');
+                }
+            }, (error: HttpErrorResponse) => {
+                if (error.status === HttpStatus.NOT_FOUND || error.status === HttpStatus.UNAUTHORIZED) {
+                    this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
+                } else {
+                    this.restService.handleError(error, 'get');
+                    reject('');
+                }
+            });
+        });
+    }
+    /** Method to check given string is JSON or not @public */
+    public checkJson(jsonString: string): boolean {
+        jsonString = jsonString.replace(/'/g, '"');
+        try {
+            JSON.parse(jsonString);
+        } catch (e) {
+            return false;
+        }
+        return true;
+    }
+    /** Clean the form before submit @public */
+    public cleanForm(formGroup: FormGroup): void {
+        Object.keys(formGroup.controls).forEach((key: string) => {
+            if ((!isNullOrUndefined((formGroup.get(key) as FormArray | FormGroup).controls)) && key !== 'vimconfig') {
+                // tslint:disable-next-line: no-shadowed-variable
+                for (const { item, index } of (formGroup.get(key).value).map((item: {}, index: number) => ({ item, index }))) {
+                    const newFormGroup: FormGroup = (formGroup.get(key) as FormArray).controls[index] as FormGroup;
+                    this.cleanForm(newFormGroup);
+                }
+            } else if (formGroup.get(key).value !== undefined && formGroup.get(key).value !== null && key !== 'vimconfig') {
+                if (!Array.isArray(formGroup.get(key).value)) {
+                    if (typeof formGroup.get(key).value === 'string') {
+                        formGroup.get(key).setValue(formGroup.get(key).value.trim());
+                    }
+                }
+            } else if (key === 'vimconfig') {
+                const newFormGroup: FormGroup = formGroup.get(key) as FormGroup;
+                this.cleanForm(newFormGroup);
+            }
+        });
+    }
+    /** Method to return the config of pager value for ngSmarttable @public */
+    public paginationPagerConfig(): PAGERSMARTTABLE {
+        return {
+            display: true,
+            perPage: environment.paginationNumber
+        };
+    }
+    /** Method to return the class for the table for ngSmarttable @public */
+    public tableClassConfig(): SMARTTABLECLASS {
+        return {
+            class: 'table list-data'
+        };
+    }
+    /** Method to return all languages name and its code @public */
+    public languageCodeList(): {}[] {
+        return [
+            { code: 'en', language: 'English' },
+            { code: 'es', language: 'Spanish' },
+            { code: 'pt', language: 'Portuguese' },
+            { code: 'de', language: 'German' }
+        ];
+    }
+    /** Fetch OSM Version @public */
+    public fetchOSMVersion(): void {
+        this.restService.getResource(environment.OSM_VERSION_URL).subscribe((res: { version: string }) => {
+            const version: string[] = res.version.split('+');
+            if (!isNullOrUndefined(version[0])) {
+                this.osmVersion = version[0];
+            } else {
+                this.osmVersion = null;
+            }
+        }, (error: ERRORDATA) => {
+            this.osmVersion = null;
+            this.restService.handleError(error, 'get');
+        });
+    }
+    /** Method to validate file extension and size @private */
+    private vaildataFileInfo(fileInfo: File, fileType: string): boolean {
+        const extension: string = fileInfo.name.substring(fileInfo.name.lastIndexOf('.') + 1);
+        const packageSize: number = CONSTANTNUMBER.oneMB * environment.packageSize;
+        if (extension.toLowerCase() === fileType && fileInfo.size <= packageSize) {
+            return true;
+        }
+        return false;
+    }
+    /** Method to read file content based on type @private */
+    private readFileContent(reader: FileReader, fileInfo: File, fileType: string): void {
+        if (fileType === 'gz') {
+            reader.readAsArrayBuffer(fileInfo);
+        } else {
+            reader.readAsText(fileInfo);
+        }
+    }
+    /** Method to handle http options @public */
+    private getHttpOptions(): GETAPIURLHEADER {
+        return {
+            headers: new HttpHeaders({
+                Accept: 'application/gzip, application/json',
+                'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+            }),
+            responseType: 'arraybuffer'
+        };
+    }
+}
diff --git a/src/test.ts b/src/test.ts
new file mode 100644 (file)
index 0000000..cf21bef
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+/**
+ * @file This file is required by karma.conf.js and loads recursively all the .spec and framework files.
+ */
+import { getTestBed } from '@angular/core/testing';
+import {
+    BrowserDynamicTestingModule,
+    platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+import 'zone.js/dist/zone-testing';
+
+/** const variable require */
+// tslint:disable:no-reserved-keywords
+// tslint:disable-next-line:no-any
+declare const require: any;
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+    BrowserDynamicTestingModule,
+    platformBrowserDynamicTesting()
+);
+
+/** const variable context */
+// Then we find all the tests.
+// tslint:disable-next-line:typedef
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/src/tsconfig.app.json b/src/tsconfig.app.json
new file mode 100644 (file)
index 0000000..384c218
--- /dev/null
@@ -0,0 +1,16 @@
+{
+    "extends": "../tsconfig.json",
+    "compilerOptions": {
+        "outDir": "../out-tsc/app",
+        "types": []
+    },
+    "exclude": [
+        "test.ts",
+        "**/*.spec.ts"
+    ],
+    "angularCompilerOptions": {
+        "enableIvy": true,
+        "fullTemplateTypeCheck": false,
+        "strictInjectionParameters": false
+    }
+}
\ No newline at end of file
diff --git a/src/tsconfig.spec.json b/src/tsconfig.spec.json
new file mode 100644 (file)
index 0000000..0a65d17
--- /dev/null
@@ -0,0 +1,18 @@
+{
+    "extends": "../tsconfig.json",
+    "compilerOptions": {
+        "outDir": "../out-tsc/spec",
+        "types": [
+            "jasmine",
+            "node"
+        ]
+    },
+    "files": [
+        "test.ts",
+        "polyfills.ts"
+    ],
+    "include": [
+        "**/*.spec.ts",
+        "**/*.d.ts"
+    ]
+}
diff --git a/src/tslint.json b/src/tslint.json
new file mode 100644 (file)
index 0000000..52e2c1a
--- /dev/null
@@ -0,0 +1,17 @@
+{
+    "extends": "../tslint.json",
+    "rules": {
+        "directive-selector": [
+            true,
+            "attribute",
+            "app",
+            "camelCase"
+        ],
+        "component-selector": [
+            true,
+            "element",
+            "app",
+            "kebab-case"
+        ]
+    }
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644 (file)
index 0000000..fca2693
--- /dev/null
@@ -0,0 +1,139 @@
+{
+    "compileOnSave": false,
+    "compilerOptions": {
+        "resolveJsonModule": true,
+        "baseUrl": ".",
+        "downlevelIteration": true,
+        "outDir": "./dist/out-tsc",
+        "sourceMap": true,
+        "declaration": false,
+        "module": "esnext",
+        "moduleResolution": "node",
+        "emitDecoratorMetadata": true,
+        "experimentalDecorators": true,
+        "importHelpers": true,
+        "target": "es5",
+        "typeRoots": [
+            "node_modules/@types"
+        ],
+        "lib": [
+            "es2018",
+            "dom"
+        ],
+        "paths": {
+            "CommonModel": ["src/models/CommonModel"],
+            "environment": ["src/environments/environment"],
+            "AuthInterceptorService": ["src/services/AuthInterceptorService"],
+            "RestService": ["src/services/RestService"],
+            "SharedService": ["src/services/SharedService"],
+            "ProjectService": ["src/services/ProjectService"],
+            "DataService": ["src/services/DataService"],
+            "AuthenticationService": ["src/services/AuthenticationService"],
+            "AuthGuardService": ["src/services/AuthGuardService"],
+            "AcessGuardService": ["src/services/AcessGuardService"],
+            "DeviceCheckService": ["src/services/DeviceCheckService"],
+            "NSDModel":["src/models/NSDModel"],
+            "VimAccountModel" : ["src/models/VimAccountModel"],
+            "LayoutComponent": ["src/app/layouts/LayoutComponent"],
+            "SidebarComponent": ["src/app/layouts/sidebar/SidebarComponent"],
+            "HeaderComponent": ["src/app/layouts/header/HeaderComponent"],
+            "UserSettingsComponent": ["src/app/user-settings/UserSettingsComponent"],
+            "LoginComponent": ["src/app/login/LoginComponent"],
+            "DashboardComponent": ["src/app/dashboard/DashboardComponent"],
+            "NSPackages" : ["src/app/packages/ns-packages/NSPackagesComponent"],
+            "NsPackagesAction": ["src/app/utilities/ns-packages-action/NsPackagesActionComponent"],
+            "InstantiateNs": ["src/app/packages/instantiate-ns/InstantiateNsComponent"],
+            "ShowContent": ["src/app/packages/show-content/ShowContentComponent"],
+            "DeleteComponent": ["src/app/utilities/delete/DeleteComponent"],
+            "EditPackagesComponent": ["src/app/utilities/edit-packages/EditPackagesComponent"],
+            "NetsliceTemplate":["src/app/packages/netslice-template/NetsliceTemplateComponent"],
+            "DragDirective": ["src/app/utilities/dragDropUpload/DragDirective"],
+            "NSComposer": ["src/app/packages/ns-packages/ns-composer/NSComposerComponent"],
+            "VNFComposer": ["src/app/packages/ns-packages/vnf-composer/VNFComposerComponent"],
+            "Packages":["src/app/packages/PackagesComponent"],
+            "VNFPackages": ["src/app/packages/vnf-packages/VNFPackagesComponent"],
+            "VNFDModel": ["src/models/VNFDModel"],
+            "VNFPackagesAction" :["src/app/utilities/vnf-packages-action/VNFPackagesActionComponent"],
+            "NetworkSliceModel" : ["src/models/NetworkSliceModel"],
+            "NetslicePackagesAction" : ["src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent"],
+            "PageNotFound" : ["src/app/page-not-found/PageNotFoundComponent"],
+            "ProjectsModule" : ["src/app/projects/ProjectsModule"],
+            "ProjectModel" : ["src/models/ProjectModel"],
+            "ProjectsComponent" : ["src/app/projects/ProjectsComponent"],
+            "ProjectCreateUpdate" : ["src/app/projects/project-create-update/ProjectCreateUpdateComponent"],
+            "ProjectsAction": ["src/app/utilities/projects-action/ProjectsActionComponent"],
+            "BreadCrumb": ["src/app/layouts/breadcrumb/BreadcrumbComponent"],
+            "VNFDEdit": ["src/app/packages/vnfd-edit/VNFDEditComponent"],
+            "VNFInstanceModel": ["src/models/VNFInstanceModel"],
+            "InstancesComponent": ["src/app/instances/InstancesComponent"],
+            "VNFInstancesComponent": ["src/app/instances/vnf-instances/VNFInstancesComponent"],
+            "NSInstancesComponent": ["src/app/instances/ns-instances/NSInstancesComponent"],
+            "HistoryOperationsComponent": ["src/app/instances/ns-history-operations/HistoryOperationsComponent"],
+            "NetsliceInstancesComponent": ["src/app/instances/netslice-instances/NetsliceInstancesComponent"],
+            "VNFInstancesActionComponent": ["src/app/utilities/vnf-instances-action/VNFInstancesActionComponent"],
+            "NSInstancesActionComponent": ["src/app/utilities/ns-instances-action/NSInstancesActionComponent"],
+            "NetsliceInstancesActionComponent": ["src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent"],
+            "NSInstanceModel": ["src/models/NSInstanceModel"],
+            "ShowInfoComponent": ["src/app/utilities/show-info/ShowInfoComponent"],
+            "NSTopologyComponent": ["src/app/instances/ns-topology/NSTopologyComponent"],
+            "NSTopologyModel": ["src/models/NSTopologyModel"],
+            "SDNControllerComponent": ["src/app/sdn-controller/SDNControllerComponent"],
+            "SDNControllerDetailsComponent": ["src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent"],
+            "SDNControllerInfoComponent": ["src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent"],
+            "SDNControllerActionComponent": ["src/app/utilities/sdn-controller-action/SDNControllerActionComponent"],
+            "NewSDNControllerComponent": ["src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent"],
+            "SDNControllerModel": ["src/models/SDNControllerModel"],
+            "UserModel": ["src/models/UserModel"],
+            "UsersComponent": ["src/app/users/UsersComponent"],
+            "UserDetailsComponent": ["src/app/users/user-details/UserDetailsComponent"],
+            "AddEditUserComponent": ["src/app/users/add-user/AddEditUserComponent"],
+            "UsersActionComponent": ["src/app/utilities/users-action/UsersActionComponent"],
+            "ProjectRoleComponent": ["src/app/users/project-role/ProjectRoleComponent"],
+            "PagePerRow": ["src/app/utilities/page-per-row/PagePerRow"],
+            "PagePerRowModule": ["src/app/utilities/page-per-row/PagePerRowModule"],
+            "VimAccountsModule": ["src/app/vim-accounts/VimAccountsModule"],
+            "VimAccountsComponent": ["src/app/vim-accounts/VimAccountsComponent"],
+            "VimAccountDetails": ["src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent"],
+            "NewVimaccount": ["src/app/vim-accounts/new-vimaccount/NewVimaccountComponent"],
+            "InfoVim": ["src/app/vim-accounts/info-vim/InfoVimComponent"],
+            "VimAccountsAction": ["src/app/utilities/vim-accounts-action/VimAccountsActionComponent"],
+            "InstantiateNetSliceTemplate":["src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent"],
+            "LoaderComponent": ["src/app/utilities/loader/LoaderComponent"],
+            "LoaderModule": ["src/app/utilities/loader/LoaderModule"],
+            "NSPrimitiveComponent": ["src/app/instances/ns-primitive/NSPrimitiveComponent"],
+            "ConfirmationTopology": ["src/app/utilities/confirmation-topology/ConfirmationTopologyComponent"],
+            "ComposePackages": ["src/app/utilities/compose-packages/ComposePackages"],
+            "WIMAccountsAction": ["src/app/utilities/wim-accounts-action/WIMAccountsActionComponent"],
+            "WIMAccountsModule": ["src/app/wim-accounts/WIMAccountsModule"],
+            "WIMAccountsComponent": ["src/app/wim-accounts/WIMAccountsComponent"],
+            "WIMAccountDetails": ["src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent"],
+            "NewWIMAccount": ["src/app/wim-accounts/new-wim-account/NewWIMAccountComponent"],
+            "WIMAccountInfo": ["src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent"],
+            "WIMAccountModel": ["src/models/WIMAccountModel"],
+            "Roles": ["src/app/roles/RolesComponent"],
+            "RolesDetails": ["src/app/roles/roles-details/RolesDetailsComponent"],
+            "RolesAction": ["src/app/utilities/roles-action/RolesActionComponent"],
+            "RolesCreateEdit": ["src/app/roles/roles-create-edit/RolesCreateEditComponent"],
+            "RolesModel": ["src/models/RoleModel"],
+            "PDUInstancesComponent": ["src/app/instances/pdu-instances/PDUInstancesComponent"],
+            "PDUInstanceModel": ["src/models/PDUInstanceModel"],
+            "PDUInstancesActionComponent": ["src/app/utilities/pdu-instances-action/PDUInstancesActionComponent"],
+            "AddPDUInstancesComponent": ["src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent"],
+            "ClonePackage": ["src/app/utilities/clone-package/ClonePackageComponent"],
+            "K8sComponent": ["src/app/k8s/K8sComponent"],
+            "K8sClusterComponent": ["src/app/k8s/k8scluster/K8sClusterComponent"],
+            "K8sRepositoryComponent":["src/app/k8s/k8srepository/K8sRepositoryComponent"],
+            "K8sActionComponent": ["src/app/k8s/k8s-action/K8sActionComponent"],
+            "K8sModel": ["src/models/K8sModel"],
+            "K8sAddClusterComponent": ["src/app/k8s/k8s-add-cluster/K8sAddClusterComponent"],
+            "K8sAddRepoComponent": ["src/app/k8s/k8s-add-repo/K8sAddRepoComponent"],
+            "SwitchProjectComponent": ["src/app/utilities/switch-project/SwitchProjectComponent"],
+            "ProjectLinkComponent":["src/app/utilities/project-link/ProjectLinkComponent"],
+            "PageReload": ["src/app/utilities/page-reload/PageReload"],
+            "PageReloadModule": ["src/app/utilities/page-reload/PageReloadModule"],
+            "GoToTopDirective": ["src/directive/GoToTopDirective"],
+            "VNFLinkComponent": ["src/app/instances/vnf-instances/vnf-link/VNFLinkComponent"],
+            "PACKAGEJSON": ["package.json"]
+        }
+    }
+}
\ No newline at end of file
diff --git a/tslint.json b/tslint.json
new file mode 100644 (file)
index 0000000..ba584e0
--- /dev/null
@@ -0,0 +1,299 @@
+{
+    "linterOptions" : {
+        "exclude" : [
+          "package.json"
+        ]
+      },
+    "defaultSeverity": "error",
+    "rules": {
+        "insecure-random": false,
+        "no-banned-terms": true,
+        "no-cookies": true,
+        "no-delete-expression": true,
+        "no-disable-auto-sanitization": true,
+        "no-document-domain": true,
+        "no-document-write": true,
+        "no-eval": true,
+        "no-exec-script": true,
+        "no-function-constructor-with-string-args": true,
+        "no-http-string": [
+            true,
+            "http://www.example.com/?.*",
+            "http://www.examples.com/?.*"
+        ],
+        "no-inner-html": true,
+        "no-octal-literal": true,
+        "no-reserved-keywords": true,
+        "no-string-based-set-immediate": true,
+        "no-string-based-set-interval": true,
+        "no-string-based-set-timeout": true,
+        "non-literal-require": true,
+        "possible-timing-attack": true,
+        "react-anchor-blank-noopener": true,
+        "react-iframe-missing-sandbox": true,
+        "react-no-dangerous-html": true,
+        "forin": true,
+        "jquery-deferred-must-complete": true,
+        "label-position": true,
+        "mocha-avoid-only": true,
+        "mocha-no-side-effect-code": true,
+        "no-any": true,
+        "no-arg": true,
+        "no-backbone-get-set-outside-model": true,
+        "no-bitwise": true,
+        "no-conditional-assignment": true,
+        "no-console": false,
+        "no-constant-condition": true,
+        "no-control-regex": true,
+        "no-debugger": true,
+        "no-duplicate-case": true,
+        "no-duplicate-variable": true,
+        "no-empty": true,
+        "no-increment-decrement": true,
+        "no-invalid-regexp": true,
+        "no-invalid-this": true,
+        "no-jquery-raw-elements": true,
+        "no-misused-new": true,
+        "no-regex-spaces": true,
+        "no-sparse-arrays": true,
+        "no-stateless-class": true,
+        "no-string-literal": true,
+        "no-string-throw": true,
+        "no-unnecessary-bind": true,
+        "no-unnecessary-initializer": true,
+        "no-unnecessary-override": true,
+        "no-unsafe-finally": true,
+        "no-unused-expression": true,
+        "no-with-statement": true,
+        "promise-must-complete": true,
+        "radix": true,
+        "react-this-binding-issue": true,
+        "react-unused-props-and-state": true,
+        "switch-default": true,
+        "triple-equals": [
+            true,
+            "allow-null-check"
+        ],
+        "use-isnan": true,
+        "use-named-parameter": true,
+        "valid-typeof": true,
+        "adjacent-overload-signatures": true,
+        "array-type": [
+            true,
+            "array"
+        ],
+        "arrow-parens": true,
+        "callable-types": true,
+        "chai-prefer-contains-to-index-of": true,
+        "chai-vague-errors": true,
+        "class-name": true,
+        "comment-format": true,
+        "export-name": true,
+        "function-name": true,
+        "import-name": true,
+        "interface-name": false,
+        "jsdoc-format": true,
+        "max-classes-per-file": [
+            true,
+            3
+        ],
+        "max-file-line-count": true,
+        "max-func-body-length": [
+            true,
+            100,
+            {
+                "ignore-parameters-to-function-regex": "describe"
+            }
+        ],
+        "max-line-length": [
+            true,
+            140
+        ],
+        "member-access": true,
+        "member-ordering": [
+            true,
+            {
+                "order": "fields-first"
+            }
+        ],
+        "missing-jsdoc": true,
+        "mocha-unneeded-done": true,
+        "new-parens": true,
+        "no-construct": true,
+        "no-default-export": true,
+        "no-empty-interface": true,
+        "no-for-in": true,
+        "no-function-expression": true,
+        "no-inferrable-types": false,
+        "no-multiline-string": true,
+        "no-null-keyword": false,
+        "no-parameter-properties": true,
+        "no-relative-imports": false,
+        "no-require-imports": true,
+        "no-shadowed-variable": true,
+        "no-typeof-undefined": true,
+        "no-unnecessary-field-initialization": true,
+        "no-unnecessary-local-variable": true,
+        "no-var-keyword": true,
+        "no-var-requires": true,
+        "no-var-self": true,
+        "object-literal-sort-keys": false,
+        "one-variable-per-declaration": true,
+        "only-arrow-functions": [
+            true,
+            "allow-declarations",
+            "allow-named-functions"
+        ],
+        "ordered-imports": true,
+        "prefer-array-literal": true,
+        "prefer-const": true,
+        "prefer-for-of": true,
+        "prefer-method-signature": true,
+        "typedef": [
+            true,
+            "call-signature",
+            "arrow-call-signature",
+            "parameter",
+            "arrow-parameter",
+            "property-declaration",
+            "variable-declaration",
+            "member-variable-declaration"
+        ],
+        "underscore-consistent-invocation": true,
+        "unified-signatures": true,
+        "variable-name": true,
+        "react-a11y-anchors": true,
+        "react-a11y-aria-unsupported-elements": true,
+        "react-a11y-event-has-role": true,
+        "react-a11y-image-button-has-alt": true,
+        "react-a11y-img-has-alt": true,
+        "react-a11y-lang": true,
+        "react-a11y-meta": true,
+        "react-a11y-props": true,
+        "react-a11y-proptypes": true,
+        "react-a11y-role": true,
+        "react-a11y-role-has-required-aria-props": true,
+        "react-a11y-role-supports-aria-props": true,
+        "react-a11y-tabindex-no-positive": true,
+        "react-a11y-titles": true,
+        "align": [
+            true,
+            "statements"
+        ],
+        "curly": true,
+        "eofline": true,
+        "import-spacing": true,
+        "indent": [
+            true,
+            "spaces"
+        ],
+        "linebreak-style": false,
+        "no-consecutive-blank-lines": true,
+        "no-empty-line-after-opening-brace": true,
+        "no-trailing-whitespace": true,
+        "no-unnecessary-semicolons": true,
+        "object-literal-key-quotes": [
+            true,
+            "as-needed"
+        ],
+        "one-line": [
+            false
+        ],
+        "quotemark": [
+            true,
+            "single"
+        ],
+        "react-tsx-curly-spacing": true,
+        "semicolon": [
+            true,
+            "always"
+        ],
+        "trailing-comma": [
+            true,
+            {
+                "singleline": "never",
+                "multiline": "never"
+            }
+        ],
+        "typedef-whitespace": false,
+        "whitespace": [
+            true,
+            "check-branch",
+            "check-decl",
+            "check-operator",
+            "check-separator",
+            "check-type"
+        ],
+        "ban": false,
+        "cyclomatic-complexity": true,
+        "file-header": false,
+        "import-blacklist": false,
+        "interface-over-type-literal": true,
+        "no-internal-module": true,
+        "no-magic-numbers": true,
+        "no-mergeable-namespace": false,
+        "no-namespace": true,
+        "no-reference": true,
+        "no-unexternalized-strings": true,
+        "object-literal-shorthand": true,
+        "no-angle-bracket-type-assertion": true,
+        "prefer-type-cast": false,
+        "space-before-function-paren": false,
+        "missing-optional-annotation": false,
+        "no-duplicate-parameter-names": false,
+        "no-empty-interfaces": true,
+        "no-missing-visibility-modifiers": false,
+        "no-multiple-var-decl": false,
+        "no-switch-case-fall-through": true,
+        //As of 2017-08-21 'no-unused-variable' doesn't work well with generics, disabled for now
+        "no-unused-variable": false,
+        "typeof-compare": true,
+        "no-inferred-empty-object-type": true,
+        "await-promise": true,
+        "no-floating-promises": true,
+        "no-for-in-array": true,
+        "no-use-before-declare": true,
+        "promise-function-async": true,
+        "completed-docs": [
+            true,
+            {
+                "classes": {
+                    "visibilities": ["all"]
+                },
+                "enums": {
+                    "visibilities": ["all"]
+                },
+                "functions": {
+                    "visibilities": ["all"]
+                },
+                "interfaces": {
+                    "visibilities": ["all"]
+                },
+                "methods": {
+                    "locations": ["all"],
+                    "privacies": ["all"]
+                },
+                "namespaces": {
+                    "visibilities": ["all"]
+                },
+                "properties": {
+                    "locations": ["all"],
+                    "privacies": ["all"]
+                },
+                "types": {
+                    "visibilities": ["all"]
+                },
+                "variables": {
+                    "visibilities": ["all"]
+                }
+            }
+        ],
+        "no-unnecessary-qualifier": true,
+        "no-void-expression": true,
+        "strict-boolean-expressions": [true, "allow-null-union"],
+        // The following produce too much noise with untyped or not-sufficiently typed libraries
+        "restrict-plus-operands": false,
+        "no-unsafe-any": false
+    },
+    "rulesDirectory": ["./node_modules/tslint-microsoft-contrib/"]
+}