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
 # 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
 
-   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,
-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
-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
 
-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
 
-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
 
-Add additional notes about how to deploy this on a live system
+To deploy the NG UI use the [Dockerfile](Dockerfile)
 
 ## 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
 
@@ -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
-
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.
 
 
-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"
@@ -52,5 +52,3 @@ pushd $PKG_DIR
 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/"]
+}