aboutsummaryrefslogtreecommitdiffstats
path: root/vid-webpack-master/src
diff options
context:
space:
mode:
authorSonsino, Ofir (os0695) <os0695@intl.att.com>2018-07-10 15:57:37 +0300
committerSonsino, Ofir (os0695) <os0695@intl.att.com>2018-07-10 15:57:37 +0300
commitff76b5ed0aa91d5fdf9dc4f95e8b20f91ed9d072 (patch)
treeaae42404a93fdffdd16ff050eaa28129959f7577 /vid-webpack-master/src
parentc72d565bb58226b20625b2bce5f0019046bee649 (diff)
New Angular UI from 1806
Change-Id: I39c160db0e0a6ec2e587ccf007ee1b23c6a08666 Issue-ID: VID-208 Signed-off-by: Sonsino, Ofir (os0695) <os0695@intl.att.com>
Diffstat (limited to 'vid-webpack-master/src')
-rw-r--r--vid-webpack-master/src/WEB-INF/web.xml61
-rw-r--r--vid-webpack-master/src/app/app.component.e2e-spec.js27
-rw-r--r--vid-webpack-master/src/app/app.component.html6
-rw-r--r--vid-webpack-master/src/app/app.component.scss24
-rw-r--r--vid-webpack-master/src/app/app.component.ts28
-rw-r--r--vid-webpack-master/src/app/app.module.ts79
-rw-r--r--vid-webpack-master/src/app/app.routing.ts40
-rw-r--r--vid-webpack-master/src/app/browseSdc/browseSdc.component.html26
-rw-r--r--vid-webpack-master/src/app/browseSdc/browseSdc.component.scss59
-rw-r--r--vid-webpack-master/src/app/browseSdc/browseSdc.component.ts176
-rw-r--r--vid-webpack-master/src/app/browseSdc/browseSdc.module.ts35
-rw-r--r--vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.component.ts29
-rw-r--r--vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.css4
-rw-r--r--vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.html18
-rw-r--r--vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.html26
-rw-r--r--vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.scss40
-rw-r--r--vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.ts59
-rw-r--r--vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts80
-rw-r--r--vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html22
-rw-r--r--vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss58
-rw-r--r--vid-webpack-master/src/app/components/form-async/form-async.component.ts80
-rw-r--r--vid-webpack-master/src/app/components/form-async/form-async.style.scss15
-rw-r--r--vid-webpack-master/src/app/components/form-async/form-async.template.html67
-rw-r--r--vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts9
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts238
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html168
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss64
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts26
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts22
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts32
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.component.ts144
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.html52
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.scss185
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts138
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.service.ts33
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts275
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html114
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss64
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts241
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts64
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts26
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts55
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts190
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html54
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss185
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts827
-rw-r--r--vid-webpack-master/src/app/configuration/vid.configuration.ts98
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.html35
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.scss398
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.ts166
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.spec.ts450
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.ts36
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.html33
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.scss95
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.ts119
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-header/tmp_instansiate_request.ts52
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.component.ts133
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.html42
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.scss274
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawingBoard.module.ts41
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.html13
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.scss16
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.ts77
-rw-r--r--vid-webpack-master/src/app/factories/models/requestDetails.model.ts126
-rw-r--r--vid-webpack-master/src/app/factories/mso.factory.spec.ts319
-rw-r--r--vid-webpack-master/src/app/factories/mso.factory.ts92
-rw-r--r--vid-webpack-master/src/app/global.actions.ts23
-rw-r--r--vid-webpack-master/src/app/global.reducer.ts29
-rw-r--r--vid-webpack-master/src/app/healthStatus/health-status.component.html36
-rw-r--r--vid-webpack-master/src/app/healthStatus/health-status.component.scss187
-rw-r--r--vid-webpack-master/src/app/healthStatus/health-status.component.ts42
-rw-r--r--vid-webpack-master/src/app/home/home.component.e2e-spec.js13
-rw-r--r--vid-webpack-master/src/app/home/home.component.html3
-rw-r--r--vid-webpack-master/src/app/home/home.component.scss4
-rw-r--r--vid-webpack-master/src/app/home/home.component.ts30
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/InstantiationStatus.module.ts33
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.html84
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.scss159
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.service.ts0
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.ts83
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.html100
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.scss277
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.spec.ts278
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.ts75
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.spec.ts88
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.ts145
-rw-r--r--vid-webpack-master/src/app/modules/inputs.module.ts20
-rw-r--r--vid-webpack-master/src/app/service.actions.ts197
-rw-r--r--vid-webpack-master/src/app/service.reducer.spec.ts286
-rw-r--r--vid-webpack-master/src/app/service.reducer.ts214
-rw-r--r--vid-webpack-master/src/app/services/aaiService/aai.actions.ts75
-rw-r--r--vid-webpack-master/src/app/services/aaiService/aai.epics.ts81
-rw-r--r--vid-webpack-master/src/app/services/aaiService/aai.service.ts189
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getAicZonesResponseInterface.ts3
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getCategoryParamsResponseInterface.ts10
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServiceModelResponseInterface.ts5
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServicesResponseInterface.ts9
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubDetailsResponseInterface.ts12
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubscribersResponseInterface.ts5
-rw-r--r--vid-webpack-master/src/app/services/configuration.service.ts34
-rw-r--r--vid-webpack-master/src/app/services/data.service.ts528
-rw-r--r--vid-webpack-master/src/app/services/flags.resolve.ts14
-rw-r--r--vid-webpack-master/src/app/services/msoService/mso.service.ts26
-rw-r--r--vid-webpack-master/src/app/services/sdc.service.ts28
-rw-r--r--vid-webpack-master/src/app/services/service-planning.service.spec.ts467
-rw-r--r--vid-webpack-master/src/app/services/service-planning.service.ts282
-rw-r--r--vid-webpack-master/src/app/shared/api.service.ts6
-rw-r--r--vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts27
-rw-r--r--vid-webpack-master/src/app/shared/components/error/error.component.service.ts35
-rw-r--r--vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.html4
-rw-r--r--vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.scss14
-rw-r--r--vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.ts10
-rw-r--r--vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.html10
-rw-r--r--vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.scss48
-rw-r--r--vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.ts11
-rw-r--r--vid-webpack-master/src/app/shared/components/messageBox/messageBox.component.ts50
-rw-r--r--vid-webpack-master/src/app/shared/components/messageBox/messageBox.data.ts51
-rw-r--r--vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.spec.ts49
-rw-r--r--vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.ts18
-rw-r--r--vid-webpack-master/src/app/shared/components/model-information/model-information.component.ts42
-rw-r--r--vid-webpack-master/src/app/shared/components/model-information/model-information.html12
-rw-r--r--vid-webpack-master/src/app/shared/components/model-information/model-information.scss34
-rw-r--r--vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.html5
-rw-r--r--vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.scss26
-rw-r--r--vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.ts23
-rw-r--r--vid-webpack-master/src/app/shared/components/popover/popover.component.html8
-rw-r--r--vid-webpack-master/src/app/shared/components/popover/popover.component.scss4
-rw-r--r--vid-webpack-master/src/app/shared/components/popover/popover.component.ts17
-rw-r--r--vid-webpack-master/src/app/shared/components/spinner/spinner.component.html2
-rw-r--r--vid-webpack-master/src/app/shared/components/spinner/spinner.component.scss87
-rw-r--r--vid-webpack-master/src/app/shared/components/spinner/spinner.component.spec.ts42
-rw-r--r--vid-webpack-master/src/app/shared/components/spinner/spinner.component.ts18
-rw-r--r--vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.spec.ts39
-rw-r--r--vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.ts20
-rw-r--r--vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.spec.ts66
-rw-r--r--vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.ts24
-rw-r--r--vid-webpack-master/src/app/shared/directives/svg/svg.directive.html0
-rw-r--r--vid-webpack-master/src/app/shared/directives/svg/svg.directive.ts34
-rw-r--r--vid-webpack-master/src/app/shared/index.ts1
-rw-r--r--vid-webpack-master/src/app/shared/models/ServiceNodeTypes.ts8
-rw-r--r--vid-webpack-master/src/app/shared/models/aicZone.ts9
-rw-r--r--vid-webpack-master/src/app/shared/models/categoryParams.ts15
-rw-r--r--vid-webpack-master/src/app/shared/models/dynamicInput.ts123
-rw-r--r--vid-webpack-master/src/app/shared/models/externalComponentStatus.ts11
-rw-r--r--vid-webpack-master/src/app/shared/models/inputTypes.ts12
-rw-r--r--vid-webpack-master/src/app/shared/models/lcpRegion.ts11
-rw-r--r--vid-webpack-master/src/app/shared/models/lcpRegionTenants.ts13
-rw-r--r--vid-webpack-master/src/app/shared/models/lcpRegionsAndTenants.ts12
-rw-r--r--vid-webpack-master/src/app/shared/models/modelInfo.ts21
-rw-r--r--vid-webpack-master/src/app/shared/models/nodeModel.ts29
-rw-r--r--vid-webpack-master/src/app/shared/models/owningEntity.ts14
-rw-r--r--vid-webpack-master/src/app/shared/models/productFamily.ts13
-rw-r--r--vid-webpack-master/src/app/shared/models/project.ts14
-rw-r--r--vid-webpack-master/src/app/shared/models/selectOption.ts17
-rw-r--r--vid-webpack-master/src/app/shared/models/serviceInstance.ts28
-rw-r--r--vid-webpack-master/src/app/shared/models/serviceModel.ts44
-rw-r--r--vid-webpack-master/src/app/shared/models/serviceNodeTypeToModelKeyMapper.ts8
-rw-r--r--vid-webpack-master/src/app/shared/models/serviceType.ts17
-rw-r--r--vid-webpack-master/src/app/shared/models/subscriber.ts11
-rw-r--r--vid-webpack-master/src/app/shared/models/tenant.ts11
-rw-r--r--vid-webpack-master/src/app/shared/models/vfModule.ts39
-rw-r--r--vid-webpack-master/src/app/shared/models/vfModuleInstance.ts5
-rw-r--r--vid-webpack-master/src/app/shared/models/vfModuleTreeNode.ts17
-rw-r--r--vid-webpack-master/src/app/shared/models/vfModulesMap.ts5
-rw-r--r--vid-webpack-master/src/app/shared/models/vfcInstanceGroup.ts14
-rw-r--r--vid-webpack-master/src/app/shared/models/vfcInstanceGroupMap.ts5
-rw-r--r--vid-webpack-master/src/app/shared/models/vfcInstanceGroupProperties.ts7
-rw-r--r--vid-webpack-master/src/app/shared/models/vnfInstance.ts19
-rw-r--r--vid-webpack-master/src/app/shared/models/vnfModel.ts52
-rw-r--r--vid-webpack-master/src/app/shared/models/vnfTreeNode.ts18
-rw-r--r--vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.spec.ts25
-rw-r--r--vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.ts12
-rw-r--r--vid-webpack-master/src/app/shared/pipes/data-filter.pipe.ts29
-rw-r--r--vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.spec.ts43
-rw-r--r--vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.ts12
-rw-r--r--vid-webpack-master/src/app/shared/pipes/highlight-filter.pipe.ts10
-rw-r--r--vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.spec.ts58
-rw-r--r--vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.ts13
-rw-r--r--vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.spec.ts60
-rw-r--r--vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.ts17
-rw-r--r--vid-webpack-master/src/app/shared/server/serviceInfo/AuditStatus.model.ts10
-rw-r--r--vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.model.ts38
-rw-r--r--vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts235
-rw-r--r--vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts38
-rw-r--r--vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts73
-rw-r--r--vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts82
-rw-r--r--vid-webpack-master/src/app/shared/shared.module.ts92
-rw-r--r--vid-webpack-master/src/app/shared/utils/constants.ts287
-rw-r--r--vid-webpack-master/src/app/shared/utils/httpInterceptor/httpInterceptor.service.ts32
-rw-r--r--vid-webpack-master/src/app/shared/utils/iframe.service.ts19
-rw-r--r--vid-webpack-master/src/app/shared/utils/log/log.service.spec.ts29
-rw-r--r--vid-webpack-master/src/app/shared/utils/log/log.service.ts58
-rw-r--r--vid-webpack-master/src/app/store/epics.ts13
-rw-r--r--vid-webpack-master/src/app/store/module.ts29
-rw-r--r--vid-webpack-master/src/app/store/reducers.ts17
-rw-r--r--vid-webpack-master/src/app/utils/utils.ts271
-rw-r--r--vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.html14
-rw-r--r--vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.scss17
-rw-r--r--vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.ts66
-rw-r--r--vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.html27
-rw-r--r--vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.scss168
-rw-r--r--vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.ts203
-rw-r--r--vid-webpack-master/src/app/vlanTagging/vlan-tagging.module.ts33
-rw-r--r--vid-webpack-master/src/assets/.gitkeep0
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/Apache License.txt201
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Bold.ttfbin0 -> 224592 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-BoldItalic.ttfbin0 -> 213292 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-ExtraBold.ttfbin0 -> 222584 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttfbin0 -> 213420 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Italic.ttfbin0 -> 212896 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Light.ttfbin0 -> 222412 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-LightItalic.ttfbin0 -> 213128 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Regular.ttfbin0 -> 217360 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Semibold.ttfbin0 -> 221328 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-SemiboldItalic.ttfbin0 -> 212820 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/icomoon.eotbin0 -> 14864 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/icomoon.svg70
-rw-r--r--vid-webpack-master/src/assets/fonts/icomoon.ttfbin0 -> 14700 bytes
-rw-r--r--vid-webpack-master/src/assets/fonts/icomoon.woffbin0 -> 14776 bytes
-rw-r--r--vid-webpack-master/src/assets/img/Menu.svg8
-rw-r--r--vid-webpack-master/src/assets/img/UPLOAD.svg15
-rw-r--r--vid-webpack-master/src/assets/img/X_o.svg8
-rw-r--r--vid-webpack-master/src/assets/img/angular.pngbin0 -> 4509 bytes
-rw-r--r--vid-webpack-master/src/assets/img/chevron.svg8
-rw-r--r--vid-webpack-master/src/assets/img/fail.svg8
-rw-r--r--vid-webpack-master/src/assets/img/favicon.icobin0 -> 5430 bytes
-rw-r--r--vid-webpack-master/src/assets/img/inprogress.svg14
-rw-r--r--vid-webpack-master/src/assets/img/pause.svg14
-rw-r--r--vid-webpack-master/src/assets/img/pending.svg14
-rw-r--r--vid-webpack-master/src/assets/img/stoped.svg14
-rw-r--r--vid-webpack-master/src/assets/img/success+Circle.svg14
-rw-r--r--vid-webpack-master/src/environments/environment.prod.ts3
-rw-r--r--vid-webpack-master/src/environments/environment.ts8
-rw-r--r--vid-webpack-master/src/index.html12
-rw-r--r--vid-webpack-master/src/main.ts11
-rw-r--r--vid-webpack-master/src/polyfills.ts66
-rw-r--r--vid-webpack-master/src/public/img/UPLOAD.svg15
-rw-r--r--vid-webpack-master/src/public/img/angular.pngbin0 -> 4509 bytes
-rw-r--r--vid-webpack-master/src/public/img/favicon.icobin0 -> 5430 bytes
-rw-r--r--vid-webpack-master/src/public/img/spinner.gifbin0 -> 7358 bytes
-rw-r--r--vid-webpack-master/src/public/index.html14
-rw-r--r--vid-webpack-master/src/public/service-worker.js1
-rw-r--r--vid-webpack-master/src/style/app.scss125
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/Apache License.txt201
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Bold.ttfbin0 -> 224592 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-BoldItalic.ttfbin0 -> 213292 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-ExtraBold.ttfbin0 -> 222584 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttfbin0 -> 213420 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Italic.ttfbin0 -> 212896 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Light.ttfbin0 -> 222412 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-LightItalic.ttfbin0 -> 213128 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Regular.ttfbin0 -> 217360 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Semibold.ttfbin0 -> 221328 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/OpenSans/OpenSans-SemiboldItalic.ttfbin0 -> 212820 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/icomoon.eotbin0 -> 14864 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/icomoon.svg70
-rw-r--r--vid-webpack-master/src/style/fonts/icomoon.ttfbin0 -> 14700 bytes
-rw-r--r--vid-webpack-master/src/style/fonts/icomoon.woffbin0 -> 14776 bytes
-rw-r--r--vid-webpack-master/src/styles.scss171
-rw-r--r--vid-webpack-master/src/test.ts20
-rw-r--r--vid-webpack-master/src/tsconfig.app.json13
-rw-r--r--vid-webpack-master/src/tsconfig.spec.json19
-rw-r--r--vid-webpack-master/src/vendor.ts16
263 files changed, 15796 insertions, 0 deletions
diff --git a/vid-webpack-master/src/WEB-INF/web.xml b/vid-webpack-master/src/WEB-INF/web.xml
new file mode 100644
index 000000000..a4152daaa
--- /dev/null
+++ b/vid-webpack-master/src/WEB-INF/web.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
+
+ <!-- This is a stub web.xml in the common area -->
+ <display-name>vid-ebpack-master</display-name>
+
+ <!--
+ `vid-webpack-master` servlet and it's servlet mapping below, serves
+ Angular's index.html for any requests like the following, letting
+ the JavaScript router do its magic:
+ * /vid/app/ui/
+ * /vid/app/ui/servicePlanning
+ * /vid/app/ui/browseSdc
+ -->
+ <servlet>
+ <servlet-name>vid-webpack-master</servlet-name>
+ <jsp-file>/app/ui/index.html</jsp-file>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>vid-webpack-master</servlet-name>
+ <url-pattern>/app/ui/*</url-pattern>
+ </servlet-mapping>
+
+
+ <!--
+ All the files under the paths below are served as static files, using
+ tomcat's `default` servlet. This overrides the `vid-webpack-master`
+ url-pattern.
+ The filter `charset-to-utf8-filter` adds "charset=UTF-8" to these files
+ content type, as the default content-type is platform-dependant (which
+ is not ok for Windows stations).
+ -->
+ <servlet-mapping>
+ <servlet-name>default</servlet-name>
+ <url-pattern>/app/ui/css/*</url-pattern>
+ <url-pattern>/app/ui/fonts/*</url-pattern>
+ <url-pattern>/app/ui/img/*</url-pattern>
+ <url-pattern>/app/ui/js/*</url-pattern>
+ </servlet-mapping>
+
+ <filter>
+ <filter-name>charset-to-utf8-filter</filter-name>
+ <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
+ <init-param>
+ <param-name>encoding</param-name>
+ <param-value>UTF-8</param-value>
+ </init-param>
+ <init-param>
+ <param-name>forceEncoding</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>charset-to-utf8-filter</filter-name>
+ <url-pattern>/app/ui/*</url-pattern>
+ </filter-mapping>
+
+</web-app>
diff --git a/vid-webpack-master/src/app/app.component.e2e-spec.js b/vid-webpack-master/src/app/app.component.e2e-spec.js
new file mode 100644
index 000000000..9ec9d23db
--- /dev/null
+++ b/vid-webpack-master/src/app/app.component.e2e-spec.js
@@ -0,0 +1,27 @@
+describe('App', function () {
+
+ beforeEach(function () {
+ browser.get('/');
+ });
+
+ it('should have a title', function () {
+ expect(browser.getTitle()).toEqual("Angular 2 App | ng2-webpack");
+ });
+
+ it('should have <header>', function () {
+ expect(element(by.css('my-app header')).isPresent()).toEqual(true);
+ });
+
+ it('should have <main>', function () {
+ expect(element(by.css('my-app main')).isPresent()).toEqual(true);
+ });
+
+ it('should have a main title', function () {
+ expect(element(by.css('main h1')).getText()).toEqual('Hello from Angular 2!');
+ });
+
+ it('should have <footer>', function () {
+ expect(element(by.css('my-app footer')).getText()).toEqual("Webpack Angular 2 Starter");
+ });
+
+});
diff --git a/vid-webpack-master/src/app/app.component.html b/vid-webpack-master/src/app/app.component.html
new file mode 100644
index 000000000..3768d0c53
--- /dev/null
+++ b/vid-webpack-master/src/app/app.component.html
@@ -0,0 +1,6 @@
+<main>
+ <router-outlet>
+ <message-box></message-box>
+ <spinner-component></spinner-component>
+ </router-outlet>
+</main>
diff --git a/vid-webpack-master/src/app/app.component.scss b/vid-webpack-master/src/app/app.component.scss
new file mode 100644
index 000000000..9149aefc0
--- /dev/null
+++ b/vid-webpack-master/src/app/app.component.scss
@@ -0,0 +1,24 @@
+// styles applied on :host are applied on the current component, "app" in this case
+:host {
+ display: block;
+}
+
+header {
+ background-color: #fff;
+ padding: 16px;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5);
+}
+
+main {
+ font-family: Arial, Helvetica, sans-serif;
+ display: block;
+}
+
+footer {
+ text-align: center;
+ font-size: 0.8em;
+}
diff --git a/vid-webpack-master/src/app/app.component.ts b/vid-webpack-master/src/app/app.component.ts
new file mode 100644
index 000000000..528c7d7a4
--- /dev/null
+++ b/vid-webpack-master/src/app/app.component.ts
@@ -0,0 +1,28 @@
+import {Component, Inject} from '@angular/core';
+
+import { ApiService } from './shared';
+
+import '../style/app.scss';
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "./store/reducers";
+import { LogService } from './shared/utils/log/log.service';
+
+@Component({
+ selector: 'vid-app', // <vid-app></vid-app>
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.scss'],
+})
+export class AppComponent {
+ url = 'https://github.com/preboot/angular2-webpack';
+ title: string;
+
+
+ constructor(private api: ApiService, private store: NgRedux<AppState>, private _logService : LogService) {
+ this.title = this.api.title;
+ store.subscribe(()=>{
+ sessionStorage.setItem('reduxState', JSON.stringify(store.getState()));
+ });
+
+ this._logService.info("testing new log service");
+ }
+}
diff --git a/vid-webpack-master/src/app/app.module.ts b/vid-webpack-master/src/app/app.module.ts
new file mode 100644
index 000000000..a87ffb5b7
--- /dev/null
+++ b/vid-webpack-master/src/app/app.module.ts
@@ -0,0 +1,79 @@
+import { ApplicationRef, NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { AppComponent } from './app.component';
+import { HomeComponent } from './home/home.component';
+import { ApiService } from './shared';
+import { routing } from './app.routing';
+import { createNewHosts, removeNgStyles } from '@angularclass/hmr';
+import { BrowseSdcModule } from './browseSdc/browseSdc.module';
+import { VlanTaggingModule } from './vlanTagging/vlan-tagging.module'
+import { BootstrapModalModule } from 'ng2-bootstrap-modal';
+import { HashLocationStrategy, LocationStrategy } from "@angular/common";
+import { InstantiationStatusModule } from './instantiationStatus/InstantiationStatus.module';
+import { SharedModule } from './shared/shared.module';
+import { AngularSvgIconModule } from 'angular-svg-icon';
+import { NgReduxModule } from '@angular-redux/store';
+import { StoreModule } from "./store/module";
+import { HttpInterceptorService } from './shared/utils/httpInterceptor/httpInterceptor.service';
+import { DrawingBoardModule } from './drawingBoard/drawingBoard.module';
+import { HealthStatusComponent } from './healthStatus/health-status.component';
+import { ScrollToModule } from '@nicky-lenaers/ngx-scroll-to';
+import { LogService } from './shared/utils/log/log.service';
+
+@NgModule({
+ imports: [
+ BrowserModule,
+ HttpClientModule,
+ FormsModule,
+ routing,
+ SharedModule.forRoot(),
+ ScrollToModule.forRoot(),
+ DrawingBoardModule,
+ VlanTaggingModule,
+ InstantiationStatusModule,
+ BrowseSdcModule,
+ BootstrapModalModule,
+ BrowseSdcModule,
+ AngularSvgIconModule,
+ ReactiveFormsModule,
+ NgReduxModule,
+ StoreModule,
+ ],
+ declarations: [
+ AppComponent,
+ HomeComponent,
+ HealthStatusComponent
+ ],
+ providers: [
+ ApiService,
+ LogService,
+ { provide: LocationStrategy, useClass: HashLocationStrategy },
+ { provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorService, multi: true }
+ ],
+ bootstrap: [AppComponent]
+})
+export class AppModule {
+ private static CustomLoader: any;
+
+ constructor(public appRef: ApplicationRef) {
+ //for ng2-bootstrap-modal in angualar 5
+ Object.defineProperty(appRef, '_rootComponents', { get: () => appRef['components'] });
+ }
+ hmrOnInit(store) {
+ console.log('HMR store', store);
+ }
+ hmrOnDestroy(store) {
+ let cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement);
+ // recreate elements
+ store.disposeOldHosts = createNewHosts(cmpLocation);
+ // remove styles
+ removeNgStyles();
+ }
+ hmrAfterDestroy(store) {
+ // display new elements
+ store.disposeOldHosts();
+ delete store.disposeOldHosts;
+ }
+}
diff --git a/vid-webpack-master/src/app/app.routing.ts b/vid-webpack-master/src/app/app.routing.ts
new file mode 100644
index 000000000..e6f42f9ed
--- /dev/null
+++ b/vid-webpack-master/src/app/app.routing.ts
@@ -0,0 +1,40 @@
+import {RouterModule, Routes} from '@angular/router';
+
+import {HomeComponent} from './home/home.component';
+import {BrowseSdcComponent} from './browseSdc/browseSdc.component';
+import {ServicePlanningComponent, ServicePlanningEmptyComponent} from './drawingBoard/service-planning/service-planning.component';
+import {VlanTaggingComponent} from './vlanTagging/vlan-tagging.component';
+import {ServicePopupComponent} from './components/service-popup/service-popup.component';
+import { InstantiationStatusComponent } from './instantiationStatus/instantiationStatus.component';
+import {HealthStatusComponent} from "./healthStatus/health-status.component";
+import {FlagsResolve} from "./services/flags.resolve";
+
+const routes: Routes = [
+ { path: '', component: HomeComponent, pathMatch: 'full' ,resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'browseSdc', component: BrowseSdcComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'servicePlanning', component: ServicePlanningComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'servicePlanningEmpty', component: ServicePlanningEmptyComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'servicePopup', component: ServicePopupComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path :'vlan', component : VlanTaggingComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'instantiationStatus', component: InstantiationStatusComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'healthStatus', component: HealthStatusComponent, resolve : {
+ flags : FlagsResolve,
+ }}
+
+];
+
+export const routing = RouterModule.forRoot(routes);
diff --git a/vid-webpack-master/src/app/browseSdc/browseSdc.component.html b/vid-webpack-master/src/app/browseSdc/browseSdc.component.html
new file mode 100644
index 000000000..7ffd7931c
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/browseSdc.component.html
@@ -0,0 +1,26 @@
+<div>
+
+ <span class="statusLine" [hidden]="!isSpinnerVisible">
+ <img src="./img/spinner.gif"/>
+ </span>
+ <span class="statusLine" [hidden]="!isProgressVisible">
+ <label>Status:</label><span class="status"><span [hidden]="!error"><font color='red'><b>Error: </b></font></span>{{status}}</span>
+ </span>
+ <br><br>
+ <div>
+ <input class="form-control search-query" placeholder="Filter..." data-tests-id="browseFilter" type="text" [(ngModel)]="filterQuery" size="20" style="width: 250px;">
+ </div>
+
+ <h1 class="heading1" style="margin-top:20px;">Browse SDC Service Models</h1>
+ <div style="margin-top:30px">
+ <button (click)="deploy()">deploy</button>
+ <vid-table
+ [options]="tableOptions"
+ [filterQuery]="filterQuery"
+ (clickEvent)="clickAction($event)">
+ Loading table...
+ </vid-table>
+ </div>
+</div>
+
+
diff --git a/vid-webpack-master/src/app/browseSdc/browseSdc.component.scss b/vid-webpack-master/src/app/browseSdc/browseSdc.component.scss
new file mode 100644
index 000000000..0d1678a94
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/browseSdc.component.scss
@@ -0,0 +1,59 @@
+div[ng-controller=ServiceModelController] .popupContents {
+ text-align: left;
+}
+
+div[ng-controller=ServiceModelController] .statusLine {
+ vertical-align: center;
+}
+
+div[ng-controller=ServiceModelController] .statusLine img {
+ width: 20px;
+ margin: 10px;
+}
+
+div[ng-controller=ServiceModelController] .status {
+ margin-left: 5px;
+}
+
+div[ng-controller=ServiceModelController] .feedback {
+ height: 35px;
+ vertical-align: center;
+}
+
+div[ng-controller=ServiceModelController] .progress {
+ margin: 0px 10px;
+ font-weight: bold;
+}
+
+div[ng-controller=ServiceModelController] .error {
+ width: 630px;
+ font-weight: bold;
+ font-size: 16px;
+ color: red;
+ margin: 0px 10px 0px 45px;
+}
+
+div[ng-controller=ServiceModelController] .error img {
+ width: 25px;
+ margin: 0px 10px;
+}
+
+div[ng-controller=ServiceModelController] .buttonRow {
+ text-align: center;
+ margin-bottom: 10px;
+}
+
+div[ng-controller=ServiceModelController] .log {
+ width: 700px;
+ height: 500px;
+ border: solid black 1px;
+ text-align: left !important;
+ margin: 10px;
+ padding: 10px;
+ overflow: auto;
+}
+
+
+.previous-versions-button {
+ width: 113px;
+}
diff --git a/vid-webpack-master/src/app/browseSdc/browseSdc.component.ts b/vid-webpack-master/src/app/browseSdc/browseSdc.component.ts
new file mode 100644
index 000000000..46f37dc2e
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/browseSdc.component.ts
@@ -0,0 +1,176 @@
+import {Component, Input, OnInit} from '@angular/core';
+import * as _ from 'lodash';
+import {SdcService} from '../services/sdc.service';
+import {DialogService} from 'ng2-bootstrap-modal';
+import {Constants} from '../shared/utils/constants';
+import {CustomTableColumnDefinition, CustomTableOptions} from './vid-table/vid-table.component';
+import {ServicePopupComponent} from "../components/service-popup/service-popup.component";
+import { PreviousVersionsComponent } from './previous-versions/previous-versions.component';
+
+@Component({
+ selector: 'browse-sdc',
+ templateUrl: './browseSdc.component.html',
+ styleUrls: ['./browseSdc.component.scss']
+})
+
+
+export class BrowseSdcComponent implements OnInit {
+
+ isSpinnerVisible = false;
+ isProgressVisible = false;
+ error: boolean;
+ status: string;
+ // table
+
+ private basicColumns: CustomTableColumnDefinition[];
+ @Input () filterQuery = '';
+ tableOptions: CustomTableOptions;
+ private wholeData: any[];
+
+ constructor(private _sdcService: SdcService, private dialogService: DialogService) {}
+
+ initTableOptions() {
+ this.basicColumns = [
+ { displayName: 'Action', key: 'action', type: 'button' , text: 'deploy', action: 'deploy' },
+ { displayName: 'UUID', key: 'uuid', filter: 'text'},
+ { displayName: 'invariantUUID', key: 'invariantUUID', filter: 'text'},
+ { displayName: 'Name', key: 'name', filter: 'text'},
+ { displayName: 'Version', key: 'version', filter: 'text'},
+ { displayName: 'Category', key: 'category', filter: 'text'},
+ { displayName: 'Distribution Status', key: 'distributionStatus', filter: 'text'},
+ { displayName: 'Last Updated By', key: 'lastUpdaterUserId', filter: 'text'},
+ { displayName: 'Tosca Model', key: 'toscaModelUrl', filter: 'text'}
+ ];
+
+ let columns: CustomTableColumnDefinition[] = this.basicColumns.concat(
+ {displayName: 'Action', key: 'actions', type: 'button', text: 'Previous Versions',
+ showCondition: 'hasPreviousVersion', action: 'loadPreviousData' }
+ );
+
+ this.tableOptions = {
+ data: [],
+ columns: columns,
+ config: {
+ sortBy: 'name',
+ sortOrder: 'asc',
+ pageSize: 10,
+ pageNumber: 1,
+ totalCount: 0,
+ totalPages: 0,
+ maxSize: 10,
+ showSelectCheckbox: true,
+ showSelectAll: true,
+ showSort: true,
+ clientSort: true,
+ clientPaging: true,
+ // displayPager: true,
+ // displayPageSize: true,
+ stickyHeader: true,
+ stickyHeaderOffset: 0,
+ stickyContainer: '.table1-container'
+ },
+ };
+ }
+ private deploy(service: any): void {
+ if (service) {
+ console.log('this row uuid:' + service.uuid);
+ }
+
+ this.dialogService.addDialog(ServicePopupComponent, {
+ })
+ }
+
+ private filterDataWithHigherVersion(serviceData) {
+ let delimiter = '$$';
+ let filterDataServices = {};
+ for (let i = 0; i < serviceData.length; i++) {
+ let index = serviceData[i].invariantUUID.trim() + delimiter + serviceData[i].name.trim();
+ if (!filterDataServices[index]) {
+ filterDataServices[index] = {
+ service: serviceData[i],
+ hasPreviousVersion: false
+ };
+ } else {
+ filterDataServices[index].hasPreviousVersion = true;
+ if (parseFloat(serviceData[i].version.trim()) > parseFloat(filterDataServices[index].service.version.trim())) {
+ filterDataServices[index].service = serviceData[i];
+ }
+ }
+ }
+ return Object.keys(filterDataServices).map(function (key) {
+ let service = filterDataServices[key].service;
+ service.hasPreviousVersion = filterDataServices[key].hasPreviousVersion;
+ return service;
+ });
+ }
+
+ private initData() {
+ this.isProgressVisible = true;
+ this.isSpinnerVisible = true;
+ console.log('getServicesModels: ');
+ this._sdcService.getServicesModels().subscribe(
+ // onNext() function
+ value => this.getServiceCallback(value),
+ // onError() function
+ error => this.getServiceOnError(error),
+ // onComplete() function
+ () => console.log('completed')
+ );
+ }
+
+ private getServiceCallback(responseBody: any): void {
+ console.log('response is ' , responseBody);
+ this.wholeData = responseBody.services;
+ this.tableOptions.data = this.filterDataWithHigherVersion(responseBody.services);
+ this.isSpinnerVisible = false;
+ this.isProgressVisible = false;
+ }
+ private getServiceOnError(error: any): void {
+ console.log('error is ' , error);
+ this.status = Constants.Status.FAILED_SERVICE_MODELS_ASDC;
+ this.error = true;
+ this.isSpinnerVisible = false;
+ }
+
+ private loadPreviousVersionData(service): void {
+ let previousVersionData: any[] = _.filter(this.wholeData, function(item) {
+ return item.invariantUUID === service.invariantUUID && item.name === service.name && service.version !== item.version;
+ });
+
+ let modalTableOptions: CustomTableOptions = {
+ data: previousVersionData,
+ columns: this.basicColumns,
+ config: {
+ sortBy: 'version',
+ sortOrder: 'desc'}
+ };
+ // open modal
+ this.dialogService.addDialog(PreviousVersionsComponent, {
+ title: service.name + ' - Previous Version',
+ tableOptions: modalTableOptions
+ })
+ .subscribe( service => {
+ if (service) {
+ this.deploy(service);
+ }
+ });
+ }
+
+
+ public clickAction(row) {
+ switch (row.actionName) {
+ case 'loadPreviousData':
+ this.loadPreviousVersionData(row);
+ break;
+ case 'deploy':
+ this.deploy(row);
+ break;
+ }
+ }
+
+ ngOnInit() {
+ console.log('Browse SDC Service Models');
+ this.initTableOptions();
+ this.initData();
+ }
+}
diff --git a/vid-webpack-master/src/app/browseSdc/browseSdc.module.ts b/vid-webpack-master/src/app/browseSdc/browseSdc.module.ts
new file mode 100644
index 000000000..b7dd78e54
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/browseSdc.module.ts
@@ -0,0 +1,35 @@
+
+import { NgModule } from '@angular/core';
+import {BrowseSdcComponent} from './browseSdc.component';
+import {VidTableComponent} from './vid-table/vid-table.component';
+import {SdcService} from '../services/sdc.service';
+import {CommonModule} from '@angular/common';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import {DataTableModule} from 'angular2-datatable';
+import {BootstrapModalModule} from 'ng2-bootstrap-modal';
+import {PreviousVersionsComponent} from './previous-versions/previous-versions.component';
+import {ServicePopupComponent} from '../components/service-popup/service-popup.component';
+import {ServiceInstanceDetailsComponent} from "../components/service-popup/service-instance-details/service-instance-details.component";
+import {TooltipModule} from 'ngx-tooltip';
+import {InputsModule} from "../modules/inputs.module";
+import {VnfPopupComponent} from "../components/vnf-popup/vnf-popup.components";
+import {VnfInstanceDetailsComponent} from "../components/vnf-popup/vnf-instance-details/vnf-instance-details.component";
+import { VnfInstanceDetailsService } from '../components/vnf-popup/vnf-instance-details/vnf-instance-details.service';
+import { SharedModule } from '../shared/shared.module';
+import { ServiceInstanceDetailsService } from '../components/service-popup/service-instance-details/service-instance-details.service';
+import { ServicePopupService } from '../components/service-popup/service-popup.service';
+import { DataFilterPipe } from '../shared/pipes/data-filter.pipe';
+
+
+@NgModule({
+ imports: [CommonModule, FormsModule, ReactiveFormsModule, BootstrapModalModule, DataTableModule, TooltipModule, InputsModule, SharedModule.forRoot()],
+ providers: [SdcService, VnfInstanceDetailsService, ServiceInstanceDetailsService, ServicePopupService],
+ declarations: [BrowseSdcComponent, VidTableComponent, DataFilterPipe, PreviousVersionsComponent,
+ ServicePopupComponent, ServiceInstanceDetailsComponent, VnfPopupComponent, VnfInstanceDetailsComponent
+ ],
+ entryComponents: [BrowseSdcComponent, PreviousVersionsComponent, ServicePopupComponent, VnfPopupComponent],
+ exports: [ ]
+
+})
+
+export class BrowseSdcModule { }
diff --git a/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.component.ts b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.component.ts
new file mode 100644
index 000000000..8faf04d6c
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.component.ts
@@ -0,0 +1,29 @@
+import { Component } from '@angular/core';
+import { DialogComponent, DialogService } from 'ng2-bootstrap-modal';
+import { CustomTableOptions } from '../vid-table/vid-table.component';
+
+export interface PreviousVersionsModel {
+
+ title: string;
+ tableOptions: CustomTableOptions;
+}
+
+@Component({
+ selector: 'previous-versions',
+ templateUrl: 'previous-versions.html',
+ styleUrls: ['previous-versions.css']
+})
+export class PreviousVersionsComponent extends DialogComponent<PreviousVersionsModel, boolean> implements PreviousVersionsModel {
+
+ title: string;
+ tableOptions: CustomTableOptions;
+
+ constructor(dialogService: DialogService) {
+ super(dialogService);
+ }
+
+ public deploy(row) {
+ this.result = row;
+ this.close();
+ }
+}
diff --git a/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.css b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.css
new file mode 100644
index 000000000..92bcbd100
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.css
@@ -0,0 +1,4 @@
+.modal-dialog {
+ width: 1145px;
+ font-size: 11px;
+}
diff --git a/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.html b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.html
new file mode 100644
index 000000000..68209b8e8
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.html
@@ -0,0 +1,18 @@
+<div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" (click)="close()" >&times;</button>
+ <h4 class="modal-title">{{title}}</h4>
+ </div>
+ <div class="modal-body">
+ <vid-table
+ [options]="tableOptions"
+ (clickEvent)="deploy($event)">
+ Loading table...
+ </vid-table>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" (click)="close()" >Cancel</button>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.html b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.html
new file mode 100644
index 000000000..5650e5d35
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.html
@@ -0,0 +1,26 @@
+<table class="table table-hover table-striped table-sortable" [mfData]="options.data | dataFilter : filterQuery" #mf="mfDataTable" [(mfSortBy)]="options.config.sortBy" [(mfSortOrder)]="options.config.sortOrder" [mfRowsOnPage]="10">
+ <thead>
+ <tr>
+ <th *ngFor="let column of options.columns">
+ <mfDefaultSorter by="{{column.key}}"> {{column.displayName}}</mfDefaultSorter>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let row of mf.data">
+ <td *ngFor="let column of options.columns" >
+ <button class="btn btn-primary" *ngIf="column.type==='button' && (!column.showCondition || row[column.showCondition])" title="{{column.text}}" (click)="clickBtn(row, column.action)">
+ {{column.text}}
+ </button>
+ {{row[column.key]}}
+ </td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td colspan="5">
+ <mfBootstrapPaginator [rowsOnPageSet]="[10,15,20]"></mfBootstrapPaginator>
+ </td>
+ </tr>
+ </tfoot>
+</table>
diff --git a/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.scss b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.scss
new file mode 100644
index 000000000..f34887987
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.scss
@@ -0,0 +1,40 @@
+table > thead > tr > th {
+ cursor: pointer;
+ position: relative;
+ background-image: none;
+ color: #fff;
+ background-color: #666;
+ a{
+ color: #fff;
+ }
+}
+
+.table-sortable > thead > tr > th:after,
+.table-sortable > thead > tr > th.sort-false:after,
+.table-sortable > thead > tr > th.sort-true:after {
+ font-family: FontAwesome;
+ padding-left: 5px;
+}
+
+.table-sortable > thead > tr > th:after {
+ content: "\f0dc";
+ color: #ddd;
+}
+.table-sortable > thead > tr > th.sort-false:after {
+ content: "\f0de";
+ color: #767676;
+}
+.table-sortable > thead > tr > th.sort-true:after {
+ content: "\f0dd";
+ color: #767676;
+}
+//.table-sortable > tbody > td >
+.table-sortable {
+ tbody{
+ td{
+ .btn-primary{
+ min-width: 100px;
+ }
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.ts b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.ts
new file mode 100644
index 000000000..aa2030908
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.ts
@@ -0,0 +1,59 @@
+/**
+ * Created by cp2122 on 1/2/2018.
+ */
+import { Component, Input, EventEmitter, Output } from '@angular/core';
+export class CustomTableColumnDefinition {
+ public displayName = '';
+ public key = '';
+ public type? = 'text';
+ public text? = ''; // for button
+ public action? = ''; // for button - callback
+ public showCondition? = ''; // for button
+ // public binding = '';
+ public filter? = '';
+ // public computedClass: any;
+ // public isComputed = false;
+ // public isAnchor = false;
+ // public srefBinding = '';
+}
+
+export class CustomTableConfig {
+ public sortBy = '';
+ public sortOrder = 'desc';
+ public pageSize? = 10;
+ public pageNumber? = 1;
+ public totalCount? = 0;
+ public totalPages? = 0;
+ public maxSize? = 10;
+ public showSelectCheckbox? = false;
+ public showSelectAll? = true;
+ public showSort? = true;
+ public clientSort? = true;
+ public clientPaging? = true;
+ public stickyHeader? = true;
+ public stickyHeaderOffset? = 0;
+ public stickyContainer? = '';
+}
+
+export class CustomTableOptions {
+ public data: any[];
+ public columns: Array<CustomTableColumnDefinition>;
+ public config: CustomTableConfig;
+ // public callbacks: any;
+}
+@Component({
+ selector: 'vid-table',
+ styleUrls: ['./vid-table.component.scss'],
+ templateUrl: './vid-table.component.html'
+})
+
+export class VidTableComponent {
+ @Input() options: CustomTableOptions;
+ @Input() filterQuery = '';
+
+ @Output() clickEvent = new EventEmitter<any>();
+ clickBtn(row, actionName) {
+ row.actionName = actionName;
+ this.clickEvent.emit(row);
+ }
+}
diff --git a/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts
new file mode 100644
index 000000000..921c923df
--- /dev/null
+++ b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts
@@ -0,0 +1,80 @@
+import {Component, Input, OnInit} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {DynamicInput, DynamicMultiSelect, DynamicNumber, DynamicSelect} from "../../shared/models/dynamicInput";
+
+@Component({
+ selector: 'dynamic-inputs',
+ templateUrl: './dynamic-inputs.html',
+ styleUrls: ['./dynamic-inputs.scss']
+})
+
+export class DynamicInputsComponent implements OnInit{
+ @Input() public list:any[] = [];
+ @Input() public group: FormGroup;
+
+ private dynamicList:DynamicInput<any>[] = [];
+
+ isDynamicNumber(item: any): item is DynamicNumber {
+ return item;
+ }
+
+ buildValidators(item: DynamicInput<any>) {
+ let validatorArr = [];
+ item.maxLength && validatorArr.push(Validators.maxLength(item.maxLength));
+ item.minLength && validatorArr.push(Validators.minLength(item.minLength));
+ if(this.isDynamicNumber(item)) {
+ item.max && validatorArr.push(Validators.max(item.max));
+ item.min && validatorArr.push(Validators.min(item.min));
+ }
+ return Validators.compose(validatorArr);
+ }
+
+ ngOnInit(): void {
+ this.list.forEach((item)=> {
+ let dynamicItem: DynamicInput<any>;
+ switch (item.type) {
+ case 'multi_select':
+ item.optionList.forEach(function(option) { option.id = option.id||option.name;
+ option.itemName = option.name;});
+ item.settings = {
+ disabled: !item.isEnabled,
+ text: item.prompt,
+ };
+ dynamicItem = new DynamicMultiSelect(item);
+ break;
+ case 'select':
+ let defaultValue:any = item.optionList.find((option) => option.isDataLoading && option.name);
+ item.value = defaultValue && defaultValue.id;
+ dynamicItem = new DynamicSelect(item);
+ break;
+ case 'boolean':
+ item.value = item.value || false;
+ item.optionList = [{name: true, isPermitted: true, isDataLoading: item.value}, {name: false, isPermitted: true, isDataLoading: !item.value}];
+
+ dynamicItem = new DynamicSelect(item);
+ break;
+ case 'number':
+ dynamicItem = new DynamicNumber(item);
+ break;
+ case 'file':
+ dynamicItem = new DynamicInput<any>(item);
+ break;
+ case 'checkbox':
+ dynamicItem = new DynamicInput<boolean>(item);
+ break;
+ case 'map':
+ item.prompt = "{<key1>: <value1>,\.\.\.,<keyN>: <valueN>}";
+ dynamicItem = new DynamicInput<string>(item);
+ break;
+ case 'list':
+ item.prompt = "[<value1>,...,<valueN>]";
+ dynamicItem = new DynamicInput<string>(item);
+ break;
+ default: dynamicItem = new DynamicInput<string>(item);
+ }
+ this.dynamicList.push(dynamicItem);
+ this.group.addControl(dynamicItem.name, new FormControl({value: dynamicItem.value, disabled: !dynamicItem.isEnabled}, this.buildValidators(dynamicItem)));
+ })
+ }
+
+}
diff --git a/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html
new file mode 100644
index 000000000..a933364e2
--- /dev/null
+++ b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html
@@ -0,0 +1,22 @@
+<div *ngFor="let item of dynamicList">
+ <div id="{{item.id}}" class="details-item" [ngSwitch]="item.type" [formGroup]="group" [hidden]="!item.isVisible">
+ <label>{{item.name | dynamicInputLabel }}</label>
+ <select *ngSwitchCase="item.type === 'select'|| item.type === 'boolean'? item.type: ''" name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" title="{{item.description}}" [required]="item.isRequired && item.isVisible" maxlength="{{item.maxLength}}" minlength="{{item.minLength}}">
+ <option value="null" [selected]="item.value == null || item.value == undefined" hidden disabled>{{item.prompt}}</option>
+ <option *ngFor="let option of item.optionList" [ngValue]="option.id || option.name" [disabled]="!option.isPermitted" [selected]="option.isDataLoading">{{option.name}}</option>
+ </select>
+ <angular2-multiselect *ngSwitchCase="'multi_select'" [formControlName]="item.name" [(ngModel)]="item.selectedItems" [data]="item.optionList" [settings]="item.settings" title="{{item.description}}" [required]="item.isRequired && item.isVisible"></angular2-multiselect>
+ <input *ngSwitchCase="'number'" name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" type="number" placeholder="{{item.prompt}}" title="{{item.description}}" min="{{item.min}}" max="{{item.max}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+ <div *ngSwitchCase="'file'">
+
+ <label class="dynamicFileName" for="dynamicFileInput-{{item.name}}">
+ <input id="dynamicFileInput-{{item.name}}" name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" type="file" placeholder="{{item.prompt}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+ <label for="dynamicFileInput-{{item.name}}" class="labelForImage">
+ <span class="icon-browse"></span>
+ </label>
+ </label>
+ </div>
+ <input *ngSwitchCase="'checkbox'" name="{{item.name}}" [formControlName]="item.name" type="checkbox" data-toggle="toggle" title="{{item.description}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+ <input *ngSwitchDefault name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" placeholder="{{item.prompt}}" title="{{item.description}}" maxlength="{{item.maxLength}}" minlength="{{item.minLength}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible"/>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss
new file mode 100644
index 000000000..11a141420
--- /dev/null
+++ b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss
@@ -0,0 +1,58 @@
+input[type=file] {
+ opacity: 0;
+ position: relative;
+ z-index: 1;
+ width: 0.5px;
+ height: 0.5px;
+ display: inline-block;
+ input {
+ display: none;
+ }
+}
+
+.dynamicFileName {
+ width: 100%;
+ height: 34px;
+ background: #FFFFFF;
+ border: 1px solid #D2D2D2;
+ border-radius: 2px;
+ display: inline-block;
+ line-height: 34px;
+ font-weight: normal !important;
+ padding-left: 3px;
+ border-bottom-right-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.labelForImage {
+ background: #F2F2F2;
+ border-left: 1px solid #D2D2D2;
+ float: right;
+ height: 32px;
+}
+
+.icon-browse:before {
+ content: "\e90d";
+ color: #5A5A5A;
+ font-size: 15px;
+ cursor: pointer;
+ width: 34px;
+ height: 100%;
+ line-height: 34px;
+ text-align: center;
+ display: inline-block;
+ vertical-align: super;
+ border-radius: 2px;
+ border-bottom-left-radius: 0;
+ border-top-left-radius: 0;
+}
+
+.icon-browse:hover::before {
+ background-color: #E6F6FB;
+ color: #009FDB;
+}
+
+.icon-browse:active::before {
+ background-color: #E6F6FB;
+ color: #009FDB;
+}
diff --git a/vid-webpack-master/src/app/components/form-async/form-async.component.ts b/vid-webpack-master/src/app/components/form-async/form-async.component.ts
new file mode 100644
index 000000000..e71c4446b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/form-async/form-async.component.ts
@@ -0,0 +1,80 @@
+import {Component, Input, OnInit, ViewChild} from '@angular/core';
+import { NgRedux, select } from '@angular-redux/store';
+import { Observable } from "rxjs/Observable";
+import { updateProductFamilies } from "../../service.actions";
+import { AppState } from "../../store/reducers";
+import {
+ loadProductFamiliesAction, loadLcpTenant, loadAicZones,
+ loadCategoryParameters
+} from '../../services/aaiService/aai.actions';
+import { LcpRegionsAndTenants } from "../../shared/models/lcpRegionsAndTenants";
+import {NgForm} from "@angular/forms";
+import {SelectOption} from "../../shared/models/selectOption";
+import {VNFModel} from "../../shared/models/vnfModel";
+
+@Component({
+ selector: "formasync",
+ templateUrl: "form-async.template.html",
+ styleUrls: ["form-async.style.scss"],
+
+})
+
+export class formasync implements OnInit {
+
+ constructor(private store: NgRedux<AppState>) { }
+
+ @ViewChild('form') form: NgForm;
+
+ @Input()
+ set model(model: VNFModel) {
+ if (model) {
+ this.isUserProvidedNaming = model.isUserProvidedNaming;
+ }
+ };
+
+ @select(['service', 'productFamilies'])
+ readonly productFamilies: Observable<any>;
+
+ @select(['service', 'lcpRegionsAndTenants'])
+ readonly lcpRegionsAndTenants: Observable<any>;
+
+ @select(['service', 'lcpRegionsAndTenants', 'lcpRegionList'])
+ readonly lcpRegions: Observable<any>;
+
+ @select(['service', 'aicZones'])
+ readonly aicZones: Observable<any>;
+
+ @select(['service', 'categoryParameters', 'platformList'])
+ readonly platformList: Observable<any>;
+
+ @select(['service', 'categoryParameters', 'lineOfBusinessList'])
+ readonly lineOfBusinessList: Observable<any>;
+
+ rollbackOnFailure = [
+ new SelectOption({id: 'true', name: 'Rollback'}),
+ new SelectOption({id: 'false', name: 'Don\'t Rollback'})
+ ];
+ tenants = [];
+
+ serviceInstance: any = {
+ rollback:'true'
+ };
+
+ isUserProvidedNaming: boolean = false;
+
+ onLcpSelect(newValue: string) {
+ let value: LcpRegionsAndTenants = undefined;
+ this.lcpRegionsAndTenants.subscribe(data => value = data);
+ this.tenants = value.lcpRegionsTenantsMap[newValue];
+ }
+
+ ngOnInit() {
+ this.store.dispatch(loadProductFamiliesAction());
+ this.store.dispatch(loadLcpTenant());
+ this.store.dispatch(loadAicZones());
+ this.store.dispatch(loadCategoryParameters());
+ }
+}
+
+
+
diff --git a/vid-webpack-master/src/app/components/form-async/form-async.style.scss b/vid-webpack-master/src/app/components/form-async/form-async.style.scss
new file mode 100644
index 000000000..e6c89bcae
--- /dev/null
+++ b/vid-webpack-master/src/app/components/form-async/form-async.style.scss
@@ -0,0 +1,15 @@
+.form-wrapper{
+ width:640px;
+ padding-left: 50px;
+ padding-top: 50px;
+ .details-item{
+ padding-bottom: 30px;
+ }
+ .details-item {
+ select {
+ font-family: OpenSans-Italic;
+ font-size: 14px;
+ color: #959595 !important;
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/components/form-async/form-async.template.html b/vid-webpack-master/src/app/components/form-async/form-async.template.html
new file mode 100644
index 000000000..c63a7bee6
--- /dev/null
+++ b/vid-webpack-master/src/app/components/form-async/form-async.template.html
@@ -0,0 +1,67 @@
+<div class="content">
+ <form #form="ngForm" name="networkNodeForm" class="form-wrapper">
+ <div *ngIf="isUserProvidedNaming" class="details-item">
+ <label class="placeholder">Instance name*</label>
+ <input [attr.data-tests-id]="'instanceName'" id="instance-name" [(ngModel)]="serviceInstance.instanceName" name="instance-name"
+ class="form-control input-text" placeholder="Type Instance Name" type="text" required>
+ </div>
+
+ <div class="details-item">
+ <label>Product family</label>
+ <select class="form-control input-text" [(ngModel)]="serviceInstance.productFamily" data-tests-id="productFamily" id="product-family-select"
+ name="product-family-select">
+ <option class="placeholder" [value]="undefined" disabled>Select Product Family</option>
+ <option *ngFor="let productFamily of productFamilies | async" [value]="productFamily.id" [disabled]="!productFamily.isPermitted">{{productFamily.name}}</option>
+ </select>
+ </div>
+
+ <div class="details-item">
+ <label>LCP region:*</label>
+ <select (change)="onLcpSelect($event.target.value)" class="form-control input-text" [(ngModel)]="serviceInstance.lcpRegion"
+ name="lcpRegion" id="lcpRegion-select" data-tests-id="lcpRegion" required>
+ <option class="placeholder1" [value]="undefined" disabled>Select LCP Region</option>
+ <option *ngFor="let lcpRegion of lcpRegions | async" [value]="lcpRegion.id" [disabled]="!lcpRegion.isPermitted" class="lcpRegionOption">{{lcpRegion.id}}</option>
+ </select>
+ </div>
+ <div class="details-item">
+ <label>Tenant:*</label>
+ <select class="form-control input-text" [(ngModel)]="serviceInstance.tenantId" name="tenant" id="tenant-select" data-tests-id="tenant"
+ required>
+ <option class="placeholder1" [value]="undefined" disabled>Select Tenant</option>
+ <option *ngFor="let tenant of tenants" [value]="tenant.id" [disabled]="!tenant.isPermitted">{{tenant.name}}</option>
+ </select>
+ </div>
+
+ <div class="details-item">
+ <label>AIC Zone:</label>
+ <select class="form-control input-text" name="aicZone" id="aicZone-select" data-tests-id="aic_zone" [(ngModel)]="serviceInstance.aicZone">
+ <option class="placeholder1" [value]="undefined" disabled>Select AIC Zone</option>
+ <option class="aicZoneOption" *ngFor="let aicZone of aicZones | async" [value]="aicZone.id">{{aicZone.name}}</option>
+ </select>
+ </div>
+ <div class="details-item">
+ <label>Platform:</label>
+ <select data-tests-id="platform" class="form-control input-text" name="platform" id="platform" [(ngModel)]="serviceInstance.platformName">
+ <option class="placeholder1" [value]="undefined" disabled>Select Platform</option>
+ <option *ngFor="let platform of platformList | async" [value]="platform.id">{{platform.name}}</option>
+ </select>
+ </div>
+
+ <div class="details-item">
+ <label>Line Of Business:*</label>
+ <select data-tests-id="lineOfBusiness" class="form-control input-text" [(ngModel)]="serviceInstance.lineOfBusiness"
+ name="owningEntity" id="owningEntity" required>
+ <option class="placeholder1" [value]="undefined" disabled>Select Line Of Business</option>
+ <option *ngFor="let lineOfBusiness of lineOfBusinessList | async" [value]="lineOfBusiness.id">{{lineOfBusiness.name}}</option>
+ </select>
+ </div>
+ <div class="details-item">
+ <label>Rollback On Failure:</label>
+ <select data-tests-id="suppressRollback" class="form-control input-text" name="rollbackOnFailure" id="rollbackOnFailure" [(ngModel)]="serviceInstance.rollback">
+ <option *ngFor="let option of rollbackOnFailure" [value]="option.id">{{option.name}}</option>
+ </select>
+ </div>
+ </form>
+
+</div>
+
diff --git a/vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts b/vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts
new file mode 100644
index 000000000..b8ce613d4
--- /dev/null
+++ b/vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts
@@ -0,0 +1,9 @@
+import {ModelInformationItem} from "../../shared/components/model-information/model-information.component";
+
+
+export interface InstancePopup {
+ onCancelClick():void;
+ createModelInformationItems(): Array<ModelInformationItem>;
+ getModelName():string;
+}
+
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts
new file mode 100644
index 000000000..b6a2e3967
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts
@@ -0,0 +1,238 @@
+import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {ServicePopupDataModel} from './servicePopupDataModel';
+import {AaiService} from '../../../services/aaiService/aai.service';
+import {updateServiceInstance} from "../../../service.actions";
+import * as _ from 'lodash';
+import {ServiceModel} from "../../../shared/models/serviceModel";
+import {ModelInfo} from "../../../shared/models/modelInfo";
+import {loadProductFamiliesAction} from "../../../services/aaiService/aai.actions";
+import {Observable} from "rxjs/Observable";
+import {SelectOptionInterface} from "../../../shared/models/selectOption";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../../../store/reducers";
+import {isNullOrUndefined} from 'util';
+import {ServiceInstanceDetailsService} from './service-instance-details.service';
+import {NumbersLettersUnderscoreValidator} from '../../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {DefaultDataGeneratorService} from '../../../shared/services/defaultDataServiceGenerator/default.data.generator.service';
+
+
+@Component({
+ selector: 'service-instance-details',
+ templateUrl: 'service-instance-details.html',
+ styleUrls: ['service-instance-details.scss'],
+ providers: [AaiService]
+})
+
+export class ServiceInstanceDetailsComponent implements OnInit, OnChanges {
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes["serviceInstance"] !== undefined && changes["serviceInstance"].currentValue !== changes["serviceInstance"].previousValue && changes["serviceInstance"].currentValue !== null) {
+ this.oldServiceInstance = Object.assign({}, this.serviceInstance);
+ }
+ }
+ _serviceModel: ServiceModel;
+ @Input () serviceInstance: any;
+ @Input () dynamicInputs;
+ @Input () servicesQty: number;
+ @Input ()
+ set serviceModel(serviceModel: ServiceModel) {
+ this._serviceModel = serviceModel;
+ this.updateFormGroupControlsWithServiceModel(serviceModel);
+ }
+ @ViewChild('serviceForm') serviceForm: 'ServiceForm';
+ @Output() closePopup : EventEmitter<any> = new EventEmitter<any>();
+ @Output() onDataChanged: EventEmitter<any> = new EventEmitter<any>();
+ oldServiceInstance = {};
+
+ //todo: implement Epics and use @select to fetch the rest of the form's data as done with productFamilies.
+ //that way we can loose the updateFormData function and the subscription to store in the constructor.
+ @select(['service','productFamilies'])
+ readonly productFamilies : Observable<SelectOptionInterface[]>;
+ serviceDetails:any = {
+
+ };
+ servicePopupDataModel: ServicePopupDataModel = new ServicePopupDataModel();
+ serviceInstanceDetailsFormGroup: FormGroup;
+ serviceInstanceDetailsService : ServiceInstanceDetailsService;
+
+ constructor(private _aaiService: AaiService, private store: NgRedux<AppState>, private _serviceInstanceDetailsService : ServiceInstanceDetailsService, private _defaultDataGeneratorService : DefaultDataGeneratorService) {
+ this.store.subscribe(() => {this.updateFormData()});
+ this.serviceInstanceDetailsService = this._serviceInstanceDetailsService;
+ this.serviceInstanceDetailsFormGroup = this.createFormGroup();
+
+ this.serviceInstanceDetailsFormGroup.valueChanges.subscribe(()=> {
+ this.onDataChanged.next();
+ })
+ }
+
+ ngOnInit() {
+ this.subscribeToFormChanges();
+ this._aaiService.getSubscribers().subscribe();
+ this._aaiService.getCategoryParameters(null).subscribe();
+ this._aaiService.getAicZones().subscribe();
+ this.store.dispatch(loadProductFamiliesAction());
+ }
+
+
+ createFormGroup(): FormGroup {
+ const formGroup = new FormGroup({
+ globalSubscriberId: new FormControl(
+ Validators.compose([Validators.required])
+ ),
+ productFamilyId: new FormControl(),
+ subscriptionServiceType: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ lcpCloudRegionId: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ tenantId: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ aicZoneId: new FormControl(),
+ projectName: new FormControl(),
+ owningEntityId: new FormControl(Validators.compose([Validators.required])),
+ rollbackOnFailure: new FormControl(null, Validators.required),
+ });
+
+ return formGroup;
+ }
+
+ updateFormGroupControlsWithServiceModel(serviceModel: ServiceModel) {
+ this.serviceInstanceDetailsFormGroup.markAsUntouched();
+
+ if (serviceModel) {
+ this.serviceDetails.isUserProvidedNaming = serviceModel.isUserProvidedNaming;
+ if (serviceModel.isUserProvidedNaming) {
+ this.serviceInstanceDetailsFormGroup.addControl('instanceName', new FormControl('', Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid])))
+ }else{
+ this.serviceInstanceDetailsFormGroup.removeControl('instanceName');
+ }
+
+ if (serviceModel.isMultiStepDesign) {
+ this.serviceInstanceDetailsFormGroup.addControl('pause', new FormControl(true));
+ }else{
+ this.serviceInstanceDetailsFormGroup.removeControl('pause');
+ }
+ }
+ }
+
+ updateFormData() {
+ let service = this.store.getState().service;
+ this.servicePopupDataModel.subscribers = service.subscribers;
+ this.servicePopupDataModel.serviceTypes = service.serviceTypes[this.servicePopupDataModel.globalCustomerId];
+ this.servicePopupDataModel.lcpRegions = service.lcpRegionsAndTenants.lcpRegionList;
+ if (this.serviceInstance) {
+ this.servicePopupDataModel.tenants = service.lcpRegionsAndTenants.lcpRegionsTenantsMap[this.serviceInstance.lcpCloudRegionId];
+ }
+ this.servicePopupDataModel.aicZones = service.aicZones;
+ this.servicePopupDataModel.owningEntities = _.get(service.categoryParameters, 'owningEntityList');
+ this.servicePopupDataModel.projects = _.get(service.categoryParameters, 'projectList');
+ this.onDataChanged.next();
+ }
+
+ subscribeToFormChanges(): void {
+ this.serviceInstanceDetailsFormGroup.get('globalSubscriberId').valueChanges.subscribe(val => {
+ this.updateServiceTypes(val);
+ this.setDisabledState(val, 'subscriptionServiceType');
+
+ });
+ this.serviceInstanceDetailsFormGroup.get('subscriptionServiceType').valueChanges.subscribe(val => {
+ this.getTenants(val);
+ this.setDisabledState(val, 'lcpCloudRegionId');
+
+ });
+ this.serviceInstanceDetailsFormGroup.get('lcpCloudRegionId').valueChanges.subscribe(val => {
+ this.setDisabledState(val, 'tenantId');
+ this.updateTenantList(val);
+
+ });
+
+ this.serviceInstanceDetailsFormGroup.get('tenantId').valueChanges.subscribe(val => {
+ this.serviceDetails.tenantName = this.getNameFromListById(this.servicePopupDataModel.tenants, val);
+ this.onDataChanged.next();
+ });
+
+ this.serviceInstanceDetailsFormGroup.get('aicZoneId').valueChanges.subscribe(val => {
+ this.serviceDetails.aicZoneName = this.getNameFromListById(this.servicePopupDataModel.aicZones, val);
+ this.onDataChanged.next();
+ });
+ }
+
+ getNameFromListById(list, id:string ) {
+ if(list && id) {
+ let filterItem = list.filter(item => {
+ return item.id == id;
+ })
+ return filterItem && filterItem[0].name;
+ }
+ return null;
+ }
+
+ setDisabledState(val, field: string): void {
+ if(val) {
+ this.serviceInstanceDetailsFormGroup.controls[field].enable();
+ } else {
+ this.serviceInstanceDetailsFormGroup.controls[field].disable();
+ }
+ }
+
+ isShowingNotificationArea(): boolean {
+ return this.servicesQty > 1;
+ }
+
+ updateServiceTypes(subscriberId) {
+ if (subscriberId) {
+ this.servicePopupDataModel.globalCustomerId = subscriberId;
+ this._aaiService.getServiceTypes(subscriberId).subscribe(() => {
+ this.updateFormData();
+ this.onDataChanged.next();
+ }, (error) => {
+
+ });
+ }
+ }
+
+ updateTenantList(cloudRegionId) {
+ this.servicePopupDataModel.tenants = this.store.getState().service.lcpRegionsAndTenants.lcpRegionsTenantsMap[cloudRegionId];
+ this.onDataChanged.next();
+ }
+
+ getTenants(serviceType) {
+ if (serviceType) {
+ this._aaiService.getLcpRegionsAndTenants(this.servicePopupDataModel.globalCustomerId, serviceType).subscribe(()=>{
+ this.onDataChanged.next();
+ });
+ }
+ }
+
+ onSubmit(formValues): void {
+ formValues.bulkSize = this.servicesQty;
+ let dynamicFields: { [dynamicField: string] : string; };
+ dynamicFields = {};
+ this.dynamicInputs.map(function (x) {
+ let dynamicField: string = x.id;
+ dynamicFields[dynamicField] = formValues[dynamicField];
+ delete formValues[dynamicField];
+ });
+ formValues.instanceParams = [];
+ formValues.instanceParams.push(dynamicFields);
+ formValues.modelInfo = new ModelInfo(this._serviceModel);
+ Object.assign(formValues, this.serviceDetails);
+ this.store.dispatch(updateServiceInstance(formValues, this._serviceModel.uuid));
+ if (this.store.getState().global.flags['FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD']){
+ this._defaultDataGeneratorService.updateReduxOnFirstSet(this._serviceModel.uuid,formValues);
+ }
+ window.parent.postMessage( {
+ eventId: 'submitIframe',
+ data: {
+ serviceModelId: this._serviceModel.uuid
+ }
+ }, "*");
+ this.closePopup.emit(this._serviceModel.uuid);
+ }
+
+ hasApiError(controlName : string, data : Array<any>){
+ if(!isNullOrUndefined(this.servicePopupDataModel) && !isNullOrUndefined(data)){
+ if(!this.serviceInstanceDetailsFormGroup.controls[controlName].disabled && data.length === 0){
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html
new file mode 100644
index 000000000..3d632bd89
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html
@@ -0,0 +1,168 @@
+
+<div id="service-instance-details">
+ <form id="serviceForm" #serviceForm="ngForm" (ngSubmit)="onSubmit(serviceForm.value)" [formGroup]="serviceInstanceDetailsFormGroup">
+ <!--We can't use [hidden] since bootstrap.css label has display: inline-block. -->
+ <!--see https://stackoverflow.com/questions/34650410/angular-2-hidden-does-not-seem-to-be-working-->
+ <label id="notification-area" *ngIf="isShowingNotificationArea()">Data entered will apply to all service instances</label>
+
+ <div class="details-item" *ngIf="serviceInstanceDetailsFormGroup.get('instanceName')">
+ <label class="required">Instance name:</label>
+ <input patternInput
+ pattern="^[a-zA-Z0-9_]*$"
+ [attr.data-tests-id]="'instanceName'"
+ id="instance-name"
+ name="instance-name"
+ [ngClass]="{'error-style' :(serviceInstance?.instanceName != '' && serviceInstanceDetailsFormGroup.controls['instanceName']?.touched && serviceInstanceDetailsFormGroup.controls['instanceName']?.errors?.pattern !== null)}"
+ [formControlName]="'instanceName'"
+ class="form-control input-text"
+ placeholder="Type Instance Name"
+ type="text"
+ [(ngModel)]="serviceInstance.instanceName" required>
+ <form-control-error
+ *ngIf="serviceInstance?.instanceName != '' && serviceInstanceDetailsFormGroup.controls['instanceName']?.touched && serviceInstanceDetailsFormGroup.controls['instanceName']?.errors?.pattern !== null"
+ [message]="'Instance name may include only alphanumeric characters and underscore.'"></form-control-error>
+
+ </div>
+
+ <div class="details-item">
+ <label class="required">Subscriber name:</label>
+ <select class="subscriber form-control input-text" id="subscriber-name-select" data-tests-id="subscriberName"
+ name="subscriber-name-select" [formControlName]="'globalSubscriberId'"
+ [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('globalSubscriberId',servicePopupDataModel?.subscribers, serviceInstanceDetailsFormGroup)}"
+ [(ngModel)]="serviceInstance.globalSubscriberId"
+ required>
+ <option [value]="undefined" disabled>Select Subscriber Name</option>
+ <option class="subscriberNameOption" *ngFor="let subscriber of servicePopupDataModel.subscribers"
+ [value]="subscriber.id" [disabled]="!subscriber.isPermitted">{{subscriber.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('globalSubscriberId',servicePopupDataModel?.subscribers, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+
+ </div>
+
+ <div class="details-item">
+ <label class="required">Service type:</label>
+ <select class="form-control input-text"
+ [(ngModel)]="serviceInstance.subscriptionServiceType"
+ [formControlName]="'subscriptionServiceType'"
+ [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('subscriptionServiceType',servicePopupDataModel?.serviceTypes, serviceInstanceDetailsFormGroup)}"
+ data-tests-id="serviceType" id="service-type-select"
+ name="service-type" required>
+ <option [value]="undefined" disabled>Select Service Type</option>
+ <option *ngFor="let serviceType of servicePopupDataModel.serviceTypes" class="serviceTypeOption" [value]="serviceType.name" [disabled]="!serviceType.isPermitted">{{serviceType.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('subscriptionServiceType',servicePopupDataModel?.serviceTypes, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item">
+ <label class="required">Product family:</label>
+ <select class="form-control input-text"
+ data-tests-id="productFamily"
+ id="product-family-select"
+ [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('productFamilyId',productFamilies, serviceInstanceDetailsFormGroup)}"
+ [formControlName]="'productFamilyId'"
+ [(ngModel)]="serviceInstance.productFamilyId"
+ name="product-family-select" required>
+ <option [value]="undefined" disabled>Select Product Family</option>
+ <option *ngFor="let productFamily of productFamilies | async" [value]="productFamily.id"
+ [disabled]="!productFamily.isPermitted">{{productFamily.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('productFamilyId',productFamilies, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item">
+ <label class="required">LCP region:</label>
+ <select
+ class="form-control input-text"
+ [formControlName]="'lcpCloudRegionId'"
+ [(ngModel)]="serviceInstance.lcpCloudRegionId"
+ [ngClass]="{'error-style ' : serviceInstanceDetailsService.hasApiError('lcpCloudRegionId', servicePopupDataModel?.lcpRegions, serviceInstanceDetailsFormGroup)}"
+ name="lcpRegion"
+ id="lcpRegion-select"
+ data-tests-id="lcpRegion"
+ required>
+ <option [value]="undefined" disabled>Select LCP Region</option>
+ <option *ngFor="let lcpRegion of servicePopupDataModel.lcpRegions" [value]="lcpRegion.id" [disabled]="!lcpRegion.isPermitted" class="lcpRegionOption">{{lcpRegion.id}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('lcpCloudRegionId', servicePopupDataModel?.lcpRegions, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item">
+ <label class="required">Tenant:</label>
+ <select class="form-control input-text"
+ [formControlName]="'tenantId'"
+ [(ngModel)]="serviceInstance.tenantId"
+ name="tenant" id="tenant-select"
+ [ngClass]="{'error-style ' : serviceInstanceDetailsService.hasApiError('tenantId',servicePopupDataModel?.tenants ,serviceInstanceDetailsFormGroup)}"
+ data-tests-id="tenant" required>
+ <option [value]="undefined" disabled>Select Tenant</option>
+ <option *ngFor="let tenant of servicePopupDataModel.tenants" [value]="tenant.id" [disabled]="!tenant.isPermitted">{{tenant.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('tenantId',servicePopupDataModel?.tenants ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item">
+ <label>AIC Zone:</label>
+ <select
+ class="form-control input-text"
+ name="aicZone" id="aicZone-select"
+ data-tests-id="aic_zone"
+ [formControlName]="'aicZoneId'"
+ [ngClass]="{'error-style ' : servicePopupDataModel?.aicZones?.length == 0 && serviceInstanceDetailsFormGroup.controls['aicZoneId'].disabled == false}"
+ [(ngModel)]="serviceInstance.aicZoneId" >
+ <option [value]="undefined" disabled>Select AIC Zone</option>
+ <option class="aicZoneOption" *ngFor="let aicZone of servicePopupDataModel.aicZones" [value]="aicZone.id">{{aicZone.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('aicZoneId',servicePopupDataModel?.aicZones ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+
+ </div>
+
+ <div class="details-item">
+ <label>Project:</label>
+ <select
+ [attr.data-tests-id]="'project'"
+ class="form-control input-text"
+ [ngClass]="{'error-style ' : servicePopupDataModel?.projects?.length == 0 && serviceInstanceDetailsFormGroup.controls['projectName'].disabled == false}"
+ name="project" id="project"
+ [formControlName]="'projectName'"
+ [(ngModel)]="serviceInstance.projectName" >
+ <option [value]="undefined" disabled>Select Project</option>
+ <option *ngFor="let project of servicePopupDataModel.projects" [value]="project.id">{{project.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('projectName',servicePopupDataModel?.projects ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+
+ </div>
+
+ <div class="details-item">
+ <label class="required">Owning entity:</label>
+ <select [attr.data-tests-id]="'owningEntity'"
+ class="form-control input-text"
+ [formControlName]="'owningEntityId'"
+ [(ngModel)]="serviceInstance.owningEntityId"
+ name="owningEntity" id="owningEntity"
+ [ngClass]="{'error-style ' : servicePopupDataModel?.owningEntities?.length == 0 && serviceInstanceDetailsFormGroup.controls['owningEntityId'].disabled == false}"
+ required>
+ <option [value]="undefined" disabled>Select Owning Entity</option>
+ <option *ngFor="let owningEntity of servicePopupDataModel.owningEntities" [value]="owningEntity.id">{{owningEntity.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('owningEntityId',servicePopupDataModel?.owningEntities ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+ <div class="details-item">
+ <label class="required">Rollback On Failure:</label>
+ <select [attr.data-tests-id]="'rollback'"
+ [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('rollbackOnFailure',servicePopupDataModel?.rollbackOnFailure, serviceInstanceDetailsFormGroup)}"
+ class="form-control input-text"
+ [(ngModel)]="serviceInstance.rollbackOnFailure"
+ [formControlName]="'rollbackOnFailure'" name="rollbackOnFailure" id="rollbackOnFailure">
+ <option *ngFor="let option of servicePopupDataModel.rollbackOnFailure" [value]="option.id">{{option.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('rollbackOnFailure',servicePopupDataModel?.rollbackOnFailure, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+ <div class="details-item" *ngIf="serviceInstanceDetailsFormGroup.get('pause')">
+ <input #pause id="pause" [formControlName]="'pause'" [(ngModel)]="serviceInstance.pause" type="checkbox" name="pause" data-toggle="toggle">
+ <label class="checkbox-label" for="pause">Pause on pause points:</label>
+ </div>
+
+
+ <dynamic-inputs *ngIf="dynamicInputs != undefined && dynamicInputs.length>0" [group]="serviceInstanceDetailsFormGroup" [list]="dynamicInputs"></dynamic-inputs>
+ </form>
+</div>
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss
new file mode 100644
index 000000000..928343d43
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss
@@ -0,0 +1,64 @@
+#service-instance-details {
+ position: relative;
+
+ #notification-area {
+ color: #959595;
+ font-size: 12px;
+ position: absolute;
+ top: 3px;
+ left: 30px;
+ }
+
+ height: 100%;
+ overflow: auto;
+ padding: 30px;
+
+ /deep/ {
+ .form-control {
+ border-radius: 2px;
+ box-shadow: none;
+ border-color: #D2D2D2;
+ }
+
+ label {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ select {
+ @extend .form-control;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: url('../../../../assets/img/chevron.svg') 0 0 no-repeat;
+ background-size: 24px;
+ background-position-x: right;
+ background-position-y: center;
+ font-family: OpenSans-Italic;
+ font-size: 14px;
+ color: #959595;
+ height: 38px;
+ }
+
+ input:not([type='checkbox']) {
+ @extend .form-control;
+ height: 38px;
+ }
+
+ .form-control[disabled], fieldset[disabled] .form-control {
+ opacity: 0.5;
+ }
+ .input-text {
+ border: 1px solid #D2D2D2;
+ border-radius: 2px;
+ }
+
+ .details-item {
+ margin-bottom: 20px;
+ }
+ }
+
+ .checkbox-label {
+ font-family: OpenSans-Regular;
+ }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts
new file mode 100644
index 000000000..605653bd0
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts
@@ -0,0 +1,26 @@
+import { getTestBed, TestBed } from '@angular/core/testing';
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { ServiceInstanceDetailsService } from './service-instance-details.service';
+import { NgRedux } from '@angular-redux/store';
+
+export class MockAppStore<T> {}
+
+describe('Service instance details service', () => {
+ let injector;
+ let service: ServiceInstanceDetailsService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [ServiceInstanceDetailsService,
+ {provide: NgRedux, useClass: MockAppStore}]
+ });
+
+ injector = getTestBed();
+ service = injector.get(ServiceInstanceDetailsService);
+ httpMock = injector.get(HttpTestingController);
+ });
+});
+
+
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts
new file mode 100644
index 000000000..99b390d2f
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts
@@ -0,0 +1,22 @@
+import { Injectable } from '@angular/core';
+import { isNullOrUndefined } from 'util';
+import { FormGroup } from '@angular/forms';
+import * as _ from 'lodash';
+import { createVFModuleInstance, updateVFModuleInstance, updateVNFInstance } from '../../../service.actions';
+import { NgRedux } from '@angular-redux/store';
+import { AppState } from '../../../store/reducers';
+
+@Injectable()
+export class ServiceInstanceDetailsService {
+ static controlsFieldsStatus = {};
+
+ constructor(private store: NgRedux<AppState>) { }
+ hasApiError(controlName: string, data: Array<any>, serviceInstanceDetailsFormGroup: FormGroup) {
+ if (!isNullOrUndefined(data)) {
+ if (!serviceInstanceDetailsFormGroup.controls[controlName].disabled && data.length === 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts
new file mode 100644
index 000000000..c7894e2cd
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts
@@ -0,0 +1,32 @@
+import {SelectOption, SelectOptionInterface} from "../../../shared/models/selectOption";
+
+export class ServicePopupDataModel {
+ subscribers: SelectOptionInterface[];
+ serviceTypes: SelectOptionInterface[];
+ aicZones: SelectOptionInterface[];
+ lcpRegions: SelectOptionInterface[];
+ productFamilies: SelectOptionInterface[];
+ lcpRegionsTenantsMap: object;
+ tenants: SelectOptionInterface[];
+ projects: SelectOptionInterface[];
+ owningEntities: SelectOptionInterface[];
+ globalCustomerId: string;
+ rollbackOnFailure: SelectOptionInterface[];
+
+
+ constructor(){
+ this.subscribers = null;
+ this.serviceTypes = null;
+ this.aicZones = null;
+ this.lcpRegions = null;
+ this.lcpRegionsTenantsMap = {};
+ this.tenants = null;
+ this.productFamilies = null;
+ this.projects = null;
+ this.owningEntities = null;
+ this.rollbackOnFailure = [
+ new SelectOption({id: 'true', name: 'Rollback'}),
+ new SelectOption({id: 'false', name: 'Don\'t Rollback'})
+ ];
+ }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.component.ts b/vid-webpack-master/src/app/components/service-popup/service-popup.component.ts
new file mode 100644
index 000000000..908ae4adf
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.component.ts
@@ -0,0 +1,144 @@
+import {Component, ViewChild} from '@angular/core';
+import {DialogComponent, DialogService} from 'ng2-bootstrap-modal';
+import {ServiceModel} from '../../shared/models/serviceModel';
+import {Constants} from '../../shared/utils/constants';
+import {ServiceInstanceDetailsComponent} from './service-instance-details/service-instance-details.component';
+import {ActivatedRoute} from "@angular/router";
+import {AaiService} from "../../services/aaiService/aai.service";
+import {Utils} from "../../utils/utils";
+import {ServicePlanningService} from "../../services/service-planning.service";
+import * as _ from 'lodash';
+import {ModelInformationItem} from '../../shared/components/model-information/model-information.component';
+import {deleteServiceInstance} from '../../service.actions';
+
+import {InstancePopup} from "../instance-popup/instance-popup.components";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import {ServicePopupService} from './service-popup.service';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+export interface ServicePopupModel {
+ serviceModel: ServiceModel
+}
+
+@Component({
+ selector: 'service-popup',
+ templateUrl: 'service-popup.html',
+ styleUrls: ['service-popup.scss'],
+ providers: [AaiService, ServicePopupService]
+})
+
+export class ServicePopupComponent extends DialogComponent<ServicePopupModel, boolean>
+ implements ServicePopupModel, InstancePopup{
+ @ViewChild(ServiceInstanceDetailsComponent) serviceInstanceDetails: ServiceInstanceDetailsComponent;
+
+ serviceModel: ServiceModel;
+ serviceModelId: string;
+ serviceInstance: any = {
+ 'rollbackOnFailure' : 'false'
+ };
+ title: string = Constants.ServicePopup.TITLE;
+ dynamicInputs: any[] = null;
+
+ maxServiceQty:number = 50;
+ minServiceQty:number = 1;
+ servicesQty = 1; //default
+ quantityOptions = this.getQuantityOptions();
+
+ modelInformationItems: Array<ModelInformationItem> = [];
+ hasGeneralApiError : boolean = false;
+ parentElementClassName = 'content';
+
+ constructor(dialogService: DialogService, private route: ActivatedRoute, private _aaiService: AaiService,
+ private _iframeService : IframeService,
+ private _servicePlanningService: ServicePlanningService, private store: NgRedux<AppState>, private _servicePopupService : ServicePopupService) {
+ super(dialogService);
+ this.title = Constants.ServicePopup.TITLE;
+ }
+
+ updateGeneralErrorSection() : void {
+ this.hasGeneralApiError = this._servicePopupService.onControlError(this.serviceInstanceDetails, this.serviceInstanceDetails.serviceInstanceDetailsFormGroup);
+ }
+
+
+ ngOnInit() {
+ this.route
+ .queryParams
+ .subscribe(params => {
+ this.serviceModelId = params['serviceModelId'];
+ if(params['isCreate']=="true") {
+ this.store.dispatch(deleteServiceInstance(this.serviceModelId));
+ }
+ this.updateServiceModelById(this.serviceModelId);
+ this.updateInstanceFromStore();
+ });
+ }
+
+ updateInstanceFromStore() {
+ let serviceInstance;
+ if (_.has(this.store.getState().service.serviceInstance, this.serviceModelId)) {
+ serviceInstance = Object.assign({}, this.store.getState().service.serviceInstance[this.serviceModelId]);
+ }
+
+ this.serviceInstance = serviceInstance ? serviceInstance : this.serviceInstance;
+ this.servicesQty = serviceInstance ? serviceInstance.bulkSize : 1;
+ if (serviceInstance && serviceInstance.instanceParams && serviceInstance.instanceParams[0]) {
+ this.dynamicInputs = this.dynamicInputs.map(function (x) {
+ x.value = (serviceInstance.instanceParams[0][x.id]) ? serviceInstance.instanceParams[0][x.id] : x.value;
+ return x;
+ });
+ }
+ }
+
+ updateServiceModelById(serviceModelId) {
+ this._aaiService.getServiceModelById(serviceModelId).subscribe(
+ value => {
+ const convertedModel = Utils.convertModel(value);
+ this.serviceModel = new ServiceModel(convertedModel);
+ let displayInputs = Object.assign({},convertedModel.service.inputs);
+ this.dynamicInputs = _.isEmpty(displayInputs)? [] : this._servicePlanningService.getArbitraryInputs(displayInputs);
+ this.modelInformationItems = this.createModelInformationItems();
+ },
+ error => {console.log('error is ', error)},
+ () => {console.log('completed')}
+ );
+ }
+
+ createModelInformationItems() : Array<ModelInformationItem> {
+ return [
+ new ModelInformationItem("Model version", "modelVersion", [this.serviceModel.version], "", true),
+ new ModelInformationItem("Description", "description", [this.serviceModel.description]),
+ new ModelInformationItem("Category", "category", [this.serviceModel.category]),
+ new ModelInformationItem("UUID", "uuid", [this.serviceModel.uuid], Constants.ServicePopup.TOOLTIP_UUID, true),
+ new ModelInformationItem("Invariant UUID", "invariantUuid", [this.serviceModel.invariantUuid], Constants.ServicePopup.TOOLTIP_INVARIANT_UUID, true),
+ new ModelInformationItem("Service type", "serviceType", [this.serviceModel.serviceType]),
+ new ModelInformationItem("Service role", "serviceRole", [this.serviceModel.serviceRole])
+ ];
+ }
+
+ onCancelClick() {
+ this._iframeService.removeClassCloseModal(this.parentElementClassName);
+ this.dialogService.removeDialog(this);
+ this.serviceInstance = this.serviceInstanceDetails.oldServiceInstance;
+
+ this._servicePopupService.resetDynamicInputs(this.serviceInstanceDetails, this.dynamicInputs);
+ // Delaying the iframe close in few milliseconds.
+ // This should workaround a problem in Selenium tests' that
+ // blocks after click because the iframe goes out before
+ // the driver understands it was clicked. Similar bug is
+ // described here:
+ // - https://github.com/mozilla/geckodriver/issues/611
+ // - https://bugzilla.mozilla.org/show_bug.cgi?id=1223277
+ setTimeout(() => {
+ window.parent.postMessage("closeIframe", "*");
+ }, 15);
+ }
+
+ getModelName(): string {
+ return (this.serviceModel && this.serviceModel.name) || "";
+ }
+
+ getQuantityOptions(){
+ return _.range(this.minServiceQty, this.maxServiceQty + 1);
+ }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.html b/vid-webpack-master/src/app/components/service-popup/service-popup.html
new file mode 100644
index 000000000..e967daa3b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.html
@@ -0,0 +1,52 @@
+<div id="service-popup" class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" (click)="onCancelClick()" >&times;</button>
+ <span [attr.data-tests-id]="'create-modal-title'" class="modal-title">{{title}}</span>
+ </div>
+ <div class="modal-body popup-content">
+
+ <div class="header-left">
+ <div>SERVICE MODEL: <span>"{{getModelName()}}"</span></div>
+ </div>
+
+ <div class="header-right">
+ Service Instance Details
+ </div>
+
+ <label class="quantity-label">Qty:</label>
+ <div class="quantity">
+ <select class="quantity-select" [(ngModel)]="servicesQty" name="quantity" id="quantity-select" required>
+ <option *ngFor="let qty of quantityOptions" [value]="qty">{{qty}}</option>
+ </select>
+ </div>
+
+ <div class="service-model">
+
+ <model-information [modelInformationItems]="modelInformationItems"></model-information>
+ </div>
+
+ <div class="service-instance">
+ <service-instance-details [dynamicInputs]="dynamicInputs"
+ [serviceInstance]="serviceInstance"
+ [serviceModel]="serviceModel"
+ [servicesQty]="servicesQty"
+ (onDataChanged)="updateGeneralErrorSection()"
+ (closePopup)="onCancelClick($event)"></service-instance-details>
+ </div>
+
+ </div>
+ <div class="modal-footer row" style="padding: 0">
+ <div class="col-md-6">
+ <div *ngIf="hasGeneralApiError == true">
+ <form-general-error [message]="'Page contains errors. Please see details next to the relevant fields.'"></form-general-error>
+ </div>
+ </div>
+ <div class="col-md-6" style="padding: 15px;padding-right: 35px;">
+ <button [attr.data-tests-id]="'cancelButton'" type="button" class="btn btn-default cancel" (click)="onCancelClick()"><span>Cancel</span></button>
+ <input type="submit" value="Set" form="serviceForm" data-tests-id="service-form-set"
+ class="btn btn-success submit" [disabled]="!serviceInstanceDetails?.serviceForm?.valid">
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.scss b/vid-webpack-master/src/app/components/service-popup/service-popup.scss
new file mode 100644
index 000000000..aa4552d2f
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.scss
@@ -0,0 +1,185 @@
+$grid-border: 1px #d2d2d2 solid;
+
+#service-popup {
+ color: #191919;
+
+ .left-panel {
+ background: #f2f2f2;
+ border-right: $grid-border;
+ }
+
+ .header-common {
+ height: 100%;
+ align-items: center;
+ display: flex;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ .header-text {
+ padding-left: 30px;
+ @extend .header-common;
+ }
+
+ .header-left {
+ grid-area: header-left;
+ @extend .header-text;
+ @extend .left-panel;
+ border-bottom: $grid-border;
+
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ };
+ }
+
+ .header-right {
+ grid-area: header-right;
+
+ @extend .header-text;
+ border-bottom: $grid-border;
+ }
+
+ .quantity-label {
+ grid-area: quantity-label;
+ @extend .header-common;
+ border-bottom: $grid-border;
+ height: 100%;
+ font-family: OpenSans-Regular;
+ }
+
+ .quantity {
+ grid-area: quantity;
+ border-left: $grid-border;
+ border-bottom: $grid-border;
+ border-top-style: none;
+ font-family: OpenSans-Semibold;
+ text-align: start;
+ text-indent: 10px;
+ }
+
+ .quantity-select {
+ width: 78px;
+ height: 100%;
+ border: 0;
+ background: white;
+ outline: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: url('../../../assets/img/chevron.svg') 0 0 no-repeat;
+ background-size: 24px;
+ background-position-x: right;
+ background-position-y: center;
+ }
+ input[type="number"]:hover::-webkit-inner-spin-button {
+ height: 20px;
+ }
+
+ .service-model {
+ grid-area: service-model;
+
+ padding: 30px;
+ overflow: auto;
+ @extend .left-panel;
+ }
+
+ .service-instance {
+ grid-area: service-instance;
+ }
+
+ .popup-content {
+ display: grid;
+ grid-template-columns: 400px auto 30px 93px;
+ grid-template-rows: 50px calc(100vh - 180px);
+ grid-template-areas:
+ "header-left header-right quantity-label quantity"
+ "service-model service-instance service-instance service-instance";
+ padding: 0;
+ }
+}
+
+.modal {
+ background-color: #191919;
+ opacity: 0.8;
+}
+
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 0;
+}
+@media (min-width: 1150px) {
+ .popup-content {
+ grid-template-rows: 30px 680px;
+ }
+}
+
+.modal-content {
+ border-radius: 0;
+ box-shadow: none;
+ border: none;
+}
+
+.modal-footer {
+ .cancel {
+ width: 120px;
+ height: 36px;
+ background: #ffffff;
+ border: 1px solid #009fdb;
+ border-radius: 2px;
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #009fdb;
+ line-height: 16px;
+ }
+ }
+
+ .submit {
+ width: 120px;
+ height: 36px;
+ background: #009fdb;
+ border-radius: 2px;
+ border-color: #009fdb;
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #FFFFFF;
+ line-height: 16px;
+ }
+ }
+}
+
+.modal-header {
+ background-color: #009fdb;
+
+ padding-bottom: 13px;
+ padding-top: 13px;
+ padding-left: 29px;
+ padding-right: 21px;
+
+ .close {
+ font-size: 32px;
+ font-weight: 200;
+ color: #d8d8d8;
+ text-shadow: none;
+ filter: none;
+ opacity: 1;
+ }
+
+ .modal-title {
+ font-family: OpenSans-Regular;
+ font-size: 24px;
+ color: #fff;
+ line-height: 34px;
+ }
+}
+//
+//@media (min-width: 1200px) {
+// .service-model,
+// .service-instance {
+// width: 1050px;
+// margin: 30px auto;
+// }
+//}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts b/vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts
new file mode 100644
index 000000000..cddc6400a
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts
@@ -0,0 +1,138 @@
+
+import { TestBed, getTestBed} from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+import { ServicePopupService } from './service-popup.service';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { NumbersLettersUnderscoreValidator } from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+
+describe('Service Popup Service', () => {
+ let injector;
+ let service: ServicePopupService;
+ let httpMock: HttpTestingController;
+ let form : FormGroup;
+ let servicePopupDataModel;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [ServicePopupService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(ServicePopupService);
+ httpMock = injector.get(HttpTestingController);
+
+ form = generateFormGroup();
+ servicePopupDataModel = generateServicePopupDataModel();
+ });
+
+ describe('#resetDynamicInputs', () => {
+ it('resetDynamicInputs should reset dymanic fields',(done: DoneFn) => {
+ const dynamicInputs = generateDynamicInputs();
+ let serviceForm = generateFormGroup();
+ serviceForm.addControl(dynamicInputs[0].name, new FormControl({value: dynamicInputs[0].value, disabled: false}));
+
+ serviceForm.controls[dynamicInputs[0].name].setValue("diffValue");
+ service.resetDynamicInputs({
+ serviceInstanceDetailsFormGroup : serviceForm,
+ dynamicInputs : dynamicInputs
+ }, dynamicInputs);
+
+ expect(serviceForm.controls[dynamicInputs[0].name].value).toEqual(dynamicInputs[0].value);
+ done();
+ })
+ });
+
+ describe('#onControlError', () => {
+
+ it('should return true if instanceName is illegal', (done: DoneFn) => {
+ form.controls['instanceName'].setValue("illegal - illegal");
+
+ let result : boolean = service.onControlError(<any>servicePopupDataModel, form);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('should return false if instanceName is legal', (done: DoneFn) => {
+
+ form.controls['instanceName'].setValue("legal");
+ let result = service.onControlError(<any>servicePopupDataModel, form);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('should return false if lcpRegions is empty and is disabled', (done: DoneFn) => {
+ servicePopupDataModel.servicePopupDataModel['lcpRegions'] = [];
+ let result = service.onControlError(<any>servicePopupDataModel, form);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('should return true if lcpRegions is empty', (done: DoneFn) => {
+ servicePopupDataModel.servicePopupDataModel['lcpRegions'] = [];
+ form.controls['lcpCloudRegionId'].enable();
+ let result = service.onControlError(<any>servicePopupDataModel, form);
+ expect(result).toBeTruthy();
+ done()
+ });
+ });
+
+
+ function generateDynamicInputs(){
+ return JSON.parse('[{"id":"2017488_adiodvpe0_ASN","type":"string","name":"2017488_adiodvpe0_ASN","value":"AV_vPE","isRequired":true,"description":"AV/PE"}]');
+ }
+
+
+ function generateServicePopupDataModel() {
+ return {
+ "servicePopupDataModel" : JSON.parse('{"subscribers":[{"id":"a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb","name":"Mobility","isPermitted":false},{"id":"a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fc","name":"PACKET CORE","isPermitted":false},{"id":"e433710f-9217-458d-a79d-1c7aff376d89","name":"USP VOICE","isPermitted":true}],"serviceTypes":[{"id":"0","name":"vFlowLogic","isPermitted":false},{"id":"1","name":"VIRTUAL USP","isPermitted":true},{"id":"2","name":"Mobility","isPermitted":false},{"id":"3","name":"vBNG","isPermitted":false},{"id":"4","name":"vVoiceMail","isPermitted":false},{"id":"5","name":"Nimbus","isPermitted":false},{"id":"6","name":"vSEGW","isPermitted":false},{"id":"7","name":"vVM","isPermitted":false},{"id":"8","name":"vOTA","isPermitted":false},{"id":"9","name":"vMME","isPermitted":false},{"id":"10","name":"vMNS","isPermitted":false},{"id":"11","name":"vSCP","isPermitted":false},{"id":"12","name":"VPMS","isPermitted":false},{"id":"13","name":"vMMSC","isPermitted":false},{"id":"14","name":"SSD","isPermitted":false},{"id":"15","name":"vMOG","isPermitted":false},{"id":"16","name":"FIRSTNET","isPermitted":false},{"id":"17","name":"ACTIVE_CHARGE","isPermitted":false},{"id":"18","name":"vHSS","isPermitted":false}],"aicZones":[{"id":"NFT1","name":"NFTJSSSS-NFT1"},{"id":"JAG1","name":"YUDFJULP-JAG1"},{"id":"YYY1","name":"UUUAIAAI-YYY1"},{"id":"BAN1","name":"VSDKYUTP-BAN1"},{"id":"DKJ1","name":"DKJSJDKA-DKJ1"},{"id":"MCS1","name":"ASACMAMS-MCS1"},{"id":"UIO1","name":"uioclli1-UIO1"},{"id":"RAJ1","name":"YGBIJNLQ-RAJ1"},{"id":"OPA1","name":"opaclli1-OPA1"},{"id":"SDE1","name":"ZXCVBNMA-SDE1"},{"id":"VEN2","name":"FGHJUHIL-VEN2"},{"id":"ORL1","name":"ORLDFLMA-ORL1"},{"id":"JAD1","name":"JADECLLI-JAD1"},{"id":"ZXL1","name":"LWLWCANN-ZXL1"},{"id":"CKL1","name":"CLKSKCKK-CKL1"},{"id":"SDF1","name":"sdfclli1-SDF1"},{"id":"RAD1","name":"RADICAL1-RAD1"},{"id":"KIT1","name":"BHYJFGLN-KIT1"},{"id":"REL1","name":"INGERFGT-REL1"},{"id":"JNL1","name":"CJALSDAC-JNL1"},{"id":"OLK1","name":"OLKOLKLS-OLK1"},{"id":"CHI1","name":"CHILLIWE-CHI1"},{"id":"UUU4","name":"UUUAAAUU-UUU4"},{"id":"TUF1","name":"TUFCLLI1-TUF1"},{"id":"KJN1","name":"CKALDKSA-KJN1"},{"id":"SAM1","name":"SNDGCA64-SAN1"},{"id":"SCK1","name":"SCKSCKSK-SCK1"},{"id":"HJH1","name":"AOEEQQQD-HJH1"},{"id":"HGD1","name":"SDFQWHGD-HGD1"},{"id":"KOR1","name":"HYFLNBVT-KOR1"},{"id":"ATL43","name":"AICLOCID-ATL43"},{"id":"ATL54","name":"AICFTAAI-ATL54"},{"id":"ATL66","name":"CLLIAAII-ATL66"},{"id":"VEL1","name":"BNMLKUIK-VEL1"},{"id":"ICC1","name":"SANJITAT-ICC1"},{"id":"MNT11","name":"WSXEFBTH-MNT11"},{"id":"DEF2","name":"WSBHGTYL-DEF2"},{"id":"MAD11","name":"SDFQWGKL-MAD11"},{"id":"OLG1","name":"OLHOLHOL-OLG1"},{"id":"GAR1","name":"NGFVSJKO-GAR1"},{"id":"SAN22","name":"GNVLSCTL-SAN22"},{"id":"HRG1","name":"HRGHRGGS-HRG1"},{"id":"JCS1","name":"JCSJSCJS-JCS1"},{"id":"DHA12","name":"WSXEDECF-DHA12"},{"id":"HJE1","name":"AOEEWWWD-HJE1"},{"id":"NCA1","name":"NCANCANN-NCA1"},{"id":"IOP1","name":"iopclli1-IOP1"},{"id":"RTY1","name":"rtyclli1-RTY1"},{"id":"KAP1","name":"HIOUYTRQ-KAP1"},{"id":"ZEN1","name":"ZENCLLI1-ZEN1"},{"id":"HKA1","name":"JAKHLASS-HKA1"},{"id":"CQK1","name":"CQKSCAKK-CQK1"},{"id":"SAI1","name":"UBEKQLPD-SAI1"},{"id":"ERT1","name":"ertclli1-ERT1"},{"id":"IBB1","name":"PLMKOIJU-IBB1"},{"id":"TIR2","name":"PLKINHYI-TIR2"},{"id":"HSD1","name":"CHASKCDS-HSD1"},{"id":"SLF78","name":"SDCTLFN1-SLF78"},{"id":"SEE78","name":"SDCTEEE4-SEE78"},{"id":"SAN13","name":"TOKYJPFA-SAN13"},{"id":"SAA78","name":"SDCTAAA1-SAA78"},{"id":"LUC1","name":"ATLDFGYC-LUC1"},{"id":"AMD13","name":"MEMATLAN-AMD13"},{"id":"TOR1","name":"TOROONXN-TOR1"},{"id":"QWE1","name":"QWECLLI1-QWE1"},{"id":"ZOG1","name":"ZOGASTRO-ZOG1"},{"id":"CAL33","name":"CALIFORN-CAL33"},{"id":"SHH78","name":"SDIT1HHH-SHH78"},{"id":"DSA1","name":"LKJHGFDS-DSA1"},{"id":"CLG1","name":"CLGRABAD-CLG1"},{"id":"BNA1","name":"BNARAGBK-BNA1"},{"id":"ATL84","name":"CANTTCOC-ATL84"},{"id":"APP1","name":"WBHGTYUI-APP1"},{"id":"RJN1","name":"RJNRBZAW-RJN1"},{"id":"EHH78","name":"SDCSHHH5-EHH78"},{"id":"mac10","name":"PKGTESTF-mac10"},{"id":"SXB78","name":"SDCTGXB1-SXB78"},{"id":"SAX78","name":"SDCTAXG1-SAX78"},{"id":"SYD1","name":"SYDNAUBV-SYD1"},{"id":"TOK1","name":"TOKYJPFA-TOK1"},{"id":"KGM2","name":"KGMTNC20-KGM2"},{"id":"DCC1b","name":"POIUYTGH-DCC1b"},{"id":"SKK78","name":"SDCTKKK1-SKK78"},{"id":"SGG78","name":"SDCTGGG1-SGG78"},{"id":"SJJ78","name":"SDCTJJJ1-SJJ78"},{"id":"SBX78","name":"SDCTBXG1-SBX78"},{"id":"LAG1","name":"LARGIZON-LAG1"},{"id":"IAA1","name":"QAZXSWED-IAA1"},{"id":"POI1","name":"PLMNJKIU-POI1"},{"id":"LAG1a","name":"LARGIZON-LAG1a"},{"id":"PBL1","name":"PBLAPBAI-PBL1"},{"id":"LAG45","name":"LARGIZON-LAG1a"},{"id":"MAR1","name":"MNBVCXZM-MAR1"},{"id":"HST70","name":"HSTNTX70-HST70"},{"id":"DCC1a","name":"POIUYTGH-DCC1a"},{"id":"TOL1","name":"TOLDOH21-TOL1"},{"id":"LON1","name":"LONEENCO-LON1"},{"id":"SJU78","name":"SDIT1JUB-SJU78"},{"id":"STN27","name":"HSTNTX01-STN27"},{"id":"SSW56","name":"ss8126GT-SSW56"},{"id":"SBB78","name":"SDIT1BBB-SBB78"},{"id":"DCC3","name":"POIUYTGH-DCC3"},{"id":"GNV1","name":"GNVLSCTL-GNV1"},{"id":"WAS1","name":"WASHDCSW-WAS1"},{"id":"TOY1","name":"TORYONNZ-TOY1"},{"id":"STT1","name":"STTLWA02-STT1"},{"id":"STG1","name":"STTGGE62-STG1"},{"id":"SLL78","name":"SDCTLLL1-SLL78"},{"id":"SBU78","name":"SDIT1BUB-SBU78"},{"id":"ATL2","name":"ATLNGANW-ATL2"},{"id":"BOT1","name":"BOTHWAKY-BOT1"},{"id":"SNG1","name":"SNGPSIAU-SNG1"},{"id":"NYC1","name":"NYCMNY54-NYC1"},{"id":"LAG1b","name":"LARGIZON-LAG1b"},{"id":"AMD15","name":"AMDFAA01-AMD15"},{"id":"SNA1","name":"SNANTXCA-SNA1"},{"id":"PLT1","name":"PLTNCA60-PLT1"},{"id":"TLP1","name":"TLPNXM18-TLP1"},{"id":"SDD81","name":"SAIT1DD6-SDD81"},{"id":"DCC1","name":"POIUYTGH-DCC1"},{"id":"DCC2","name":"POIUYTGH-DCC2"},{"id":"OKC1","name":"OKCBOK55-OKC1"},{"id":"PAR1","name":"PARSFRCG-PAR1"},{"id":"TES36","name":"ABCEETES-TES36"},{"id":"COM1","name":"PLMKOPIU-COM1"},{"id":"ANI1","name":"ATLNGTRE-ANI1"},{"id":"SDG78","name":"SDIT1BDG-SDG78"},{"id":"mac20","name":"PKGTESTF-mac20"},{"id":"DSF45","name":"DSFBG123-DSF45"},{"id":"HST25","name":"HSTNTX01-HST25"},{"id":"AMD18","name":"AUDIMA01-AMD18"},{"id":"SAA80","name":"SAIT9AA3-SAA80"},{"id":"SSA56","name":"SSIT2AA7-SSA56"},{"id":"SDD82","name":"SAIT1DD9-SDD82"},{"id":"JCV1","name":"JCVLFLBW-JCV1"},{"id":"SUL2","name":"WERTYUJK-SUL2"},{"id":"PUR1","name":"purelyde-PUR1"},{"id":"FDE55","name":"FDERT555-FDE55"},{"id":"SITE","name":"LONEENCO-SITE"},{"id":"ATL1","name":"ATLNGAMA-ATL1"},{"id":"JUL1","name":"ZXCVBNMM-JUL1"},{"id":"TAT34","name":"TESAAISB-TAT34"},{"id":"XCP12","name":"CHKGH123-XCP12"},{"id":"RAI1","name":"poiuytre-RAI1"},{"id":"HPO1","name":"ATLNGAUP-HPO1"},{"id":"KJF12","name":"KJFDH123-KJF12"},{"id":"SCC80","name":"SAIT9CC3-SCC80"},{"id":"SAA12","name":"SAIT9AF8-SAA12"},{"id":"SAA14","name":"SAIT1AA9-SAA14"},{"id":"ATL35","name":"TTESSAAI-ATL35"},{"id":"CWY1","name":"CWYMOWBS-CWY1"},{"id":"ATL76","name":"TELEPAAI-ATL76"},{"id":"DSL12","name":"DSLFK242-DSL12"},{"id":"ATL53","name":"AAIATLTE-ATL53"},{"id":"SAA11","name":"SAIT9AA2-SAA11"},{"id":"ATL62","name":"TESSASCH-ATL62"},{"id":"AUG1","name":"ASDFGHJK-AUG1"},{"id":"POI22","name":"POIUY123-POI22"},{"id":"SAA13","name":"SAIT1AA9-SAA13"},{"id":"BHY17","name":"BHYTFRF3-BHY17"},{"id":"LIS1","name":"HOSTPROF-LIS1"},{"id":"SIP1","name":"ZXCVBNMK-SIP1"},{"id":"ATL99","name":"TEESTAAI-ATL43"},{"id":"ATL64","name":"FORLOAAJ-ATL64"},{"id":"TAT33","name":"TESAAISA-TAT33"},{"id":"RAD10","name":"INDIPUNE-RAD10"},{"id":"RTW5","name":"BHYTFRY4-RTW5"},{"id":"JGS1","name":"KSJKKKKK-JGS1"},{"id":"ATL98","name":"TEESTAAI-ATL43"},{"id":"WAN1","name":"LEIWANGW-WAN1"},{"id":"ATL44","name":"ATLSANAB-ATL44"},{"id":"RTD2","name":"BHYTFRk4-RTD2"},{"id":"NIR1","name":"ORFLMANA-NIR1"},{"id":"ATL75","name":"SANAAIRE-ATL75"},{"id":"NUM1","name":"QWERTYUI-NUM1"},{"id":"MTN32","name":"MDTWNJ21-MTN32"},{"id":"RTZ4","name":"BHYTFRZ6-RTZ4"},{"id":"ATL56","name":"ATLSANAC-ATL56"},{"id":"AMS1","name":"AMSTNLBW-AMS1"},{"id":"RCT1","name":"AMSTERNL-RCT1"},{"id":"JAN1","name":"ORFLMATT-JAN1"},{"id":"ABC14","name":"TESAAISA-ABC14"},{"id":"TAT37","name":"TESAAISD-TAT37"},{"id":"MIC54","name":"MICHIGAN-MIC54"},{"id":"ABC11","name":"ATLSANAI-ABC11"},{"id":"AMF11","name":"AMDOCS01-AMF11"},{"id":"ATL63","name":"ATLSANEW-ATL63"},{"id":"ABC12","name":"ATLSECIA-ABC12"},{"id":"MTN20","name":"MDTWNJ21-MTN20"},{"id":"ABC15","name":"AAITESAN-ABC15"},{"id":"AVT1","name":"AVTRFLHD-AVT1"},{"id":"ATL34","name":"ATLSANAI-ATL34"}],"lcpRegions":[{"id":"AAIAIC25","name":"AAIAIC25","isPermitted":true},{"id":"mtn6","name":"mtn6","isPermitted":true}],"lcpRegionsTenantsMap":{},"tenants":[{"id":"bae71557c5bb4d5aac6743a4e5f1d054","name":"AIN Web Tool-15-D-testgamma","isPermitted":true},{"id":"229bcdc6eaeb4ca59d55221141d01f8e","name":"AIN Web Tool-15-D-STTest2","isPermitted":true},{"id":"1178612d2b394be4834ad77f567c0af2","name":"AIN Web Tool-15-D-SSPtestcustome","isPermitted":true},{"id":"19c5ade915eb461e8af52fb2fd8cd1f2","name":"AIN Web Tool-15-D-UncheckedEcopm","isPermitted":true},{"id":"de007636e25249238447264a988a927b","name":"AIN Web Tool-15-D-dfsdf","isPermitted":true},{"id":"62f29b3613634ca6a3065cbe0e020c44","name":"AIN/SMS-16-D-Multiservices1","isPermitted":true},{"id":"649289e30d3244e0b48098114d63c2aa","name":"AIN Web Tool-15-D-SSPST66","isPermitted":true},{"id":"3f21eeea6c2c486bba31dab816c05a32","name":"AIN Web Tool-15-D-ASSPST47","isPermitted":true},{"id":"f60ce21d3ee6427586cff0d22b03b773","name":"CESAR-100-D-sspjg67246","isPermitted":true},{"id":"8774659e425f479895ae091bb5d46560","name":"CESAR-100-D-sspjg68359","isPermitted":true},{"id":"624eb554b0d147c19ff8885341760481","name":"AINWebTool-15-D-iftach","isPermitted":true},{"id":"214f55f5fc414c678059c383b03e4962","name":"CESAR-100-D-sspjg612401","isPermitted":true},{"id":"c90666c291664841bb98e4d981ff1db5","name":"CESAR-100-D-sspjg621340","isPermitted":true},{"id":"ce5b6bc5c7b348e1bf4b91ac9a174278","name":"sspjg621351cloned","isPermitted":true},{"id":"b386b768a3f24c8e953abbe0b3488c02","name":"AINWebTool-15-D-eteancomp","isPermitted":true},{"id":"dc6c4dbfd225474e9deaadd34968646c","name":"AINWebTool-15-T-SPFET","isPermitted":true},{"id":"02cb5030e9914aa4be120bd9ed1e19eb","name":"AINWebTool-15-X-eeweww","isPermitted":true},{"id":"f2f3830e4c984d45bcd00e1a04158a79","name":"CESAR-100-D-spjg61909","isPermitted":true},{"id":"05b91bd5137f4929878edd965755c06d","name":"CESAR-100-D-sspjg621512cloned","isPermitted":true},{"id":"7002fbe8482d4a989ddf445b1ce336e0","name":"AINWebTool-15-X-vdr","isPermitted":true},{"id":"4008522be43741dcb1f5422022a2aa0b","name":"AINWebTool-15-D-ssasa","isPermitted":true},{"id":"f44e2e96a1b6476abfda2fa407b00169","name":"AINWebTool-15-D-PFNPT","isPermitted":true},{"id":"b69a52bec8a84669a37a1e8b72708be7","name":"AINWebTool-15-X-vdre","isPermitted":true},{"id":"fac7d9fd56154caeb9332202dcf2969f","name":"AINWebTool-15-X-NONPODECOMP","isPermitted":true},{"id":"2d34d8396e194eb49969fd61ffbff961","name":"DN5242-Nov16-T5","isPermitted":true},{"id":"cb42a77ff45b48a8b8deb83bb64acc74","name":"ro-T11","isPermitted":true},{"id":"fa45ca53c80b492fa8be5477cd84fc2b","name":"ro-T112","isPermitted":true},{"id":"4914ab0ab3a743e58f0eefdacc1dde77","name":"DN5242-Nov21-T1","isPermitted":true},{"id":"d0a3e3f2964542259d155a81c41aadc3","name":"test-mtn6-09","isPermitted":true},{"id":"cbb99fe4ada84631b7baf046b6fd2044","name":"DN5242-Nov16-T3","isPermitted":true}],"productFamilies":null,"projects":[{"id":"DFW","name":"DFW"},{"id":"x1","name":"x1"},{"id":"yyy1","name":"yyy1"}],"owningEntities":[{"id":"aaa1","name":"aaa1"},{"id":"d61e6f2d-12fa-4cc2-91df-7c244011d6fc","name":"MetroPacketCore"},{"id":"Wireline","name":"Wireline"}],"globalCustomerId":"e433710f-9217-458d-a79d-1c7aff376d89"}')}
+ }
+
+ function generateFormGroup(){
+ return new FormGroup({
+ globalSubscriberId: new FormControl(
+ Validators.compose([Validators.required])
+ ),
+ productFamilyId: new FormControl(),
+ subscriptionServiceType: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ lcpCloudRegionId: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ tenantId: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ aicZoneId: new FormControl(),
+ projectName: new FormControl(),
+ owningEntityId: new FormControl(Validators.compose([Validators.required])),
+ instanceName : new FormControl({value: null}, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid]))
+ });
+ }
+
+
+ function generateServiceInstanceDetails(){
+ return {
+ servicePopupDataModel : {
+ "productFamilies" : []
+ },
+ serviceInstanceDetailsFormGroup : {
+ controls : {
+ productFamilyId : {
+ disabled : false
+ }
+ }
+ }
+ }
+ }
+
+ function generateLegalServiceInstance(){
+ return {
+ instanceName : "legalInstanceName"
+ }
+ }
+
+ function generateIllegalServiceInstance(){
+ return {
+ instanceName : "illegalInstanceName"
+ }
+ }
+
+});
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.service.ts b/vid-webpack-master/src/app/components/service-popup/service-popup.service.ts
new file mode 100644
index 000000000..f6efd353b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.service.ts
@@ -0,0 +1,33 @@
+import {Injectable} from '@angular/core';
+import {isNullOrUndefined} from "util";
+import {NumbersLettersUnderscoreValidator} from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {ServiceInstanceDetailsComponent} from './service-instance-details/service-instance-details.component';
+import {FormGroup} from '@angular/forms';
+import * as _ from "lodash";
+
+@Injectable()
+export class ServicePopupService {
+ onControlError(serviceInstanceDetails : ServiceInstanceDetailsComponent, serviceInstanceDetailsFormGroup : FormGroup) : boolean{
+ if(!isNullOrUndefined(serviceInstanceDetailsFormGroup) && !isNullOrUndefined(serviceInstanceDetailsFormGroup.controls['instanceName']) && NumbersLettersUnderscoreValidator.valid(serviceInstanceDetailsFormGroup.controls['instanceName'].value) && serviceInstanceDetailsFormGroup.controls['instanceName'].value != null && serviceInstanceDetailsFormGroup.controls['instanceName'].value.length > 0){
+ return true;
+ }
+
+ const controlName : Array<string> = ['productFamilyId', 'lcpCloudRegionId', 'tenantId', 'owningEntityId', 'projectName', 'aicZoneId', 'subscriptionServiceType', 'globalSubscriberId', 'rollbackOnFailure'];
+ const selectDataName : Array<string> = ['productFamilies', 'lcpRegions', 'tenants', 'owningEntities', 'projects', 'aicZones', 'serviceTypes', 'subscribers', 'rollbackOnFailure'];
+ for(let i = 0 ; i < controlName.length ; i++){
+ if (!isNullOrUndefined(serviceInstanceDetails.servicePopupDataModel) && !isNullOrUndefined(serviceInstanceDetails.servicePopupDataModel[selectDataName[i]])) {
+ if (!serviceInstanceDetailsFormGroup.controls[controlName[i]].disabled && serviceInstanceDetails.servicePopupDataModel[selectDataName[i]].length === 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ resetDynamicInputs(serviceInstance : any, defaultDynamicInputs : any) : void {
+ for(let dynamicInput of serviceInstance.dynamicInputs){
+ const defaultDymanicInput = _.find(defaultDynamicInputs, {name:dynamicInput.name});
+ serviceInstance.serviceInstanceDetailsFormGroup.controls[dynamicInput.name].setValue(defaultDymanicInput.value);
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts
new file mode 100644
index 000000000..725e44293
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts
@@ -0,0 +1,275 @@
+import {Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {VNFPopupDataModel} from './vnfPopupDataModel';
+import {AaiService} from '../../../services/aaiService/aai.service';
+import { createVFModuleInstance, updateVFModuleInstance, updateVNFInstance } from '../../../service.actions';
+import {VnfInstance} from "../../../shared/models/vnfInstance";
+import {ServiceInstance} from "../../../shared/models/serviceInstance";
+import {VNFModel} from "../../../shared/models/vnfModel";
+import {InputType} from "../../../shared/models/inputTypes";
+import {ModelInfo} from "../../../shared/models/modelInfo";
+import {VfModuleInstance} from "../../../shared/models/vfModuleInstance";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../../../store/reducers";
+import {SelectOptionInterface} from "../../../shared/models/selectOption";
+import {Observable} from "rxjs/Observable";
+import {loadProductFamiliesAction} from "../../../services/aaiService/aai.actions";
+import {VnfInstanceDetailsService} from "./vnf-instance-details.service";
+import {isNullOrUndefined} from 'util';
+import {NumbersLettersUnderscoreValidator} from '../../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import * as _ from "lodash";
+import {ServiceNodeTypes} from "../../../shared/models/ServiceNodeTypes";
+
+@Component({
+ selector: 'vnf-instance-details',
+ templateUrl: 'vnf-instance-details.html',
+ styleUrls: ['vnf-instance-details.scss'],
+ providers: [AaiService]
+})
+
+export class VnfInstanceDetailsComponent implements OnInit {
+ @ViewChild('vnfForm') vnfForm: 'VnfForm';
+ _vnfModel: VNFModel;
+ @Input ()
+ set vnfModel(vnfModel: VNFModel) {
+ this._vnfModel = vnfModel;
+ this.updateFormGroupControlsFromVNFModel();
+ }
+ @Input() vnfInstance: any;
+ @Input() serviceInstance: ServiceInstance;
+ @Input() dynamicInputs;
+ @Input() modelName: string;
+ @Input() serviceUuid: string;
+ @Input() userProvidedNaming: boolean;
+ _modelType: string;
+ @Input()
+ set modelType(modelType: string) {
+ this._modelType = modelType;
+ this.updateFormGroupControlsFromVNFModel();
+ }
+
+ @Input() parentModelName: string;
+ @Input() isNewVfModule : boolean;
+
+
+ @Output() onSubmitClick: EventEmitter<any> = new EventEmitter<any>();
+ @Output() onServiceInstanceNameChanged : EventEmitter<boolean> = new EventEmitter<boolean>();
+ @Output() onVolumeGroupNameChanged : EventEmitter<boolean> = new EventEmitter<boolean>();
+
+@Output() onDataChanged: EventEmitter<any> = new EventEmitter<any>();
+ @select(['service','productFamilies'])
+ readonly productFamilies : Observable<SelectOptionInterface[]>;
+
+ vnfPopupDataModel: VNFPopupDataModel = new VNFPopupDataModel();
+ lcpRegionsThatEnableLegacyRegionField = ['AAIAIC25', 'rdm3', 'rdm5a'];
+ shouldShowLegacyRegion: boolean;
+ instanceFormGroup: FormGroup = null;
+ inputType = InputType;
+ isNotUniqueInstanceName : boolean = false;
+ isNotUniqueVolumeGroupName : boolean = false;
+
+ constructor(private _aaiService: AaiService, private store: NgRedux<AppState>,
+ private _vnfInstanceDetailsService : VnfInstanceDetailsService) {
+ this.store.subscribe(() => {
+ this.updateFormData()
+ });
+ }
+
+ ngOnInit() {
+ this.updateFormGroup();
+ this.subscribeToFormChanges();
+ this._aaiService.getCategoryParameters(null).subscribe();
+ this._aaiService.getLcpRegionsAndTenants(this.serviceInstance.globalSubscriberId, this.serviceInstance.subscriptionServiceType).subscribe();
+ this.updateLegacyRegionVisibility();
+ this.store.dispatch(loadProductFamiliesAction());
+ }
+
+ isInputShouldBeShown(inputType: any) {
+ let vnfInputs = [InputType.LCP_REGION, InputType.LOB, InputType.TENANT, InputType.PRODUCT_FAMILY, InputType.PLATFORM, InputType.ROLLBACK];
+ let vfInputs = [InputType.VG];
+ let exist = false;
+ if (this._modelType === 'VF') {
+ exist = vnfInputs.indexOf(inputType) > -1;
+ }
+ else {
+ exist = vfInputs.indexOf(inputType) > -1;
+ }
+ return exist;
+ }
+
+ updateFormGroupControlsFromVNFModel() {
+ if (this._vnfModel && this._modelType) {
+ if (this._modelType === ServiceNodeTypes.VF) {
+ const vnfInstance = <VnfInstance>this.vnfInstance;
+ if (this.instanceFormGroup && this.userProvidedNaming
+ && !this.instanceFormGroup.get('instanceName')) {
+ const initialInstanceName = vnfInstance.instanceName || (!isNullOrUndefined(this._vnfModel.name) ? this._vnfModel.name.replace(/[-]/g, "") : this._vnfModel.name);
+ this.instanceFormGroup.addControl('instanceName', new FormControl(initialInstanceName, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid])))
+ }
+ }
+ else if (this._modelType === ServiceNodeTypes.VFmodule) {
+ const vfInstance = <VfModuleInstance>this.vnfInstance;
+ if (this.instanceFormGroup && this.userProvidedNaming && !this.instanceFormGroup.get('instanceName')) {
+ this.instanceFormGroup.addControl('instanceName', new FormControl(vfInstance.instanceName, Validators.required));
+
+ let vfModule = this.extractVfAccordingToVfModuleUuid(this.store.getState(), this._vnfModel.uuid);
+ if (vfModule.volumeGroupAllowed && !this.instanceFormGroup.get('volumeGroupName')) {
+ this.instanceFormGroup.addControl('volumeGroupName', new FormControl(vfInstance.volumeGroupName));
+ }
+ }
+ }
+ }
+ }
+
+ updateFormGroup() {
+ const tenantDisabled = !this.vnfInstance.lcpCloudRegionId;
+
+ if (this._modelType === ServiceNodeTypes.VF) {
+ const vnfInstance = <VnfInstance>this.vnfInstance;
+ this.instanceFormGroup = new FormGroup({
+ productFamilyId: new FormControl(vnfInstance.productFamilyId),
+ lcpCloudRegionId: new FormControl(vnfInstance.lcpCloudRegionId, Validators.required),
+ tenantId: new FormControl({value: vnfInstance.tenantId, disabled: tenantDisabled}, Validators.required),
+ legacyRegion: new FormControl(vnfInstance.legacyRegion),
+ lineOfBusiness: new FormControl(vnfInstance.lineOfBusiness),
+ platformName: new FormControl(vnfInstance.platformName, Validators.required),
+ });
+ }
+ else if (this._modelType === ServiceNodeTypes.VFmodule) {
+ const vfInstance = <VfModuleInstance>this.vnfInstance;
+ this.instanceFormGroup = new FormGroup({
+ });
+ }
+
+ this.instanceFormGroup.valueChanges.subscribe(()=> {
+ this.checkForUniqueInstanceName();
+ this.onDataChanged.next();
+ });
+
+ this.updateFormGroupControlsFromVNFModel();
+ }
+
+ private getParentVnfModel(): VNFModel {
+ const rawModel = _.get(this.store.getState().service.serviceHierarchy[this.serviceUuid], ['vnfs', this.parentModelName]);
+ return new VNFModel(rawModel);
+ }
+
+ extractVfAccordingToVfModuleUuid(state : any,vfModuleUuid : string) {
+ const vnfs = this.store.getState().service.serviceHierarchy[this.serviceUuid].vnfs;
+ const vnfsArray = Object.values(vnfs);
+ for (let i = 0; i<vnfsArray.length;i++){
+ let vfModules = Object.values(vnfsArray[i].vfModules);
+ for (let j = 0; j<vfModules.length;j++){
+ if (vfModules[j].uuid === vfModuleUuid){
+ return vfModules[j];
+ }
+ }
+ }
+ }
+
+ updateFormData() {
+ let service = this.store.getState().service;
+ this.vnfPopupDataModel.lcpRegions = service.lcpRegionsAndTenants.lcpRegionList;
+ if (this.vnfInstance && this.vnfInstance.lcpCloudRegionId) {
+ this.vnfPopupDataModel.tenants = service.lcpRegionsAndTenants.lcpRegionsTenantsMap[this.vnfInstance.lcpCloudRegionId];
+ console.log('setting vnf instances tenant: ' + JSON.stringify(this.vnfPopupDataModel.tenants));
+ }
+ this.vnfPopupDataModel.platforms = service.categoryParameters.platformList;
+ this.vnfPopupDataModel.lineOfBusinesses = service.categoryParameters.lineOfBusinessList;
+ this.onDataChanged.next();
+ }
+
+ subscribeToFormChanges(): void {
+ if (this.instanceFormGroup.get('lcpCloudRegionId') !== null) {
+ this.instanceFormGroup.get('lcpCloudRegionId').valueChanges.subscribe(val => {
+ this.setDisabledState(val, 'tenantId');
+ this.updateTenantList(val);
+ this.updateLegacyRegionVisibility();
+ this.onDataChanged.next();
+ });
+ }
+ }
+
+ setDisabledState(val, field: string): void {
+ if (val) {
+ this.instanceFormGroup.controls[field].enable();
+ }
+ }
+
+ updateLegacyRegionVisibility() {
+ if (this.instanceFormGroup.get('lcpCloudRegionId') !== null) {
+ this.shouldShowLegacyRegion = this.lcpRegionsThatEnableLegacyRegionField.indexOf(this.instanceFormGroup.get('lcpCloudRegionId').value) > -1;
+ if (!this.shouldShowLegacyRegion) {
+ this.instanceFormGroup.controls.legacyRegion.setValue(undefined);
+ }
+ }
+ }
+
+ updateTenantList(cloudRegionId) {
+ this.resetTenantSelection();
+ const tenantsForCloudRegionId = this.store.getState().service.lcpRegionsAndTenants.lcpRegionsTenantsMap[cloudRegionId];
+ console.log('tenants for selected cloud region id: ' + JSON.stringify(tenantsForCloudRegionId));
+ this.vnfPopupDataModel.tenants = tenantsForCloudRegionId;
+ }
+
+ resetTenantSelection() {
+ this.instanceFormGroup.controls.tenantId.setValue(undefined);
+ }
+
+ checkForUniqueInstanceName() {
+ let currentName = !isNullOrUndefined(this.instanceFormGroup.get('instanceName')) ? this.instanceFormGroup.get('instanceName').value : null;
+
+ if(currentName && !this._vnfInstanceDetailsService.isUnique(this.store.getState().service.serviceInstance, this.serviceUuid, currentName, currentName === this.serviceInstance.instanceName) && this.userProvidedNaming){
+ this.isNotUniqueInstanceName = true;
+ this.onServiceInstanceNameChanged.emit(true);
+ }else {
+ this.isNotUniqueInstanceName = false;
+ this.onServiceInstanceNameChanged.emit(false);
+ }
+ }
+
+ checkForUniqueGroupName(){
+ let currentName = this.instanceFormGroup.get('volumeGroupName').value;
+ if( !this._vnfInstanceDetailsService.isUnique(this.store.getState().service.serviceInstance, this.serviceUuid, currentName, currentName === this.serviceInstance['volumeGroupName'])){
+ this.isNotUniqueVolumeGroupName = true;
+ this.onVolumeGroupNameChanged.emit(true);
+ }else {
+ this.isNotUniqueVolumeGroupName = false;
+ this.onVolumeGroupNameChanged.emit(false);
+ }
+ }
+
+ onSubmit(formValues): void {
+ formValues.modelInfo = new ModelInfo(this._vnfModel);
+ if (this._modelType === 'VFmodule') {
+ let dynamicFields: { [dynamicField: string]: string; };
+ dynamicFields = {};
+ if(!_.isEmpty(this.dynamicInputs)) {
+ this.dynamicInputs.map(function (x) {
+ let dynamicField: string = x.id;
+ dynamicFields[dynamicField] = formValues[dynamicField];
+ delete formValues[dynamicField];
+ });
+ }
+ formValues.instanceParams = [];
+ formValues.instanceParams.push(dynamicFields);
+ if(this.isNewVfModule){
+ this.store.dispatch(createVFModuleInstance(formValues, this.modelName, this.serviceUuid));
+ }else {
+ this.store.dispatch(updateVFModuleInstance(formValues, this.modelName, this.serviceUuid));
+ }
+
+ }
+ else {
+ formValues.isUserProvidedNaming = this.userProvidedNaming;
+ this.store.dispatch(updateVNFInstance(formValues, this.modelName, this.serviceUuid));
+ }
+ window.parent.postMessage({
+ eventId: 'submitIframe',
+ data: {
+ serviceModelId: this.serviceUuid
+ }
+ }, "*");
+ this.onSubmitClick.emit(this.serviceUuid);
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html
new file mode 100644
index 000000000..ccdaac53b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html
@@ -0,0 +1,114 @@
+
+<div id="vnf-instance-details">
+ <form id="vnfForm" #vnfForm="ngForm" (ngSubmit)="onSubmit(vnfForm.value)" [formGroup]="instanceFormGroup">
+
+ <div class="details-item" *ngIf="instanceFormGroup.get('instanceName')">
+ <label class="required">Instance name:</label>
+ <input patternInput
+ pattern="^[a-zA-Z0-9_]*$"
+ [attr.data-tests-id]="'instanceName'"
+ [ngClass]="{'error-style' : _vnfInstanceDetailsService.hasInstanceNameError(instanceFormGroup) || _vnfInstanceDetailsService.hasUniqueError(isNotUniqueInstanceName)}"
+ id="instance-name" name="instance-name"
+ [formControlName]="'instanceName'"
+ class="form-control input-text"
+ placeholder="Type Instance Name"
+ type="text"
+ (blur)="checkForUniqueInstanceName()">
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasUniqueError(isNotUniqueInstanceName)" [message]="'Instance name is already in use, please pick another name.'"></form-control-error>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasInstanceNameError(instanceFormGroup)" [message]="'Instance name may include only alphanumeric characters and underscore.'"></form-control-error>
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.PRODUCT_FAMILY)" class="details-item">
+ <label>Product family:</label>
+ <select class="form-control input-text"
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('productFamilyId',productFamilies, instanceFormGroup)}"
+ data-tests-id="productFamily"
+ id="product-family-select"
+ [formControlName]="'productFamilyId'"
+ name="product-family-select" >
+ <option [value]="null" disabled>Select Product Family</option>
+ <option *ngFor="let productFamily of productFamilies | async" [value]="productFamily.id"
+ [disabled]="!productFamily.isPermitted">{{productFamily.name}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('productFamilyId',productFamilies, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.LCP_REGION)" class="details-item">
+ <label class="required">LCP region:</label>
+ <select
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('lcpCloudRegionId',vnfPopupDataModel?.lcpRegions, instanceFormGroup)}"
+ class="form-control input-text"
+ [formControlName]="'lcpCloudRegionId'"
+ name="lcpRegion" id="lcpRegion-select"
+ data-tests-id="lcpRegion">
+ <option [value]="null" disabled>Select LCP Region</option>
+ <option *ngFor="let lcpRegion of vnfPopupDataModel.lcpRegions" [value]="lcpRegion.id" [disabled]="!lcpRegion.isPermitted" class="lcpRegionOption">{{lcpRegion.id}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('lcpCloudRegionId',vnfPopupDataModel?.lcpRegions, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item" *ngIf="shouldShowLegacyRegion">
+ <label>Legacy Region:</label>
+ <input
+ [attr.data-tests-id]="'lcpRegionText'"
+ id="legacy-region"
+ name="legacy-region"
+ [formControlName]="'legacyRegion'"
+ class="form-control input-text"
+ placeholder="Type Legacy Region" type="text">
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.TENANT)" class="details-item">
+ <label class="required">Tenant:</label>
+ <select class="form-control input-text"
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('tenantId',vnfPopupDataModel?.tenants, instanceFormGroup)}"
+ [formControlName]="'tenantId'"
+ name="tenant" id="tenant-select" data-tests-id="tenant">
+ <option [value]="undefined" disabled>Select Tenant</option>
+ <option *ngFor="let tenant of vnfPopupDataModel.tenants" [value]="tenant.id" [disabled]="!tenant.isPermitted">{{tenant.name}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('tenantId',vnfPopupDataModel?.tenants, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.LOB)" class="details-item">
+ <label>Line of business:</label>
+ <select [attr.data-tests-id]="'lineOfBusiness'"
+ class="form-control input-text"
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('lineOfBusiness',vnfPopupDataModel?.lineOfBusinesses, instanceFormGroup)}"
+ name="lineOfBusiness" id="lineOfBusiness"
+ [formControlName]="'lineOfBusiness'">
+ <option [value]="null" disabled>Select Line Of Business</option>
+ <option *ngFor="let project of vnfPopupDataModel.lineOfBusinesses" [value]="project.id">{{project.name}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('lineOfBusiness',vnfPopupDataModel?.lineOfBusinesses, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.PLATFORM)" class="details-item">
+ <label class="required">Platform:</label>
+ <select
+ [attr.data-tests-id]="'platform'"
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('platformName',vnfPopupDataModel?.platforms, instanceFormGroup)}"
+ class="form-control input-text"
+ [formControlName]="'platformName'"
+ name="platform" id="platform">
+ <option [value]="null" disabled>Select Platform</option>
+ <option *ngFor="let platform of vnfPopupDataModel.platforms" [value]="platform.id">{{platform.name}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('platformName',vnfPopupDataModel?.platforms, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+
+ <div *ngIf="isInputShouldBeShown(inputType.VG) && instanceFormGroup.get('volumeGroupName')" class="details-item" >
+ <label class="required">Volume Group Name:</label>
+ <input [attr.data-tests-id]="'volumeGroupName'"
+ id="vgName" name="vgName"
+ [ngClass]="{'error-style' :isNotUniqueVolumeGroupName}"
+ [formControlName]="'volumeGroupName'"
+ class="form-control input-text"
+ placeholder="Type Instance Name" type="text" (blur)="checkForUniqueGroupName()">
+ <form-control-error *ngIf="isNotUniqueVolumeGroupName" [message]="'Volume Group instance name is already in use, please pick another name.'"></form-control-error>
+ </div>
+
+ <dynamic-inputs *ngIf="dynamicInputs != undefined && dynamicInputs.length>0" [group]="instanceFormGroup" [list]="dynamicInputs"></dynamic-inputs>
+ </form>
+</div>
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss
new file mode 100644
index 000000000..080540a57
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss
@@ -0,0 +1,64 @@
+#vnf-instance-details {
+ position: relative;
+
+ #notification-area {
+ color: #959595;
+ font-size: 12px;
+ position: absolute;
+ top: 3px;
+ left: 30px;
+ }
+
+ height: 100%;
+ overflow: auto;
+ padding: 30px;
+
+ /deep/ {
+ .form-control {
+ border-radius: 2px;
+ box-shadow: none;
+ border-color: #D2D2D2;
+ }
+
+ label {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ select {
+ @extend .form-control;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: url('../../../../assets/img/chevron.svg') 0 0 no-repeat;
+ background-size: 24px;
+ background-position-x: right;
+ background-position-y: center;
+ font-family: OpenSans-Italic;
+ font-size: 14px;
+ color: #959595;
+ height: 38px;
+ }
+
+ input:not([type='checkbox']) {
+ @extend .form-control;
+ height: 38px;
+ }
+
+ .form-control[disabled], fieldset[disabled] .form-control {
+ opacity: 0.5;
+ }
+ .input-text {
+ border: 1px solid #D2D2D2;
+ border-radius: 2px;
+ }
+
+ .details-item {
+ margin-bottom: 20px;
+ }
+ }
+
+ .checkbox-label {
+ font-family: OpenSans-Regular;
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts
new file mode 100644
index 000000000..41ddb4372
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts
@@ -0,0 +1,241 @@
+import { TestBed, getTestBed } from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+import { VnfInstanceDetailsService } from './vnf-instance-details.service';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { NumbersLettersUnderscoreValidator } from '../../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+
+describe('Vnf Instance Details Service', () => {
+ let injector;
+ let service: VnfInstanceDetailsService;
+ let httpMock: HttpTestingController;
+
+ let SERVICE_ID: string = '1a80c596-27e5-4ca9-b5bb-e03a7fd4c0fd';
+ let serviceHierarchy;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [VnfInstanceDetailsService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(VnfInstanceDetailsService);
+ httpMock = injector.get(HttpTestingController);
+ serviceHierarchy = getServiceServiceHierarchy();
+ });
+
+
+ describe('#hasInstanceNameError', ()=> {
+ it('hasInstanceNameError should return true if instanceName is illegal and enabled', (done: DoneFn) => {
+ let form = generateFormGroup();
+ form.controls['instanceName'].setValue('----');
+ form.controls['instanceName'].setErrors({
+ pattern : true
+ });
+ form.controls['instanceName'].markAsTouched();
+ let result = service.hasInstanceNameError(form);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('hasInstanceNameError should return false if instanceName is illegal and enabled and pattern is ok', (done: DoneFn) => {
+ let form = generateFormGroup();
+ form.controls['instanceName'].setValue('----');
+ form.controls['instanceName'].setErrors({
+ otherError : true
+ });
+ form.controls['instanceName'].markAsTouched();
+ let result = service.hasInstanceNameError(form);
+ expect(result).toBeFalsy();
+ done();
+ });
+ });
+
+ describe('#isUnique', () => {
+ it('Create Mode: should return false if instanceName exist', (done: DoneFn) => {
+ serviceHierarchy = getServiceServiceHierarchy();
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceName', false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('Update Mode: should return true if instanceName exist once', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceName', true);
+ expect(result).toBeTruthy()
+ done();
+ });
+
+ it('Create Mode: should return true if instanceName not exist', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameNotExist', false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('Create Mode: should return false if instanceName exist inside vf modules', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameVfModule', false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('Update Mode: should return true if instanceName exist once inside vf modules', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameVfModule', true);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('Create Mode: should return true if instanceName is not exist at vf modules and vnfs', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameVfModuleNotExist', false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('Create Mode: should return false if instanceName exist service name', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'Instance-Name', false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('Create Mode: should return false if volumeGroupName exist service name', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'volumeGroupNameExist', false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('Create Mode: should return true if volumeGroupName not exist service name', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'volumeGroupNameNotExist', false);
+ expect(result).toBeTruthy();
+ done();
+ });
+ });
+
+ function getServiceServiceHierarchy() {
+ return JSON.parse(JSON.stringify(
+ {
+ "1a80c596-27e5-4ca9-b5bb-e03a7fd4c0fd": {
+ "vnfs": {
+ "2017-388_ADIOD-vPE 1": {
+ "rollbackOnFailure": "true",
+ "vfModules": {},
+ "instanceParams": [
+ {}
+ ],
+ "productFamilyId": "a4f6f2ae-9bf5-4ed7-b904-06b2099c4bd7",
+ "lcpCloudRegionId": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+ "lineOfBusiness": "zzz1",
+ "platformName": "platform",
+ "instanceName": "uniqueInstanceName",
+ "modelInfo": {
+ "modelInvariantId": "00beb8f9-6d39-452f-816d-c709b9cbb87d",
+ "modelVersionId": "0903e1c0-8e03-4936-b5c2-260653b96413",
+ "modelName": "2017-388_ADIOD-vPE",
+ "modelVersion": "1.0",
+ "modelCustomizationId": "280dec31-f16d-488b-9668-4aae55d6648a",
+ "modelCustomizationName": "2017-388_ADIOD-vPE 1"
+ },
+ "isUserProvidedNaming": true
+ },
+ "2017-388_ADIOD-vPE 0": {
+ "rollbackOnFailure": "true",
+ "vfModules": {},
+ "instanceParams": [
+ {}
+ ],
+ "productFamilyId": null,
+ "lcpCloudRegionId": "mtn6",
+ "tenantId": "1178612d2b394be4834ad77f567c0af2",
+ "lineOfBusiness": "ECOMP",
+ "platformName": "xxx1",
+ "instanceName": "blaaa",
+ "modelInfo": {
+ "modelInvariantId": "72e465fe-71b1-4e7b-b5ed-9496118ff7a8",
+ "modelVersionId": "afacccf6-397d-45d6-b5ae-94c39734b168",
+ "modelName": "2017-388_ADIOD-vPE",
+ "modelVersion": "4.0",
+ "modelCustomizationId": "b3c76f73-eeb5-4fb6-9d31-72a889f1811c",
+ "modelCustomizationName": "2017-388_ADIOD-vPE 0"
+ },
+ "isUserProvidedNaming": true
+ },
+ "2017488_ADIODvPE 0": {
+ "rollbackOnFailure": "true",
+ "vfModules": {
+ "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1": {
+ "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1": {
+ "rollbackOnFailure": "true",
+ "instanceName": "uniqueInstanceNameVfModule",
+ "volumeGroupName": "volumeGroupNameExist",
+ "modelInfo": {
+ "modelInvariantId": "7253ff5c-97f0-4b8b-937c-77aeb4d79aa1",
+ "modelVersionId": "25284168-24bb-4698-8cb4-3f509146eca5",
+ "modelName": "2017488AdiodVpe..ADIOD_vRE_BV..module-1",
+ "modelVersion": "6"
+ }
+ }
+ }
+ },
+ "instanceParams": [
+ {}
+ ],
+ "productFamilyId": "ebc3bc3d-62fd-4a3f-a037-f619df4ff034",
+ "lcpCloudRegionId": "mtn6",
+ "tenantId": "19c5ade915eb461e8af52fb2fd8cd1f2",
+ "lineOfBusiness": "zzz1",
+ "platformName": "platform",
+ "instanceName": "2017488_ADIODvPE",
+ "modelInfo": {
+ "modelInvariantId": "72e465fe-71b1-4e7b-b5ed-9496118ff7a8",
+ "modelVersionId": "69e09f68-8b63-4cc9-b9ff-860960b5db09",
+ "modelName": "2017488_ADIODvPE",
+ "modelVersion": "5.0",
+ "modelCustomizationId": "1da7b585-5e61-4993-b95e-8e6606c81e45",
+ "modelCustomizationName": "2017488_ADIODvPE 0"
+ },
+ "isUserProvidedNaming": true
+ }
+ },
+ "instanceParams": [
+ {}
+ ],
+ "globalSubscriberId": "e433710f-9217-458d-a79d-1c7aff376d89",
+ "productFamilyId": "17cc1042-527b-11e6-beb8-9e71128cae77",
+ "subscriptionServiceType": "VIRTUAL USP",
+ "lcpCloudRegionId": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+ "aicZoneId": "DKJ1",
+ "projectName": "DFW",
+ "owningEntityId": "aaa1",
+ "instanceName": "Instance-Name",
+ "bulkSize": 1,
+ "modelInfo": {
+ "modelInvariantId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0",
+ "modelVersionId": "1a80c596-27e5-4ca9-b5bb-e03a7fd4c0fd",
+ "modelName": "action-data",
+ "modelVersion": "1.0"
+ },
+ "tenantName": "USP-SIP-IC-24335-T-01",
+ "aicZoneName": "DKJSJDKA-DKJ1",
+ "isUserProvidedNaming": true
+ }
+ }
+ ));
+ }
+
+ function generateFormGroup() {
+ return new FormGroup({
+ productFamilyId: new FormControl(),
+ lcpCloudRegionId: new FormControl(Validators.required),
+ tenantId: new FormControl({value: null, disabled: false}, Validators.required),
+ legacyRegion: new FormControl(),
+ lineOfBusiness: new FormControl(),
+ platformName: new FormControl(Validators.required),
+ rollbackOnFailure: new FormControl(Validators.required),
+ instanceName: new FormControl({value: null}, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid]))
+
+ });
+ }
+
+});
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts
new file mode 100644
index 000000000..677895e72
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts
@@ -0,0 +1,64 @@
+import { Injectable } from '@angular/core';
+import { isNullOrUndefined } from "util";
+import { FormGroup } from '@angular/forms';
+@Injectable()
+export class VnfInstanceDetailsService {
+ isUnique(serviceInstance : any, serviceId : string, name: string, isEqualToOriginalInstanceName : boolean) : boolean {
+ const service = serviceInstance[serviceId];
+ let countInstanceName = 0;
+ let countVolumeGroupName = 0;
+ if(service){
+ if(service.instanceName === name) return false;
+ if(service.vnfs){
+ for(let key in service.vnfs){
+ if(service.vnfs[key].instanceName === name) {
+ countInstanceName++;
+ if((isEqualToOriginalInstanceName && countInstanceName > 1) || (!isEqualToOriginalInstanceName)) return false;
+ }
+ if(service.vnfs[key].vfModules){
+ for(let vfModule in service.vnfs[key].vfModules){
+ if(service.vnfs[key].vfModules[vfModule]) {
+ for(let module in service.vnfs[key].vfModules[vfModule]){
+ if(service.vnfs[key].vfModules[vfModule][module].instanceName === name ) {
+ countInstanceName++;
+ if((isEqualToOriginalInstanceName && countInstanceName > 1) || (!isEqualToOriginalInstanceName)) return false;
+ }
+
+ if(service.vnfs[key].vfModules[vfModule][module].volumeGroupName === name ) {
+ countVolumeGroupName++;
+ if((isEqualToOriginalInstanceName && countVolumeGroupName > 1) || (!isEqualToOriginalInstanceName)) return false;
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+ return true;
+ }
+
+ hasApiError(controlName: string, data: Array<any>, form: FormGroup) {
+ if (!isNullOrUndefined(data)) {
+ if (!form.controls[controlName].disabled && data.length === 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ hasInstanceNameError(form : FormGroup) : boolean {
+ if(!isNullOrUndefined(form) && !isNullOrUndefined(form.controls['instanceName'])){
+ if (form.controls['instanceName'].touched && form.controls['instanceName'].errors && form.controls['instanceName'].errors.pattern) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ hasUniqueError(isNotUniqueInstanceName) : boolean {
+ return isNotUniqueInstanceName;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts
new file mode 100644
index 000000000..9a2694c70
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts
@@ -0,0 +1,26 @@
+import {Project} from "../../../shared/models/project";
+import {LcpRegion} from "../../../shared/models/lcpRegion";
+import {Tenant} from "../../../shared/models/tenant";
+import {ProductFamily} from "../../../shared/models/productFamily";
+import {SelectOption, SelectOptionInterface} from "../../../shared/models/selectOption";
+
+export class VNFPopupDataModel {
+ productFamilies: ProductFamily[];
+ lcpRegions: LcpRegion[];
+ lcpRegionsTenantsMap: any;
+ tenants: Tenant[];
+ projects: Project[];
+ lineOfBusinesses: SelectOption[];
+ platforms: SelectOptionInterface[];
+ globalCustomerId: string;
+
+
+ constructor(){
+ this.lcpRegions = [];
+ this.lcpRegionsTenantsMap = {};
+ this.tenants = [];
+ this.productFamilies = [];
+ this.lineOfBusinesses = [];
+ this.platforms = [];
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts
new file mode 100644
index 000000000..7dbe9b11b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts
@@ -0,0 +1,55 @@
+import {Injectable} from "@angular/core";
+import {ServiceNodeTypeToModelKeyMapper} from "../../shared/models/serviceNodeTypeToModelKeyMapper";
+import {ServiceNodeTypes} from "../../shared/models/ServiceNodeTypes";
+import {VfModule} from "../../shared/models/vfModule";
+import {ServicePlanningService} from "../../services/service-planning.service";
+import {VNFModel} from "../../shared/models/vnfModel";
+import * as _ from 'lodash';
+import {isNullOrUndefined} from "util";
+import {NumbersLettersUnderscoreValidator} from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {FormGroup} from '@angular/forms';
+import {VnfInstanceDetailsComponent} from './vnf-instance-details/vnf-instance-details.component';
+import {VnfInstanceDetailsService} from './vnf-instance-details/vnf-instance-details.service';
+
+@Injectable()
+export class VnfPopupService {
+
+ constructor(private _servicePlanningService : ServicePlanningService, private _vnfInstanceDetailsService : VnfInstanceDetailsService) {
+ }
+
+ public getModelFromResponse(result : any, modelType : string, modelName:string) {
+ let model = null;
+ let rawModel = _.get(result, [ServiceNodeTypeToModelKeyMapper[modelType], modelName]);
+ if (!rawModel) return;
+
+ if (modelType === ServiceNodeTypes.VFmodule) {
+ model = new VfModule(rawModel);
+ }
+ else {
+ model = new VNFModel(rawModel);
+ }
+ return model;
+ }
+
+ onControlError(servicePopupDataModel : VnfInstanceDetailsComponent, serviceInstanceDetailsFormGroup : FormGroup, isNotUniqueInstanceName : boolean, isNotUniqueVolumeGroupName : boolean) : boolean{
+ if(this._vnfInstanceDetailsService.hasUniqueError(isNotUniqueInstanceName) || isNotUniqueVolumeGroupName){
+ return true;
+ }
+ if(!isNullOrUndefined(serviceInstanceDetailsFormGroup.controls['instanceName']) && NumbersLettersUnderscoreValidator.valid(serviceInstanceDetailsFormGroup.controls['instanceName'].value) && serviceInstanceDetailsFormGroup.controls['instanceName'].value != null && serviceInstanceDetailsFormGroup.controls['instanceName'].value.length > 0){
+ return true;
+ }
+
+ const controlName : Array<string> = ['lcpCloudRegionId', 'tenantId', 'lineOfBusiness', 'platformName'];
+ const selectDataName : Array<string> = ['lcpRegions', 'tenants', 'lineOfBusinesses', 'platforms', 'projects'];
+
+ for(let i = 0 ; i < controlName.length ; i++){
+ if (!isNullOrUndefined(servicePopupDataModel.vnfPopupDataModel) && !isNullOrUndefined(servicePopupDataModel.vnfPopupDataModel[selectDataName[i]])) {
+ if (!isNullOrUndefined(serviceInstanceDetailsFormGroup.controls[controlName[i]]) && !serviceInstanceDetailsFormGroup.controls[controlName[i]].disabled && servicePopupDataModel.vnfPopupDataModel[selectDataName[i]].length === 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts
new file mode 100644
index 000000000..26e667d4c
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts
@@ -0,0 +1,190 @@
+import {Component, OnInit, ViewChild} from "@angular/core";
+import {AaiService} from "../../services/aaiService/aai.service";
+import {ModelInformationItem} from "../../shared/components/model-information/model-information.component";
+import {ActivatedRoute} from "@angular/router";
+import {DialogComponent, DialogService} from "ng2-bootstrap-modal";
+import {InstancePopup} from "../instance-popup/instance-popup.components";
+import {ServiceModel} from "../../shared/models/serviceModel";
+import {Constants} from "../../shared/utils/constants";
+import * as _ from "lodash";
+import {VnfInstance} from "../../shared/models/vnfInstance";
+import {ServiceInstance} from "../../shared/models/serviceInstance";
+import {VnfInstanceDetailsComponent} from "./vnf-instance-details/vnf-instance-details.component";
+import {Subscriber} from "../../shared/models/subscriber";
+import {ServiceNodeTypes} from "../../shared/models/ServiceNodeTypes";
+import {AppState} from "../../store/reducers";
+import {NgRedux} from "@angular-redux/store";
+import {VfModuleInstance} from "../../shared/models/vfModuleInstance";
+import {VnfPopupService} from './vnf-popup-service';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+export interface VnfPopupModel {
+ serviceModelId: string;
+ modelName: string;
+ parentModelName: string;
+ modelType: string;
+ dynamicInputs: any;
+ userProvidedNaming: boolean;
+ isNewVfModule : boolean;
+}
+
+@Component({
+ selector: 'vnf-popup',
+ templateUrl: 'vnf-popup.html',
+ styleUrls: ['vnf-popup.scss'],
+ providers: [AaiService, VnfPopupService]
+})
+
+export class VnfPopupComponent extends DialogComponent<VnfPopupModel, boolean> implements VnfPopupModel, InstancePopup, OnInit {
+
+ @ViewChild(VnfInstanceDetailsComponent) vnfInstanceDetails: VnfInstanceDetailsComponent;
+
+ serviceModelId: string;
+ modelName: string;
+ parentModelName: string;
+ modelType: string;
+ isNewVfModule : boolean;
+ model: any;
+ serviceModel: ServiceModel;
+ popupTypeName: string;
+ serviceInstance: ServiceInstance;
+ vnfInstance: VnfInstance;
+ dynamicInputs;
+ userProvidedNaming: boolean;
+ typeMapperForTitle = {
+ VF: "VNF",
+ VFmodule: "Module (Heat stack)"
+ };
+
+ modelInformationItems: Array<ModelInformationItem> = [];
+ isNotUniqueInstanceName : boolean = false;
+ isNotUniqueVolumeGroupName : boolean = false;
+ hasGeneralApiError : boolean = false;
+
+ parentElementClassName = 'content';
+
+ constructor(dialogService: DialogService, protected route: ActivatedRoute, protected _aaiService: AaiService,
+ private store: NgRedux<AppState>,
+ private _iframeService : IframeService,
+ private _vnfPopupService: VnfPopupService) {
+ super(dialogService);
+ this.vnfInstance = new VnfInstance();
+ }
+
+ updateGeneralErrorSection() : void {
+ this.hasGeneralApiError = this._vnfPopupService.onControlError(
+ this.vnfInstanceDetails,
+ this.vnfInstanceDetails.instanceFormGroup,
+ this.vnfInstanceDetails.isNotUniqueInstanceName,
+ this.vnfInstanceDetails.isNotUniqueVolumeGroupName);
+ }
+
+ ngOnInit(): void {
+ this.updateServiceModelById();
+ this.popupTypeName = this.getModelTypeForPopupTitle();
+ this.updateServiceModelById();
+ this.updateInstanceFromStore();
+ }
+
+ onCancelClick() {
+ this._iframeService.removeClassCloseModal(this.parentElementClassName);
+ super.close();
+ }
+
+ onServiceInstanceNameChanged(isNotUniqueInstanceName: boolean) : void {
+ this.isNotUniqueInstanceName = isNotUniqueInstanceName;
+ }
+
+ onVolumeGroupNameChanged(isNotUniqueVolumeGroupName: boolean) : void {
+ this.isNotUniqueVolumeGroupName = isNotUniqueVolumeGroupName;
+ }
+
+ onSetClick() {
+ this._iframeService.removeClassCloseModal(this.parentElementClassName);
+ this.result = true;
+ super.close();
+ }
+
+ updateServiceModelById() {
+ this._aaiService.getServiceModelById(this.serviceModelId).subscribe(
+ result => {
+ this.serviceModel = new ServiceModel(result);
+ this.model = this._vnfPopupService.getModelFromResponse(result, this.modelType, this.modelName);
+ this.modelInformationItems = this.createModelInformationItems();
+ },
+ error => {
+ console.log('error is ', error)
+ }
+ );
+ }
+
+ updateInstanceFromStore() {
+ let instance;
+ const serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+ if (this.modelType === ServiceNodeTypes.VF) {
+ instance = serviceInstance.vnfs[this.modelName] || new VnfInstance();
+ } else {
+ instance = new VfModuleInstance();
+ }
+
+ if (instance.instanceParams && instance.instanceParams[0]) {
+ this.dynamicInputs = this.dynamicInputs.map(x => {
+ x.value = (instance.instanceParams[0][x.id]) ? instance.instanceParams[0][x.id] : x.value;
+ return x;
+ });
+ }
+ this.vnfInstance = instance;
+ }
+
+ getModelName(): string {
+ return this.modelName;
+ }
+
+ getModelTypeForPopupTitle(): string {
+ if (_.has(this.typeMapperForTitle, this.modelType)) {
+ return this.typeMapperForTitle[this.modelType];
+ }
+ return this.modelType;
+ }
+
+ extractSubscriberNameBySubscriberId(subsriberId: string) {
+ var result: string = null;
+ var filteredArray: any = _.filter(this.store.getState().service.subscribers, function (o: Subscriber) {
+ return o.id === subsriberId
+ })
+ if (filteredArray.length > 0) {
+ result = filteredArray[0].name;
+ }
+ return result;
+ }
+
+ createModelInformationItems(): Array<ModelInformationItem> {
+ var serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+
+ let items = [
+ new ModelInformationItem("Subscriber Name", "subscriberName", [this.extractSubscriberNameBySubscriberId(serviceInstance.globalSubscriberId)], "", true),
+ new ModelInformationItem("Service Name", "serviceModelName", [this.serviceModel.name], "", true),
+
+ new ModelInformationItem("Service Instance Name", "serviceName", [serviceInstance.instanceName], "", false),
+ new ModelInformationItem("Model Name", "modelName", [this.model.name], "", true),
+ new ModelInformationItem("Model version", "modelVersion", [this.model.version], "", true),
+ new ModelInformationItem("Description", "description", [this.model.description]),
+ new ModelInformationItem("Category", "category", [this.model.category]),
+ new ModelInformationItem("Sub Category", "subCategory",[this.model.subCategory]),
+ new ModelInformationItem("UUID", "uuid", [this.model.uuid], Constants.ServicePopup.TOOLTIP_UUID, true),
+ new ModelInformationItem("Invariant UUID", "invariantUuid", [this.model.invariantUuid], Constants.ServicePopup.TOOLTIP_INVARIANT_UUID, true),
+ new ModelInformationItem("Service type", "serviceType", [this.serviceModel.serviceType]),
+ new ModelInformationItem("Service role", "serviceRole", [this.serviceModel.serviceRole]),
+
+
+ ];
+ if (this.modelType === 'VFmodule') {
+ items.push(new ModelInformationItem("Minimum to instantiate", "min", [this.model.min], "", true),
+ new ModelInformationItem("Maximum to instantiate", "max", this.model.max == undefined ? [1] : [this.model.max], "", true),
+ new ModelInformationItem("Recommended to instantiate", "initial", [this.model.initial]));
+
+ }
+
+ return items;
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html
new file mode 100644
index 000000000..d2e043b18
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html
@@ -0,0 +1,54 @@
+<div id="instance-popup" class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" (click)="onCancelClick()" >&times;</button>
+ <span [attr.data-tests-id]="'create-modal-title'" class="modal-title">Set a new {{popupTypeName}}</span>
+ </div>
+ <div class="modal-body popup-content">
+
+ <div class="header-left">
+ <div>MODEL: <span>"{{popupTypeName}}"</span></div>
+ </div>
+
+ <div class="header-right">
+ {{getModelTypeForPopupTitle()}} Instance Details
+ </div>
+
+ <div class="model-information">
+ <model-information [modelInformationItems]="modelInformationItems"></model-information>
+ </div>
+
+ <div class="instance-form">
+ <vnf-instance-details [dynamicInputs]="dynamicInputs"
+ [vnfModel]="model"
+ [modelType]="modelType"
+ [modelName]="modelName"
+ [parentModelName]="parentModelName"
+ [isNewVfModule]="isNewVfModule"
+ [serviceInstance]="vnfInstance"
+ [vnfInstance]="vnfInstance"
+ [serviceUuid]="serviceModelId"
+ [userProvidedNaming]="userProvidedNaming"
+ (onSubmitClick)="onSetClick($event)"
+ (onDataChanged)="updateGeneralErrorSection()"
+ (onServiceInstanceNameChanged)="onServiceInstanceNameChanged($event)"
+ (onVolumeGroupNameChanged)="onVolumeGroupNameChanged($event)"
+
+ ></vnf-instance-details>
+ </div>
+
+ </div>
+ <div class="modal-footer row" style="padding: 0">
+ <div class="col-md-6">
+ <div *ngIf="hasGeneralApiError == true">
+ <form-general-error [message]="'Page contains errors. Please see details next to the relevant fields.'"></form-general-error>
+ </div>
+ </div>
+ <div class="col-md-6" style="padding: 15px;padding-right: 35px;">
+ <button [attr.data-tests-id]="'cancelButton'" type="button" class="btn btn-default cancel" (click)="onCancelClick()"><span>Cancel</span></button>
+ <input type="submit" value="Set" form="vnfForm" data-tests-id="vnf-form-set"
+ class="btn btn-success submit" [disabled]="!vnfInstanceDetails?.vnfForm?.valid || isNotUniqueInstanceName || isNotUniqueVolumeGroupName">
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss
new file mode 100644
index 000000000..6e606dbb9
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss
@@ -0,0 +1,185 @@
+$grid-border: 1px #d2d2d2 solid;
+
+#instance-popup {
+ color: #191919;
+
+ .left-panel {
+ background: #f2f2f2;
+ border-right: $grid-border;
+ }
+
+ .header-common {
+ height: 100%;
+ align-items: center;
+ display: flex;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ .header-text {
+ padding-left: 30px;
+ @extend .header-common;
+ }
+
+ .header-left {
+ grid-area: header-left;
+ @extend .header-text;
+ @extend .left-panel;
+ border-bottom: $grid-border;
+
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ };
+ }
+
+ .header-right {
+ grid-area: header-right;
+
+ @extend .header-text;
+ border-bottom: $grid-border;
+ }
+
+ .quantity-label {
+ grid-area: quantity-label;
+ @extend .header-common;
+ border-bottom: $grid-border;
+ height: 100%;
+ font-family: OpenSans-Regular;
+ }
+
+ .quantity {
+ grid-area: quantity;
+ border-left: $grid-border;
+ border-bottom: $grid-border;
+ border-top-style: none;
+ font-family: OpenSans-Semibold;
+ text-align: start;
+ text-indent: 10px;
+ }
+
+ .quantity-select {
+ width: 78px;
+ height: 100%;
+ border: 0;
+ background: white;
+ outline: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: url('../../../assets/img/chevron.svg') 0 0 no-repeat;
+ background-size: 24px;
+ background-position-x: right;
+ background-position-y: center;
+ }
+ input[type="number"]:hover::-webkit-inner-spin-button {
+ height: 20px;
+ }
+
+ .model-information {
+ grid-area: model-information;
+
+ padding: 30px;
+ overflow: auto;
+ @extend .left-panel;
+ }
+
+ .instance-form {
+ grid-area: instance-form;
+ }
+
+ .popup-content {
+ display: grid;
+ grid-template-columns: 400px auto 30px 93px;
+ grid-template-rows: 50px calc(100vh - 180px);
+ grid-template-areas:
+ "header-left header-right header-right header-right"
+ "model-information instance-form instance-form instance-form";
+ padding: 0;
+ }
+}
+
+.modal {
+ background-color: #191919;
+ opacity: 0.8;
+}
+
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 0;
+}
+@media (min-width: 1150px) {
+ .popup-content {
+ grid-template-rows: 30px 680px;
+ }
+}
+
+.modal-content {
+ border-radius: 0;
+ box-shadow: none;
+ border: none;
+}
+
+.modal-footer {
+ .cancel {
+ width: 120px;
+ height: 36px;
+ background: #ffffff;
+ border: 1px solid #009fdb;
+ border-radius: 2px;
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #009fdb;
+ line-height: 16px;
+ }
+ }
+
+ .submit {
+ width: 120px;
+ height: 36px;
+ background: #009fdb;
+ border-radius: 2px;
+ border-color: #009fdb;
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #FFFFFF;
+ line-height: 16px;
+ }
+ }
+}
+
+.modal-header {
+ background-color: #009fdb;
+
+ padding-bottom: 13px;
+ padding-top: 13px;
+ padding-left: 29px;
+ padding-right: 21px;
+
+ .close {
+ font-size: 32px;
+ font-weight: 200;
+ color: #d8d8d8;
+ text-shadow: none;
+ filter: none;
+ opacity: 1;
+ }
+
+ .modal-title {
+ font-family: OpenSans-Regular;
+ font-size: 24px;
+ color: #fff;
+ line-height: 34px;
+ }
+}
+//
+//@media (min-width: 1200px) {
+// .service-model,
+// .service-instance {
+// width: 1050px;
+// margin: 30px auto;
+// }
+//}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts
new file mode 100644
index 000000000..02296f728
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts
@@ -0,0 +1,827 @@
+import {VnfPopupService} from './vnf-popup-service';
+import {ServicePlanningService} from '../../services/service-planning.service';
+import {ServiceNodeTypes} from '../../shared/models/ServiceNodeTypes';
+import {NgRedux} from '@angular-redux/store';
+import {VNFModel} from '../../shared/models/vnfModel';
+import {VfModule} from '../../shared/models/vfModule';
+import {FormControl, FormGroup, Validators} from '@angular/forms';
+import {NumbersLettersUnderscoreValidator} from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {VnfInstanceDetailsService} from './vnf-instance-details/vnf-instance-details.service';
+import {ReflectiveInjector} from '@angular/core';
+
+export class MockAppStore<T> {
+}
+
+describe('Vnf popup service', () => {
+ let injector;
+ let service: VnfPopupService;
+ let fg: FormGroup;
+ let data = generateModelData();
+ let servicePopupDataModel = generateServicePopupDataModel();
+ let form: FormGroup = generateFormGroup();
+ beforeEach(() => {
+
+ let injector = ReflectiveInjector.resolveAndCreate([
+ VnfPopupService,
+ ServicePlanningService,
+ VnfInstanceDetailsService,
+ {provide: FormGroup, useClass: MockAppStore},
+ {provide: NgRedux, useClass: MockAppStore}
+ ]);
+
+ service = injector.get(VnfPopupService);
+ fg = injector.get(FormGroup);
+ });
+
+ describe('#updateVnfDataFromModel', () => {
+ it('update vnf data from model should return new vnf', (done: DoneFn) => {
+ let vnf: VNFModel = service.getModelFromResponse(data, ServiceNodeTypes.VF, '2017-388_ADIOD-vPE 1');
+
+ expect(vnf).toEqual(jasmine.any(VNFModel));
+ done();
+ });
+
+ it('update wrong vnf data from model should be undefined', (done: DoneFn) => {
+ let vnf: VNFModel = service.getModelFromResponse(data, ServiceNodeTypes.VF, '2017-388_ADIOD-vPE 3');
+
+ expect(vnf).toBeUndefined();
+ done();
+ });
+
+ it('update vfModule data from model should return new vfModule', (done: DoneFn) => {
+ let vfModule: VfModule = service.getModelFromResponse(data, ServiceNodeTypes.VFmodule, '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1');
+
+ expect(vfModule).toEqual(jasmine.any(VfModule));
+ done();
+ });
+
+ });
+
+
+ describe('#onControlError', () => {
+ it('onControlError should return true if instanceName is not legal', (done: DoneFn) => {
+ form.controls['instanceName'].setValue('aaaa - aaa');
+
+ let result: boolean = service.onControlError(<any>servicePopupDataModel, form, false, false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('onControlError should return false if instanceName is legal', (done: DoneFn) => {
+
+ form.controls['instanceName'].setValue('aaaa');
+ let result = service.onControlError(<any>servicePopupDataModel, form, false, false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('onControlError should return true if instanceName is not unique', (done: DoneFn) => {
+
+ form.controls['instanceName'].setValue('aaaa');
+ let result = service.onControlError(<any>servicePopupDataModel, form, true, false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('onControlError should return true if lcpRegions is empty', (done: DoneFn) => {
+ servicePopupDataModel.vnfPopupDataModel['lcpRegions'] = [];
+ let result = service.onControlError(<any>servicePopupDataModel, form, true, false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('onControlError should return true if isNotUniqueVolumeGroupName is true', (done: DoneFn) => {
+ let result = service.onControlError(<any>servicePopupDataModel, form, true, true);
+ expect(result).toBeTruthy();
+ done();
+ })
+ });
+
+
+ function generateServicePopupDataModel() {
+ return {
+ 'vnfPopupDataModel': JSON.parse('{"tenants" : [1,2,3],"lcpRegions":[1,2,3],"lcpRegionsTenantsMap":{},"productFamilies":[1,2,3],"lineOfBusinesses":[{"id":"ECOMP","name":"ECOMP"},{"id":"zzz1","name":"zzz1"}],"platforms":[{"id":"platform","name":"platform"},{"id":"xxx1","name":"xxx1"}],"rollbackOnFailure":[{"id":"true","name":"Rollback"}]}')
+ }
+ }
+
+ function generateFormGroup() {
+ return new FormGroup({
+ productFamilyId: new FormControl(),
+ lcpCloudRegionId: new FormControl(Validators.required),
+ tenantId: new FormControl({value: null, disabled: false}, Validators.required),
+ legacyRegion: new FormControl(),
+ lineOfBusiness: new FormControl(),
+ platformName: new FormControl(Validators.required),
+ instanceName: new FormControl({value: null}, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid]))
+ });
+ }
+
+ function generateModelData() {
+ return JSON.parse(JSON.stringify(
+ {
+ 'service': {
+ 'uuid': '2f80c596-27e5-4ca9-b5bb-e03a7fd4c0fd',
+ 'invariantUuid': 'e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0',
+ 'name': 'action-data',
+ 'version': '1.0',
+ 'toscaModelURL': null,
+ 'category': '',
+ 'serviceType': '',
+ 'serviceRole': '',
+ 'description': '',
+ 'serviceEcompNaming': 'true',
+ 'instantiationType': 'ClientConfig',
+ 'inputs': {
+ '2017488_adiodvpe0_ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'adiodvpe0_bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ '2017488_adiodvpe0_vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ },
+ '2017488_adiodvpe0_vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ '2017488_adiodvpe0_AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'adiodvpe0_bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ }
+ }
+ },
+ 'vnfs': {
+ '2017-388_ADIOD-vPE 1': {
+ 'uuid': '0903e1c0-8e03-4936-b5c2-260653b96413',
+ 'invariantUuid': '00beb8f9-6d39-452f-816d-c709b9cbb87d',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017-388_ADIOD-vPE',
+ 'version': '1.0',
+ 'customizationUuid': '280dec31-f16d-488b-9668-4aae55d6648a',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017-388_ADIOD-vPE 1',
+ 'vfModules': {},
+ 'volumeGroups': {}
+ },
+ '2017-388_ADIOD-vPE 0': {
+ 'uuid': 'afacccf6-397d-45d6-b5ae-94c39734b168',
+ 'invariantUuid': '72e465fe-71b1-4e7b-b5ed-9496118ff7a8',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017-388_ADIOD-vPE',
+ 'version': '4.0',
+ 'customizationUuid': 'b3c76f73-eeb5-4fb6-9d31-72a889f1811c',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017-388_ADIOD-vPE 0',
+ 'vfModules': {},
+ 'volumeGroups': {}
+ },
+ '2017488_ADIODvPE 0': {
+ 'uuid': '69e09f68-8b63-4cc9-b9ff-860960b5db09',
+ 'invariantUuid': '72e465fe-71b1-4e7b-b5ed-9496118ff7a8',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017488_ADIODvPE',
+ 'version': '5.0',
+ 'customizationUuid': '1da7b585-5e61-4993-b95e-8e6606c81e45',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017488_ADIODvPE 0',
+ 'vfModules': {
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1': {
+ 'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+ 'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+ 'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true,
+ 'inputs': {
+ '2017488_adiodvpe0_vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ '2017488_adiodvpe0_AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ }
+ }
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_base_vPE_BV..module-0': {
+ 'uuid': 'f8360508-3f17-4414-a2ed-6bc71161e8db',
+ 'invariantUuid': 'b34833bb-6aa9-4ad6-a831-70b06367a091',
+ 'customizationUuid': 'a55961b2-2065-4ab0-a5b7-2fcee1c227e3',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+ 'version': '5',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+ 'commands': {},
+ 'volumeGroupAllowed': false,
+ 'inputs': {
+ '2017488_adiodvpe0_ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'adiodvpe0_bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ }
+ }
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2': {
+ 'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+ 'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+ 'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true,
+ 'inputs': {}
+ }
+ },
+ 'volumeGroups': {
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1': {
+ 'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+ 'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+ 'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0}
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2': {
+ 'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+ 'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+ 'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0}
+ }
+ }
+ }
+ },
+ 'vfModules': {
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1': {
+ 'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+ 'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+ 'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_base_vPE_BV..module-0': {
+ 'uuid': 'f8360508-3f17-4414-a2ed-6bc71161e8db',
+ 'invariantUuid': 'b34833bb-6aa9-4ad6-a831-70b06367a091',
+ 'customizationUuid': 'a55961b2-2065-4ab0-a5b7-2fcee1c227e3',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+ 'version': '5',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2': {
+ 'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+ 'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+ 'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true
+ }
+ },
+ 'networks': {},
+ 'collectionResource': {},
+ 'configurations': {},
+ 'serviceProxies': {},
+ 'pnfs': {}
+ }
+ ))
+ }
+
+});
diff --git a/vid-webpack-master/src/app/configuration/vid.configuration.ts b/vid-webpack-master/src/app/configuration/vid.configuration.ts
new file mode 100644
index 000000000..2430d3ba5
--- /dev/null
+++ b/vid-webpack-master/src/app/configuration/vid.configuration.ts
@@ -0,0 +1,98 @@
+export class VidConfiguration {
+
+ public static VNF_STATUS_CHECK_ENABLED = false;
+
+ /*
+ * UPLOAD_SUPPLEMENTARY_STATUS_CHECK_ENABLED: Determines the Property to Govern Presence of
+ * Upload Supplementary File on Volume Group Screen.
+ * Set to false, to disable the check.
+ */
+ public static UPLOAD_SUPPLEMENTARY_STATUS_CHECK_ENABLED = false;
+
+ /*
+ * List of valid VNF status combinations
+ */
+ public static VNF_VALID_STATUS_LIST = [
+ {
+ 'provStatus': 'preprov',
+ 'orchestrationStatus': 'pending-create',
+ 'inMaint': false,
+ 'operationalStatus': null
+ },
+ {
+ 'provStatus': 'preprov',
+ 'orchestrationStatus': 'created',
+ 'inMaint': false,
+ 'operationalStatus': null
+ },
+ {
+ 'provStatus': 'preprov',
+ 'orchestrationStatus': 'active',
+ 'inMaint': false,
+ 'operationalStatus': null
+ },
+ {
+ 'provStatus': 'nvtprov',
+ 'orchestrationStatus': 'active',
+ 'inMaint': false,
+ 'operationalStatus': null
+ },
+ {
+ 'provStatus': 'prov',
+ 'orchestrationStatus': 'active',
+ 'inMaint': false,
+ 'operationalStatus': 'out-of-service-path'
+ },
+ {
+ 'provStatus': 'prov',
+ 'orchestrationStatus': 'activated',
+ 'inMaint': false,
+ 'operationalStatus': 'out-of-service-path'
+ }
+ ];
+
+ /*
+ * The model status VID uses to query SDC for a list of models. The possible values are:
+ * DISTRIBUTION_NOT_APPROVED,
+ * DISTRIBUTION_APPROVED,
+ * DISTRIBUTED,
+ * DISTRIBUTION_REJECTED,
+ * ALL,
+ * In the production env, this should always be set to DISTRIBUTED
+ */
+ public static ASDC_MODEL_STATUS = 'DISTRIBUTED';
+
+ /*
+ * Max number of times that VID will poll MSO for a given request status
+ */
+ public static MSO_MAX_POLLS = 10;
+
+ /*
+ * Number of msecs that VID will wait between MSO polls.
+ */
+ public static MSO_POLLING_INTERVAL_MSECS = 10000;
+
+ public static SCHEDULER_POLLING_INTERVAL_MSECS = 10000;
+
+ public static SCHEDULER_MAX_POLLS = 10;
+
+ public static COMPONENT_LIST_NAMED_QUERY_ID = '0367193e-c785-4d5f-9cb8-7bc89dc9ddb7';
+
+ /*
+ * List of all service model invariant UUIDs that need macro instantiation.
+ * Example:
+ * MACRO_SERVICES : ['3cf30cbb-5fe7-4fb3-b049-559a4997b221', 'b135a703-bab5-4295-a37f-580a4f2d0961']
+ *
+ */
+ public static MACRO_SERVICES = ['c9514b73-3dfe-4d7e-9146-b318d48655d9', '93150ffa-00c6-4ea0-85f2-3536ca46ebd2',
+ '2b54297f-72e7-4a94-b451-72df88d0be0b',
+ 'd27e42cf-087e-4d31-88ac-6c4b7585f800',
+ 'ec0c4bab-c272-4dab-b087-875031bb0c9f', '0311f998-9268-4fd6-bbba-afff15087b72',
+ '43596836-ae36-4608-a987-6608ede10dac', '306caa85-74c7-48a9-aa22-7e3a564b957a',
+ 'e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0'];
+
+ public static SCHEDULER_CALLBACK_URL = 'https://vid-web-ete.ecomp.cci.att.com:8000/vid/change-management/workflow/';
+
+ public static SCHEDULER_PORTAL_URL = 'http://www.ecomp.att.com';
+
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.html b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.html
new file mode 100644
index 000000000..5eb977325
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.html
@@ -0,0 +1,35 @@
+<div class="available-models-tree">
+ <h5>
+ <span>SERVICE MODEL:</span>
+ <span id="service-model-name">{{service | serviceInfo: _store: serviceModelId : 'name'}}</span>
+ </h5>
+ <div class="available-models-content-wrapper">
+ <div class="search-container">
+ <input [attr.data-tests-id]="'search-left-tree'" #filter (keyup)="searchTree(filter.value, $event)" placeholder="Filter..."/>
+ <span class="icon-search"></span>
+ </div>
+
+ <tree-root #tree [attr.data-tests-id]="'available-models-tree'" [nodes]="nodes" [options]="options">
+ <ng-template #treeNodeTemplate let-node let-index="index">
+ <div [attr.data-tests-id]="'node-'+node.data.name" (click)="selectNode(node)" [ngClass]="{'selected': index , 'isParent': node.data.type !== 'VFmodule' , 'isChild': node.data.type === 'VFmodule' }">
+ <span class="vf-type">{{node.data.type.substring(0,1)}}</span>
+ <span class="span-name" [innerHTML]=" isFilterEnabled ? (node.data.name | highlight : filter.value) : (node.data.name)"></span>
+ <span class="actions">
+ <span class="number-button" *ngIf="isShowNodeCount(node)">
+ <span>{{getNodeCount(node)}}</span>
+ </span>
+ <span class="icon-v" *ngIf="isShowIconV(node)">
+ <span ></span>
+ </span>
+ <span class="icon-plus" *ngIf="isShowIconAdd(node)">
+ <span tooltip="Add" [attr.data-tests-id]="'node-'+node.data.name+'-add-btn'" (click)="onClickAdd($event,node)">
+ <i class="fa fa-plus-circle" aria-hidden="true"></i>
+ </span>
+ </span>
+ </span>
+ </div>
+ </ng-template>
+ </tree-root>
+
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.scss b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.scss
new file mode 100644
index 000000000..44f94109a
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.scss
@@ -0,0 +1,398 @@
+available-models-tree {
+ .available-models-tree {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ line-height: 14px;
+ border-right: #D2D2D2 1.5px solid;
+ min-width: 340px;
+ h5 {
+ font-family: OpenSans-Semibold;
+ color: #5A5A5A;
+ background-color: #F2F2F2;
+ margin: 0;
+ padding: 15px;
+ padding-left: 20px;
+ span {
+ vertical-align: middle;
+ &:first-child {
+ font-size: 12px;
+ color: #191919;
+ }
+ }
+ }
+ .available-models-content-wrapper {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ padding: 20px;
+ background-color: #F2F2F2;
+ .search-container {
+ margin-bottom: 30px;
+ width: 100%;
+ display: flex;
+ background: #FFFFFF;
+ border: 1px solid #D2D2D2;
+ border-radius: 2px;
+ height: 40px;
+ min-width: 40px;
+ font-family: OpenSans-Italic;
+ color: #959595;
+ input {
+ flex: 1;
+ border: 0;
+ padding-left: 10px;
+ outline: 0;
+ }
+ .icon-search {
+ display: flex;
+ width: 40px;
+ &:after {
+ content: "\e92e";
+ cursor: pointer;
+ font-size: 20px;
+ font-weight: 600;
+ text-align: center;
+ display: inline-block;
+ flex: auto;
+ align-self: center;
+ }
+ }
+ }
+ tree-root {
+ flex: 1;
+ display: flex;
+ }
+ tree-viewport {
+ flex: 1;
+ height: auto;
+ overflow: auto;
+ padding-top: 5px;
+ .tree-node {
+ color: #5A5A5A;
+ font-size: 13px;
+ white-space: normal;
+ word-break: break-all;
+ tree-node-drop-slot {
+ .node-drop-slot {
+ display: none;
+ }
+ }
+ &.tree-node-disabled {
+ color: #D2D2D2;
+ cursor: default;
+ pointer-events: none;
+ }
+ &:not(.tree-node-disabled) {
+ >tree-node-wrapper {
+ .node-wrapper:hover {
+ color: #009FDB;
+ .node-content-wrapper {
+ tree-node-content {
+ > div {
+ span.actions {
+ .number-button {
+ span {
+ //background-color: #009FDB;
+ }
+ }
+ .icon-plus span:before {
+ display: inline-block;
+ color: #5A5A5A;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ &.tree-node-focused:not(.tree-node-disabled) {
+ & > tree-node-wrapper {
+ .node-wrapper {
+ color: #009FDB;
+ .node-content-wrapper-focused,
+ .node-content-wrapper:hover {
+ background: none;
+ box-shadow: none;
+ tree-node-content {
+ > div {
+ span.actions {
+ .number-button {
+ span {
+ //background-color: #009FDB;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ tree-node-wrapper {
+ .node-wrapper {
+ height: 36px;
+ tree-node-expander {
+ font-family: 'icomoon' !important;
+ height: 100%;
+ .toggle-children-wrapper {
+ padding: 0;
+ display: block;
+ height: 100%;
+ span.toggle-children {
+ display: flex;
+ width: 20px;
+ top: 0;
+ height: inherit;
+ background-image: none;
+ &:before {
+ content: "\e900";
+ font-weight: 600;
+ text-align: center;
+ display: inline-block;
+ flex: auto;
+ align-self: center;
+ font-size: 20px;
+ }
+ }
+ }
+ .toggle-children-wrapper-expanded {
+ span.toggle-children {
+ transform: none;
+ &:before {
+ content: "\e930";
+ }
+ }
+ }
+ .toggle-children-placeholder {
+ width: 20px;
+ }
+ }
+ .node-content-wrapper {
+ padding: 0;
+ background: none;
+ box-shadow: none;
+ height: 100%;
+ flex: 1;
+ min-width: 0;
+ border-left: 1px solid #D2D2D2;
+ tree-node-content {
+ > div {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding-left: 10px;
+ span {
+ &.actions {
+ height: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ >span {
+ width: 45px;
+ max-width: 45px;
+ text-align: center;
+ }
+ .number-button {
+ width: 30px;
+ padding-left: 0;
+ text-align: center;
+ span {
+ display: block;
+ font-size: 11px;
+ }
+ }
+ .icon-v {
+ width: 45px;
+ span:before {
+ content: "\e932";
+ color: #5A5A5A;
+ font-size: 16px;
+ text-align: center;
+ display: inline-block;
+ vertical-align: baseline;
+ }
+ }
+ .icon-plus {
+ width: 45px;
+ span {
+ &:before {
+ //content: "\e901";
+ //fill:#009FDB;
+ //color: #009FDB;
+ //font-size: 16px;
+ //text-align: center;
+ //display: none;
+ //vertical-align: baseline;
+ }
+ &:hover:before {
+ //color: #009FDB !important;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+ tree-node-children {
+ .tree-children {
+ padding-left: 20px;
+ }
+ }
+ }
+ }
+
+ }
+ }
+}
+.highlight {
+ background-color: #9DD9EF;
+}
+
+#drawing-board-tree{
+ .tree-node.tree-node-expanded.tree-node-focused {
+ border: 1px solid #009FDB;
+ }
+
+}
+
+available-models-tree {
+
+ .tree-root {
+ margin-top: 35px;
+ }
+
+ tree-node-expander {
+ background: #FFFFFF;
+ border: 1px solid #D2D2D2;
+ border-right: none;
+ width: 45px;
+ padding-left: 12px;
+ }
+
+ .node-content-wrapper {
+ border: none;
+ }
+
+ tree-node-wrapper tree-node-expander{
+ background: none !important;
+ border: none !important;
+ }
+
+ tree-node-content div {
+ background: white;
+ }
+
+ .node-wrapper {
+ height: 45px !important;
+ background: #FFFFFF;
+ border: 1px solid #D2D2D2;
+ }
+
+ tree-node-collection div {
+ margin-top: 0px;
+ }
+
+ .tree-node-leaf .node-wrapper tree-node-expander {
+ display: none;
+ }
+
+ .tree-children {
+ padding: 20px;
+ }
+
+ .tree-node.tree-node-expanded.tree-node-focused {
+ border: 1px solid #009FDB;
+ }
+
+ .tree-node.tree-node-expanded {
+ border: 1px solid rgba(128, 128, 128, 0.72);
+ margin-bottom: 10px;
+ }
+
+ .tree-children {
+ padding-left: 0;
+ }
+
+ tree-node-content .actions .number-button {
+ height: 45px;
+ padding-top: 14px;
+ border: 1px solid #D2D2D2;
+ padding-left: 0;
+ span {
+ background: none;
+ font-size: 11px;
+ color: #5A5A5A;
+ }
+ }
+
+
+
+ .node-content-wrapper.node-content-wrapper-focused tree-node-content div{
+ background: #009FDB !important;
+ color: white;
+
+ .isParent {
+ border-left: 1px solid #009FDB;
+ }
+
+ .number-button span{
+ color: white !important;
+ }
+
+ .icon-v span:before{
+ color: white !important;
+ }
+ }
+
+ .vf-type {
+ width: 20px;
+ height: 45px;
+ padding-top: 16px;
+ border-right: 1px solid #D2D2D2;
+
+ }
+
+ .isParent {
+ width: 100%;
+ padding-left: 5px;
+ }
+
+ .tree-node-expanded .isChild .vf-type {
+ display: none;
+ }
+
+ .isParent .span-name {
+ width: 100%;
+ padding-left: 10px;
+ }
+
+ .toggle-children-wrapper.toggle-children-wrapper-expanded {
+ .toggle-children:before {
+ color: #009FDB;
+ }
+ }
+
+ .tree-node.tree-node-expanded .tree-children {
+ border: 1px solid rgba(128, 128, 128, 0.72);
+ }
+
+ .tree-node.tree-node-expanded.tree-node-focused .tree-children {
+ border: 1px solid #009fdb;
+ }
+
+ .tree-node-leaf .node-wrapper{
+ margin-left: 45px;
+ border-left: none;
+ }
+}
+
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.ts b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.ts
new file mode 100644
index 000000000..4e5819e4c
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.ts
@@ -0,0 +1,166 @@
+import {Component, EventEmitter, Output, ViewChild} from '@angular/core';
+import {ITreeOptions, TreeComponent} from 'angular-tree-component';
+import '../../../../node_modules/angular-tree-component/dist/angular-tree-component.css';
+import {IDType, ITreeNode} from 'angular-tree-component/dist/defs/api';
+import {DialogService} from 'ng2-bootstrap-modal';
+import {AvailableModelsTreeService} from './available-models-tree.service';
+import {NgRedux} from "@angular-redux/store";
+import {ActivatedRoute} from '@angular/router';
+import {AppState} from '../../store/reducers';
+import {AaiService} from '../../services/aaiService/aai.service';
+import {ServicePlanningService} from '../../services/service-planning.service';
+import {VnfPopupComponent} from '../../components/vnf-popup/vnf-popup.components';
+import {ServiceNodeTypes} from '../../shared/models/ServiceNodeTypes';
+import {VfModuleMap} from '../../shared/models/vfModulesMap';
+import {IframeService} from "../../shared/utils/iframe.service";
+import {createVFModuleInstance} from "../../service.actions";
+import {DefaultDataGeneratorService} from "../../shared/services/defaultDataServiceGenerator/default.data.generator.service";
+
+
+@Component({
+ selector: 'available-models-tree',
+ templateUrl: './available-models-tree.component.html',
+ styleUrls: ['./available-models-tree.component.scss']
+})
+
+
+export class AvailableModelsTreeComponent{
+
+ serviceModelId: string;
+ serviceHierarchy;
+ parentElementClassName = 'content';
+ _store : NgRedux<AppState>;
+ constructor(private _servicePlanningService: ServicePlanningService,
+ private _iframeService: IframeService,
+ private _aaiService: AaiService,
+ private route: ActivatedRoute,
+ private dialogService: DialogService,
+ private _availableModelsTreeService: AvailableModelsTreeService,
+ private _defaultDataGeneratorService: DefaultDataGeneratorService,
+ private store: NgRedux<AppState>) {
+ this._store = store;
+ this.route
+ .queryParams
+ .subscribe(params => {
+ this.serviceModelId = params['serviceModelId'];
+ this._aaiService.getServiceModelById(this.serviceModelId).subscribe(
+ value => {
+ this.serviceHierarchy = value;
+ this.nodes = this._servicePlanningService.convertServiceModelToTreeNodes(this.serviceHierarchy);
+ },
+ error => {
+ console.log('error is ', error)
+ }
+ );
+ });
+
+ }
+
+ @Output()
+ highlightInstances: EventEmitter<number> = new EventEmitter<number>();
+ @ViewChild('tree') tree: TreeComponent;
+
+ nodes = [];
+ service = {name: ''};
+ isFilterEnabled: boolean = false;
+
+ options: ITreeOptions = {
+ nodeHeight: 36,
+ dropSlotHeight: 0,
+ nodeClass: (node: ITreeNode) => {
+ if(node.data.type === ServiceNodeTypes.VFmodule && !this.getNodeCount(node.parent))
+ {
+ node.data.disabled = true;
+ return 'tree-node tree-node-disabled';
+ }
+ node.data.disabled = false;
+ return 'tree-node';
+ }
+ };
+
+ expandParentByNodeId(id: IDType): void {
+ this.tree.treeModel.getNodeById(id).parent.expand();
+ }
+
+ searchTree(searchText: string, event: KeyboardEvent): void {
+ if (searchText === '') {
+ return;
+ }
+ this.isFilterEnabled = event.key === 'Delete' || event.key === 'Backspace' || searchText.length > 1;
+ if (this.isFilterEnabled) {
+ let __this = this;
+ let results: ITreeNode[] = [];
+ this.nodes.forEach(function (node) {
+ __this.searchTreeNode(node, searchText, results);
+ });
+ results.forEach(function (result) {
+ __this.expandParentByNodeId(result.id)
+ });
+ }
+ }
+
+ searchTreeNode(node, searchText: string, results): void {
+ if (node.name.toLowerCase().indexOf(searchText.toLowerCase()) != -1) {
+ results.push(node);
+ }
+ if (node.children != null) {
+ for (let i = 0; i < node.children.length; i++) {
+ this.searchTreeNode(node.children[i], searchText, results);
+ }
+ }
+ }
+
+ selectNode(node: ITreeNode): void {
+ node.expand();
+ this.highlightInstances.emit(node.data.id);
+ }
+
+ onClickAdd(e: MouseEvent, node: ITreeNode): void {
+ let data = node.data;
+ let dynamicInputs = data.dynamicInputs;
+ let userProvidedNaming:boolean = data.userProvidedNaming;
+ let type:string = data.type;
+ if(!this.store.getState().global.flags['FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD']|| node.data.type === ServiceNodeTypes.VF || this._availableModelsTreeService.shouldOpenDialog(type, dynamicInputs, userProvidedNaming)) {
+ this._iframeService.addClassOpenModal(this.parentElementClassName);
+ this.dialogService.addDialog(VnfPopupComponent, {
+ serviceModelId: this.serviceModelId,
+ parentModelName: node.parent && node.parent.data.name,
+ modelName: data.name,
+ modelType: type,
+ dynamicInputs: dynamicInputs,
+ userProvidedNaming: userProvidedNaming,
+ isNewVfModule : true
+ });
+ }
+ else {
+ let vfModule = this._defaultDataGeneratorService.generateVFModule(this.serviceHierarchy, node.parent.data.name, node.data.name);
+ this.store.dispatch(createVFModuleInstance(vfModule, node.data.name, this.serviceModelId));
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ }
+
+ getNodeCount(node: ITreeNode): number {
+ let modelName: string = node.data.name;
+ if (ServicePlanningService.isVfModule(node)) {
+ let parentVnfModelName = node.parent.data.name;
+ let vfModuleMap: VfModuleMap = this._servicePlanningService.getVfModuleMap(this.serviceModelId, parentVnfModelName, modelName);
+ return vfModuleMap ? Object.keys(vfModuleMap).length : 0;
+ } else if (ServicePlanningService.isVnf(node)) {
+ let vnfInstance = this._servicePlanningService.getVnfInstance(this.serviceModelId, modelName);
+ return vnfInstance ? 1 : 0;
+ }
+ }
+
+ isShowIconV(node: ITreeNode): boolean {
+ return this.getNodeCount(node) > 0;
+ }
+
+ isShowNodeCount(node: ITreeNode): boolean {
+ return this.getNodeCount(node) > 0;
+ }
+
+ isShowIconAdd(node: ITreeNode): boolean {
+ return this._availableModelsTreeService.shouldShowAddIcon(node, this.store.getState().service.serviceHierarchy, this.serviceModelId, this.getNodeCount(node));
+ }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.spec.ts b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.spec.ts
new file mode 100644
index 000000000..10cbb0d8f
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.spec.ts
@@ -0,0 +1,450 @@
+import {TestBed, getTestBed} from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+import {AvailableModelsTreeService} from './available-models-tree.service';
+import {ServicePlanningService} from "../../services/service-planning.service";
+import {ServiceNodeTypes} from "../../shared/models/ServiceNodeTypes";
+import {NgRedux} from "@angular-redux/store";
+import {MockAppStore} from "../../services/service-planning.service.spec";
+
+describe('Available Models Tree Service', () => {
+ let injector;
+ let service: AvailableModelsTreeService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [AvailableModelsTreeService,
+ ServicePlanningService,
+ {provide: NgRedux, useClass: MockAppStore}]
+ });
+
+ injector = getTestBed();
+ service = injector.get(AvailableModelsTreeService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ describe('#shouldShowAddIcon', () => {
+ it('should return true if number of current vnf modules is under the max', (done: DoneFn) => {
+ let treeNode = {
+ data: {
+ children: [],
+ name: 'vf_vmee0..VfVmee..base_vmme..module-0'
+ }
+ };
+
+ let serviceHierarchy = getSericeServiceHierarchy();
+ let result = service.shouldShowAddIcon(treeNode, serviceHierarchy, '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 0);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('should return false if number of current vnf modules are more than max', (done: DoneFn) => {
+ let treeNode = {
+ data: {
+ children: [],
+ name: 'vf_vmee0..VfVmee..base_vmme..module-0'
+ }
+ };
+
+ let serviceHierarchy = getSericeServiceHierarchy();
+ let result = service.shouldShowAddIcon(treeNode, serviceHierarchy, '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 2);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('should return true if number of current vnf modules are more than max and max is null', (done: DoneFn) => {
+ let treeNode = {
+ data: {
+ children: [],
+ name: 'vf_vmee0..VfVmee..base_vmme..module-0'
+ }
+ };
+
+ let serviceHierarchy = getSericeServiceHierarchy();
+ let result = service.shouldShowAddIcon(treeNode, serviceHierarchy, '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 0);
+ expect(result).toBeTruthy();
+ done();
+ });
+ });
+
+ describe('#shouldOpenModalDialogOnAddInstance', () => {
+ let serviceHierarchy = getSericeServiceHierarchy();
+
+ it('should open popup on add instance', (done: DoneFn) => {
+ // add vnf should return true
+ let result = service.shouldOpenDialog(ServiceNodeTypes.VF, [], false);
+ expect(result).toBeTruthy();
+
+ // add vfModule with user provided naming should return true
+ result = service.shouldOpenDialog(ServiceNodeTypes.VFmodule, [], true);
+ expect(result).toBeTruthy();
+
+ // add vfModule with dynamicInputs without defaultValues should return true
+ result = service.shouldOpenDialog(ServiceNodeTypes.VFmodule, [{
+ id: '2017488_adiodvpe0_vnf_config_template_version',
+ type: 'string',
+ name: '2017488_adiodvpe0_vnf_config_template_version',
+ isRequired: true,
+ description: 'VPE Software Version'
+ }], false);
+ expect(result).toBeTruthy();
+
+ // add vfModule with dynamicInputs with defaultValues should return false
+ result = service.shouldOpenDialog(ServiceNodeTypes.VFmodule, [{
+ id: '2017488_adiodvpe0_vnf_config_template_version',
+ type: 'string',
+ name: '2017488_adiodvpe0_vnf_config_template_version',
+ value: '17.2',
+ isRequired: true,
+ description: 'VPE Software Version'
+ }], false);
+ expect(result).toBeFalsy();
+ done();
+ });
+ });
+
+ function getSericeServiceHierarchy() {
+ return JSON.parse(JSON.stringify(
+ {
+ '6e59c5de-f052-46fa-aa7e-2fca9d674c44': {
+ 'service': {
+ 'uuid': '6e59c5de-f052-46fa-aa7e-2fca9d674c44',
+ 'invariantUuid': 'e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0',
+ 'name': 'ComplexService',
+ 'version': '1.0',
+ 'toscaModelURL': null,
+ 'category': 'Mobility',
+ 'serviceType': '',
+ 'serviceRole': '',
+ 'description': 'ComplexService',
+ 'serviceEcompNaming': 'true',
+ 'instantiationType': 'Macro',
+ 'inputs': {}
+ },
+ 'vnfs': {
+ 'VF_vMee 0': {
+ 'uuid': 'd6557200-ecf2-4641-8094-5393ae3aae60',
+ 'invariantUuid': '4160458e-f648-4b30-a176-43881ffffe9e',
+ 'description': 'VSP_vMee',
+ 'name': 'VF_vMee',
+ 'version': '2.0',
+ 'customizationUuid': '91415b44-753d-494c-926a-456a9172bbb9',
+ 'inputs': {},
+ 'commands': {},
+ 'properties': {
+ 'gpb2_Internal2_mac': '00:80:37:0E:02:22',
+ 'sctp-b-ipv6-egress_src_start_port': '0',
+ 'sctp-a-ipv6-egress_rule_application': 'any',
+ 'Internal2_allow_transit': 'true',
+ 'sctp-b-IPv6_ethertype': 'IPv6',
+ 'sctp-a-egress_rule_application': 'any',
+ 'sctp-b-ingress_action': 'pass',
+ 'sctp-b-ingress_rule_protocol': 'icmp',
+ 'ncb2_Internal1_mac': '00:80:37:0E:0F:12',
+ 'sctp-b-ipv6-ingress-src_start_port': '0.0',
+ 'ncb1_Internal2_mac': '00:80:37:0E:09:12',
+ 'fsb_volume_size_0': '320.0',
+ 'sctp-b-egress_src_addresses': 'local',
+ 'sctp-a-ipv6-ingress_ethertype': 'IPv4',
+ 'sctp-a-ipv6-ingress-dst_start_port': '0',
+ 'sctp-b-ipv6-ingress_rule_application': 'any',
+ 'domain_name': 'default-domain',
+ 'sctp-a-ingress_rule_protocol': 'icmp',
+ 'sctp-b-egress-src_start_port': '0.0',
+ 'sctp-a-egress_src_addresses': 'local',
+ 'sctp-b-display_name': 'epc-sctp-b-ipv4v6-sec-group',
+ 'sctp-a-egress-src_start_port': '0.0',
+ 'sctp-a-ingress_ethertype': 'IPv4',
+ 'sctp-b-ipv6-ingress-dst_end_port': '65535',
+ 'sctp-b-dst_subnet_prefix_v6': '::',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'sctp-a-ipv6-ingress_src_subnet_prefix': '0.0.0.0',
+ 'sctp-b-egress-dst_start_port': '0.0',
+ 'ncb_flavor_name': 'nv.c20r64d1',
+ 'gpb1_Internal1_mac': '00:80:37:0E:01:22',
+ 'sctp-b-egress_dst_subnet_prefix_len': '0.0',
+ 'Internal2_net_cidr': '169.255.0.0',
+ 'sctp-a-ingress-dst_start_port': '0.0',
+ 'sctp-a-egress-dst_start_port': '0.0',
+ 'fsb1_Internal2_mac': '00:80:37:0E:0B:12',
+ 'sctp-a-egress_ethertype': 'IPv4',
+ 'vlc_st_service_mode': 'in-network-nat',
+ 'sctp-a-ipv6-egress_ethertype': 'IPv4',
+ 'sctp-a-egress-src_end_port': '65535.0',
+ 'sctp-b-ipv6-egress_rule_application': 'any',
+ 'sctp-b-egress_action': 'pass',
+ 'sctp-a-ingress-src_subnet_prefix_len': '0.0',
+ 'sctp-b-ipv6-ingress-src_end_port': '65535.0',
+ 'sctp-b-name': 'epc-sctp-b-ipv4v6-sec-group',
+ 'fsb2_Internal1_mac': '00:80:37:0E:0D:12',
+ 'sctp-a-ipv6-ingress-src_start_port': '0.0',
+ 'sctp-b-ipv6-egress_ethertype': 'IPv4',
+ 'Internal1_net_cidr': '169.253.0.0',
+ 'sctp-a-egress_dst_subnet_prefix': '0.0.0.0',
+ 'fsb_flavor_name': 'nv.c20r64d1',
+ 'sctp_rule_protocol': '132',
+ 'sctp-b-ipv6-ingress_src_subnet_prefix_len': '0',
+ 'sctp-a-ipv6-ingress_rule_application': 'any',
+ 'sctp-a-IPv6_ethertype': 'IPv6',
+ 'vlc2_Internal1_mac': '00:80:37:0E:02:12',
+ 'vlc_st_virtualization_type': 'virtual-machine',
+ 'sctp-b-ingress-dst_start_port': '0.0',
+ 'sctp-b-ingress-dst_end_port': '65535.0',
+ 'sctp-a-ipv6-ingress-src_end_port': '65535.0',
+ 'sctp-a-display_name': 'epc-sctp-a-ipv4v6-sec-group',
+ 'sctp-b-ingress_rule_application': 'any',
+ 'int2_sec_group_name': 'int2-sec-group',
+ 'vlc_flavor_name': 'nd.c16r64d1',
+ 'sctp-b-ipv6-egress_src_addresses': 'local',
+ 'vlc_st_interface_type_int1': 'other1',
+ 'sctp-b-egress-src_end_port': '65535.0',
+ 'sctp-a-ipv6-egress-dst_start_port': '0',
+ 'vlc_st_interface_type_int2': 'other2',
+ 'sctp-a-ipv6-egress_rule_protocol': 'any',
+ 'Internal2_shared': 'false',
+ 'sctp-a-ipv6-egress_dst_subnet_prefix_len': '0',
+ 'Internal2_rpf': 'disable',
+ 'vlc1_Internal1_mac': '00:80:37:0E:01:12',
+ 'sctp-b-ipv6-egress_src_end_port': '65535',
+ 'sctp-a-ipv6-egress_src_addresses': 'local',
+ 'sctp-a-ingress-dst_end_port': '65535.0',
+ 'sctp-a-ipv6-egress_src_end_port': '65535',
+ 'Internal1_forwarding_mode': 'l2',
+ 'Internal2_dhcp': 'false',
+ 'sctp-a-dst_subnet_prefix_v6': '::',
+ 'pxe_image_name': 'MME_PXE-Boot_16ACP04_GA.qcow2',
+ 'vlc_st_interface_type_gtp': 'other0',
+ 'ncb1_Internal1_mac': '00:80:37:0E:09:12',
+ 'sctp-b-src_subnet_prefix_v6': '::',
+ 'sctp-a-egress_dst_subnet_prefix_len': '0.0',
+ 'int1_sec_group_name': 'int1-sec-group',
+ 'Internal1_dhcp': 'false',
+ 'sctp-a-ipv6-egress_dst_end_port': '65535',
+ 'Internal2_forwarding_mode': 'l2',
+ 'fsb2_Internal2_mac': '00:80:37:0E:0D:12',
+ 'sctp-b-egress_dst_subnet_prefix': '0.0.0.0',
+ 'Internal1_net_cidr_len': '17',
+ 'gpb2_Internal1_mac': '00:80:37:0E:02:22',
+ 'sctp-b-ingress-src_subnet_prefix_len': '0.0',
+ 'sctp-a-ingress_dst_addresses': 'local',
+ 'sctp-a-egress_action': 'pass',
+ 'fsb_volume_type_0': 'SF-Default-SSD',
+ 'ncb2_Internal2_mac': '00:80:37:0E:0F:12',
+ 'vlc_st_interface_type_sctp_a': 'left',
+ 'vlc_st_interface_type_sctp_b': 'right',
+ 'sctp-a-src_subnet_prefix_v6': '::',
+ 'vlc_st_version': '2',
+ 'sctp-b-egress_ethertype': 'IPv4',
+ 'sctp-a-ingress_rule_application': 'any',
+ 'gpb1_Internal2_mac': '00:80:37:0E:01:22',
+ 'instance_ip_family_v6': 'v6',
+ 'sctp-a-ipv6-egress_src_start_port': '0',
+ 'sctp-b-ingress-src_start_port': '0.0',
+ 'sctp-b-ingress_dst_addresses': 'local',
+ 'fsb1_Internal1_mac': '00:80:37:0E:0B:12',
+ 'vlc_st_interface_type_oam': 'management',
+ 'multi_stage_design': 'false',
+ 'oam_sec_group_name': 'oam-sec-group',
+ 'Internal2_net_gateway': '169.255.0.3',
+ 'sctp-a-ipv6-ingress-dst_end_port': '65535',
+ 'sctp-b-ipv6-egress-dst_start_port': '0',
+ 'Internal1_net_gateway': '169.253.0.3',
+ 'sctp-b-ipv6-egress_rule_protocol': 'any',
+ 'gtp_sec_group_name': 'gtp-sec-group',
+ 'sctp-a-ipv6-egress_dst_subnet_prefix': '0.0.0.0',
+ 'sctp-b-ipv6-egress_dst_subnet_prefix_len': '0',
+ 'sctp-a-ipv6-ingress_dst_addresses': 'local',
+ 'sctp-a-egress_rule_protocol': 'icmp',
+ 'sctp-b-ipv6-egress_action': 'pass',
+ 'sctp-a-ipv6-egress_action': 'pass',
+ 'Internal1_shared': 'false',
+ 'sctp-b-ipv6-ingress_rule_protocol': 'any',
+ 'Internal2_net_cidr_len': '17',
+ 'sctp-a-name': 'epc-sctp-a-ipv4v6-sec-group',
+ 'sctp-a-ingress-src_end_port': '65535.0',
+ 'sctp-b-ipv6-ingress_src_subnet_prefix': '0.0.0.0',
+ 'sctp-a-egress-dst_end_port': '65535.0',
+ 'sctp-a-ingress_action': 'pass',
+ 'sctp-b-egress_rule_protocol': 'icmp',
+ 'sctp-b-ipv6-ingress_action': 'pass',
+ 'vlc_st_service_type': 'firewall',
+ 'sctp-b-ipv6-egress_dst_end_port': '65535',
+ 'sctp-b-ipv6-ingress-dst_start_port': '0',
+ 'vlc2_Internal2_mac': '00:80:37:0E:02:12',
+ 'vlc_st_availability_zone': 'true',
+ 'fsb_volume_image_name_1': 'MME_FSB2_16ACP04_GA.qcow2',
+ 'sctp-b-ingress-src_subnet_prefix': '0.0.0.0',
+ 'sctp-a-ipv6-ingress_src_subnet_prefix_len': '0',
+ 'Internal1_allow_transit': 'true',
+ 'gpb_flavor_name': 'nv.c20r64d1',
+ 'availability_zone_max_count': '1',
+ 'fsb_volume_image_name_0': 'MME_FSB1_16ACP04_GA.qcow2',
+ 'sctp-b-ipv6-ingress_dst_addresses': 'local',
+ 'sctp-b-ipv6-egress_dst_subnet_prefix': '0.0.0.0',
+ 'sctp-b-ipv6-ingress_ethertype': 'IPv4',
+ 'vlc1_Internal2_mac': '00:80:37:0E:01:12',
+ 'sctp-a-ingress-src_subnet_prefix': '0.0.0.0',
+ 'sctp-a-ipv6-ingress_action': 'pass',
+ 'Internal1_rpf': 'disable',
+ 'sctp-b-ingress_ethertype': 'IPv4',
+ 'sctp-b-egress_rule_application': 'any',
+ 'sctp-b-ingress-src_end_port': '65535.0',
+ 'sctp-a-ipv6-ingress_rule_protocol': 'any',
+ 'sctp-a-ingress-src_start_port': '0.0',
+ 'sctp-b-egress-dst_end_port': '65535.0'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': 'VF_vMee 0',
+ 'vfModules': {
+ 'vf_vmee0..VfVmee..vmme_vlc..module-1': {
+ 'uuid': '522159d5-d6e0-4c2a-aa44-5a542a12a830',
+ 'invariantUuid': '98a7c88b-b577-476a-90e4-e25a5871e02b',
+ 'customizationUuid': '55b1be94-671a-403e-a26c-667e9c47d091',
+ 'description': null,
+ 'name': 'VfVmee..vmme_vlc..module-1',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..vmme_vlc..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ 'vf_vmee0..VfVmee..vmme_gpb..module-2': {
+ 'uuid': '41708296-e443-4c71-953f-d9a010f059e1',
+ 'invariantUuid': '1cca90b8-3490-495e-87da-3f3e4c57d5b9',
+ 'customizationUuid': '6add59e0-7fe1-4bc4-af48-f8812422ae7c',
+ 'description': null,
+ 'name': 'VfVmee..vmme_gpb..module-2',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..vmme_gpb..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ 'vf_vmee0..VfVmee..base_vmme..module-0': {
+ 'uuid': 'a27f5cfc-7f12-4f99-af08-0af9c3885c87',
+ 'invariantUuid': 'a6f9e51a-2b35-416a-ae15-15e58d61f36d',
+ 'customizationUuid': 'f8c040f1-7e51-4a11-aca8-acf256cfd861',
+ 'description': null,
+ 'name': 'VfVmee..base_vmme..module-0',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..base_vmme..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+ 'commands': {},
+ 'volumeGroupAllowed': true
+ }
+ },
+ 'volumeGroups': {
+ 'vf_vmee0..VfVmee..base_vmme..module-0': {
+ 'uuid': 'a27f5cfc-7f12-4f99-af08-0af9c3885c87',
+ 'invariantUuid': 'a6f9e51a-2b35-416a-ae15-15e58d61f36d',
+ 'customizationUuid': 'f8c040f1-7e51-4a11-aca8-acf256cfd861',
+ 'description': null,
+ 'name': 'VfVmee..base_vmme..module-0',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..base_vmme..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1}
+ }
+ }
+ }
+ },
+ 'networks': {
+ 'ExtVL 0': {
+ 'uuid': 'ddc3f20c-08b5-40fd-af72-c6d14636b986',
+ 'invariantUuid': '379f816b-a7aa-422f-be30-17114ff50b7c',
+ 'description': 'ECOMP generic virtual link (network) base type for all other service-level and global networks',
+ 'name': 'ExtVL',
+ 'version': '37.0',
+ 'customizationUuid': '94fdd893-4a36-4d70-b16a-ec29c54c184f',
+ 'inputs': {},
+ 'commands': {},
+ 'properties': {
+ 'network_assignments': '{is_external_network=false, ipv4_subnet_default_assignment={min_subnets_count=1}, ecomp_generated_network_assignment=false, ipv6_subnet_default_assignment={min_subnets_count=1}}',
+ 'exVL_naming': '{ecomp_generated_naming=true}',
+ 'network_flows': '{is_network_policy=false, is_bound_to_vpn=false}',
+ 'network_homing': '{ecomp_selected_instance_node_target=false}'
+ },
+ 'type': 'VL',
+ 'modelCustomizationName': 'ExtVL 0'
+ }
+ },
+ 'configurations': {
+ 'Port Mirroring Configuration By Policy 0': {
+ 'uuid': 'b4398538-e89d-4f13-b33d-ca323434ba50',
+ 'invariantUuid': '6ef0ca40-f366-4897-951f-abd65d25f6f7',
+ 'description': 'A port mirroring configuration by policy object',
+ 'name': 'Port Mirroring Configuration By Policy',
+ 'version': '27.0',
+ 'customizationUuid': '3c3b7b8d-8669-4b3b-8664-61970041fad2',
+ 'inputs': {},
+ 'commands': {},
+ 'properties': {},
+ 'type': 'Configuration',
+ 'modelCustomizationName': 'Port Mirroring Configuration By Policy 0',
+ 'sourceNodes': [],
+ 'collectorNodes': null,
+ 'configurationByPolicy': false
+ }
+ },
+ 'serviceProxies': {},
+ 'vfModules': {
+ 'vf_vmee0..VfVmee..vmme_vlc..module-1': {
+ 'uuid': '522159d5-d6e0-4c2a-aa44-5a542a12a830',
+ 'invariantUuid': '98a7c88b-b577-476a-90e4-e25a5871e02b',
+ 'customizationUuid': '55b1be94-671a-403e-a26c-667e9c47d091',
+ 'description': null,
+ 'name': 'VfVmee..vmme_vlc..module-1',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..vmme_vlc..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ 'vf_vmee0..VfVmee..vmme_gpb..module-2': {
+ 'uuid': '41708296-e443-4c71-953f-d9a010f059e1',
+ 'invariantUuid': '1cca90b8-3490-495e-87da-3f3e4c57d5b9',
+ 'customizationUuid': '6add59e0-7fe1-4bc4-af48-f8812422ae7c',
+ 'description': null,
+ 'name': 'VfVmee..vmme_gpb..module-2',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..vmme_gpb..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ 'vf_vmee0..VfVmee..base_vmme..module-0': {
+ 'uuid': 'a27f5cfc-7f12-4f99-af08-0af9c3885c87',
+ 'invariantUuid': 'a6f9e51a-2b35-416a-ae15-15e58d61f36d',
+ 'customizationUuid': 'f8c040f1-7e51-4a11-aca8-acf256cfd861',
+ 'description': null,
+ 'name': 'VfVmee..base_vmme..module-0',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..base_vmme..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+ 'commands': {},
+ 'volumeGroupAllowed': true
+ }
+ },
+ 'volumeGroups': {
+ 'vf_vmee0..VfVmee..base_vmme..module-0': {
+ 'uuid': 'a27f5cfc-7f12-4f99-af08-0af9c3885c87',
+ 'invariantUuid': 'a6f9e51a-2b35-416a-ae15-15e58d61f36d',
+ 'customizationUuid': 'f8c040f1-7e51-4a11-aca8-acf256cfd861',
+ 'description': null,
+ 'name': 'VfVmee..base_vmme..module-0',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..base_vmme..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1}
+ }
+ },
+ 'pnfs': {}
+ }
+ }
+ ));
+ }
+
+});
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.ts b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.ts
new file mode 100644
index 000000000..57dc4b409
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.ts
@@ -0,0 +1,36 @@
+import {Injectable} from '@angular/core';
+import * as _ from "lodash";
+import {ServicePlanningService} from "../../services/service-planning.service";
+
+@Injectable()
+export class AvailableModelsTreeService {
+ constructor(private _servicePlanningService: ServicePlanningService) {
+ }
+
+ shouldShowAddIcon(node: any, serviceHierarchy: any, serviceModelId: string, currentNodeCount: number): boolean {
+ let maxNodes: number = 1;
+ if (node.data.children !== null && node.data.children.length == 0) {
+ let vnfModules = serviceHierarchy[serviceModelId].vfModules;
+ if (vnfModules[node.data.name]) {
+ maxNodes = vnfModules[node.data.name].properties.maxCountInstances || 1;
+ }
+ }
+ return !node.data.disabled && currentNodeCount < maxNodes
+ }
+
+ shouldOpenDialog(type: string, dynamicInputs: any, userProvidedNaming: boolean): boolean {
+ if (userProvidedNaming || this._servicePlanningService.requiredFields[type].length > 0) {
+ return true;
+ }
+
+ if (dynamicInputs) {
+ for(let input of dynamicInputs) {
+ if (input.isRequired && _.isEmpty(input.value)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.html b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.html
new file mode 100644
index 000000000..7d0f7f456
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.html
@@ -0,0 +1,33 @@
+<div class="drawing-board-header">
+ <div class="left-header">
+ <span [attr.data-tests-id]="'backBtn'" class="icon-back" (click)="closePage()"></span>
+ <span [attr.data-tests-id]="'serviceInstance'" class="service-instance-label">Service instance:</span>
+ <span [attr.data-tests-id]="'serviceName'" class="service-instance-name">{{serviceName}}</span>
+ <span class="quantity-container" style=" padding: 10px;font-size: 13px;" tooltip="Number of services to instantiate including all their objects as defined below">
+ <span [attr.data-tests-id]="'quantityLabel'" class="quantity-label" >Scale Times:</span>
+ <span [attr.data-tests-id]="'servicesQuantity'" class="quantity" style="font-family: OpenSans-Semibold;font-size: 14px;"> {{numServicesToDeploy}} </span>
+ </span>
+ <span class="service-instance-label">status:</span>
+ <span [attr.data-tests-id]="'serviceStatus'" class="status">{{status}}</span>
+ </div>
+ <div class="right-header">
+ <span class="menu-container">
+ <span [attr.data-tests-id]="'openMenuBtn'" class="icon-browse" (click)="onContextMenu($event)"></span>
+ <context-menu>
+ <ng-template contextMenuItem (execute)="editService()">
+ <div [attr.data-tests-id]="'context-menu-header-edit-item'">
+ <span class="icon-edit"></span>
+ Edit
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem (execute)="closePage()">
+ <div [attr.data-tests-id]="'context-menu-header-delete-item'">
+ <span class="icon-trash"></span>
+ Delete
+ </div>
+ </ng-template>
+ </context-menu>
+ </span>
+ <button [disabled]="false" [attr.data-tests-id]="'deployBtn'" (click)="deployMacroservice()" class="deploy-btn">DEPLOY</button>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.scss b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.scss
new file mode 100644
index 000000000..29b7711bc
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.scss
@@ -0,0 +1,95 @@
+.drawing-board-header {
+ height: 56px;
+ margin-bottom: 4px;
+ position: relative;
+ font-family: OpenSans-Regular;
+ display: flex;
+ justify-content: space-between;
+ font-size: 14px;
+ box-shadow: 2px 2px 6px #D2D2D2;
+ color: #191919;
+ [class^="icon-"] {
+ height: 56px;
+ width: 56px;
+ display: flex;
+ align-items: center;
+ text-align: center;
+ color: #5A5A5A;
+ cursor: pointer;
+ &:before {
+ font-size: 18px;
+ width: 100%;
+ }
+ &:hover:before {
+ color: #009FDB;
+ }
+ }
+ .left-header {
+ display: flex;
+ align-items: center;
+ .icon-back {
+ border-right: 1px solid #EAEAEA;
+ &:before {
+ content: "\e906";
+ font-size: 24px;
+ }
+ }
+ .service-instance-label {
+ padding: 0 5px;
+ font-family: OpenSans-Regular;
+ font-size: 13px;
+ color: #191919;
+ }
+ .service-instance-name {
+ padding-right: 20px;
+ color: #191919;
+ font-family: OpenSans-Semibold;
+ background-color: white;
+ font-size: 16px
+ }
+ .status {
+ font-family: OpenSans-Semibold;
+ line-height: 14px;
+ font-size: 14px;
+ }
+ }
+ .right-header {
+ display: flex;
+ align-items: center;
+ .quantity-container {
+ .quantity-label {
+ padding-left: 10px;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+ .quantity {
+ padding: 5px 10px 5px 0;
+ font-family: OpenSans-Semibold;
+ font-size: 18px;
+ }
+ }
+ [class^="icon-"] {
+ border-left: 1px solid #EAEAEA;
+ }
+ .menu-container {
+ height: 100%;
+ display: flex;
+ background: none;
+ border: none;
+ padding: 0;
+ outline: none;
+ }
+ .icon-browse:before {
+ content: '\e924';
+ display: inline-block;
+ font-size: 24px;
+ }
+ .deploy-btn {
+ color: #FFFFFF ;
+ background: #009fdb;
+ width: 128px;
+ height: 100%;
+ border: none;
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.ts b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.ts
new file mode 100644
index 000000000..38284e214
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.ts
@@ -0,0 +1,119 @@
+import {Component, ViewChild} from '@angular/core';
+import {ContextMenuComponent, ContextMenuService} from 'ngx-contextmenu';
+import {DialogService} from 'ng2-bootstrap-modal';
+import {ServicePopupComponent} from '../../components/service-popup/service-popup.component';
+import {MsoService} from '../../services/msoService/mso.service'
+import * as _ from 'lodash';
+import {ActivatedRoute} from '@angular/router';
+import {ServiceInstance} from "../../shared/models/serviceInstance";
+import {OwningEntity} from "../../shared/models/owningEntity";
+import {MessageBoxData, ModalSize, ModalType} from "../../shared/components/messageBox/messageBox.data";
+import {MessageBoxService} from "../../shared/components/messageBox/messageBox.service";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import {IframeService} from "../../shared/utils/iframe.service";
+
+@Component({
+ selector: 'drawing-board-header',
+ providers: [MsoService],
+ templateUrl: './drawing-board-header.component.html',
+ styleUrls: ['./drawing-board-header.component.scss']
+})
+
+export class DrawingBoardHeader {
+ serviceName: string;
+ numServicesToDeploy: number;
+ status: string = 'Designing a new service';
+ serviceModelId: string;
+ parentElementClassName = 'content';
+
+ constructor(private _contextMenuService: ContextMenuService, private dialogService: DialogService,
+ private _iframeService : IframeService,
+ private route: ActivatedRoute, private msoService: MsoService,
+ private store: NgRedux<AppState>) {
+ this.route
+ .queryParams
+ .subscribe(params => {
+ this.serviceModelId = params['serviceModelId'];
+ if (_.has(this.store.getState().service.serviceHierarchy, this.serviceModelId)) {
+ this.setValuesFromStore();
+ this.store.subscribe(() => {
+ this.setValuesFromStore();
+ });
+ }
+ });
+ }
+
+
+ @ViewChild(ContextMenuComponent) public contextMenu: ContextMenuComponent;
+
+ public onContextMenu($event: MouseEvent, item: any): void {
+ this._contextMenuService.show.next({
+ contextMenu: this.contextMenu,
+ event: $event,
+ item: item,
+ });
+ $event.preventDefault();
+ $event.stopPropagation();
+ }
+
+ private setValuesFromStore() {
+ const serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+ this.numServicesToDeploy = serviceInstance.bulkSize;
+ this.serviceName = serviceInstance.instanceName || '<Automatically Assigned>';
+
+ }
+
+ public editService(): void {
+ this._iframeService.addClassOpenModal(this.parentElementClassName);
+ this.dialogService.addDialog(ServicePopupComponent, {})
+
+ }
+
+
+ extractOwningEntityNameAccordingtoId(id:String): string {
+ let owningEntityName;
+ _.forEach(this.store.getState().service.categoryParameters.owningEntityList,function(owningEntity: OwningEntity) {
+ if (owningEntity.id === id) {
+ owningEntityName = owningEntity.name;
+
+ }})
+
+ return owningEntityName;
+ }
+
+ extractServiceFields(): any {
+ let instanceFields : ServiceInstance;
+ instanceFields = this.store.getState().service.serviceInstance[Object.keys(this.store.getState().service.serviceInstance)[0]];
+ instanceFields.subscriberName = this.store.getState().service.subscribers.find(sub => sub.id === instanceFields.globalSubscriberId).name;
+ instanceFields.owningEntityName = this.extractOwningEntityNameAccordingtoId(instanceFields.owningEntityId);
+ return instanceFields;
+ }
+
+ public deployMacroservice(): void {
+ var instanceFields = this.extractServiceFields();
+ instanceFields.rollbackOnFailure = instanceFields.rollbackOnFailure === 'true';
+ this.msoService.submitMsoTask(instanceFields).subscribe((result) => {
+ window.parent.postMessage("navigateToInstantiationStatus", '*');
+ })
+ }
+
+ closePage() {
+ let messageBoxData : MessageBoxData = new MessageBoxData(
+ "Delete Instantiation", // modal title
+ "You are about to stop the instantiation process of this service. \nAll data will be lost. Are you sure you want to stop?",
+
+ ModalType.alert,
+ ModalSize.medium,
+ [
+ {text:"Stop Instantiation", size:"large", callback: this.navigate.bind(this), closeModal:true},
+ {text:"Cancel", size:"medium", closeModal:true}
+ ]);
+
+ MessageBoxService.openModal.next(messageBoxData);
+ }
+
+ navigate(){
+ window.parent.postMessage("navigateTo", "*");
+ }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-header/tmp_instansiate_request.ts b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/tmp_instansiate_request.ts
new file mode 100644
index 000000000..7accc3a9c
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/tmp_instansiate_request.ts
@@ -0,0 +1,52 @@
+export default
+ {
+ "modelInfo": {
+ "modelType": "service",
+ "modelInvariantId": "5d48acb5-097d-4982-aeb2-f4a3bd87d31b",
+ "modelVersionId": "3c40d244-808e-42ca-b09a-256d83d19d0a",
+ "modelName": "MOW AVPN vMX BV vPE 1 Service",
+ "modelVersion": "10.0"
+ },
+ "owningEntityId": "038d99af-0427-42c2-9d15-971b99b9b489",
+ "owningEntityName": "PACKET CORE",
+ "projectName": "{some project name}",
+ "globalSubscriberId": "{some subscriber id}",
+ "productFamilyId": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb",
+ "instanceName": "vPE_Service",
+ "subscriptionServiceType": "VMX",
+ "lcpCloudRegionId": "mdt1",
+ "tenantId": "88a6ca3ee0394ade9403f075db23167e",
+ "vnfs": [
+ {
+ "modelInfo": {
+ "modelName": "2016-73_MOW-AVPN-vPE-BV-L",
+ "modelVersionId": "7f40c192-f63c-463e-ba94-286933b895f8",
+ "modelCustomizationName": "2016-73_MOW-AVPN-vPE-BV-L 0",
+ "modelCustomizationId": "ab153b6e-c364-44c0-bef6-1f2982117f04"
+ },
+ "lcpCloudRegionId": "mdt1",
+ "tenantId": "88a6ca3ee0394ade9403f075db23167e",
+ "platformName": "test",
+ "productFamilyId": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb",
+ "instanceName": "vmxnjr001",
+ "instanceParams": [],
+ "vfModules": [
+ {
+ "modelInfo": {
+ "modelType": "vfModule",
+ "modelName": "201673MowAvpnVpeBvL..AVPN_base_vPE_BV..module-0",
+ "modelVersionId": "4c75f813-fa91-45a4-89d0-790ff5f1ae79",
+ "modelCustomizationId": "a25e8e8c-58b8-4eec-810c-97dcc1f5cb7f"
+ },
+ "instanceName": "vmxnjr001_AVPN_base_vPE_BV_base_001",
+ "instanceParams": [
+ {
+ "vmx_int_net_len": "24"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.component.ts b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.component.ts
new file mode 100644
index 000000000..6b717a930
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.component.ts
@@ -0,0 +1,133 @@
+import {AfterViewInit, Component, EventEmitter, OnInit, Output, ViewChild} from '@angular/core';
+import { ContextMenuService } from 'ngx-contextmenu';
+import { Constants } from '../../shared/utils/constants';
+import {ServicePlanningService} from "../../services/service-planning.service";
+import {ITreeNode} from "angular-tree-component/dist/defs/api";
+import {ITreeOptions, TreeComponent} from "angular-tree-component";
+import {VnfPopupComponent} from "../../components/vnf-popup/vnf-popup.components";
+import {DialogService} from "ng2-bootstrap-modal";
+import {ActivatedRoute} from "@angular/router";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import { MessageBoxData, ModalSize, ModalType } from '../../shared/components/messageBox/messageBox.data';
+import { MessageBoxService } from '../../shared/components/messageBox/messageBox.service';
+import { deleteVnfInstance, deleteVfModuleInstance } from '../../service.actions';
+import { isNullOrUndefined } from 'util';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+
+@Component({
+ selector: 'drawing-board-tree',
+ templateUrl: './drawing-board-tree.html',
+ styleUrls : ['./drawing-board-tree.scss']
+})
+
+
+export class DrawingBoardTreeComponent implements OnInit, AfterViewInit {
+ constructor(private _contextMenuService: ContextMenuService,
+ private _servicePlanningService: ServicePlanningService,
+ private _iframeService : IframeService,
+ private dialogService: DialogService,
+ private store: NgRedux<AppState>,
+ private route: ActivatedRoute) {
+ this.route
+ .queryParams
+ .subscribe(params => {
+ this.serviceModelId = params['serviceModelId'];
+ });
+ }
+
+ @Output()
+ highlightNode : EventEmitter<number> = new EventEmitter<number>();
+
+ @ViewChild('tree') tree: TreeComponent;
+ missingDataTooltip: string = Constants.Error.MISSING_VNF_DETAILS;
+ currentNode: ITreeNode = null; //
+ nodes = [];
+ serviceModelId: string;
+ options: ITreeOptions = {
+ nodeHeight: 45,
+ dropSlotHeight: 1
+ };
+ parentElementClassName = 'content';
+
+ ngOnInit(): void {
+ this.store.subscribe(() => {this.updateTree()});
+ this.updateTree()
+ }
+
+ updateTree() {
+ const serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+ this.nodes = this._servicePlanningService.convertServiceInstanceToTreeData(serviceInstance, this.serviceModelId);
+ }
+
+ ngAfterViewInit():void {
+ // Expand drawing tree on init.
+ this.tree.treeModel.expandAll();
+ }
+
+ public onContextMenu($event: MouseEvent, node: ITreeNode): void {
+ this.currentNode = node;
+ node.focus();
+ node.setActiveAndVisible(false);
+ this.selectNode(node);
+ this._contextMenuService.show.next({
+ event: <any>$event,
+ item: node,
+ });
+ $event.preventDefault();
+ $event.stopPropagation();
+ }
+
+ public editItem(node: ITreeNode): void {
+ node = this.currentNode;
+ this._iframeService.addClassOpenModal(this.parentElementClassName);
+ this.dialogService.addDialog(VnfPopupComponent, {
+ serviceModelId: this.serviceModelId,
+ modelName: node.data.modelName,
+ modelType: node.data.type,
+ parentModelName: node.parent.data.modelName,
+ isNewVfModule : false
+ })
+ }
+
+ public deleteItem(node: ITreeNode): void {
+ if(this.currentNode.data.type === 'VF'){
+ if(!isNullOrUndefined(this.currentNode.data.children) && this.currentNode.data.children.length === 0){
+ this.store.dispatch(deleteVnfInstance(this.currentNode.data.modelName, this.serviceModelId));
+ }else {
+ let messageBoxData : MessageBoxData = new MessageBoxData(
+ "Remove VNF", // modal title
+ "You are about to remove this VNF and all its children from this service. Are you sure you want to remove it?",
+
+ ModalType.alert,
+ ModalSize.medium,
+ [
+ {text:"Remove VNF", size:"large", callback: this.removeVnf.bind(this), closeModal:true},
+ {text:"Don’t Remove", size:"medium", closeModal:true}
+ ]);
+
+ MessageBoxService.openModal.next(messageBoxData);
+ }
+ }else {
+ this.store.dispatch(deleteVfModuleInstance(this.currentNode.data.modelName, this.serviceModelId, node.parent.data.modelName));
+ }
+ }
+
+ removeVnf() {
+ this.store.dispatch(deleteVnfInstance(this.currentNode.data.modelName, this.serviceModelId));
+ }
+
+ public selectNode(node: ITreeNode): void {
+ node.expand();
+ this.highlightNode.emit(node.data.modelId);
+ }
+
+ isDataMissing(node: ITreeNode) {
+ //todo: currently not showing the alert icon. will be implemented in upcoming story.
+ return false;
+ }
+
+}
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.html b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.html
new file mode 100644
index 000000000..c4061db9e
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.html
@@ -0,0 +1,42 @@
+<div class="drawing-board-tree">
+ <div *ngIf="nodes?.length == 0" style="text-align: center; margin-top: 50px;">
+ <no-content-message-and-icon class="span-over"
+ data-title="Please add objects (VNFs, network, modules etc.) from the left tree to design the service instance"
+ subtitle="Once done, click Deploy to start instantiation"
+ iconPath="./assets/img/UPLOAD.svg"
+ iconClass="upload-icon-service-planing"></no-content-message-and-icon>
+ </div>
+ <tree-root [attr.data-tests-id]="'drawing-board-tree'" #tree [nodes]="nodes" [options]="options" id="drawing-board-tree">
+ <ng-template #treeNodeTemplate let-node let-index="index">
+ <div [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName" (click)="selectNode(node)">
+ <div class="model-info">
+ <span>
+ <span class="property-name">{{node.data.type}}{{node.data.name ? ': ': ''}}<span class="auto-name">{{node.data.name? node.data.name: ''}}</span></span>
+ </span>
+ </div>
+ <div class="model-actions">
+ <span class="icon-browse" [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName+'-menu-btn'" (click)="onContextMenu($event, node)" >
+ <context-menu>
+ <ng-template contextMenuItem (execute)="editItem(node)">
+ <div [attr.data-tests-id]="'context-menu-item'">
+ <span class="icon-edit"></span>
+ Edit
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem (execute)="deleteItem(node)">
+ <div>
+ <span class="icon-trash"></span>
+ Remove
+ </div>
+ </ng-template>
+ </context-menu>
+ </span>
+ <span *ngIf="isDataMissing(node)" class="icon-alert" tooltip="{{ missingDataTooltip }}" tooltipPlacement="left" [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName+'-alert-icon'"></span>
+ </div>
+ </div>
+
+ </ng-template>
+ </tree-root>
+</div>
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.scss b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.scss
new file mode 100644
index 000000000..fed9ead10
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.scss
@@ -0,0 +1,274 @@
+@mixin highlight($background-color, $color) {
+ background: none;
+ padding: 0;
+ background-color: $background-color;
+ border: $color 1px solid;
+ color: $color;
+}
+@mixin highlight-toggle-children {
+ tree-node-expander {
+ .toggle-children-wrapper {
+ span.toggle-children {
+ @include highlight(white, #009FDB);
+ border-right: none;
+ }
+ }
+ }
+}
+
+@mixin highlight-tree-node-content {
+ tree-node-content {
+ > div {
+ .model-actions {
+ .icon-browse:before {
+ display: inline-block;
+ }
+ }
+ }
+ }
+}
+
+drawing-board-tree {
+
+ .toggle-children-wrapper.toggle-children-wrapper-expanded {
+ .toggle-children:before {
+ color: #009FDB;
+ }
+ }
+
+ overflow: auto;
+ flex: 1;
+ color: #5A5A5A;
+ line-height: 14px;
+ .drawing-board-tree {
+ width: 100%;
+ }
+ tree-viewport {
+ padding: 50px 3.5% 1% 6%;
+ tree-node {
+ tree-node-drop-slot {
+ .node-drop-slot {
+ display: none;
+ }
+ }
+ & .tree-node-focused,
+ & .tree-node-active {
+ & > tree-node-wrapper {
+ .node-wrapper {
+ @include highlight-toggle-children;
+ .node-content-wrapper-focused,
+ .node-content-wrapper-active
+ {
+ @include highlight(#E6F6FB, #009FDB);
+ .property-name {
+ color: #009FDB;
+ }
+ .auto-name {
+ font-family: OpenSans-Regular !important;
+ }
+ .icon-browse:before {
+ color: #5A5A5A;
+ }
+ @include highlight-tree-node-content;
+ }
+ }
+ }
+ }
+ & .tree-node-expanded {
+ > tree-node-wrapper .node-wrapper {
+ box-shadow: 0 0px 2px rgba(90,90,90,0.24);
+ }
+ }
+
+ .tree-node-active .tree-children {
+ border: 1px solid #009FDB;
+ padding: 20px;
+ }
+
+
+
+ .tree-node.tree-node-active.tree-node-expanded {
+ border: 1px solid #009FDB;
+ }
+
+ .tree-node-leaf .node-wrapper{
+ margin-left: -45px;
+ }
+
+ tree-node-wrapper {
+ .node-wrapper {
+ height: 45px;
+ &:hover {
+ @include highlight-toggle-children;
+ .node-content-wrapper {
+ @include highlight(#E6F6FB, #009FDB);
+ .property-name {
+ color: #009FDB;
+ }
+ .icon-browse:before {
+ color: #5A5A5A;
+ }
+ @include highlight-tree-node-content;
+ }
+ }
+ tree-node-expander {
+ font-family: 'icomoon' !important;
+ height: 100%;
+ .toggle-children-wrapper {
+ padding: 0;
+ display: block;
+ height: 100%;
+ span.toggle-children {
+ display: flex;
+ width: 45px;
+ padding: 0;
+ top: 0;
+ height: inherit;
+ background-image: none;
+ background-color: white;
+ border: 1px solid #D2D2D2;
+ border-right: none;
+ &:before {
+ content: "\e900";
+ font-size: 20px;
+ font-weight: 600;
+ text-align: center;
+ display: inline-block;
+ flex: auto;
+ align-self: center;
+ }
+ }
+ }
+ .toggle-children-wrapper-expanded {
+ span.toggle-children {
+ transform: none;
+ &:before {
+ content: "\e930";
+ }
+ }
+ }
+ .toggle-children-placeholder {
+ width:45px;
+ }
+ }
+ .node-content-wrapper {
+ padding: 0;
+ background: none;
+ box-shadow: none;
+ border-radius: 0;
+ border: 1px solid #D2D2D2;
+ height: 100%;
+ flex: 1;
+ tree-node-content {
+ > div {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ .model-info {
+ flex: 1;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding-left: 8px;
+ > span {
+ flex: 1;
+ padding: 0 8px;
+ span:nth-child(2) {
+ display: block;
+ }
+ }
+ }
+ .model-actions {
+ display: flex;
+ align-items: center;
+ padding-right: 12px;
+ .icon-browse {
+ padding: 0;
+ width: 30px;
+ &:before {
+ content: "\e924";
+ font-size: 24px;
+ display: none;
+ }
+ &:hover:before {
+ color: #009FDB;
+ }
+ &:focus:before,
+ &:active:before {
+ color: #009FDB;
+ }
+ }
+
+ .icon-alert {
+ padding-left: 10px;
+ &:before {
+ content: "\e904";
+ font-size: 16px;
+ color: #ffb81c;
+ }
+ }
+ }
+ }
+ }
+ .property-name {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ line-height: 12px;
+ color: #191919;
+ text-transform: capitalize;
+ }
+ }
+
+
+ }
+ }
+ tree-node-children {
+ .tree-children {
+ padding: 20px;
+ .model-info span:first-child {
+ flex: 1.1 !important;
+ }
+ }
+ }
+ }
+ }
+}
+.cdk-overlay-pane.ngx-contextmenu {
+ ul.dropdown-menu {
+ width: 200px;
+ box-shadow: none;
+ padding: 0;
+ padding-top: 10px;
+ margin: 0;
+ border: 1px solid #D2D2D2;
+ border-top: 3px solid #009FDB;
+ box-shadow: 0 0px 2px rgba(90,90,90,0.24);
+ border-radius: 2px;
+ li {
+ height: 40px;
+ a {
+ font-family: OpenSans-Regular;
+ display: flex;
+ align-items: center;
+ height: 100%;
+ padding: 12px;
+ color: #5A5A5A;
+ &:hover {
+ background: #E6F6FB;
+ color: #009FDB;
+ }
+ span {
+ padding-right: 12px;
+ &.icon-edit:before {
+ content: '\e917';
+ }
+ &.icon-trash:before {
+ content: '\e937';
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/vid-webpack-master/src/app/drawingBoard/drawingBoard.module.ts b/vid-webpack-master/src/app/drawingBoard/drawingBoard.module.ts
new file mode 100644
index 000000000..41efbe0e8
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawingBoard.module.ts
@@ -0,0 +1,41 @@
+import { AvailableModelsTreeService } from './available-models-tree/available-models-tree.service';
+import { NgModule } from '@angular/core';
+import { HighlightPipe } from '../shared/pipes/highlight-filter.pipe';
+import { TreeModule } from 'angular-tree-component';
+import { BrowserModule } from '@angular/platform-browser';
+import { TooltipModule } from 'ngx-tooltip';
+import { AvailableModelsTreeComponent } from './available-models-tree/available-models-tree.component';
+import { ServicePlanningService } from '../services/service-planning.service';
+import { AaiService } from '../services/aaiService/aai.service';
+import { DrawingBoardTreeComponent } from './drawing-board-tree/drawing-board-tree.component';
+import { SharedModule } from '../shared/shared.module';
+import { ContextMenuModule, ContextMenuService } from 'ngx-contextmenu';
+import { CommonModule } from '@angular/common';
+import { DrawingBoardHeader } from './drawing-board-header/drawing-board-header.component';
+import { ServicePlanningComponent, ServicePlanningEmptyComponent } from './service-planning/service-planning.component';
+
+@NgModule({
+ imports: [
+ TreeModule,
+ BrowserModule,
+ ContextMenuModule,
+ TooltipModule,
+ CommonModule,
+ SharedModule.forRoot()],
+ providers: [
+ ServicePlanningService,
+ AaiService,
+ AvailableModelsTreeService ,
+ ContextMenuService,
+ ServicePlanningService],
+ declarations: [
+ AvailableModelsTreeComponent,
+ HighlightPipe,
+ DrawingBoardTreeComponent,
+ DrawingBoardHeader,
+ ServicePlanningComponent,
+ ServicePlanningEmptyComponent],
+ exports: [ AvailableModelsTreeComponent, DrawingBoardTreeComponent, DrawingBoardHeader]
+})
+
+export class DrawingBoardModule { }
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.html b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.html
new file mode 100644
index 000000000..5b2f22d5f
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.html
@@ -0,0 +1,13 @@
+<div class="service-planning-header">
+ <drawing-board-header></drawing-board-header>
+</div>
+<div class="service-planning-content row">
+ <available-models-tree class="left-side col-md-6" (highlightInstances)="highlightInstancesBySelectingNode($event)"></available-models-tree>
+ <!--<no-content-message-and-icon *ngIf="!isShowTree()" class="span-over"-->
+ <!--data-title="Please add objects (VNFs, network, modules etc.) from the left tree to design the service instance"-->
+ <!--subtitle="Once done, click Deploy to start instantiation"-->
+ <!--iconPath="./img/UPLOAD.svg"-->
+ <!--iconClass="upload-icon-service-planing"></no-content-message-and-icon>-->
+ <drawing-board-tree *ngIf="isShowTree()" class="span-over col-md-6" (highlightNode)="highlightNodeBySelectingInstance($event)"></drawing-board-tree>
+</div>
+
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.scss b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.scss
new file mode 100644
index 000000000..69546a6c0
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.scss
@@ -0,0 +1,16 @@
+
+.service-planning-content {
+ display: flex;
+ flex: 1;
+}
+
+.span-over {
+ display: flex;
+ flex: 1;
+}
+
+//css for the icon. :host ::ng-deep are needed for applying css to child component
+:host ::ng-deep .upload-icon-service-planing {
+ height: 117px;
+ margin-top: 32px;
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.ts
new file mode 100644
index 000000000..1ce0e8100
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.ts
@@ -0,0 +1,77 @@
+import {Component, ViewChild} from '@angular/core';
+import {DrawingBoardTreeComponent} from "../drawing-board-tree/drawing-board-tree.component";
+import {AvailableModelsTreeComponent} from "../available-models-tree/available-models-tree.component";
+import {ITreeNode} from "angular-tree-component/dist/defs/api";
+import {TreeComponent} from 'angular-tree-component';
+
+@Component({
+ selector: 'service-planning',
+ templateUrl: './service-planning.component.html',
+ styleUrls: ['./service-planning.component.scss']
+})
+
+export class ServicePlanningComponent {
+
+ @ViewChild(DrawingBoardTreeComponent) drawingModelTree;
+ @ViewChild(AvailableModelsTreeComponent) availableModelTree;
+
+ isShowTree(): boolean {
+ return true;
+ }
+
+ public highlightNodeBySelectingInstance(modelId: number): void {
+ this.availableModelTree.tree.treeModel.getNodeBy((node: ITreeNode) => node.data.id === modelId)
+ .setActiveAndVisible().expand();
+ }
+
+ public highlightInstancesBySelectingNode(id: number): void {
+ if(this.isShowTree()) {
+ let _this = this;
+ let matchInstances = _this.searchTree(id);
+ if (!matchInstances.length)
+ _this.clearSelectionInTree(_this.drawingModelTree.tree);
+ matchInstances.forEach(function (instance, index) {
+ let multi : boolean = !!index;
+ _this.drawingModelTree.tree.treeModel.getNodeById(instance.id)
+ .setActiveAndVisible(multi).expand();
+ });
+
+ }
+ }
+
+ clearSelectionInTree(tree: TreeComponent): void {
+ let activateNode = tree.treeModel.getActiveNode();
+ activateNode ? activateNode.toggleActivated().blur() : null;
+ }
+
+ searchTree(modelId: number) {
+ let _this = this;
+ let results = [];
+ let nodes = _this.drawingModelTree.nodes;
+ nodes.forEach(function (node) {
+ _this.searchTreeNode(node, modelId, results);
+ });
+ return results;
+ }
+
+ searchTreeNode(node, modelId: number, results): void {
+ if(node.modelId === modelId){
+ results.push(node);
+ }
+ if (node.children != null){
+ for(let i = 0; i < node.children.length; i++){
+ this.searchTreeNode(node.children[i], modelId, results);
+ }
+ }
+ }
+
+
+}
+
+export class ServicePlanningEmptyComponent extends ServicePlanningComponent {
+ isShowTree() : boolean {
+ return false;
+ }
+}
+
+
diff --git a/vid-webpack-master/src/app/factories/models/requestDetails.model.ts b/vid-webpack-master/src/app/factories/models/requestDetails.model.ts
new file mode 100644
index 000000000..4ccc4781b
--- /dev/null
+++ b/vid-webpack-master/src/app/factories/models/requestDetails.model.ts
@@ -0,0 +1,126 @@
+export class RequestInfo {
+ instanceName: string;
+ source: string;
+ suppressRollback: boolean;
+ requestorId: string;
+ productFamilyId: string;
+}
+
+export class ModelInfo {
+ modelType: string;
+ modelInvariantId: string;
+ modelVersionId: string;
+ modelName: string;
+ modelVersion: string;
+ modelCustomizationId: string;
+ modelCustomizationName: string;
+}
+
+export class RequestParameters {
+ userParams: any[];
+ testApi: string;
+}
+
+export class CloudConfiguration {
+ lcpCloudRegionId: string;
+ tenantId: string;
+}
+
+export class LineOfBusiness {
+ lineOfBusinessName: string;
+}
+
+export class Platform {
+ platformName: string;
+}
+
+export class VfcModel {
+ uuid: string;
+ invariantUuid: string;
+ name: string;
+ version: string;
+ vfcInstanceGroupProperties : any;
+}
+
+export class RelatedInstance {
+ instanceId: string;
+ modelInfo: ModelInfo;
+}
+
+export class RelatedInstanceList {
+ relatedInstance: RelatedInstance;
+}
+
+export class RequestDetails {
+ requestInfo: RequestInfo;
+ modelInfo: ModelInfo;
+ requestParameters: RequestParameters;
+ cloudConfiguration: CloudConfiguration;
+ lineOfBusiness: LineOfBusiness;
+ platform: Platform;
+ relatedInstanceList: RelatedInstanceList[];
+}
+
+export class RootObject {
+ requestDetails: RequestDetails;
+}
+// {
+// "requestDetails": {
+// "modelInfo": {
+// “modelType”: “vnf”,
+// “modelInvariantId”: “ff5256d1-5a33-55df-13ab-12abad84e7ff”,
+// “modelVersionId”: “fe042c22-ba82-43c6-b2f6-8f1fc4164091”,
+// “modelName”: “vSAMP12”,
+// "modelVersion": "1.0",
+// “modelCustomizationName”: “vSAMP12 1”,
+// “modelCustomizationId”: “a7f1d08e-b02d-11e6-80f5-76304dec7eb7”
+// },
+// “cloudConfiguration”: {
+// “lcpCloudRegionId”: “mdt1”,
+// “tenantId”: “88a6ca3ee0394ade9403f075db23167e”
+// },
+// "requestInfo": {
+// “instanceName”: “MSOTEST103a”,
+// “productFamilyId”: “a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb”,
+// “source”: “VID”,
+// “suppressRollback”: false,
+// “requestorId”: “az2016”
+// },
+// "platform": {
+// "platformName": "{some platformName}"
+// },
+// "lineOfBusiness": {
+// "lineOfBusinessName": "{some string}"
+// },
+// "relatedInstanceList": [
+// {
+// “relatedInstance”: {
+// “instanceId”: “{serviceInstanceId}”,
+// “modelInfo”: {
+// “modelType”: “service”,
+// “modelInvariantId”: “ff3514e3-5a33-55df-13ab-12abad84e7ff”,
+// “modelVersionId”: “fe6985cd-ea33-3346-ac12-ab121484a3fe”,
+// “modelName”: “{parent service model name}”,
+// "modelVersion": "1.0"
+// }
+// }
+// },
+// {
+// “relatedInstance”: {
+// “instanceId”: “{instanceGroupId}”,
+// “modelInfo”: {
+// “modelType”: “networkCollection”,
+// “modelInvariantId”: “9ea660dc-155f-44d3-b45c-cc7648b4f31c”,
+// “modelVersionId”: “bb07aad1-ce2d-40c1-85cb-5392f76bb1ef”,
+// “modelName”: “{network collection model name}”,
+// "modelVersion": "1.0"
+// }
+// }
+// }
+
+// ],
+// “requestParameters”: {
+// “userParams”: []
+// }
+// }
+// }
diff --git a/vid-webpack-master/src/app/factories/mso.factory.spec.ts b/vid-webpack-master/src/app/factories/mso.factory.spec.ts
new file mode 100644
index 000000000..16efd2970
--- /dev/null
+++ b/vid-webpack-master/src/app/factories/mso.factory.spec.ts
@@ -0,0 +1,319 @@
+import {createRequest} from './mso.factory';
+
+sessionStorage.setItem("msoRequestParametersTestApiValue","GR_API");
+describe('Vlantagging', () => {
+ it('should create a correct request', (done: DoneFn) => {
+ let userInputs_withEcompGeneratedNaming = {
+ "productFamily": "e433710f-9217-458d-a79d-1c7aff376d89",
+ "lcpRegion": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+ "aicZone": "YYY1",
+ "platformName": "plat1",
+ "lineOfBusiness": "ecomp"
+ };
+ let userInputs_withoutEcompGeneratedNaming = {
+ "instanceName": "New Name",
+ "productFamily": "e433710f-9217-458d-a79d-1c7aff376d89",
+ "lcpRegion": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+ "aicZone": "YYY1",
+ "platformName": "plat1",
+ "lineOfBusiness": "ecomp"
+ };
+ let service = {
+ "service": {
+ "uuid": "6bce7302-70bd-4057-b48e-8d5b99e686ca",
+ "invariantUuid": "9aa04749-c02c-432d-a90c-18caa361c833",
+ "name": "vDBE_srv",
+ "version": "1.0",
+ "toscaModelURL": null,
+ "category": "Network L4+",
+ "serviceType": "",
+ "serviceRole": "",
+ "description": "vDBE_srv",
+ "serviceEcompNaming": "true",
+ "instantiationType": "A-La-Carte",
+ "inputs": {}
+ },
+ "vnfs": {
+ "vDBE 0": {
+ "uuid": "61535073-2e50-4141-9000-f66fea69b433",
+ "invariantUuid": "fcdf49ce-6f0b-4ca2-b676-a484e650e734",
+ "description": "vDBE",
+ "name": "vDBE",
+ "version": "0.2",
+ "customizationUuid": "1",
+ "inputs": {},
+ "commands": {},
+ "properties": {
+ "nf_naming": "{ecomp_generated_naming=true}",
+ "multi_stage_design": "false",
+ "oam_vfc_instance_group_function": "oambbb",
+ "availability_zone_max_count": "1",
+ "oam_network_collection_function": "oamaaa",
+ "ecomp_generated_naming": "true",
+ "untr_vfc_instance_group_function": "untrbbb",
+ "untr_network_collection_function": "untraaa"
+ },
+ "type": "VF",
+ "modelCustomizationName": "vDBE 0",
+ "vfModules": {
+ "vdbe0..Vdbe..main..module-0": {
+ "uuid": "25a4d009-2f5a-44b4-b02a-62c584c15912",
+ "invariantUuid": "614afb1a-3e7e-44e9-90ab-424d0070c781",
+ "customizationUuid": "3443b341-7b0b-498c-a84a-a7ee736cba7e",
+ "description": null,
+ "name": "Vdbe..main..module-0",
+ "version": "1",
+ "modelCustomizationName": "Vdbe..main..module-0",
+ "properties": {
+ "minCountInstances": 1,
+ "maxCountInstances": 1,
+ "initialCount": 1,
+ "vfModuleLabel": "main"
+ },
+ "inputs": {},
+ "volumeGroupAllowed": false
+ }
+ },
+ "volumeGroups": {},
+ "vfcInstanceGroups": {
+ "untr_group": {
+ "uuid": "5fca04e2-a889-4579-8338-f60f1bf285fa",
+ "invariantUuid": "fb1e384b-117a-46ae-9ad1-bf2f1ee1e49f",
+ "name": "untr_group",
+ "version": "1",
+ "vfcInstanceGroupProperties": {
+ "vfcParentPortRole": "untr",
+ "networkCollectionFunction": "untraaa",
+ "vfcInstanceGroupFunction": null,
+ "subinterfaceRole": "untr"
+ }
+ },
+ "oam_group": {
+ "uuid": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "invariantUuid": "9384abf9-1231-4da4-bd8d-89e4d2f8a749",
+ "name": "oam_group",
+ "version": "1",
+ "vfcInstanceGroupProperties": {
+ "vfcParentPortRole": "untr",
+ "networkCollectionFunction": "untraaa",
+ "vfcInstanceGroupFunction": null,
+ "subinterfaceRole": "untr"
+ }
+ }
+ }
+ }
+ },
+ "networks": {},
+ "collectionResource": {},
+ "configurations": {},
+ "serviceProxies": {},
+ "vfModules": {
+ "vdbe0..Vdbe..main..module-0": {
+ "uuid": "25a4d009-2f5a-44b4-b02a-62c584c15912",
+ "invariantUuid": "614afb1a-3e7e-44e9-90ab-424d0070c781",
+ "customizationUuid": "3443b341-7b0b-498c-a84a-a7ee736cba7e",
+ "description": null,
+ "name": "Vdbe..main..module-0",
+ "version": "1",
+ "modelCustomizationName": "Vdbe..main..module-0",
+ "properties": {
+ "minCountInstances": 1,
+ "maxCountInstances": 1,
+ "initialCount": 1,
+ "vfModuleLabel": "main"
+ },
+ "inputs": {},
+ "volumeGroupAllowed": false
+ }
+ },
+ "volumeGroups": {},
+ "pnfs": {}
+ };
+ let serviceInstanceId: string = "6bce7302-70bd-4057-b48e-8d5b99e686ca";
+ let networkInstanceGroups = {
+ "untr_group": {
+ "instance-group": {
+ "instance-group-role": "JZmha7QSS4tJ",
+ "model-invariant-id": "model-id3",
+ "model-version-id": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "id": "AAI-12002-test3-vm230w",
+ "description": "a9DEa0kpY",
+ "instance-group-type": "type",
+ "resource-version": "1520888659539",
+ "instance-group-name": "wKmBXiO1xm8bK",
+ "instance-group-function": "testfunction2",
+ "relationship-list": {
+ "relationship": [
+ {
+ "relationDataList": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "AAI-12002-vm230w"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "AAI-region-vm230w"
+ }
+ ],
+ "relatedToPropertyList": [
+ {
+ "property-key": "cloud-region.owner-defined-type",
+ "property-value": null
+ }
+ ],
+ "related-to": "cloud-region",
+ "related-link": "/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/AAI-12002-vm230w/AAI-region-vm230w",
+ "relationship-label": "org.onap.relationships.inventory.Uses",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "AAI-12002-vm230w"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "AAI-region-vm230w"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "cloud-region.owner-defined-type",
+ "property-value": null
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ "oam_group": {
+ "instance-group": {
+ "instance-group-role": "JZmha7QSS4tJ",
+ "model-invariant-id": "model-id3",
+ "model-version-id": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "id": "AAI-12002-test3-vm230w",
+ "description": "a9DEa0kpY",
+ "instance-group-type": "type",
+ "resource-version": "1520888659539",
+ "instance-group-name": "wKmBXiO1xm8bK",
+ "instance-group-function": "testfunction2",
+ "relationship-list": {
+ "relationship": [
+ {
+ "relationDataList": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "AAI-12002-vm230w"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "AAI-region-vm230w"
+ }
+ ],
+ "relatedToPropertyList": [
+ {
+ "property-key": "cloud-region.owner-defined-type",
+ "property-value": null
+ }
+ ],
+ "related-to": "cloud-region",
+ "related-link": "/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/AAI-12002-vm230w/AAI-region-vm230w",
+ "relationship-label": "org.onap.relationships.inventory.Uses",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "AAI-12002-vm230w"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "AAI-region-vm230w"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "cloud-region.owner-defined-type",
+ "property-value": null
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ };
+ let expectedResult = {
+ "requestInfo": {
+ "productFamilyId": "e433710f-9217-458d-a79d-1c7aff376d89",
+ "source": "VID",
+ "requestorId": "az2016",
+ "suppressRollback": false
+ },
+ "lineOfBusiness": Object({ lineOfBusinessName: "ecomp" }),
+ "cloudConfiguration": {
+ "lcpCloudRegionId": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86"
+ },
+ "platform": Object({ platformName: "plat1" }),
+ "modelInfo": {
+ modelCustomizationId :'1',
+ "modelVersionId": "61535073-2e50-4141-9000-f66fea69b433",
+ "modelCustomizationName": "vDBE 0",
+ "modelName": "vDBE",
+ "modelInvariantId": "fcdf49ce-6f0b-4ca2-b676-a484e650e734",
+ "modelType": "vnf",
+ "modelVersion": "0.2"
+ },
+ "requestParameters": {
+ "userParams": [],
+ "testApi": "GR_API"
+ },
+ "relatedInstanceList": [
+ {
+ "relatedInstance": {
+ "instanceId": "6bce7302-70bd-4057-b48e-8d5b99e686ca",
+ "modelInfo": {
+ "modelVersionId": "6bce7302-70bd-4057-b48e-8d5b99e686ca",
+ "modelName": "vDBE_srv",
+ "modelInvariantId": "9aa04749-c02c-432d-a90c-18caa361c833",
+ "modelType": "service",
+ "modelVersion": "1.0"
+ }
+ }
+ },
+ {
+ "relatedInstance": {
+ "instanceId": "AAI-12002-test3-vm230w",
+ "modelInfo": {
+ "modelName": "oam_group",
+ "modelType": "networkCollection",
+ "modelVersion": "1",
+ "modelVersionId": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "modelInvariantId": "9384abf9-1231-4da4-bd8d-89e4d2f8a749"
+ }
+ }
+ },
+ {
+ "relatedInstance": {
+ "instanceId": "AAI-12002-test3-vm230w",
+ "modelInfo": {
+ "modelName": "oam_group",
+ "modelType": "networkCollection",
+ "modelVersion": "1",
+ "modelVersionId": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "modelInvariantId": "9384abf9-1231-4da4-bd8d-89e4d2f8a749"
+ }
+ }
+ }
+ ]
+ };
+
+
+ let actualResult_withEcompGeneratedNaming = <any>createRequest("az2016",userInputs_withEcompGeneratedNaming, service, serviceInstanceId, networkInstanceGroups,'vDBE 0','1');
+ expect(actualResult_withEcompGeneratedNaming).toEqual(expectedResult);
+ expectedResult["requestInfo"]["instanceName"] = "New Name";
+ let actualResult_withoutEcompGeneratedNaming = <any>createRequest("az2016",userInputs_withoutEcompGeneratedNaming, service, serviceInstanceId, networkInstanceGroups,'vDBE 0','1');
+ expect(actualResult_withoutEcompGeneratedNaming).toEqual(expectedResult);
+ done();
+ });
+});
diff --git a/vid-webpack-master/src/app/factories/mso.factory.ts b/vid-webpack-master/src/app/factories/mso.factory.ts
new file mode 100644
index 000000000..c26296edf
--- /dev/null
+++ b/vid-webpack-master/src/app/factories/mso.factory.ts
@@ -0,0 +1,92 @@
+import { RequestInfo, RequestDetails, ModelInfo, CloudConfiguration, LineOfBusiness, Platform, RelatedInstanceList, VfcModel } from "./models/requestDetails.model";
+import * as _ from "lodash";
+
+function extractModelInfoFromNodeTemplate(node: any, type: string) {
+ let modelInfo: ModelInfo = <ModelInfo>{};
+ if (node["customizationUuid"] !== undefined) {
+ modelInfo.modelCustomizationId = node["customizationUuid"];
+ }
+ if (node["modelCustomizationName"] !== undefined) {
+ modelInfo.modelCustomizationName = node["modelCustomizationName"];
+ }
+ modelInfo.modelVersionId = node["uuid"];
+ modelInfo.modelName = node["name"];
+ modelInfo.modelInvariantId = node["invariantUuid"];
+ modelInfo.modelType = type;
+ modelInfo.modelVersion = node["version"];
+ return modelInfo;
+}
+
+function extractRequestInfo(userInputs: any, userId: string): RequestInfo {
+ let requestInfo: RequestInfo = <RequestInfo>{};
+ if (userInputs["instanceName"] !== undefined) requestInfo.instanceName = userInputs["instanceName"];
+ requestInfo.productFamilyId = userInputs["productFamily"];
+ requestInfo.source = "VID";
+ requestInfo.suppressRollback = userInputs["rollback"] === "false";
+ requestInfo.requestorId = userId;
+ return requestInfo;
+}
+
+function extractPlatform(userInputs: any): Platform {
+ let platform: Platform = <Platform>{};
+ platform.platformName = userInputs["platformName"];
+ return platform;
+}
+
+function extractVfcGroupModelAccordingToUuid(vnfModel: any, vfcUuid: string) {
+ return _.find(vnfModel.vfcInstanceGroups, { uuid: vfcUuid });
+}
+
+function extractLineOfBusiness(userInputs: any) {
+ let lob: LineOfBusiness = <LineOfBusiness>{};
+ lob.lineOfBusinessName = userInputs["lineOfBusiness"];
+ return lob;
+}
+
+function extractCloudConfiguration(userInputs: any) {
+ let cloudConfig: CloudConfiguration = <CloudConfiguration>{};
+ cloudConfig.lcpCloudRegionId = userInputs["lcpRegion"];
+ cloudConfig.tenantId = userInputs["tenantId"];
+ return cloudConfig;
+}
+
+function extractModelInfoFromVfcNode(vfcModel: VfcModel): ModelInfo {
+ let modelinfo: ModelInfo = <ModelInfo>{};
+ modelinfo.modelName = vfcModel.name;
+ modelinfo.modelType = "networkCollection";
+ modelinfo.modelVersion = vfcModel.version;
+ modelinfo.modelVersionId = vfcModel.uuid;
+ modelinfo.modelInvariantId = vfcModel.invariantUuid;
+ return modelinfo;
+}
+
+export function createRequest(userId: string, userInputs: any, service: any, serviceInstanceId: string, networkInstanceGroups: any, vnfCustomizationName: string, vnfCustomizationId: string) {
+ let request: RequestDetails = <RequestDetails>{};
+ request.requestInfo = extractRequestInfo(userInputs, userId);
+ request.lineOfBusiness = extractLineOfBusiness(userInputs);
+ request.cloudConfiguration = extractCloudConfiguration(userInputs);
+ request.platform = extractPlatform(userInputs);
+ request.modelInfo = extractModelInfoFromNodeTemplate(service.vnfs[vnfCustomizationName], "vnf");
+ request.requestParameters = { userParams: [], testApi: sessionStorage.getItem("msoRequestParametersTestApiValue")};
+ request.relatedInstanceList = [];
+ let serviceRelatedInstance: RelatedInstanceList = {
+ relatedInstance: {
+ instanceId: serviceInstanceId,
+ modelInfo: extractModelInfoFromNodeTemplate(service.service, "service")
+ }
+ };
+ request.relatedInstanceList.push(serviceRelatedInstance);
+ _.forOwn(networkInstanceGroups, function(group) {
+ let modelUuid = group["instance-group"]["model-version-id"];
+ let vfcModel = extractVfcGroupModelAccordingToUuid(service.vnfs[vnfCustomizationName], modelUuid);
+ let networkInstanceGroup: RelatedInstanceList = {
+ relatedInstance: {
+ instanceId: group["instance-group"].id,
+ modelInfo: extractModelInfoFromVfcNode(vfcModel)
+ }
+ };
+ request.relatedInstanceList.push(networkInstanceGroup);
+ });
+
+ return request;
+}
diff --git a/vid-webpack-master/src/app/global.actions.ts b/vid-webpack-master/src/app/global.actions.ts
new file mode 100644
index 000000000..46575fb34
--- /dev/null
+++ b/vid-webpack-master/src/app/global.actions.ts
@@ -0,0 +1,23 @@
+import {Action, ActionCreator} from "redux";
+export const UPDATE_NAME= '[NAME] Update';
+export const UPDATE_FLAGS= '[FLAGS] Update';
+
+export interface UpdateGlobalAction extends Action {
+ name?: string;
+}
+
+export interface UpdateFlagsAction extends Action {
+ flags?: any;
+}
+
+export const updateName: ActionCreator<UpdateGlobalAction> =
+ (name) => ({
+ type: UPDATE_NAME,
+ name: name
+ });
+
+export const updateFlags: ActionCreator<UpdateFlagsAction> =
+ (flags) => ({
+ type: UPDATE_FLAGS,
+ flags: flags
+ });
diff --git a/vid-webpack-master/src/app/global.reducer.ts b/vid-webpack-master/src/app/global.reducer.ts
new file mode 100644
index 000000000..cffd34603
--- /dev/null
+++ b/vid-webpack-master/src/app/global.reducer.ts
@@ -0,0 +1,29 @@
+/* tslint:disable no-switch-case-fall-through */
+import {Action} from 'redux';
+import {UPDATE_FLAGS, UPDATE_NAME, UpdateFlagsAction, UpdateGlobalAction} from "./global.actions";
+
+
+
+export interface GlobalState {
+ name : string;
+ flags : { [key: string]: boolean };
+}
+
+const initialState: GlobalState = {
+ name : null,
+ flags : null
+};
+
+
+export const GlobalReducer =
+ function (state: GlobalState = initialState, action: Action): GlobalState {
+ switch (action.type) {
+ case UPDATE_NAME:
+ return Object.assign(state, state, (<UpdateGlobalAction>action));
+ case UPDATE_FLAGS:
+ Object.assign(state, (<UpdateFlagsAction>action));
+ return Object.assign({}, state);
+ default:
+ return state;
+ }
+ };
diff --git a/vid-webpack-master/src/app/healthStatus/health-status.component.html b/vid-webpack-master/src/app/healthStatus/health-status.component.html
new file mode 100644
index 000000000..600c873be
--- /dev/null
+++ b/vid-webpack-master/src/app/healthStatus/health-status.component.html
@@ -0,0 +1,36 @@
+<div class="row">
+ <div class="health-status-header">
+ <div>
+ <div class="row" style="margin-left: 0;">
+ <div>
+ <span class="title">Health Status </span>
+ </div>
+ <div class="lastUpdate">
+ <div style="float: left;margin-top: 3px;"><span>Last update: {{lastUpdatedDate | date:'MMM. dd, yyyy | HH:mm'}}</span>
+ </div>
+ <div class="refresh-btn" [ngClass]="{'spin' : !dataIsReady}" (click)="refreshData()">
+ <span class="icon-refresh"></span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="row">
+ <table id="health-status-table" class="table table-bordered">
+ <tbody>
+ <tr class="row spaceUnder" *ngFor="let componentStatus of componentStatuses" [attr.data-tests-id]="'component-'+componentStatus?.component">
+ <td class="col-md-1 col-xs-1 component-name"
+ [attr.data-tests-id]="'component-name-'+componentStatus?.component"
+ [ngClass]="isAvailable(componentStatus) ? 'border-is-ok': 'border-not-ok'">
+ {{componentStatus?.component}}
+ </td>
+ <td class="col-md-11 col-xs-3 component-metadata-cell"
+ [attr.data-tests-id]="'component-metadata-'+componentStatus?.component"
+ [ngClass]="isAvailable(componentStatus) ? 'border-is-ok': 'border-not-ok'">
+ <pre class="component-metadata">{{getMetadata(componentStatus) | json}}</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</div>
diff --git a/vid-webpack-master/src/app/healthStatus/health-status.component.scss b/vid-webpack-master/src/app/healthStatus/health-status.component.scss
new file mode 100644
index 000000000..0dda6b215
--- /dev/null
+++ b/vid-webpack-master/src/app/healthStatus/health-status.component.scss
@@ -0,0 +1,187 @@
+div.dataTables_wrapper {
+ width: 800px;
+ margin: 0 auto;
+}
+
+.row {
+ margin-left: 15px;
+ margin-right: 15px;
+}
+
+.health-status-header {
+ margin-top: 30px;
+ .title {
+ font-family: OpenSans-Semibold;
+ font-size: 24px;
+ color: #4A4A4A;
+ float: left;
+ }
+
+ .info {
+ width: 18px;
+ height: 18px;
+ border: 0;
+ background-size: auto 100%;
+ cursor: pointer;
+ float: left;
+ margin: 10px;
+ }
+
+ .refresh-btn {
+ float: left;
+ margin-top: 6px;
+ margin-left: 10px;
+ cursor: pointer;
+ }
+
+ .lastUpdate {
+ margin-top: 5px;
+ padding-top: 0px;
+ font-size: 15px;
+ border-left: 1px solid black;
+ float: left;
+ padding-left: 10px;
+ color: gray;
+ height: 26px;
+ margin-left: 10px;
+ }
+
+ .refreshBtn {
+ width: 18px;
+ height: 18px;
+ border: 0;
+ background-size: auto 100%;
+ outline: none;
+ margin-left: 10px;
+ background: transparent;
+ }
+
+ svg-icon use {
+ fill: #0000ff !important;
+ }
+
+ //.sub-title {
+ // font-family: OpenSans-Semibold;
+ // font-size: 14px;
+ // color: #4A4A4A;
+ // margin-left: 0;
+ //}
+}
+
+.loader {
+ border: 5px solid #f3f3f3;
+ border-radius: 50%;
+ border-top: 5px solid #3498db;
+ width: 170px;
+ height: 170px;
+ -webkit-animation: spin 2s linear infinite;
+ animation: spin 2s linear infinite;
+ position: absolute;
+ left: 50%;
+ right: 50%;
+ top: 50%;
+}
+
+/* Safari */
+@-webkit-keyframes spin {
+ 0% { -webkit-transform: rotate(0deg); }
+ 100% { -webkit-transform: rotate(360deg); }
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+
+.spin {
+ -webkit-animation: spin .4s infinite linear;
+ -moz-animation: spin .4s infinite linear;
+ -o-animation: spin .4s infinite linear;
+ animation: spin .4s infinite linear;
+ -webkit-transform-origin: 50% 44%;
+ transform-origin:50% 44%;
+ -ms-transform-origin:50% 44% /* IE 9 */
+}
+
+@-moz-keyframes spin {
+ from {
+ -moz-transform: rotate(0deg);
+ }
+ to {
+ -moz-transform: rotate(360deg);
+ }
+}
+
+@-webkit-keyframes spin {
+ from {
+ -webkit-transform: rotate(0deg);
+ }
+ to {
+ -webkit-transform: rotate(360deg);
+ }
+}
+
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.icon-refresh:before {
+ font-family: icomoon;
+ content: '\e936';
+}
+
+.row{
+ max-width: 1500px;
+}
+
+.red {
+ color: red;
+}
+
+.border-not-ok {
+ border : 2px solid red;
+}
+
+.border-is-ok {
+ border : 2px solid #2fcc66;
+}
+
+
+.component-name {
+ min-width: 100px;
+ vertical-align: middle;
+ text-align: center;
+ background: #f5f5f5;
+ border-right: unset;
+}
+
+.component-metadata-cell {
+ border-left: unset;
+}
+
+.component-metadata {
+ white-space: pre-wrap;
+ background-color: unset;
+ border: unset;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+}
+
+
+.table-bordered {
+ margin-top: 10px;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ overflow-x: auto;
+ display: block;
+ color: #5A5A5A;
+ border: none;
+ border-spacing: 0px 3px;
+ border-collapse: separate;
+}
diff --git a/vid-webpack-master/src/app/healthStatus/health-status.component.ts b/vid-webpack-master/src/app/healthStatus/health-status.component.ts
new file mode 100644
index 000000000..6a9ddfdd7
--- /dev/null
+++ b/vid-webpack-master/src/app/healthStatus/health-status.component.ts
@@ -0,0 +1,42 @@
+import { Component, OnInit } from '@angular/core';
+import {ExternalComponentStatus} from "../shared/models/externalComponentStatus";
+import {HealthStatusService} from "../shared/server/healthStatusService/health-status.service";
+
+@Component({
+ selector: 'app-health-status',
+ templateUrl: './health-status.component.html',
+ styleUrls: ['./health-status.component.scss']
+})
+export class HealthStatusComponent implements OnInit {
+ private componentStatuses: Array<ExternalComponentStatus> = [];
+ private dataIsReady: boolean;
+ private lastUpdatedDate: Date;
+
+ constructor(private _healthStatusService: HealthStatusService) {
+ }
+
+
+ ngOnInit() {
+ this.refreshData();
+ }
+
+ refreshData(): void {
+ this.dataIsReady = false;
+ this._healthStatusService.getProbe()
+ .subscribe((res: Array<ExternalComponentStatus>) => {
+ this.componentStatuses = res;
+ this.dataIsReady = true;
+ this.lastUpdatedDate = new Date();
+ })
+ }
+
+ getMetadata(status : ExternalComponentStatus):string {
+ let metadata = status.metadata;
+ delete metadata.rawData;
+ return metadata;
+ }
+
+ isAvailable(componentStatus: ExternalComponentStatus) {
+ return componentStatus.available;
+ }
+}
diff --git a/vid-webpack-master/src/app/home/home.component.e2e-spec.js b/vid-webpack-master/src/app/home/home.component.e2e-spec.js
new file mode 100644
index 000000000..41203f9d8
--- /dev/null
+++ b/vid-webpack-master/src/app/home/home.component.e2e-spec.js
@@ -0,0 +1,13 @@
+describe('Home', function () {
+
+ beforeEach(function () {
+ browser.get('/');
+ });
+
+ it('should have <my-home>', function () {
+ var home = element(by.css('vid-app my-home'));
+ expect(home.isPresent()).toEqual(true);
+ expect(home.getText()).toEqual("Home Works!");
+ });
+
+});
diff --git a/vid-webpack-master/src/app/home/home.component.html b/vid-webpack-master/src/app/home/home.component.html
new file mode 100644
index 000000000..604d9e1d0
--- /dev/null
+++ b/vid-webpack-master/src/app/home/home.component.html
@@ -0,0 +1,3 @@
+<p>
+ Home Works!
+</p>
diff --git a/vid-webpack-master/src/app/home/home.component.scss b/vid-webpack-master/src/app/home/home.component.scss
new file mode 100644
index 000000000..5db1e17a3
--- /dev/null
+++ b/vid-webpack-master/src/app/home/home.component.scss
@@ -0,0 +1,4 @@
+// component styles are encapsulated and only applied to their components
+* {
+ color: #FFEF00;
+}
diff --git a/vid-webpack-master/src/app/home/home.component.ts b/vid-webpack-master/src/app/home/home.component.ts
new file mode 100644
index 000000000..1adaf0ebf
--- /dev/null
+++ b/vid-webpack-master/src/app/home/home.component.ts
@@ -0,0 +1,30 @@
+import { Component, OnInit } from '@angular/core';
+import { SdcService } from '../services/sdc.service';
+import { DataService } from '../services/data.service';
+
+@Component({
+ selector: 'my-home',
+ templateUrl: './home.component.html',
+ styleUrls: ['./home.component.scss'],
+ providers: [SdcService, DataService]
+})
+export class HomeComponent implements OnInit {
+
+ constructor(private _sdcService: SdcService) {
+ // Do stuff
+ }
+
+ ngOnInit() {
+ console.log('Hello Home');
+ console.log('getServicesModels: ');
+ this._sdcService.getServicesModels().subscribe(
+ // onNext() function
+ value => console.log('value is ', value),
+ // onError() function
+ error => console.log('error is ', error),
+ // onComplete() function
+ () => console.log('completed')
+ );
+ }
+
+}
diff --git a/vid-webpack-master/src/app/instantiationStatus/InstantiationStatus.module.ts b/vid-webpack-master/src/app/instantiationStatus/InstantiationStatus.module.ts
new file mode 100644
index 000000000..01db0f187
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/InstantiationStatus.module.ts
@@ -0,0 +1,33 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { InputsModule } from '../modules/inputs.module';
+import { DataTableModule } from 'angular2-datatable';
+import { BootstrapModalModule } from 'ng2-bootstrap-modal';
+import { TooltipModule } from 'ngx-tooltip';
+import { InstantiationStatusComponent } from './instantiationStatus.component';
+import { InstantiationStatusComponentService } from './instantiationStatus.component.service';
+import { SharedModule } from '../shared/shared.module';
+import { AngularSvgIconModule } from 'angular-svg-icon';
+import { ContextMenuModule, ContextMenuService } from 'ngx-contextmenu';
+import {ModalModule, PopoverModule} from 'ngx-bootstrap';
+import {AuditInfoModalComponent} from "./auditInfoModal/auditInfoModal.component";
+
+@NgModule({
+ imports: [
+ CommonModule,
+ FormsModule,
+ ReactiveFormsModule,
+ BootstrapModalModule,
+ DataTableModule,
+ TooltipModule,
+ ModalModule,
+ InputsModule,
+ AngularSvgIconModule,
+ ContextMenuModule,
+ SharedModule.forRoot(),
+ PopoverModule.forRoot()],
+ declarations: [InstantiationStatusComponent, AuditInfoModalComponent],
+ providers: [InstantiationStatusComponentService, ContextMenuService]
+})
+export class InstantiationStatusModule { }
diff --git a/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.html b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.html
new file mode 100644
index 000000000..9386af347
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.html
@@ -0,0 +1,84 @@
+<div class="modal fade" bsModal #auditInfoModal="bs-modal" [config]="{backdrop: 'static'}"
+ tabindex="-1" role="dialog" aria-labelledby="dialog-static-name">
+ <div id="audit-info-modal" class="">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" (click)="onCancelClick()">&times;</button>
+ <span [attr.data-tests-id]="'audit-info-title'" class="modal-title">{{title}}</span>
+ </div>
+ <div class="modal-body row">
+ <div class="col-md-4 left-panel">
+ <div id="service-model-name" class="row">SERVICE MODEL: {{serviceModelName}}</div>
+ <div class="row service-model">
+ <model-information [modelInformationItems]="modelInfoItems"></model-information>
+ </div>
+ </div>
+ <div class="col-md-8 right-panel">
+ <div class="row"><span class="table-title">VID status</span></div>
+ <div class="row">
+ <table id="service-instantiation-audit-info-vid" class="table table-bordered">
+ <thead class="thead-dark">
+ <tr class="row">
+ <th class="col-md-4" scope="col">Status</th>
+ <th class="col-md-4" scope="col">Status time</th>
+ <th class="col-md-4" scope="col">Final</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr class="row" *ngFor="let data of vidInfoData">
+ <td class="col-md-4" id="vidJobStatus" [attr.data-tests-id]="'vidJobStatus'">
+ <custom-ellipsis [id]="data?.jobStatus" [value]="data?.jobStatus | capitalizeAndFormat"></custom-ellipsis>
+ </td>
+ <td class="col-md-4" id="vidStatusTime">
+ <custom-ellipsis [id]="data?.vidCreated"
+ [value]="data?.createdDate | date:'MMM dd, yyyy HH:mm'"></custom-ellipsis>
+ </td>
+ <td class="col-md-4" id="vidFinalStatus">
+ <custom-ellipsis [id]="data?.final"
+ [value]="data?.final ? 'Yes' : 'No'"></custom-ellipsis>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="no-result" *ngIf="!isLoading && vidInfoData?.length == 0">There is no data.</div>
+ </div>
+
+ <div class="row"><span class="table-title">MSO status</span></div>
+ <table id="service-instantiation-audit-info-mso" class="table table-bordered">
+ <thead class="thead-dark row">
+ <tr class="row">
+ <th class="col-md-3" scope="col">Request ID</th>
+ <th class="col-md-3" scope="col">Status</th>
+ <th class="col-md-3" scope="col">Status time</th>
+ <th class="col-md-3" scope="col">Additional info</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr class="row" *ngFor="let data of msoInfoData">
+ <td class="col-md-3" id="msoRequestId">
+ <custom-ellipsis [id]="data?.requestId" [value]="data?.requestId"></custom-ellipsis>
+ </td>
+ <td class="col-md-3" id="msoJobStatus">
+ <custom-ellipsis [id]="data?.jobStatus" [value]="data?.jobStatus | capitalizeAndFormat"></custom-ellipsis>
+ </td>
+ <td class="col-md-3" id="msoStatusTime">
+ <custom-ellipsis [id]="data?.vidCreated"
+ [value]="data?.createdDate | date:'MMM dd, yyyy HH:mm'"></custom-ellipsis>
+ </td>
+ <td class="col-md-3" id="msoAdditionalInfo">
+ <custom-ellipsis [id]="data?.additionalInfo" [value]="data?.additionalInfo"></custom-ellipsis>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="no-result" *ngIf="!isLoading && msoInfoData?.length == 0">There is no data.</div>
+ </div>
+ </div>
+ <div class="modal-footer row">
+ <button id="cancelButton" type="button" class="btn btn-default cancel" (click)="onCancelClick()">
+ Close
+ </button>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.scss b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.scss
new file mode 100644
index 000000000..27b271496
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.scss
@@ -0,0 +1,159 @@
+.templatebody.modal-open{
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1040;
+ background-color: #000;
+ opacity: 0.5;
+}
+.modal{
+
+ #audit-info-modal {
+
+ .modal-content{
+ border-radius: 0px;
+ border: none;
+ .modal-header{
+ background: #009FDB;
+ font-size: 24px;
+ color: #ffffff;
+ .close{
+ font-size: 32px;
+ font-weight: 200;
+ color: #ffffff;
+ text-shadow: none;
+ filter: none;
+ opacity: 1;
+ &:hover{
+ color: #d2d2d2;
+ }
+ }
+ .modal-title{
+
+ }
+ }
+ .modal-body{
+ padding: 0px;
+ margin: 0px;
+ display: flex;
+ .left-panel{
+ background: #f2f2f2;
+ border-right: 1px solid #D2D2D2;
+ padding-right: 0px;
+ .row:first-child{
+ border-bottom: 1px solid #D2D2D2;
+ height: 50px;
+ font-size: 12px;
+ line-height: 50px;
+ padding-left: 30px;
+ font-weight: 700;
+ margin-right: 0px;
+ }
+ .service-model{
+ padding-left: 30px;
+ padding-top: 15px;
+ }
+ }
+ .right-panel{
+ padding: 30px 30px 15px 30px;
+ .row{
+ margin: 0px;
+ }
+ .table-title{
+ font-size: 12px;
+ text-transform: uppercase;
+ font-weight: bold;
+ }
+ .no-result{
+ margin-bottom: 20px;
+ text-align: center;
+ border: 1px solid #d2d2d2;
+ padding: 20px;
+ margin-top: -23px;
+ }
+
+ .table-bordered{
+ width: 100%;
+ margin-top: 10px;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ overflow-x: auto;
+ display: block;
+ color: #5A5A5A;
+
+ thead {
+ position: sticky;
+ top: 0;
+ z-index: 100;
+ display: block;
+ background: rgb(242, 242, 242);
+ border-bottom: 1px solid #d2d2d2;
+ tr {
+ display: flex;
+ th {
+ flex-grow: 1;
+ border-right: 1px solid #d2d2d2;
+ &:last-child{
+ border-right: none;
+ }
+ }
+ }
+ }
+
+ tbody {
+ border: none !important;
+ max-height: 152px;
+ display: block;
+
+ tr {
+ display: flex;
+ border-bottom: 1px solid #d2d2d2;
+ &:last-child{
+ border-bottom: none;
+ }
+ td {
+ border: none;
+ border-right: 1px solid #d2d2d2;
+ &:last-child{
+ border-right: none;
+ }
+ }
+ }
+ }
+
+ th {
+ background: #f2f2f2;
+ font-family: OpenSans-Semibold;
+ color: #000000;
+ font-weight: bold;
+ border: none;
+ }
+
+ tr.odd {
+ background-color: rgb(242, 242, 242);
+ }
+
+ tr:hover {
+ background: #e1e1e1;
+ }
+ }
+ }
+ }
+ .modal-footer{
+ margin: 0px;
+ .cancel{
+ width: 120px;
+ height: 36px;
+ background: #009fdb;
+ border-radius: 2px;
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #ffffff;
+ line-height: 16px;
+ }
+ }
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.service.ts b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.service.ts
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.service.ts
diff --git a/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.ts b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.ts
new file mode 100644
index 000000000..1cff97f5b
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.ts
@@ -0,0 +1,83 @@
+import {Component, ViewChild} from '@angular/core';
+import {Subject} from 'rxjs/Subject';
+import {ModalDirective} from 'ngx-bootstrap'
+import {Constants} from '../../shared/utils/constants';
+import {ModelInformationItem} from '../../shared/components/model-information/model-information.component';
+import {ServiceModel} from '../../shared/models/serviceModel';
+import {ServiceInfoService} from '../../shared/server/serviceInfo/serviceInfo.service';
+import {ServiceInfoModel} from '../../shared/server/serviceInfo/serviceInfo.model';
+import {AuditStatus} from '../../shared/server/serviceInfo/AuditStatus.model';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+@Component({
+ selector: 'audit-info-modal',
+ templateUrl: './auditInfoModal.component.html',
+ styleUrls: ['./auditInfoModal.component.scss']
+})
+export class AuditInfoModalComponent {
+ static openModal: Subject<ServiceInfoModel> = new Subject<ServiceInfoModel>();
+ @ViewChild('auditInfoModal') public auditInfoModal: ModalDirective;
+ title: string = Constants.AuditInfoModal.TITLE;
+ modelInfoItems: Array<ModelInformationItem> = [];
+ serviceModel: ServiceModel;
+ serviceModelName: string;
+ vidInfoData: Array<AuditStatus> = [];
+ msoInfoData: Array<AuditStatus> = [];
+ parentElementClassName = 'content';
+ isLoading = true;
+
+ constructor(private _serviceInfoService: ServiceInfoService, private _iframeService : IframeService) {
+ AuditInfoModalComponent.openModal.subscribe((jobData: ServiceInfoModel) => {
+ this.initializeProperties();
+ if (jobData) {
+ this.openAuditInfoModal(jobData);
+ _iframeService.addClassOpenModal(this.parentElementClassName);
+ this.serviceModelName = jobData.serviceModelName ? jobData.serviceModelName : '';
+ this.auditInfoModal.show();
+ } else {
+ _iframeService.removeClassCloseModal(this.parentElementClassName);
+ this.auditInfoModal.hide();
+ }
+ })
+ }
+
+ initializeProperties() : void {
+ this.modelInfoItems = null;
+ this.vidInfoData = [];
+ this.msoInfoData = [];
+ this.isLoading = true;
+ }
+
+ openAuditInfoModal(jobData: ServiceInfoModel): void {
+ this.modelInfoItems = this.createModelInformationItems(jobData);
+ this.initAuditInfoData(jobData['jobId']);
+ this.auditInfoModal.show();
+ }
+
+ initAuditInfoData(jobId: string) {
+ this._serviceInfoService.getJobAuditStatus(jobId)
+ .subscribe((res: Array<Array<AuditStatus>>) => {
+ this.vidInfoData = res[0];
+ this.msoInfoData = res[1];
+ this.isLoading = false;
+ });
+ }
+
+ createModelInformationItems(serviceModel: ServiceInfoModel): Array<ModelInformationItem> {
+ return [
+ new ModelInformationItem('Subscriber name', 'subscriberName', [serviceModel.subscriberName]),
+ new ModelInformationItem('Service type', 'serviceType', [serviceModel.serviceType]),
+ new ModelInformationItem('Service model version', 'serviceModelVersion', [serviceModel.serviceModelVersion]),
+ new ModelInformationItem('Service instance name', 'serviceInstanceName', [serviceModel.serviceInstanceName], '', true),
+ new ModelInformationItem('Service instance ID', 'serviceInstanceId', [serviceModel.serviceInstanceId]),
+ new ModelInformationItem('Requestor User ID', 'userId', [serviceModel.userId]),
+ ];
+ }
+
+ onCancelClick() {
+ this._iframeService.removeClassCloseModal(this.parentElementClassName);
+ this.initializeProperties();
+ this.auditInfoModal.hide();
+ }
+}
+
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.html b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.html
new file mode 100644
index 000000000..e0641d03b
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.html
@@ -0,0 +1,100 @@
+<div class="row">
+ <div class="instantiation-status-header">
+ <div>
+ <div class="row" style="margin-left: 0;">
+ <div>
+ <span class="title">Instantiation Status</span>
+ <span class="icon-info"
+ triggers="mouseenter:mouseleave"
+ popover="This table presents all the instantiation requests you made that are waiting, during or finished instantiating. You may see others requests by removing the Show only my requests checkmark."
+ placement="bottom"></span>
+
+ </div>
+ <div class="lastUpdate">
+ <div style="float: left;margin-top: 3px;"><span>Last update: {{lastUpdatedDate | date:'MMM. dd, yyyy | HH:mm'}}</span></div>
+ <div id="refresh-btn" class="refresh-btn" [ngClass]="{'spin' : !dataIsReady}" (click)="deactivateInterval(); refreshData(); activateInterval();">
+ <span class="icon-refresh"></span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="instantiation-status-data table-responsive">
+ <table id="instantiation-status" class="table table-bordered">
+ <thead class="thead-dark">
+ <tr>
+ <th scope="col" class="smallTd">User ID</th>
+ <th scope="col" class="normal">Model Name</th>
+ <th scope="col" class="normal">Instance Name</th>
+ <th scope="col" class="smallTd">Model version</th>
+ <th scope="col" class="normal">Subscriber</th>
+ <th scope="col" class="mediumTd">Service Type</th>
+ <th scope="col" class="normal">Region</th>
+ <th scope="col" class="mediumTd">Tenant</th>
+ <th scope="col" class="mediumTd">AIC Zone</th>
+ <th scope="col" class="mediumTd">Project</th>
+ <th scope="col" class="mediumTd">Owning entity</th>
+ <th scope="col" class="smallTd">Pause</th>
+ <th scope="col" class="mediumTd">Date</th>
+ <th scope="col" class="last">Status</th>
+ </tr>
+ </thead>
+ <tbody >
+ <tr *ngFor="let data of serviceInfoData; let i = index" [ngClass]="{'odd' : data.serviceIndex%2 == 1}" [id]="data.jobId" (mouseenter)="currentJobId = data?.jobId">
+ <td class="smallTd" id="userId"><custom-ellipsis [id]="data.userId" [value]="data.userId"></custom-ellipsis></td>
+ <td class="normal" id="serviceModelName"><custom-ellipsis [id]="data.serviceModelName" [value]="data.serviceModelName"></custom-ellipsis></td>
+ <td class="normal" id="serviceInstanceName"><custom-ellipsis [id]="data.serviceInstanceName" [value]="data.serviceInstanceName"></custom-ellipsis></td>
+ <td class="smallTd" id="serviceModelVersion"><custom-ellipsis [id]="data.serviceModelVersion" [value]="data.serviceModelVersion"></custom-ellipsis></td>
+ <td class="normal" id="subscriberName"><custom-ellipsis [id]="data.subscriberName" [value]="data.subscriberName"></custom-ellipsis></td>
+ <td class="mediumTd" id="serviceType"><custom-ellipsis [id]="data.serviceType" [value]="data.serviceType"></custom-ellipsis></td>
+ <td class="normal" id="regionId"><custom-ellipsis [id]="data.regionId" [value]="data.regionId"></custom-ellipsis></td>
+ <td class="mediumTd" id="tenantName"><custom-ellipsis [id]="data.tenantName" [value]="data.tenantName"></custom-ellipsis></td>
+ <td class="mediumTd" id="aicZoneName"><custom-ellipsis [id]="data.aicZoneName" [value]="data.aicZoneName"></custom-ellipsis></td>
+ <td class="mediumTd" id="project"><custom-ellipsis [id]="data.project" [value]="data.project"></custom-ellipsis></td>
+ <td class="mediumTd" id="owningEntityName"><custom-ellipsis [id]="data.owningEntityName" [value]="data.owningEntityName"></custom-ellipsis></td>
+ <td class="smallTd" id="pause"><custom-ellipsis [id]="data.pause" [value]="data.pause"></custom-ellipsis></td>
+ <td class="mediumTd" id="created"><custom-ellipsis [id]="data.created" [value]="data.created | date:'MMM. dd, yyyy HH:mm'"></custom-ellipsis></td>
+ <td class="last" id="jobStatus" [ngClass]="data.jobStatus">
+ <custom-popover [value]="data.serviceStatus.tooltip" style="float: left;">
+ <svg-icon id="jobStatusIcon-{{i}}" (click)="auditInfo(data)" svg-directive [fill]="data.serviceStatus.color" [widthViewBox]="27" [heightViewBox]="27"
+ src="./assets/img/{{data.serviceStatus.iconClassName}}.svg"></svg-icon>
+ </custom-popover>
+ <div class="menu-div" (click)="onContextMenu($event, data); currentJobId = data.jobId">
+ <span class="icon-menu"></span>
+ <context-menu>
+ <ng-template contextMenuItem (execute)="open($event?.item)" [enabled]="isOpenVisible">
+ <div [attr.data-tests-id]="'context-menu-open'">
+ <span class="context-menu-icon"><i class="fa fa-external-link" aria-hidden="true"></i></span>
+ Open
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem (execute)="auditInfo($event?.item)">
+ <div [attr.data-tests-id]="'context-menu-audit-info'">
+ <span class="context-menu-icon audit-icon"><i class="fa fa-info-circle" aria-hidden="true"></i></span>
+ Audit info
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem let-item (execute)="deleteItem($event?.item)" [enabled]="isDeleteEnabled">
+ <div [attr.data-tests-id]="'context-menu-delete'">
+ <span class="context-menu-icon"><i class="fa fa-trash-o" aria-hidden="true"></i></span>
+ Delete
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem let-item (execute)="hideItem($event?.item)" [enabled]="isHideEnabled">
+ <div [attr.data-tests-id]="'context-menu-hide'">
+ <span class="context-menu-icon"><i class="fa fa-eye-slash" aria-hidden="true"></i></span>
+ Hide request
+ </div>
+ </ng-template>
+ </context-menu>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <audit-info-modal></audit-info-modal>
+</div>
+
+
+
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.scss b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.scss
new file mode 100644
index 000000000..65c2400a3
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.scss
@@ -0,0 +1,277 @@
+
+.last {
+ position: sticky;
+ background: #f8f8f8;
+ right: 0;
+ padding-left: 15px;
+ padding-right: 15px;
+ width: 100px !important;
+ max-width: 100px !important;
+ min-width: 85px;
+}
+
+div.dataTables_wrapper {
+ width: 800px;
+ margin: 0 auto;
+}
+
+.row {
+ margin-left: 15px;
+ margin-right: 15px;
+}
+
+.instantiation-status-header {
+ margin-top: 30px;
+ .title {
+ font-family: OpenSans-Semibold;
+ font-size: 24px;
+ color: #4A4A4A;
+ float: left;
+ }
+
+ .info {
+ width: 18px;
+ height: 18px;
+ border: 0;
+ background-size: auto 100%;
+ cursor: pointer;
+ float: left;
+ margin: 10px;
+ }
+
+ .refresh-btn {
+ float: left;
+ margin-top: 6px;
+ margin-left: 10px;
+ cursor: pointer;
+ }
+
+ .lastUpdate {
+ margin-top: 5px;
+ padding-top: 0px;
+ font-size: 15px;
+ border-left: 1px solid black;
+ float: left;
+ padding-left: 10px;
+ color: gray;
+ height: 26px;
+ }
+
+ .refreshBtn {
+ width: 18px;
+ height: 18px;
+ border: 0;
+ background-size: auto 100%;
+ outline: none;
+ margin-left: 10px;
+ background: transparent;
+ }
+
+ svg-icon use {
+ fill: #0000ff !important;
+ }
+
+ .sub-title {
+ font-family: OpenSans-Semibold;
+ font-size: 14px;
+ color: #4A4A4A;
+ margin-left: 0;
+ }
+}
+
+.instantiation-status-data {
+ table {
+ width: 100%;
+ margin-top: 30px;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ overflow-x: auto;
+ display: block;
+ color: #5A5A5A;
+
+ }
+
+ thead {
+ position: sticky;
+ top: 0;
+ z-index: 100;
+ display: block;
+ }
+
+ thead th.normal, tbody td.normal {
+ min-width: 200px !important;
+ max-width: 200px;
+ }
+
+ thead th.smallTd ,tbody td.smallTd {
+ max-width: 100px !important;
+ min-width: 100px !important;
+ }
+
+ thead th.mediumTd ,tbody td.mediumTd {
+ max-width: 150px !important;
+ min-width: 150px !important;
+ }
+
+ tbody {
+ border: none !important;
+ max-height: 500px;
+ display: block;
+ }
+
+ th {
+ background: #f2f2f2;
+ font-family: OpenSans-Semibold;
+ color: #5A5A5A;
+ font-weight: bold;
+ }
+ .menu-div {
+ float: right;
+ border-left: 1px solid gray;
+ height: 23px;
+ }
+
+ tr.odd {
+ background-color: rgb(242, 242, 242);
+ }
+
+ tr:hover {
+ background: #e1e1e1;
+ }
+
+ thead {
+ background: rgb(242, 242, 242);
+ }
+
+ td#jobStatus {
+ cursor: pointer;
+ box-shadow: -2px 1px 5px -2px #aaa;
+ }
+}
+
+
+.loader {
+ border: 5px solid #f3f3f3;
+ border-radius: 50%;
+ border-top: 5px solid #3498db;
+ width: 170px;
+ height: 170px;
+ -webkit-animation: spin 2s linear infinite;
+ animation: spin 2s linear infinite;
+ position: absolute;
+ left: 50%;
+ right: 50%;
+ top: 50%;
+}
+
+/* Safari */
+@-webkit-keyframes spin {
+ 0% { -webkit-transform: rotate(0deg); }
+ 100% { -webkit-transform: rotate(360deg); }
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+
+.spin {
+ -webkit-animation: spin .4s infinite linear;
+ -moz-animation: spin .4s infinite linear;
+ -o-animation: spin .4s infinite linear;
+ animation: spin .4s infinite linear;
+ -webkit-transform-origin: 50% 44%;
+ transform-origin:50% 44%;
+ -ms-transform-origin:50% 44% /* IE 9 */
+}
+
+@-moz-keyframes spin {
+ from {
+ -moz-transform: rotate(0deg);
+ }
+ to {
+ -moz-transform: rotate(360deg);
+ }
+}
+
+@-webkit-keyframes spin {
+ from {
+ -webkit-transform: rotate(0deg);
+ }
+ to {
+ -webkit-transform: rotate(360deg);
+ }
+}
+
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.icon-refresh:before {
+ font-family: icomoon;
+ content: '\e936';
+}
+
+.icon-info {
+ float: left;
+ margin-top: 10px;
+ margin-left: 10px;
+ font-size: 17px;
+ margin-right: 10px
+}
+
+.icon-info:before {
+ font-family: icomoon;
+ content: '\e91f';
+}
+
+.context-menu-icon{
+ width: 25px;
+ float: left;
+}
+
+.icon-x:before {
+ font-family: icomoon;
+ content: '\e93d';
+}
+
+.icon-inprogress:before {
+ font-family: icomoon;
+ content: '\e899';
+}
+
+.icon-success_o:before {
+ font-family: icomoon;
+ content: '\e934';
+}
+
+.icon-menu:before {
+ font-family: icomoon;
+ content: '\e924';
+ font-size: 22px;
+}
+
+.icon-X_o:before {
+ font-family: icomoon;
+ content: '\e93d';
+ color: #D02B2B;
+}
+
+
+.icon-inprogress:before {
+ font-family: icomoon;
+ content: '\e941';
+ color: #009FDB;
+}
+
+.status-icon {
+ font-size: 20px;
+ margin-top: 0px;
+ height: 0;
+}
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.spec.ts b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.spec.ts
new file mode 100644
index 000000000..c9f434e99
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.spec.ts
@@ -0,0 +1,278 @@
+import {getTestBed, TestBed} from '@angular/core/testing';
+import {
+ INPROGRESS,
+ InstantiationStatusComponentService,
+ PAUSE,
+ PENDING,
+ ServiceStatus,
+ STOPED,
+ SUCCESS_CIRCLE,
+ X_O
+} from './instantiationStatus.component.service';
+import {ServiceInfoModel} from '../shared/server/serviceInfo/serviceInfo.model';
+import { Observable } from 'rxjs/Rx';
+
+describe('Instantiation Status Service', () => {
+ let injector;
+ let service: InstantiationStatusComponentService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [],
+ providers: [InstantiationStatusComponentService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(InstantiationStatusComponentService);
+ });
+
+ it('generateServiceInfoDataMapping should return mapping of arrays', (done: DoneFn) => {
+ let data : Array<ServiceInfoModel> = generateServiceInfoData();
+ let result = service.generateServiceInfoDataMapping(data);
+
+ expect(result['1']).toBeDefined();
+ expect(result['2']).toBeDefined();
+ expect(result['3']).toBeDefined();
+
+ expect(result['1'].length).toEqual(2);
+ expect(result['2'].length).toEqual(2);
+ expect(result['3'].length).toEqual(1);
+ done();
+ });
+
+ it('generateServiceInfoDataMapping if array is empty should return empty object', (done: DoneFn) => {
+ let result = service.generateServiceInfoDataMapping([]);
+
+ expect(result['1']).not.toBeDefined();
+ expect(result['2']).not.toBeDefined();
+ expect(result['3']).not.toBeDefined();
+ done();
+ });
+
+ it('convertObjectToArray', (done: DoneFn) => {
+
+ spyOn(service, 'convertObjectToArray').and.returnValue(
+ Observable.of([])
+ );
+
+ let data : Array<ServiceInfoModel> = generateServiceInfoData();
+ service.convertObjectToArray(data).subscribe((result) => {
+ expect(result).toBeDefined();
+ done();
+ });
+ });
+
+ it('getStatusTooltip should return status popover', (done: DoneFn) => {
+ let result : ServiceStatus = service.getStatus('pending');
+ expect(result.tooltip).toEqual('Pending: The service will automatically be sent for instantiation as soon as possible.');
+
+ result = service.getStatus('IN_PROGRESS');
+ expect(result.tooltip).toEqual('In-progress: the service is in process of instantiation.');
+
+ result = service.getStatus('PAUSED');
+ expect(result.tooltip).toEqual('Paused: Service has paused and waiting for your action.\n Select actions from the menu to the right.');
+
+ result = service.getStatus('FAILED');
+ expect(result.tooltip).toEqual('Failed: Service instantiation has failed, load the service to see the error returned.');
+
+ result = service.getStatus('COMPLETED');
+ expect(result.tooltip).toEqual('Completed successfully: Service is successfully instantiated.');
+
+ result = service.getStatus('STOPPED');
+ expect(result.tooltip).toEqual('Stopped: Due to previous failure, will not be instantiated.');
+ done();
+ });
+
+ it('getStatusTooltip should return correct icon per job status', (done: DoneFn) => {
+ let result : ServiceStatus = service.getStatus('pending');
+ expect(result.iconClassName).toEqual(PENDING);
+
+ result = service.getStatus('IN_PROGRESS');
+ expect(result.iconClassName).toEqual(INPROGRESS);
+
+ result = service.getStatus('PAUSED');
+ expect(result.iconClassName).toEqual(PAUSE);
+
+ result = service.getStatus('FAILED');
+ expect(result.iconClassName).toEqual(X_O);
+
+ result = service.getStatus('COMPLETED');
+ expect(result.iconClassName).toEqual(SUCCESS_CIRCLE);
+
+ result = service.getStatus('STOPPED');
+ expect(result.iconClassName).toEqual(STOPED);
+ done();
+ });
+
+
+ function generateServiceInfoData(){
+ return JSON.parse(JSON.stringify([
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "1",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "1",
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "1",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "1",
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "2",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "2",
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "2",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "2",
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "3",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "3",
+ "hidden": false
+ }
+ ]));
+ }
+
+});
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.ts b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.ts
new file mode 100644
index 000000000..293397cc9
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.ts
@@ -0,0 +1,75 @@
+import {Injectable} from '@angular/core';
+import {ServiceInfoModel, ServiceInfoUiModel} from '../shared/server/serviceInfo/serviceInfo.model';
+import {isNullOrUndefined} from "util";
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/observable/of';
+
+export let PENDING : string = "pending";
+export let INPROGRESS : string = "inprogress";
+export let PAUSE : string = "pause";
+export let X_O : string = "X_o";
+export let SUCCESS_CIRCLE : string = "success+Circle";
+export let STOPED : string = "stoped";
+
+
+@Injectable()
+export class InstantiationStatusComponentService {
+ generateServiceInfoDataMapping(arr: Array<ServiceInfoModel>) : { [serviceInstanceId: string]: Array<ServiceInfoModel>}{
+ let serviceInfoData: { [serviceInstanceId: string]: Array<ServiceInfoModel>; } = {};
+ for(let item of arr){
+ if(isNullOrUndefined(serviceInfoData[item.templateId])){
+ serviceInfoData[item.templateId] = [item];
+ }else {
+ serviceInfoData[item.templateId].push(item);
+ }
+ }
+ return serviceInfoData;
+ }
+
+ convertObjectToArray(arr: Array<ServiceInfoModel>) : Observable<Array<ServiceInfoUiModel>>{
+ const obj = this.generateServiceInfoDataMapping(arr);
+ let index:number = 0;
+ let result = [];
+ for(let item in obj) {
+ obj[item].map(item => {
+ item['serviceStatus'] = this.getStatus(item.jobStatus);
+ item['serviceIndex'] = index;
+ });
+ index++;
+ result = result.concat(obj[item]);
+ }
+
+ console.log(result);
+ return Observable.of(result);
+ }
+
+ getStatus(status : string) : ServiceStatus {
+ switch(status.toUpperCase()) {
+ case 'PENDING' :
+ return new ServiceStatus(PENDING, '#009FDB', 'Pending: The service will automatically be sent for instantiation as soon as possible.');
+ case 'IN_PROGRESS' :
+ return new ServiceStatus(INPROGRESS, '#009FDB', 'In-progress: the service is in process of instantiation.');
+ case 'PAUSED' :
+ return new ServiceStatus(PAUSE, '#009FDB', 'Paused: Service has paused and waiting for your action.\n Select actions from the menu to the right.');
+ case 'FAILED' :
+ return new ServiceStatus(X_O, '#D02B2B', 'Failed: Service instantiation has failed, load the service to see the error returned.');
+ case 'COMPLETED' :
+ return new ServiceStatus(SUCCESS_CIRCLE, '#53AD15', 'Completed successfully: Service is successfully instantiated.');
+ case 'STOPPED' :
+ return new ServiceStatus(STOPED, '#D02B2B', 'Stopped: Due to previous failure, will not be instantiated.');
+ }
+ }
+}
+
+
+export class ServiceStatus {
+ iconClassName : string;
+ color : string;
+ tooltip : string;
+
+ constructor(_iconClassName : string, _color : string, _tooltip : string){
+ this.iconClassName = _iconClassName;
+ this.color = _color;
+ this.tooltip = _tooltip;
+ }
+}
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.spec.ts b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.spec.ts
new file mode 100644
index 000000000..00b6a9945
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.spec.ts
@@ -0,0 +1,88 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import {InstantiationStatusComponent} from './instantiationStatus.component';
+import {ServiceInfoService} from '../shared/server/serviceInfo/serviceInfo.service';
+import {InstantiationStatusComponentService} from './instantiationStatus.component.service';
+import { ContextMenuModule, ContextMenuService } from 'ngx-contextmenu';
+import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ScrollToModule } from '@nicky-lenaers/ngx-scroll-to';
+import { ConfigurationService } from '../services/configuration.service';
+import { LogService } from '../shared/utils/log/log.service';
+
+describe('Instantiation Status Component', () => {
+ let component: InstantiationStatusComponent;
+ let fixture: ComponentFixture<InstantiationStatusComponent>;
+ let enableDeleteItems = [
+ { jobStatus:"PENDING" },
+ { jobStatus:"STOPPED" }];
+ let disableDeleteItems = [
+ { jobStatus:"COMPLETED" },
+ { jobStatus:"FAILED" },
+ {jobStatus:"IN_PROGRESS"},
+ {jobStatus:"UnknownOne"}];
+
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule, ContextMenuModule, ScrollToModule.forRoot()],
+ providers: [ServiceInfoService, InstantiationStatusComponentService, ContextMenuService, ConfigurationService, LogService],
+ declarations: [InstantiationStatusComponent],
+ schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(InstantiationStatusComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('component should initialize basic parameters', (done: DoneFn) => {
+ component.TIMER_TIME_IN_SECONDS = 2;
+ expect(component.TIMER_TIME_IN_SECONDS).toEqual(2);
+ expect(component.dataIsReady).toBeFalsy();
+ expect(component.lastUpdatedDate).toBeNull();
+ done();
+ });
+
+ it('component constructor should call activateInterval and ngOnInit', (done: DoneFn) => {
+ component.refreshData();
+ expect(component.dataIsReady).toBeFalsy();
+ done();
+ });
+
+ it('stopped and pending status isDeleteEnabled button should be enabled, not allowed delete statuses isDeleteEnabled button should be disabled', (done: DoneFn) => {
+ enableDeleteItems.forEach((item) => {
+ let isDeleteEnabled: boolean = component.isDeleteEnabled(item);
+ expect(isDeleteEnabled).toBeTruthy();
+ });
+
+ disableDeleteItems.forEach((item) => {
+ let isDeleteEnabled: boolean = component.isDeleteEnabled(item);
+ expect(isDeleteEnabled).toBeFalsy();
+ });
+ done();
+ });
+
+ it('[COMPLETED, FAILED, STOPPED] status isHideEnable button should be enabled, [IN_PROGRESS, PAUSE, PENDING] status isHideEnable button should be disabled', (done: DoneFn) => {
+ const enableHideItems = [
+ { jobStatus:"COMPLETED" },
+ { jobStatus:"FAILED" },
+ { jobStatus:"STOPPED" }];
+ enableHideItems.forEach((item) => {
+ let isDeleteEnabled: boolean = component.isHideEnabled(item);
+ expect(isDeleteEnabled).toBeTruthy();
+ });
+
+ const disableHideItems = [
+ { jobStatus:"IN_PROGRESS" },
+ { jobStatus:"PAUSE" },
+ { jobStatus:"PENDING" },
+ { jobStatus:"NOT_MATTER"}];
+ disableHideItems.forEach((item) => {
+ let isDeleteEnabled: boolean = component.isHideEnabled(item);
+ expect(isDeleteEnabled).toBeFalsy();
+ });
+ done();
+ });
+});
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.ts b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.ts
new file mode 100644
index 000000000..ed45ce43c
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.ts
@@ -0,0 +1,145 @@
+import {AfterViewChecked, Component, ViewChild} from '@angular/core';
+import {ServiceInfoService} from '../shared/server/serviceInfo/serviceInfo.service';
+import {ServiceInfoModel} from '../shared/server/serviceInfo/serviceInfo.model';
+import {InstantiationStatusComponentService} from './instantiationStatus.component.service';
+import {ContextMenuComponent, ContextMenuService} from 'ngx-contextmenu';
+import {AuditInfoModalComponent} from "./auditInfoModal/auditInfoModal.component";
+import * as _ from 'lodash';
+import {ScrollToConfigOptions, ScrollToService} from '@nicky-lenaers/ngx-scroll-to';
+import {ConfigurationService} from "../services/configuration.service";
+import {LogService} from '../shared/utils/log/log.service';
+
+
+@Component({
+ selector : 'instantiation-status',
+ templateUrl : './instantiationStatus.component.html',
+ styleUrls : ['./instantiationStatus.component.scss']
+})
+export class InstantiationStatusComponent implements AfterViewChecked{
+
+
+ TIMER_TIME_IN_SECONDS : number = 0;
+ timer = null;
+ dataIsReady : boolean = false;
+ scroll : boolean = false;
+ lastUpdatedDate: Date = null;
+ currentJobId: string = null;
+ instantiationStatusComponentService: InstantiationStatusComponentService;
+ configurationService : ConfigurationService;
+ serviceInfoData: Array<ServiceInfoModel> = null;
+ @ViewChild(ContextMenuComponent) public contextMenu: ContextMenuComponent;
+
+ constructor(private _serviceInfoService: ServiceInfoService,
+ private _instantiationStatusComponentService : InstantiationStatusComponentService,
+ private _contextMenuService: ContextMenuService,
+ private _configurationService : ConfigurationService,
+ private _scrollToService: ScrollToService,
+ private _logService : LogService) {
+ this.instantiationStatusComponentService = _instantiationStatusComponentService;
+ this.configurationService = this._configurationService;
+ this.configurationService.getConfiguration("refreshTimeInstantiationDashboard").subscribe(response => {
+ this.TIMER_TIME_IN_SECONDS = _.isNumber(response) ? response : 0;
+ this.activateInterval();
+ this.refreshData();
+ });
+ }
+
+ activateInterval() {
+ if (this.TIMER_TIME_IN_SECONDS > 0) {
+ this.timer = setInterval(() => {
+ this.refreshData();
+ }, this.TIMER_TIME_IN_SECONDS * 1000);
+ }
+ }
+
+ deactivateInterval() {
+ clearInterval(this.timer);
+ }
+
+ refreshData(): void {
+ this.dataIsReady = false;
+ this._serviceInfoService.getServicesJobInfo(true)
+ .subscribe((res: Array<ServiceInfoModel>) => {
+ this._instantiationStatusComponentService.convertObjectToArray(res).subscribe((res) => {
+ this._logService.info('refresh instantiation status table', res);
+ this.dataIsReady = true;
+ this.lastUpdatedDate = new Date();
+ if (!_.isEqual(this.serviceInfoData, res)) {
+ this.serviceInfoData = res;
+ this.scroll = true;
+ }
+ });
+ })
+ }
+
+ ngAfterViewChecked(){
+ if (this.scroll) {
+ this.scrollToElement();
+ this.scroll = false;
+ }
+ }
+
+
+
+ isDeleteEnabled(item):boolean {
+ return _.includes(['PENDING', 'STOPPED'], item.jobStatus);
+ }
+
+ deleteItem(item): void {
+ this._serviceInfoService.deleteJob(item.jobId).subscribe(() => {
+ this.refreshData();
+ });
+ }
+
+ hideItem(item): void {
+ this._serviceInfoService.hideJob(item.jobId).subscribe(() => {
+ this.refreshData();
+ });
+ }
+
+ auditInfo(jobData : ServiceInfoModel): void {
+ AuditInfoModalComponent.openModal.next(jobData);
+
+ }
+
+ isOpenVisible(item):boolean {
+ return _.includes(['COMPLETED', 'PAUSE'], item.jobStatus);
+ }
+
+ open(item): void {
+ let query =
+ `subscriberId=${item['subscriberName']}&` +
+ `serviceType=${item['serviceType']}&` +
+ `serviceInstanceId=${item['serviceInstanceId']}`;
+
+ window.parent.location.assign('../../serviceModels.htm#/instantiate?' + query);
+ }
+
+ public onContextMenu($event: MouseEvent, item: any): void {
+ this._contextMenuService.show.next({
+ contextMenu: this.contextMenu,
+ event: $event,
+ item: item,
+ });
+ $event.preventDefault();
+ $event.stopPropagation();
+ }
+
+ getImagesSrc(imageName : string) : string {
+ return './' + imageName + '.svg';
+ }
+
+ isHideEnabled(item: any):boolean {
+ return _.includes(['COMPLETED', 'FAILED', 'STOPPED'], item.jobStatus);
+ }
+ scrollToElement() {
+ if(this.currentJobId){
+ const config: ScrollToConfigOptions = {
+ target: this.currentJobId,
+ duration: 50,
+ offset: -35 //header height
+ };
+ this._scrollToService.scrollTo(config);
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/modules/inputs.module.ts b/vid-webpack-master/src/app/modules/inputs.module.ts
new file mode 100644
index 000000000..cb5f914cd
--- /dev/null
+++ b/vid-webpack-master/src/app/modules/inputs.module.ts
@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { DynamicInputsComponent } from '../components/dynamic-inputs/dynamic-inputs.component';
+import { AngularMultiSelectModule } from "angular2-multiselect-dropdown";
+import { DynamicInputLabelPipe } from '../shared/pipes/dynamicInputLabel/dynamic-input-label.pipe';
+
+
+@NgModule({
+ imports: [
+ CommonModule, FormsModule, ReactiveFormsModule, AngularMultiSelectModule
+ ],
+ providers: [],
+ declarations: [ DynamicInputLabelPipe, DynamicInputsComponent ],
+ entryComponents: [],
+ exports: [ DynamicInputLabelPipe, DynamicInputsComponent ]
+
+})
+
+export class InputsModule { }
diff --git a/vid-webpack-master/src/app/service.actions.ts b/vid-webpack-master/src/app/service.actions.ts
new file mode 100644
index 000000000..a62fec673
--- /dev/null
+++ b/vid-webpack-master/src/app/service.actions.ts
@@ -0,0 +1,197 @@
+import { Action, ActionCreator } from "redux";
+import { LcpRegionsAndTenants } from "./shared/models/lcpRegionsAndTenants";
+import { ServiceInstance } from "./shared/models/serviceInstance";
+import { SelectOptionInterface } from "./shared/models/selectOption";
+import { ServiceType } from "./shared/models/serviceType";
+import { VnfInstance } from "./shared/models/vnfInstance";
+
+export const UPDATE_MODEL = "[MODEL] Update";
+export const UPDATE_SERVICE_INSTANCE = "[SERVICE INSTANCE] Update";
+export const UPDATE_VNF_INSTANCE = "[VNF INSTANCE] Update";
+export const UPDATE_VF_MODULE = "[VF MODULE] Update";
+export const CREATE_VF_MODULE = "[VF MODULE] Create";
+
+export const UPDATE_LCP_REGIONS_AND_TENANTS = "[LCP_REGIONS_AND_TENANTS] Update";
+export const UPDATE_SUBSCRIBERS = "[SUBSCRIBERS] Update";
+export const UPDATE_PRODUCT_FAMILIES = "[PRODUCT_FAMILIES] Update";
+export const UPDATE_SERVICE_TYPES = "[SERVICE_TYPE] Update";
+export const UPDATE_AIC_ZONES = "[AIC_ZONES] Update";
+export const DELETE_SERVICE_INSTANCE = "[SERVICE_INSTANCE] Delete";
+export const DELETE_VNF_INSTANCE = "[VNF_INSTANCE] Delete";
+export const DELETE_VNF_MODULE_INSTANCE = "[VNF_MODULE_INSTANCE] Delete";
+export const UPDATE_CATEGORY_PARAMETERS = "[CATEGORY_PARAMETERS] Update";
+export const UPDATE_NETWORK_FUNCTION = "[UPDATE_NETWORK_FUNCTION] Update";
+export const UPDATE_USER_ID = "[UPDATE_USER_ID] Update";
+
+
+export interface UpdateServiceModelAction extends Action {
+ serviceHierarchy?: any;
+}
+
+export interface UpdateNetworkCollectionFunction extends Action {
+ networksAccordingToNetworkCollection: any;
+ network_function: any;
+}
+
+export interface UpdateServiceInstanceAction extends Action {
+ serviceUuid?: string;
+ serviceInstance?: ServiceInstance;
+}
+
+export interface UpdateVFModuleInstanceAction extends Action {
+ vfInstance: any;
+ vfId: string;
+ serviceUuid: string;
+}
+
+export interface CreateVFModuleInstanceAction extends Action {
+ vfInstance: any;
+ vfId: string;
+ serviceUuid: string;
+ index : number
+}
+
+export interface UpdateUserIdAction extends Action {
+ userId: string;
+}
+
+export interface UpdateVnfInstanceAction extends Action {
+ vnfInstance?: VnfInstance;
+ vnfModelName?: string;
+ serviceUuid?: string;
+}
+
+export interface UpdateLcpRegionsAndTenantsAction extends Action {
+ lcpRegionsAndTenants?: LcpRegionsAndTenants;
+}
+
+export interface UpdateSubscribersAction extends Action {
+ subscribers?: SelectOptionInterface[];
+}
+
+export interface UpdateProductFamiliesAction extends Action {
+ productFamilies?: SelectOptionInterface[];
+}
+
+export interface UpdateAicZonesAction extends Action {
+ aicZones?: SelectOptionInterface[];
+}
+
+export interface UpdateServiceTypesAction extends Action {
+ serviceTypes?: ServiceType[];
+ subscriberId: string;
+}
+
+export interface DeleteServiceInstanceAction extends Action {
+ serviceUuid?: string;
+}
+
+export interface DeleteVnfInstanceAction extends Action {
+ modelName?: string;
+ serviceModelId: string;
+}
+
+export interface DeleteVfModuleInstanceAction extends Action {
+ modelName?: string;
+ serviceModelId?: string;
+ vfName?: string;
+}
+
+export interface UpdateCategoryParametersAction extends Action {
+ categoryParameters?: string;
+}
+
+export const updateModel: ActionCreator<UpdateServiceModelAction> = serviceHierarchy => ({
+ type: UPDATE_MODEL,
+ serviceHierarchy: serviceHierarchy
+});
+
+export const updateServiceInstance: ActionCreator<UpdateServiceInstanceAction> = (serviceInstance, serviceUuid) => ({
+ type: UPDATE_SERVICE_INSTANCE,
+ serviceInstance: serviceInstance,
+ serviceUuid: serviceUuid
+});
+
+export const updateVFModuleInstance: ActionCreator<UpdateVFModuleInstanceAction> = (vfInstance, vfId, serviceUuid) => ({
+ type: UPDATE_VF_MODULE,
+ vfInstance: vfInstance,
+ vfId: vfId,
+ serviceUuid: serviceUuid
+})
+
+export const createVFModuleInstance: ActionCreator<CreateVFModuleInstanceAction> = (vfInstance, vfId, serviceUuid, index) => ({
+ type: CREATE_VF_MODULE,
+ vfInstance: vfInstance,
+ vfId: vfId,
+ serviceUuid: serviceUuid,
+ index : index
+})
+
+
+
+export const updateVNFInstance: ActionCreator<UpdateVnfInstanceAction> = (vnfInstance, vnfModelName, serviceUuid) => ({
+ type: UPDATE_VNF_INSTANCE,
+ vnfInstance: vnfInstance,
+ vnfModelName: vnfModelName,
+ serviceUuid: serviceUuid
+});
+
+export const updateLcpRegionsAndTenants: ActionCreator<UpdateLcpRegionsAndTenantsAction> = lcpRegionsAndTenants => ({
+ type: UPDATE_LCP_REGIONS_AND_TENANTS,
+ lcpRegionsAndTenants: lcpRegionsAndTenants
+});
+
+export const updateSubscribers: ActionCreator<UpdateSubscribersAction> = subscribers => ({
+ type: UPDATE_SUBSCRIBERS,
+ subscribers: subscribers
+});
+
+export const updateProductFamilies: ActionCreator<UpdateProductFamiliesAction> = productFamilies => ({
+ type: UPDATE_PRODUCT_FAMILIES,
+ productFamilies: productFamilies
+});
+
+export const updateAicZones: ActionCreator<UpdateAicZonesAction> = aicZones => ({
+ type: UPDATE_AIC_ZONES,
+ aicZones: aicZones
+});
+
+export const updateUserId: ActionCreator<UpdateUserIdAction> = userId => ({
+ type: UPDATE_USER_ID,
+ userId: userId
+});
+
+export const updateCategoryParameters: ActionCreator<UpdateCategoryParametersAction> = categoryParameters => ({
+ type: UPDATE_CATEGORY_PARAMETERS,
+ categoryParameters: categoryParameters
+});
+
+export const updateServiceTypes: ActionCreator<UpdateServiceTypesAction> = (serviceTypes, subscriberId) => ({
+ type: UPDATE_SERVICE_TYPES,
+ serviceTypes: serviceTypes,
+ subscriberId: subscriberId
+});
+
+export const updateNetworkCollectionFunction: ActionCreator<UpdateNetworkCollectionFunction> = (ncf, networksAccordingToNetworkCollection) => ({
+ type: UPDATE_NETWORK_FUNCTION,
+ networksAccordingToNetworkCollection: networksAccordingToNetworkCollection["results"],
+ network_function: ncf
+});
+
+export const deleteServiceInstance: ActionCreator<DeleteServiceInstanceAction> = serviceUuid => ({
+ type: DELETE_SERVICE_INSTANCE,
+ serviceUuid: serviceUuid
+});
+
+export const deleteVnfInstance: ActionCreator<DeleteVnfInstanceAction> = (modelName, serviceModelId) => ({
+ type: DELETE_VNF_INSTANCE,
+ modelName: modelName,
+ serviceModelId: serviceModelId
+});
+
+export const deleteVfModuleInstance: ActionCreator<DeleteVfModuleInstanceAction> = (modelName, serviceModelId, vfName) => ({
+ type: DELETE_VNF_MODULE_INSTANCE,
+ modelName: modelName,
+ serviceModelId: serviceModelId,
+ vfName: vfName
+});
diff --git a/vid-webpack-master/src/app/service.reducer.spec.ts b/vid-webpack-master/src/app/service.reducer.spec.ts
new file mode 100644
index 000000000..f734979ac
--- /dev/null
+++ b/vid-webpack-master/src/app/service.reducer.spec.ts
@@ -0,0 +1,286 @@
+import { LcpRegionsAndTenants } from './shared/models/lcpRegionsAndTenants';
+import { ServiceReducer, ServiceState } from './service.reducer';
+import { CategoryParams } from './shared/models/categoryParams';
+import {
+ DELETE_VNF_INSTANCE, DELETE_VNF_MODULE_INSTANCE, DeleteVfModuleInstanceAction,
+ DeleteVnfInstanceAction,
+ UPDATE_AIC_ZONES,
+ UPDATE_LCP_REGIONS_AND_TENANTS,
+ UPDATE_PRODUCT_FAMILIES,
+ UPDATE_SERVICE_INSTANCE,
+ UPDATE_SUBSCRIBERS,
+ UPDATE_USER_ID,
+ UPDATE_VNF_INSTANCE,
+ UpdateAicZonesAction,
+ UpdateProductFamiliesAction, UpdateServiceInstanceAction,
+ UpdateSubscribersAction, UpdateUserIdAction,
+ UpdateVnfInstanceAction
+} from './service.actions';
+import { VnfInstance } from './shared/models/vnfInstance';
+import { ServiceInstance } from './shared/models/serviceInstance';
+import { LcpRegion } from './shared/models/lcpRegion';
+import { Tenant } from './shared/models/tenant';
+import { SelectOption } from './shared/models/selectOption';
+
+
+const initialState: ServiceState = {
+ serviceHierarchy: {},
+ serviceInstance: {},
+ lcpRegionsAndTenants: new LcpRegionsAndTenants(),
+ subscribers: null,
+ productFamilies: null,
+ serviceTypes: {},
+ aicZones: null,
+ categoryParameters: new CategoryParams()
+};
+
+
+describe('service reducer', () => {
+ const userId: string = 'userId';
+ it('should handle initial state', () => {
+ expect(ServiceReducer(undefined, <any>{})).toEqual(initialState);
+ });
+
+ it('#UPDATE_USER_ID : should update userId ', (done: DoneFn) => {
+ expect(ServiceReducer(<any>{},
+ <UpdateUserIdAction>{
+ type: UPDATE_USER_ID,
+ userId: userId
+ }
+ )['userId']).toEqual(userId);
+ done();
+ });
+
+ it('#UPDATE_SERVICE_INSTANCE : should update service instance with service id ', (done: DoneFn) => {
+ const serviceUuid:string = 'serviceUuid';
+
+ let serviceInstanceObject : ServiceInstance = {
+ instanceName: 'instanceName',
+ isUserProvidedNaming: false,
+ globalSubscriberId: 'globalSubscriberId',
+ productFamilyId: 'productFamilyId',
+ subscriptionServiceType: 'subscriptionServiceType',
+ lcpCloudRegionId: 'lcpCloudRegionId',
+ tenantId: 'tenantId',
+ tenantName: 'tenantName',
+ aicZoneId: 'aicZoneId',
+ aicZoneName: 'aicZoneName',
+ projectName: 'projectName',
+ owningEntityId: 'owningEntityId',
+ owningEntityName: 'owningEntityName',
+ pause: false,
+ bulkSize: 1,
+ vnfs: {},
+ instanceParams : {},
+ rollbackOnFailure: false,
+ subscriberName: 'subscriberName'
+ };
+
+ let serviceState = ServiceReducer(<any>{serviceInstance : {}},
+ <UpdateServiceInstanceAction>{
+ type: UPDATE_SERVICE_INSTANCE,
+ serviceUuid: serviceUuid,
+ serviceInstance : serviceInstanceObject
+ }).serviceInstance['serviceUuid'];
+
+ expect(serviceState.instanceName).toEqual(serviceInstanceObject.instanceName);
+ expect(serviceState.isUserProvidedNaming).toEqual(serviceInstanceObject.isUserProvidedNaming);
+ expect(serviceState.globalSubscriberId).toEqual(serviceInstanceObject.globalSubscriberId);
+ expect(serviceState.productFamilyId).toEqual(serviceInstanceObject.productFamilyId);
+ expect(serviceState.subscriptionServiceType).toEqual(serviceInstanceObject.subscriptionServiceType);
+ expect(serviceState.lcpCloudRegionId).toEqual(serviceInstanceObject.lcpCloudRegionId);
+ expect(serviceState.tenantId).toEqual(serviceInstanceObject.tenantId);
+ expect(serviceState.tenantName).toEqual(serviceInstanceObject.tenantName);
+ expect(serviceState.aicZoneId).toEqual(serviceInstanceObject.aicZoneId);
+ expect(serviceState.aicZoneName).toEqual(serviceInstanceObject.aicZoneName);
+ expect(serviceState.projectName).toEqual(serviceInstanceObject.projectName);
+ expect(serviceState.owningEntityId).toEqual(serviceInstanceObject.owningEntityId);
+ expect(serviceState.owningEntityName).toEqual(serviceInstanceObject.owningEntityName);
+ expect(serviceState.pause).toEqual(serviceInstanceObject.pause);
+ expect(serviceState.bulkSize).toEqual(serviceInstanceObject.bulkSize);
+ expect(serviceState.vnfs).toEqual(serviceInstanceObject.vnfs);
+ expect(serviceState.instanceParams).toEqual(serviceInstanceObject.instanceParams);
+ expect(serviceState.rollbackOnFailure).toEqual(serviceInstanceObject.rollbackOnFailure);
+ expect(serviceState.subscriberName).toEqual(serviceInstanceObject.subscriberName);
+
+ done();
+ });
+
+ it('#UPDATE_VNF_INSTANCE : should update vnf instance with service id and vnfModelName ', (done: DoneFn) => {
+ let vnfInstanceObj : VnfInstance = {
+ instanceName: 'instanceName',
+ isUserProvidedNaming: false,
+ productFamilyId: 'productFamilyId',
+ lcpCloudRegionId: 'lcpCloudRegionId',
+ legacyRegion: 'legacyRegion',
+ tenantId: 'tenantId',
+ platformName: 'platformName',
+ lineOfBusiness: 'lineOfBusiness',
+ rollbackOnFailure: 'false',
+ vfModules: {}
+ };
+
+ let vnfState = ServiceReducer(<any>{serviceInstance : {
+ 'serviceUuid' : {
+ vnfs : {}
+ }
+ }},
+ <UpdateVnfInstanceAction>{
+ type: UPDATE_VNF_INSTANCE,
+ serviceUuid : 'serviceUuid',
+ vnfInstance: vnfInstanceObj,
+ vnfModelName : 'vnfModelName'
+ }).serviceInstance['serviceUuid'].vnfs['vnfModelName'];
+
+ expect(vnfState.instanceName).toEqual(vnfInstanceObj.instanceName);
+ expect(vnfState.isUserProvidedNaming).toEqual(vnfInstanceObj.isUserProvidedNaming);
+ expect(vnfState.productFamilyId).toEqual(vnfInstanceObj.productFamilyId);
+ expect(vnfState.lcpCloudRegionId).toEqual(vnfInstanceObj.lcpCloudRegionId);
+ expect(vnfState.legacyRegion).toEqual(vnfInstanceObj.legacyRegion);
+ expect(vnfState.tenantId).toEqual(vnfInstanceObj.tenantId);
+ expect(vnfState.platformName).toEqual(vnfInstanceObj.platformName);
+ expect(vnfState.lineOfBusiness).toEqual(vnfInstanceObj.lineOfBusiness);
+ expect(vnfState.vfModules).toEqual(vnfInstanceObj.vfModules);
+ expect(vnfState.rollbackOnFailure).toEqual(vnfInstanceObj.rollbackOnFailure);
+
+ done();
+ });
+
+ it('#UPDATE_LCP_REGIONS_AND_TENANTS : should update lcp region and tenants', (done: DoneFn) => {
+ let lcpRegionsAndTenantsObj = [
+ {
+ lcpRegionList : [
+ new LcpRegion({
+ "cloudRegionID" : 'cloudRegionID',
+ "is-permitted" : "is-permitted"
+ })
+ ],
+ lcpRegionsTenantsMap : {
+ "lcpRegion" : [new Tenant({
+ "tenantID" : "tenantID",
+ "tenantName" : "tenantName",
+ "is-permitted" : true
+ })]
+ }
+ }
+ ];
+ let lcpRegionsAndTenantsState = ServiceReducer(<any>{serviceInstance : {}},
+ <any>{
+ type: UPDATE_LCP_REGIONS_AND_TENANTS,
+ lcpRegionsAndTenants : lcpRegionsAndTenantsObj
+ })['lcpRegionsAndTenants'];
+
+ expect(lcpRegionsAndTenantsState).toBeDefined();
+ done();
+ });
+
+ it('#UPDATE_SUBSCRIBERS : should update subscribers', (done: DoneFn) => {
+ let subscribersList = [
+ new SelectOption({
+ id : 'id',
+ name : 'name',
+ isPermitted : false
+ })
+ ];
+ let subscribersState = ServiceReducer(<any>{serviceInstance : {}},
+ <UpdateSubscribersAction>{
+ type: UPDATE_SUBSCRIBERS,
+ subscribers : subscribersList
+ })['subscribers'];
+
+ expect(subscribersState).toBeDefined();
+ expect(subscribersState[0].id).toEqual(subscribersList[0].id);
+ expect(subscribersState[0].isPermitted).toEqual(subscribersList[0].isPermitted);
+ expect(subscribersState[0].name).toEqual(subscribersList[0].name);
+
+ done();
+ });
+
+ it('#UpdateProductFamiliesAction : should update product families', (done: DoneFn) => {
+ let productFamiliesObj = [
+ new SelectOption({
+ id : 'id',
+ name : 'name',
+ isPermitted : false
+ })
+ ];
+ let productFamiliesState = ServiceReducer(<any>{serviceInstance : {}},
+ <UpdateProductFamiliesAction>{
+ type: UPDATE_PRODUCT_FAMILIES,
+ productFamilies : productFamiliesObj
+ })['productFamilies'];
+
+ expect(productFamiliesState).toBeDefined();
+ expect(productFamiliesState[0].id).toEqual(productFamiliesObj[0].id);
+ expect(productFamiliesState[0].isPermitted).toEqual(productFamiliesObj[0].isPermitted);
+ expect(productFamiliesState[0].name).toEqual(productFamiliesObj[0].name);
+
+ done();
+ });
+
+ it('#UPDATE_AIC_ZONES : should update aic zones', (done: DoneFn) => {
+ let aicZonesObj = [
+ new SelectOption({
+ id : 'id',
+ name : 'name',
+ isPermitted : false
+ })
+ ];
+ let aicZonesState = ServiceReducer(<any>{serviceInstance : {}},
+ <UpdateAicZonesAction>{
+ type: UPDATE_AIC_ZONES,
+ aicZones : aicZonesObj
+ })['aicZones'];
+
+ expect(aicZonesState).toBeDefined();
+ expect(aicZonesState[0].id).toEqual(aicZonesObj[0].id);
+ expect(aicZonesState[0].isPermitted).toEqual(aicZonesObj[0].isPermitted);
+ expect(aicZonesState[0].name).toEqual(aicZonesObj[0].name);
+
+ done();
+ });
+
+ it('#DELETE_VNF_INSTANCE : should delete existing vnf', (done: DoneFn) => {
+ let state = ServiceReducer(<any>{serviceInstance : {
+ 'serviceModelId' : {
+ vnfs : {
+ 'modelName' : {}
+ }
+ }
+ }},
+ <DeleteVnfInstanceAction>{
+ type: DELETE_VNF_INSTANCE,
+ modelName : 'modelName',
+ serviceModelId : 'serviceModelId'
+ });
+
+ expect(state).toBeDefined();
+ expect(state.serviceInstance[ 'serviceModelId'].vnfs['modelName']).not.toBeDefined();
+ done();
+ });
+
+ it('#DELETE_VNF_MODULE_INSTANCE : should delete existing vnf module', (done: DoneFn) => {
+ let state = ServiceReducer(<any>{serviceInstance : {
+ 'serviceModelId' : {
+ vnfs : {
+ 'vfName' : {
+ vfModules : {
+ 'modelName' : {}
+ }
+ }
+ }
+ }
+ }},
+ <DeleteVfModuleInstanceAction>{
+ type: DELETE_VNF_MODULE_INSTANCE,
+ modelName : 'modelName',
+ vfName : 'vfName',
+ serviceModelId : 'serviceModelId'
+ });
+
+ expect(state).toBeDefined();
+ expect(state.serviceInstance['serviceModelId'].vnfs['vfName'].vfModules['modelName']).not.toBeDefined();
+ done();
+ });
+
+});
diff --git a/vid-webpack-master/src/app/service.reducer.ts b/vid-webpack-master/src/app/service.reducer.ts
new file mode 100644
index 000000000..a11f31e80
--- /dev/null
+++ b/vid-webpack-master/src/app/service.reducer.ts
@@ -0,0 +1,214 @@
+import { Action } from 'redux';
+import {
+ CREATE_VF_MODULE,
+ CreateVFModuleInstanceAction,
+ DELETE_SERVICE_INSTANCE,
+ DELETE_VNF_INSTANCE,
+ DELETE_VNF_MODULE_INSTANCE,
+ DeleteServiceInstanceAction,
+ DeleteVfModuleInstanceAction,
+ DeleteVnfInstanceAction,
+ UPDATE_AIC_ZONES,
+ UPDATE_CATEGORY_PARAMETERS,
+ UPDATE_LCP_REGIONS_AND_TENANTS,
+ UPDATE_MODEL,
+ UPDATE_NETWORK_FUNCTION,
+ UPDATE_PRODUCT_FAMILIES,
+ UPDATE_SERVICE_INSTANCE,
+ UPDATE_SERVICE_TYPES,
+ UPDATE_SUBSCRIBERS,
+ UPDATE_USER_ID,
+ UPDATE_VF_MODULE,
+ UPDATE_VNF_INSTANCE,
+ UpdateAicZonesAction,
+ UpdateCategoryParametersAction,
+ UpdateLcpRegionsAndTenantsAction,
+ UpdateNetworkCollectionFunction,
+ UpdateProductFamiliesAction,
+ UpdateServiceInstanceAction,
+ UpdateServiceModelAction,
+ UpdateServiceTypesAction,
+ UpdateSubscribersAction,
+ UpdateUserIdAction,
+ UpdateVFModuleInstanceAction,
+ UpdateVnfInstanceAction,
+} from './service.actions';
+import { LcpRegionsAndTenants } from './shared/models/lcpRegionsAndTenants';
+import * as _ from 'lodash';
+import { ServiceInstance } from './shared/models/serviceInstance';
+import { CategoryParams } from './shared/models/categoryParams';
+import { SelectOptionInterface } from './shared/models/selectOption';
+import { ServiceType } from './shared/models/serviceType';
+import { VnfInstance } from './shared/models/vnfInstance';
+import { VfModuleMap } from './shared/models/vfModulesMap';
+
+export interface ServiceState {
+ serviceHierarchy: any;
+ serviceInstance: { [uuid: string]: ServiceInstance; };
+ lcpRegionsAndTenants: LcpRegionsAndTenants;
+ subscribers: SelectOptionInterface[];
+ productFamilies: any;
+ serviceTypes: { [subscriberId: string]: ServiceType[]; };
+ aicZones: SelectOptionInterface[];
+ categoryParameters: CategoryParams;
+}
+
+const initialState: ServiceState = {
+ serviceHierarchy: {},
+ serviceInstance: {},
+ lcpRegionsAndTenants: new LcpRegionsAndTenants(),
+ subscribers: null,
+ productFamilies: null,
+ serviceTypes: {},
+ aicZones: null,
+ categoryParameters: new CategoryParams()
+};
+
+export const ServiceReducer =
+ function (state: ServiceState = initialState, action: Action): ServiceState {
+ switch (action.type) {
+ case UPDATE_MODEL: {
+ let uuid = (<UpdateServiceModelAction>action).serviceHierarchy.service.uuid;
+ state.serviceHierarchy[uuid] = _.cloneDeep((<UpdateServiceModelAction>action).serviceHierarchy);
+ return Object.assign({}, state);
+ }
+ case UPDATE_SERVICE_INSTANCE: {
+ const updateServiceInstanceAction = <UpdateServiceInstanceAction>action;
+ const uuid = updateServiceInstanceAction.serviceUuid;
+ const newState = _.cloneDeep(state);
+
+ const serviceInstance: ServiceInstance = newState.serviceInstance[uuid] || new ServiceInstance();
+
+ newState.serviceInstance[uuid] = Object.assign(serviceInstance, updateServiceInstanceAction.serviceInstance);
+ return newState;
+ }
+ case UPDATE_VNF_INSTANCE: {
+ const updateVnfInstanceAction = <UpdateVnfInstanceAction>action;
+ const serviceUuid = updateVnfInstanceAction.serviceUuid;
+ const vnfModelName = updateVnfInstanceAction.vnfModelName;
+
+ const newState = _.cloneDeep(state);
+ const vnfInstance: VnfInstance = newState.serviceInstance[serviceUuid].vnfs[vnfModelName] || new VnfInstance();
+
+ newState.serviceInstance[serviceUuid].vnfs[vnfModelName] = Object.assign(vnfInstance, updateVnfInstanceAction.vnfInstance);
+ return newState;
+ }
+
+
+ case UPDATE_USER_ID: {
+ const updateUserId : UpdateUserIdAction = <UpdateUserIdAction>action;
+ // var newState2 = {...state,'userId':updateUserId.userId}
+ var newState = _.cloneDeep(state);
+ newState['userId'] = updateUserId.userId;
+ return newState;
+
+ // state = (... {userId:action["userId"]},state]}
+ }
+
+ case UPDATE_VF_MODULE: {
+ const updateVFModuleInstanceAction = <UpdateVFModuleInstanceAction>action;
+ const vfInstance = updateVFModuleInstanceAction.vfInstance;
+ const serviceUuid = updateVFModuleInstanceAction.serviceUuid;
+ const vfModuleId = updateVFModuleInstanceAction.vfId;
+ const newState = _.cloneDeep(state);
+ const vnfs = newState.serviceHierarchy[serviceUuid].vnfs;
+ const vnfId = getVfModuleParentVnfId(vnfs, vfModuleId);
+ let vfModulesMap = newState.serviceInstance[serviceUuid].vnfs[vnfId].vfModules[vfModuleId] || new VfModuleMap();
+ vfModulesMap[vfModuleId] = vfInstance;
+ newState.serviceInstance[serviceUuid].vnfs[vnfId].vfModules[vfModuleId] = vfModulesMap;
+ return newState;
+ }
+
+ case CREATE_VF_MODULE: {
+ const updateVFModuleInstanceAction = <CreateVFModuleInstanceAction>action;
+ const vfInstance = updateVFModuleInstanceAction.vfInstance;
+ const serviceUuid = updateVFModuleInstanceAction.serviceUuid;
+ const vfModuleId = updateVFModuleInstanceAction.vfId;
+ const index = updateVFModuleInstanceAction.index;
+ let newState = Object.assign({}, state);
+ const vnfs = newState.serviceHierarchy[serviceUuid].vnfs;
+ const vnfId = getVfModuleParentVnfId(vnfs, vfModuleId);
+ let vfModulesMap = newState.serviceInstance[serviceUuid].vnfs[vnfId].vfModules[vfModuleId] || new VfModuleMap();
+ let randomId = generateId();
+ vfModulesMap[vfModuleId + randomId] = vfInstance;
+
+ newState.serviceInstance[serviceUuid].vnfs[vnfId].vfModules[vfModuleId] = vfModulesMap;
+ return newState;
+ }
+
+
+ case UPDATE_LCP_REGIONS_AND_TENANTS: {
+ Object.assign(state, (<UpdateLcpRegionsAndTenantsAction>action));
+ return Object.assign({}, state);
+ }
+ case UPDATE_SUBSCRIBERS: {
+ Object.assign(state, (<UpdateSubscribersAction>action));
+ return Object.assign({}, state);
+ }
+ case UPDATE_AIC_ZONES: {
+ Object.assign(state, (<UpdateAicZonesAction>action));
+ return Object.assign({}, state);
+ }
+ case UPDATE_PRODUCT_FAMILIES: {
+ Object.assign(state, (<UpdateProductFamiliesAction>action));
+ return Object.assign({}, state);
+ }
+ case UPDATE_NETWORK_FUNCTION: {
+ let networkFunctionReduxObj = state["networkFunctions"] == undefined ? {} : state["networkFunctions"];
+ networkFunctionReduxObj[(<UpdateNetworkCollectionFunction>action).network_function] = (<UpdateNetworkCollectionFunction>action).networksAccordingToNetworkCollection;
+ Object.assign(state, {"networkFunctions":networkFunctionReduxObj});
+ return Object.assign({}, state);
+ }
+ case UPDATE_SERVICE_TYPES: {
+ let subscriberId = (<UpdateServiceTypesAction>action).subscriberId;
+ let serviceTypes = (<UpdateServiceTypesAction>action).serviceTypes;
+ state.serviceTypes[subscriberId] = serviceTypes;
+ return Object.assign({}, state);
+ }
+ case UPDATE_CATEGORY_PARAMETERS: {
+ Object.assign(state, (<UpdateCategoryParametersAction>action));
+ return Object.assign({}, state);
+ }
+ case DELETE_SERVICE_INSTANCE: {
+ const uuid = (<DeleteServiceInstanceAction>action).serviceUuid;
+ if (state.serviceHierarchy[uuid]) {
+ let newState = _.omit(state, ['serviceInstance[' + uuid + ']']);
+ return Object.assign({}, state, newState);
+ }
+ return Object.assign({}, state);
+ }
+ case DELETE_VNF_INSTANCE: {
+ const actionData =(<DeleteVnfInstanceAction>action);
+ if(state.serviceInstance[actionData.serviceModelId]){
+ delete state.serviceInstance[actionData.serviceModelId].vnfs[actionData.modelName];
+ }
+ return Object.assign({}, state);
+ }
+
+ case DELETE_VNF_MODULE_INSTANCE: {
+ const actionData =(<DeleteVfModuleInstanceAction>action);
+ if(state.serviceInstance[actionData.serviceModelId]){
+ delete state.serviceInstance[actionData.serviceModelId].vnfs[actionData.vfName].vfModules[actionData.modelName];
+ }
+ return Object.assign({}, state);
+ }
+ default:
+ return Object.assign({}, state);
+ }
+ };
+
+const generateId = () => {
+ return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
+};
+
+
+const getVfModuleParentVnfId = (vnfs: object, vfModuleId: string) => {
+ let vnfId = undefined;
+ _.forOwn(vnfs, (value, key) => {
+ if (vnfs[key].vfModules && vnfs[key].vfModules[vfModuleId]) {
+ vnfId = vnfs[key].modelCustomizationName;
+ return false;
+ }
+ });
+ return vnfId;
+};
diff --git a/vid-webpack-master/src/app/services/aaiService/aai.actions.ts b/vid-webpack-master/src/app/services/aaiService/aai.actions.ts
new file mode 100644
index 000000000..649fb1456
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/aai.actions.ts
@@ -0,0 +1,75 @@
+import {Action, ActionCreator} from "redux";
+
+export const LOAD_PRODUCT_FAMILIES = '[PRODUCT_FAMILIES] Load';
+
+export const LOAD_LCP_TENANT = '[LCP_TENANT] Load';
+
+export const LOAD_AIC_ZONES = '[AIC_ZONES] Load';
+
+export const LOAD_CATEGORY_PARAMETERS = '[LOAD_CATEGORY_PARAMETERS] Load';
+
+export const LOAD_SERVICE_MDOEL_BY_UUID = '[LOAD_SERVICE_MDOEL_BY_UUID] Load';
+
+export const LOAD_NETWORK_ACCORDING_TO_NF = '[LOAD_NETWORK_ACCORDING_TO_NF] Load'
+
+export const LOAD_USER_ID = '[LOAD_USER_ID] Load'
+
+
+export interface LoadProductFamiliesAction extends Action {}
+
+interface LoadLcpTenant extends Action {}
+
+interface LoadAicZones extends Action {}
+
+interface LoadCategoryParameters extends Action {}
+
+interface LoadServiceModelByUuid extends Action {}
+
+interface LoadNetworkAccordingToNetworkCF extends Action{}
+
+interface LoadUserId extends Action{}
+
+
+export const loadServiceAccordingToUuid : ActionCreator<LoadServiceModelByUuid> =
+ (uuid : string) =>({
+ type : LOAD_SERVICE_MDOEL_BY_UUID,
+ modelId : uuid
+ })
+
+
+export const loadProductFamiliesAction: ActionCreator<LoadProductFamiliesAction> =
+ () => ({
+ type: LOAD_PRODUCT_FAMILIES,
+ });
+
+
+export const loadUserId: ActionCreator<LoadUserId> =
+() => ({
+ type: LOAD_USER_ID,
+});
+
+
+ export const loadLcpTenant: ActionCreator<LoadLcpTenant> =
+ () => ({
+ type: LOAD_LCP_TENANT,
+ });
+
+
+export const loadAicZones: ActionCreator<LoadAicZones> =
+ () => ({
+ type: LOAD_AIC_ZONES,
+ });
+
+export const loadCategoryParameters: ActionCreator<LoadCategoryParameters> =
+ () => ({
+ type: LOAD_CATEGORY_PARAMETERS,
+ });
+
+
+export const loadAaiNetworkAccordingToNetworkCF: ActionCreator<LoadNetworkAccordingToNetworkCF> =
+ (networkFunction,cloudOwner,cloudRegionId) => ({
+ type: LOAD_NETWORK_ACCORDING_TO_NF,
+ networkFunctions: networkFunction,
+ cloudOwner: cloudOwner,
+ cloudRegionId: cloudRegionId
+ });
diff --git a/vid-webpack-master/src/app/services/aaiService/aai.epics.ts b/vid-webpack-master/src/app/services/aaiService/aai.epics.ts
new file mode 100644
index 000000000..5249cea82
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/aai.epics.ts
@@ -0,0 +1,81 @@
+import {updateServiceInstance} from './../../service.actions';
+import {Injectable} from '@angular/core';
+import {createEpicMiddleware} from 'redux-observable';
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/map';
+import 'rxjs/add/operator/do';
+import 'rxjs/add/operator/startWith';
+import {
+ LOAD_PRODUCT_FAMILIES,
+ LOAD_LCP_TENANT,
+ LOAD_AIC_ZONES,
+ LOAD_CATEGORY_PARAMETERS,
+ LOAD_SERVICE_MDOEL_BY_UUID,
+ LOAD_NETWORK_ACCORDING_TO_NF,
+ LOAD_USER_ID
+} from "./aai.actions";
+import {AaiService} from "./aai.service";
+import {
+ updateAicZones, updateCategoryParameters, updateLcpRegionsAndTenants, updateNetworkCollectionFunction,
+ updateProductFamilies, updateUserId
+} from "../../service.actions";
+import {AppState} from "../../store/reducers";
+
+const notFetchedAlready = (state: AppState): boolean => state.service.productFamilies !== null;
+
+@Injectable()
+export class AAIEpics {
+ constructor(private aaiService: AaiService) {
+ }
+
+ public createEpic() {
+ return [createEpicMiddleware(this.loadProductFamiliesEpic)
+ , createEpicMiddleware(this.loadLcpTenants)
+ , createEpicMiddleware(this.loadAicZones)
+ , createEpicMiddleware(this.loadCategoryParameters)
+ , createEpicMiddleware(this.loadServiceAccordingToUuid)
+ , createEpicMiddleware(this.loadNetworkAccordingToNetworkFunction)
+ , createEpicMiddleware(this.loadUserId)
+ ];
+ }
+
+ private loadLcpTenants = (action$, store) =>
+ action$
+ .ofType(LOAD_LCP_TENANT)
+ .switchMap(() => this
+ .aaiService
+ .getLcpRegionsAndTenants('e433710f-9217-458d-a79d-1c7aff376d89', 'VIRTUAL USP')
+ .map(data => updateLcpRegionsAndTenants(data)));
+
+ private loadProductFamiliesEpic = (action$, store) => action$
+ .ofType(LOAD_PRODUCT_FAMILIES)
+ .switchMap(() => this.aaiService.getProductFamilies().map(data => updateProductFamilies(data)));
+
+ private loadCategoryParameters = (action$, store) => action$
+ .ofType(LOAD_CATEGORY_PARAMETERS)
+ .switchMap(() => this.aaiService.getCategoryParameters(null).map(data => updateCategoryParameters(data)));
+
+
+ private loadNetworkAccordingToNetworkFunction = (action$, store) => action$
+ .ofType(LOAD_NETWORK_ACCORDING_TO_NF)
+ .flatMap((action) => this.aaiService.getCRAccordingToNetworkFunctionId(action.networkFunctions, action.cloudOwner, action.cloudRegionId).map((res) =>
+ updateNetworkCollectionFunction(action.networkFunctions, res)));
+
+ private loadServiceAccordingToUuid = (action$, store) => action$
+ .ofType(LOAD_SERVICE_MDOEL_BY_UUID)
+ .switchMap((action) => this.aaiService.getServiceModelById(action.modelId)
+ .map(data => updateServiceInstance(action.uuid, data)));
+
+ private loadUserId = (action$, store) => action$
+ .ofType(LOAD_USER_ID)
+ .switchMap(() => this.aaiService.getUserId()
+ .map(res => updateUserId(res)));
+
+
+ private loadAicZones = (action$, store) => action$
+ .ofType(LOAD_AIC_ZONES)
+ .switchMap(() => this.aaiService.getAicZones().map(data => updateAicZones(data)));
+ // .catch(response => of(this.actions.loadFailed(status)))
+ // .startWith(this.actions.loadStarted()));
+
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/aai.service.ts b/vid-webpack-master/src/app/services/aaiService/aai.service.ts
new file mode 100644
index 000000000..dd9d9fb29
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/aai.service.ts
@@ -0,0 +1,189 @@
+import {Injectable} from '@angular/core';
+import {HttpClient, HttpHeaders} from '@angular/common/http';
+import { Constants } from '../../shared/utils/constants';
+import { ServiceType } from "../../shared/models/serviceType";
+import {GetSubDetailsResponse} from "./responseInterfaces/getSubDetailsResponseInterface";
+import {Observable} from "rxjs/Observable";
+import * as _ from 'lodash';
+import {CategoryParams} from "../../shared/models/categoryParams";
+import {GetCategoryParamsResponseInterface} from "./responseInterfaces/getCategoryParamsResponseInterface";
+import {Project} from "../../shared/models/project";
+import {OwningEntity} from "../../shared/models/owningEntity";
+import {GetServicesResponseInterface} from "./responseInterfaces/getServicesResponseInterface";
+import {Subscriber} from "../../shared/models/subscriber";
+import {GetSubscribersResponse} from "./responseInterfaces/getSubscribersResponseInterface";
+import {AicZone} from "../../shared/models/aicZone";
+import {GetAicZonesResponse} from "./responseInterfaces/getAicZonesResponseInterface";
+import {LcpRegionsAndTenants} from "../../shared/models/lcpRegionsAndTenants";
+import {LcpRegion} from "../../shared/models/lcpRegion";
+import {Tenant} from "../../shared/models/tenant";
+import {ProductFamily} from "../../shared/models/productFamily"
+import {
+ updateAicZones, updateCategoryParameters, updateLcpRegionsAndTenants, updateModel, updateProductFamilies,
+ updateServiceTypes, updateSubscribers, updateUserId
+} from '../../service.actions';
+import {SelectOption} from '../../shared/models/selectOption';
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import {ResponseContentType, ResponseType} from "@angular/http";
+import 'rxjs/add/operator/do';
+import 'rxjs/add/observable/of';
+import 'rxjs/add/operator/catch';
+
+@Injectable()
+export class AaiService {
+
+ constructor (private http: HttpClient, private store: NgRedux<AppState>) {}
+
+ public getServiceModelById(serviceModelId: string): Observable<any> {
+ if (_.has(this.store.getState().service.serviceHierarchy,serviceModelId)){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.serviceHierarchy[serviceModelId])));
+ }
+ let pathQuery: string = Constants.Path.SERVICES_PATH + serviceModelId;
+ return this.http.get(pathQuery).map(res => res )
+ .do((res) => {
+ this.store.dispatch(updateModel(res));
+ });
+ }
+
+ public getUserId() : Observable<any>{
+ return this.http.get("../../getuserID",{responseType: 'text'}).do((res)=>this.store.dispatch(updateUserId(res)));
+ }
+
+
+ public getCRAccordingToNetworkFunctionId(networkCollectionFunction,cloudOwner,cloudRegionId){
+ return this.http.get('../../aai_get_instance_groups_by_cloudregion/'+cloudOwner+'/'+cloudRegionId+'/' + networkCollectionFunction)
+ .map(res=>res).do((res)=>console.log(res));
+ }
+
+ public getCategoryParameters(familyName): Observable<CategoryParams> {
+ familyName = familyName || Constants.Path.PARAMETER_STANDARDIZATION_FAMILY;
+ let pathQuery: string = Constants.Path.GET_CATEGORY_PARAMETERS +"?familyName=" + familyName+ "&r=" + Math.random();
+
+ return this.http.get<GetCategoryParamsResponseInterface>(pathQuery)
+ .map(this.categoryParametersResponseToProductAndOwningEntity)
+ .do(res => {
+ this.store.dispatch(updateCategoryParameters(res))
+ });
+ }
+
+
+
+ categoryParametersResponseToProductAndOwningEntity(res: GetCategoryParamsResponseInterface): CategoryParams {
+ if (res && res.categoryParameters) {
+ const owningEntityList = res.categoryParameters.owningEntity.map(owningEntity => new OwningEntity(owningEntity));
+ const projectList = res.categoryParameters.project.map(project => new Project(project));
+ const lineOfBusinessList = res.categoryParameters.lineOfBusiness.map(owningEntity => new SelectOption(owningEntity));
+ const platformList = res.categoryParameters.platform.map(platform => new SelectOption(platform));
+
+ return new CategoryParams(owningEntityList, projectList, lineOfBusinessList, platformList);
+ } else {
+ return new CategoryParams();
+ }
+ }
+
+ public getProductFamilies(): Observable<ProductFamily[]> {
+ return this.getServices().map(res => res.service.map(service => new ProductFamily(service)));
+ }
+
+ public getServices(): Observable<GetServicesResponseInterface> {
+ let pathQuery: string = Constants.Path.AAI_GET_SERVICES + Constants.Path.ASSIGN + Math.random();
+
+ return this.http.get<GetServicesResponseInterface>(pathQuery);
+ }
+
+ public getSubscribers(): Observable<Subscriber[]> {
+ if (this.store.getState().service.subscribers){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.subscribers)));
+ }
+
+ let pathQuery: string = Constants.Path.AAI_GET_SUBSCRIBERS + Constants.Path.ASSIGN + Math.random();
+
+ return this.http.get<GetSubscribersResponse>(pathQuery).map(res =>
+ res.customer.map( subscriber => new Subscriber(subscriber))).do((res) => {
+ this.store.dispatch(updateSubscribers(res));
+ });
+ }
+
+ public getAicZones(): Observable<AicZone[]> {
+ if (this.store.getState().service.aicZones){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.aicZones)));
+ }
+
+ let pathQuery: string = Constants.Path.AAI_GET_AIC_ZONES + Constants.Path.ASSIGN + Math.random();
+
+ return this.http.get<GetAicZonesResponse>(pathQuery).map(res =>
+ res.zone.map(aicZone => new AicZone(aicZone))).do((res) => {
+ this.store.dispatch(updateAicZones(res));
+ });
+ }
+
+ public getLcpRegionsAndTenants(globalCustomerId, serviceType): Observable<LcpRegionsAndTenants> {
+ if (this.store.getState().service.lcpRegionsAndTenants.lcpRegionList.length !== 0){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.lcpRegionsAndTenants)));
+ }
+ let pathQuery: string = Constants.Path.AAI_GET_TENANTS
+ + globalCustomerId + Constants.Path.FORWARD_SLASH + serviceType + Constants.Path.ASSIGN + Math.random();
+
+ console.log("AaiService:getSubscriptionServiceTypeList: globalCustomerId: "
+ + globalCustomerId);
+ if (globalCustomerId != null) {
+ return this.http.get(pathQuery)
+ .map(this.tenantResponseToLcpRegionsAndTenants).do((res) => {
+ this.store.dispatch(updateLcpRegionsAndTenants(res));
+ });
+ }
+ }
+
+ tenantResponseToLcpRegionsAndTenants(cloudRegionTenantList): LcpRegionsAndTenants {
+
+ const lcpRegionsTenantsMap = {};
+
+ const lcpRegionList = _.uniqBy(cloudRegionTenantList, 'cloudRegionID').map((cloudRegionTenant) => {
+ return new LcpRegion(cloudRegionTenant)
+ });
+
+ lcpRegionList.forEach(region => {
+ lcpRegionsTenantsMap[region.id] = _.filter(cloudRegionTenantList, {'cloudRegionID' : region.id})
+ .map((cloudRegionTenant) => {
+ return new Tenant(cloudRegionTenant)
+ });
+ const reducer = (accumulator, currentValue) => {
+ accumulator.isPermitted = accumulator.isPermitted || currentValue.isPermitted;
+
+ return accumulator;
+ };
+ region.isPermitted = lcpRegionsTenantsMap[region.id].reduce(reducer).isPermitted;
+ });
+
+ return new LcpRegionsAndTenants(lcpRegionList, lcpRegionsTenantsMap);
+ }
+
+ public getServiceTypes(subscriberId): Observable<ServiceType[]> {
+ console.log("AaiService:getSubscriptionServiceTypeList: globalCustomerId: " + subscriberId);
+ if (_.has(this.store.getState().service.serviceTypes, subscriberId)){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.serviceTypes[subscriberId])));
+ }
+
+ return this.getSubscriberDetails(subscriberId)
+ .map(this.subDetailsResponseToServiceTypes)
+ .do((res) => {this.store.dispatch(updateServiceTypes(res, subscriberId));});
+ }
+
+ public getSubscriberDetails(subscriberId): Observable<GetSubDetailsResponse> {
+ let pathQuery: string = Constants.Path.AAI_SUB_DETAILS_PATH + subscriberId + Constants.Path.ASSIGN + Math.random();
+
+ if (subscriberId != null) {
+ return this.http.get<GetSubDetailsResponse>(pathQuery);
+ }
+ }
+
+ subDetailsResponseToServiceTypes(res: GetSubDetailsResponse): ServiceType[] {
+ if (res && res['service-subscriptions']) {
+ const serviceSubscriptions = res['service-subscriptions']['service-subscription'];
+ return serviceSubscriptions.map((subscription, index) => new ServiceType(String(index), subscription))
+ } else {
+ return [];
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getAicZonesResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getAicZonesResponseInterface.ts
new file mode 100644
index 000000000..62581c9e2
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getAicZonesResponseInterface.ts
@@ -0,0 +1,3 @@
+export interface GetAicZonesResponse {
+ zone: any[];
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getCategoryParamsResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getCategoryParamsResponseInterface.ts
new file mode 100644
index 000000000..06398904c
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getCategoryParamsResponseInterface.ts
@@ -0,0 +1,10 @@
+interface CategoryParametersResponse {
+ owningEntity: any[],
+ project: any[]
+ lineOfBusiness: any[]
+ platform: any[]
+}
+
+export interface GetCategoryParamsResponseInterface {
+ categoryParameters: CategoryParametersResponse;
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServiceModelResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServiceModelResponseInterface.ts
new file mode 100644
index 000000000..87671155d
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServiceModelResponseInterface.ts
@@ -0,0 +1,5 @@
+import {ServiceModelResponseInterface} from "../../../shared/models/serviceModel";
+
+export interface GetServiceModelResponseInterface {
+ service: ServiceModelResponseInterface
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServicesResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServicesResponseInterface.ts
new file mode 100644
index 000000000..ae04055e4
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServicesResponseInterface.ts
@@ -0,0 +1,9 @@
+export interface ServiceResponseInterface {
+ 'service-id': string,
+ 'service-description': string
+ 'is-permitted': boolean
+}
+
+export interface GetServicesResponseInterface {
+ service: ServiceResponseInterface[];
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubDetailsResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubDetailsResponseInterface.ts
new file mode 100644
index 000000000..dbfb695d0
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubDetailsResponseInterface.ts
@@ -0,0 +1,12 @@
+export interface Subscription {
+ 'service-type': string;
+ 'is-permitted': boolean;
+}
+
+interface ServiceSubscriptions {
+ 'service-subscription': Subscription[];
+}
+
+export interface GetSubDetailsResponse {
+ 'service-subscriptions': ServiceSubscriptions;
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubscribersResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubscribersResponseInterface.ts
new file mode 100644
index 000000000..065f66e21
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubscribersResponseInterface.ts
@@ -0,0 +1,5 @@
+import {Subscriber} from "../../../shared/models/subscriber";
+
+export interface GetSubscribersResponse {
+ customer: Subscriber[];
+}
diff --git a/vid-webpack-master/src/app/services/configuration.service.ts b/vid-webpack-master/src/app/services/configuration.service.ts
new file mode 100644
index 000000000..4edd8ffb5
--- /dev/null
+++ b/vid-webpack-master/src/app/services/configuration.service.ts
@@ -0,0 +1,34 @@
+import {Injectable} from '@angular/core';
+import {HttpClient} from "@angular/common/http";
+import {Constants} from "../shared/utils/constants";
+import {Observable} from 'rxjs/Observable';
+import {updateFlags} from "../global.actions";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../store/reducers";
+
+@Injectable()
+export class ConfigurationService {
+ store : NgRedux<AppState>;
+
+ constructor(private _http: HttpClient, _store : NgRedux<AppState>) {
+ this.store = _store;
+ }
+
+ getConfiguration(key : string): Observable<any> {
+ let pathQuery = Constants.Path.CONFIGURATION_PATH;
+ pathQuery = pathQuery.replace("{name}",key);
+ return this._http.get(pathQuery).map(response => response);
+ }
+
+ getFlags(): Observable<{[key: string] : boolean}> {
+ let flags = this.store.getState().global.flags;
+ if (flags) {
+ return Observable.of(flags);
+ }
+ let pathQuery = Constants.Path.FEATURES_FLAG_PATH;
+ return this._http.get<{[key: string] : boolean}>(pathQuery).map(response => {
+ this.store.dispatch(updateFlags(response));
+ return response;
+ });
+ }
+}
diff --git a/vid-webpack-master/src/app/services/data.service.ts b/vid-webpack-master/src/app/services/data.service.ts
new file mode 100644
index 000000000..4f8bf3623
--- /dev/null
+++ b/vid-webpack-master/src/app/services/data.service.ts
@@ -0,0 +1,528 @@
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class DataService {
+
+ private static _availableVolumeGroupList;
+ private static _cloudRegionTenantList;
+ private static _globalCustomerId;
+ private static _customizationUUID;
+ private static _rescustomizationUUID;
+ private static _inventoryItem;
+ private static _modelId;
+ private static _modelInstanceName;
+ private static _modelInfo;
+ private static _networkInstanceId;
+ private static _serviceIdList;
+ private static _aicZones;
+ private static _aicZone;
+ private static _serviceInstanceId;
+ private static _serviceInstanceName;
+ private static _serviceName;
+ private static _serviceType;
+ private static _serviceUuid;
+ private static _serviceTypeName;
+ private static _createSubscriberName;
+ private static _uploadSupplementoryDataFile;
+ private static _supplementoryDataFile;
+ private static _subscriberId;
+ private static _loggedInUserId;
+ private static _subscriberName;
+ private static _subscribers;
+ private static _subscriptionServiceTypeList;
+ private static _userParams;
+ private static _userServiceInstanceName;
+ private static _vfModuleInstanceId;
+ private static _vnfInstanceId;
+ private static _vfModuleInstanceName;
+ private static _volumeGroupInstanceId;
+ private static _lcpRegion;
+ private static _tenant;
+ private static _treeHandle;
+ private static _serviceInstanceToCustomer;
+ private static _aLaCarte: boolean;
+ private static _macro: boolean;
+ private static _resources;
+ private static _syspropProvStatusList;
+ private static _updatedvnfProvStatus;
+ private static _arbitraryParameters;
+ private static _hideServiceFields;
+ private static _serviceProxies;
+ private static _sourceServiceProxies;
+ private static _collectorServiceProxies;
+ private static _configurationByPolicy;
+ private static _suppressRollback;
+ private static _portMirroningConfigFields;
+ private static _configurationInstanceId: string;
+ private static _configurationStatus: string;
+ private static _portStatus: string;
+ private static _portId: string;
+ private static _pnf;
+ private static _owningEntityProperties;
+
+ static get availableVolumeGroupList() {
+ return this._availableVolumeGroupList;
+ }
+
+ static set availableVolumeGroupList(value) {
+ this._availableVolumeGroupList = value;
+ }
+
+ static get cloudRegionTenantList() {
+ return this._cloudRegionTenantList;
+ }
+
+ static set cloudRegionTenantList(value) {
+ this._cloudRegionTenantList = value;
+ }
+
+ static get globalCustomerId() {
+ return this._globalCustomerId;
+ }
+
+ static set globalCustomerId(value) {
+ this._globalCustomerId = value;
+ }
+
+ static get customizationUUID() {
+ return this._customizationUUID;
+ }
+
+ static set customizationUUID(value) {
+ this._customizationUUID = value;
+ }
+
+ static get rescustomizationUUID() {
+ return this._rescustomizationUUID;
+ }
+
+ static set rescustomizationUUID(value) {
+ this._rescustomizationUUID = value;
+ }
+
+ static get inventoryItem() {
+ return this._inventoryItem;
+ }
+
+ static set inventoryItem(value) {
+ this._inventoryItem = value;
+ }
+
+ static get modelId() {
+ return this._modelId;
+ }
+
+ static set modelId(value) {
+ this._modelId = value;
+ }
+
+ static get modelInstanceName() {
+ return this._modelInstanceName;
+ }
+
+ static set modelInstanceName(value) {
+ this._modelInstanceName = value;
+ }
+
+ static get modelInfo() {
+ return this._modelInfo;
+ }
+
+ static set modelInfo(value) {
+ this._modelInfo = value;
+ }
+
+ static getModelInfo(componentId) {
+ return this._modelInfo[componentId];
+ }
+
+ static setModelInfo(componentId, modelInfo) {
+ if (!this._modelInfo) {
+ this._modelInfo = {};
+ }
+ this._modelInfo[componentId] = modelInfo;
+ }
+
+ static get networkInstanceId() {
+ return this._networkInstanceId;
+ }
+
+ static set networkInstanceId(value) {
+ this._networkInstanceId = value;
+ }
+
+ static get serviceIdList() {
+ return this._serviceIdList;
+ }
+
+ static set serviceIdList(value) {
+ this._serviceIdList = value;
+ }
+
+ static get aicZones() {
+ return this._aicZones;
+ }
+
+ static set aicZones(value) {
+ this._aicZones = value;
+ }
+
+ static get aicZone() {
+ return this._aicZone;
+ }
+
+ static set aicZone(value) {
+ this._aicZone = value;
+ }
+
+ static get serviceInstanceId() {
+ return this._serviceInstanceId;
+ }
+
+ static set serviceInstanceId(value) {
+ this._serviceInstanceId = value;
+ }
+
+ static get serviceInstanceName() {
+ return this._serviceInstanceName;
+ }
+
+ static set serviceInstanceName(value) {
+ this._serviceInstanceName = value;
+ }
+
+ static get serviceName() {
+ return this._serviceName;
+ }
+
+ static set serviceName(value) {
+ this._serviceName = value;
+ }
+
+ static get serviceType() {
+ return this._serviceType;
+ }
+
+ static set serviceType(value) {
+ this._serviceType = value;
+ }
+
+ static get serviceUuid() {
+ return this._serviceUuid;
+ }
+
+ static set serviceUuid(value) {
+ this._serviceUuid = value;
+ }
+
+ static get serviceTypeName() {
+ return this._serviceTypeName;
+ }
+
+ static set serviceTypeName(value) {
+ this._serviceTypeName = value;
+ }
+
+ static get createSubscriberName() {
+ return this._createSubscriberName;
+ }
+
+ static set createSubscriberName(value) {
+ this._createSubscriberName = value;
+ }
+
+ static get uploadSupplementoryDataFile() {
+ return this._uploadSupplementoryDataFile;
+ }
+
+ static set uploadSupplementoryDataFile(value) {
+ this._uploadSupplementoryDataFile = value;
+ }
+
+ static get supplementoryDataFile() {
+ return this._supplementoryDataFile;
+ }
+
+ static set supplementoryDataFile(value) {
+ this._supplementoryDataFile = value;
+ }
+
+ static get subscriberId() {
+ return this._subscriberId;
+ }
+
+ static set subscriberId(value) {
+ this._subscriberId = value;
+ }
+
+ static get loggedInUserId() {
+ return this._loggedInUserId;
+ }
+
+ static set loggedInUserId(value) {
+ this._loggedInUserId = value;
+ }
+
+ static get subscriberName() {
+ return this._subscriberName;
+ }
+
+ static set subscriberName(value) {
+ this._subscriberName = value;
+ }
+
+ static get subscribers() {
+ return this._subscribers;
+ }
+
+ static set subscribers(value) {
+ this._subscribers = value;
+ }
+
+ static get subscriptionServiceTypeList() {
+ return this._subscriptionServiceTypeList;
+ }
+
+ static set subscriptionServiceTypeList(value) {
+ this._subscriptionServiceTypeList = value;
+ }
+
+ static get userParams() {
+ return this._userParams;
+ }
+
+ static set userParams(value) {
+ this._userParams = value;
+ }
+
+ static get userServiceInstanceName() {
+ return this._userServiceInstanceName;
+ }
+
+ static set userServiceInstanceName(value) {
+ this._userServiceInstanceName = value;
+ }
+
+ static get vfModuleInstanceId() {
+ return this._vfModuleInstanceId;
+ }
+
+ static set vfModuleInstanceId(value) {
+ this._vfModuleInstanceId = value;
+ }
+
+ static get vnfInstanceId() {
+ return this._vnfInstanceId;
+ }
+
+ static set vnfInstanceId(value) {
+ this._vnfInstanceId = value;
+ }
+
+ static get vfModuleInstanceName() {
+ return this._vfModuleInstanceName;
+ }
+
+ static set vfModuleInstanceName(value) {
+ this._vfModuleInstanceName = value;
+ }
+
+ static get volumeGroupInstanceId() {
+ return this._volumeGroupInstanceId;
+ }
+
+ static set volumeGroupInstanceId(value) {
+ this._volumeGroupInstanceId = value;
+ }
+
+ static get lcpRegion() {
+ return this._lcpRegion;
+ }
+
+ static set lcpRegion(value) {
+ this._lcpRegion = value;
+ }
+
+ static get tenant() {
+ return this._tenant;
+ }
+
+ static set tenant(value) {
+ this._tenant = value;
+ }
+
+ static get treeHandle() {
+ return this._treeHandle;
+ }
+
+ static set treeHandle(value) {
+ this._treeHandle = value;
+ }
+
+ static get serviceInstanceToCustomer() {
+ return this._serviceInstanceToCustomer;
+ }
+
+ static set serviceInstanceToCustomer(value) {
+ this._serviceInstanceToCustomer = value;
+ }
+
+ static get aLaCarte() {
+ if (!this._aLaCarte) {
+ return true;
+ }
+ return this._aLaCarte;
+ }
+
+ static set aLaCarte(value: boolean) {
+ this._aLaCarte = value;
+ }
+
+ static get macro() {
+ if (!this._macro) {
+ return false;
+ }
+ return this._macro;
+ }
+
+ static set macro(value: boolean) {
+ this._macro = value;
+ }
+
+ static get resources() {
+ return this._resources;
+ }
+
+ static set resources(value) {
+ this._resources = value;
+ }
+
+ static get syspropProvStatusList() {
+ return this._syspropProvStatusList;
+ }
+
+ static set syspropProvStatusList(value) {
+ this._syspropProvStatusList = value;
+ }
+
+ static get updatedvnfProvStatus() {
+ return this._updatedvnfProvStatus;
+ }
+
+ static set updatedvnfProvStatus(value) {
+ this._updatedvnfProvStatus = value;
+ }
+
+ static get arbitraryParameters() {
+ return this._arbitraryParameters;
+ }
+
+ static set arbitraryParameters(value) {
+ this._arbitraryParameters = value;
+ }
+
+ static get hideServiceFields() {
+ return this._hideServiceFields;
+ }
+
+ static set hideServiceFields(value) {
+ this._hideServiceFields = value;
+ }
+
+ static get serviceProxies() {
+ return this._serviceProxies;
+ }
+
+ static set serviceProxies(value) {
+ this._serviceProxies = value;
+ }
+
+ static get sourceServiceProxies() {
+ return this._sourceServiceProxies;
+ }
+
+ static set sourceServiceProxies(value) {
+ this._sourceServiceProxies = value;
+ }
+
+ static get collectorServiceProxies() {
+ return this._collectorServiceProxies;
+ }
+
+ static set collectorServiceProxies(value) {
+ this._collectorServiceProxies = value;
+ }
+
+ static get configurationByPolicy() {
+ return this._configurationByPolicy;
+ }
+
+ static set configurationByPolicy(value) {
+ this._configurationByPolicy = value;
+ }
+
+ static get suppressRollback() {
+ return this._suppressRollback;
+ }
+
+ static set suppressRollback(value) {
+ this._suppressRollback = value;
+ }
+
+ static get portMirroningConfigFields() {
+ return this._portMirroningConfigFields;
+ }
+
+ static set portMirroningConfigFields(value) {
+ this._portMirroningConfigFields = value;
+ }
+
+ static get configurationInstanceId(): string {
+ return this._configurationInstanceId;
+ }
+
+ static set configurationInstanceId(value: string) {
+ this._configurationInstanceId = value;
+ }
+
+ static get configurationStatus(): string {
+ return this._configurationStatus;
+ }
+
+ static set configurationStatus(value: string) {
+ this._configurationStatus = value;
+ }
+
+ static get portStatus(): string {
+ return this._portStatus;
+ }
+
+ static set portStatus(value: string) {
+ this._portStatus = value;
+ }
+
+ static get portId(): string {
+ return this._portId;
+ }
+
+ static set portId(value: string) {
+ this._portId = value;
+ }
+
+ static get pnf() {
+ return this._pnf;
+ }
+
+ static set pnf(value) {
+ this._pnf = value;
+ }
+
+ static get owningEntityProperties() {
+ return this._owningEntityProperties;
+ }
+
+ static set owningEntityProperties(value) {
+ this._owningEntityProperties = value;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/services/flags.resolve.ts b/vid-webpack-master/src/app/services/flags.resolve.ts
new file mode 100644
index 000000000..70449379f
--- /dev/null
+++ b/vid-webpack-master/src/app/services/flags.resolve.ts
@@ -0,0 +1,14 @@
+import {ActivatedRouteSnapshot, Resolve} from "@angular/router";
+import {Injectable} from "@angular/core";
+import {ConfigurationService} from "./configuration.service";
+import {Observable} from "rxjs/Observable";
+
+@Injectable()
+export class FlagsResolve implements Resolve<Observable< { [key: string]: boolean }>> {
+
+ constructor(private _configurationService: ConfigurationService) {}
+
+ resolve(route: ActivatedRouteSnapshot) {
+ return this._configurationService.getFlags();
+ }
+}
diff --git a/vid-webpack-master/src/app/services/msoService/mso.service.ts b/vid-webpack-master/src/app/services/msoService/mso.service.ts
new file mode 100644
index 000000000..1402b50f7
--- /dev/null
+++ b/vid-webpack-master/src/app/services/msoService/mso.service.ts
@@ -0,0 +1,26 @@
+import {Injectable} from "@angular/core";
+import {HttpClient} from "@angular/common/http";
+import {Observable} from "rxjs/Observable";
+import {Constants} from "../../shared/utils/constants";
+
+@Injectable()
+export class MsoService {
+ httpClient: HttpClient;
+
+ constructor(http: HttpClient) {
+ this.httpClient = http;
+ }
+
+
+ public submitMsoTask(instanceFields): Observable<any> {
+ let path = '../../asyncInstantiation/bulk';
+ return this.httpClient.post(path, instanceFields);
+ }
+ public createVnf(requestDetails, serviceInstanceId): Observable<any> {
+ let pathQuery: string = Constants.Path.MSO_CREATE_VNF_INSTANCE + serviceInstanceId;
+
+ return this.httpClient.post( pathQuery, {
+ requestDetails : requestDetails
+ });
+ }
+}
diff --git a/vid-webpack-master/src/app/services/sdc.service.ts b/vid-webpack-master/src/app/services/sdc.service.ts
new file mode 100644
index 000000000..d4eba260a
--- /dev/null
+++ b/vid-webpack-master/src/app/services/sdc.service.ts
@@ -0,0 +1,28 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import 'rxjs/add/operator/map';
+import { Constants } from '../shared/utils/constants';
+import { VidConfiguration } from '../configuration/vid.configuration';
+
+@Injectable()
+export class SdcService {
+
+
+ constructor (private http: HttpClient) {
+ }
+
+ public getServicesModels(): any {
+ let pathQuery: string = Constants.Path.SERVICES_DIST_STATUS_PATH + VidConfiguration.ASDC_MODEL_STATUS;
+
+ if ( VidConfiguration.ASDC_MODEL_STATUS === Constants.Status.ALL) {
+ pathQuery = Constants.Path.SERVICES_PATH;
+ }
+
+ return this.http.get(pathQuery);
+ }
+
+ getService(uuid: string) {
+ return this.http.get(Constants.Path.SERVICES_PATH + uuid);
+ }
+
+}
diff --git a/vid-webpack-master/src/app/services/service-planning.service.spec.ts b/vid-webpack-master/src/app/services/service-planning.service.spec.ts
new file mode 100644
index 000000000..5d60e29f7
--- /dev/null
+++ b/vid-webpack-master/src/app/services/service-planning.service.spec.ts
@@ -0,0 +1,467 @@
+import {ServicePlanningService} from "./service-planning.service";
+import {ReflectiveInjector} from "@angular/core";
+import {NgRedux} from "@angular-redux/store";
+import {ServiceNodeTypes} from "../shared/models/ServiceNodeTypes";
+
+export class MockAppStore<T> {
+}
+
+describe('Service planning service', () => {
+ let injector;
+ let service: ServicePlanningService;
+
+ beforeEach(() => {
+
+ let injector = ReflectiveInjector.resolveAndCreate([
+ ServicePlanningService,
+ {provide: NgRedux, useClass: MockAppStore}
+ ]);
+
+ service = injector.get(ServicePlanningService);
+ });
+
+ describe('#updateDynamicInputsVnfDataFromModel', () => {
+ it('get vfModule instance params', (done: DoneFn) => {
+ //get vfModule instance params
+ let dynamicInputs = service.updateDynamicInputsVnfDataFromModel(ServiceNodeTypes.VFmodule, generateVFModule());
+ expect(dynamicInputs).toEqual([{
+ id: '2017488_adiodvpe0_vnf_config_template_version',
+ type: 'string',
+ name: '2017488_adiodvpe0_vnf_config_template_version',
+ value: '17.2',
+ isRequired: true,
+ description: 'VPE Software Version'
+ }, {
+ id: '2017488_adiodvpe0_AIC_CLLI',
+ type: 'string',
+ name: '2017488_adiodvpe0_AIC_CLLI',
+ value: 'ATLMY8GA',
+ isRequired: true,
+ description: 'AIC Site CLLI'
+ }]);
+
+ //get vfModule with no instance params should return empty array
+ dynamicInputs = service.updateDynamicInputsVnfDataFromModel(ServiceNodeTypes.VFmodule, generateVFModule2);
+ expect(dynamicInputs).toEqual([]);
+
+ //get vf instance params should be undefined
+ dynamicInputs = service.updateDynamicInputsVnfDataFromModel(ServiceNodeTypes.VF, generateVNF());
+ expect(dynamicInputs).toEqual([]);
+ done();
+ });
+ });
+
+ describe('#isUserProvidedNaming', () => {
+ it('get vfModule with generate ecompNaming should return userProvided false', (done: DoneFn) => {
+ //get vfModule with generate ecompNaming should return userProvided false
+ let isUserProvidedNaming = service.isUserProvidedNaming(ServiceNodeTypes.VFmodule, generateVFModule(), generateVNF());
+ expect(isUserProvidedNaming).toBeFalsy();
+
+ //get vfModule without generate ecompNaming should return userProvided true
+ isUserProvidedNaming = service.isUserProvidedNaming(ServiceNodeTypes.VFmodule, generateVFModule(), generateVNF_ecompNamingFalse());
+ expect(isUserProvidedNaming).toBeTruthy();
+
+ //get vnf with generate ecompNaming should return userProvided false
+ isUserProvidedNaming = service.isUserProvidedNaming(ServiceNodeTypes.VF, generateVNF(), null);
+ expect(isUserProvidedNaming).toBeFalsy();
+
+ //get vnf without generate ecompNaming should return userProvided true
+ isUserProvidedNaming = service.isUserProvidedNaming(ServiceNodeTypes.VF, generateVNF_ecompNamingFalse(), null);
+ expect(isUserProvidedNaming).toBeTruthy();
+ done();
+ });
+ });
+
+ function generateVFModule() {
+ return {
+ 'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+ 'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+ 'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true,
+ 'inputs': {
+ '2017488_adiodvpe0_vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ '2017488_adiodvpe0_AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ }
+ }
+ };
+ }
+
+ function generateVFModule2() {
+ return {
+ 'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+ 'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+ 'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true,
+ 'inputs': {}
+ };
+ }
+
+ function generateVNF() {
+ return {
+ 'uuid': '0903e1c0-8e03-4936-b5c2-260653b96413',
+ 'invariantUuid': '00beb8f9-6d39-452f-816d-c709b9cbb87d',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017-388_ADIOD-vPE',
+ 'version': '1.0',
+ 'customizationUuid': '280dec31-f16d-488b-9668-4aae55d6648a',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017-388_ADIOD-vPE 1',
+ 'vfModules': {},
+ 'volumeGroups': {}
+ };
+ }
+
+ function generateVNF_ecompNamingFalse() {
+ return {
+ 'uuid': '0903e1c0-8e03-4936-b5c2-260653b96413',
+ 'invariantUuid': '00beb8f9-6d39-452f-816d-c709b9cbb87d',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017-388_ADIOD-vPE',
+ 'version': '1.0',
+ 'customizationUuid': '280dec31-f16d-488b-9668-4aae55d6648a',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'ecomp_generated_naming': "false",
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=false}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017-388_ADIOD-vPE 1',
+ 'vfModules': {},
+ 'volumeGroups': {}
+ };
+ }
+
+});
+
+
+
+
diff --git a/vid-webpack-master/src/app/services/service-planning.service.ts b/vid-webpack-master/src/app/services/service-planning.service.ts
new file mode 100644
index 000000000..75720c8a1
--- /dev/null
+++ b/vid-webpack-master/src/app/services/service-planning.service.ts
@@ -0,0 +1,282 @@
+import {Injectable} from '@angular/core';
+import {Constants} from "../shared/utils/constants";
+import {Utils} from "../utils/utils";
+import * as _ from 'lodash';
+import Parameter = Constants.Parameter;
+import {ITreeNode} from "angular-tree-component/dist/defs/api";
+import {ServiceInstance} from "../shared/models/serviceInstance";
+import {VNFModel} from "../shared/models/vnfModel";
+import {ServiceNodeTypes} from "../shared/models/ServiceNodeTypes";
+import {VfModuleMap} from "../shared/models/vfModulesMap";
+import {VnfInstance} from "../shared/models/vnfInstance";
+import {VfModuleTreeNode} from "../shared/models/vfModuleTreeNode";
+import {VfModule} from "../shared/models/vfModule";
+import {VnfTreeNode} from "../shared/models/vnfTreeNode";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../store/reducers";
+import {InputType} from "../shared/models/inputTypes";
+
+
+@Injectable()
+export class ServicePlanningService {
+
+ modelDataTree: any[] = [];
+ drawingDataTree: any[] = [];
+ service: any = {name:'My Service'} ;
+ public requiredFields = {
+ VF: [InputType.LCP_REGION, InputType.TENANT, InputType.PLATFORM],
+ VFmodule: []
+ };
+
+ constructor(private store: NgRedux<AppState>) {}
+
+
+ public getServiceName() :string{
+ return this.service.name;
+ }
+
+ public getServiceInstance(serviceModelId): ServiceInstance {
+ return this.store.getState().service.serviceInstance[serviceModelId];
+ }
+
+ public getVnfInstance(serviceModelId, vnfModelName): VnfInstance {
+ return this.getServiceInstance(serviceModelId).vnfs[vnfModelName];
+ }
+
+ public getVfModuleMap(serviceModelId, vnfModelName, vfModuleModelName): VfModuleMap {
+ let vnfInstance = this.getVnfInstance(serviceModelId, vnfModelName);
+ return _.get(vnfInstance, ['vfModules', vfModuleModelName]);
+ }
+
+ public convertServiceModelToTreeNodes(serviceModel) {
+ let _this = this;
+
+ _.forOwn(serviceModel.vnfs, function(item, key) {
+ _this.addFirstLevelModel(key, item, item.type, serviceModel);
+ });
+
+ _.forOwn(serviceModel.configurations, function(item, key) {
+ _this.addFirstLevelModel(key, item, ServiceNodeTypes.Configuration, serviceModel);
+ });
+
+ _.forOwn(serviceModel.networks, function(network, key) {
+ _this.addFirstLevelModel(key, network, ServiceNodeTypes.Network, serviceModel);
+ });
+
+ return this.modelDataTree;
+ }
+
+ private addFirstLevelModel(key, value, valueType, serviceModel) {
+
+ let node = this.convertItemToTreeNode(key, value, valueType, null, false);
+ let vnfInstance = this.getVnfInstance(serviceModel.service.uuid, key);
+ if(value.vfModules) {
+ node.children = Object.keys(value.vfModules).map((vmKey) =>
+ this.convertItemToTreeNode(vmKey, value.vfModules[vmKey], ServiceNodeTypes.VFmodule, value, !vnfInstance));
+ }
+ this.modelDataTree.push(node);
+ }
+
+ private convertItemToTreeNode(key, value, valueType, parentModel , disabled) {
+
+ return {
+ id: value.uuid,
+ name: key,
+ tooltip: valueType,
+ type: valueType,
+ count: value.count || 0,
+ max: value.max || 1,
+ children: [],
+ disabled: disabled,
+ dynamicInputs: this.updateDynamicInputsVnfDataFromModel(valueType, value),
+ userProvidedNaming: this.isUserProvidedNaming(valueType, value, parentModel)
+ }
+ }
+
+ public convertServiceInstanceToTreeData(serviceInstance: ServiceInstance, modelId: string): any {
+ let drawingBoardData = [];
+ let _this = this;
+ _.forOwn(serviceInstance.vnfs, (vnfInstance, vnfModelName) => {
+ let vnfModel: VNFModel = _this.store.getState().service.serviceHierarchy[modelId].vnfs[vnfModelName];
+ let vnfNode = new VnfTreeNode(vnfInstance, vnfModel);
+
+ let vfModuleNodes = [];
+ _.forOwn(vnfInstance.vfModules, (vfModuleMap, vfModuleModelName) => {
+ _.forOwn(vfModuleMap, (vfModuleInstance, vfModuleInstsanceName) => {
+ let vfModule: VfModule = _this.store.getState().service.serviceHierarchy[modelId].vnfs[vnfModelName].vfModules[vfModuleModelName];
+ let vfModuleNode: VfModuleTreeNode = new VfModuleTreeNode(vfModuleInstance, vfModule, vfModuleModelName);
+ vfModuleNodes.push(vfModuleNode);
+ });
+ });
+ vnfNode.children = vfModuleNodes;
+ drawingBoardData.push(vnfNode);
+ });
+
+ return drawingBoardData;
+ }
+
+ public getArbitraryInputs(inputs) {
+ let parameter;
+ let parameterList = [];
+ for (let key in inputs) {
+ parameter = {
+ id : key,
+ type : Parameter.STRING,
+ name : key,
+ value : inputs[key][Parameter.DEFAULT],
+ isRequired : inputs[key][Parameter.REQUIRED],
+ description : inputs[key][Parameter.DESCRIPTION]
+ };
+ switch (inputs[key][Parameter.TYPE]) {
+ case Parameter.INTEGER:
+ parameter.type = Parameter.NUMBER;
+ break;
+ case Parameter.BOOLEAN:
+ parameter.type = Parameter.BOOLEAN;
+ break;
+ case Parameter.RANGE:
+ break;
+ case Parameter.LIST:
+ parameter.type = Parameter.LIST;
+ break;
+ case Parameter.MAP:
+ parameter.type = Parameter.MAP;
+ break;
+ }
+ if ( Utils.hasContents(inputs[key][Parameter.CONSTRAINTS])
+ && ( inputs[key][Parameter.CONSTRAINTS].length > 0 ) ) {
+ let constraintsArray = inputs[key][Parameter.CONSTRAINTS];
+ this.addConstraintParameters (parameterList, constraintsArray, key, inputs, parameter);
+ }
+ else {
+
+ parameterList.push(parameter);
+ }
+ }
+ return parameterList;
+ }
+
+ private addConstraintParameters(parameterList, constraintsArray, key, inputs, parameter) {
+ // If there are constraints and the operator is "valid_values",
+ // use a select parameter type.
+ let i:number = constraintsArray.length;
+ let parameterPushed: boolean = false;
+ if ( i > 0 ) {
+ while ( (i--) && (!parameterPushed) ) {
+ let keys = Object.keys(constraintsArray[i]);
+ for ( let operator in keys ) {
+ switch (keys[operator]) {
+ case Parameter.VALID_VALUES:
+ let j: number = constraintsArray[i][Parameter.VALID_VALUES].length;
+ if ( j > 0 ) {
+ let oList = [];
+ let option;
+ while (j--) {
+ option = {
+ name: constraintsArray[i][Parameter.VALID_VALUES][j],
+ isDefault: false
+ };
+ if ( (Utils.hasContents (inputs[key][Parameter.DEFAULT]) )
+ && (inputs[key][Parameter.DEFAULT] === constraintsArray[i][Parameter.VALID_VALUES][j] ) ) {
+ option = {
+ name: constraintsArray[i][Parameter.VALID_VALUES][j],
+ isDefault: true
+ }
+ }
+ oList.push(option);
+ }
+ parameter.type = Parameter.SELECT;
+ parameter.optionList = oList;
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+
+ case Parameter.EQUAL:
+ if ( constraintsArray[i][Parameter.EQUAL] != null ) {
+ //override parameter type
+ parameter.type = Parameter.STRING;
+ parameter.isReadOnly = true;
+ parameter.value = constraintsArray[i][Parameter.EQUAL];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+
+ case Parameter.LENGTH:
+ if ( constraintsArray[i][Parameter.LENGTH] != null ) {
+ parameter.minLength = constraintsArray[i][Parameter.LENGTH];
+ parameter.maxLength = constraintsArray[i][Parameter.LENGTH];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+ case Parameter.MAX_LENGTH:
+ if ( constraintsArray[i][Parameter.MAX_LENGTH] != null ) {
+ parameter.maxLength = constraintsArray[i][Parameter.MAX_LENGTH];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+ case Parameter.MIN_LENGTH:
+ if ( constraintsArray[i][Parameter.MIN_LENGTH] != null ) {
+ parameter.minLength = constraintsArray[i][Parameter.MIN_LENGTH];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+ case Parameter.IN_RANGE:
+ if ( constraintsArray[i][Parameter.IN_RANGE] != null ) {
+ if (constraintsArray[i][Parameter.IN_RANGE].length > 1 ) {
+ parameter.min = constraintsArray[i][Parameter.IN_RANGE][0];
+ parameter.max = constraintsArray[i][Parameter.IN_RANGE][1];
+ parameter.type = Parameter.NUMBER;
+ parameter.value = inputs[key][Parameter.DEFAULT];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ }
+ break;
+ case Parameter.GREATER_THAN:
+ if ( constraintsArray[i][Parameter.GREATER_THAN] != null ) {
+ parameter.type = Parameter.NUMBER;
+ parameter.min = constraintsArray[i][Parameter.GREATER_THAN];
+ parameter.value = inputs[key][Parameter.DEFAULT];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+ }//switch
+ }//for
+ }//while
+ }//if
+ };
+
+ public static isVfModule(node:ITreeNode): boolean {
+ return node.data.type=='VFmodule';
+ }
+
+ public static isVnf(node:ITreeNode): boolean {
+ return node.data.type == ServiceNodeTypes.VF;
+ }
+
+ updateDynamicInputsVnfDataFromModel(modelType: string, model: any): Array<any> {
+ let displayInputs;
+ if (modelType === ServiceNodeTypes.VFmodule) {
+ displayInputs = model.inputs;
+ }
+ return _.isEmpty(displayInputs) ? [] : this.getArbitraryInputs(displayInputs);
+ }
+
+ isUserProvidedNaming(type: string, nodeModel: any, parentModel: any) : boolean {
+ let model;
+ if (type === ServiceNodeTypes.VFmodule) {
+ model = parentModel;
+ }
+ else {
+ model = nodeModel;
+ }
+ const ecompGeneratedNaming = model.properties.ecomp_generated_naming;
+ return ecompGeneratedNaming !== undefined && ecompGeneratedNaming === "false";
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/api.service.ts b/vid-webpack-master/src/app/shared/api.service.ts
new file mode 100644
index 000000000..a69d91ea4
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/api.service.ts
@@ -0,0 +1,6 @@
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class ApiService {
+ title = 'Angular 2';
+}
diff --git a/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts b/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts
new file mode 100644
index 000000000..fd58b6507
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts
@@ -0,0 +1,27 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector : 'custom-ellipsis',
+ template: `
+ <span
+ class="ellipsis"
+ id="{{id}}"
+ tooltip="{{value}}">{{value}}</span>`,
+ styles : [
+ `
+ .ellipsis {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: inline-block;
+ width: 99%;
+ text-align: left;
+ }
+ `
+ ]
+})
+export class EllipsisComponent {
+ @Input() value : string;
+ @Input() id : string;
+
+}
diff --git a/vid-webpack-master/src/app/shared/components/error/error.component.service.ts b/vid-webpack-master/src/app/shared/components/error/error.component.service.ts
new file mode 100644
index 000000000..35b83f0b6
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/error/error.component.service.ts
@@ -0,0 +1,35 @@
+import {Injectable} from "@angular/core";
+import {Subject} from "rxjs/Subject";
+import { MessageBoxService } from '../messageBox/messageBox.service';
+import { MessageBoxData, ModalSize, ModalType } from '../messageBox/messageBox.data';
+
+@Injectable()
+export class ErrorService {
+ static showErrorWithMessage(error : ErrorMessage) : void {
+ setTimeout(()=>{
+ let messageBoxData : MessageBoxData = new MessageBoxData(
+ error.title, // modal title
+ error.text,
+
+ ModalType.error,
+ ModalSize.medium,
+ [
+ {text:"Close", size:"large", closeModal:true}
+ ]);
+ MessageBoxService.openModal.next(messageBoxData);
+ }
+ ,500);
+ }
+}
+
+export class ErrorMessage {
+ title : string;
+ text : string;
+ errorNumber : number;
+
+ constructor( title : string, text : string,errorNumber : number){
+ this.title = title;
+ this.text = text;
+ this.errorNumber = errorNumber;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.html b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.html
new file mode 100644
index 000000000..daa35e659
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.html
@@ -0,0 +1,4 @@
+<div *ngIf="message">
+ <span class="icon-alert"></span>
+ <span class="message">{{message}}</span>
+</div>
diff --git a/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.scss b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.scss
new file mode 100644
index 000000000..d174f511c
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.scss
@@ -0,0 +1,14 @@
+.icon-alert {
+ margin-top: 10px;
+ &:before {
+ content: "\e904";
+ font-size: 16px;
+ color: #cf2a2a;
+ }
+}
+
+.message {
+ font-size: 12px;
+ line-height: 14px;
+ color: #cf2a2a;
+}
diff --git a/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.ts b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.ts
new file mode 100644
index 000000000..a20b26030
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.ts
@@ -0,0 +1,10 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector : 'form-control-error',
+ templateUrl : 'formControlError.component.html',
+ styleUrls : ['formControlError.component.scss']
+})
+export class FormControlErrorComponent {
+ @Input() message = null;
+}
diff --git a/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.html b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.html
new file mode 100644
index 000000000..4c794e686
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.html
@@ -0,0 +1,10 @@
+<div *ngIf="message" class="row row-padding">
+ <div class="col-md-2 icon-div"><span class="icon-alert"></span></div>
+ <div class="col-md-10 left-align parentbox">
+ <div class="childbox">
+ <span>{{message}}</span>
+ </div>
+ </div>
+</div>
+
+
diff --git a/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.scss b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.scss
new file mode 100644
index 000000000..5271cad49
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.scss
@@ -0,0 +1,48 @@
+.icon-alert {
+ margin-top: 10px;
+ &:before {
+ content: "\e904";
+ font-size: 30px;
+ color: #ffffff;
+ }
+}
+
+.icon-div {
+ background: rgb(207,41,41);
+ text-align: center;
+ padding-top: 18px;
+ width: 77px;
+ height: 110px;
+ float: left;
+}
+
+
+.error-title {
+ color: #cf2a2a;
+}
+
+.row-padding {
+ margin-left: 0 !important;
+ margin-right: 0 !important;
+}
+
+.left-align {
+ text-align: left;
+}
+
+.parentbox {
+ padding-right: 0;
+}
+
+.parentbox:before {
+ content: ' ';
+ display: inline-block;
+ vertical-align: middle;
+ height: 100%;
+}
+
+.childbox {
+ color: #cf2a2a;
+ display: inline-block;
+ vertical-align: middle;
+}
diff --git a/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.ts b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.ts
new file mode 100644
index 000000000..0c0516a4d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.ts
@@ -0,0 +1,11 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector : 'form-general-error',
+ templateUrl : 'formGeneralErrors.component.html',
+ styleUrls : ['formGeneralErrors.component.scss']
+})
+
+export class FormGeneralErrorsComponent {
+ @Input() message : string = null;
+}
diff --git a/vid-webpack-master/src/app/shared/components/messageBox/messageBox.component.ts b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.component.ts
new file mode 100644
index 000000000..08e199cf5
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.component.ts
@@ -0,0 +1,50 @@
+/************************************************************************************************
+ * @Component: Message box component
+ * In order to use component you need to do a number of things:
+ * 1) Inside your component constructor you need to add listener to the button trigger.
+ * 2) Inside the listener you should write your callback logic.
+ *
+ * Example:
+ * @Component({
+ * selector : 'some-component'
+ * ...
+ * })
+ *
+ * export class SomeComponent {
+ * openModal() : void {
+ * let messageBoxData : MessageBoxData = new MessageBoxData(
+ * "title", // modal title
+ * "message", ModalType.alert, // modal type
+ * [
+ {text:"Save", size:"'x-small'", callback: this.someFunction.bind(this), closeModal:true},
+ {text:"Cancel", size:"'x-small'", closeModal:true}
+ ]);
+ *
+ * MessageBoxService.openModal.next(messageBoxData); // open modal
+ * }
+ * }
+
+ ************************************************************************************************/
+
+
+import { Component } from '@angular/core';
+import { MessageBoxData} from './messageBox.data';
+import { MessageBoxService } from './messageBox.service';
+import { SdcUiComponents } from 'sdc-ui/lib/angular';
+
+@Component({
+ selector: 'message-box',
+ template: '<div id="message-box"></div>'
+})
+
+export class MessageBoxComponent {
+ modalService: SdcUiComponents.ModalService;
+
+ constructor(modalService: SdcUiComponents.ModalService, private _messageBoxService : MessageBoxService) {
+ this.modalService = modalService;
+ MessageBoxService.openModal.subscribe((messageBoxData: MessageBoxData) => {
+ modalService.openModal(this._messageBoxService.setConfig(messageBoxData))
+ });
+ }
+}
+
diff --git a/vid-webpack-master/src/app/shared/components/messageBox/messageBox.data.ts b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.data.ts
new file mode 100644
index 000000000..165140ba7
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.data.ts
@@ -0,0 +1,51 @@
+import { Subject } from 'rxjs/Subject';
+
+export class MessageBoxData {
+ title?: string;
+ message?: string;
+ size : ModalSize;
+ type: ModalType;
+ buttons: Array<IModalButtonComponent>;
+
+ constructor(title: string, message: string, type: ModalType, size : ModalSize, buttons: Array<IModalButtonComponent>) {
+ this.title = title;
+ this.message = message;
+ this.size = size;
+ this.type = type;
+ this.buttons = buttons;
+ }
+}
+
+export interface IModalConfig {
+ size?: string;
+ title?: string;
+ message?: string;
+ buttons?: Array<IModalButtonComponent>;
+ type?: string;
+}
+export interface IButtonComponent {
+ text: string;
+ disabled?: boolean;
+ type?: string;
+ size?: string;
+}
+export interface IModalButtonComponent extends IButtonComponent {
+ callback?: Function;
+ closeModal?: boolean;
+}
+export enum ModalType {
+ alert = "alert",
+ error = "error",
+ standard = "info",
+ custom = "custom",
+}
+export enum ModalSize {
+ xlarge = "xl",
+ large = "l",
+ medium = "md",
+ small = "sm",
+ xsmall = "xsm",
+}
+
+
+
diff --git a/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.spec.ts b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.spec.ts
new file mode 100644
index 000000000..89562ac54
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.spec.ts
@@ -0,0 +1,49 @@
+import { TestBed, getTestBed } from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+
+import { MessageBoxService } from './messageBox.service';
+import {MessageBoxData, ModalSize, ModalType } from './messageBox.data';
+
+describe('MessageBoxService', () => {
+ let injector;
+ let service: MessageBoxService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [MessageBoxService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(MessageBoxService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ describe('#setConfig', () => {
+ it('should return <IModalConfig>', (done: DoneFn) => {
+ let title = "Delete Instantiation";
+ let message = "You are about to stop the instantiation process of this service. \nAll data will be lost. Are you sure you want to stop?";
+ let messageBoxData : MessageBoxData = new MessageBoxData(
+ title,
+ message,
+ ModalType.alert,
+ ModalSize.medium,
+ [
+ {text:"Stop Instantiation", size:"large", closeModal:true},
+ {text:"Cancel", size:"medium", closeModal:true}
+ ]);
+
+ let result = service.setConfig(messageBoxData);
+ expect(result.title).toEqual(title);
+ expect(result.message).toEqual(message);
+ expect(result.buttons.length).toEqual(2);
+ expect(result.type).toEqual(ModalType.alert);
+ expect(result.size).toEqual(ModalSize.medium);
+ done();
+ });
+ });
+});
diff --git a/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.ts b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.ts
new file mode 100644
index 000000000..eaa012d3b
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.ts
@@ -0,0 +1,18 @@
+import { Injectable } from '@angular/core';
+import { Subject } from 'rxjs/Subject';
+import { IModalConfig, MessageBoxData, ModalSize, ModalType } from './messageBox.data';
+
+@Injectable()
+export class MessageBoxService {
+ static openModal: Subject<MessageBoxData> = new Subject<MessageBoxData>();
+ setConfig(messageBoxData: MessageBoxData) : IModalConfig{
+ return {
+ size : ModalSize.medium,
+ title : messageBoxData.title,
+ type : messageBoxData.type,
+ message : messageBoxData.message,
+ buttons: messageBoxData.buttons
+ };
+ }
+
+}
diff --git a/vid-webpack-master/src/app/shared/components/model-information/model-information.component.ts b/vid-webpack-master/src/app/shared/components/model-information/model-information.component.ts
new file mode 100644
index 000000000..fea4c44c7
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/model-information/model-information.component.ts
@@ -0,0 +1,42 @@
+import {Component, Input} from '@angular/core';
+import * as _ from 'lodash';
+
+@Component({
+ selector: 'model-information',
+ templateUrl: 'model-information.html',
+ styleUrls: ['model-information.scss']
+})
+
+export class ModelInformationComponent {
+ private _modelInformationItems: Array<ModelInformationItem>;
+
+
+ get modelInformationItems(): Array<ModelInformationItem> {
+ return this._modelInformationItems;
+ }
+
+ @Input()
+ set modelInformationItems(_modelInformationItems: Array<ModelInformationItem>) {
+ if (_modelInformationItems) {
+ this._modelInformationItems = _modelInformationItems.filter(x => x.mandatory || (!_.isEmpty(x.values) && !_.isEmpty(x.values[0])));
+ }
+ }
+}
+
+
+export class ModelInformationItem {
+ label: string;
+ testsId: string;
+ values: Array<string>;
+ toolTipText: string;
+ mandatory: boolean;
+
+ constructor(label: string, testsId: string, values: Array<any>, toolTipText: string = "", mandatory: boolean = false,nested:boolean=false) {
+ this.label = label;
+ this.testsId = testsId;
+ this.values = values;
+ this.toolTipText = toolTipText;
+ this.mandatory = mandatory;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/shared/components/model-information/model-information.html b/vid-webpack-master/src/app/shared/components/model-information/model-information.html
new file mode 100644
index 000000000..456dfdee4
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/model-information/model-information.html
@@ -0,0 +1,12 @@
+<div id="model-information">
+ <div *ngFor="let item of modelInformationItems" class="item" attr.data-tests-id="model-item-{{item.label}}">
+ <tooltip-content #a>
+ <span> {{item.toolTipText}}</span>
+ </tooltip-content>
+
+ <div class="wrapper" [tooltip]="a" [tooltipDisabled]="!item.toolTipText" tooltipPlacement="top" [tooltipAnimation]="false">
+ <label attr.data-tests-id="model-item-label-{{item.testsId}}">{{item.label}}</label>
+ <div *ngFor="let value of item.values" attr.data-tests-id="model-item-value-{{item.testsId}}">{{value}}</div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/shared/components/model-information/model-information.scss b/vid-webpack-master/src/app/shared/components/model-information/model-information.scss
new file mode 100644
index 000000000..cd42136ed
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/model-information/model-information.scss
@@ -0,0 +1,34 @@
+#model-information {
+ overflow: auto;
+
+}
+
+tooltip-content span {
+ font-family: OpenSans-Regular;
+ font-size: 12px;
+ color: #FFFFFF;
+ letter-spacing: 0;
+ line-height: 16px;
+}
+
+.item {
+ display: block;
+
+ .wrapper {
+
+ display: inline-block;
+ margin-bottom: 25px;
+
+ label {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ div {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ }
+ }
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.html b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.html
new file mode 100644
index 000000000..bbe7bc78c
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.html
@@ -0,0 +1,5 @@
+<div class="width-100">
+ <div class="text-title" [ngClass]="titleClass">{{title}}</div>
+ <div class="text-subtitle" [ngClass]="subtitleClass">{{subtitle}}</div>
+ <img id="not-node-img-id" src="{{iconPath}}" alt="" class="no-content-icon" [ngClass]="iconClass" data-tests-id="no-content-icon">
+</div>
diff --git a/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.scss b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.scss
new file mode 100644
index 000000000..1320ef731
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.scss
@@ -0,0 +1,26 @@
+.width-100 {
+ width: 100%;
+ margin-top: 126px;
+
+}
+
+.text-title {
+ font-family: OpenSans-Semibold;
+ font-size: 16px;
+ color: #4A4A4A;
+ text-align: center;
+}
+
+.text-subtitle {
+ font-family: OpenSans-Regular;
+ font-size: 16px;
+ color: #959595;
+ text-align: center;
+ margin-top: 7px;
+}
+
+.no-content-icon {
+ display: block;
+ vertical-align: middle;
+ margin: 30px auto;
+}
diff --git a/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.ts b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.ts
new file mode 100644
index 000000000..7f4e98294
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.ts
@@ -0,0 +1,23 @@
+import {Component, Input} from '@angular/core';
+
+@Component({
+ selector: 'no-content-message-and-icon',
+ templateUrl: './no-content-message-and-icon.component.html',
+ styleUrls: ['./no-content-message-and-icon.component.scss']
+})
+
+
+export class NoContentMessageAndIconComponent {
+ constructor() {}
+
+ @Input() title: string;
+ @Input() subtitle: string;
+ @Input() iconPath: string;
+
+ @Input() titleClass: string="";
+ @Input() subtitleClass: string="";
+ @Input() iconClass: string="";
+
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/components/popover/popover.component.html b/vid-webpack-master/src/app/shared/components/popover/popover.component.html
new file mode 100644
index 000000000..c5515596c
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/popover/popover.component.html
@@ -0,0 +1,8 @@
+<div
+ triggers="mouseenter:mouseleave"
+ popover="{{value}}"
+ [hidden]="value == null"
+ container="body">
+ <ng-content ></ng-content>
+</div>
+
diff --git a/vid-webpack-master/src/app/shared/components/popover/popover.component.scss b/vid-webpack-master/src/app/shared/components/popover/popover.component.scss
new file mode 100644
index 000000000..ca2800a27
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/popover/popover.component.scss
@@ -0,0 +1,4 @@
+.popover.popover-top.top {
+ color : green !important;
+ font-size: 10px;
+}
diff --git a/vid-webpack-master/src/app/shared/components/popover/popover.component.ts b/vid-webpack-master/src/app/shared/components/popover/popover.component.ts
new file mode 100644
index 000000000..d6a4c3ae1
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/popover/popover.component.ts
@@ -0,0 +1,17 @@
+import {Component, Input} from "@angular/core";
+
+@Component({
+ selector: 'custom-popover',
+ templateUrl: 'popover.component.html',
+ styles: [`
+ :host >>> .popover {
+ font-size: 13px;
+ text-align: left;
+ z-index: 10000;
+ }
+ `]
+})
+
+export class PopoverComponent {
+ @Input() value: String;
+}
diff --git a/vid-webpack-master/src/app/shared/components/spinner/spinner.component.html b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.html
new file mode 100644
index 000000000..cb11feea8
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.html
@@ -0,0 +1,2 @@
+<div *ngIf="show"
+ class="spinner"></div>
diff --git a/vid-webpack-master/src/app/shared/components/spinner/spinner.component.scss b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.scss
new file mode 100644
index 000000000..d31dfed80
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.scss
@@ -0,0 +1,87 @@
+.spinner {
+ height: 150px;
+ width: 150px;
+ margin: 0 auto;
+ -webkit-animation: rotation .6s infinite linear;
+ animation: rotation .6s infinite linear;
+ border: 6px solid rgba(0, 174, 239, 0.01);
+ border-radius: 100%;
+ position: absolute;
+ z-index: 1000;
+ left: 50%;
+ right: 50%;
+ top: 50%;
+ bottom: 50%;
+}
+
+
+
+.spinner:before {
+ content: "";
+ display: block;
+ position: absolute;
+ top: -6px;
+ height: 100%;
+ width: 100%;
+ border-top: 6px solid #009fdb;
+ border-left: 6px solid transparent;
+ border-bottom: 6px solid #c3161600;
+ border-right: 6px solid transparent;
+ border-radius: 100%;
+}
+
+@-webkit-keyframes rotation {
+ from {-webkit-transform: rotate(0deg);}
+ to {-webkit-transform: rotate(359deg);}
+}
+@-moz-keyframes rotation {
+ from {-moz-transform: rotate(0deg);}
+ to {-moz-transform: rotate(359deg);}
+}
+@-o-keyframes rotation {
+ from {-o-transform: rotate(0deg);}
+ to {-o-transform: rotate(359deg);}
+}
+@keyframes rotation {
+ from {transform: rotate(0deg);}
+ to {transform: rotate(359deg);}
+}
+
+.spinner-sm {
+ height:16px;
+ width:16px;
+}
+
+.spinner-md {
+ height:40px;
+ width:40px;
+}
+
+.spinner-lr {
+ height:150px;
+ width:150px;
+}
+
+.spinner-red {
+ border:6px solid rgba(216, 27, 34, .15);
+}
+
+.spinner-red:before {
+ border-top:6px solid rgba(216, 27, 34, 1);
+}
+
+.spinner-green {
+ border:6px solid rgba(40, 183, 121, .15);
+}
+
+.spinner-green:before {
+ border-top:6px solid rgba(40, 183, 121, 1);
+}
+
+.spinner-grey {
+ border:6px solid rgba(139, 146, 154, .15);
+}
+
+.spinner-grey:before {
+ border-top:6px solid rgba(139, 146, 154, 1);
+}
diff --git a/vid-webpack-master/src/app/shared/components/spinner/spinner.component.spec.ts b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.spec.ts
new file mode 100644
index 000000000..531ee8c62
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.spec.ts
@@ -0,0 +1,42 @@
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {HttpClientTestingModule} from '@angular/common/http/testing';
+import { SpinnerComponent } from './spinner.component';
+
+describe('Spinner component', () => {
+ let component: SpinnerComponent;
+ let fixture: ComponentFixture<SpinnerComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [],
+ declarations: [SpinnerComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SpinnerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('component should be defined', () => {
+ expect(component).toBeDefined();
+ });
+
+
+ it('component constructor should subscribe of showSpinner event with true', ()=> {
+ SpinnerComponent.showSpinner.next(true);
+ expect(component.show).toBeTruthy();
+ });
+
+ it('component constructor should subscribe of showSpinner event with false', ()=> {
+ SpinnerComponent.showSpinner.next(false);
+ expect(component.show).toBeFalsy();
+ });
+
+
+
+
+});
diff --git a/vid-webpack-master/src/app/shared/components/spinner/spinner.component.ts b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.ts
new file mode 100644
index 000000000..0ce5d2074
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.ts
@@ -0,0 +1,18 @@
+import { Component, Input } from '@angular/core';
+import { Subject } from 'rxjs/Subject';
+
+@Component({
+ selector : 'spinner-component',
+ templateUrl : './spinner.component.html',
+ styleUrls : ['./spinner.component.scss']
+})
+export class SpinnerComponent {
+ show : boolean = false;
+ static showSpinner: Subject<boolean> = new Subject<boolean>();
+
+ constructor(){
+ SpinnerComponent.showSpinner.subscribe((status) => {
+ this.show = status;
+ })
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.spec.ts b/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.spec.ts
new file mode 100644
index 000000000..ec9f3f73e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.spec.ts
@@ -0,0 +1,39 @@
+import { ReflectiveInjector } from '@angular/core';
+import { NumbersLettersUnderscoreValidator } from './numbersLettersUnderscore.validator';
+
+describe('Numbers letters underscore validator', () => {
+ let injector;
+ let service: NumbersLettersUnderscoreValidator;
+
+ beforeEach(() => {
+
+ let injector = ReflectiveInjector.resolveAndCreate([
+ NumbersLettersUnderscoreValidator
+ ]);
+
+ service = injector.get(NumbersLettersUnderscoreValidator);
+ });
+
+
+ describe('#valid', () => {
+ it("'legal' should return null", ()=> {
+ let legalVal: string = "legal";
+ let result = NumbersLettersUnderscoreValidator.valid(legalVal);
+ expect(result).toBeNull();
+ });
+
+ it("'illegal' should return object with invalidNumberLettersUnderscore true", ()=> {
+ let illegalVal: string = "illegal-Val";
+ let result = NumbersLettersUnderscoreValidator.valid(illegalVal);
+ expect(result.invalidNumberLettersUnderscore).toBeTruthy();
+ });
+
+ it("'null' should return null", ()=> {
+ let nullVal: string = null
+ let result = NumbersLettersUnderscoreValidator.valid(nullVal);
+ expect(result).toBeNull();
+ });
+
+
+ });
+});
diff --git a/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.ts b/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.ts
new file mode 100644
index 000000000..418bdfc4d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.ts
@@ -0,0 +1,20 @@
+import { Injectable } from '@angular/core';
+import { isNullOrUndefined, isString } from 'util';
+
+@Injectable()
+export class NumbersLettersUnderscoreValidator {
+ static valid(control: any) {
+ let reg = /^[a-zA-Z0-9_]*$/;
+
+ if(isNullOrUndefined(control)) return null;
+ let val = isString(control) ? control : control.value;
+ if (val === null) {
+ return {'invalidNumberLettersUnderscore': true};
+ }
+ if (reg.test(val)) {
+ return null;
+ } else {
+ return {'invalidNumberLettersUnderscore': true};
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.spec.ts b/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.spec.ts
new file mode 100644
index 000000000..846ff70f2
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.spec.ts
@@ -0,0 +1,66 @@
+import {TestBed, ComponentFixture} from '@angular/core/testing';
+import {Component, DebugElement} from "@angular/core";
+import {By} from "@angular/platform-browser";
+import { InputPreventionPatternDirective } from './inputPreventionPattern.directive';
+
+@Component({
+ template: `<input
+ patternInput
+ pattern="^[a-zA-Z0-9_]*$">`
+})
+class TestHoverFocusComponent {
+}
+
+
+describe('InputPrevention Pattern Directive', () => {
+
+ let component: TestHoverFocusComponent;
+ let fixture: ComponentFixture<TestHoverFocusComponent>;
+ let directiveInstance : InputPreventionPatternDirective;
+ let inputEl: DebugElement;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [TestHoverFocusComponent, InputPreventionPatternDirective]
+ });
+ fixture = TestBed.createComponent(TestHoverFocusComponent);
+ component = fixture.componentInstance;
+ inputEl = fixture.debugElement.query(By.css('input'));
+ directiveInstance = inputEl.injector.get(InputPreventionPatternDirective);
+ });
+
+ it('directive should be defined', () => {
+ expect(directiveInstance).toBeDefined();
+ });
+
+ it('pattern exists', () => {
+ expect(inputEl.nativeElement.pattern).toEqual('^[a-zA-Z0-9_]*$');
+ });
+
+ it('kepress legal input', () => {
+ fixture.detectChanges();
+ inputEl.nativeElement.value = "legalInput";
+ expect(new RegExp(inputEl.nativeElement.pattern).test(inputEl.nativeElement.value)).toBeTruthy();
+ });
+
+ it('kepress illegal input', () => {
+ inputEl.triggerEventHandler('kepress', " ");
+ fixture.detectChanges();
+ expect(inputEl.nativeElement.value).toBe('');
+ });
+
+ it('kepress event legal input should return event', () => {
+ const event = <any>{ key: 'A' };
+ inputEl.nativeElement.value = "legalInput";
+ let result = directiveInstance.onKeypress(event);
+ expect(result).toBe(event);
+ });
+
+ it('kepress event illegal input should prevent default', () => {
+ const event = <any>{key: '-', preventDefault : function () {} };
+ spyOn(event, 'preventDefault');
+ inputEl.nativeElement.value = "-";
+ let result = directiveInstance.onKeypress(event);
+ expect(event.preventDefault).toHaveBeenCalled();
+ });
+});
diff --git a/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.ts b/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.ts
new file mode 100644
index 000000000..dada09bef
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.ts
@@ -0,0 +1,24 @@
+import {Directive, ElementRef} from '@angular/core';
+
+@Directive({
+ selector: '[patternInput]',
+ host: {
+ '(keypress)': 'onKeypress($event)'
+ }
+})
+export class InputPreventionPatternDirective{
+ inputElement : ElementRef;
+ constructor(el: ElementRef) {
+ this.inputElement = el;
+ }
+
+ onKeypress(event: KeyboardEvent) {
+ const pattern = new RegExp(this.inputElement.nativeElement.pattern);
+ if(pattern){
+ if(!pattern.test(event['key'])){
+ event.preventDefault();
+ }
+ }
+ return event;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/directives/svg/svg.directive.html b/vid-webpack-master/src/app/shared/directives/svg/svg.directive.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/directives/svg/svg.directive.html
diff --git a/vid-webpack-master/src/app/shared/directives/svg/svg.directive.ts b/vid-webpack-master/src/app/shared/directives/svg/svg.directive.ts
new file mode 100644
index 000000000..e4dc55a56
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/directives/svg/svg.directive.ts
@@ -0,0 +1,34 @@
+import { AfterContentChecked, AfterViewInit, Directive, ElementRef, Input } from '@angular/core';
+import { isNullOrUndefined } from 'util';
+
+
+/*
+ Temporary
+ Changing svg color and size.
+ color changing according to fill attribute
+ size according to viewBox
+*/
+@Directive({
+ selector: '[svg-directive]'
+})
+export class SvgDirective implements AfterContentChecked {
+ @Input('fill') fill: string = "black";
+ @Input('widthViewBox') widthViewBox: string = null;
+ @Input('heightViewBox') heightViewBox: string = null;
+
+ constructor(private elRef: ElementRef) {}
+ ngAfterContentChecked(): void {
+ if(this.elRef !== undefined && this.elRef.nativeElement.children !== undefined && this.elRef.nativeElement.children[0] !== undefined){
+ this.elRef.nativeElement.children[0].children[1].children[0].style.fill = this.fill;
+ if(this.elRef.nativeElement.children[0].children[1].children.length > 1){
+ this.elRef.nativeElement.children[0].children[1].children[1].style.fill = this.fill;
+ this.elRef.nativeElement.children[0].children[1].children[2].children[0].style.fill = this.fill;
+ }
+
+ if(this.widthViewBox && this.heightViewBox){
+ this.elRef.nativeElement.firstChild.setAttribute('viewBox', "1 1 " + this.widthViewBox + " " + this.heightViewBox)
+ }
+
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/index.ts b/vid-webpack-master/src/app/shared/index.ts
new file mode 100644
index 000000000..68fada65d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/index.ts
@@ -0,0 +1 @@
+export * from './api.service';
diff --git a/vid-webpack-master/src/app/shared/models/ServiceNodeTypes.ts b/vid-webpack-master/src/app/shared/models/ServiceNodeTypes.ts
new file mode 100644
index 000000000..f72b32d8b
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/ServiceNodeTypes.ts
@@ -0,0 +1,8 @@
+export enum ServiceNodeTypes {
+ VF = "VF",
+ VFmodule = "VFmodule",
+ Network = "Network",
+ Configuration = "Configuration"
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/models/aicZone.ts b/vid-webpack-master/src/app/shared/models/aicZone.ts
new file mode 100644
index 000000000..7b9e1ed4e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/aicZone.ts
@@ -0,0 +1,9 @@
+export class AicZone {
+ id: string;
+ name: string;
+
+ constructor(serviceJson){
+ this.id = serviceJson["zone-id"];
+ this.name = serviceJson["zone-name"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/categoryParams.ts b/vid-webpack-master/src/app/shared/models/categoryParams.ts
new file mode 100644
index 000000000..9e0052979
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/categoryParams.ts
@@ -0,0 +1,15 @@
+import {SelectOptionInterface} from "./selectOption";
+
+export class CategoryParams {
+ owningEntityList: SelectOptionInterface[];
+ projectList: SelectOptionInterface[];
+ lineOfBusinessList: SelectOptionInterface[];
+ platformList: SelectOptionInterface[];
+
+ constructor(owningEntityList=[], projectList=[], lob=[], platform=[]){
+ this.owningEntityList = owningEntityList;
+ this.projectList = projectList;
+ this.lineOfBusinessList = lob;
+ this.platformList = platform;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/dynamicInput.ts b/vid-webpack-master/src/app/shared/models/dynamicInput.ts
new file mode 100644
index 000000000..a08cdfc77
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/dynamicInput.ts
@@ -0,0 +1,123 @@
+export class DynamicInput<T>{
+
+ id: string;
+ name: string;
+ type: string;
+ description: string;
+ value: T;
+ prompt: any;
+ maxLength: number;
+ minLength: number;
+ isVisible: boolean;
+ isRequired: boolean;
+ isEnabled: boolean;
+ isReadOnly: boolean;
+
+
+ constructor(options: {
+ id?: string,
+ name?: string,
+ type: string,
+ description?: string,
+ value?: T,
+ prompt?: any,
+ maxLength?: number,
+ minLength?: number,
+ isVisible?: boolean,
+ isRequired?: boolean,
+ isEnabled?: boolean,
+ isReadOnly?: boolean,
+ }) {
+ this.id = options.id;
+ this.name = options.name || '';
+ this.type = options.type;
+ this.description = options.description || '';
+ this.value = options.value;
+ this.prompt = options.prompt;
+ this.maxLength = options.maxLength;
+ this.minLength = options.minLength;
+ this.isVisible = options.isVisible == false? options.isVisible: true;
+ this.isEnabled = options.isEnabled == false? options.isEnabled: true;
+ this.isRequired = options.isRequired == null? false: options.isRequired;
+ this.isReadOnly = options.isReadOnly == null? false: options.isReadOnly;
+ }
+}
+
+export class DynamicNumber extends DynamicInput<number> {
+
+ max: number;
+ min: number;
+
+ constructor(options: {
+ id?: string,
+ name?: string,
+ type: string,
+ description?: string,
+ value?: number,
+ prompt?: any,
+ maxLength?: number,
+ minLength?: number,
+ isVisible?: boolean,
+ isRequired?: boolean,
+ isEnabled?: boolean,
+ isReadOnly?: boolean,
+ max?: number,
+ min?: number
+ }){
+ super(options);
+ this.max = options.max;
+ this.min = options.min;
+ }
+
+}
+
+export class DynamicSelect extends DynamicInput<any> {
+ optionList: any[];
+
+ constructor(options: {
+ id?: string,
+ name?: string,
+ type: string,
+ description?: string,
+ value?: any,
+ prompt?: any,
+ maxLength?: number,
+ minLength?: number,
+ isVisible?: boolean,
+ isRequired?: boolean,
+ isEnabled?: boolean,
+ isReadOnly?: boolean,
+ optionList?: any[]
+ }) {
+ super(options);
+ this.optionList = options.optionList || [];
+ }
+}
+
+export class DynamicMultiSelect extends DynamicSelect {
+ selectedItems: any[];
+ settings: any;
+
+ constructor(options: {
+ id?: string,
+ name?: string,
+ type: string,
+ description?: string,
+ value?: any,
+ prompt?: any,
+ maxLength?: number,
+ minLength?: number,
+ isVisible?: boolean,
+ isRequired?: boolean,
+ isEnabled?: boolean,
+ isReadOnly?: boolean,
+ settings?: any,
+ optionList?: any[],
+ selectedItems?: any[]
+ }) {
+ super(options);
+ this.settings = options.settings || {};
+ this.selectedItems = options.selectedItems || [];
+ }
+}
+
diff --git a/vid-webpack-master/src/app/shared/models/externalComponentStatus.ts b/vid-webpack-master/src/app/shared/models/externalComponentStatus.ts
new file mode 100644
index 000000000..21ef61a8a
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/externalComponentStatus.ts
@@ -0,0 +1,11 @@
+export class ExternalComponentStatus {
+ component: string;
+ available: boolean;
+ metadata: any;
+
+ constructor(component: string, available: boolean, metadata: any) {
+ this.component = component;
+ this.available = available;
+ this.metadata = metadata;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/inputTypes.ts b/vid-webpack-master/src/app/shared/models/inputTypes.ts
new file mode 100644
index 000000000..1f7222f52
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/inputTypes.ts
@@ -0,0 +1,12 @@
+export enum InputType {
+ LCP_REGION = "LCP_REGION",
+ TENANT = "TENANT",
+ LOB = "LOB",
+ PLATFORM = "PLATFORM",
+ ROLLBACK = "ROLLBACK",
+ PRODUCT_FAMILY = "PRODUCT_FAMILY",
+ VG = "VG"
+
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/models/lcpRegion.ts b/vid-webpack-master/src/app/shared/models/lcpRegion.ts
new file mode 100644
index 000000000..e39321d58
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/lcpRegion.ts
@@ -0,0 +1,11 @@
+export class LcpRegion {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+ constructor(serviceJson){
+ this.id = serviceJson["cloudRegionID"];
+ this.name = serviceJson["cloudRegionID"];
+ this.isPermitted = serviceJson["is-permitted"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/lcpRegionTenants.ts b/vid-webpack-master/src/app/shared/models/lcpRegionTenants.ts
new file mode 100644
index 000000000..d215546aa
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/lcpRegionTenants.ts
@@ -0,0 +1,13 @@
+export class LcpRegionTenants {
+ id: string;
+ tenantId: string;
+ tenantName: string;
+ isPermitted: boolean;
+
+ constructor(serviceJson){
+ this.id = serviceJson["cloudRegionID"];
+ this.tenantId = serviceJson["tenantID"];
+ this.tenantName = serviceJson["tenantName"];
+ this.isPermitted = serviceJson["is-permitted"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/lcpRegionsAndTenants.ts b/vid-webpack-master/src/app/shared/models/lcpRegionsAndTenants.ts
new file mode 100644
index 000000000..79f6e07d4
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/lcpRegionsAndTenants.ts
@@ -0,0 +1,12 @@
+import {LcpRegion} from "./lcpRegion";
+import {Tenant} from "./tenant";
+
+export class LcpRegionsAndTenants {
+ lcpRegionList: LcpRegion[];
+ lcpRegionsTenantsMap: { [lcpRegion: string] : Tenant[]; };
+
+ constructor(lcpRegionList: LcpRegion[] = [], lcpRegionsTenantsMap: any = {}) {
+ this.lcpRegionList = lcpRegionList;
+ this.lcpRegionsTenantsMap = lcpRegionsTenantsMap;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/modelInfo.ts b/vid-webpack-master/src/app/shared/models/modelInfo.ts
new file mode 100644
index 000000000..091c02ef1
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/modelInfo.ts
@@ -0,0 +1,21 @@
+
+export class ModelInfo {
+ modelInvariantId: string;
+ modelVersionId: string;
+ modelName: string;
+ modelVersion: string;
+ modelCustomizationId: string;
+ modelCustomizationName: string;
+
+
+
+ constructor(instanceModel) {
+ this.modelInvariantId = instanceModel.invariantUuid;
+ this.modelVersionId = instanceModel.uuid;
+ this.modelName = instanceModel.name;
+ this.modelVersion = instanceModel.version;
+ this.modelCustomizationId = instanceModel.customizationUuid;
+ this.modelCustomizationName = instanceModel.modelCustomizationName;
+ }
+}
+
diff --git a/vid-webpack-master/src/app/shared/models/nodeModel.ts b/vid-webpack-master/src/app/shared/models/nodeModel.ts
new file mode 100644
index 000000000..4b22b8d91
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/nodeModel.ts
@@ -0,0 +1,29 @@
+export interface NodeModelResponseInterface {
+ name: string;
+ version: string;
+ description: string;
+ category: string;
+ uuid: string;
+ invariantUuid: string;
+}
+
+export class NodeModel {
+ name: string;
+ version: string;
+ description: string;
+ category: string;
+ uuid: string;
+ invariantUuid: string;
+
+ constructor(serviceJson?: NodeModelResponseInterface) {
+ if (serviceJson) {
+ this.name = serviceJson.name;
+ this.version = serviceJson.version;
+ this.description = serviceJson.description;
+ this.category = serviceJson.category;
+ this.uuid = serviceJson.uuid;
+ this.invariantUuid = serviceJson.invariantUuid;
+ }
+ }
+
+}
diff --git a/vid-webpack-master/src/app/shared/models/owningEntity.ts b/vid-webpack-master/src/app/shared/models/owningEntity.ts
new file mode 100644
index 000000000..f06b24ff0
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/owningEntity.ts
@@ -0,0 +1,14 @@
+interface OwningEntityResponse {
+ id: string,
+ name: string
+}
+
+export class OwningEntity {
+ id: string;
+ name: string;
+
+ constructor(serviceJson: OwningEntityResponse){
+ this.id = serviceJson.id;
+ this.name = serviceJson.name;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/productFamily.ts b/vid-webpack-master/src/app/shared/models/productFamily.ts
new file mode 100644
index 000000000..3c55ac004
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/productFamily.ts
@@ -0,0 +1,13 @@
+import {ServiceResponseInterface} from "../../services/aaiService/responseInterfaces/getServicesResponseInterface";
+
+export class ProductFamily {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+ constructor(serviceResponse: ServiceResponseInterface){
+ this.id = serviceResponse['service-id'];
+ this.name = serviceResponse["service-description"];
+ this.isPermitted = serviceResponse["is-permitted"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/project.ts b/vid-webpack-master/src/app/shared/models/project.ts
new file mode 100644
index 000000000..db8929e38
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/project.ts
@@ -0,0 +1,14 @@
+interface ProjectResponseInterface {
+ id: string,
+ name: string
+}
+
+export class Project {
+ id: string;
+ name: string;
+
+ constructor(projectResponse: ProjectResponseInterface){
+ this.id = projectResponse.id;
+ this.name = projectResponse.name;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/selectOption.ts b/vid-webpack-master/src/app/shared/models/selectOption.ts
new file mode 100644
index 000000000..c12c1a823
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/selectOption.ts
@@ -0,0 +1,17 @@
+export interface SelectOptionInterface {
+ id: string,
+ name: string
+ isPermitted?: boolean
+}
+
+export class SelectOption {
+ id: string;
+ name: string;
+ isPermitted?: boolean;
+
+ constructor(option: SelectOptionInterface){
+ this.id = option.id;
+ this.name = option.name;
+ this.isPermitted = option.isPermitted;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/serviceInstance.ts b/vid-webpack-master/src/app/shared/models/serviceInstance.ts
new file mode 100644
index 000000000..a952430b0
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/serviceInstance.ts
@@ -0,0 +1,28 @@
+import {VnfInstance} from "./vnfInstance";
+
+export class ServiceInstance {
+ instanceName: string;
+ isUserProvidedNaming: boolean;
+ globalSubscriberId: string;
+ productFamilyId: string;
+ subscriptionServiceType: string;
+ lcpCloudRegionId: string;
+ tenantId: string;
+ tenantName: string;
+ aicZoneId: string;
+ aicZoneName: string;
+ projectName: string;
+ owningEntityId: string;
+ owningEntityName: string;
+ pause: boolean;
+ bulkSize: number;
+ vnfs: { [vnf_module_model_name: string] : VnfInstance; };
+ instanceParams: { [key: string] : string; };
+ rollbackOnFailure : boolean;
+ subscriberName : string;
+
+ constructor() {
+ this.vnfs = {};
+ this.instanceParams = {};
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/serviceModel.ts b/vid-webpack-master/src/app/shared/models/serviceModel.ts
new file mode 100644
index 000000000..18d8582e8
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/serviceModel.ts
@@ -0,0 +1,44 @@
+import {NodeModel, NodeModelResponseInterface} from "./nodeModel";
+import * as _ from "lodash";
+
+
+export interface ServiceModelResponseInterface extends NodeModelResponseInterface{
+
+ serviceType: string;
+ serviceRole: string;
+ serviceEcompNaming: boolean;
+}
+
+export class ServiceModel extends NodeModel{
+
+ serviceType: string;
+ serviceRole: string;
+ servicesQty: number;
+ isUserProvidedNaming: boolean;
+ isMultiStepDesign: boolean;
+
+ constructor(serviceModelJson?: any){
+ super(serviceModelJson.service);
+ if (serviceModelJson) {
+ const service: ServiceModelResponseInterface = serviceModelJson.service;
+ this.serviceType = service.serviceType;
+ this.serviceRole = service.serviceRole;
+ this.isUserProvidedNaming = this.getIsUserProvidedName(service);
+ this.isMultiStepDesign = this.getIsMultiStepDesign(serviceModelJson);
+ }
+ }
+
+ private getIsUserProvidedName(serviceJson): boolean {
+ return serviceJson.serviceEcompNaming !== undefined && serviceJson.serviceEcompNaming === "false";
+ };
+
+ private getIsMultiStepDesign(serviceModel): boolean {
+ for (let key in serviceModel.vnfs) {
+ const vnf = serviceModel.vnfs[key];
+ if (vnf.properties.multi_stage_design === "true") {
+ return true
+ }
+ }
+ return false;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/serviceNodeTypeToModelKeyMapper.ts b/vid-webpack-master/src/app/shared/models/serviceNodeTypeToModelKeyMapper.ts
new file mode 100644
index 000000000..1134bbb89
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/serviceNodeTypeToModelKeyMapper.ts
@@ -0,0 +1,8 @@
+export enum ServiceNodeTypeToModelKeyMapper {
+ VF = "vnfs",
+ VFmodule="vfModules",
+ Network = "networks",
+ Configuration = "configurations"
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/models/serviceType.ts b/vid-webpack-master/src/app/shared/models/serviceType.ts
new file mode 100644
index 000000000..67aacdc07
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/serviceType.ts
@@ -0,0 +1,17 @@
+export interface SubscriptionResponseInterface {
+ 'service-type': string
+ 'is-permitted': boolean
+}
+
+export class ServiceType {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+
+ constructor(id: string, subscription: SubscriptionResponseInterface){
+ this.id = id;
+ this.name = subscription['service-type'];
+ this.isPermitted = subscription['is-permitted'];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/subscriber.ts b/vid-webpack-master/src/app/shared/models/subscriber.ts
new file mode 100644
index 000000000..55fc83792
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/subscriber.ts
@@ -0,0 +1,11 @@
+export class Subscriber {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+ constructor(subscriberResponse){
+ this.id = subscriberResponse['global-customer-id'];
+ this.name = subscriberResponse['subscriber-name'];
+ this.isPermitted = subscriberResponse['is-permitted'];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/tenant.ts b/vid-webpack-master/src/app/shared/models/tenant.ts
new file mode 100644
index 000000000..234f1dbff
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/tenant.ts
@@ -0,0 +1,11 @@
+export class Tenant {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+ constructor(serviceJson){
+ this.id = serviceJson["tenantID"];
+ this.name = serviceJson["tenantName"];
+ this.isPermitted = serviceJson["is-permitted"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfModule.ts b/vid-webpack-master/src/app/shared/models/vfModule.ts
new file mode 100644
index 000000000..21f43ed17
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfModule.ts
@@ -0,0 +1,39 @@
+import {NodeModel, NodeModelResponseInterface} from "./nodeModel";
+
+
+export interface properties{
+ initialCount: number;
+ maxCountInstances: number;
+ minCountInstances: number;
+}
+
+export interface VFModuleResponseInterface extends NodeModelResponseInterface {
+ customizationUuid: string;
+ modelCustomizationName: string;
+ properties: properties
+}
+
+export class VfModule extends NodeModel {
+
+ min:number;
+ max:number;
+ vgName:string;
+ rollbackOnFailure:boolean;
+ initial:number;
+ customizationUuid: string;
+ modelCustomizationName: string;
+
+ constructor(vf?: VFModuleResponseInterface) {
+ super(vf);
+ if(vf){
+ this.customizationUuid = vf.customizationUuid;
+ this.modelCustomizationName = vf.modelCustomizationName;
+ }
+ if (vf && vf.properties) {
+ this.min = vf.properties.minCountInstances;
+ this.max = vf.properties.maxCountInstances;
+ this.initial = vf.properties.initialCount;
+ this.rollbackOnFailure = true
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfModuleInstance.ts b/vid-webpack-master/src/app/shared/models/vfModuleInstance.ts
new file mode 100644
index 000000000..c6db00025
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfModuleInstance.ts
@@ -0,0 +1,5 @@
+export class VfModuleInstance {
+ instanceName: string;
+ volumeGroupName: string;
+ instanceParams: { [key: string] : string; };
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfModuleTreeNode.ts b/vid-webpack-master/src/app/shared/models/vfModuleTreeNode.ts
new file mode 100644
index 000000000..d4cc7e9c7
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfModuleTreeNode.ts
@@ -0,0 +1,17 @@
+import {VfModule} from "./vfModule";
+import {VfModuleInstance} from "./vfModuleInstance";
+import {ServiceNodeTypes} from "./ServiceNodeTypes";
+
+export class VfModuleTreeNode {
+ modelId: string;
+ name: string;
+ modelName: string;
+ type: string;
+
+ constructor(vfModuleInstance: VfModuleInstance, vfModuleModel: VfModule, vfModuleModelName: string){
+ this.name = vfModuleInstance.instanceName || vfModuleInstance.volumeGroupName || '<Automatically Assigned>';
+ this.modelId = vfModuleModel.uuid;
+ this.modelName = vfModuleModelName;
+ this.type = ServiceNodeTypes.VFmodule;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfModulesMap.ts b/vid-webpack-master/src/app/shared/models/vfModulesMap.ts
new file mode 100644
index 000000000..95396fd55
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfModulesMap.ts
@@ -0,0 +1,5 @@
+import {VfModuleInstance} from "./vfModuleInstance";
+
+export class VfModuleMap {
+ [id: string] : VfModuleInstance;
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfcInstanceGroup.ts b/vid-webpack-master/src/app/shared/models/vfcInstanceGroup.ts
new file mode 100644
index 000000000..64354b01e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfcInstanceGroup.ts
@@ -0,0 +1,14 @@
+import {VfcInstanceGroupProperties} from "./vfcInstanceGroupProperties";
+
+export class VfcInstanceGroup {
+ name: string;
+ version: string;
+ uuid: string;
+ invariantUuid: string;
+ vfcInstanceGroupProperties: VfcInstanceGroupProperties;
+
+
+}
+
+
+
diff --git a/vid-webpack-master/src/app/shared/models/vfcInstanceGroupMap.ts b/vid-webpack-master/src/app/shared/models/vfcInstanceGroupMap.ts
new file mode 100644
index 000000000..7ee3888c1
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfcInstanceGroupMap.ts
@@ -0,0 +1,5 @@
+import {VfcInstanceGroup} from "./vfcInstanceGroup";
+
+export class VfcInstanceGroupMap {
+ [id: string] : VfcInstanceGroup;
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfcInstanceGroupProperties.ts b/vid-webpack-master/src/app/shared/models/vfcInstanceGroupProperties.ts
new file mode 100644
index 000000000..1a7bf718a
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfcInstanceGroupProperties.ts
@@ -0,0 +1,7 @@
+export class VfcInstanceGroupProperties {
+ networkCollectionFunction: string;
+ subinterfaceRole: string;
+ vfcInstanceGroupFunction: string;
+ vfcParentPortRole: string;
+
+}
diff --git a/vid-webpack-master/src/app/shared/models/vnfInstance.ts b/vid-webpack-master/src/app/shared/models/vnfInstance.ts
new file mode 100644
index 000000000..7f41e483a
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vnfInstance.ts
@@ -0,0 +1,19 @@
+import {VfModuleMap} from "./vfModulesMap";
+
+export class VnfInstance {
+ instanceName: string;
+ isUserProvidedNaming: boolean;
+ productFamilyId: string;
+ lcpCloudRegionId: string;
+ legacyRegion: string;
+ tenantId: string;
+ platformName: string;
+ lineOfBusiness: string;
+ rollbackOnFailure: string;
+ vfModules: { [vf_module_model_name: string] : VfModuleMap; };
+
+ constructor() {
+ this.rollbackOnFailure = 'true';
+ this.vfModules = {};
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/vnfModel.ts b/vid-webpack-master/src/app/shared/models/vnfModel.ts
new file mode 100644
index 000000000..e1302f1d0
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vnfModel.ts
@@ -0,0 +1,52 @@
+import {NodeModel, NodeModelResponseInterface} from "./nodeModel";
+import {VfcInstanceGroupMap} from "./vfcInstanceGroupMap";
+
+
+export interface VnfProperties {
+ ecomp_generated_naming: string
+}
+
+export interface VNFModelResponseInterface extends NodeModelResponseInterface{
+
+ serviceType: string;
+ serviceRole: string;
+ subCategory: string;
+ customizationUuid: string;
+ serviceEcompNaming: boolean;
+ type: string;
+ modelCustomizationName: string;
+ properties: VnfProperties;
+ vfcInstanceGroups: VfcInstanceGroupMap;
+}
+
+export class VNFModel extends NodeModel{
+
+ serviceType: string;
+ serviceRole: string;
+ subCategory: string;
+ customizationUuid: string;
+ isUserProvidedNaming: boolean;
+ type: string;
+ modelCustomizationName: string;
+ vfcInstanceGroups: VfcInstanceGroupMap;
+
+ constructor(vnfJson?: VNFModelResponseInterface){
+ super(vnfJson);
+ if (vnfJson) {
+ this.serviceType = vnfJson.serviceType;
+ this.serviceRole = vnfJson.serviceRole;
+ this.subCategory = vnfJson.subCategory;
+ this.customizationUuid = vnfJson.customizationUuid;
+ this.isUserProvidedNaming = this.getIsUserProvidedName(vnfJson);
+ this.type = vnfJson.type;
+ this.modelCustomizationName = vnfJson.modelCustomizationName;
+ this.vfcInstanceGroups = vnfJson.vfcInstanceGroups;
+
+ }
+ }
+
+ private getIsUserProvidedName(vnfJson) {
+ const ecompGeneratedNaming = vnfJson.properties.ecomp_generated_naming;
+ return ecompGeneratedNaming !== undefined && ecompGeneratedNaming === "false";
+ };
+}
diff --git a/vid-webpack-master/src/app/shared/models/vnfTreeNode.ts b/vid-webpack-master/src/app/shared/models/vnfTreeNode.ts
new file mode 100644
index 000000000..316bf3e8b
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vnfTreeNode.ts
@@ -0,0 +1,18 @@
+import {VNFModel} from "./vnfModel";
+import {VnfInstance} from "./vnfInstance";
+import {VfModuleTreeNode} from "./vfModuleTreeNode";
+
+export class VnfTreeNode {
+ modelId: string;
+ name: string;
+ modelName: string;
+ type: string;
+ children: VfModuleTreeNode[];
+
+ constructor(instance: VnfInstance, vnfModel: VNFModel){
+ this.name = instance.instanceName || vnfModel['properties'].ecomp_generated_naming == 'false' ? vnfModel.modelCustomizationName : '<Automatically Assigned>';
+ this.modelId = vnfModel.uuid;
+ this.modelName = vnfModel.modelCustomizationName;
+ this.type = vnfModel.type;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.spec.ts b/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.spec.ts
new file mode 100644
index 000000000..84d2ff4b6
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.spec.ts
@@ -0,0 +1,25 @@
+
+import {CapitalizeAndFormatPipe} from "./capitalize-and-format.pipe";
+
+describe('Capitalize And Format Pipe', () => {
+ let capitalizeAndFormatPipe: CapitalizeAndFormatPipe;
+
+ beforeEach(() => {
+ capitalizeAndFormatPipe = new CapitalizeAndFormatPipe();
+ });
+
+ it('Capitalize And Format Pipe should be defined', () => {
+ expect(capitalizeAndFormatPipe).toBeDefined();
+ });
+
+ it('Capitalize And Format Pipe : (UPPERCASE)', ()=> {
+ let result: string = capitalizeAndFormatPipe.transform('PENDING');
+ expect(result).toEqual('Pending');
+ });
+
+ it('Capitalize And Format Pipe (UPPERCASE) and Underscore should replace by -', ()=> {
+ let result: string = capitalizeAndFormatPipe.transform('IN_PROGRESS');
+ expect(result).toEqual('In-progress');
+ });
+
+});
diff --git a/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.ts b/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.ts
new file mode 100644
index 000000000..e3ec9ae9a
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.ts
@@ -0,0 +1,12 @@
+import {PipeTransform, Pipe} from '@angular/core';
+
+@Pipe({ name: 'capitalizeAndFormat' })
+export class CapitalizeAndFormatPipe implements PipeTransform {
+ transform(text: string): string {
+ if (text) {
+ text = text.toLowerCase().replace('_', '-');
+ return text.charAt(0).toUpperCase() + text.slice(1);
+ }
+ return text;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/data-filter.pipe.ts b/vid-webpack-master/src/app/shared/pipes/data-filter.pipe.ts
new file mode 100644
index 000000000..1ff836762
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/data-filter.pipe.ts
@@ -0,0 +1,29 @@
+/**
+ * Created by cp2122 on 1/4/2018.
+ */
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+ name: 'dataFilter'
+})
+export class DataFilterPipe implements PipeTransform {
+ keys = [];
+ transform(items: any, args: string): any {
+ if (items != null && items.length > 0) {
+ let ans = [];
+
+ if (this.keys.length === 0) {
+ this.keys = Object.keys(items[0]);
+ }
+ for (let i of items) {
+ for (let k of this.keys) {
+ if (i[k] !== null && i[k].toString().match('^.*' + args + '.*$')) {
+ ans.push(i);
+ break;
+ }
+ }
+ }
+ return ans;
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.spec.ts b/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.spec.ts
new file mode 100644
index 000000000..22b619290
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.spec.ts
@@ -0,0 +1,43 @@
+import { DynamicInputLabelPipe } from './dynamic-input-label.pipe';
+
+describe('Dynamic input label Pipe', () => {
+ let dynamicInputLabelPipe: DynamicInputLabelPipe;
+
+ beforeEach(() => {
+ dynamicInputLabelPipe = new DynamicInputLabelPipe();
+ });
+
+ it('Dynamic input label Pipe should be defined', () => {
+ expect(dynamicInputLabelPipe).toBeDefined();
+ });
+
+ it('Dynamic input label Pipe : Empty string should return empty string', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('');
+ expect(result).toEqual(':*');
+ });
+
+ it('Dynamic input label Pipe: vnf should be VNF (UPPERCASE)', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('vnf');
+ expect(result).toEqual('VNF:*');
+ });
+
+ it('Dynamic input label Pipe : nf should be NF (UPPERCASE)\'', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('nf');
+ expect(result).toEqual('NF:*');
+ });
+
+ it('Dynamic input label Pipe : Underscore should replace by empty character', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('nf_Test');
+ expect(result).toEqual('NF test:*');
+ });
+
+ it('Dynamic input label Pipe : Complex string', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('nf_Test_vnf_nf');
+ expect(result).toEqual('NF test VNF NF:*');
+ });
+
+ it('Dynamic input label Pipe : First letter should be uppercase', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('nfr');
+ expect(result).toEqual('Nfr:*');
+ });
+});
diff --git a/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.ts b/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.ts
new file mode 100644
index 000000000..bec87b46d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.ts
@@ -0,0 +1,12 @@
+import {PipeTransform, Pipe} from '@angular/core';
+
+@Pipe({ name: 'dynamicInputLabel' })
+export class DynamicInputLabelPipe implements PipeTransform {
+ transform(text: string): string {
+ let split_label = text.toLowerCase().replace(/_/g,' ');
+ let uppercase_vnf = split_label.replace(/\bvnf\b/ig, 'VNF');
+ let uppercase_nf = uppercase_vnf.replace(/\bnf\b/ig, 'NF');
+ let capitalize_sentence = uppercase_nf.charAt(0).toUpperCase() + uppercase_nf.slice(1);
+ return capitalize_sentence + ':*';
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/highlight-filter.pipe.ts b/vid-webpack-master/src/app/shared/pipes/highlight-filter.pipe.ts
new file mode 100644
index 000000000..93aecbf69
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/highlight-filter.pipe.ts
@@ -0,0 +1,10 @@
+import {PipeTransform, Pipe} from '@angular/core';
+
+@Pipe({ name: 'highlight' })
+export class HighlightPipe implements PipeTransform {
+ transform(text: string, search: string): string {
+ let pattern = search.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
+ let regex = new RegExp(pattern, 'gi');
+ return search ? text.replace(regex, (match) => `<span class="highlight">${match}</span>`) : text;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.spec.ts b/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.spec.ts
new file mode 100644
index 000000000..984e3378c
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.spec.ts
@@ -0,0 +1,58 @@
+import {ServiceInfoPipe} from "./serviceInfo.pipe";
+
+
+describe('Service info Pipe', () => {
+ let pipe: ServiceInfoPipe;
+
+ beforeEach(() => {
+ pipe = new ServiceInfoPipe();
+ });
+
+ it('Service info Pipe should return model name', () => {
+ let store = {
+ getState : function() {
+ return {
+ service: {
+ serviceHierarchy : generateserviceHierarchy()
+ }
+ }
+ }
+ };
+ let result : string = pipe.transform(null, store , '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 'name');
+ expect(result).toEqual('ComplexService')
+ });
+
+
+
+ it('Service info Pipe should return null if field name not exist', () => {
+ let store = {
+ getState : function() {
+ return {
+ service: {
+ serviceHierarchy : generateserviceHierarchy()
+ }
+ }
+ }
+ };
+ let result : string = pipe.transform(null, store , '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 'notExist');
+ expect(result).toBeNull();
+ });
+
+ it('Service info Pipe should return null if model not exist', () => {
+ let store = {
+ getState : function() {
+ return {
+ service: {
+ serviceHierarchy : generateserviceHierarchy()
+ }
+ }
+ }
+ };
+ let result : string = pipe.transform(null, store , 'modelNotExist', 'name');
+ expect(result).toBeNull();
+ });
+
+ function generateserviceHierarchy(){
+ return JSON.parse('{"6e59c5de-f052-46fa-aa7e-2fca9d674c44":{"service":{"uuid":"6e59c5de-f052-46fa-aa7e-2fca9d674c44","invariantUuid":"e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0","name":"ComplexService","version":"1.0","toscaModelURL":null,"category":"Mobility","serviceType":"","serviceRole":"","description":"ComplexService","serviceEcompNaming":"true","instantiationType":"Macro","inputs":{}},"vnfs":{"VF_vMee 0":{"uuid":"d6557200-ecf2-4641-8094-5393ae3aae60","invariantUuid":"4160458e-f648-4b30-a176-43881ffffe9e","description":"VSP_vMee","name":"VF_vMee","version":"2.0","customizationUuid":"91415b44-753d-494c-926a-456a9172bbb9","inputs":{},"commands":{},"properties":{"gpb2_Internal2_mac":"00:80:37:0E:02:22","sctp-b-ipv6-egress_src_start_port":"0","sctp-a-ipv6-egress_rule_application":"any","Internal2_allow_transit":"true","sctp-b-IPv6_ethertype":"IPv6","sctp-a-egress_rule_application":"any","sctp-b-ingress_action":"pass","sctp-b-ingress_rule_protocol":"icmp","ncb2_Internal1_mac":"00:80:37:0E:0F:12","sctp-b-ipv6-ingress-src_start_port":"0.0","ncb1_Internal2_mac":"00:80:37:0E:09:12","fsb_volume_size_0":"320.0","sctp-b-egress_src_addresses":"local","sctp-a-ipv6-ingress_ethertype":"IPv4","sctp-a-ipv6-ingress-dst_start_port":"0","sctp-b-ipv6-ingress_rule_application":"any","domain_name":"default-domain","sctp-a-ingress_rule_protocol":"icmp","sctp-b-egress-src_start_port":"0.0","sctp-a-egress_src_addresses":"local","sctp-b-display_name":"epc-sctp-b-ipv4v6-sec-group","sctp-a-egress-src_start_port":"0.0","sctp-a-ingress_ethertype":"IPv4","sctp-b-ipv6-ingress-dst_end_port":"65535","sctp-b-dst_subnet_prefix_v6":"::","nf_naming":"{ecomp_generated_naming=true}","sctp-a-ipv6-ingress_src_subnet_prefix":"0.0.0.0","sctp-b-egress-dst_start_port":"0.0","ncb_flavor_name":"nv.c20r64d1","gpb1_Internal1_mac":"00:80:37:0E:01:22","sctp-b-egress_dst_subnet_prefix_len":"0.0","Internal2_net_cidr":"169.255.0.0","sctp-a-ingress-dst_start_port":"0.0","sctp-a-egress-dst_start_port":"0.0","fsb1_Internal2_mac":"00:80:37:0E:0B:12","sctp-a-egress_ethertype":"IPv4","vlc_st_service_mode":"in-network-nat","sctp-a-ipv6-egress_ethertype":"IPv4","sctp-a-egress-src_end_port":"65535.0","sctp-b-ipv6-egress_rule_application":"any","sctp-b-egress_action":"pass","sctp-a-ingress-src_subnet_prefix_len":"0.0","sctp-b-ipv6-ingress-src_end_port":"65535.0","sctp-b-name":"epc-sctp-b-ipv4v6-sec-group","fsb2_Internal1_mac":"00:80:37:0E:0D:12","sctp-a-ipv6-ingress-src_start_port":"0.0","sctp-b-ipv6-egress_ethertype":"IPv4","Internal1_net_cidr":"169.253.0.0","sctp-a-egress_dst_subnet_prefix":"0.0.0.0","fsb_flavor_name":"nv.c20r64d1","sctp_rule_protocol":"132","sctp-b-ipv6-ingress_src_subnet_prefix_len":"0","sctp-a-ipv6-ingress_rule_application":"any","ecomp_generated_naming":"true","sctp-a-IPv6_ethertype":"IPv6","vlc2_Internal1_mac":"00:80:37:0E:02:12","vlc_st_virtualization_type":"virtual-machine","sctp-b-ingress-dst_start_port":"0.0","sctp-b-ingress-dst_end_port":"65535.0","sctp-a-ipv6-ingress-src_end_port":"65535.0","sctp-a-display_name":"epc-sctp-a-ipv4v6-sec-group","sctp-b-ingress_rule_application":"any","int2_sec_group_name":"int2-sec-group","vlc_flavor_name":"nd.c16r64d1","sctp-b-ipv6-egress_src_addresses":"local","vlc_st_interface_type_int1":"other1","sctp-b-egress-src_end_port":"65535.0","sctp-a-ipv6-egress-dst_start_port":"0","vlc_st_interface_type_int2":"other2","sctp-a-ipv6-egress_rule_protocol":"any","Internal2_shared":"false","sctp-a-ipv6-egress_dst_subnet_prefix_len":"0","Internal2_rpf":"disable","vlc1_Internal1_mac":"00:80:37:0E:01:12","sctp-b-ipv6-egress_src_end_port":"65535","sctp-a-ipv6-egress_src_addresses":"local","sctp-a-ingress-dst_end_port":"65535.0","sctp-a-ipv6-egress_src_end_port":"65535","Internal1_forwarding_mode":"l2","Internal2_dhcp":"false","sctp-a-dst_subnet_prefix_v6":"::","pxe_image_name":"MME_PXE-Boot_16ACP04_GA.qcow2","vlc_st_interface_type_gtp":"other0","ncb1_Internal1_mac":"00:80:37:0E:09:12","sctp-b-src_subnet_prefix_v6":"::","sctp-a-egress_dst_subnet_prefix_len":"0.0","int1_sec_group_name":"int1-sec-group","Internal1_dhcp":"false","sctp-a-ipv6-egress_dst_end_port":"65535","Internal2_forwarding_mode":"l2","fsb2_Internal2_mac":"00:80:37:0E:0D:12","sctp-b-egress_dst_subnet_prefix":"0.0.0.0","Internal1_net_cidr_len":"17","gpb2_Internal1_mac":"00:80:37:0E:02:22","sctp-b-ingress-src_subnet_prefix_len":"0.0","sctp-a-ingress_dst_addresses":"local","sctp-a-egress_action":"pass","fsb_volume_type_0":"SF-Default-SSD","ncb2_Internal2_mac":"00:80:37:0E:0F:12","vlc_st_interface_type_sctp_a":"left","vlc_st_interface_type_sctp_b":"right","sctp-a-src_subnet_prefix_v6":"::","vlc_st_version":"2","sctp-b-egress_ethertype":"IPv4","sctp-a-ingress_rule_application":"any","gpb1_Internal2_mac":"00:80:37:0E:01:22","instance_ip_family_v6":"v6","sctp-a-ipv6-egress_src_start_port":"0","sctp-b-ingress-src_start_port":"0.0","sctp-b-ingress_dst_addresses":"local","fsb1_Internal1_mac":"00:80:37:0E:0B:12","vlc_st_interface_type_oam":"management","multi_stage_design":"false","oam_sec_group_name":"oam-sec-group","Internal2_net_gateway":"169.255.0.3","sctp-a-ipv6-ingress-dst_end_port":"65535","sctp-b-ipv6-egress-dst_start_port":"0","Internal1_net_gateway":"169.253.0.3","sctp-b-ipv6-egress_rule_protocol":"any","gtp_sec_group_name":"gtp-sec-group","sctp-a-ipv6-egress_dst_subnet_prefix":"0.0.0.0","sctp-b-ipv6-egress_dst_subnet_prefix_len":"0","sctp-a-ipv6-ingress_dst_addresses":"local","sctp-a-egress_rule_protocol":"icmp","sctp-b-ipv6-egress_action":"pass","sctp-a-ipv6-egress_action":"pass","Internal1_shared":"false","sctp-b-ipv6-ingress_rule_protocol":"any","Internal2_net_cidr_len":"17","sctp-a-name":"epc-sctp-a-ipv4v6-sec-group","sctp-a-ingress-src_end_port":"65535.0","sctp-b-ipv6-ingress_src_subnet_prefix":"0.0.0.0","sctp-a-egress-dst_end_port":"65535.0","sctp-a-ingress_action":"pass","sctp-b-egress_rule_protocol":"icmp","sctp-b-ipv6-ingress_action":"pass","vlc_st_service_type":"firewall","sctp-b-ipv6-egress_dst_end_port":"65535","sctp-b-ipv6-ingress-dst_start_port":"0","vlc2_Internal2_mac":"00:80:37:0E:02:12","vlc_st_availability_zone":"true","fsb_volume_image_name_1":"MME_FSB2_16ACP04_GA.qcow2","sctp-b-ingress-src_subnet_prefix":"0.0.0.0","sctp-a-ipv6-ingress_src_subnet_prefix_len":"0","Internal1_allow_transit":"true","gpb_flavor_name":"nv.c20r64d1","availability_zone_max_count":"1","fsb_volume_image_name_0":"MME_FSB1_16ACP04_GA.qcow2","sctp-b-ipv6-ingress_dst_addresses":"local","sctp-b-ipv6-egress_dst_subnet_prefix":"0.0.0.0","sctp-b-ipv6-ingress_ethertype":"IPv4","vlc1_Internal2_mac":"00:80:37:0E:01:12","sctp-a-ingress-src_subnet_prefix":"0.0.0.0","sctp-a-ipv6-ingress_action":"pass","Internal1_rpf":"disable","sctp-b-ingress_ethertype":"IPv4","sctp-b-egress_rule_application":"any","sctp-b-ingress-src_end_port":"65535.0","sctp-a-ipv6-ingress_rule_protocol":"any","sctp-a-ingress-src_start_port":"0.0","sctp-b-egress-dst_end_port":"65535.0"},"type":"VF","modelCustomizationName":"VF_vMee 0","vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"uuid":"522159d5-d6e0-4c2a-aa44-5a542a12a830","invariantUuid":"98a7c88b-b577-476a-90e4-e25a5871e02b","customizationUuid":"55b1be94-671a-403e-a26c-667e9c47d091","description":null,"name":"VfVmee..vmme_vlc..module-1","version":"2","modelCustomizationName":"VfVmee..vmme_vlc..module-1","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_vlc"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..vmme_gpb..module-2":{"uuid":"41708296-e443-4c71-953f-d9a010f059e1","invariantUuid":"1cca90b8-3490-495e-87da-3f3e4c57d5b9","customizationUuid":"6add59e0-7fe1-4bc4-af48-f8812422ae7c","description":null,"name":"VfVmee..vmme_gpb..module-2","version":"2","modelCustomizationName":"VfVmee..vmme_gpb..module-2","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_gpb"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{},"volumeGroupAllowed":true}},"volumeGroups":{"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{}}},"vfcInstanceGroups":{}}},"networks":{"ExtVL 0":{"uuid":"ddc3f20c-08b5-40fd-af72-c6d14636b986","invariantUuid":"379f816b-a7aa-422f-be30-17114ff50b7c","description":"ECOMP generic virtual link (network) base type for all other service-level and global networks","name":"ExtVL","version":"37.0","customizationUuid":"94fdd893-4a36-4d70-b16a-ec29c54c184f","inputs":{},"commands":{},"properties":{"network_assignments":"{is_external_network=false, ipv4_subnet_default_assignment={min_subnets_count=1}, ecomp_generated_network_assignment=false, ipv6_subnet_default_assignment={min_subnets_count=1}}","exVL_naming":"{ecomp_generated_naming=true}","network_flows":"{is_network_policy=false, is_bound_to_vpn=false}","network_homing":"{ecomp_selected_instance_node_target=false}"},"type":"VL","modelCustomizationName":"ExtVL 0"}},"collectionResource":{},"configurations":{"Port Mirroring Configuration By Policy 0":{"uuid":"b4398538-e89d-4f13-b33d-ca323434ba50","invariantUuid":"6ef0ca40-f366-4897-951f-abd65d25f6f7","description":"A port mirroring configuration by policy object","name":"Port Mirroring Configuration By Policy","version":"27.0","customizationUuid":"3c3b7b8d-8669-4b3b-8664-61970041fad2","inputs":{},"commands":{},"properties":{},"type":"Configuration","modelCustomizationName":"Port Mirroring Configuration By Policy 0","sourceNodes":[],"collectorNodes":null,"configurationByPolicy":false}},"serviceProxies":{},"vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"uuid":"522159d5-d6e0-4c2a-aa44-5a542a12a830","invariantUuid":"98a7c88b-b577-476a-90e4-e25a5871e02b","customizationUuid":"55b1be94-671a-403e-a26c-667e9c47d091","description":null,"name":"VfVmee..vmme_vlc..module-1","version":"2","modelCustomizationName":"VfVmee..vmme_vlc..module-1","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_vlc"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..vmme_gpb..module-2":{"uuid":"41708296-e443-4c71-953f-d9a010f059e1","invariantUuid":"1cca90b8-3490-495e-87da-3f3e4c57d5b9","customizationUuid":"6add59e0-7fe1-4bc4-af48-f8812422ae7c","description":null,"name":"VfVmee..vmme_gpb..module-2","version":"2","modelCustomizationName":"VfVmee..vmme_gpb..module-2","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_gpb"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{},"volumeGroupAllowed":true}},"volumeGroups":{"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{}}},"pnfs":{}}}');
+ }
+});
diff --git a/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.ts b/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.ts
new file mode 100644
index 000000000..8cb2e1dcd
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.ts
@@ -0,0 +1,13 @@
+import {PipeTransform, Pipe} from '@angular/core';
+import {isNullOrUndefined} from "util";
+
+@Pipe({ name: 'serviceInfo'})
+export class ServiceInfoPipe implements PipeTransform {
+ transform(service: string, store : any , modelId : string, fieldName : string): string {
+ const serviceHierarchy = store.getState().service.serviceHierarchy;
+ if(!isNullOrUndefined(serviceHierarchy) && !isNullOrUndefined(serviceHierarchy[modelId])){
+ return serviceHierarchy[modelId].service[fieldName] || null;
+ }
+ return null;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.spec.ts b/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.spec.ts
new file mode 100644
index 000000000..36f6349e2
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.spec.ts
@@ -0,0 +1,60 @@
+import {TestBed, inject, getTestBed} from '@angular/core/testing';
+
+import { HealthStatusService } from './health-status.service';
+import {Constants} from "../../utils/constants";
+import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
+import {ExternalComponentStatus} from "../../models/externalComponentStatus";
+
+describe('HealthStatusService', () => {
+
+ let injector;
+ let service: HealthStatusService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [HealthStatusService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(HealthStatusService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ describe('#getProbe', () =>{
+ it('when call probe, there is http GET with right url', () => {
+
+ service.getProbe().subscribe((result: Array<ExternalComponentStatus>)=>{
+ expect(result[0].component).toEqual("AAI");
+ expect(result[0].available).toBeTruthy();
+ expect(result[0].metadata).toEqual({ myKey: 'myValue' });
+
+ expect(result[1].component).toEqual("MSO");
+ expect(result[1].available).toBeFalsy();
+ expect(result[1].metadata).toEqual({otherKey: 123});
+ });
+
+ const req = httpMock.expectOne(Constants.Path.SERVICES_PROBE_PATH);
+ expect(req.request.method).toEqual('GET');
+ req.flush([
+ {
+ "component": "AAI",
+ "available": true,
+ "metadata": {
+ "myKey": "myValue"
+ }
+ },
+ {
+ "component": "MSO",
+ "available": false,
+ "metadata": {
+ "otherKey": 123
+ }
+ },
+ ]);
+ });
+
+ });
+
+});
diff --git a/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.ts b/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.ts
new file mode 100644
index 000000000..4305ab97e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.ts
@@ -0,0 +1,17 @@
+import { Injectable } from '@angular/core';
+import {HttpClient} from "@angular/common/http";
+import {Observable} from "rxjs/Observable";
+import {Constants} from "../../utils/constants";
+import {ExternalComponentStatus} from "../../models/externalComponentStatus";
+
+@Injectable()
+export class HealthStatusService {
+
+ constructor(private _http: HttpClient) {
+ }
+
+ getProbe(): Observable<Array<ExternalComponentStatus>> {
+ let pathQuery = Constants.Path.SERVICES_PROBE_PATH;
+ return this._http.get<Array<ExternalComponentStatus>>(pathQuery).map(res => res);
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/AuditStatus.model.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/AuditStatus.model.ts
new file mode 100644
index 000000000..0b4c70f9d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/serviceInfo/AuditStatus.model.ts
@@ -0,0 +1,10 @@
+export class AuditStatus{
+ id: number;
+ createdDate: number;
+ final: boolean;
+ jobId :string;
+ jobStatus :string;
+ source: string;
+ requestId: string;
+ additionalInfo :any
+}
diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.model.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.model.ts
new file mode 100644
index 000000000..0b4695930
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.model.ts
@@ -0,0 +1,38 @@
+import {ServiceStatus} from '../../../instantiationStatus/instantiationStatus.component.service';
+
+export class ServiceInfoModel {
+ id: number;
+ created: Date;
+ modified: Date;
+ createdId: number;
+ modifiedId: number;
+ numRow: number;
+ uuid: string;
+ userId: string;
+ jobStatus: string;
+ pause: boolean;
+ owningEntityId: string;
+ owningEntityName: string;
+ project: string;
+ aicZoneId: string;
+ aicZoneName: string;
+ tenantId: string;
+ tenantName: string;
+ regionId: string;
+ regionName: string;
+ serviceType: string;
+ subscriberName: string;
+ serviceInstanceId: string;
+ serviceInstanceName: string;
+ serviceModelId: string;
+ serviceModelName: string;
+ serviceModelVersion: string;
+ templateId: string;
+ auditUserId: string;
+ jobId: string;
+}
+
+export class ServiceInfoUiModel extends ServiceInfoModel{
+ serviceStatus : ServiceStatus;
+ serviceIndex : number;
+}
diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts
new file mode 100644
index 000000000..78c1b5ab9
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts
@@ -0,0 +1,235 @@
+import {getTestBed, TestBed} from '@angular/core/testing';
+import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
+import {ServiceInfoService} from './serviceInfo.service';
+import {ServiceInfoModel} from './serviceInfo.model';
+import {Constants} from "../../utils/constants";
+
+describe('Service Info Service', () => {
+ let injector;
+ let service: ServiceInfoService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [ServiceInfoService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(ServiceInfoService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ describe('#getServicesJobInfo', () => {
+ it('should return an Observable<ServiceInfoModel[]>', () => {
+ const dummyServiceInfo: ServiceInfoModel[] = generateServiceInfoData();
+
+ service.getServicesJobInfo(true).subscribe((serviceInfo:Array<ServiceInfoModel>) => {
+ expect(serviceInfo).toEqual(dummyServiceInfo);
+ });
+ });
+
+
+ });
+
+ describe('#deleteJob', () =>{
+ it('delete job', () => {
+ const jobId : string = "1111";
+
+ service.deleteJob(jobId).subscribe();
+
+ const req = httpMock.expectOne(Constants.Path.SERVICES_JOB_INFO_PATH + '/job/' + jobId);
+ expect(req.request.method).toEqual('DELETE');
+
+ });
+ });
+
+ describe('#hideJob', () =>{
+ it('when call hide job, there is http POST with right url', () => {
+ const jobId : string = "3";
+
+ service.hideJob(jobId).subscribe();
+
+ const req = httpMock.expectOne(Constants.Path.SERVICES_JOB_INFO_PATH + '/hide/' + jobId);
+ expect(req.request.method).toEqual('POST');
+ });
+ });
+
+ describe('#getJobAuditStatus', ()=> {
+ it('should return Observable<Object[]>', ()=>{
+ const jobId : string = '111';
+
+ service.getJobAuditStatus(jobId).subscribe();
+ const req = httpMock.expectOne(Constants.Path.SERVICES_JOB_INFO_PATH + Constants.Path.SERVICES_JOB_AUDIT_PATH + '/' + jobId + '?source=VID');
+ const req2 = httpMock.expectOne(Constants.Path.SERVICES_JOB_INFO_PATH + Constants.Path.SERVICES_JOB_AUDIT_PATH + '/' + jobId + '?source=MSO');
+
+ expect(req.request.method).toEqual('GET');
+ expect(req2.request.method).toEqual('GET');
+ });
+ });
+
+ function generateServiceInfoData(){
+ return <ServiceInfoModel[]>JSON.parse(JSON.stringify(
+ [{
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "1",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "1",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "2",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "2",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "3",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ }]
+ ));
+ }
+});
diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts
new file mode 100644
index 000000000..e0057bb4d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts
@@ -0,0 +1,38 @@
+import {Injectable} from '@angular/core';
+import {Observable} from 'rxjs/Observable';
+import {ServiceInfoModel} from './serviceInfo.model';
+import {HttpClient} from '@angular/common/http';
+import 'rxjs/add/operator/map'
+import {Constants} from '../../utils/constants';
+import {forkJoin} from "rxjs/observable/forkJoin";
+
+@Injectable()
+export class ServiceInfoService {
+ constructor(private _http: HttpClient) {
+ }
+
+ getServicesJobInfo(filterByUser : boolean): Observable<ServiceInfoModel[]> {
+ let pathQuery = Constants.Path.SERVICES_JOB_INFO_PATH;
+ return this._http.get<ServiceInfoModel[]>(pathQuery).map(res => res );
+ }
+
+ deleteJob(jobId: string): Observable<any> {
+ let pathQuery = Constants.Path.SERVICES_JOB_INFO_PATH + '/job/' + jobId;
+ return this._http.delete<any>(pathQuery).map(res => res);
+ }
+
+ hideJob(jobId: string): Observable<any> {
+ let pathQuery = Constants.Path.SERVICES_JOB_INFO_PATH + '/hide/' + jobId;
+ return this._http.post<any>(pathQuery, null).map(res => res);
+ }
+
+ getJobAuditStatus(jobId : string) : Observable<Object[]>{
+ let pathQueryVID = Constants.Path.SERVICES_JOB_INFO_PATH + Constants.Path.SERVICES_JOB_AUDIT_PATH + '/' + jobId + '?source=VID';
+ let pathQueryMSO = Constants.Path.SERVICES_JOB_INFO_PATH + Constants.Path.SERVICES_JOB_AUDIT_PATH + '/' + jobId + '?source=MSO';
+
+ let vidObs = this._http.get(pathQueryVID);
+ let msoObs = this._http.get(pathQueryMSO);
+ return forkJoin([vidObs, msoObs]);
+ }
+
+}
diff --git a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts
new file mode 100644
index 000000000..617dbd3da
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts
@@ -0,0 +1,73 @@
+import { getTestBed, TestBed } from '@angular/core/testing';
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { NgRedux } from '@angular-redux/store';
+import { DefaultDataGeneratorService } from './default.data.generator.service';
+
+export class MockAppStore<T> {}
+
+describe('Default Data Generator Service', () => {
+ let injector;
+ let service: DefaultDataGeneratorService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [DefaultDataGeneratorService,
+ {provide: NgRedux, useClass: MockAppStore}]
+ });
+
+ injector = getTestBed();
+ service = injector.get(DefaultDataGeneratorService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ it('generateVFModule should create vf module object', () => {
+ const serviceHierarchy = generateServiceHierarchy();
+ const vnfUUID: string = 'VF_vMee 0';
+ const vnfModuleUUID: string = 'vf_vmee0..VfVmee..base_vmme..module-0';
+
+ let result = service.generateVFModule(serviceHierarchy, vnfUUID, vnfModuleUUID);
+
+ expect(result.modelInfo.modelType).toEqual('VFmodule');
+ expect(result.modelInfo.modelInvariantId).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].invariantUuid);
+ expect(result.modelInfo.modelVersionId).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].uuid);
+ expect(result.modelInfo.modelName).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].name);
+ expect(result.modelInfo.modelVersion).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].version);
+ expect(result.modelInfo.modelCustomizationId).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].customizationUuid);
+ expect(result.modelInfo.modelCustomizationName).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].modelCustomizationName);
+ expect(result.sdncPreReload).toBeNull();
+ });
+
+ it('generateVNFData should create vnf object', () => {
+ const serviceHierarchy = generateServiceHierarchy();
+ const vnfName: string = 'VF_vMee 0';
+ const formValues = generateVNFFormValues();
+ const vfUUID: string = 'vf_vmee0..VfVmee..base_vmme..module-0';
+
+ let result = service.generateVNFData(serviceHierarchy, vnfName, vfUUID, formValues);
+
+ expect(result.productFamilyId).toEqual(formValues.productFamilyId);
+ expect(result.lcpCloudRegionId).toBeNull();
+ expect(result.tenantId).toBeNull();
+ expect(result.lineOfBusiness).toBeNull();
+ expect(result.platformName).toBeNull();
+ expect(result.modelInfo.modelType).toEqual('VF');
+ expect(result.modelInfo.modelInvariantId).toEqual(serviceHierarchy.vnfs[vnfName].invariantUuid);
+ expect(result.modelInfo.modelVersionId).toEqual(formValues.modelInfo.modelVersionId);
+ expect(result.modelInfo.modelName).toEqual(serviceHierarchy.vnfs[vnfName].name);
+ expect(result.modelInfo.modelVersion).toEqual(serviceHierarchy.vnfs[vnfName].version);
+ expect(result.modelInfo.modelCustomizationId).toEqual(serviceHierarchy.vnfs[vnfName].modelCustomizationId);
+ expect(result.modelInfo.modelCustomizationName).toEqual(serviceHierarchy.vnfs[vnfName].modelCustomizationName);
+ });
+});
+
+
+function generateServiceHierarchy() {
+ return JSON.parse('{"service":{"uuid":"6e59c5de-f052-46fa-aa7e-2fca9d674c44","invariantUuid":"e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0","name":"ComplexService","version":"1.0","toscaModelURL":null,"category":"Mobility","serviceType":"","serviceRole":"","description":"ComplexService","serviceEcompNaming":"true","instantiationType":"Macro","inputs":{}},"vnfs":{"VF_vMee 0":{"uuid":"d6557200-ecf2-4641-8094-5393ae3aae60","invariantUuid":"4160458e-f648-4b30-a176-43881ffffe9e","description":"VSP_vMee","name":"VF_vMee","version":"2.0","customizationUuid":"91415b44-753d-494c-926a-456a9172bbb9","inputs":{},"commands":{},"properties":{"gpb2_Internal2_mac":"00:80:37:0E:02:22","sctp-b-ipv6-egress_src_start_port":"0","sctp-a-ipv6-egress_rule_application":"any","Internal2_allow_transit":"true","sctp-b-IPv6_ethertype":"IPv6","sctp-a-egress_rule_application":"any","sctp-b-ingress_action":"pass","sctp-b-ingress_rule_protocol":"icmp","ncb2_Internal1_mac":"00:80:37:0E:0F:12","sctp-b-ipv6-ingress-src_start_port":"0.0","ncb1_Internal2_mac":"00:80:37:0E:09:12","fsb_volume_size_0":"320.0","sctp-b-egress_src_addresses":"local","sctp-a-ipv6-ingress_ethertype":"IPv4","sctp-a-ipv6-ingress-dst_start_port":"0","sctp-b-ipv6-ingress_rule_application":"any","domain_name":"default-domain","sctp-a-ingress_rule_protocol":"icmp","sctp-b-egress-src_start_port":"0.0","sctp-a-egress_src_addresses":"local","sctp-b-display_name":"epc-sctp-b-ipv4v6-sec-group","sctp-a-egress-src_start_port":"0.0","sctp-a-ingress_ethertype":"IPv4","sctp-b-ipv6-ingress-dst_end_port":"65535","sctp-b-dst_subnet_prefix_v6":"::","nf_naming":"{ecomp_generated_naming=true}","sctp-a-ipv6-ingress_src_subnet_prefix":"0.0.0.0","sctp-b-egress-dst_start_port":"0.0","ncb_flavor_name":"nv.c20r64d1","gpb1_Internal1_mac":"00:80:37:0E:01:22","sctp-b-egress_dst_subnet_prefix_len":"0.0","Internal2_net_cidr":"169.255.0.0","sctp-a-ingress-dst_start_port":"0.0","sctp-a-egress-dst_start_port":"0.0","fsb1_Internal2_mac":"00:80:37:0E:0B:12","sctp-a-egress_ethertype":"IPv4","vlc_st_service_mode":"in-network-nat","sctp-a-ipv6-egress_ethertype":"IPv4","sctp-a-egress-src_end_port":"65535.0","sctp-b-ipv6-egress_rule_application":"any","sctp-b-egress_action":"pass","sctp-a-ingress-src_subnet_prefix_len":"0.0","sctp-b-ipv6-ingress-src_end_port":"65535.0","sctp-b-name":"epc-sctp-b-ipv4v6-sec-group","fsb2_Internal1_mac":"00:80:37:0E:0D:12","sctp-a-ipv6-ingress-src_start_port":"0.0","sctp-b-ipv6-egress_ethertype":"IPv4","Internal1_net_cidr":"169.253.0.0","sctp-a-egress_dst_subnet_prefix":"0.0.0.0","fsb_flavor_name":"nv.c20r64d1","sctp_rule_protocol":"132","sctp-b-ipv6-ingress_src_subnet_prefix_len":"0","sctp-a-ipv6-ingress_rule_application":"any","ecomp_generated_naming":"true","sctp-a-IPv6_ethertype":"IPv6","vlc2_Internal1_mac":"00:80:37:0E:02:12","vlc_st_virtualization_type":"virtual-machine","sctp-b-ingress-dst_start_port":"0.0","sctp-b-ingress-dst_end_port":"65535.0","sctp-a-ipv6-ingress-src_end_port":"65535.0","sctp-a-display_name":"epc-sctp-a-ipv4v6-sec-group","sctp-b-ingress_rule_application":"any","int2_sec_group_name":"int2-sec-group","vlc_flavor_name":"nd.c16r64d1","sctp-b-ipv6-egress_src_addresses":"local","vlc_st_interface_type_int1":"other1","sctp-b-egress-src_end_port":"65535.0","sctp-a-ipv6-egress-dst_start_port":"0","vlc_st_interface_type_int2":"other2","sctp-a-ipv6-egress_rule_protocol":"any","Internal2_shared":"false","sctp-a-ipv6-egress_dst_subnet_prefix_len":"0","Internal2_rpf":"disable","vlc1_Internal1_mac":"00:80:37:0E:01:12","sctp-b-ipv6-egress_src_end_port":"65535","sctp-a-ipv6-egress_src_addresses":"local","sctp-a-ingress-dst_end_port":"65535.0","sctp-a-ipv6-egress_src_end_port":"65535","Internal1_forwarding_mode":"l2","Internal2_dhcp":"false","sctp-a-dst_subnet_prefix_v6":"::","pxe_image_name":"MME_PXE-Boot_16ACP04_GA.qcow2","vlc_st_interface_type_gtp":"other0","ncb1_Internal1_mac":"00:80:37:0E:09:12","sctp-b-src_subnet_prefix_v6":"::","sctp-a-egress_dst_subnet_prefix_len":"0.0","int1_sec_group_name":"int1-sec-group","Internal1_dhcp":"false","sctp-a-ipv6-egress_dst_end_port":"65535","Internal2_forwarding_mode":"l2","fsb2_Internal2_mac":"00:80:37:0E:0D:12","sctp-b-egress_dst_subnet_prefix":"0.0.0.0","Internal1_net_cidr_len":"17","gpb2_Internal1_mac":"00:80:37:0E:02:22","sctp-b-ingress-src_subnet_prefix_len":"0.0","sctp-a-ingress_dst_addresses":"local","sctp-a-egress_action":"pass","fsb_volume_type_0":"SF-Default-SSD","ncb2_Internal2_mac":"00:80:37:0E:0F:12","vlc_st_interface_type_sctp_a":"left","vlc_st_interface_type_sctp_b":"right","sctp-a-src_subnet_prefix_v6":"::","vlc_st_version":"2","sctp-b-egress_ethertype":"IPv4","sctp-a-ingress_rule_application":"any","gpb1_Internal2_mac":"00:80:37:0E:01:22","instance_ip_family_v6":"v6","sctp-a-ipv6-egress_src_start_port":"0","sctp-b-ingress-src_start_port":"0.0","sctp-b-ingress_dst_addresses":"local","fsb1_Internal1_mac":"00:80:37:0E:0B:12","vlc_st_interface_type_oam":"management","multi_stage_design":"false","oam_sec_group_name":"oam-sec-group","Internal2_net_gateway":"169.255.0.3","sctp-a-ipv6-ingress-dst_end_port":"65535","sctp-b-ipv6-egress-dst_start_port":"0","Internal1_net_gateway":"169.253.0.3","sctp-b-ipv6-egress_rule_protocol":"any","gtp_sec_group_name":"gtp-sec-group","sctp-a-ipv6-egress_dst_subnet_prefix":"0.0.0.0","sctp-b-ipv6-egress_dst_subnet_prefix_len":"0","sctp-a-ipv6-ingress_dst_addresses":"local","sctp-a-egress_rule_protocol":"icmp","sctp-b-ipv6-egress_action":"pass","sctp-a-ipv6-egress_action":"pass","Internal1_shared":"false","sctp-b-ipv6-ingress_rule_protocol":"any","Internal2_net_cidr_len":"17","sctp-a-name":"epc-sctp-a-ipv4v6-sec-group","sctp-a-ingress-src_end_port":"65535.0","sctp-b-ipv6-ingress_src_subnet_prefix":"0.0.0.0","sctp-a-egress-dst_end_port":"65535.0","sctp-a-ingress_action":"pass","sctp-b-egress_rule_protocol":"icmp","sctp-b-ipv6-ingress_action":"pass","vlc_st_service_type":"firewall","sctp-b-ipv6-egress_dst_end_port":"65535","sctp-b-ipv6-ingress-dst_start_port":"0","vlc2_Internal2_mac":"00:80:37:0E:02:12","vlc_st_availability_zone":"true","fsb_volume_image_name_1":"MME_FSB2_16ACP04_GA.qcow2","sctp-b-ingress-src_subnet_prefix":"0.0.0.0","sctp-a-ipv6-ingress_src_subnet_prefix_len":"0","Internal1_allow_transit":"true","gpb_flavor_name":"nv.c20r64d1","availability_zone_max_count":"1","fsb_volume_image_name_0":"MME_FSB1_16ACP04_GA.qcow2","sctp-b-ipv6-ingress_dst_addresses":"local","sctp-b-ipv6-egress_dst_subnet_prefix":"0.0.0.0","sctp-b-ipv6-ingress_ethertype":"IPv4","vlc1_Internal2_mac":"00:80:37:0E:01:12","sctp-a-ingress-src_subnet_prefix":"0.0.0.0","sctp-a-ipv6-ingress_action":"pass","Internal1_rpf":"disable","sctp-b-ingress_ethertype":"IPv4","sctp-b-egress_rule_application":"any","sctp-b-ingress-src_end_port":"65535.0","sctp-a-ipv6-ingress_rule_protocol":"any","sctp-a-ingress-src_start_port":"0.0","sctp-b-egress-dst_end_port":"65535.0"},"type":"VF","modelCustomizationName":"VF_vMee 0","vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"uuid":"522159d5-d6e0-4c2a-aa44-5a542a12a830","invariantUuid":"98a7c88b-b577-476a-90e4-e25a5871e02b","customizationUuid":"55b1be94-671a-403e-a26c-667e9c47d091","description":null,"name":"VfVmee..vmme_vlc..module-1","version":"2","modelCustomizationName":"VfVmee..vmme_vlc..module-1","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_vlc"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..vmme_gpb..module-2":{"uuid":"41708296-e443-4c71-953f-d9a010f059e1","invariantUuid":"1cca90b8-3490-495e-87da-3f3e4c57d5b9","customizationUuid":"6add59e0-7fe1-4bc4-af48-f8812422ae7c","description":null,"name":"VfVmee..vmme_gpb..module-2","version":"2","modelCustomizationName":"VfVmee..vmme_gpb..module-2","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_gpb"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{},"volumeGroupAllowed":true}},"volumeGroups":{"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{}}},"vfcInstanceGroups":{}}},"networks":{"ExtVL 0":{"uuid":"ddc3f20c-08b5-40fd-af72-c6d14636b986","invariantUuid":"379f816b-a7aa-422f-be30-17114ff50b7c","description":"ECOMP generic virtual link (network) base type for all other service-level and global networks","name":"ExtVL","version":"37.0","customizationUuid":"94fdd893-4a36-4d70-b16a-ec29c54c184f","inputs":{},"commands":{},"properties":{"network_assignments":"{is_external_network=false, ipv4_subnet_default_assignment={min_subnets_count=1}, ecomp_generated_network_assignment=false, ipv6_subnet_default_assignment={min_subnets_count=1}}","exVL_naming":"{ecomp_generated_naming=true}","network_flows":"{is_network_policy=false, is_bound_to_vpn=false}","network_homing":"{ecomp_selected_instance_node_target=false}"},"type":"VL","modelCustomizationName":"ExtVL 0"}},"collectionResource":{},"configurations":{"Port Mirroring Configuration By Policy 0":{"uuid":"b4398538-e89d-4f13-b33d-ca323434ba50","invariantUuid":"6ef0ca40-f366-4897-951f-abd65d25f6f7","description":"A port mirroring configuration by policy object","name":"Port Mirroring Configuration By Policy","version":"27.0","customizationUuid":"3c3b7b8d-8669-4b3b-8664-61970041fad2","inputs":{},"commands":{},"properties":{},"type":"Configuration","modelCustomizationName":"Port Mirroring Configuration By Policy 0","sourceNodes":[],"collectorNodes":null,"configurationByPolicy":false}},"serviceProxies":{},"vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"uuid":"522159d5-d6e0-4c2a-aa44-5a542a12a830","invariantUuid":"98a7c88b-b577-476a-90e4-e25a5871e02b","customizationUuid":"55b1be94-671a-403e-a26c-667e9c47d091","description":null,"name":"VfVmee..vmme_vlc..module-1","version":"2","modelCustomizationName":"VfVmee..vmme_vlc..module-1","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_vlc"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..vmme_gpb..module-2":{"uuid":"41708296-e443-4c71-953f-d9a010f059e1","invariantUuid":"1cca90b8-3490-495e-87da-3f3e4c57d5b9","customizationUuid":"6add59e0-7fe1-4bc4-af48-f8812422ae7c","description":null,"name":"VfVmee..vmme_gpb..module-2","version":"2","modelCustomizationName":"VfVmee..vmme_gpb..module-2","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_gpb"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{},"volumeGroupAllowed":true}},"volumeGroups":{"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{}}},"pnfs":{}}');
+}
+
+
+function generateVNFFormValues() {
+ return JSON.parse('{"globalSubscriberId":"e433710f-9217-458d-a79d-1c7aff376d89","productFamilyId":"vRRaaS","subscriptionServiceType":"VIRTUAL USP","lcpCloudRegionId":"mtn6","tenantId":"1178612d2b394be4834ad77f567c0af2","aicZoneId":"JAG1","projectName":"DFW","owningEntityId":"d61e6f2d-12fa-4cc2-91df-7c244011d6fc","rollbackOnFailure":"true","bulkSize":1,"instanceParams":[{}],"modelInfo":{"modelInvariantId":"e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0","modelVersionId":"6e59c5de-f052-46fa-aa7e-2fca9d674c44","modelName":"ComplexService","modelVersion":"1.0"},"isUserProvidedNaming":false,"tenantName":"AIN Web Tool-15-D-SSPtestcustome","aicZoneName":"YUDFJULP-JAG1"}');
+}
diff --git a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts
new file mode 100644
index 000000000..b1e676fc5
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts
@@ -0,0 +1,82 @@
+import { Injectable } from '@angular/core';
+import * as _ from 'lodash';
+import { createVFModuleInstance, updateVNFInstance } from '../../../service.actions';
+import { NgRedux } from '@angular-redux/store';
+import { AppState } from '../../../store/reducers';
+
+@Injectable()
+export class DefaultDataGeneratorService {
+ static controlsFieldsStatus = {};
+
+ constructor(private store: NgRedux<AppState>) { }
+
+ updateReduxOnFirstSet(serviceId: string, formServiceValues: any): void {
+ const serviceHierarchy = this.store.getState().service.serviceHierarchy[serviceId];
+ if (serviceHierarchy && !_.isEmpty(serviceHierarchy.vnfs)) {
+ for (let vnfUUID in serviceHierarchy.vnfs) {
+ for (let vnfModuleUUID in serviceHierarchy.vnfs[vnfUUID].vfModules) {
+ if (serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].properties.minCountInstances > 0) {
+
+ let vfModule = this.generateVFModule(serviceHierarchy, vnfUUID, vnfModuleUUID);
+ this.updateVNFInstanceRedux(
+ serviceHierarchy.vnfs[vnfUUID].modelName,
+ serviceId,
+ serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].properties.initialCount,
+ vfModule,
+ this.generateVNFData(serviceHierarchy, vnfUUID, vnfModuleUUID, formServiceValues),
+ vnfModuleUUID
+ );
+ }
+ }
+ }
+ }
+ }
+
+ updateVNFInstanceRedux(vnfModelName: string, serviceId: string, numberOfVfModules: number, vfModuleData: any, vnfData: any, vfModuleName : string): void {
+ if (numberOfVfModules > 0) {
+ this.store.dispatch(updateVNFInstance(vnfData, vnfData.modelInfo.modelCustomizationName, serviceId));
+ for (let i = 0; i < numberOfVfModules; i++) {
+ this.store.dispatch(createVFModuleInstance(vfModuleData, vfModuleName, serviceId));
+ }
+ }
+ }
+
+
+ generateVFModule(serviceHierarchy: any, vnfUUID: string, vnfModuleUUID: string) {
+ return {
+ 'sdncPreReload': null,
+ 'modelInfo': {
+ 'modelType': 'VFmodule',
+ 'modelInvariantId': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].invariantUuid,
+ 'modelVersionId': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].uuid,
+ 'modelName': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].name,
+ 'modelVersion': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].version,
+ 'modelCustomizationId': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].customizationUuid,
+ 'modelCustomizationName': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].modelCustomizationName
+ },
+ 'instanceParams': [
+ {}
+ ]
+ };
+ }
+
+ generateVNFData(serviceHierarchy: any, vnfName: string, vnfUUID: string, formValues: any) {
+ return {
+ 'productFamilyId': formValues.productFamilyId,
+ 'lcpCloudRegionId': null,
+ 'tenantId': null,
+ 'lineOfBusiness': null,
+ 'platformName': null,
+ 'modelInfo': {
+ 'modelType': 'VF',
+ 'modelInvariantId': serviceHierarchy.vnfs[vnfName].invariantUuid,
+ 'modelVersionId': formValues.modelInfo.modelVersionId,
+ 'modelName': serviceHierarchy.vnfs[vnfName].name,
+ 'modelVersion': serviceHierarchy.vnfs[vnfName].version,
+ 'modelCustomizationId': serviceHierarchy.vnfs[vnfName].modelCustomizationId,
+ 'modelCustomizationName': serviceHierarchy.vnfs[vnfName].modelCustomizationName
+ },
+ 'isUserProvidedNaming': null
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/shared.module.ts b/vid-webpack-master/src/app/shared/shared.module.ts
new file mode 100644
index 000000000..ab6ecaa08
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/shared.module.ts
@@ -0,0 +1,92 @@
+import {NgModule, ModuleWithProviders} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {RouterModule} from '@angular/router';
+import { BrowserModule } from '@angular/platform-browser';
+import { HttpClientModule } from '@angular/common/http';
+import { ServiceInfoService } from './server/serviceInfo/serviceInfo.service';
+import { PopoverModule } from 'ngx-bootstrap';
+import { AngularSvgIconModule } from 'angular-svg-icon';
+import { SvgDirective } from './directives/svg/svg.directive';
+import { PopoverComponent } from './components/popover/popover.component';
+import { EllipsisComponent } from './components/ellipsis/ellipsis.component';
+import { MessageBoxComponent } from './components/messageBox/messageBox.component';
+import { MessageBoxService } from './components/messageBox/messageBox.service';
+import { SdcUiComponentsModule , SdcUiComponents} from 'sdc-ui/lib/angular';
+import { HttpInterceptorService } from './utils/httpInterceptor/httpInterceptor.service';
+import { FormControlErrorComponent } from './components/formControlError/formControlError.component';
+import { InputPreventionPatternDirective } from './directives/inputPrevention/inputPreventionPattern.directive';
+import { FormGeneralErrorsComponent } from './components/formGeneralErrors/formGeneralErrors.component';
+import { NumbersLettersUnderscoreValidator } from './components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import { SpinnerComponent } from './components/spinner/spinner.component';
+import { NoContentMessageAndIconComponent } from './components/no-content-message-and-icon/no-content-message-and-icon.component';
+import { ModelInformationComponent } from './components/model-information/model-information.component';
+import { TooltipModule } from 'ngx-tooltip';
+import {IframeService} from "./utils/iframe.service";
+import {CapitalizeAndFormatPipe} from "./pipes/capitalize/capitalize-and-format.pipe";
+import { DefaultDataGeneratorService } from './services/defaultDataServiceGenerator/default.data.generator.service';
+import {ServiceInfoPipe} from "./pipes/serviceInfo/serviceInfo.pipe";
+import {HealthStatusService} from "./server/healthStatusService/health-status.service";
+import {ConfigurationService} from "../services/configuration.service";
+import {FlagsResolve} from "../services/flags.resolve";
+
+
+@NgModule({
+ imports: [
+ BrowserModule,
+ HttpClientModule,
+ CommonModule,
+ RouterModule,
+ PopoverModule.forRoot(),
+ AngularSvgIconModule,
+ TooltipModule,
+ SdcUiComponentsModule,
+ ],
+ declarations: [
+ PopoverComponent,
+ SvgDirective,
+ EllipsisComponent,
+ MessageBoxComponent,
+ FormControlErrorComponent,
+ InputPreventionPatternDirective,
+ FormGeneralErrorsComponent,
+ SpinnerComponent,
+ NoContentMessageAndIconComponent,
+ ModelInformationComponent,
+ CapitalizeAndFormatPipe,
+ ServiceInfoPipe,
+ ],
+ exports: [
+ PopoverComponent,
+ SvgDirective,
+ EllipsisComponent,
+ MessageBoxComponent,
+ FormControlErrorComponent,
+ InputPreventionPatternDirective,
+ FormGeneralErrorsComponent,
+ SpinnerComponent,
+ NoContentMessageAndIconComponent,
+ ModelInformationComponent,
+ CapitalizeAndFormatPipe,
+ ServiceInfoPipe,
+ ],
+ providers: [
+ ServiceInfoService,
+ MessageBoxService,
+ SdcUiComponents.ModalService,
+ HttpInterceptorService,
+ IframeService,
+ NumbersLettersUnderscoreValidator,
+ DefaultDataGeneratorService,
+ HealthStatusService,
+ ConfigurationService,
+ FlagsResolve
+ ]
+})
+export class SharedModule {
+ static forRoot(): ModuleWithProviders {
+ return {
+ ngModule: SharedModule,
+ providers: [MessageBoxService]
+ };
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/utils/constants.ts b/vid-webpack-master/src/app/shared/utils/constants.ts
new file mode 100644
index 000000000..c78e12e28
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/constants.ts
@@ -0,0 +1,287 @@
+export module Constants {
+
+ export class Component {
+ public static NAME = 'name';
+ public static SERVICE = 'service';
+ public static A_LA_CARTE = 'a la carte';
+ public static MACRO = 'Macro';
+ public static SUBSCRIBER_NAME = 'subscriberName';
+ public static OLDVERSION = 'oldversion';
+ public static SERVICE_TYPE = 'serviceType';
+ }
+
+ export class Path {
+ public static FORWARD_SLASH = '/';
+
+ public static AAI_GET_FULL_SUBSCRIBERS = '../../aai_get_full_subscribers';
+ public static AAI_REFRESH_FULL_SUBSCRIBERS = 'aai_refresh_full_subscribers';
+ public static AAI_GET_SUBSCRIBERS = '../../aai_get_subscribers';
+
+ public static AAI_GET_TENTANTS = '../../aai_get_tenants';
+ public static AAI_REFRESH_SUBSCRIBERS = 'aai_refresh_subscribers';
+ public static AAI_SUB_DETAILS = 'aai_sub_details';
+ public static AAI_SUB_VIEWEDIT = '../../aai_sub_viewedit';
+
+ public static GET_WORKFLOW = 'change-management/get_vnf_workflow_relation';
+ public static GET_MSO_WORKFLOWS = 'change-management/mso';
+ public static GET_SCHEDULER_CHANGE_MANAGEMENTS = 'change-management/scheduler';
+ public static CANCEL_SCHEDULE_REQUEST = 'change-management/scheduler/schedules';
+ public static ASSIGN = '?r=';
+ public static AAI_GET_SERVICE_INSTANCE_PATH = 'aai_get_service_instance/';
+ public static AAI_GET_SERVICES = '../../aai_get_services';
+ public static AAI_GET_AIC_ZONES = '../../aai_get_aic_zones';
+ public static AAI_GET_AIC_ZONE_FOR_PNF = 'aai_get_aic_zone_for_pnf/@globalCustomerId/@serviceType/@serviceInstanceId';
+ public static AAI_GET_SERVICES_BY_TYPE = 'aai_get_models_by_service_type';
+ public static AAI_GET_TENANTS = '../../aai_get_tenants/';
+ public static AAI_SUB_DETAILS_PATH = '../../aai_sub_details/';
+ public static AAI_GET_VERSION_BY_INVARIANT_ID = 'aai_get_version_by_invariant_id/';
+ public static SEARCH_SERVICE_INSTANCES = 'search_service_instances';
+ public static AAI_GET_VNF_DATA_PATH = 'aai_get_vnf_data/';
+ public static AAI_GET_VNF_BY_CUSTOMERID_AND_SERVICETYPE = 'get_vnf_data_by_globalid_and_service_type/';
+ public static AAI_GET_SERVICES_BY_OWNING_ENTITY_ID = 'aai_get_services_by_owning_entity_id';
+ public static AAI_GET_VNF_INFO = 'aai_get_vnf_information';
+ public static AAI_GET_PNF_INSTANCE = 'aai_get_service_instance_pnfs';
+ public static AAI_GET_VNF_INSTANCES_LIST = 'aai_get_vnf_instances';
+ public static AAI_GET_PNF_INSTANCES_LIST = 'aai_get_pnf_instances';
+ public static AAI_GET_BY_URI = 'aai_get_by_uri/';
+ public static AAI_GET_CONFIGURATION = 'aai_get_configuration/';
+ public static AAI_GET_TEST_ENVIRONMENTS = 'get_operational_environments?operationalEnvironmentType=';
+ public static GET_CATEGORY_PARAMETERS = '../../category_parameter';
+ public static PARAMETER_STANDARDIZATION_FAMILY = 'PARAMETER_STANDARDIZATION';
+ public static TENANT_ISOLATION_FAMILY = 'TENANT_ISOLATION';
+ public static ASDC_GETMODEL_PATH = 'asdc/getModel/';
+ public static CREATE_INSTANCE_PATH = '/models/services/createInstance';
+ public static AAI_GET_PNF_BY_NAME = 'aai_get_pnfs/pnf/';
+
+ public static GET_SYSTEM_PROP_VNF_PROV_STATUS_PATH = 'get_system_prop_vnf_prov_status';
+ public static GET_USER_ID = 'getuserID';
+ public static INSTANTIATE_ROOT_PATH = '#/instantiate?subscriberId=';
+ public static INSTANTIATE_PATH = '/instantiate';
+ public static INVALID_STRING = '/INVALID_STRING/';
+ public static INVALID_STRING_MSO_CREATE_SVC_INSTANCE = 'INVALID_STRING_mso_create_svc_instance';
+ public static MSO = 'mso';
+ public static MSO_CREATE_NW_INSTANCE = 'mso_create_nw_instance';
+ public static MSO_CREATE_NW_INSTANCE_PATH = 'mso_create_nw_instance/';
+ public static MSO_CREATE_SVC_INSTANCE = 'mso_create_svc_instance';
+ public static MSO_CREATE_VNF_INSTANCE = '../../mso/mso_create_vnf_instance/';
+ public static MSO_DELETE_SVC_INSTANCE_PATH = 'mso_delete_svc_instance/';
+ public static MSO_ACTIVATE_INSTANCE = 'mso/mso_activate_service_instance/@serviceInstanceId';
+ public static MSO_DEACTIVATE_INSTANCE = 'mso/mso_deactivate_service_instance/@serviceInstanceId';
+ public static MSO_CREATE_REALATIONSHIP = 'mso_add_relationship';
+ public static MSO_REMOVE_RELATIONSHIP = 'mso_remove_relationship';
+ public static SELECTED_SERVICE_SUB_PATH = '#/instances/subdetails?';
+ public static SELECTED_SERVICE_INSTANCE_SUB_PATH = 'serviceInstanceIdentifier=';
+ public static SELECTED_SUBSCRIBER_SUB_PATH = 'subscriberId=';
+ public static OWNING_ENTITY_SUB_PATH = 'owningEntity=';
+ public static PROJECT_SUB_PATH = 'project=';
+ public static SERVICE_TYPE_LIST_PATH = '#/instances/serviceTypes?serviceTypeList=';
+ public static SERVICE_MODLES_INSTANCES_SUBSCRIBERS_PATH = 'serviceModels.htm#/instances/subscribers';
+ public static SERVICES_DIST_STATUS_PATH = '../../rest/models/services?distributionStatus=';
+ public static SERVICES_PATH = '../../rest/models/services/';
+ public static SERVICETYPE_SUB_PATH = '&serviceType=';
+ public static SERVICEINSTANCEID_SUB_PATH = '&serviceInstanceId=';
+ public static SERVICEMODELS_INSTANCES_SERVICES_PATH = 'serviceModels.htm#/instances/services';
+ public static SERVICEMODELS_MODELS_SERVICES_PATH = 'serviceModels.htm#/models/services';
+ public static SUBDETAILS_SELECTEDSUBSCRIBER = '#subdetails?selectedSubscriber=';
+ public static SUBSCRIBERNAME_SUB_PATH = '&subscriberName=';
+ public static WELCOME_PATH = 'welcome.htm';
+ public static IS_PERMITTED_SUB_PATH = '&isPermitted=';
+ public static SERVICES_JOB_INFO_PATH = '../../asyncInstantiation';
+ public static CONFIGURATION_PATH = '../../get_property/{name}/defaultvalue';
+ public static SERVICES_JOB_AUDIT_PATH = '/auditStatus';
+ public static SERVICES_PROBE_PATH = "../../probe";
+ public static FEATURES_FLAG_PATH ="../../flags";
+
+ // Test Environment Urls =
+ public static OPERATIONAL_ENVIRONMENT_CREATE = 'operationalEnvironment/create';
+ public static OPERATIONAL_ENVIRONMENT_DEACTIVATE = 'operationalEnvironment/deactivate?operationalEnvironment=';
+ public static OPERATIONAL_ENVIRONMENT_ACTIVATE = 'operationalEnvironment/activate?operationalEnvironment=';
+ public static OPERATIONAL_ENVIRONMENT_STATUS = 'operationalEnvironment/requestStatus?requestId=';
+
+ }
+
+ export class Key {
+
+ public static DESCRIPTION = 'description';
+ public static GENERIC_VNF = 'generic-vnf';
+ public static GLOBAL_CUSTOMER_ID = 'global-customer-id';
+ public static GLOBAL_CUST_ID = 'globalCustomerId';
+ public static IN_MAINT = 'in-maint';
+ public static INVENTORY_RESPONSE_ITEMS = 'inventory-response-items';
+ public static INVENTORY_RESPONSE_ITEM = 'inventory-response-item';
+ public static L3_NETWORK = 'l3-network';
+ public static SUB_NET = 'subnet';
+ public static SUBNET_NAME = 'subnet-name';
+ public static SUBNET_ID = 'subnet-id';
+ public static GATEWAY_ADDRESS = 'gateway-address';
+ public static NETWORK_START_ADDRESS = 'network-start-address';
+ public static CIDR_MASK = 'cidr-mask';
+ public static MODEL_CUSTOMIZATION_ID = 'model-customization-id';
+ public static MODEL_INVAR_ID = 'model-invariant-id';
+ public static MODEL_VERSION_ID = 'model-version-id';
+ public static NETWORK_NAME = 'network-name';
+ public static NETWORK_ID = 'network-id';
+ public static NETWORK_TYPE = 'network-type';
+ public static NETWORKS = 'networks';
+ public static OPERATIONAL_STATUS = 'operational-status';
+ public static ORCHESTRATION_STATUS = 'orchestration-status';
+ public static PERCENT_PROGRESS = 'percent-progress';
+ public static PERSONA_MODEL_ID = 'persona-model-id';
+ public static PERSONA_MODEL_VERSION = 'persona-model-version';
+ public static PERSONA_MODEL_CUSTOMIZATION_ID = 'persona-model-customization-id';
+ public static PROV_STATUS = 'prov-status';
+
+ public static RESOURCE_LINK = 'resource-link';
+ public static RESULT_DATA = 'result-data';
+ public static SERVICE_DESCRIPTION = 'service-description';
+ public static SERVICE_ID = 'service-id';
+ public static SERVICE_INSTANCE = 'service-instance';
+ public static SERVICE_INSTANCES = 'service-instances';
+ public static SERVICE_INSTANCE_ID = 'service-instance-id';
+ public static SERVICE_INSTANCE_NAME = 'service-instance-name';
+ public static SERVICE_SUBSCRIPTION = 'service-subscription';
+ public static SERVICE_SUBSCRIPTIONS = 'service-subscriptions';
+ public static SERVICETYPE = 'service-type';
+ public static STATUS_MESSAGE = 'statusMessage';
+ public static SUBNAME = 'subscriber-name';
+ public static IS_PERMITTED = 'is-permitted';
+ public static TIMESTAMP = 'timestamp';
+ public static VF_MODULE = 'vf-module';
+ public static VF_MODULES = 'vfModules';
+ public static VF_MODULE_ID = 'vf-module-id';
+ public static VF_MODULE_NAME = 'vf-module-name';
+ public static VID = 'VID';
+ public static VNF_ID = 'vnf-id';
+ public static VNF_NAME = 'vnf-name';
+ public static VNF_TYPE = 'vnf-type';
+ public static VNFS = 'vnfs';
+ public static AVAILABLEVOLUMEGROUPS = 'availableVolumeGroups';
+ public static VOLUMEGROUPS = 'volumeGroups';
+ public static VOLUME_GROUP = 'volume-group';
+ public static VOLUME_GROUP_ID = 'volume-group-id';
+ public static VOLUME_GROUP_NAME = 'volume-group-name';
+ public static UPLOAD_SUPPLEMENTORY_DATA_FILE = 'uploadSupplementoryDataFile';
+ public static SUPPLEMENTORY_DATA_FILE = 'supplementoryDataFile';
+ public static ZONE_ID = 'zone-id';
+ public static ZONE_NAME = 'zone-name';
+ public static GENERIC_CONFIGURATION = 'configuration';
+ public static CONFIGURATIONS = 'configurations';
+ public static CONFIGURATION = 'configuration';
+ public static CONFIGURATION_NAME = 'configuration-name';
+ public static CONFIGURATION_TYPE = 'configuration-type';
+ public static CONFIGURATION_ID = 'configuration-id';
+ public static PORT = 'l-interface';
+ public static PORT_ID = 'interface-id';
+ public static PORT_NAME = 'interface-name';
+ public static PORT_MIRRORED = 'is-port-mirrored';
+ }
+
+ export class Status {
+ public static ALL = 'ALL';
+ public static COMPLETE = 'Complete';
+ public static DONE = 'Done';
+ public static ERROR = 'Error';
+ public static FAILED = 'Failed';
+ public static FAILED_SERVICE_MODELS_ASDC = 'Failed to get service models from SDC.';
+ public static FETCHING_SERVICE_TYPES = 'Fetching service types list from A&AI';
+ public static FETCHING_SERVICE_CATALOG = 'Fetching service catalog from AAI. Please wait.';
+ public static FETCHING_SERVICE_CATALOG_ASDC = 'Fetching service catalog from SDC. Please wait.';
+ public static FETCHING_SUB_DETAILS = 'Fetching subscriber details from A&AI for ';
+ public static FETCHING_SERVICE_INST_DATA = 'Fetching service instance data from A&AI for service-instance-id=';
+ public static FETCHING_SUBSCRIBER_LIST_AAI = 'Fetching subscriber list from A&AI...';
+ public static IN_PROGRESS = 'In Progress';
+ public static IS_SUCCESSFUL = ' isSuccessful = ';
+ public static MSO_FAILURE = 'msoFailure';
+ public static NONE = 'None';
+ public static NOT_FOUND = 'Not Found';
+ public static NO_SERVICE_SUBSCRIPTION_FOUND = 'No Service Subscription Found';
+ public static SUBMITTING_REQUEST = 'Submitting Request';
+ public static SUCCESS_VNF_PROV_STATUS = 'Successfully set the VNF\'s Prov_Status to ';
+ public static UNLOCKED = 'Unlocked';
+ public static AAI_ACTIVE = 'Active';
+ public static AAI_INACTIVE = 'Inactive';
+ public static AAI_CREATED = 'Created';
+ public static AAI_ENABLED = 'Enabled';
+ public static AAI_DISABLED = 'Disabled';
+ }
+
+ export class Error {
+ public static AAI = 'A&AI failure - see log below for details';
+ public static AAI_ERROR = 'A&AI Error';
+ public static AAI_FETCHING_CUST_DATA = 'Failed to fetch customer data from A&AI= Response Code= ';
+ public static FETCHING_SERVICE_TYPES = 'Failed to fetch service types from A&AI= Response Code= ';
+ public static FETCHING_SERVICES = 'Failed to fetch services from A&AI= Response Code= ';
+ public static FETCHING_SERVICE_INSTANCE_DATA = 'Failed to fetch service instance data from A&AI= Response Code= ';
+ public static INVALID_INSTANCE_NAME = 'Invalid instance name= ';
+ // tslint:disable-next-line:max-line-length
+ public static INSTANCE_NAME_VALIDATE = 'The instance name must contain only alphanumeric or \'_-.\' characters; and must start with an alphabetic character';
+ public static INVALID_LIST = 'Invalid list parameter= ';
+ public static INVALID_MAP = 'Invalid map parameter= ';
+ public static LIST_VALIDATE = 'A list parameter value must have the following syntax= \'[<value1>;\.\.\.;<valueN>]\'';
+ // tslint:disable-next-line:max-line-length
+ public static MAP_VALIDATE = 'A map parameter value must have the following syntax= \'{ <entry_key_1>= <entry_value_1>; \.\.\.; <entry_key_n>= <entry_value_n> }\'';
+ public static MAX_POLLS_EXCEEDED = 'Maximum number of poll attempts exceeded';
+ public static MISSING_DATA = 'Missing data';
+ public static MODEL_VERSION_ID_MISSING = 'Error= model-version-id is not populated in A&AI';
+ public static MSO = 'MSO failure - see log below for details';
+ public static NO_MATCHING_MODEL = 'No matching model found matching the persona Model Id = ';
+ public static NO_MATCHING_MODEL_AAI = 'No matching model found matching the A&AI model version ID = ';
+ public static SELECT = 'Please select a subscriber or enter a service instance';
+ public static SERVICE_INST_DNE = 'That service instance does not exist. Please try again.';
+ public static SYSTEM_FAILURE = 'System failure';
+ public static INVALID_DATA_FORMAT = 'Invalid data format.Please check your file content whether it is not in json or not.';
+ public static MISSING_FILE = 'Please Select JSON File.';
+
+ public static MISSING_VNF_DETAILS = 'Missing required information.\n' +
+ 'Please open and fill in the details.\n';
+ }
+
+ export class EventType {
+ public static COMPONENT_STATUS = 'ComponentStatus';
+ public static CREATE_COMPONENT = 'createComponent';
+ public static DELETE_RESUME_COMPONENT = 'deleteResumeComponent';
+ }
+
+ export class ServicePopup {
+ public static TITLE = 'Create a new service instance';
+ public static TOOLTIP_UUID = 'Unique identifier for this service in this version.';
+ public static TOOLTIP_INVARIANT_UUID = 'Unique identifier for this service cross versions.';
+
+ }
+
+ export class Parameter {
+ public static BOOLEAN = "boolean";
+ public static SELECT = "select";
+ public static MULTI_SELECT = "multi_select";
+ public static STRING = "string";
+ public static NUMBER = "number";
+ public static VALID_VALUES = "valid_values";
+ public static EQUAL = "equal";
+ public static LENGTH = "length";
+ public static MAX_LENGTH = "max_length";
+ public static MIN_LENGTH = "min_length";
+ public static IN_RANGE = "in_range";
+ public static CONSTRAINTS = "constraints";
+ public static OPERATOR = "operator";
+ public static CONSTRAINT_VALUES = "constraintValues";
+ public static DEFAULT = "default";
+ public static DESCRIPTION = "description";
+ public static TYPE = "type";
+ public static INTEGER = "integer";
+ public static RANGE = "range";
+ public static LIST = "list";
+ public static MAP = "map";
+ public static REQUIRED = "required";
+ public static GREATER_THAN = "greater_than";
+ public static LESS_THAN = "less_than";
+ public static GREATER_OR_EQUAL = "greater_or_equal";
+ public static LESS_OR_EQUAL = "less_or_equal";
+ public static DISPLAY_NAME = "displayName";
+ public static CHECKBOX ='checkbox';
+ public static FILE ='file';
+ }
+
+ export class AuditInfoModal{
+ public static TITLE = 'Service Instantiation Information';
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/utils/httpInterceptor/httpInterceptor.service.ts b/vid-webpack-master/src/app/shared/utils/httpInterceptor/httpInterceptor.service.ts
new file mode 100644
index 000000000..be9ade080
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/httpInterceptor/httpInterceptor.service.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import {
+ HttpInterceptor,
+ HttpRequest,
+ HttpHandler,
+ HttpEvent, HttpErrorResponse
+} from '@angular/common/http';
+
+import { Observable } from 'rxjs/Observable';
+import { ErrorMessage, ErrorService } from '../../components/error/error.component.service';
+import { SpinnerComponent } from '../../components/spinner/spinner.component';
+
+@Injectable()
+export class HttpInterceptorService implements HttpInterceptor {
+ intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
+ SpinnerComponent.showSpinner.next(true);
+ return next.handle(request)
+ .catch((err: HttpErrorResponse) => {
+ if (err.status === 500) {
+ const errorMessage: ErrorMessage = new ErrorMessage('Server not available',
+ 'It appears that one of the backend servers is not responding.\n Please try later.',
+ 500);
+ ErrorService.showErrorWithMessage(errorMessage);
+ return Observable.of(null);
+ }
+ return Observable.throw(err);
+ }).finally(() => {
+ SpinnerComponent.showSpinner.next(false);
+ });
+ }
+}
+
diff --git a/vid-webpack-master/src/app/shared/utils/iframe.service.ts b/vid-webpack-master/src/app/shared/utils/iframe.service.ts
new file mode 100644
index 000000000..9a6636f4e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/iframe.service.ts
@@ -0,0 +1,19 @@
+import {Injectable} from "@angular/core";
+
+@Injectable()
+export class IframeService {
+
+ addClassOpenModal(elementClassName: string) {
+ var parentBodyElement = parent.document.getElementsByClassName(elementClassName)[0];
+ if (parentBodyElement) {
+ parentBodyElement.classList.add("modal-open");
+ }
+ }
+
+ removeClassCloseModal(elementClassName: string) {
+ var parentBodyElement = parent.document.getElementsByClassName(elementClassName)[0];
+ if (parentBodyElement) {
+ parentBodyElement.classList.remove("modal-open");
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/utils/log/log.service.spec.ts b/vid-webpack-master/src/app/shared/utils/log/log.service.spec.ts
new file mode 100644
index 000000000..ea0eb0499
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/log/log.service.spec.ts
@@ -0,0 +1,29 @@
+
+
+import {LogService} from "./log.service";
+
+describe('log service service', () => {
+ let logService : LogService;
+
+ beforeEach(() => {
+ logService = new LogService();
+ });
+
+
+ it('check all ILogger function are defined', ()=>{
+ expect(logService.log).toBeDefined();
+ expect(logService.assert).toBeDefined();
+ expect(logService.error).toBeDefined();
+ expect(logService.group).toBeDefined();
+ expect(logService.groupEnd).toBeDefined();
+ expect(logService.info).toBeDefined();
+ expect(logService.warn).toBeDefined();
+ });
+
+ it('test getPrefixLog function', ()=> {
+ let args = ['message', [1,2,3,4,5]];
+ let result = LogService.getPrefixLog(args);
+ expect(result).toBeDefined();
+ });
+
+});
diff --git a/vid-webpack-master/src/app/shared/utils/log/log.service.ts b/vid-webpack-master/src/app/shared/utils/log/log.service.ts
new file mode 100644
index 000000000..422fe0134
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/log/log.service.ts
@@ -0,0 +1,58 @@
+import {isDevMode} from "@angular/core";
+declare var console: any;
+
+export interface ILogger {
+ assert(...args: any[]): void;
+ error(...args: any[]): void;
+ group(...args: any[]): void;
+ groupEnd(...args: any[]): void;
+ info(...args: any[]): void;
+ log(...args: any[]): void;
+ warn(...args: any[]): void;
+}
+
+export class LogService implements ILogger {
+
+ isProduction : boolean = !isDevMode();
+ public assert(...args: any[]): void {
+ console.assert(LogService.getPrefixLog(...args));
+ }
+
+ public error(...args: any[]): void {
+ console.error(LogService.getPrefixLog(...args));
+ }
+
+ public group(...args: any[]): void {
+ console.group(LogService.getPrefixLog(...args));
+ }
+
+ public groupEnd(...args: any[]): void {
+ console.groupEnd(LogService.getPrefixLog(...args));
+ }
+
+ public info(...args: any[]): void {
+ console.info(LogService.getPrefixLog(...args));
+ }
+
+ public log(...args: any[]): void {
+ if(!this.isProduction){
+ console.log(LogService.getPrefixLog(...args));
+ }
+ }
+
+ public warn(...args: any[]): void {
+ console.warn(LogService.getPrefixLog(...args));
+ }
+
+ static getPrefixLog(...args :any[]){
+ return {
+ time : new Date(),
+ message : args[0],
+ data : args.length > 0 ? args[1] : ''
+ };
+ }
+}
+
+
+
+
diff --git a/vid-webpack-master/src/app/store/epics.ts b/vid-webpack-master/src/app/store/epics.ts
new file mode 100644
index 000000000..f424e7355
--- /dev/null
+++ b/vid-webpack-master/src/app/store/epics.ts
@@ -0,0 +1,13 @@
+import { Injectable } from '@angular/core';
+
+import {AAIEpics} from "../services/aaiService/aai.epics";
+
+@Injectable()
+export class RootEpics {
+ constructor(private aaiEpics: AAIEpics) {}
+
+ public createEpics() {
+ return this.aaiEpics.createEpic();
+
+ }
+}
diff --git a/vid-webpack-master/src/app/store/module.ts b/vid-webpack-master/src/app/store/module.ts
new file mode 100644
index 000000000..c0909c124
--- /dev/null
+++ b/vid-webpack-master/src/app/store/module.ts
@@ -0,0 +1,29 @@
+import { NgModule } from '@angular/core';
+import { NgReduxModule, NgRedux, DevToolsExtension } from '@angular-redux/store';
+import { RootEpics } from './epics';
+
+import rootReducer, {AppState} from "./reducers";
+import {AAIEpics} from "../services/aaiService/aai.epics";
+
+@NgModule({
+ imports: [NgReduxModule],
+ providers: [RootEpics, AAIEpics],
+})
+
+export class StoreModule {
+ constructor(
+ public store: NgRedux<AppState>,
+ devTools: DevToolsExtension,
+ rootEpics: RootEpics,
+ ) {
+
+ const persistedState = sessionStorage.getItem('reduxState') ?
+ JSON.parse(sessionStorage.getItem('reduxState')) : {};
+
+ store.configureStore(
+ rootReducer,
+ persistedState,
+ rootEpics.createEpics(),
+ devTools.isEnabled() ? [ devTools.enhancer() ] : []);
+ }
+}
diff --git a/vid-webpack-master/src/app/store/reducers.ts b/vid-webpack-master/src/app/store/reducers.ts
new file mode 100644
index 000000000..b3e4f4712
--- /dev/null
+++ b/vid-webpack-master/src/app/store/reducers.ts
@@ -0,0 +1,17 @@
+import {Reducer, combineReducers} from 'redux';
+import {GlobalReducer, GlobalState} from "../global.reducer";
+import {ServiceReducer, ServiceState} from "../service.reducer";
+
+
+export interface AppState {
+ global: GlobalState;
+ service: ServiceState;
+
+}
+
+const rootReducer: Reducer<AppState> = combineReducers<AppState>({
+ global: GlobalReducer,
+ service: ServiceReducer
+});
+
+export default rootReducer;
diff --git a/vid-webpack-master/src/app/utils/utils.ts b/vid-webpack-master/src/app/utils/utils.ts
new file mode 100644
index 000000000..dc4db3e4f
--- /dev/null
+++ b/vid-webpack-master/src/app/utils/utils.ts
@@ -0,0 +1,271 @@
+import { Constants } from '../shared/utils/constants';
+import Parameter = Constants.Parameter;
+import * as _ from 'lodash'
+
+export class Utils {
+
+ public static clampNumber = (number, min, max) => {
+ return Math.max(min, Math.min(number, max));
+ };
+
+ public static hasContents(object: Object): boolean {
+ if (object === undefined || object === null || object === "") {
+ return false;
+ }
+ return true;
+ };
+
+ public static convertModel(serviceModel) {
+
+ let isNewFlow:boolean = false;
+
+ for (let networkCustomizationName in serviceModel.networks) {
+ let networkModel = serviceModel.networks[networkCustomizationName];
+ if ( networkModel.customizationUuid != null ) {
+ isNewFlow = true;
+ break;
+ }
+ }
+ if ( !isNewFlow ) {
+ for (let vnfCustomizationName in serviceModel.vnfs) {
+ let vnfModel = serviceModel.vnfs[vnfCustomizationName];
+ if ( vnfModel.customizationUuid != null ) {
+ isNewFlow = true;
+ break;
+ }
+ }
+ }
+ if ( isNewFlow ) {
+ return (Utils.convertNewModel (serviceModel) );
+ }
+ else {
+ return (Utils.convertOldModel (serviceModel) );
+ }
+ };
+
+ private static convertNewModel (serviceModel ) {
+ let completeResources = new Array();
+ let resource = {};
+ let convertedAsdcModel = {
+ "service": serviceModel.service,
+ "networks": {},
+ "vnfs": {},
+ "pnfs": serviceModel.pnfs,
+ "serviceProxies": serviceModel.serviceProxies,
+ "completeDisplayInputs": {},
+ "isNewFlow": true
+ };
+
+ for(let key in serviceModel.service.inputs) {
+ if(_.includes(["instance_node_target", "naming_policy", "vf_instance_name"], key)) {
+ delete convertedAsdcModel.service.inputs[key];
+ }
+ }
+
+ for (let networkCustomizationName in serviceModel.networks) {
+ let networkModel = serviceModel.networks[networkCustomizationName];
+
+ convertedAsdcModel.networks[networkModel.customizationUuid] = {
+ "uuid": networkModel.uuid,
+ "invariantUuid": networkModel.invariantUuid,
+ "version": networkModel.version,
+ "name": networkModel.name,
+ "modelCustomizationName": networkModel.modelCustomizationName,
+ "customizationUuid": networkModel.customizationUuid,
+ "inputs": "",
+ "description": networkModel.description,
+ "commands": {},
+ "displayInputs": {}
+ };
+
+ resource = {
+ "name": networkModel.modelCustomizationName,
+ "description": networkModel.description
+ };
+
+ completeResources.push (resource);
+
+ }
+
+ _.forEach(serviceModel.configurations, function(element) {
+ element.isConfig = true;
+ });
+ _.forEach(serviceModel.pnfs, function(element, key) {
+ element.isPnf= true;
+ element.modelCustomizationName= key;
+ });
+ let mergedVnfs = Object.assign(serviceModel.vnfs, serviceModel.configurations, serviceModel.pnfs);
+
+ for (let vnfCustomizationName in mergedVnfs) {
+ let vnfModel = mergedVnfs[vnfCustomizationName];
+ let vnfCustomizationUuid = vnfModel.customizationUuid;
+ convertedAsdcModel.vnfs[vnfModel.customizationUuid] = {
+ "uuid": vnfModel.uuid,
+ "invariantUuid": vnfModel.invariantUuid,
+ "version": vnfModel.version,
+ "name": vnfModel.name,
+ "modelCustomizationName": vnfModel.modelCustomizationName,
+ "customizationUuid": vnfModel.customizationUuid,
+ "inputs": "",
+ "description": vnfModel.description,
+ "vfModules": {},
+ "volumeGroups": {},
+ "commands": {},
+ "displayInputs": {},
+ "properties": {},
+ "nfRole": "",
+ "nfType": "",
+ "sourceNodes": vnfModel.sourceNodes,
+ "collectorNodes": vnfModel.collectorNodes,
+ "isConfigurationByPolicy": vnfModel.configurationByPolicy ? vnfModel.configurationByPolicy : false,
+ "isConfig": vnfModel.isConfig ? vnfModel.isConfig : false,
+ "isPnf": vnfModel.isPnf ? vnfModel.isPnf : false
+ };
+
+ resource = {
+ "name": vnfModel.modelCustomizationName,
+ "description": vnfModel.description
+ };
+ completeResources.push (resource);
+
+ if (vnfModel.commands != null) {
+ /*
+ * commands: {
+ * internal_net_param_ntu: {
+ * command: get_input,
+ * displaName: internal_net_param_ntu,
+ * inputName: vccfd1_internal_net_param_ntu // pointer to input key
+ * }
+ * If the input name (ptr) is one of instance_node_target, naming_policy or vf_instance_name
+ * then ignore it
+ *
+ */
+
+ convertedAsdcModel.vnfs[vnfCustomizationUuid].properties=vnfModel.properties;
+ //
+ let vnf_type = "";
+ let vnf_role = "";
+ let vnf_function = "";
+ let vnf_code = "";
+ if ( !( _.isEmpty(vnfModel.properties) ) ) {
+ if (this.hasContents (vnfModel.properties.nf_type) ) {
+ vnf_type = vnfModel.properties.nf_type;
+ }
+ if (this.hasContents (vnfModel.properties.nf_role) ) {
+ vnf_role = vnfModel.properties.nf_role;
+ }
+ if (this.hasContents (vnfModel.properties.nf_function) ) {
+ vnf_function = vnfModel.properties.nf_function;
+ }
+ if (this.hasContents (vnfModel.properties.nf_naming_code) ) {
+ vnf_code = vnfModel.properties.nf_naming_code;
+ }
+ }
+ convertedAsdcModel.vnfs[vnfCustomizationUuid]["nfType"] = vnf_type;
+ convertedAsdcModel.vnfs[vnfCustomizationUuid]["nfRole"] = vnf_role;
+ convertedAsdcModel.vnfs[vnfCustomizationUuid]["nfFunction"] = vnf_function;
+ convertedAsdcModel.vnfs[vnfCustomizationUuid]["nfCode"] = vnf_code;
+ //
+ for (let vfModuleCustomizationName in serviceModel.vnfs[vnfCustomizationName].vfModules) {
+ let vfModuleModel = serviceModel.vnfs[vnfCustomizationName].vfModules[vfModuleCustomizationName];
+ convertedAsdcModel.vnfs[vnfCustomizationUuid].vfModules[vfModuleModel.customizationUuid] = vfModuleModel;
+ }
+
+ for (let volumeGroupCustomizationName in serviceModel.vnfs[vnfCustomizationName].volumeGroups) {
+ let volumeGroupModel = serviceModel.vnfs[vnfCustomizationName].volumeGroups[volumeGroupCustomizationName];
+ convertedAsdcModel.vnfs[vnfCustomizationUuid].volumeGroups[volumeGroupModel.customizationUuid] = volumeGroupModel;
+ }
+ }
+ }
+
+ return (convertedAsdcModel);
+ };
+
+ private static convertOldModel(serviceModel ) {
+ let resource = {};
+ let convertedAsdcModel = {
+ "service": serviceModel.service,
+ "networks": {},
+ "vnfs": {},
+ "pnfs": serviceModel.pnfs,
+ "serviceProxies": serviceModel.serviceProxies,
+ "completeDisplayInputs": {},
+ "isNewFlow": false
+ };
+ let completeResources = new Array();
+ for (let networkCustomizationName in serviceModel.networks) {
+ let networkModel = serviceModel.networks[networkCustomizationName];
+ convertedAsdcModel.networks[networkModel.invariantUuid] = {};
+ //convertedAsdcModel.networks[networkModel.invariantUuid][networkModel.version] = networkModel;
+ // need a network model to test this
+ convertedAsdcModel.networks[networkModel.uuid] = {
+ "uuid": networkModel.uuid,
+ "invariantUuid": networkModel.invariantUuid,
+ "version": networkModel.version,
+ "name": networkModel.name,
+ "modelCustomizationName": networkModel.modelCustomizationName,
+ "customizationUuid": networkModel.customizationUuid,
+ "inputs": "",
+ "description": networkModel.description,
+ "commands": {},
+ "displayInputs": {}
+ };
+ resource = {
+ "name": networkModel.modelCustomizationName,
+ "description": networkModel.description
+ };
+ completeResources.push (resource);
+ }
+
+ _.forEach(serviceModel.configurations, function(element) {
+ element.isConfig = true;
+ });
+ _.forEach(serviceModel.pnfs, function(element, key) {
+ element.isPnf= true;
+ element.modelCustomizationName= key;
+ });
+ let mergedVnfs = Object.assign(serviceModel.vnfs, serviceModel.configurations, serviceModel.pnfs);
+
+ for (let vnfCustomizationName in mergedVnfs) {
+ let vnfModel = mergedVnfs[vnfCustomizationName];
+ convertedAsdcModel.vnfs[vnfModel.uuid] = {
+ "uuid": vnfModel.uuid,
+ "invariantUuid": vnfModel.invariantUuid,
+ "version": vnfModel.version,
+ "name": vnfModel.name,
+ "modelCustomizationName": vnfModel.modelCustomizationName,
+ "customizationUuid": vnfModel.customizationUuid,
+ "inputs": "",
+ "description": vnfModel.description,
+ "vfModules": {},
+ "volumeGroups": {},
+ "commands": {},
+ "displayInputs": {},
+ "sourceNodes": vnfModel.sourceNodes,
+ "collectorNodes": vnfModel.collectorNodes,
+ "isConfigurationByPolicy": vnfModel.configurationByPolicy ? vnfModel.configurationByPolicy : false,
+ "isConfig": vnfModel.isConfig ? vnfModel.isConfig : false,
+ "isPnf": vnfModel.isPnf ? vnfModel.isPnf : false
+ };
+ resource = {
+ "name": vnfModel.modelCustomizationName,
+ "description": vnfModel.description
+ };
+ completeResources.push (resource);
+
+ for (let vfModuleCustomizationName in serviceModel.vnfs[vnfCustomizationName].vfModules) {
+ let vfModuleModel = serviceModel.vnfs[vnfCustomizationName].vfModules[vfModuleCustomizationName];
+ convertedAsdcModel.vnfs[vnfModel.uuid].vfModules[vfModuleModel.uuid] = vfModuleModel;
+ }
+
+ for (let volumeGroupCustomizationName in serviceModel.vnfs[vnfCustomizationName].volumeGroups) {
+ let volumeGroupModel = serviceModel.vnfs[vnfCustomizationName].volumeGroups[volumeGroupCustomizationName];
+ convertedAsdcModel.vnfs[vnfModel.uuid].volumeGroups[volumeGroupModel.uuid] = volumeGroupModel;
+ }
+ }
+
+ let completeDisplayInputs = {};
+
+ return (convertedAsdcModel);
+ };
+}
diff --git a/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.html b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.html
new file mode 100644
index 000000000..fbb16949a
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.html
@@ -0,0 +1,14 @@
+<div class="form-wrapper">
+ <form #form="ngForm">
+ <div class="network" *ngFor="let group of groups">
+ <label class="placeholder" [attr.data-tests-id]="'groupLabel'">{{getValueOfLabelInGroup(group,'Group Name')}}</label>
+ <select [(ngModel)]="groupSelection[getValueOfLabelInGroup(group,'Group Name')]" class="form-control input-text"
+ [attr.data-tests-id]="'groupTestId'"
+ id="{{getGroupName(group)}}" name="{{getGroupName(group)}}" required>
+ <option class="placeholder" [value]="undefined" disabled>Select Network</option>
+ <option *ngFor="let singleGroup of getNetworksByNetworkFunctionRole(group) | async"
+ [ngValue]="singleGroup">{{singleGroup["instance-group"]["instance-group-name"]}}</option>
+ </select>
+ </div>
+ </form>
+</div>
diff --git a/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.scss b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.scss
new file mode 100644
index 000000000..aa45b34f3
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.scss
@@ -0,0 +1,17 @@
+.form-wrapper{
+ width:640px;
+ padding-left: 50px;
+ padding-top: 50px;
+ .network{
+ padding-bottom: 30px;
+ }
+ .network {
+ select {
+ font-family: OpenSans-Italic;
+ font-size: 14px;
+ color: #959595 !important;
+ }
+ }
+}
+
+
diff --git a/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.ts b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.ts
new file mode 100644
index 000000000..46a176984
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.ts
@@ -0,0 +1,66 @@
+import {Component, Input, OnInit, ViewChild} from "@angular/core";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import {ModelInformationItem} from "../../shared/components/model-information/model-information.component";
+import {Observable} from "rxjs/Observable";
+import {NgForm} from "@angular/forms";
+import * as _ from 'lodash';
+
+@Component({
+ selector: "app-network-selector",
+ templateUrl: "./network-selector.component.html",
+ styleUrls: ["./network-selector.component.scss"]
+})
+export class NetworkSelectorComponent implements OnInit {
+ private localStore: NgRedux<AppState>;
+ networkSelection: any;
+ groupSelection :any;
+ @Input() groups: Array<string>;
+ @Input() cloudOwner : string;
+ @Input() cloudRegionId : string;
+ @select(['service', 'networkFunctions'])
+ readonly networkFunctions: Observable<any>;
+
+ @ViewChild('form') form: NgForm;
+
+ constructor(store: NgRedux<AppState>) {
+ this.localStore = store;
+ this.groupSelection = {};
+ console.log(store);
+ }
+
+ getValueOfLabelInGroup(group: any, label: string){
+ let item = _.find(group, {"label": label});
+ if (item) {
+ return item["values"][0];
+ }
+ }
+
+ getNetworksByNetworkFunctionRole(group: any): Observable<string[]> {
+ let filteredItem = this.getValueOfLabelInGroup(group,"Network Collection Function");
+ return this.networkFunctions.map(data => {
+ return (data && data[filteredItem]) || [];
+ });
+ }
+
+ getGroupName(group: ModelInformationItem[]) {
+ return this.getValueOfLabelInGroup(group,"Group Name");
+ }
+
+ /**
+ * [ncf=>aaiResonse]
+ * groups => groupsModel
+ */
+
+ ngOnInit() {
+ let store = this.localStore;
+ this.networkSelection = {};
+
+ }
+}
+
+
+//
+/*
+Info inside redux = {ncfNetworkMap }
+*/
diff --git a/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.html b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.html
new file mode 100644
index 000000000..f474f4bd1
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.html
@@ -0,0 +1,27 @@
+<div class="vlan-wrapper-config">
+ <div class="head">
+ <div class="title">Collection Resource Consumer VNF</div>
+ <div class="btn-wrapper">
+ <button class="cancel-btn grey" data-tests-id="cancelButton" (click)="cancel()">{{cancelButtonText}}</button>
+ <button class="next-btn blue" data-tests-id="nextButton" [disabled]="isNextButtonDisabled()" (click)="nextStep()">{{nextButtonText}}</button>
+ </div>
+ </div>
+ <span (serviceInstamce)="onServiceInstanceChange($event)"></span>
+ <div class="content-wrapper">
+ <div class="left-side">
+ <formasync [hidden]="currentStep === wizardSteps.two" [model]="model" class="form"></formasync>
+ <app-network-selector [hidden]="currentStep === wizardSteps.one" class="form-wrapper" [groups]="groups"></app-network-selector>
+ </div>
+
+ <div style="padding-left: 30px;padding-right: 30px" class="sidebar-right">
+ <div class="headline">META DATA</div>
+ <div class="seperator"></div>
+ <model-information [modelInformationItems]="modelInfoItems"></model-information>
+ <div class="headline">Collection Resource Consumer VNF</div>
+ <div *ngFor="let group of groups">
+ <div class="seperator"></div>
+ <model-information [modelInformationItems]="group"></model-information>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.scss b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.scss
new file mode 100644
index 000000000..af4a7e212
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.scss
@@ -0,0 +1,168 @@
+$popupHeaderHeight: 59px;
+
+.vlan-wrapper-config * {
+ font-family: OpenSans-Regular, sans-serif;
+}
+
+.body-content-jsp {
+ margin-top: 35px;
+ margin-left: 201px;
+ margin-right: 0px;
+ background-color: white;
+}
+
+:host {
+ height: 100%;
+}
+.form-wrapper{
+ min-width: 75%;
+ overflow: auto;
+}
+button {
+ border-radius: 2px;
+ font-size: 14px;
+ line-height: 28px;
+ height: 30px;
+ &.blue {
+ border: #0091c8 1px solid;
+ background-color: #009fdb;
+ color: white;
+ &:hover {
+ background-color: #1ec2ff;
+ border-color: #0091c8;
+ }
+ &:active {
+ background-color: #0091c7;
+ border-color: #006186;
+ }
+ &[disabled] {
+ background-color: rgba(5, 104, 174, 0.3);
+ border-color: rgba(4, 113, 168, 0.3);
+ }
+ }
+ &.grey {
+ color: #009FDB;
+ background-color: #ffffff;
+ border: 1px solid #009FDB;
+ &:hover {
+ background-color: #f8f8f8;
+ border-color: #009fdb;
+ }
+ &:active {
+ background-color: #d8d8d8;
+ border-color: #5a5a5a;
+ }
+ &[disabled] {
+ background-color: #f8f8f8;
+ border-color: #d8d8d8;
+ color: #cdcdcd;
+ }
+ }
+ &.white {
+ border: #009fdb 1px solid;
+ background-color: white;
+ color: #009fdb;
+ }
+}
+
+.vlan-wrapper-config {
+ /*todo: remove. this a temporary fix for the sub-interface popup not showing as a page beside the sidebar. currently showing it in full screen.*/
+ /*it is necessary inside the iframe (and not just in the angularjs - old app) angular app because in Firefox the iframe content isn't effected by the iframe size */
+ width: 100vw;
+ height: 100vh;
+ position: fixed;
+ /********************/
+ .head {
+ line-height: $popupHeaderHeight;
+ height: $popupHeaderHeight;
+ display: flex;
+ background-color: #F8F8F8;
+ border-bottom: 1px solid #D8D8D8;
+ .title {
+ font-size: 18px;
+ margin-left: 56px;
+ color: #5A5A5A;
+ }
+ .btn-wrapper {
+ flex: 1;
+ text-align: right;
+ margin-right: 15px;
+ button {
+ width: 120px;
+ &.delete-btn {
+ margin-left: 13px;
+ }
+ }
+ }
+ }
+ .content-wrapper {
+ display: flex;
+ .form {
+ overflow-y: auto;
+ }
+ height: calc(100% - #{$popupHeaderHeight});
+ .form {
+ margin-top: 48px;
+
+ }
+ .content {
+ .form-wrapper {
+
+ margin: 0 auto;
+ }
+ }
+
+ }
+
+ span.error {
+ color: #cf2a2a;
+ }
+ .content-wrapper .content .form-wrapper .instance-field {
+ .ng-invalid-pattern {
+ border-color: #cf2a2a;
+ color: #cf2a2a;
+ }
+ margin-bottom: 25px;
+ label {
+ color: #191919;
+ font-size: 13px;
+ }
+ input,
+ select {
+ border-color: #D2D2D2;
+ }
+ &.lcpRegionText,
+ &.productFamily {
+ display: none;
+ }
+ }
+
+}
+
+.sidebar-right {
+ min-width: 25%;
+ background-color: #F8F8F8;
+ overflow-y: auto;
+ .headline {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ color: #009FDB;
+ padding-bottom: 6px;
+ padding-top: 20px
+ }
+ .seperator{
+ background: #D2D2D2;
+ height: 1px;
+ margin-bottom: 10px;
+ }
+}
+
+.left-side{
+ min-width: 75%;
+ overflow:auto;
+
+}
+
+.sidebar-right service-metadata .metadata-content {
+ padding-bottom: 20px;
+}
diff --git a/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.ts b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.ts
new file mode 100644
index 000000000..f3f63e1e9
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.ts
@@ -0,0 +1,203 @@
+import {formasync} from './../components/form-async/form-async.component';
+import {Component, OnInit, ViewChild} from "@angular/core";
+import {NetworkSelectorComponent} from "./network-selector/network-selector.component";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../store/reducers";
+import {ActivatedRoute} from "@angular/router";
+import {
+ loadServiceAccordingToUuid, loadAaiNetworkAccordingToNetworkCF,
+ loadUserId
+} from "../services/aaiService/aai.actions";
+import {createRequest} from "../factories/mso.factory";
+import {Observable} from "rxjs/Observable";
+import {VNFModel} from "../shared/models/vnfModel";
+import {VfcInstanceGroupProperties} from "../shared/models/vfcInstanceGroupProperties";
+import * as _ from "lodash";
+import {ModelInformationItem} from "../shared/components/model-information/model-information.component";
+
+enum WizardSteps {
+ one,
+ two
+}
+
+const buttonTextNext = "Next";
+const buttonTextBack = "Back";
+const buttonTextConfirm = "Confirm";
+const buttonTextCancel = "Cancel";
+
+@Component({
+ selector: "vlan-tagging",
+ templateUrl: "./vlan-tagging.component.html",
+ styleUrls: ["./vlan-tagging.component.scss"]
+})
+
+export class VlanTaggingComponent implements OnInit {
+ constructor(private store: NgRedux<AppState>,
+ private route: ActivatedRoute) {
+ this.nextButtonText = buttonTextNext;
+ this.cancelButtonText = buttonTextCancel;
+ this.currentStep = WizardSteps.one;
+ }
+
+ subscriberName: string;
+ serviceKey: string;
+ serviceType: string;
+ vnfKey: string;
+ serviceInstanceName: string;
+ serviceModelId: string;
+ modelInfoItems: Array<ModelInformationItem>;
+ groups: Array<Array<ModelInformationItem>>;
+ currentStep: WizardSteps;
+ nextButtonText: string;
+ cancelButtonText: string;
+ wizardSteps = WizardSteps;
+ cloudOwner: string;
+ cloudRegionId: string;
+ serviceInstanceId : string;
+ model: VNFModel;
+ userId: string;
+ modelCustomizationId : string;
+ onServiceInstanceChange(event) {
+ console.log(event);
+ }
+
+ private serviceHirarchy: any;
+
+ @select(['service', 'serviceHierarchy'])
+ readonly serviceHierarchyObserable: Observable<any>;
+
+ @select(['service', 'userId'])
+ readonly userIdObs: Observable<any>;
+
+
+ @ViewChild(NetworkSelectorComponent)
+ public networkSelectorComponent: NetworkSelectorComponent;
+ @ViewChild(formasync)
+ public formAsync: formasync;
+
+
+ deploySubInterface() {
+
+ const requestDetails = createRequest(
+ this.userId,
+ this.formAsync.serviceInstance,
+ this.serviceHirarchy[this.serviceModelId],
+ this.serviceKey,
+ this.networkSelectorComponent.groupSelection,
+ this.vnfKey,
+ this.modelCustomizationId
+ );
+
+ // this.msoService.createVnf(requestDetails, this.serviceKey).subscribe();
+
+ window.parent.postMessage({
+ eventId: 'submitIframe',
+ data: requestDetails
+ }, "*");
+ }
+
+ ngOnInit() {
+ this.cloudRegionId = "";
+ this.store.dispatch(loadUserId());
+ this.userIdObs.subscribe(res => this.userId = res);
+ this.route.queryParams.subscribe(params => {
+ this.serviceModelId = params["serviceModelId"];
+ this.subscriberName = params["subscriberName"];
+ this.serviceType = params["serviceType"];
+ this.serviceKey = params["serviceInstanceID"];
+ this.vnfKey = params["modelCustomizationName"];
+ this.serviceInstanceId = params["serviceInstanceID"];
+ this.serviceInstanceName = params["serviceInstanceName"];
+ this.modelCustomizationId = params["modelCustomizationId"];
+ this.cloudOwner = params["globalCustomerId"];
+ this.store.dispatch(loadServiceAccordingToUuid(this.serviceModelId));
+ this.serviceHierarchyObserable.subscribe(data => {
+ this.serviceHirarchy = data;
+ if (data && data[this.serviceModelId]) {
+ this.model = new VNFModel(data[this.serviceModelId].vnfs[this.vnfKey]);
+ this.updateModelInfo(this.model);
+ }
+ });
+ });
+ }
+
+ private updateModelInfo(vnfModel: VNFModel) {
+ this.modelInfoItems = [
+ new ModelInformationItem("Service Instance Name", "serviceInstanceName", [this.serviceInstanceName], "", true),
+ new ModelInformationItem("Model Invariant UUID", "modelInvariantUUID", [vnfModel.invariantUuid], "", true),
+ new ModelInformationItem("Model Version", "modelVersion", [vnfModel.version], "", true),
+ new ModelInformationItem("Model UUID", "modelUuid", [vnfModel.uuid], "", true),
+ new ModelInformationItem("Model Customization UUID", "modelCustomizationUuid", [vnfModel.customizationUuid], "", true),
+ ];
+
+ this.groups = [];
+ _.forOwn(vnfModel.vfcInstanceGroups, (vfcInstanceGroup, key) => {
+ const properties: VfcInstanceGroupProperties = vfcInstanceGroup.vfcInstanceGroupProperties;
+ this.groups.push(this.createGroupsInformation(vfcInstanceGroup.name, properties));
+ });
+ }
+
+ nextStep() {
+ switch (this.currentStep) {
+ case WizardSteps.one:
+ this.groups.map(group => {
+ let networkName = _.find(group, (groupElements: ModelInformationItem) => groupElements.testsId === "networkCollectionFunction");
+ this.store.dispatch(
+ loadAaiNetworkAccordingToNetworkCF(networkName["values"][0], this.cloudOwner, this.formAsync.serviceInstance.lcpRegion)
+ );
+ });
+ this.currentStep = WizardSteps.two;
+ this.updateNavigationButtonText(this.currentStep);
+ break;
+ case WizardSteps.two:
+ this.deploySubInterface();
+ break;
+ }
+ }
+
+ cancel() {
+ switch (this.currentStep) {
+ case WizardSteps.one:
+ window.parent.postMessage({
+ eventId: 'closeIframe'
+ }, "*");
+ break;
+ case WizardSteps.two:
+ this.currentStep = WizardSteps.one;
+ this.updateNavigationButtonText(this.currentStep);
+ break;
+ }
+ }
+
+ updateNavigationButtonText(step: WizardSteps) {
+ switch (step) {
+ case WizardSteps.one:
+ this.nextButtonText = buttonTextNext;
+ this.cancelButtonText = buttonTextCancel;
+ break;
+ case WizardSteps.two:
+ this.nextButtonText = buttonTextConfirm;
+ this.cancelButtonText = buttonTextBack;
+ break;
+ }
+ }
+
+ isNextButtonDisabled() {
+ switch (this.currentStep) {
+ case WizardSteps.one:
+ return !this.formAsync.form.valid;
+ case WizardSteps.two:
+ return !this.networkSelectorComponent.form.valid;
+ }
+ }
+
+ createGroupsInformation(name: string, properties: VfcInstanceGroupProperties): Array<ModelInformationItem> {
+ let modelInfoItems = [];
+ modelInfoItems.push(new ModelInformationItem("Group Name", "groupName", [name], "", true));
+ modelInfoItems.push(new ModelInformationItem("Network Collection Function", "networkCollectionFunction", [properties.networkCollectionFunction], "", true));
+ modelInfoItems.push(new ModelInformationItem("VFC Instance Group Function", "instanceGroupFunction", [properties.vfcInstanceGroupFunction], "", true));
+ modelInfoItems.push(new ModelInformationItem("Parent Port Role", "parentPortRole", [properties.vfcParentPortRole], "", true));
+ modelInfoItems.push(new ModelInformationItem("Sub Interface Role", "subInterfaceRole", [properties.subinterfaceRole], "", true));
+ return modelInfoItems;
+ }
+}
diff --git a/vid-webpack-master/src/app/vlanTagging/vlan-tagging.module.ts b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.module.ts
new file mode 100644
index 000000000..3227542c6
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.module.ts
@@ -0,0 +1,33 @@
+
+import { formasync } from './../components/form-async/form-async.component';
+import {NgModule,} from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { VlanTaggingComponent } from './vlan-tagging.component';
+import {CommonModule} from '@angular/common';
+import { BrowserModule } from '@angular/platform-browser';
+import { NgReduxModule } from '@angular-redux/store';
+import { SharedModule } from '../shared/shared.module';
+import { NetworkSelectorComponent } from './network-selector/network-selector.component';
+import { TooltipModule } from 'ngx-tooltip';
+
+
+
+@NgModule({
+
+imports: [
+ CommonModule,
+ NgReduxModule,
+ FormsModule,
+ BrowserModule,
+ TooltipModule,
+ SharedModule.forRoot()
+
+ ],
+ providers: [ ],
+ declarations: [VlanTaggingComponent,formasync,NetworkSelectorComponent],
+ entryComponents: [],
+ exports: [formasync]
+
+})
+
+export class VlanTaggingModule { }
diff --git a/vid-webpack-master/src/assets/.gitkeep b/vid-webpack-master/src/assets/.gitkeep
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vid-webpack-master/src/assets/.gitkeep
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/Apache License.txt b/vid-webpack-master/src/assets/fonts/OpenSans/Apache License.txt
new file mode 100644
index 000000000..989e2c59e
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/Apache License.txt
@@ -0,0 +1,201 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. \ No newline at end of file
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Bold.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Bold.ttf
new file mode 100644
index 000000000..fd79d43be
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Bold.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-BoldItalic.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-BoldItalic.ttf
new file mode 100644
index 000000000..9bc800958
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-BoldItalic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-ExtraBold.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-ExtraBold.ttf
new file mode 100644
index 000000000..21f6f84a0
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-ExtraBold.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf
new file mode 100644
index 000000000..31cb68834
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Italic.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Italic.ttf
new file mode 100644
index 000000000..c90da48ff
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Italic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Light.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Light.ttf
new file mode 100644
index 000000000..0d381897d
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Light.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-LightItalic.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-LightItalic.ttf
new file mode 100644
index 000000000..68299c4bc
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-LightItalic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Regular.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Regular.ttf
new file mode 100644
index 000000000..db433349b
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Regular.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Semibold.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Semibold.ttf
new file mode 100644
index 000000000..1a7679e39
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-Semibold.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-SemiboldItalic.ttf b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-SemiboldItalic.ttf
new file mode 100644
index 000000000..59b6d16b0
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/OpenSans/OpenSans-SemiboldItalic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/icomoon.eot b/vid-webpack-master/src/assets/fonts/icomoon.eot
new file mode 100644
index 000000000..a568b91a5
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/icomoon.eot
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/icomoon.svg b/vid-webpack-master/src/assets/fonts/icomoon.svg
new file mode 100644
index 000000000..44c81d7dc
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/icomoon.svg
@@ -0,0 +1,70 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>Generated by IcoMoon</metadata>
+<defs>
+<font id="icomoon" horiz-adv-x="1024">
+<font-face units-per-em="1024" ascent="960" descent="-64" />
+<missing-glyph horiz-adv-x="1024" />
+<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
+<glyph unicode="&#xe900;" glyph-name="add" d="M810.667 490.667h-256v256c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-256h-256c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h256v-256c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v256h256c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667z" />
+<glyph unicode="&#xe901;" glyph-name="add_f" d="M512 917.333c260.267 0 469.333-209.067 469.333-469.333s-209.067-469.333-469.333-469.333c-260.267 0-469.333 209.067-469.333 469.333s209.067 469.333 469.333 469.333zM682.667 490.667h-128v128c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-128h-128c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h128v-128c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v128h128c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667z" />
+<glyph unicode="&#xe902;" glyph-name="add_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333zM682.667 490.667h-128v128c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-128h-128c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h128v-128c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v128h128c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667z" />
+<glyph unicode="&#xe903;" glyph-name="alert_f" d="M997.611 209.079c12.843-17.067 17.067-42.667 21.333-64 0-34.176-12.8-64-38.4-89.6-21.333-25.6-55.424-38.4-89.6-38.4h-725.333c-21.333 0-42.667 4.267-59.733 17.067-59.733 34.091-81.067 115.2-46.933 174.933l358.4 610.133c8.533 17.024 25.6 34.133 42.667 42.667 29.867 17.024 64 21.333 98.133 12.8s64-29.867 81.067-59.776l358.4-605.824zM512 618.667c-25.6 0-42.667-17.067-42.667-42.667v-170.667c0-25.643 17.067-42.667 42.667-42.667s42.667 17.024 42.667 42.667v170.667c0 25.6-17.067 42.667-42.667 42.667zM482.133 264.533c-8.533-8.491-12.8-17.024-12.8-29.824 0-12.843 4.267-21.333 12.8-29.867 8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.533 8.533 12.8 21.333 12.8 29.867 0 8.491-4.267 21.333-12.8 29.824-17.067 17.067-42.667 17.067-59.733 0z" />
+<glyph unicode="&#xe904;" glyph-name="alert_o" d="M920.811 115.213c-8.533-8.533-21.333-12.8-29.867-12.8h-725.333c-8.533 0-12.8 0-21.333 4.267-21.333 12.8-25.6 38.4-17.067 59.733l362.667 601.6c4.267 4.224 8.533 12.8 12.8 12.8 21.333 12.757 46.933 4.267 59.733-12.8l362.709-601.6c4.224-4.267 4.224-12.843 4.224-21.333 4.267-12.843-4.224-21.333-8.533-29.867zM997.611 209.079l-358.4 605.824c-17.067 29.909-46.933 51.243-81.067 59.776s-68.267 4.224-98.133-12.8c-17.067-8.533-34.133-25.643-42.667-42.667l-358.4-610.133c-34.133-59.733-12.8-140.843 46.933-174.933 17.067-12.8 38.4-17.067 59.733-17.067h725.333c34.176 0 68.267 12.8 89.6 38.4 25.6 25.6 38.4 55.424 38.4 89.6-4.267 21.333-8.491 46.933-21.333 64zM512 618.667c-25.6 0-42.667-17.067-42.667-42.667v-170.667c0-25.643 17.067-42.667 42.667-42.667s42.667 17.024 42.667 42.667v170.667c0 25.6-17.067 42.667-42.667 42.667zM482.133 264.533c-8.533-8.491-12.8-17.024-12.8-29.824 0-12.843 4.267-21.333 12.8-29.867 8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.533 8.533 12.8 21.333 12.8 29.867 0 8.491-4.267 21.333-12.8 29.824-17.067 17.067-42.667 17.067-59.733 0z" />
+<glyph unicode="&#xe905;" glyph-name="API" d="M853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 874.667h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128zM798.165 478.165l-170.667 170.667c-16.683 16.683-43.648 16.683-60.331 0s-16.683-43.648 0-60.331l140.501-140.501-140.501-140.501c-16.683-16.683-16.683-43.648 0-60.331 8.32-8.32 19.243-12.501 30.165-12.501s21.845 4.181 30.165 12.501l170.667 170.667c16.683 16.683 16.683 43.648 0 60.331zM225.835 478.165l170.667 170.667c16.683 16.683 43.648 16.683 60.331 0s16.683-43.648 0-60.331l-140.501-140.501 140.501-140.501c16.683-16.683 16.683-43.648 0-60.331-8.32-8.32-19.243-12.501-30.165-12.501s-21.845 4.181-30.165 12.501l-170.667 170.667c-16.683 16.683-16.683 43.648 0 60.331z" />
+<glyph unicode="&#xe906;" glyph-name="arrow-left" d="M183.467 477.899c-4.267-4.309-8.533-8.533-8.533-12.8-4.267-4.267-4.267-12.843-4.267-17.067 0-4.267 0-12.8 4.267-17.109 4.267-4.224 4.267-8.491 8.533-12.757l170.667-170.667c17.067-17.067 42.667-17.067 59.733 0s17.067 42.667 0 59.733l-98.091 98.133h494.891c25.6 0 42.667 17.067 42.667 42.667 0 25.557-17.067 42.667-42.667 42.667h-494.891l98.091 98.133c17.067 17.067 17.067 42.667 0 59.733-17.067 17.024-42.667 17.024-59.733 0l-170.667-170.667z" />
+<glyph unicode="&#xe907;" glyph-name="arrow-right" d="M840.533 418.101c4.267 4.309 8.533 8.533 8.533 12.8 4.267 4.267 4.267 12.843 4.267 17.067 0 4.267 0 12.8-4.267 17.109-4.267 4.224-4.267 8.491-8.533 12.757l-170.667 170.667c-17.067 17.067-42.667 17.067-59.733 0s-17.067-42.667 0-59.733l98.091-98.133h-494.891c-25.6 0-42.667-17.067-42.667-42.667 0-25.557 17.067-42.667 42.667-42.667h494.891l-98.091-98.133c-17.067-17.067-17.067-42.667 0-59.733 17.067-17.024 42.667-17.024 59.733 0l170.667 170.667z" />
+<glyph unicode="&#xe908;" glyph-name="arrow_f" d="M938.667 448c0-235.641-191.025-426.667-426.667-426.667s-426.667 191.025-426.667 426.667c0 235.641 191.025 426.667 426.667 426.667s426.667-191.025 426.667-426.667zM458.762 311.637c-10.286-10.637-10.286-27.88 0-38.516s26.962-10.637 37.248 0l150.497 155.621c10.286 10.637 10.286 27.88 0 38.516l-150.497 155.621c-10.286 10.637-26.962 10.637-37.248 0s-10.286-27.88 0-38.516l131.948-136.441-131.948-136.285z" />
+<glyph unicode="&#xe909;" glyph-name="arrow_o" d="M458.762 311.637c-10.286-10.637-10.286-27.88 0-38.516s26.962-10.637 37.248 0l150.497 155.621c10.286 10.637 10.286 27.88 0 38.516l-150.497 155.621c-10.286 10.637-26.962 10.637-37.248 0s-10.286-27.88 0-38.516l131.948-136.441-131.948-136.285zM512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM42.667 448c0-260.267 209.067-469.333 469.333-469.333s469.333 209.067 469.333 469.333c0 260.267-209.067 469.333-469.333 469.333s-469.333-209.067-469.333-469.333z" />
+<glyph unicode="&#xe90a;" glyph-name="attach" d="M924.768 478.208c-16.768 15.872-41.941 15.872-58.709 0l-386.005-364.757c-83.925-79.275-213.973-79.275-297.856 0-83.925 79.317-83.925 202.197 0 281.515l386.005 364.757c46.123 43.563 130.005 43.563 176.171 0 50.347-47.616 50.347-122.923 0-166.571l-385.963-364.715c-16.811-15.872-41.984-15.872-58.752 0-4.181 3.968-8.405 11.904-8.405 23.765 0 11.904 4.224 19.84 12.587 27.776l356.651 336.981c16.768 15.872 16.768 39.68 0 55.509-16.811 15.872-41.984 15.872-58.752 0l-356.651-336.981c-25.173-19.84-37.717-51.541-37.717-83.285 0-31.701 12.544-63.403 37.717-83.243 50.389-47.573 130.091-47.573 176.213 0l386.005 364.757c83.925 79.275 83.925 202.197 0 281.472-37.76 35.669-92.288 59.477-146.816 59.477-54.571 0-109.099-19.84-146.859-59.477l-386.005-364.715c-113.28-107.051-113.28-285.483 0-392.533 58.752-55.467 134.272-79.275 209.792-79.275s150.997 27.733 209.749 79.275l386.005 364.757c8.405 11.904 8.405 39.637-8.405 55.509z" />
+<glyph unicode="&#xe90b;" glyph-name="beadcrumbs" d="M731.429 448l-365.714-365.714v731.429z" />
+<glyph unicode="&#xe90c;" glyph-name="bedge" d="M273.067 789.333h477.867c150.811 0 273.067-122.256 273.067-273.067v-136.533c0-150.811-122.256-273.067-273.067-273.067h-477.867c-150.811 0-273.067 122.256-273.067 273.067v136.533c0 150.811 122.256 273.067 273.067 273.067z" />
+<glyph unicode="&#xe90d;" glyph-name="browse" d="M279.704 400.593c-36.655 0-66.37 29.715-66.37 66.37s29.715 66.37 66.37 66.37c36.655 0 66.37-29.715 66.37-66.37s-29.715-66.37-66.37-66.37zM744.296 400.593c-36.655 0-66.37 29.715-66.37 66.37s29.715 66.37 66.37 66.37c36.655 0 66.37-29.715 66.37-66.37s-29.715-66.37-66.37-66.37zM512 400.593c-36.655 0-66.37 29.715-66.37 66.37s29.715 66.37 66.37 66.37c36.655 0 66.37-29.715 66.37-66.37s-29.715-66.37-66.37-66.37z" />
+<glyph unicode="&#xe90e;" glyph-name="calendar" d="M810.667 64h-597.333c-25.6 0-42.667 17.067-42.667 42.667v384h682.667v-384c0-25.6-17.067-42.667-42.667-42.667zM213.333 746.667h85.333v-42.667c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v42.667h256v-42.667c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v42.667h85.333c25.6 0 42.667-17.067 42.667-42.667v-128h-682.667v128c0 25.6 17.067 42.667 42.667 42.667zM810.667 832h-85.333v42.667c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-42.667h-256v42.667c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-42.667h-85.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe90f;" glyph-name="camera" d="M938.667 149.333c0-25.6-17.067-42.667-42.667-42.667h-768c-25.6 0-42.667 17.067-42.667 42.667v469.333c0 25.6 17.067 42.667 42.667 42.667h170.667c12.8 0 25.6 8.533 34.133 17.067l72.533 110.933h209.067l72.533-110.933c12.8-8.533 25.6-17.067 38.4-17.067h170.667c25.6 0 42.667-17.067 42.667-42.667v-469.333zM896 746.667h-149.333l-72.533 110.933c-8.533 8.533-21.333 17.067-34.133 17.067h-256c-12.8 0-25.6-8.533-34.133-17.067l-72.533-110.933h-149.333c-72.533 0-128-55.467-128-128v-469.333c0-72.533 55.467-128 128-128h768c72.533 0 128 55.467 128 128v469.333c0 72.533-55.467 128-128 128zM512 234.667c-72.533 0-128 55.467-128 128s55.467 128 128 128c72.533 0 128-55.467 128-128s-55.467-128-128-128zM512 576c-119.467 0-213.333-93.867-213.333-213.333s93.867-213.333 213.333-213.333c119.467 0 213.333 93.867 213.333 213.333s-93.867 213.333-213.333 213.333z" />
+<glyph unicode="&#xe910;" glyph-name="chevron" d="M482.125 290.125c8.533-8.533 21.333-12.8 29.867-12.8s21.333 4.267 29.867 12.8l213.333 213.333c17.067 17.067 17.067 42.667 0 59.733s-42.667 17.067-59.733 0l-183.467-183.467-183.467 183.467c-17.067 17.067-42.667 17.067-59.733 0s-17.067-42.667 0-59.733l213.333-213.333z" />
+<glyph unicode="&#xe911;" glyph-name="close" d="M580.25 448l258.475 258.475c19.499 19.499 19.499 48.725 0 68.224s-48.768 19.499-68.267 0l-258.475-258.432-258.432 258.432c-19.499 19.499-48.768 19.499-68.267 0s-19.499-48.725 0-68.224l258.475-258.475-258.475-258.475c-19.499-19.499-19.499-48.725 0-68.224 9.771-9.771 19.499-14.635 34.133-14.635s24.363 4.864 34.133 14.635l258.432 258.432 258.475-258.432c9.771-9.771 24.363-14.635 34.133-14.635 9.728 0 24.363 4.864 34.133 14.635 19.499 19.499 19.499 48.725 0 68.224l-258.475 258.475z" />
+<glyph unicode="&#xe912;" glyph-name="commit" d="M896.086 106.965c-338.304 1.152-340.693 454.101-340.651 473.557v106.88l99.157-97.323c8.32-8.192 19.072-12.245 29.867-12.245 11.136 0 22.187 4.309 30.592 12.843 16.469 16.896 16.213 44.032-0.683 60.544l-171.819 168.576c-0.341 0.299-0.811 0.384-1.152 0.725-3.541 3.285-7.509 6.187-12.203 8.149-0.213 0.085-0.341 0.085-0.512 0.128-0.725 0.299-1.451 0.299-2.133 0.555-4.139 1.408-8.277 2.176-12.501 2.304-0.768 0-1.451 0.256-2.219 0.256-0.171 0-0.341 0.085-0.512 0.085-1.067 0-1.963-0.555-3.029-0.597-2.603-0.299-5.12-0.811-7.68-1.579-8.96-2.347-16.512-7.253-22.144-14.293l-165.803-163.456c-16.811-16.597-17.067-43.691-0.512-60.587 16.555-16.811 43.605-17.024 60.416-0.469l96 94.677v-105.387c0.043-19.243-2.347-472.192-340.651-473.344-23.595-0.085-42.667-19.328-42.581-42.965 0.085-23.595 19.2-42.667 42.752-42.667h0.171c107.051 0.384 196.949 36.608 267.307 107.648 56.832 57.429 93.056 130.347 116.437 200.789 23.424-70.443 59.648-143.36 116.48-200.789 70.315-71.040 160.213-107.264 267.264-107.648h0.171c23.552 0 42.667 19.072 42.752 42.667 0.085 23.637-18.987 42.88-42.581 42.965z" />
+<glyph unicode="&#xe913;" glyph-name="composition" d="M810.667 104.533c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667zM213.333 104.533c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667zM213.333 787.2c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM512 488.533c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM810.667 275.2c-55.68 0-102.528-35.755-120.149-85.333h-357.035c-12.843 36.224-41.259 64.64-77.483 77.483v135.851h135.851c17.621-49.579 64.469-85.333 120.149-85.333 70.699 0 128 57.301 128 128s-57.301 128-128 128c-55.68 0-102.528-35.755-120.149-85.333h-135.851v135.851c49.579 17.621 85.333 64.469 85.333 120.149 0 70.699-57.301 128-128 128s-128-57.301-128-128c0-55.68 35.755-102.528 85.333-120.149v-357.035c-49.579-17.621-85.333-64.469-85.333-120.149 0-70.699 57.301-128 128-128 55.68 0 102.528 35.755 120.149 85.333h357.035c17.621-49.579 64.469-85.333 120.149-85.333 70.699 0 128 57.301 128 128s-57.301 128-128 128z" />
+<glyph unicode="&#xe914;" glyph-name="deployment_Artifacts" d="M853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 874.667h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128zM298.667 277.333c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM512 661.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM725.333 277.333c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667zM405.888 387.285l66.176 110.379c12.629-4.224 25.899-6.997 39.936-6.997 6.784 0 13.312 0.981 19.84 2.005l81.152-108.16c-23.339-15.232-41.003-37.845-50.475-64.512h-101.035c-10.112 28.544-29.909 52.181-55.595 67.285zM461.483 234.667h101.035c17.621-49.579 64.469-85.333 120.149-85.333 70.699 0 128 57.301 128 128 0 62.805-45.312 114.773-104.96 125.653l-98.304 131.115c20.053 22.571 32.597 51.968 32.597 84.565 0 70.699-57.301 128-128 128s-128-57.301-128-128c0-25.216 7.552-48.597 20.139-68.395l-88.533-147.541c-58.368-11.904-102.272-63.531-102.272-125.397 0-70.699 57.301-128 128-128 55.68 0 102.528 35.755 120.149 85.333z" />
+<glyph unicode="&#xe915;" glyph-name="download" d="M896 277.333c25.6 0 42.667-17.067 42.667-42.667v-128c0-72.533-55.467-128-128-128h-597.333c-72.533 0-128 55.467-128 128v128c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-128c0-25.6 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.067 42.667 42.667v128c0 25.6 17.067 42.667 42.667 42.667zM482.101 247.467l-170.667 170.667c-17.024 17.067-17.024 42.667 0 59.733 17.067 17.067 42.667 17.067 59.733 0l98.133-98.091v494.891c0 25.6 17.109 42.667 42.667 42.667 25.6 0 42.667-17.067 42.667-42.667v-494.891l98.133 98.091c17.067 17.067 42.667 17.067 59.733 0s17.067-42.667 0-59.733l-170.667-170.667c-4.267-4.267-8.533-4.267-12.757-8.533-4.309-4.267-12.843-4.267-17.109-4.267-4.224 0-12.8 0-17.067 4.267-4.267 0-8.491 4.267-12.8 8.533z" />
+<glyph unicode="&#xe916;" glyph-name="duplicate" d="M128 106.667c0-25.6 17.067-42.667 42.667-42.667h384c25.6 0 42.667 17.067 42.667 42.667v384c0 25.6-17.067 42.667-42.667 42.667h-384c-25.6 0-42.667-17.067-42.667-42.667v-384zM170.667 618.667h384c72.533 0 128-55.467 128-128v-384c0-72.533-55.467-128-128-128h-384c-72.533 0-128 55.467-128 128v384c0 72.533 55.467 128 128 128zM810.667 362.667h42.667c25.6 0 42.667 17.067 42.667 42.667v384c0 25.6-17.067 42.667-42.667 42.667h-384c-25.6 0-42.667-17.067-42.667-42.667v-42.667c0-25.6-17.067-42.667-42.667-42.667s-42.667 17.067-42.667 42.667v42.667c0 72.533 55.467 128 128 128h384c72.533 0 128-55.467 128-128v-384c0-72.533-55.467-128-128-128h-42.667c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667z" />
+<glyph unicode="&#xe917;" glyph-name="edit" d="M170.667 388.271v-110.933h110.933l426.667 426.667-110.933 110.933-426.667-426.667zM128 192.004c-25.6 0-42.667 17.067-42.667 42.667v170.667c0 12.8 4.267 21.333 12.8 29.867l469.333 469.333c17.067 17.067 42.667 17.067 59.733 0l170.667-170.667c17.067-17.067 17.067-42.667 0-59.733l-469.333-469.333c-8.533-8.533-17.067-12.8-29.867-12.8h-170.667zM896 64c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667h-768c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h768z" />
+<glyph unicode="&#xe918;" glyph-name="expand" d="M934.426 849.067c4.267-4.309 4.267-12.843 4.267-17.067v-256c0-25.6-17.109-42.667-42.667-42.667-25.6 0-42.667 17.067-42.667 42.667v153.557l-226.133-226.133c-8.533-8.533-21.333-12.757-29.867-12.757-8.576 0-21.333 4.224-29.909 12.757-17.024 17.109-17.024 42.667 0 59.776l226.133 226.133h-153.557c-25.6 0-42.667 17.067-42.667 42.667 0 25.557 17.067 42.667 42.667 42.667h256c4.224 0 12.757 0 17.067-4.267 8.491-4.309 17.024-12.843 21.333-21.333zM396.8 392.525c17.067 17.024 42.667 17.024 59.733 0 17.067-17.067 17.067-42.667 0-59.733l-226.091-226.133h153.557c25.6 0 42.667-17.109 42.667-42.667 0-25.6-17.067-42.667-42.667-42.667h-256c-4.224 0-12.8 0-17.067 4.224-8.491 4.309-17.067 12.843-21.333 21.333-4.267 4.309-4.267 12.843-4.267 17.109v256c0 25.557 17.109 42.667 42.667 42.667 25.6 0 42.667-17.109 42.667-42.667v-153.6l226.133 226.133zM913.092 25.566c-4.309-4.267-12.843-4.267-17.067-4.267h-256c-25.6 0-42.667 17.109-42.667 42.667 0 25.6 17.067 42.667 42.667 42.667h153.557l-226.133 226.133c-8.533 8.533-12.757 21.333-12.757 29.867 0 8.576 4.224 21.333 12.757 29.909 17.109 17.024 42.667 17.024 59.776 0l226.133-226.133v153.557c0 25.6 17.067 42.667 42.667 42.667 25.557 0 42.667-17.067 42.667-42.667v-256c0-4.224 0-12.757-4.267-17.067-4.309-8.491-12.843-17.024-21.333-21.333zM456.55 563.191c17.024-17.067 17.024-42.667 0-59.733-17.067-17.067-42.667-17.067-59.733 0l-226.133 226.091v-153.557c0-25.6-17.109-42.667-42.667-42.667-25.6 0-42.667 17.067-42.667 42.667v256c0 4.224 0 12.8 4.224 17.067 4.309 8.491 12.843 17.067 21.333 21.333 4.309 4.267 12.843 4.267 17.109 4.267h256c25.557 0 42.667-17.109 42.667-42.667 0-25.6-17.109-42.667-42.667-42.667h-153.6l226.133-226.133z" />
+<glyph unicode="&#xe919;" glyph-name="fail" d="M580.25 448l258.475 258.475c19.499 19.499 19.499 48.725 0 68.224s-48.768 19.499-68.267 0l-258.475-258.432-258.432 258.432c-19.499 19.499-48.768 19.499-68.267 0s-19.499-48.725 0-68.224l258.475-258.475-258.475-258.475c-19.499-19.499-19.499-48.725 0-68.224 9.771-9.771 19.499-14.635 34.133-14.635s24.363 4.864 34.133 14.635l258.432 258.432 258.475-258.432c9.771-9.771 24.363-14.635 34.133-14.635 9.728 0 24.363 4.864 34.133 14.635 19.499 19.499 19.499 48.725 0 68.224l-258.475 258.475z" />
+<glyph unicode="&#xe91a;" glyph-name="file_managment" d="M853.333 375.462c25.6 0 42.667-17.024 42.667-42.667v-226.133c0-72.533-55.467-128-128-128h-597.333c-72.533 0-128 55.467-128 128v597.333c0 72.533 55.467 128 128 128h226.133c25.6 0 42.667-17.067 42.667-42.667 0-25.557-17.067-42.667-42.667-42.667h-226.133c-25.6 0-42.667-17.067-42.667-42.667v-597.333c0-25.557 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.109 42.667 42.667v226.133c0 25.643 17.067 42.667 42.667 42.667zM494.916 320.004h-110.933v110.933l384 384 110.933-110.933-384-384zM968.559 733.871l-170.667 170.667c-17.109 17.067-42.667 17.067-59.776 0l-426.667-426.667c-8.533-8.533-12.8-17.067-12.8-29.867v-170.667c0-25.6 17.109-42.667 42.667-42.667h170.667c12.8 0 21.333 4.267 29.909 12.8l426.667 426.667c17.024 17.067 17.024 42.667 0 59.733z" />
+<glyph unicode="&#xe91b;" glyph-name="filter" d="M563.595 456.533c-4.309-8.533-8.533-17.067-8.533-29.867v-294.443l-85.333 42.667v251.776c0 8.533-4.267 21.333-8.533 25.557l-281.6 337.109h669.867l-285.867-332.8zM977.461 849.067c-8.533 17.067-21.333 25.6-38.4 25.6h-853.333c-17.109 0-29.867-8.533-38.443-25.6-8.491-12.843-4.224-29.867 4.309-42.667l332.8-392.533v-264.533c0-17.109 8.533-29.867 25.557-38.443l170.667-85.333c4.309-4.224 8.576-4.224 17.109-4.224s17.067 0 21.333 4.224c12.8 8.576 21.333 21.333 21.333 38.443v349.867l332.8 392.533c8.533 12.8 12.757 29.824 4.267 42.667z" />
+<glyph unicode="&#xe91c;" glyph-name="filterDown" d="M482.101 162.133c4.309-4.267 8.533-8.533 12.8-8.533 4.267-4.267 12.843-4.267 17.067-4.267 4.267 0 12.8 0 17.109 4.267 4.224 4.267 8.491 4.267 12.757 8.533l170.667 170.667c17.067 17.067 17.067 42.667 0 59.733s-42.667 17.067-59.733 0l-98.133-98.091v494.891c0 25.6-17.067 42.667-42.667 42.667-25.557 0-42.667-17.067-42.667-42.667v-494.891l-98.133 98.091c-17.067 17.067-42.667 17.067-59.733 0-17.024-17.067-17.024-42.667 0-59.733l170.667-170.667z" />
+<glyph unicode="&#xe91d;" glyph-name="filterUp" d="M482.101 819.2c4.309 4.267 8.533 8.533 12.8 8.533 4.267 4.267 12.843 4.267 17.067 4.267 4.267 0 12.8 0 17.109-4.267 4.224-4.267 8.491-4.267 12.757-8.533l170.667-170.667c17.067-17.067 17.067-42.667 0-59.733s-42.667-17.067-59.733 0l-98.133 98.091v-494.891c0-25.6-17.067-42.667-42.667-42.667-25.557 0-42.667 17.067-42.667 42.667v494.891l-98.133-98.091c-17.067-17.067-42.667-17.067-59.733 0-17.024 17.067-17.024 42.667 0 59.733l170.667 170.667z" />
+<glyph unicode="&#xe91e;" glyph-name="info_f" d="M512 917.333c260.267 0 469.333-209.067 469.333-469.333 0-260.309-209.067-469.333-469.333-469.333s-469.333 209.024-469.333 469.333c0 260.267 209.067 469.333 469.333 469.333zM512 490.667c-25.6 0-42.667-17.067-42.667-42.667v-170.667c0-25.643 17.067-42.667 42.667-42.667s42.667 17.024 42.667 42.667v170.667c0 25.6-17.067 42.667-42.667 42.667zM482.125 648.542c-8.533-8.533-12.8-17.067-12.8-29.867s4.267-21.333 12.8-29.867c8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.576 8.533 12.8 17.067 12.8 29.867s-4.224 21.333-12.8 29.867c-17.067 17.024-42.667 17.024-59.733 0z" />
+<glyph unicode="&#xe91f;" glyph-name="info_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333 0-260.309 209.067-469.333 469.333-469.333s469.333 209.024 469.333 469.333c0 260.267-209.067 469.333-469.333 469.333zM512 490.667c-25.6 0-42.667-17.067-42.667-42.667v-170.667c0-25.643 17.067-42.667 42.667-42.667s42.667 17.024 42.667 42.667v170.667c0 25.6-17.067 42.667-42.667 42.667zM482.125 648.542c-8.533-8.533-12.8-17.067-12.8-29.867s4.267-21.333 12.8-29.867c8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.576 8.533 12.8 17.067 12.8 29.867s-4.224 21.333-12.8 29.867c-17.067 17.024-42.667 17.024-59.733 0z" />
+<glyph unicode="&#xe920;" glyph-name="info_tabs" d="M512 490.667c25.6 0 42.667-17.067 42.667-42.667v-170.667c0-25.643-17.067-42.667-42.667-42.667s-42.667 17.024-42.667 42.667v170.667c0 25.6 17.067 42.667 42.667 42.667zM482.133 648.565c17.067 17.024 42.667 17.024 59.733 0 8.576-8.533 12.8-17.067 12.8-29.867s-4.224-21.333-12.8-29.867c-8.533-8.576-17.067-12.8-29.867-12.8s-21.333 4.224-29.867 12.8c-8.533 8.533-12.8 17.067-12.8 29.867s4.267 21.333 12.8 29.867zM853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 874.667h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe921;" glyph-name="information_artifacts" d="M512 490.667c25.6 0 42.667-17.067 42.667-42.667v-170.667c0-25.643-17.067-42.667-42.667-42.667s-42.667 17.024-42.667 42.667v170.667c0 25.6 17.067 42.667 42.667 42.667zM482.133 648.565c17.067 17.024 42.667 17.024 59.733 0 8.576-8.533 12.8-17.067 12.8-29.867s-4.224-21.333-12.8-29.867c-8.533-8.576-17.067-12.8-29.867-12.8s-21.333 4.224-29.867 12.8c-8.533 8.533-12.8 17.067-12.8 29.867s4.267 21.333 12.8 29.867zM853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 874.667h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe922;" glyph-name="inputs" d="M853.333 147.2c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 872.533h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128zM725.333 659.2h-426.667c-23.467 0-42.667-19.2-42.667-42.667s19.2-42.667 42.667-42.667h426.667c23.467 0 42.667 19.2 42.667 42.667s-19.2 42.667-42.667 42.667zM725.333 488.533h-426.667c-23.467 0-42.667-19.2-42.667-42.667s19.2-42.667 42.667-42.667h426.667c23.467 0 42.667 19.2 42.667 42.667s-19.2 42.667-42.667 42.667z" />
+<glyph unicode="&#xe923;" glyph-name="locked" d="M341.333 661.333c0 93.867 76.8 170.667 170.667 170.667s170.667-76.8 170.667-170.667v-128h-341.333v128zM810.667 533.333h-42.667v128c0 140.8-115.2 256-256 256s-256-115.2-256-256v-128h-42.667c-72.533 0-128-55.467-128-128v-298.667c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v298.667c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe924;" glyph-name="Menu" d="M445.649 699.24c0 36.655 29.715 66.37 66.37 66.37s66.37-29.715 66.37-66.37c0-36.655-29.715-66.37-66.37-66.37s-66.37 29.715-66.37 66.37zM445.649 234.648c0 36.655 29.715 66.37 66.37 66.37s66.37-29.715 66.37-66.37c0-36.655-29.715-66.37-66.37-66.37s-66.37 29.715-66.37 66.37zM445.649 466.944c0 36.655 29.715 66.37 66.37 66.37s66.37-29.715 66.37-66.37c0-36.655-29.715-66.37-66.37-66.37s-66.37 29.715-66.37 66.37z" />
+<glyph unicode="&#xe925;" glyph-name="notifications" d="M234.667 277.333h554.667c-12.8 25.6-21.333 55.467-21.333 85.333v213.333c0 140.8-115.2 256-256 256s-256-115.2-256-256v-213.333c0-29.867-8.533-59.733-21.333-85.333zM938.667 277.333c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667h-853.333c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667c46.933 0 85.333 38.4 85.333 85.333v213.333c0 187.733 153.6 341.333 341.333 341.333s341.333-153.6 341.333-341.333v-213.333c0-46.933 38.4-85.333 85.333-85.333zM644.131 100.648c21.333-12.8 29.867-38.4 8.533-59.733-25.6-42.667-68.267-64-110.933-64-21.333 0-42.667 4.267-64 17.067s-34.133 25.6-46.933 46.933c-8.533 21.333-4.309 46.933 17.024 59.733 21.333 8.533 46.976 4.267 59.776-17.067 4.224-8.533 8.533-12.8 17.067-17.067 21.333-8.533 46.933-4.267 59.733 17.067 12.757 21.333 38.4 29.867 59.733 17.067z" />
+<glyph unicode="&#xe926;" glyph-name="permissions" d="M554.667 362.667h-341.333c-119.467 0-213.333-93.867-213.333-213.333v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c0 72.533 55.467 128 128 128h341.333c72.533 0 128-55.467 128-128v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c0 119.467-93.867 213.333-213.333 213.333zM384 789.333c72.533 0 128-55.467 128-128s-55.467-128-128-128c-72.533 0-128 55.467-128 128s55.467 128 128 128zM384 448c119.467 0 213.333 93.867 213.333 213.333s-93.867 213.333-213.333 213.333c-119.467 0-213.333-93.867-213.333-213.333s93.867-213.333 213.333-213.333zM862.684 361.849c-21.333 4.267-46.976-8.533-51.2-29.867-4.267-21.333 8.533-46.933 29.867-51.2 55.467-12.8 93.867-64 93.867-123.733v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c4.267 98.133-59.733 183.467-157.867 204.8zM693.444 872.034c-21.333 8.533-42.667-4.267-51.2-29.867-4.267-21.333 8.533-46.933 29.867-51.2 68.267-17.067 110.933-85.333 93.867-157.867-12.843-46.933-46.933-81.067-93.867-93.867-21.333-4.267-38.4-29.867-29.867-51.2 4.224-21.333 21.333-34.133 42.667-34.133h8.533c76.8 21.333 136.533 76.8 153.6 153.6 29.867 119.467-38.4 238.933-153.6 264.533z" />
+<glyph unicode="&#xe927;" glyph-name="profile" d="M682.667 362.667h-341.333c-119.467 0-213.333-93.867-213.333-213.333v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c0 72.533 55.467 128 128 128h341.333c72.533 0 128-55.467 128-128v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c0 119.467-93.867 213.333-213.333 213.333zM512 789.333c72.533 0 128-55.467 128-128s-55.467-128-128-128c-72.533 0-128 55.467-128 128s55.467 128 128 128zM512 448c119.467 0 213.333 93.867 213.333 213.333s-93.867 213.333-213.333 213.333c-119.467 0-213.333-93.867-213.333-213.333s93.867-213.333 213.333-213.333z" />
+<glyph unicode="&#xe928;" glyph-name="properties" d="M512 362.658c-46.933 0-85.333 38.4-85.333 85.333 0 46.976 38.4 85.333 85.333 85.333s85.333-38.357 85.333-85.333c0-46.933-38.4-85.333-85.333-85.333zM512 618.658c-93.867 0-170.667-76.8-170.667-170.667s76.8-170.667 170.667-170.667c93.867 0 170.667 76.8 170.667 170.667s-76.8 170.667-170.667 170.667zM814.916 209.075c8.533-8.533 12.843-17.067 12.843-29.867s-4.309-21.333-12.843-29.867c-8.491-8.576-17.024-12.8-29.824-12.8-12.843 0-21.333 4.224-34.176 17.067-34.133 34.133-81.024 42.667-123.691 21.333-42.667-17.067-68.309-59.733-68.309-102.4v-8.533c0-25.6-17.024-42.667-42.667-42.667-25.6 0-42.667 17.067-42.667 42.667v4.267c0 46.933-29.824 85.333-72.491 102.4-12.843 8.533-29.867 8.533-46.976 8.533-29.867 0-59.691-12.8-81.024-34.133-17.109-17.067-38.443-17.067-55.509-4.309l-8.491 17.109h-4.309c-4.224 4.224-4.224 12.8-4.224 17.067 0 12.8 4.224 21.333 17.024 34.133 34.176 34.133 42.667 81.024 21.333 123.691-17.024 42.667-59.691 68.309-102.357 68.309h-8.576c-25.557 0-42.667 17.024-42.667 42.667 0 25.6 17.109 42.667 42.667 42.667h4.267c46.976 0 85.333 29.867 102.4 72.533 17.109 42.667 8.576 89.6-25.557 128-17.109 17.067-17.109 42.667 0 59.733 17.024 17.067 42.667 17.067 64-4.267 29.824-29.867 76.8-38.4 115.157-25.643l12.843 4.309c42.667 17.024 68.224 59.691 68.224 102.357v8.576c0 25.6 17.109 42.667 42.667 42.667 25.6 0 42.667-17.067 42.667-46.933 0-46.976 25.6-85.333 68.267-102.4s89.643-8.576 128 25.6c8.533 8.491 17.067 12.8 29.867 12.8s21.333-4.309 29.867-12.8c17.109-17.067 17.109-42.667-4.224-64-29.867-29.867-38.443-76.843-25.643-115.2l4.309-12.8c17.024-42.667 59.691-68.267 102.357-68.267h8.533c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-46.891-42.667c-46.976 0-85.333-25.6-102.443-68.267-21.333-42.667-8.533-89.643 25.6-128zM866.116 302.942c4.309 8.491 12.8 17.067 29.867 17.067 72.576 0 128 55.424 128 128 0 72.533-55.424 128-128 128h-8.533c-8.533 0-17.024 4.267-21.333 12.757l-4.224 8.576c-4.309 8.533-4.309 21.333 8.533 34.091 46.891 46.976 51.157 115.243 12.8 166.443v12.8l-17.109 8.533c-21.333 21.333-51.2 34.133-85.333 34.133s-68.224-12.8-93.867-38.4c-8.491-8.533-21.333-8.533-29.824-4.267-8.533-4.267-17.109 8.533-17.109 21.333 0 72.533-55.424 128-128 128-72.533 0-128-55.467-128-128v-8.576c0-8.491-4.224-17.024-12.757-21.333l-8.576-4.224c-8.533-4.267-21.333 0-34.091 8.533-51.243 51.2-132.309 51.2-179.243 0-51.2-51.2-51.2-132.309 4.267-183.467 8.533-8.533 8.533-21.333 4.309-34.176-4.309-8.491-17.109-17.024-29.909-17.024-72.533 0-128-55.467-128-128s55.467-128 128-128h8.576c12.757 0 21.333-8.533 25.557-17.067 4.309-8.576 4.309-21.333-8.533-34.133-25.6-25.6-38.357-55.467-38.357-89.6 0-29.867 12.757-59.733 34.091-85.333l4.267-4.267 12.843-12.8c51.157-38.443 119.467-34.133 170.667 12.8 8.491 8.533 21.333 8.533 34.133 4.267 12.757-4.267 17.024-12.843 17.024-29.867 0-72.533 55.509-128 128-128 72.533 0 128 55.467 128 128v8.533c0 12.8 8.533 21.333 17.067 25.6 8.576 4.224 21.333 4.224 34.133-8.533 51.2-51.243 132.309-51.243 179.2 0 51.243 51.2 51.243 132.267-4.224 183.424-4.309 12.843-8.533 25.643-4.309 34.176z" />
+<glyph unicode="&#xe929;" glyph-name="Q_f" d="M560.006 694.979c68.267-25.6 115.2-89.6 119.467-166.4 0-110.933-140.8-162.133-157.867-166.4-4.267-4.267-8.576-4.267-12.8-4.267-17.109 0-34.133 12.8-38.443 29.867-8.491 25.6 4.309 46.933 25.643 55.467 25.6 12.8 98.133 46.933 98.133 89.6 0 38.4-21.333 68.267-55.467 81.067-46.976 17.067-93.867-8.533-110.976-51.2-8.491-21.333-34.091-34.133-55.424-25.6-25.6 4.267-34.133 29.867-29.909 55.467 29.909 85.376 128 132.267 217.643 102.4zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333 0-260.309 209.067-469.333 469.333-469.333s469.333 209.024 469.333 469.333c0 260.267-209.067 469.333-469.333 469.333zM482.133 264.565c17.067 17.024 42.667 17.024 59.733 0 8.576-8.533 12.8-21.333 12.8-29.867s-4.224-21.333-12.8-29.867c-8.533-8.576-17.067-12.8-29.867-12.8s-21.333 4.224-29.867 12.8c-8.533 8.533-12.8 17.067-12.8 29.867s4.267 21.333 12.8 29.867z" />
+<glyph unicode="&#xe92a;" glyph-name="Q_o" d="M560.006 694.979c-89.643 29.867-187.733-17.024-217.643-102.4-4.224-25.6 4.309-51.2 29.909-55.467 21.333-8.533 46.933 4.267 55.424 25.6 17.109 42.667 64 68.267 110.976 51.2 34.133-12.8 55.467-42.667 55.467-81.067 0-42.667-72.533-76.8-98.133-89.6-21.333-8.533-34.133-29.867-25.643-55.467 4.309-17.067 21.333-29.867 38.443-29.867 4.224 0 8.533 0 12.8 4.267 17.067 4.267 157.867 55.467 157.867 166.4-4.267 76.8-51.2 140.8-119.467 166.4zM512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333 0-260.309 209.067-469.333 469.333-469.333s469.333 209.024 469.333 469.333c0 260.267-209.067 469.333-469.333 469.333zM482.133 264.565c-8.533-8.533-12.8-17.067-12.8-29.867s4.267-21.333 12.8-29.867c8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.576 8.533 12.8 21.333 12.8 29.867s-4.224 21.333-12.8 29.867c-17.067 17.024-42.667 17.024-59.733 0z" />
+<glyph unicode="&#xe92c;" glyph-name="revert" d="M597.333 422.4l115.2-115.2c17.067-17.067 17.067-42.667 0-59.733-8.533-8.533-21.333-12.8-29.867-12.8s-21.333 4.267-29.867 12.8l-128 128c-8.533 8.533-12.8 17.067-12.8 29.867v256c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-238.933zM955.895 588.856c81.024-221.867-38.4-465.067-260.309-541.867-46.891-17.067-93.867-25.6-140.757-25.6-174.933 0-341.333 110.933-405.333 285.867-8.576 21.333 4.224 46.933 25.557 55.467s46.976-4.267 55.509-25.6c64-179.2 256-273.067 435.157-209.067 89.643 29.867 157.867 93.867 196.309 174.933 38.357 81.067 42.667 174.933 12.8 260.267-29.909 89.6-93.909 157.867-174.933 196.267-81.067 38.4-174.976 42.667-260.309 12.8-46.891-17.067-93.867-46.933-128-81.067l-119.424-115.2h149.333c25.557 0 34.091-8.533 34.091-34.133s-17.024-42.667-42.667-42.667h-268.757l-4.267 4.267c-4.309 0-4.309 0-8.533 4.267-4.309 0-4.309 4.267-4.309 4.267 0 4.267-4.224 4.267-4.224 8.533v268.8c0 25.6 17.067 42.667 42.667 42.667 25.557 0 42.667-17.067 42.667-42.667v-157.867l128 119.467c42.667 42.667 98.091 76.8 157.867 98.133 106.667 38.4 221.867 34.133 324.224-17.067 102.443-51.2 179.243-136.533 217.643-243.2z" />
+<glyph unicode="&#xe92d;" glyph-name="save" d="M853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-42.667v298.667c0 25.6-17.067 42.667-42.667 42.667h-426.667c-25.6 0-42.667-17.067-42.667-42.667v-298.667h-42.667c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h42.667v-170.667c0-25.6 17.067-42.667 42.667-42.667h341.333c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667h-298.667v128h324.267l187.733-187.733v-452.267zM341.333 106.667v256h341.333v-256h-341.333zM925.867 648.533l-213.333 213.333c-8.533 8.533-17.067 12.8-29.867 12.8h-469.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v469.333c0 12.8-4.267 21.333-12.8 29.867z" />
+<glyph unicode="&#xe92e;" glyph-name="search" d="M170.667 512c0 153.6 123.733 277.333 277.333 277.333s277.333-123.733 277.333-277.333c0-76.8-29.867-145.067-81.067-196.267s-119.467-81.067-196.267-81.067c-153.6 0-277.333 123.733-277.333 277.333zM925.867 93.867l-192 192c46.933 59.733 76.8 140.8 76.8 226.133 0 200.533-162.133 362.667-362.667 362.667s-362.667-162.133-362.667-362.667c0-200.533 162.133-362.667 362.667-362.667 85.333 0 162.133 29.867 226.133 76.8l192-192c8.533-8.533 21.333-12.8 29.867-12.8s21.333 4.267 29.867 12.8c17.067 17.067 17.067 42.667 0 59.733z" />
+<glyph unicode="&#xe92f;" glyph-name="setting" d="M512 362.658c-46.933 0-85.333 38.4-85.333 85.333 0 46.976 38.4 85.333 85.333 85.333s85.333-38.357 85.333-85.333c0-46.933-38.4-85.333-85.333-85.333zM512 618.658c-93.867 0-170.667-76.8-170.667-170.667s76.8-170.667 170.667-170.667c93.867 0 170.667 76.8 170.667 170.667s-76.8 170.667-170.667 170.667zM814.916 209.075c8.533-8.533 12.843-17.067 12.843-29.867s-4.309-21.333-12.843-29.867c-8.491-8.576-17.024-12.8-29.824-12.8-12.843 0-21.333 4.224-34.176 17.067-34.133 34.133-81.024 42.667-123.691 21.333-42.667-17.067-68.309-59.733-68.309-102.4v-8.533c0-25.6-17.024-42.667-42.667-42.667-25.6 0-42.667 17.067-42.667 42.667v4.267c0 46.933-29.824 85.333-72.491 102.4-12.843 8.533-29.867 8.533-46.976 8.533-29.867 0-59.691-12.8-81.024-34.133-17.109-17.067-38.443-17.067-55.509-4.309l-8.491 17.109h-4.309c-4.224 4.224-4.224 12.8-4.224 17.067 0 12.8 4.224 21.333 17.024 34.133 34.176 34.133 42.667 81.024 21.333 123.691-17.024 42.667-59.691 68.309-102.357 68.309h-8.576c-25.557 0-42.667 17.024-42.667 42.667 0 25.6 17.109 42.667 42.667 42.667h4.267c46.976 0 85.333 29.867 102.4 72.533 17.109 42.667 8.576 89.6-25.557 128-17.109 17.067-17.109 42.667 0 59.733 17.024 17.067 42.667 17.067 64-4.267 29.824-29.867 76.8-38.4 115.157-25.643l12.843 4.309c42.667 17.024 68.224 59.691 68.224 102.357v8.576c0 25.6 17.109 42.667 42.667 42.667 25.6 0 42.667-17.067 42.667-46.933 0-46.976 25.6-85.333 68.267-102.4s89.643-8.576 128 25.6c8.533 8.491 17.067 12.8 29.867 12.8s21.333-4.309 29.867-12.8c17.109-17.067 17.109-42.667-4.224-64-29.867-29.867-38.443-76.843-25.643-115.2l4.309-12.8c17.024-42.667 59.691-68.267 102.357-68.267h8.533c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-46.891-42.667c-46.976 0-85.333-25.6-102.443-68.267-21.333-42.667-8.533-89.643 25.6-128zM866.116 302.942c4.309 8.491 12.8 17.067 29.867 17.067 72.576 0 128 55.424 128 128 0 72.533-55.424 128-128 128h-8.533c-8.533 0-17.024 4.267-21.333 12.757l-4.224 8.576c-4.309 8.533-4.309 21.333 8.533 34.091 46.891 46.976 51.157 115.243 12.8 166.443v12.8l-17.109 8.533c-21.333 21.333-51.2 34.133-85.333 34.133s-68.224-12.8-93.867-38.4c-8.491-8.533-21.333-8.533-29.824-4.267-8.533-4.267-17.109 8.533-17.109 21.333 0 72.533-55.424 128-128 128-72.533 0-128-55.467-128-128v-8.576c0-8.491-4.224-17.024-12.757-21.333l-8.576-4.224c-8.533-4.267-21.333 0-34.091 8.533-51.243 51.2-132.309 51.2-179.243 0-51.2-51.2-51.2-132.309 4.267-183.467 8.533-8.533 8.533-21.333 4.309-34.176-4.309-8.491-17.109-17.024-29.909-17.024-72.533 0-128-55.467-128-128s55.467-128 128-128h8.576c12.757 0 21.333-8.533 25.557-17.067 4.309-8.576 4.309-21.333-8.533-34.133-25.6-25.6-38.357-55.467-38.357-89.6 0-29.867 12.757-59.733 34.091-85.333l4.267-4.267 12.843-12.8c51.157-38.443 119.467-34.133 170.667 12.8 8.491 8.533 21.333 8.533 34.133 4.267 12.757-4.267 17.024-12.843 17.024-29.867 0-72.533 55.509-128 128-128 72.533 0 128 55.467 128 128v8.533c0 12.8 8.533 21.333 17.067 25.6 8.576 4.224 21.333 4.224 34.133-8.533 51.2-51.243 132.309-51.243 179.2 0 51.243 51.2 51.243 132.267-4.224 183.424-4.309 12.843-8.533 25.643-4.309 34.176z" />
+<glyph unicode="&#xe930;" glyph-name="sub" d="M213.333 490.667h597.333c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667h-597.333c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667z" />
+<glyph unicode="&#xe931;" glyph-name="sub_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333zM682.667 490.667h-341.333c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h341.333c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667z" />
+<glyph unicode="&#xe932;" glyph-name="success" d="M815.403 732.877l-360.277-515.925-203.861 197.589c-18.987 18.347-47.445 18.347-66.389 0-18.944-18.389-18.944-45.952 0-64.341l237.056-229.76c9.472-9.173 18.944-13.781 33.195-13.781 14.208 0 23.723 4.608 33.152 13.781l393.515 548.139c18.944 18.347 18.944 45.909 0 64.299s-47.403 18.389-66.389 0z" />
+<glyph unicode="&#xe933;" glyph-name="success_f" d="M757.461 590.549l-298.667-341.333c-7.808-8.875-18.901-14.165-30.72-14.549-0.427 0-0.939 0-1.408 0-11.307 0-22.144 4.48-30.165 12.501l-170.667 170.667c-16.683 16.64-16.683 43.648 0 60.331 16.683 16.64 43.648 16.64 60.331 0l138.411-138.411 268.629 306.987c15.531 17.792 42.539 19.541 60.203 4.011 17.749-15.531 19.541-42.453 4.053-60.203zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333z" />
+<glyph unicode="&#xe934;" glyph-name="success_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333zM693.21 646.771l-268.629-307.029-138.411 138.411c-16.683 16.683-43.648 16.683-60.331 0-16.683-16.64-16.683-43.648 0-60.331l170.667-170.667c7.979-8.021 18.859-12.501 30.165-12.501 0.469 0 0.939 0 1.408 0.043 11.819 0.384 22.912 5.675 30.72 14.549l298.667 341.333c15.488 17.749 13.696 44.672-4.053 60.203-17.664 15.531-44.672 13.781-60.203-4.011z" />
+<glyph unicode="&#xe936;" glyph-name="sync" d="M878.933 358.4c21.333-4.267 34.176-29.867 29.867-55.467-21.333-59.733-59.691-115.2-102.357-157.867-81.109-81.067-187.776-123.733-302.976-123.733s-221.867 42.667-294.357 123.733l-123.776 119.467v-157.867c0-25.6-17.067-42.667-42.667-42.667-25.557 0-42.667 17.067-42.667 42.667v268.8c0 4.267 4.267 4.267 4.267 8.533 4.309 0 4.309 4.267 4.309 4.267 0 4.267 4.224 8.533 8.533 8.533 0 4.267 4.224 4.267 4.224 4.267h4.267c0 4.267 4.309 4.267 8.533 4.267h256c25.643 0 42.667-17.067 42.667-42.667s-17.024-42.667-42.667-42.667h-149.333l119.467-110.933c68.309-68.267 153.643-102.4 243.2-102.4 89.643 0 179.2 34.133 238.976 98.133 38.357 34.133 64 81.067 81.024 128 8.533 21.333 34.133 34.133 55.467 25.6zM958.406 831.276c25.6 0 42.667-17.067 42.667-42.667v-260.267c0-4.267 0-8.533-4.267-12.8 0-4.267-4.267-4.267-4.267-8.533-4.267 0-4.267-4.267-4.267-4.267-4.267-4.267-8.533-4.267-12.8-8.533s-12.8-4.267-17.067-4.267h-256c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h149.333l-119.467 115.2c-34.133 38.4-81.067 64-128 81.067-85.333 29.867-179.2 25.6-260.267-12.8-81.067-42.667-145.067-110.933-174.933-196.267-8.533-21.333-34.133-34.133-55.467-25.6-21.333 4.267-34.133 29.867-25.6 51.2 38.4 110.933 115.2 196.267 217.6 243.2 102.4 51.2 217.6 55.467 328.533 21.333 59.733-21.333 115.2-59.733 157.867-102.4l123.733-119.467v157.867c0 25.6 17.067 42.667 42.667 42.667z" />
+<glyph unicode="&#xe937;" glyph-name="trash" d="M768 106.667c0-25.6-17.067-42.667-42.667-42.667h-426.667c-25.6 0-42.667 17.067-42.667 42.667v554.667h512v-554.667zM384 789.333c0 25.6 17.067 42.667 42.667 42.667h170.667c25.6 0 42.667-17.067 42.667-42.667v-42.667h-256v42.667zM896 746.667h-170.667v42.667c0 72.533-55.467 128-128 128h-170.667c-72.533 0-128-55.467-128-128v-42.667h-170.667c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h42.667v-554.667c0-72.533 55.467-128 128-128h426.667c72.533 0 128 55.467 128 128v554.667h42.667c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667zM426.667 191.996c25.6 0 42.667 17.067 42.667 42.667v256c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-256c0-25.6 17.067-42.667 42.667-42.667zM597.333 191.996c25.6 0 42.667 17.067 42.667 42.667v256c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-256c0-25.6 17.067-42.667 42.667-42.667z" />
+<glyph unicode="&#xe938;" glyph-name="undo" d="M955.733 588.856c-38.4 106.667-115.2 192-217.643 243.2-102.357 51.2-217.557 55.467-324.224 17.067-59.776-21.333-115.2-55.467-157.867-98.133l-128-119.467v157.867c0 25.6-17.109 42.667-42.667 42.667-25.6 0-42.667-17.067-42.667-42.667v-268.8c0-4.267 4.224-4.267 4.224-8.533 0 0 0-4.267 4.309-4.267 4.224-4.267 4.224-4.267 8.533-4.267l4.267-4.267h268.757c25.643 0 42.667 17.067 42.667 42.667s-8.533 34.133-34.091 34.133h-149.333l119.424 115.2c34.133 34.133 81.109 64 128 81.067 85.333 29.867 179.243 25.6 260.309-12.8 81.024-38.4 145.024-106.667 174.933-196.267 29.867-85.333 25.557-179.2-12.8-260.267-38.443-81.067-106.667-145.067-196.309-174.933-179.157-64-371.157 29.867-435.157 209.067-8.533 21.333-34.176 34.133-55.509 25.6s-34.133-34.133-25.557-55.467c64-174.933 230.4-285.867 405.333-285.867 46.891 0 93.867 8.533 140.757 25.6 221.909 76.8 341.333 320 260.309 541.867z" />
+<glyph unicode="&#xe939;" glyph-name="unlocked" d="M853.333 106.671c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v298.667c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-298.667zM810.667 533.338h-469.333v128c0 46.933 17.067 89.6 51.2 119.467 29.867 34.133 72.533 51.2 119.467 51.2 81.067 0 149.333-55.467 166.4-136.533 4.267-21.333 29.867-38.4 51.2-34.133s38.4 25.6 34.133 51.2c-25.6 119.467-132.267 204.8-251.733 204.8-68.267 0-132.267-25.6-179.2-76.8-51.2-46.933-76.8-110.933-76.8-179.2v-128h-42.667c-72.533 0-128-55.467-128-128v-298.667c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v298.667c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe93a;" glyph-name="upload" d="M896 277.333c25.6 0 42.667-17.067 42.667-42.667v-128c0-72.533-55.467-128-128-128h-597.333c-72.533 0-128 55.467-128 128v128c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-128c0-25.6 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.067 42.667 42.667v128c0 25.6 17.067 42.667 42.667 42.667zM371.2 675.189c-17.067-17.024-42.667-17.024-59.733 0-17.067 17.067-17.067 42.667 0 59.733l170.667 170.667c4.267 4.267 8.533 4.267 12.757 8.576 12.843 4.224 25.643 4.224 34.176 0 4.267 0 8.491-4.309 12.8-8.576l170.667-170.667c17.024-17.067 17.024-42.667 0-59.733-8.533-8.533-17.067-12.8-29.867-12.8s-21.333 4.267-29.867 12.8l-98.133 98.133v-494.933c0-25.557-17.109-42.667-42.667-42.667-25.6 0-42.667 17.109-42.667 42.667v494.933l-98.133-98.133z" />
+<glyph unicode="&#xe93b;" glyph-name="view" d="M510.933 149.333c-230.4 0-379.733 230.4-422.4 298.667 38.4 68.267 192 298.667 422.4 298.667s379.733-230.4 422.4-298.667c-42.667-68.267-192-298.667-422.4-298.667zM1018.667 465.067c-8.533 17.067-187.733 366.933-507.733 366.933s-499.2-349.867-507.733-366.933c-4.267-12.8-4.267-25.6 0-38.4 8.533-12.8 187.733-362.667 507.733-362.667s499.2 349.867 507.733 366.933c4.267 8.533 4.267 25.6 0 34.133zM512 362.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM512 618.667c-93.867 0-170.667-76.8-170.667-170.667s76.8-170.667 170.667-170.667c93.867 0 170.667 76.8 170.667 170.667s-76.8 170.667-170.667 170.667z" />
+<glyph unicode="&#xe93c;" glyph-name="X_f" d="M512 917.333c260.267 0 469.333-209.067 469.333-469.333s-209.067-469.333-469.333-469.333c-260.267 0-469.333 209.067-469.333 469.333s209.067 469.333 469.333 469.333zM651.055 605.894c-17.067 17.024-42.667 17.024-59.733 0l-98.133-98.133-98.133 98.133c-17.067 17.024-42.667 17.024-59.733 0-17.067-17.067-17.067-42.667 0-59.733l98.091-98.133-98.091-98.133c-17.067-17.067-17.067-42.667 0-59.733 8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8l98.133 98.091 98.133-98.091c8.533-8.576 21.333-12.8 29.867-12.8s21.333 4.224 29.867 12.8c17.024 17.067 17.024 42.667 0 59.733l-98.133 98.133 98.133 98.133c17.024 17.067 17.024 42.667 0 59.733z" />
+<glyph unicode="&#xe93d;" glyph-name="X_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333zM651.055 605.894c-17.067 17.024-42.667 17.024-59.733 0l-98.133-98.133-98.133 98.133c-17.067 17.024-42.667 17.024-59.733 0-17.067-17.067-17.067-42.667 0-59.733l98.091-98.133-98.091-98.133c-17.067-17.067-17.067-42.667 0-59.733 8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8l98.133 98.091 98.133-98.091c8.533-8.576 21.333-12.8 29.867-12.8s21.333 4.224 29.867 12.8c17.024 17.067 17.024 42.667 0 59.733l-98.133 98.133 98.133 98.133c17.024 17.067 17.024 42.667 0 59.733z" />
+</font></defs></svg> \ No newline at end of file
diff --git a/vid-webpack-master/src/assets/fonts/icomoon.ttf b/vid-webpack-master/src/assets/fonts/icomoon.ttf
new file mode 100644
index 000000000..4d82ec095
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/icomoon.ttf
Binary files differ
diff --git a/vid-webpack-master/src/assets/fonts/icomoon.woff b/vid-webpack-master/src/assets/fonts/icomoon.woff
new file mode 100644
index 000000000..451aaa8d0
--- /dev/null
+++ b/vid-webpack-master/src/assets/fonts/icomoon.woff
Binary files differ
diff --git a/vid-webpack-master/src/assets/img/Menu.svg b/vid-webpack-master/src/assets/img/Menu.svg
new file mode 100644
index 000000000..5b037bbea
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/Menu.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
+ <defs>
+ <path id="menu-a" d="M6.55555556,13.1111111 C5.69644594,13.1111111 5,12.4146652 5,11.5555556 C5,10.6964459 5.69644594,10 6.55555556,10 C7.41466517,10 8.11111111,10.6964459 8.11111111,11.5555556 C8.11111111,12.4146652 7.41466517,13.1111111 6.55555556,13.1111111 Z M17.4444444,13.1111111 C16.5853348,13.1111111 15.8888889,12.4146652 15.8888889,11.5555556 C15.8888889,10.6964459 16.5853348,10 17.4444444,10 C18.3035541,10 19,10.6964459 19,11.5555556 C19,12.4146652 18.3035541,13.1111111 17.4444444,13.1111111 Z M12,13.1111111 C11.1408904,13.1111111 10.4444444,12.4146652 10.4444444,11.5555556 C10.4444444,10.6964459 11.1408904,10 12,10 C12.8591096,10 13.5555556,10.6964459 13.5555556,11.5555556 C13.5555556,12.4146652 12.8591096,13.1111111 12,13.1111111 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use fill="#000" transform="rotate(90 12 11.556)" xlink:href="#menu-a"/>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/assets/img/UPLOAD.svg b/vid-webpack-master/src/assets/img/UPLOAD.svg
new file mode 100644
index 000000000..85ff7e308
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/UPLOAD.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="121px" height="121px" viewBox="0 0 121 121" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
+ <title>Combined Shape</title>
+ <desc>Created with Sketch.</desc>
+ <defs>
+ <linearGradient x1="78.7695312%" y1="73.9666898%" x2="20.3450521%" y2="7.42778616%" id="linearGradient-1">
+ <stop stop-color="#8C1DF3" offset="0%"></stop>
+ <stop stop-color="#E77DE8" offset="100%"></stop>
+ </linearGradient>
+ </defs>
+ <g id="VID_Deployment_5" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(-1065.000000, -322.000000)">
+ <path d="M1125.5,443 C1092.08677,443 1065,415.913227 1065,382.5 C1065,349.086773 1092.08677,322 1125.5,322 C1158.91323,322 1186,349.086773 1186,382.5 C1186,415.913227 1158.91323,443 1125.5,443 Z M1125.5,439 C1156.70409,439 1182,413.704088 1182,382.5 C1182,351.295912 1156.70409,326 1125.5,326 C1094.29591,326 1069,351.295912 1069,382.5 C1069,413.704088 1094.29591,439 1125.5,439 Z M1131.83333,355 C1142.33333,355 1150.88889,363.576271 1150.88889,374.101695 C1156.72222,375.738983 1161,381.040678 1161,387.355932 C1161,394.918644 1154.93333,401 1147.38889,401 L1147,401 L1138.75556,401 L1131.75556,401 C1127.71111,401 1124.36667,397.647458 1124.36667,393.59322 L1124.36667,391.644068 L1124.36667,387.433898 L1124.36667,381.274576 L1119.62222,386.732203 C1118.92222,387.511864 1117.67778,387.589831 1116.9,386.888136 C1116.12222,386.186441 1116.04444,384.938983 1116.74444,384.159322 L1124.44444,375.271186 L1124.91111,374.725424 C1125.68889,373.867797 1127.08889,373.867797 1127.86667,374.725424 L1128.33333,375.349153 L1135.95556,384.081356 C1136.65556,384.861017 1136.57778,386.108475 1135.8,386.810169 C1135.02222,387.511864 1133.77778,387.433898 1133.07778,386.654237 L1128.33333,381.19661 L1128.33333,387.355932 L1128.33333,391.644068 L1128.33333,393.59322 C1128.33333,395.542373 1129.88889,397.101695 1131.83333,397.101695 L1133.77778,397.101695 L1147,397.101695 L1147.38889,397.101695 C1152.75556,397.101695 1157.11111,392.735593 1157.11111,387.355932 C1157.11111,382.911864 1154.15556,379.013559 1149.87778,377.844068 C1148.16667,377.376271 1147,375.816949 1147,374.101695 C1147,365.681356 1140.23333,358.898305 1131.83333,358.976271 C1126.93333,358.976271 1122.34444,361.315254 1119.54444,365.213559 C1118.45556,366.694915 1116.51111,367.240678 1114.8,366.461017 C1114.02222,366.071186 1113.24444,365.915254 1112.38889,365.915254 C1109.2,365.915254 1106.55556,368.566102 1106.55556,371.762712 C1106.55556,372.152542 1106.63333,372.620339 1106.71111,373.010169 C1107.17778,375.271186 1105.62222,377.376271 1103.36667,377.688136 C1098.54444,378.311864 1094.88889,382.444068 1094.88889,387.355932 C1094.88889,392.735593 1099.24444,397.101695 1104.61111,397.101695 L1105,397.101695 L1117.05556,397.101695 C1118.14444,397.101695 1119,397.959322 1119,399.050847 C1119,400.142373 1118.14444,401 1117.05556,401 L1104.61111,401 C1097.06667,401 1091,394.918644 1091,387.355932 C1091,381.19661 1095.04444,376.050847 1100.64444,374.257627 L1102.9,373.789831 L1102.66667,372.152542 L1102.66667,371.762712 C1102.66667,366.383051 1107.02222,362.016949 1112.38889,362.016949 C1113.86667,362.016949 1115.18889,362.328814 1116.43333,362.874576 C1119.85556,358.118644 1125.45556,355 1131.83333,355 Z" id="Combined-Shape" fill="url(#linearGradient-1)" fill-rule="nonzero"></path>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/assets/img/X_o.svg b/vid-webpack-master/src/assets/img/X_o.svg
new file mode 100644
index 000000000..a323c190e
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/X_o.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
+ <defs>
+ <path id="x_o-a" d="M12,21 C7,21 3,17 3,12 C3,7 7,3 12,3 C17,3 21,7 21,12 C21,17 17,21 12,21 M12,1 C5.9,1 1,5.9 1,12 C1,18.1 5.9,23 12,23 C18.1,23 23,18.1 23,12 C23,5.9 18.1,1 12,1 M15.2591,8.29935 C14.8591,7.90035 14.2591,7.90035 13.8591,8.29935 L11.5591,10.59935 L9.2591,8.29935 C8.8591,7.90035 8.2591,7.90035 7.8591,8.29935 C7.4591,8.69935 7.4591,9.29935 7.8591,9.69935 L10.1581,11.99935 L7.8591,14.29935 C7.4591,14.69935 7.4591,15.29935 7.8591,15.69935 C8.0591,15.90035 8.2591,15.99935 8.5591,15.99935 C8.8591,15.99935 9.0591,15.90035 9.2591,15.69935 L11.5591,13.40035 L13.8591,15.69935 C14.0591,15.90035 14.3591,15.99935 14.5591,15.99935 C14.7591,15.99935 15.0591,15.90035 15.2591,15.69935 C15.6581,15.29935 15.6581,14.69935 15.2591,14.29935 L12.9591,11.99935 L15.2591,9.69935 C15.6581,9.29935 15.6581,8.69935 15.2591,8.29935"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use fill="#000" xlink:href="#x_o-a"/>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/assets/img/angular.png b/vid-webpack-master/src/assets/img/angular.png
new file mode 100644
index 000000000..a1d9790bc
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/angular.png
Binary files differ
diff --git a/vid-webpack-master/src/assets/img/chevron.svg b/vid-webpack-master/src/assets/img/chevron.svg
new file mode 100644
index 000000000..5718cb00e
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/chevron.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
+ <defs>
+ <path id="chevron-a" d="M11.2998,15.7002 C11.4998,15.9002 11.7998,16.0002 11.9998,16.0002 C12.1998,16.0002 12.4998,15.9002 12.6998,15.7002 L17.6998,10.7002 C18.0998,10.3002 18.0998,9.7002 17.6998,9.3002 C17.2998,8.9002 16.6998,8.9002 16.2998,9.3002 L11.9998,13.6002 L7.6998,9.3002 C7.2998,8.9002 6.6998,8.9002 6.2998,9.3002 C5.8998,9.7002 5.8998,10.3002 6.2998,10.7002 L11.2998,15.7002 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use fill="#000" xlink:href="#chevron-a"/>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/assets/img/fail.svg b/vid-webpack-master/src/assets/img/fail.svg
new file mode 100644
index 000000000..87c1baa74
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/fail.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
+ <defs>
+ <path id="fail-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use fill="#000" xlink:href="#fail-a"/>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/assets/img/favicon.ico b/vid-webpack-master/src/assets/img/favicon.ico
new file mode 100644
index 000000000..8081c7cea
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/favicon.ico
Binary files differ
diff --git a/vid-webpack-master/src/assets/img/inprogress.svg b/vid-webpack-master/src/assets/img/inprogress.svg
new file mode 100644
index 000000000..b893c621f
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/inprogress.svg
@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
+ <defs>
+ <path id="inprogress-a" d="M14.8892528,0.000671665369 C14.6521255,0.0231479869 14.4508328,0.188370906 14.3774086,0.420798226 L13.9586266,1.71936929 C13.8342077,1.78596816 13.7105976,1.8521637 13.5956824,1.92943257 L12.2834996,1.66207763 C12.0324878,1.61103505 11.7777494,1.73018631 11.6506739,1.95807534 L10.7572728,3.54309549 C10.6298181,3.76875487 10.6559818,4.05253533 10.8224168,4.24967115 L11.6785927,5.25224451 C11.6738947,5.33490337 11.6692867,5.41630641 11.6692867,5.50050222 C11.6692867,5.58469803 11.6738947,5.66610107 11.6785927,5.74875688 L10.8224168,6.75133024 C10.6559818,6.94846606 10.6298181,7.23224652 10.7572728,7.45790589 L11.6506739,9.04292605 C11.7777485,9.27081625 12.0324871,9.38996883 12.2834996,9.33892681 L13.5956824,9.07157188 C13.7105976,9.14883769 13.8342077,9.21503628 13.9586266,9.28163516 L14.3774086,10.5802001 C14.4580219,10.831579 14.687164,11.0011661 14.9450903,11.0003389 L16.7318925,11.0003389 C16.9898188,11.0011662 17.2189611,10.8315791 17.2995745,10.5802001 L17.7183562,9.28163516 C17.8427751,9.21503628 17.9663852,9.14883769 18.0813004,9.07157188 L19.3934831,9.33892681 C19.6444956,9.38996883 19.8992343,9.27081625 20.0263089,9.04292605 L20.91971,7.45790589 C21.0471647,7.23224659 21.0210012,6.94846612 20.8545662,6.75133024 L19.9983903,5.74875688 C20.0030883,5.66610107 20.0076963,5.58469803 20.0076963,5.50050222 C20.0076963,5.41630641 20.0030883,5.33490337 19.9983903,5.25224451 L20.8545662,4.24967115 C21.0210012,4.05253526 21.0471647,3.7687548 20.91971,3.54309549 L20.0263089,1.95807534 C19.8992334,1.73018631 19.644495,1.61103505 19.3934831,1.66207763 L18.0813004,1.92943257 C17.9663852,1.8521637 17.8427751,1.78596816 17.7183562,1.71936929 L17.2995745,0.420798226 C17.2189569,0.16942403 16.9898156,-0.000157392525 16.7318925,0.000671665369 L14.9450903,0.000671665369 C14.926488,-0.000223888456 14.9078551,-0.000223888456 14.8892528,0.000671665369 Z M15.3731785,1.22285691 L16.3038045,1.22285691 L16.6574424,2.31136469 C16.7113318,2.47938794 16.8335313,2.61521378 16.9924677,2.68374821 C17.2120208,2.77902652 17.42616,2.91137176 17.6252935,3.06568034 C17.7626503,3.1743391 17.939345,3.21617551 18.1092192,3.18026058 L19.2166641,2.95110009 L19.6819773,3.77225599 L18.9374763,4.64115188 C18.8235917,4.77112577 18.7693918,4.9449068 18.7885762,5.1185701 C18.8040892,5.24530229 18.8164942,5.36935475 18.8164942,5.50050222 C18.8164942,5.63164969 18.8040862,5.7556991 18.7885762,5.88243435 C18.7693927,6.05609662 18.8235925,6.22987636 18.9374763,6.3598495 L19.6819773,7.22874845 L19.2166641,8.0499013 L18.1092192,7.82074386 C17.939345,7.78482893 17.7626503,7.82666535 17.6252935,7.93532411 C17.42616,8.08963268 17.2120208,8.22197792 16.9924677,8.31725623 C16.8335313,8.38579066 16.7113318,8.52161651 16.6574424,8.68963975 L16.3038045,9.77814753 L15.3731785,9.77814753 L15.0195403,8.68963975 C14.965651,8.52161651 14.8434514,8.38579066 14.684515,8.31725623 C14.464962,8.22197792 14.2508231,8.08963268 14.0516892,7.93532411 C13.9143325,7.82666543 13.737638,7.78482902 13.5677638,7.82074386 L12.4603186,8.0499013 L11.9950055,7.22874845 L12.7395065,6.3598495 C12.8533903,6.22987636 12.9075901,6.05609662 12.8884066,5.88243435 C12.8728936,5.7556991 12.8604886,5.63164969 12.8604886,5.50050222 C12.8604886,5.36935475 12.8728936,5.24530229 12.8884066,5.1185701 C12.907591,4.9449068 12.8533911,4.77112577 12.7395065,4.64115188 L11.9950055,3.77225599 L12.4603186,2.95110009 L13.5677638,3.18026058 C13.737638,3.21617542 13.9143325,3.17433901 14.0516892,3.06568034 C14.2508231,2.91137176 14.464962,2.77902652 14.684515,2.68374821 C14.8434514,2.61521378 14.965651,2.47938794 15.0195403,2.31136469 L15.3731785,1.22285691 Z M15.8384914,3.66722435 C14.8516677,3.66722435 14.0516892,4.48801053 14.0516892,5.50050222 C14.0516892,6.51299391 14.8516677,7.33378009 15.8384914,7.33378009 C16.8253151,7.33378009 17.6252935,6.51299391 17.6252935,5.50050222 C17.6252935,4.48801053 16.8253151,3.66722435 15.8384914,3.66722435 Z M15.8384914,4.8894096 C16.167433,4.8894096 16.4340923,5.16300397 16.4340923,5.50050222 C16.4340923,5.83800047 16.167433,6.11159484 15.8384914,6.11159484 C15.5095497,6.11159484 15.2428908,5.83800047 15.2428908,5.50050222 C15.2428908,5.16300397 15.5095497,4.8894096 15.8384914,4.8894096 Z M5.35964143,7.94486966 C5.11761178,7.97028968 4.91497592,8.14417554 4.84779714,8.38409344 L4.39179031,10.007308 C4.08554756,10.1523124 3.79769239,10.3245113 3.52630811,10.5229085 L1.93493719,10.1123397 C1.67706155,10.0458059 1.40743723,10.1626959 1.27419282,10.3987918 L0.0829912853,12.5185218 C-0.0533731038,12.7550456 -0.0191039055,13.0558665 0.166747618,13.2537494 L1.29280541,14.4377158 C1.27376142,14.6131658 1.24627395,14.7832685 1.24627395,14.9724379 C1.24627395,15.1616073 1.27375992,15.3316489 1.29280541,15.5071294 L0.166747618,16.6911263 C-0.0191039055,16.8890093 -0.0533731038,17.1898302 0.0829912853,17.4263539 L1.27419282,19.546084 C1.40744436,19.7821705 1.67706707,19.8990499 1.93493719,19.8325117 L3.52630811,19.4219368 C3.79769239,19.6203339 4.08554756,19.792545 4.39179031,19.9375616 L4.84779714,21.560764 C4.92177045,21.8197002 5.15249473,21.99822 5.41547888,22 L7.79788196,22 C8.06086612,21.99822 8.2915904,21.8197002 8.3655637,21.560764 L8.82157054,19.9375616 C9.12781329,19.792545 9.41566816,19.6203339 9.68705274,19.4219368 L11.2784234,19.8325117 C11.5362936,19.8990501 11.8059165,19.7821706 11.939168,19.546084 L13.1303696,17.4263539 C13.2667339,17.1898302 13.2324648,16.8890093 13.0466132,16.6911263 L11.9205554,15.5071294 C11.9395994,15.3316489 11.9670869,15.1616073 11.9670869,14.9724379 C11.9670869,14.7832685 11.9396009,14.6131658 11.9205554,14.4377158 L13.0466132,13.2537494 C13.2324648,13.0558665 13.2667339,12.7550456 13.1303696,12.5185218 L11.939168,10.3987918 C11.8059236,10.1626958 11.5362991,10.0458057 11.2784234,10.1123397 L9.68705274,10.5229085 C9.41566816,10.3245113 9.12781329,10.1523124 8.82157054,10.007308 L8.3655637,8.38409344 C8.29158606,8.12516208 8.06086282,7.94664809 7.79788196,7.94486966 L5.41547888,7.94486966 C5.39687663,7.94397411 5.37824368,7.94397411 5.35964143,7.94486966 Z M5.86217942,9.16705491 L7.35118142,9.16705491 L7.7513505,10.5802001 C7.80203034,10.7630316 7.93273801,10.9112601 8.10498841,10.9812417 C8.51151269,11.1422694 8.89628488,11.3716194 9.23104591,11.6496137 C9.37749002,11.7698658 9.5705857,11.812321 9.75219678,11.764197 L11.1388296,11.4109138 L11.8740243,12.7190273 L10.8782543,13.7789076 C10.7474487,13.9183714 10.6887629,14.1131648 10.7200479,14.3040353 C10.7555607,14.5348213 10.7758854,14.7535074 10.7758854,14.9724379 C10.7758854,15.1913378 10.7555604,15.4100239 10.7200479,15.6408099 C10.688753,15.8316904 10.7474395,16.0264975 10.8782543,16.1659681 L11.8740243,17.2258484 L11.1388296,18.533962 L9.75219678,18.1806787 C9.5705857,18.1325548 9.37749002,18.17501 9.23104591,18.295262 C8.89628488,18.5732259 8.51151269,18.8026064 8.10498841,18.9636341 C7.93274488,19.0336094 7.80203841,19.1818252 7.7513505,19.3646451 L7.35118142,20.7778086 L5.86217942,20.7778086 L5.46201035,19.3646451 C5.41132243,19.1818252 5.28061596,19.0336094 5.10837243,18.9636341 C4.70184816,18.8026064 4.31707597,18.5732259 3.98231464,18.295262 C3.83587059,18.1750101 3.64277505,18.1325549 3.46116406,18.1806787 L2.07453128,18.533962 L1.33933657,17.2258484 L2.33510657,16.1659681 C2.46592132,16.0264975 2.52460786,15.8316904 2.49331294,15.6408099 C2.45779987,15.4100239 2.43747549,15.1913378 2.43747549,14.9724379 C2.43747549,14.7535074 2.45780047,14.5348213 2.49331294,14.3040353 C2.52459797,14.1131648 2.46591214,13.9183714 2.33510657,13.7789076 L1.33933657,12.7190273 L2.07453128,11.4109138 L3.46116406,11.764197 C3.64277505,11.8123209 3.83587059,11.7698657 3.98231464,11.6496137 C4.31707597,11.3716194 4.70184816,11.1422694 5.10837243,10.9812417 C5.28062283,10.9112601 5.4113305,10.7630316 5.46201035,10.5802001 L5.86217942,9.16705491 Z M6.60668042,12.2225302 C5.13349981,12.2225302 3.92647718,13.460916 3.92647718,14.9724379 C3.92647718,16.4839292 5.13349981,17.7223455 6.60668042,17.7223455 C8.07986133,17.7223455 9.28688366,16.4839292 9.28688366,14.9724379 C9.28688366,13.460916 8.07986133,12.2225302 6.60668042,12.2225302 Z M6.60668042,13.444691 C7.43608795,13.444691 8.09568212,14.1214659 8.09568212,14.9724379 C8.09568212,15.8234099 7.43608795,16.5001542 6.60668042,16.5001542 C5.77727289,16.5001542 5.11767872,15.8234099 5.11767872,14.9724379 C5.11767872,14.1214659 5.77727289,13.444691 6.60668042,13.444691 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(1 1)">
+ <mask id="inprogress-b" fill="#fff">
+ <use xlink:href="#inprogress-a"/>
+ </mask>
+ <use fill="#959595" fill-rule="nonzero" xlink:href="#inprogress-a"/>
+ <g fill="#5A5A5A" mask="url(#inprogress-b)">
+ <rect width="35" height="35" transform="translate(-4 -2)"/>
+ </g>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/assets/img/pause.svg b/vid-webpack-master/src/assets/img/pause.svg
new file mode 100644
index 000000000..f1f9b7954
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/pause.svg
@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
+ <defs>
+ <path id="pause-a" d="M12,21 C7,21 3,17 3,12 C3,7 7,3 12,3 C17,3 21,7 21,12 C21,17 17,21 12,21 M12,1 C18.1,1 23,5.9 23,12 C23,18.101 18.1,23 12,23 C5.9,23 1,18.101 1,12 C1,5.9 5.9,1 12,1 Z M13.9580566,7.47058824 C13.4173947,7.47058824 12.9791016,7.90888135 12.9791016,8.44954331 L12.9791016,15.5504567 C12.9791016,16.0911186 13.4173947,16.5294118 13.9580566,16.5294118 C14.4987186,16.5294118 14.9370117,16.0911186 14.9370117,15.5504567 L14.9370117,8.44954331 C14.9370117,7.90888135 14.4987186,7.47058824 13.9580566,7.47058824 Z M10.0211914,7.47058824 C9.48052945,7.47058824 9.04223633,7.90888135 9.04223633,8.44954331 L9.04223633,15.5504567 C9.04223633,16.0911186 9.48052945,16.5294118 10.0211914,16.5294118 C10.5618534,16.5294118 11.0001465,16.0911186 11.0001465,15.5504567 L11.0001465,8.44954331 C11.0001465,7.90888135 10.5618534,7.47058824 10.0211914,7.47058824 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <mask id="pause-b" fill="#fff">
+ <use xlink:href="#pause-a"/>
+ </mask>
+ <use fill="#191919" xlink:href="#pause-a"/>
+ <g mask="url(#pause-b)">
+ <rect width="35" height="35" fill="#5A5A5A" transform="translate(-5 -5)"/>
+ </g>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/assets/img/pending.svg b/vid-webpack-master/src/assets/img/pending.svg
new file mode 100644
index 000000000..78c99600e
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/pending.svg
@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
+ <defs>
+ <path id="pending-a" d="M11,20 C6,20 2,16 2,11 C2,6 6,2 11,2 C16,2 20,6 20,11 C20,16 16,20 11,20 M11,0 C17.1,0 22,4.9 22,11 C22,17.1 17.1,22 11,22 C4.9,22 0,17.1 0,11 C0,4.9 4.9,0 11,0 Z M11.0488812,10.5380604 L7.75288116,6.34206037 C7.38888116,5.92506037 6.75588116,5.88406037 6.34188116,6.24806037 C5.92588116,6.61206037 5.88388116,7.24306037 6.24688116,7.65906037 L10.2468812,12.6590604 C10.4298812,12.8670604 10.6898812,12.9910604 10.9668812,13.0000604 C10.9778812,13.0010604 10.9888812,13.0010604 10.9998812,13.0010604 C11.2648812,13.0010604 11.5198812,12.8960604 11.7068812,12.7080604 L14.7068812,10.7080604 C15.0978812,10.3170604 15.0978812,9.68406037 14.7068812,9.29406037 C14.3158812,8.90306037 13.6838812,8.90306037 13.2928812,9.29406037 L11.0488812,10.5380604 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(1 1)">
+ <mask id="pending-b" fill="#fff">
+ <use xlink:href="#pending-a"/>
+ </mask>
+ <use fill="#000" xlink:href="#pending-a"/>
+ <g fill="#5A5A5A" mask="url(#pending-b)">
+ <rect width="30" height="30" transform="translate(-2 -1)"/>
+ </g>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/assets/img/stoped.svg b/vid-webpack-master/src/assets/img/stoped.svg
new file mode 100644
index 000000000..0198f1548
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/stoped.svg
@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
+ <defs>
+ <path id="stoped-a" d="M14,7 L8,7 C7.4,7 7,7.4 7,8 L7,14 C7,14.6 7.4,15 8,15 L14,15 C14.6,15 15,14.6 15,14 L15,8 C15,7.4 14.6,7 14,7 Z M11,0 C4.9,0 0,4.9 0,11 C0,17.1 4.9,22 11,22 C17.1,22 22,17.1 22,11 C22,4.9 17.1,0 11,0 Z M11,20 C6,20 2,16 2,11 C2,6 6,2 11,2 C16,2 20,6 20,11 C20,16 16,20 11,20 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(1 1)">
+ <mask id="stoped-b" fill="#fff">
+ <use xlink:href="#stoped-a"/>
+ </mask>
+ <use fill="#191919" fill-rule="nonzero" xlink:href="#stoped-a"/>
+ <g fill="#5A5A5A" mask="url(#stoped-b)">
+ <rect width="30" height="30" transform="translate(-4 -4)"/>
+ </g>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/assets/img/success+Circle.svg b/vid-webpack-master/src/assets/img/success+Circle.svg
new file mode 100644
index 000000000..72d75aedb
--- /dev/null
+++ b/vid-webpack-master/src/assets/img/success+Circle.svg
@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
+ <defs>
+ <path id="success+circle-a" d="M20.0874369,8.68675849 C20.6613636,8.68675849 21.0439815,9.06859403 21.0439815,9.64134733 L21.0439815,10.5004773 C21.0439815,16.3234692 16.3569129,21 10.5219907,21 C4.6870686,21 0,16.3234692 0,10.5004773 C0,4.67748534 4.6870686,0 10.5219907,0 C12.0524621,0 13.487279,0.381835538 14.8264415,0.954588845 C15.3047138,1.14550661 15.4960227,1.71825992 15.3047138,2.19555434 C15.1134049,2.67284877 14.5394781,2.86376653 14.0612058,2.67284877 C12.9133523,2.19555434 11.7654987,1.90917769 10.5219907,1.90917769 C5.73926768,1.90917769 1.91308923,5.72753307 1.91308923,10.5004773 C1.91308923,15.2724669 5.73926768,19.0908223 10.5219907,19.0908223 C15.3047138,19.0908223 19.1308923,15.2724669 19.1308923,10.5004773 L19.1308923,9.64134733 C19.1308923,9.06859403 19.5135101,8.68675849 20.0874369,8.68675849 Z M21.713754,1.24067912 C22.0954153,1.62251466 22.0954153,2.19526797 21.713754,2.5771035 L11.1917633,13.0775808 C11.0004544,13.2684986 10.713491,13.3639575 10.5221821,13.3639575 C10.3308731,13.3639575 10.0439097,13.2684986 9.85260082,13.0775808 L6.98296698,10.2138143 C6.60034914,9.83197873 6.60034914,9.25922542 6.98296698,8.87738988 C7.36558483,8.49555434 7.9395116,8.49555434 8.32212944,8.87738988 L10.5221821,11.0729442 L20.3745916,1.24067912 C20.7572094,0.858843584 21.3311362,0.858843584 21.713754,1.24067912 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(1 1)">
+ <mask id="success+circle-b" fill="#fff">
+ <use xlink:href="#success+circle-a"/>
+ </mask>
+ <use fill="#000" xlink:href="#success+circle-a"/>
+ <g fill="#5A5A5A" mask="url(#success+circle-b)">
+ <rect width="29" height="29"/>
+ </g>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/environments/environment.prod.ts b/vid-webpack-master/src/environments/environment.prod.ts
new file mode 100644
index 000000000..3612073bc
--- /dev/null
+++ b/vid-webpack-master/src/environments/environment.prod.ts
@@ -0,0 +1,3 @@
+export const environment = {
+ production: true
+};
diff --git a/vid-webpack-master/src/environments/environment.ts b/vid-webpack-master/src/environments/environment.ts
new file mode 100644
index 000000000..b7f639aec
--- /dev/null
+++ b/vid-webpack-master/src/environments/environment.ts
@@ -0,0 +1,8 @@
+// The file contents for the current environment will overwrite these during build.
+// The build system defaults to the dev environment which uses `environment.ts`, but if you do
+// `ng build --env=prod` then `environment.prod.ts` will be used instead.
+// The list of which env maps to which file can be found in `.angular-cli.json`.
+
+export const environment = {
+ production: false
+};
diff --git a/vid-webpack-master/src/index.html b/vid-webpack-master/src/index.html
new file mode 100644
index 000000000..f3c3a9170
--- /dev/null
+++ b/vid-webpack-master/src/index.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Angular 2 App | ng2-webpack</title>
+ <link rel="icon" type="image/x-icon" href="./assets/img/favicon.ico">
+ <base href="./">
+</head>
+<body>
+<vid-app>Loading..</vid-app>
+</body>
+</html>
diff --git a/vid-webpack-master/src/main.ts b/vid-webpack-master/src/main.ts
new file mode 100644
index 000000000..a9ca1caf8
--- /dev/null
+++ b/vid-webpack-master/src/main.ts
@@ -0,0 +1,11 @@
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+ enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/vid-webpack-master/src/polyfills.ts b/vid-webpack-master/src/polyfills.ts
new file mode 100644
index 000000000..6fb2c4008
--- /dev/null
+++ b/vid-webpack-master/src/polyfills.ts
@@ -0,0 +1,66 @@
+/**
+ * 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/docs/ts/latest/guide/browser-support.html
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE9, IE10 and IE11 requires all of the following polyfills. **/
+import 'core-js/es6/symbol';
+import 'core-js/es6/object';
+import 'core-js/es6/function';
+import 'core-js/es6/parse-int';
+import 'core-js/es6/parse-float';
+import 'core-js/es6/number';
+import 'core-js/es6/math';
+import 'core-js/es6/string';
+import 'core-js/es6/date';
+import 'core-js/es6/array';
+import 'core-js/es6/regexp';
+import 'core-js/es6/map';
+import 'core-js/es6/set';
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js';
+
+/** IE10 and IE11 requires the following to support `@angular/animation`. */
+//import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+
+/** Evergreen browsers require these. **/
+import 'core-js/es6/reflect';
+import 'core-js/es7/reflect';
+
+
+/** ALL Firefox browsers require the following to support `@angular/animation`. **/
+//import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+
+
+/***************************************************************************************************
+ * Zone JS is required by Angular itself.
+ */
+import 'zone.js/dist/zone'; // Included with Angular CLI.
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
+
+/**
+ * Date, currency, decimal and percent pipes.
+ * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
+ */
+//import 'intl'; // Run `npm install --save intl`.
diff --git a/vid-webpack-master/src/public/img/UPLOAD.svg b/vid-webpack-master/src/public/img/UPLOAD.svg
new file mode 100644
index 000000000..85ff7e308
--- /dev/null
+++ b/vid-webpack-master/src/public/img/UPLOAD.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="121px" height="121px" viewBox="0 0 121 121" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
+ <title>Combined Shape</title>
+ <desc>Created with Sketch.</desc>
+ <defs>
+ <linearGradient x1="78.7695312%" y1="73.9666898%" x2="20.3450521%" y2="7.42778616%" id="linearGradient-1">
+ <stop stop-color="#8C1DF3" offset="0%"></stop>
+ <stop stop-color="#E77DE8" offset="100%"></stop>
+ </linearGradient>
+ </defs>
+ <g id="VID_Deployment_5" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(-1065.000000, -322.000000)">
+ <path d="M1125.5,443 C1092.08677,443 1065,415.913227 1065,382.5 C1065,349.086773 1092.08677,322 1125.5,322 C1158.91323,322 1186,349.086773 1186,382.5 C1186,415.913227 1158.91323,443 1125.5,443 Z M1125.5,439 C1156.70409,439 1182,413.704088 1182,382.5 C1182,351.295912 1156.70409,326 1125.5,326 C1094.29591,326 1069,351.295912 1069,382.5 C1069,413.704088 1094.29591,439 1125.5,439 Z M1131.83333,355 C1142.33333,355 1150.88889,363.576271 1150.88889,374.101695 C1156.72222,375.738983 1161,381.040678 1161,387.355932 C1161,394.918644 1154.93333,401 1147.38889,401 L1147,401 L1138.75556,401 L1131.75556,401 C1127.71111,401 1124.36667,397.647458 1124.36667,393.59322 L1124.36667,391.644068 L1124.36667,387.433898 L1124.36667,381.274576 L1119.62222,386.732203 C1118.92222,387.511864 1117.67778,387.589831 1116.9,386.888136 C1116.12222,386.186441 1116.04444,384.938983 1116.74444,384.159322 L1124.44444,375.271186 L1124.91111,374.725424 C1125.68889,373.867797 1127.08889,373.867797 1127.86667,374.725424 L1128.33333,375.349153 L1135.95556,384.081356 C1136.65556,384.861017 1136.57778,386.108475 1135.8,386.810169 C1135.02222,387.511864 1133.77778,387.433898 1133.07778,386.654237 L1128.33333,381.19661 L1128.33333,387.355932 L1128.33333,391.644068 L1128.33333,393.59322 C1128.33333,395.542373 1129.88889,397.101695 1131.83333,397.101695 L1133.77778,397.101695 L1147,397.101695 L1147.38889,397.101695 C1152.75556,397.101695 1157.11111,392.735593 1157.11111,387.355932 C1157.11111,382.911864 1154.15556,379.013559 1149.87778,377.844068 C1148.16667,377.376271 1147,375.816949 1147,374.101695 C1147,365.681356 1140.23333,358.898305 1131.83333,358.976271 C1126.93333,358.976271 1122.34444,361.315254 1119.54444,365.213559 C1118.45556,366.694915 1116.51111,367.240678 1114.8,366.461017 C1114.02222,366.071186 1113.24444,365.915254 1112.38889,365.915254 C1109.2,365.915254 1106.55556,368.566102 1106.55556,371.762712 C1106.55556,372.152542 1106.63333,372.620339 1106.71111,373.010169 C1107.17778,375.271186 1105.62222,377.376271 1103.36667,377.688136 C1098.54444,378.311864 1094.88889,382.444068 1094.88889,387.355932 C1094.88889,392.735593 1099.24444,397.101695 1104.61111,397.101695 L1105,397.101695 L1117.05556,397.101695 C1118.14444,397.101695 1119,397.959322 1119,399.050847 C1119,400.142373 1118.14444,401 1117.05556,401 L1104.61111,401 C1097.06667,401 1091,394.918644 1091,387.355932 C1091,381.19661 1095.04444,376.050847 1100.64444,374.257627 L1102.9,373.789831 L1102.66667,372.152542 L1102.66667,371.762712 C1102.66667,366.383051 1107.02222,362.016949 1112.38889,362.016949 C1113.86667,362.016949 1115.18889,362.328814 1116.43333,362.874576 C1119.85556,358.118644 1125.45556,355 1131.83333,355 Z" id="Combined-Shape" fill="url(#linearGradient-1)" fill-rule="nonzero"></path>
+ </g>
+</svg>
diff --git a/vid-webpack-master/src/public/img/angular.png b/vid-webpack-master/src/public/img/angular.png
new file mode 100644
index 000000000..a1d9790bc
--- /dev/null
+++ b/vid-webpack-master/src/public/img/angular.png
Binary files differ
diff --git a/vid-webpack-master/src/public/img/favicon.ico b/vid-webpack-master/src/public/img/favicon.ico
new file mode 100644
index 000000000..8081c7cea
--- /dev/null
+++ b/vid-webpack-master/src/public/img/favicon.ico
Binary files differ
diff --git a/vid-webpack-master/src/public/img/spinner.gif b/vid-webpack-master/src/public/img/spinner.gif
new file mode 100644
index 000000000..8ed30cb63
--- /dev/null
+++ b/vid-webpack-master/src/public/img/spinner.gif
Binary files differ
diff --git a/vid-webpack-master/src/public/index.html b/vid-webpack-master/src/public/index.html
new file mode 100644
index 000000000..5a639cadf
--- /dev/null
+++ b/vid-webpack-master/src/public/index.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Angular 2 App | ng2-webpack</title>
+ <link rel="icon" type="image/x-icon" href="./img/favicon.ico">
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
+ <link data-require="font-awesome@4.6.1" data-semver="4.6.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css" />
+ <base href="./">
+</head>
+<body>
+<vid-app>Loading..</vid-app>
+</body>
+</html>
diff --git a/vid-webpack-master/src/public/service-worker.js b/vid-webpack-master/src/public/service-worker.js
new file mode 100644
index 000000000..630bdbdf8
--- /dev/null
+++ b/vid-webpack-master/src/public/service-worker.js
@@ -0,0 +1 @@
+// This file is intentionally without code. \ No newline at end of file
diff --git a/vid-webpack-master/src/style/app.scss b/vid-webpack-master/src/style/app.scss
new file mode 100644
index 000000000..dbcf7b648
--- /dev/null
+++ b/vid-webpack-master/src/style/app.scss
@@ -0,0 +1,125 @@
+// styles in src/style directory are applied to the whole page
+@import "../app/drawingBoard/drawing-board-tree/drawing-board-tree";
+@import "../app/drawingBoard/available-models-tree/available-models-tree.component";
+
+@font-face {
+ font-family: OpenSans-Bold;
+ src: url("fonts/OpenSans/OpenSans-Bold.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-BoldItlaic;
+ src: url("fonts/OpenSans/OpenSans-BoldItalic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-ExtraBold;
+ src: url("fonts/OpenSans/OpenSans-ExtraBold.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-ExtraBoldItalic;
+ src: url("fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-Italic;
+ src: url("fonts/OpenSans/OpenSans-Italic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-Light;
+ src: url("fonts/OpenSans/OpenSans-Light.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-LightItalic;
+ src: url("fonts/OpenSans/OpenSans-LightItalic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-Regular;
+ src: url("fonts/OpenSans/OpenSans-Regular.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-Semibold;
+ src: url("fonts/OpenSans/OpenSans-Semibold.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-SemiboldItalic;
+ src: url("fonts/OpenSans/OpenSans-SemiboldItalic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: 'icomoon';
+ src: url('fonts/icomoon.eot?4cilop');
+ src: url('fonts/icomoon.eot?4cilop#iefix') format('embedded-opentype'),
+ url('fonts/icomoon.ttf?4cilop') format('truetype'),
+ url('fonts/icomoon.woff?4cilop') format('woff'),
+ url('fonts/icomoon.svg?4cilop#icomoon') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+
+[class^="icon-"], [class*=" icon-"] {
+ /* use !important to prevent issues with browser extensions that change fonts */
+ font-family: 'icomoon' !important;
+ speak: none;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+
+ /* Better Font Rendering =========== */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+html {
+ min-height: 100%;
+ height: 100%;
+ body {
+ height: 100%;
+ vid-app {
+ height: 100%;
+ display: flex !important;
+ flex-direction: column;
+ main {
+ &[_ngcontent-c0] {
+ font-family: OpenSans-Regular;
+ }
+
+ display: flex !important;
+ flex-direction: column;
+ flex: 1;
+
+ }
+ }
+ }
+}
+a {
+ color: #03A9F4;
+}
+
+tooltip-content {
+ .tooltip.left .tooltip-arrow {
+ border-left-color: #171f2a;
+ }
+ .tooltip.bottom .tooltip-arrow {
+ border-bottom-color: #171f2a;
+ }
+ .tooltip-inner {
+ background-color: #171f2a;
+ text-align: left;
+ }
+}
+
+service-planning {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ border: 1px solid #d2d2d2;
+}
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/Apache License.txt b/vid-webpack-master/src/style/fonts/OpenSans/Apache License.txt
new file mode 100644
index 000000000..989e2c59e
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/Apache License.txt
@@ -0,0 +1,201 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. \ No newline at end of file
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Bold.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Bold.ttf
new file mode 100644
index 000000000..fd79d43be
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Bold.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-BoldItalic.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-BoldItalic.ttf
new file mode 100644
index 000000000..9bc800958
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-BoldItalic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-ExtraBold.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-ExtraBold.ttf
new file mode 100644
index 000000000..21f6f84a0
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-ExtraBold.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf
new file mode 100644
index 000000000..31cb68834
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Italic.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Italic.ttf
new file mode 100644
index 000000000..c90da48ff
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Italic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Light.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Light.ttf
new file mode 100644
index 000000000..0d381897d
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Light.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-LightItalic.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-LightItalic.ttf
new file mode 100644
index 000000000..68299c4bc
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-LightItalic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Regular.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Regular.ttf
new file mode 100644
index 000000000..db433349b
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Regular.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Semibold.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Semibold.ttf
new file mode 100644
index 000000000..1a7679e39
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-Semibold.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-SemiboldItalic.ttf b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-SemiboldItalic.ttf
new file mode 100644
index 000000000..59b6d16b0
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/OpenSans/OpenSans-SemiboldItalic.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/icomoon.eot b/vid-webpack-master/src/style/fonts/icomoon.eot
new file mode 100644
index 000000000..a568b91a5
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/icomoon.eot
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/icomoon.svg b/vid-webpack-master/src/style/fonts/icomoon.svg
new file mode 100644
index 000000000..44c81d7dc
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/icomoon.svg
@@ -0,0 +1,70 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>Generated by IcoMoon</metadata>
+<defs>
+<font id="icomoon" horiz-adv-x="1024">
+<font-face units-per-em="1024" ascent="960" descent="-64" />
+<missing-glyph horiz-adv-x="1024" />
+<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
+<glyph unicode="&#xe900;" glyph-name="add" d="M810.667 490.667h-256v256c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-256h-256c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h256v-256c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v256h256c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667z" />
+<glyph unicode="&#xe901;" glyph-name="add_f" d="M512 917.333c260.267 0 469.333-209.067 469.333-469.333s-209.067-469.333-469.333-469.333c-260.267 0-469.333 209.067-469.333 469.333s209.067 469.333 469.333 469.333zM682.667 490.667h-128v128c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-128h-128c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h128v-128c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v128h128c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667z" />
+<glyph unicode="&#xe902;" glyph-name="add_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333zM682.667 490.667h-128v128c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-128h-128c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h128v-128c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v128h128c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667z" />
+<glyph unicode="&#xe903;" glyph-name="alert_f" d="M997.611 209.079c12.843-17.067 17.067-42.667 21.333-64 0-34.176-12.8-64-38.4-89.6-21.333-25.6-55.424-38.4-89.6-38.4h-725.333c-21.333 0-42.667 4.267-59.733 17.067-59.733 34.091-81.067 115.2-46.933 174.933l358.4 610.133c8.533 17.024 25.6 34.133 42.667 42.667 29.867 17.024 64 21.333 98.133 12.8s64-29.867 81.067-59.776l358.4-605.824zM512 618.667c-25.6 0-42.667-17.067-42.667-42.667v-170.667c0-25.643 17.067-42.667 42.667-42.667s42.667 17.024 42.667 42.667v170.667c0 25.6-17.067 42.667-42.667 42.667zM482.133 264.533c-8.533-8.491-12.8-17.024-12.8-29.824 0-12.843 4.267-21.333 12.8-29.867 8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.533 8.533 12.8 21.333 12.8 29.867 0 8.491-4.267 21.333-12.8 29.824-17.067 17.067-42.667 17.067-59.733 0z" />
+<glyph unicode="&#xe904;" glyph-name="alert_o" d="M920.811 115.213c-8.533-8.533-21.333-12.8-29.867-12.8h-725.333c-8.533 0-12.8 0-21.333 4.267-21.333 12.8-25.6 38.4-17.067 59.733l362.667 601.6c4.267 4.224 8.533 12.8 12.8 12.8 21.333 12.757 46.933 4.267 59.733-12.8l362.709-601.6c4.224-4.267 4.224-12.843 4.224-21.333 4.267-12.843-4.224-21.333-8.533-29.867zM997.611 209.079l-358.4 605.824c-17.067 29.909-46.933 51.243-81.067 59.776s-68.267 4.224-98.133-12.8c-17.067-8.533-34.133-25.643-42.667-42.667l-358.4-610.133c-34.133-59.733-12.8-140.843 46.933-174.933 17.067-12.8 38.4-17.067 59.733-17.067h725.333c34.176 0 68.267 12.8 89.6 38.4 25.6 25.6 38.4 55.424 38.4 89.6-4.267 21.333-8.491 46.933-21.333 64zM512 618.667c-25.6 0-42.667-17.067-42.667-42.667v-170.667c0-25.643 17.067-42.667 42.667-42.667s42.667 17.024 42.667 42.667v170.667c0 25.6-17.067 42.667-42.667 42.667zM482.133 264.533c-8.533-8.491-12.8-17.024-12.8-29.824 0-12.843 4.267-21.333 12.8-29.867 8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.533 8.533 12.8 21.333 12.8 29.867 0 8.491-4.267 21.333-12.8 29.824-17.067 17.067-42.667 17.067-59.733 0z" />
+<glyph unicode="&#xe905;" glyph-name="API" d="M853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 874.667h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128zM798.165 478.165l-170.667 170.667c-16.683 16.683-43.648 16.683-60.331 0s-16.683-43.648 0-60.331l140.501-140.501-140.501-140.501c-16.683-16.683-16.683-43.648 0-60.331 8.32-8.32 19.243-12.501 30.165-12.501s21.845 4.181 30.165 12.501l170.667 170.667c16.683 16.683 16.683 43.648 0 60.331zM225.835 478.165l170.667 170.667c16.683 16.683 43.648 16.683 60.331 0s16.683-43.648 0-60.331l-140.501-140.501 140.501-140.501c16.683-16.683 16.683-43.648 0-60.331-8.32-8.32-19.243-12.501-30.165-12.501s-21.845 4.181-30.165 12.501l-170.667 170.667c-16.683 16.683-16.683 43.648 0 60.331z" />
+<glyph unicode="&#xe906;" glyph-name="arrow-left" d="M183.467 477.899c-4.267-4.309-8.533-8.533-8.533-12.8-4.267-4.267-4.267-12.843-4.267-17.067 0-4.267 0-12.8 4.267-17.109 4.267-4.224 4.267-8.491 8.533-12.757l170.667-170.667c17.067-17.067 42.667-17.067 59.733 0s17.067 42.667 0 59.733l-98.091 98.133h494.891c25.6 0 42.667 17.067 42.667 42.667 0 25.557-17.067 42.667-42.667 42.667h-494.891l98.091 98.133c17.067 17.067 17.067 42.667 0 59.733-17.067 17.024-42.667 17.024-59.733 0l-170.667-170.667z" />
+<glyph unicode="&#xe907;" glyph-name="arrow-right" d="M840.533 418.101c4.267 4.309 8.533 8.533 8.533 12.8 4.267 4.267 4.267 12.843 4.267 17.067 0 4.267 0 12.8-4.267 17.109-4.267 4.224-4.267 8.491-8.533 12.757l-170.667 170.667c-17.067 17.067-42.667 17.067-59.733 0s-17.067-42.667 0-59.733l98.091-98.133h-494.891c-25.6 0-42.667-17.067-42.667-42.667 0-25.557 17.067-42.667 42.667-42.667h494.891l-98.091-98.133c-17.067-17.067-17.067-42.667 0-59.733 17.067-17.024 42.667-17.024 59.733 0l170.667 170.667z" />
+<glyph unicode="&#xe908;" glyph-name="arrow_f" d="M938.667 448c0-235.641-191.025-426.667-426.667-426.667s-426.667 191.025-426.667 426.667c0 235.641 191.025 426.667 426.667 426.667s426.667-191.025 426.667-426.667zM458.762 311.637c-10.286-10.637-10.286-27.88 0-38.516s26.962-10.637 37.248 0l150.497 155.621c10.286 10.637 10.286 27.88 0 38.516l-150.497 155.621c-10.286 10.637-26.962 10.637-37.248 0s-10.286-27.88 0-38.516l131.948-136.441-131.948-136.285z" />
+<glyph unicode="&#xe909;" glyph-name="arrow_o" d="M458.762 311.637c-10.286-10.637-10.286-27.88 0-38.516s26.962-10.637 37.248 0l150.497 155.621c10.286 10.637 10.286 27.88 0 38.516l-150.497 155.621c-10.286 10.637-26.962 10.637-37.248 0s-10.286-27.88 0-38.516l131.948-136.441-131.948-136.285zM512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM42.667 448c0-260.267 209.067-469.333 469.333-469.333s469.333 209.067 469.333 469.333c0 260.267-209.067 469.333-469.333 469.333s-469.333-209.067-469.333-469.333z" />
+<glyph unicode="&#xe90a;" glyph-name="attach" d="M924.768 478.208c-16.768 15.872-41.941 15.872-58.709 0l-386.005-364.757c-83.925-79.275-213.973-79.275-297.856 0-83.925 79.317-83.925 202.197 0 281.515l386.005 364.757c46.123 43.563 130.005 43.563 176.171 0 50.347-47.616 50.347-122.923 0-166.571l-385.963-364.715c-16.811-15.872-41.984-15.872-58.752 0-4.181 3.968-8.405 11.904-8.405 23.765 0 11.904 4.224 19.84 12.587 27.776l356.651 336.981c16.768 15.872 16.768 39.68 0 55.509-16.811 15.872-41.984 15.872-58.752 0l-356.651-336.981c-25.173-19.84-37.717-51.541-37.717-83.285 0-31.701 12.544-63.403 37.717-83.243 50.389-47.573 130.091-47.573 176.213 0l386.005 364.757c83.925 79.275 83.925 202.197 0 281.472-37.76 35.669-92.288 59.477-146.816 59.477-54.571 0-109.099-19.84-146.859-59.477l-386.005-364.715c-113.28-107.051-113.28-285.483 0-392.533 58.752-55.467 134.272-79.275 209.792-79.275s150.997 27.733 209.749 79.275l386.005 364.757c8.405 11.904 8.405 39.637-8.405 55.509z" />
+<glyph unicode="&#xe90b;" glyph-name="beadcrumbs" d="M731.429 448l-365.714-365.714v731.429z" />
+<glyph unicode="&#xe90c;" glyph-name="bedge" d="M273.067 789.333h477.867c150.811 0 273.067-122.256 273.067-273.067v-136.533c0-150.811-122.256-273.067-273.067-273.067h-477.867c-150.811 0-273.067 122.256-273.067 273.067v136.533c0 150.811 122.256 273.067 273.067 273.067z" />
+<glyph unicode="&#xe90d;" glyph-name="browse" d="M279.704 400.593c-36.655 0-66.37 29.715-66.37 66.37s29.715 66.37 66.37 66.37c36.655 0 66.37-29.715 66.37-66.37s-29.715-66.37-66.37-66.37zM744.296 400.593c-36.655 0-66.37 29.715-66.37 66.37s29.715 66.37 66.37 66.37c36.655 0 66.37-29.715 66.37-66.37s-29.715-66.37-66.37-66.37zM512 400.593c-36.655 0-66.37 29.715-66.37 66.37s29.715 66.37 66.37 66.37c36.655 0 66.37-29.715 66.37-66.37s-29.715-66.37-66.37-66.37z" />
+<glyph unicode="&#xe90e;" glyph-name="calendar" d="M810.667 64h-597.333c-25.6 0-42.667 17.067-42.667 42.667v384h682.667v-384c0-25.6-17.067-42.667-42.667-42.667zM213.333 746.667h85.333v-42.667c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v42.667h256v-42.667c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v42.667h85.333c25.6 0 42.667-17.067 42.667-42.667v-128h-682.667v128c0 25.6 17.067 42.667 42.667 42.667zM810.667 832h-85.333v42.667c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-42.667h-256v42.667c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-42.667h-85.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe90f;" glyph-name="camera" d="M938.667 149.333c0-25.6-17.067-42.667-42.667-42.667h-768c-25.6 0-42.667 17.067-42.667 42.667v469.333c0 25.6 17.067 42.667 42.667 42.667h170.667c12.8 0 25.6 8.533 34.133 17.067l72.533 110.933h209.067l72.533-110.933c12.8-8.533 25.6-17.067 38.4-17.067h170.667c25.6 0 42.667-17.067 42.667-42.667v-469.333zM896 746.667h-149.333l-72.533 110.933c-8.533 8.533-21.333 17.067-34.133 17.067h-256c-12.8 0-25.6-8.533-34.133-17.067l-72.533-110.933h-149.333c-72.533 0-128-55.467-128-128v-469.333c0-72.533 55.467-128 128-128h768c72.533 0 128 55.467 128 128v469.333c0 72.533-55.467 128-128 128zM512 234.667c-72.533 0-128 55.467-128 128s55.467 128 128 128c72.533 0 128-55.467 128-128s-55.467-128-128-128zM512 576c-119.467 0-213.333-93.867-213.333-213.333s93.867-213.333 213.333-213.333c119.467 0 213.333 93.867 213.333 213.333s-93.867 213.333-213.333 213.333z" />
+<glyph unicode="&#xe910;" glyph-name="chevron" d="M482.125 290.125c8.533-8.533 21.333-12.8 29.867-12.8s21.333 4.267 29.867 12.8l213.333 213.333c17.067 17.067 17.067 42.667 0 59.733s-42.667 17.067-59.733 0l-183.467-183.467-183.467 183.467c-17.067 17.067-42.667 17.067-59.733 0s-17.067-42.667 0-59.733l213.333-213.333z" />
+<glyph unicode="&#xe911;" glyph-name="close" d="M580.25 448l258.475 258.475c19.499 19.499 19.499 48.725 0 68.224s-48.768 19.499-68.267 0l-258.475-258.432-258.432 258.432c-19.499 19.499-48.768 19.499-68.267 0s-19.499-48.725 0-68.224l258.475-258.475-258.475-258.475c-19.499-19.499-19.499-48.725 0-68.224 9.771-9.771 19.499-14.635 34.133-14.635s24.363 4.864 34.133 14.635l258.432 258.432 258.475-258.432c9.771-9.771 24.363-14.635 34.133-14.635 9.728 0 24.363 4.864 34.133 14.635 19.499 19.499 19.499 48.725 0 68.224l-258.475 258.475z" />
+<glyph unicode="&#xe912;" glyph-name="commit" d="M896.086 106.965c-338.304 1.152-340.693 454.101-340.651 473.557v106.88l99.157-97.323c8.32-8.192 19.072-12.245 29.867-12.245 11.136 0 22.187 4.309 30.592 12.843 16.469 16.896 16.213 44.032-0.683 60.544l-171.819 168.576c-0.341 0.299-0.811 0.384-1.152 0.725-3.541 3.285-7.509 6.187-12.203 8.149-0.213 0.085-0.341 0.085-0.512 0.128-0.725 0.299-1.451 0.299-2.133 0.555-4.139 1.408-8.277 2.176-12.501 2.304-0.768 0-1.451 0.256-2.219 0.256-0.171 0-0.341 0.085-0.512 0.085-1.067 0-1.963-0.555-3.029-0.597-2.603-0.299-5.12-0.811-7.68-1.579-8.96-2.347-16.512-7.253-22.144-14.293l-165.803-163.456c-16.811-16.597-17.067-43.691-0.512-60.587 16.555-16.811 43.605-17.024 60.416-0.469l96 94.677v-105.387c0.043-19.243-2.347-472.192-340.651-473.344-23.595-0.085-42.667-19.328-42.581-42.965 0.085-23.595 19.2-42.667 42.752-42.667h0.171c107.051 0.384 196.949 36.608 267.307 107.648 56.832 57.429 93.056 130.347 116.437 200.789 23.424-70.443 59.648-143.36 116.48-200.789 70.315-71.040 160.213-107.264 267.264-107.648h0.171c23.552 0 42.667 19.072 42.752 42.667 0.085 23.637-18.987 42.88-42.581 42.965z" />
+<glyph unicode="&#xe913;" glyph-name="composition" d="M810.667 104.533c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667zM213.333 104.533c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667zM213.333 787.2c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM512 488.533c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM810.667 275.2c-55.68 0-102.528-35.755-120.149-85.333h-357.035c-12.843 36.224-41.259 64.64-77.483 77.483v135.851h135.851c17.621-49.579 64.469-85.333 120.149-85.333 70.699 0 128 57.301 128 128s-57.301 128-128 128c-55.68 0-102.528-35.755-120.149-85.333h-135.851v135.851c49.579 17.621 85.333 64.469 85.333 120.149 0 70.699-57.301 128-128 128s-128-57.301-128-128c0-55.68 35.755-102.528 85.333-120.149v-357.035c-49.579-17.621-85.333-64.469-85.333-120.149 0-70.699 57.301-128 128-128 55.68 0 102.528 35.755 120.149 85.333h357.035c17.621-49.579 64.469-85.333 120.149-85.333 70.699 0 128 57.301 128 128s-57.301 128-128 128z" />
+<glyph unicode="&#xe914;" glyph-name="deployment_Artifacts" d="M853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 874.667h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128zM298.667 277.333c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM512 661.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM725.333 277.333c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667zM405.888 387.285l66.176 110.379c12.629-4.224 25.899-6.997 39.936-6.997 6.784 0 13.312 0.981 19.84 2.005l81.152-108.16c-23.339-15.232-41.003-37.845-50.475-64.512h-101.035c-10.112 28.544-29.909 52.181-55.595 67.285zM461.483 234.667h101.035c17.621-49.579 64.469-85.333 120.149-85.333 70.699 0 128 57.301 128 128 0 62.805-45.312 114.773-104.96 125.653l-98.304 131.115c20.053 22.571 32.597 51.968 32.597 84.565 0 70.699-57.301 128-128 128s-128-57.301-128-128c0-25.216 7.552-48.597 20.139-68.395l-88.533-147.541c-58.368-11.904-102.272-63.531-102.272-125.397 0-70.699 57.301-128 128-128 55.68 0 102.528 35.755 120.149 85.333z" />
+<glyph unicode="&#xe915;" glyph-name="download" d="M896 277.333c25.6 0 42.667-17.067 42.667-42.667v-128c0-72.533-55.467-128-128-128h-597.333c-72.533 0-128 55.467-128 128v128c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-128c0-25.6 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.067 42.667 42.667v128c0 25.6 17.067 42.667 42.667 42.667zM482.101 247.467l-170.667 170.667c-17.024 17.067-17.024 42.667 0 59.733 17.067 17.067 42.667 17.067 59.733 0l98.133-98.091v494.891c0 25.6 17.109 42.667 42.667 42.667 25.6 0 42.667-17.067 42.667-42.667v-494.891l98.133 98.091c17.067 17.067 42.667 17.067 59.733 0s17.067-42.667 0-59.733l-170.667-170.667c-4.267-4.267-8.533-4.267-12.757-8.533-4.309-4.267-12.843-4.267-17.109-4.267-4.224 0-12.8 0-17.067 4.267-4.267 0-8.491 4.267-12.8 8.533z" />
+<glyph unicode="&#xe916;" glyph-name="duplicate" d="M128 106.667c0-25.6 17.067-42.667 42.667-42.667h384c25.6 0 42.667 17.067 42.667 42.667v384c0 25.6-17.067 42.667-42.667 42.667h-384c-25.6 0-42.667-17.067-42.667-42.667v-384zM170.667 618.667h384c72.533 0 128-55.467 128-128v-384c0-72.533-55.467-128-128-128h-384c-72.533 0-128 55.467-128 128v384c0 72.533 55.467 128 128 128zM810.667 362.667h42.667c25.6 0 42.667 17.067 42.667 42.667v384c0 25.6-17.067 42.667-42.667 42.667h-384c-25.6 0-42.667-17.067-42.667-42.667v-42.667c0-25.6-17.067-42.667-42.667-42.667s-42.667 17.067-42.667 42.667v42.667c0 72.533 55.467 128 128 128h384c72.533 0 128-55.467 128-128v-384c0-72.533-55.467-128-128-128h-42.667c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667z" />
+<glyph unicode="&#xe917;" glyph-name="edit" d="M170.667 388.271v-110.933h110.933l426.667 426.667-110.933 110.933-426.667-426.667zM128 192.004c-25.6 0-42.667 17.067-42.667 42.667v170.667c0 12.8 4.267 21.333 12.8 29.867l469.333 469.333c17.067 17.067 42.667 17.067 59.733 0l170.667-170.667c17.067-17.067 17.067-42.667 0-59.733l-469.333-469.333c-8.533-8.533-17.067-12.8-29.867-12.8h-170.667zM896 64c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667h-768c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h768z" />
+<glyph unicode="&#xe918;" glyph-name="expand" d="M934.426 849.067c4.267-4.309 4.267-12.843 4.267-17.067v-256c0-25.6-17.109-42.667-42.667-42.667-25.6 0-42.667 17.067-42.667 42.667v153.557l-226.133-226.133c-8.533-8.533-21.333-12.757-29.867-12.757-8.576 0-21.333 4.224-29.909 12.757-17.024 17.109-17.024 42.667 0 59.776l226.133 226.133h-153.557c-25.6 0-42.667 17.067-42.667 42.667 0 25.557 17.067 42.667 42.667 42.667h256c4.224 0 12.757 0 17.067-4.267 8.491-4.309 17.024-12.843 21.333-21.333zM396.8 392.525c17.067 17.024 42.667 17.024 59.733 0 17.067-17.067 17.067-42.667 0-59.733l-226.091-226.133h153.557c25.6 0 42.667-17.109 42.667-42.667 0-25.6-17.067-42.667-42.667-42.667h-256c-4.224 0-12.8 0-17.067 4.224-8.491 4.309-17.067 12.843-21.333 21.333-4.267 4.309-4.267 12.843-4.267 17.109v256c0 25.557 17.109 42.667 42.667 42.667 25.6 0 42.667-17.109 42.667-42.667v-153.6l226.133 226.133zM913.092 25.566c-4.309-4.267-12.843-4.267-17.067-4.267h-256c-25.6 0-42.667 17.109-42.667 42.667 0 25.6 17.067 42.667 42.667 42.667h153.557l-226.133 226.133c-8.533 8.533-12.757 21.333-12.757 29.867 0 8.576 4.224 21.333 12.757 29.909 17.109 17.024 42.667 17.024 59.776 0l226.133-226.133v153.557c0 25.6 17.067 42.667 42.667 42.667 25.557 0 42.667-17.067 42.667-42.667v-256c0-4.224 0-12.757-4.267-17.067-4.309-8.491-12.843-17.024-21.333-21.333zM456.55 563.191c17.024-17.067 17.024-42.667 0-59.733-17.067-17.067-42.667-17.067-59.733 0l-226.133 226.091v-153.557c0-25.6-17.109-42.667-42.667-42.667-25.6 0-42.667 17.067-42.667 42.667v256c0 4.224 0 12.8 4.224 17.067 4.309 8.491 12.843 17.067 21.333 21.333 4.309 4.267 12.843 4.267 17.109 4.267h256c25.557 0 42.667-17.109 42.667-42.667 0-25.6-17.109-42.667-42.667-42.667h-153.6l226.133-226.133z" />
+<glyph unicode="&#xe919;" glyph-name="fail" d="M580.25 448l258.475 258.475c19.499 19.499 19.499 48.725 0 68.224s-48.768 19.499-68.267 0l-258.475-258.432-258.432 258.432c-19.499 19.499-48.768 19.499-68.267 0s-19.499-48.725 0-68.224l258.475-258.475-258.475-258.475c-19.499-19.499-19.499-48.725 0-68.224 9.771-9.771 19.499-14.635 34.133-14.635s24.363 4.864 34.133 14.635l258.432 258.432 258.475-258.432c9.771-9.771 24.363-14.635 34.133-14.635 9.728 0 24.363 4.864 34.133 14.635 19.499 19.499 19.499 48.725 0 68.224l-258.475 258.475z" />
+<glyph unicode="&#xe91a;" glyph-name="file_managment" d="M853.333 375.462c25.6 0 42.667-17.024 42.667-42.667v-226.133c0-72.533-55.467-128-128-128h-597.333c-72.533 0-128 55.467-128 128v597.333c0 72.533 55.467 128 128 128h226.133c25.6 0 42.667-17.067 42.667-42.667 0-25.557-17.067-42.667-42.667-42.667h-226.133c-25.6 0-42.667-17.067-42.667-42.667v-597.333c0-25.557 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.109 42.667 42.667v226.133c0 25.643 17.067 42.667 42.667 42.667zM494.916 320.004h-110.933v110.933l384 384 110.933-110.933-384-384zM968.559 733.871l-170.667 170.667c-17.109 17.067-42.667 17.067-59.776 0l-426.667-426.667c-8.533-8.533-12.8-17.067-12.8-29.867v-170.667c0-25.6 17.109-42.667 42.667-42.667h170.667c12.8 0 21.333 4.267 29.909 12.8l426.667 426.667c17.024 17.067 17.024 42.667 0 59.733z" />
+<glyph unicode="&#xe91b;" glyph-name="filter" d="M563.595 456.533c-4.309-8.533-8.533-17.067-8.533-29.867v-294.443l-85.333 42.667v251.776c0 8.533-4.267 21.333-8.533 25.557l-281.6 337.109h669.867l-285.867-332.8zM977.461 849.067c-8.533 17.067-21.333 25.6-38.4 25.6h-853.333c-17.109 0-29.867-8.533-38.443-25.6-8.491-12.843-4.224-29.867 4.309-42.667l332.8-392.533v-264.533c0-17.109 8.533-29.867 25.557-38.443l170.667-85.333c4.309-4.224 8.576-4.224 17.109-4.224s17.067 0 21.333 4.224c12.8 8.576 21.333 21.333 21.333 38.443v349.867l332.8 392.533c8.533 12.8 12.757 29.824 4.267 42.667z" />
+<glyph unicode="&#xe91c;" glyph-name="filterDown" d="M482.101 162.133c4.309-4.267 8.533-8.533 12.8-8.533 4.267-4.267 12.843-4.267 17.067-4.267 4.267 0 12.8 0 17.109 4.267 4.224 4.267 8.491 4.267 12.757 8.533l170.667 170.667c17.067 17.067 17.067 42.667 0 59.733s-42.667 17.067-59.733 0l-98.133-98.091v494.891c0 25.6-17.067 42.667-42.667 42.667-25.557 0-42.667-17.067-42.667-42.667v-494.891l-98.133 98.091c-17.067 17.067-42.667 17.067-59.733 0-17.024-17.067-17.024-42.667 0-59.733l170.667-170.667z" />
+<glyph unicode="&#xe91d;" glyph-name="filterUp" d="M482.101 819.2c4.309 4.267 8.533 8.533 12.8 8.533 4.267 4.267 12.843 4.267 17.067 4.267 4.267 0 12.8 0 17.109-4.267 4.224-4.267 8.491-4.267 12.757-8.533l170.667-170.667c17.067-17.067 17.067-42.667 0-59.733s-42.667-17.067-59.733 0l-98.133 98.091v-494.891c0-25.6-17.067-42.667-42.667-42.667-25.557 0-42.667 17.067-42.667 42.667v494.891l-98.133-98.091c-17.067-17.067-42.667-17.067-59.733 0-17.024 17.067-17.024 42.667 0 59.733l170.667 170.667z" />
+<glyph unicode="&#xe91e;" glyph-name="info_f" d="M512 917.333c260.267 0 469.333-209.067 469.333-469.333 0-260.309-209.067-469.333-469.333-469.333s-469.333 209.024-469.333 469.333c0 260.267 209.067 469.333 469.333 469.333zM512 490.667c-25.6 0-42.667-17.067-42.667-42.667v-170.667c0-25.643 17.067-42.667 42.667-42.667s42.667 17.024 42.667 42.667v170.667c0 25.6-17.067 42.667-42.667 42.667zM482.125 648.542c-8.533-8.533-12.8-17.067-12.8-29.867s4.267-21.333 12.8-29.867c8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.576 8.533 12.8 17.067 12.8 29.867s-4.224 21.333-12.8 29.867c-17.067 17.024-42.667 17.024-59.733 0z" />
+<glyph unicode="&#xe91f;" glyph-name="info_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333 0-260.309 209.067-469.333 469.333-469.333s469.333 209.024 469.333 469.333c0 260.267-209.067 469.333-469.333 469.333zM512 490.667c-25.6 0-42.667-17.067-42.667-42.667v-170.667c0-25.643 17.067-42.667 42.667-42.667s42.667 17.024 42.667 42.667v170.667c0 25.6-17.067 42.667-42.667 42.667zM482.125 648.542c-8.533-8.533-12.8-17.067-12.8-29.867s4.267-21.333 12.8-29.867c8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.576 8.533 12.8 17.067 12.8 29.867s-4.224 21.333-12.8 29.867c-17.067 17.024-42.667 17.024-59.733 0z" />
+<glyph unicode="&#xe920;" glyph-name="info_tabs" d="M512 490.667c25.6 0 42.667-17.067 42.667-42.667v-170.667c0-25.643-17.067-42.667-42.667-42.667s-42.667 17.024-42.667 42.667v170.667c0 25.6 17.067 42.667 42.667 42.667zM482.133 648.565c17.067 17.024 42.667 17.024 59.733 0 8.576-8.533 12.8-17.067 12.8-29.867s-4.224-21.333-12.8-29.867c-8.533-8.576-17.067-12.8-29.867-12.8s-21.333 4.224-29.867 12.8c-8.533 8.533-12.8 17.067-12.8 29.867s4.267 21.333 12.8 29.867zM853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 874.667h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe921;" glyph-name="information_artifacts" d="M512 490.667c25.6 0 42.667-17.067 42.667-42.667v-170.667c0-25.643-17.067-42.667-42.667-42.667s-42.667 17.024-42.667 42.667v170.667c0 25.6 17.067 42.667 42.667 42.667zM482.133 648.565c17.067 17.024 42.667 17.024 59.733 0 8.576-8.533 12.8-17.067 12.8-29.867s-4.224-21.333-12.8-29.867c-8.533-8.576-17.067-12.8-29.867-12.8s-21.333 4.224-29.867 12.8c-8.533 8.533-12.8 17.067-12.8 29.867s4.267 21.333 12.8 29.867zM853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 874.667h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe922;" glyph-name="inputs" d="M853.333 147.2c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-597.333zM810.667 872.533h-597.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v597.333c0 72.533-55.467 128-128 128zM725.333 659.2h-426.667c-23.467 0-42.667-19.2-42.667-42.667s19.2-42.667 42.667-42.667h426.667c23.467 0 42.667 19.2 42.667 42.667s-19.2 42.667-42.667 42.667zM725.333 488.533h-426.667c-23.467 0-42.667-19.2-42.667-42.667s19.2-42.667 42.667-42.667h426.667c23.467 0 42.667 19.2 42.667 42.667s-19.2 42.667-42.667 42.667z" />
+<glyph unicode="&#xe923;" glyph-name="locked" d="M341.333 661.333c0 93.867 76.8 170.667 170.667 170.667s170.667-76.8 170.667-170.667v-128h-341.333v128zM810.667 533.333h-42.667v128c0 140.8-115.2 256-256 256s-256-115.2-256-256v-128h-42.667c-72.533 0-128-55.467-128-128v-298.667c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v298.667c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe924;" glyph-name="Menu" d="M445.649 699.24c0 36.655 29.715 66.37 66.37 66.37s66.37-29.715 66.37-66.37c0-36.655-29.715-66.37-66.37-66.37s-66.37 29.715-66.37 66.37zM445.649 234.648c0 36.655 29.715 66.37 66.37 66.37s66.37-29.715 66.37-66.37c0-36.655-29.715-66.37-66.37-66.37s-66.37 29.715-66.37 66.37zM445.649 466.944c0 36.655 29.715 66.37 66.37 66.37s66.37-29.715 66.37-66.37c0-36.655-29.715-66.37-66.37-66.37s-66.37 29.715-66.37 66.37z" />
+<glyph unicode="&#xe925;" glyph-name="notifications" d="M234.667 277.333h554.667c-12.8 25.6-21.333 55.467-21.333 85.333v213.333c0 140.8-115.2 256-256 256s-256-115.2-256-256v-213.333c0-29.867-8.533-59.733-21.333-85.333zM938.667 277.333c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667h-853.333c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667c46.933 0 85.333 38.4 85.333 85.333v213.333c0 187.733 153.6 341.333 341.333 341.333s341.333-153.6 341.333-341.333v-213.333c0-46.933 38.4-85.333 85.333-85.333zM644.131 100.648c21.333-12.8 29.867-38.4 8.533-59.733-25.6-42.667-68.267-64-110.933-64-21.333 0-42.667 4.267-64 17.067s-34.133 25.6-46.933 46.933c-8.533 21.333-4.309 46.933 17.024 59.733 21.333 8.533 46.976 4.267 59.776-17.067 4.224-8.533 8.533-12.8 17.067-17.067 21.333-8.533 46.933-4.267 59.733 17.067 12.757 21.333 38.4 29.867 59.733 17.067z" />
+<glyph unicode="&#xe926;" glyph-name="permissions" d="M554.667 362.667h-341.333c-119.467 0-213.333-93.867-213.333-213.333v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c0 72.533 55.467 128 128 128h341.333c72.533 0 128-55.467 128-128v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c0 119.467-93.867 213.333-213.333 213.333zM384 789.333c72.533 0 128-55.467 128-128s-55.467-128-128-128c-72.533 0-128 55.467-128 128s55.467 128 128 128zM384 448c119.467 0 213.333 93.867 213.333 213.333s-93.867 213.333-213.333 213.333c-119.467 0-213.333-93.867-213.333-213.333s93.867-213.333 213.333-213.333zM862.684 361.849c-21.333 4.267-46.976-8.533-51.2-29.867-4.267-21.333 8.533-46.933 29.867-51.2 55.467-12.8 93.867-64 93.867-123.733v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c4.267 98.133-59.733 183.467-157.867 204.8zM693.444 872.034c-21.333 8.533-42.667-4.267-51.2-29.867-4.267-21.333 8.533-46.933 29.867-51.2 68.267-17.067 110.933-85.333 93.867-157.867-12.843-46.933-46.933-81.067-93.867-93.867-21.333-4.267-38.4-29.867-29.867-51.2 4.224-21.333 21.333-34.133 42.667-34.133h8.533c76.8 21.333 136.533 76.8 153.6 153.6 29.867 119.467-38.4 238.933-153.6 264.533z" />
+<glyph unicode="&#xe927;" glyph-name="profile" d="M682.667 362.667h-341.333c-119.467 0-213.333-93.867-213.333-213.333v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c0 72.533 55.467 128 128 128h341.333c72.533 0 128-55.467 128-128v-85.333c0-25.6 17.067-42.667 42.667-42.667s42.667 17.067 42.667 42.667v85.333c0 119.467-93.867 213.333-213.333 213.333zM512 789.333c72.533 0 128-55.467 128-128s-55.467-128-128-128c-72.533 0-128 55.467-128 128s55.467 128 128 128zM512 448c119.467 0 213.333 93.867 213.333 213.333s-93.867 213.333-213.333 213.333c-119.467 0-213.333-93.867-213.333-213.333s93.867-213.333 213.333-213.333z" />
+<glyph unicode="&#xe928;" glyph-name="properties" d="M512 362.658c-46.933 0-85.333 38.4-85.333 85.333 0 46.976 38.4 85.333 85.333 85.333s85.333-38.357 85.333-85.333c0-46.933-38.4-85.333-85.333-85.333zM512 618.658c-93.867 0-170.667-76.8-170.667-170.667s76.8-170.667 170.667-170.667c93.867 0 170.667 76.8 170.667 170.667s-76.8 170.667-170.667 170.667zM814.916 209.075c8.533-8.533 12.843-17.067 12.843-29.867s-4.309-21.333-12.843-29.867c-8.491-8.576-17.024-12.8-29.824-12.8-12.843 0-21.333 4.224-34.176 17.067-34.133 34.133-81.024 42.667-123.691 21.333-42.667-17.067-68.309-59.733-68.309-102.4v-8.533c0-25.6-17.024-42.667-42.667-42.667-25.6 0-42.667 17.067-42.667 42.667v4.267c0 46.933-29.824 85.333-72.491 102.4-12.843 8.533-29.867 8.533-46.976 8.533-29.867 0-59.691-12.8-81.024-34.133-17.109-17.067-38.443-17.067-55.509-4.309l-8.491 17.109h-4.309c-4.224 4.224-4.224 12.8-4.224 17.067 0 12.8 4.224 21.333 17.024 34.133 34.176 34.133 42.667 81.024 21.333 123.691-17.024 42.667-59.691 68.309-102.357 68.309h-8.576c-25.557 0-42.667 17.024-42.667 42.667 0 25.6 17.109 42.667 42.667 42.667h4.267c46.976 0 85.333 29.867 102.4 72.533 17.109 42.667 8.576 89.6-25.557 128-17.109 17.067-17.109 42.667 0 59.733 17.024 17.067 42.667 17.067 64-4.267 29.824-29.867 76.8-38.4 115.157-25.643l12.843 4.309c42.667 17.024 68.224 59.691 68.224 102.357v8.576c0 25.6 17.109 42.667 42.667 42.667 25.6 0 42.667-17.067 42.667-46.933 0-46.976 25.6-85.333 68.267-102.4s89.643-8.576 128 25.6c8.533 8.491 17.067 12.8 29.867 12.8s21.333-4.309 29.867-12.8c17.109-17.067 17.109-42.667-4.224-64-29.867-29.867-38.443-76.843-25.643-115.2l4.309-12.8c17.024-42.667 59.691-68.267 102.357-68.267h8.533c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-46.891-42.667c-46.976 0-85.333-25.6-102.443-68.267-21.333-42.667-8.533-89.643 25.6-128zM866.116 302.942c4.309 8.491 12.8 17.067 29.867 17.067 72.576 0 128 55.424 128 128 0 72.533-55.424 128-128 128h-8.533c-8.533 0-17.024 4.267-21.333 12.757l-4.224 8.576c-4.309 8.533-4.309 21.333 8.533 34.091 46.891 46.976 51.157 115.243 12.8 166.443v12.8l-17.109 8.533c-21.333 21.333-51.2 34.133-85.333 34.133s-68.224-12.8-93.867-38.4c-8.491-8.533-21.333-8.533-29.824-4.267-8.533-4.267-17.109 8.533-17.109 21.333 0 72.533-55.424 128-128 128-72.533 0-128-55.467-128-128v-8.576c0-8.491-4.224-17.024-12.757-21.333l-8.576-4.224c-8.533-4.267-21.333 0-34.091 8.533-51.243 51.2-132.309 51.2-179.243 0-51.2-51.2-51.2-132.309 4.267-183.467 8.533-8.533 8.533-21.333 4.309-34.176-4.309-8.491-17.109-17.024-29.909-17.024-72.533 0-128-55.467-128-128s55.467-128 128-128h8.576c12.757 0 21.333-8.533 25.557-17.067 4.309-8.576 4.309-21.333-8.533-34.133-25.6-25.6-38.357-55.467-38.357-89.6 0-29.867 12.757-59.733 34.091-85.333l4.267-4.267 12.843-12.8c51.157-38.443 119.467-34.133 170.667 12.8 8.491 8.533 21.333 8.533 34.133 4.267 12.757-4.267 17.024-12.843 17.024-29.867 0-72.533 55.509-128 128-128 72.533 0 128 55.467 128 128v8.533c0 12.8 8.533 21.333 17.067 25.6 8.576 4.224 21.333 4.224 34.133-8.533 51.2-51.243 132.309-51.243 179.2 0 51.243 51.2 51.243 132.267-4.224 183.424-4.309 12.843-8.533 25.643-4.309 34.176z" />
+<glyph unicode="&#xe929;" glyph-name="Q_f" d="M560.006 694.979c68.267-25.6 115.2-89.6 119.467-166.4 0-110.933-140.8-162.133-157.867-166.4-4.267-4.267-8.576-4.267-12.8-4.267-17.109 0-34.133 12.8-38.443 29.867-8.491 25.6 4.309 46.933 25.643 55.467 25.6 12.8 98.133 46.933 98.133 89.6 0 38.4-21.333 68.267-55.467 81.067-46.976 17.067-93.867-8.533-110.976-51.2-8.491-21.333-34.091-34.133-55.424-25.6-25.6 4.267-34.133 29.867-29.909 55.467 29.909 85.376 128 132.267 217.643 102.4zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333 0-260.309 209.067-469.333 469.333-469.333s469.333 209.024 469.333 469.333c0 260.267-209.067 469.333-469.333 469.333zM482.133 264.565c17.067 17.024 42.667 17.024 59.733 0 8.576-8.533 12.8-21.333 12.8-29.867s-4.224-21.333-12.8-29.867c-8.533-8.576-17.067-12.8-29.867-12.8s-21.333 4.224-29.867 12.8c-8.533 8.533-12.8 17.067-12.8 29.867s4.267 21.333 12.8 29.867z" />
+<glyph unicode="&#xe92a;" glyph-name="Q_o" d="M560.006 694.979c-89.643 29.867-187.733-17.024-217.643-102.4-4.224-25.6 4.309-51.2 29.909-55.467 21.333-8.533 46.933 4.267 55.424 25.6 17.109 42.667 64 68.267 110.976 51.2 34.133-12.8 55.467-42.667 55.467-81.067 0-42.667-72.533-76.8-98.133-89.6-21.333-8.533-34.133-29.867-25.643-55.467 4.309-17.067 21.333-29.867 38.443-29.867 4.224 0 8.533 0 12.8 4.267 17.067 4.267 157.867 55.467 157.867 166.4-4.267 76.8-51.2 140.8-119.467 166.4zM512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333 0-260.309 209.067-469.333 469.333-469.333s469.333 209.024 469.333 469.333c0 260.267-209.067 469.333-469.333 469.333zM482.133 264.565c-8.533-8.533-12.8-17.067-12.8-29.867s4.267-21.333 12.8-29.867c8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8c8.576 8.533 12.8 21.333 12.8 29.867s-4.224 21.333-12.8 29.867c-17.067 17.024-42.667 17.024-59.733 0z" />
+<glyph unicode="&#xe92c;" glyph-name="revert" d="M597.333 422.4l115.2-115.2c17.067-17.067 17.067-42.667 0-59.733-8.533-8.533-21.333-12.8-29.867-12.8s-21.333 4.267-29.867 12.8l-128 128c-8.533 8.533-12.8 17.067-12.8 29.867v256c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-238.933zM955.895 588.856c81.024-221.867-38.4-465.067-260.309-541.867-46.891-17.067-93.867-25.6-140.757-25.6-174.933 0-341.333 110.933-405.333 285.867-8.576 21.333 4.224 46.933 25.557 55.467s46.976-4.267 55.509-25.6c64-179.2 256-273.067 435.157-209.067 89.643 29.867 157.867 93.867 196.309 174.933 38.357 81.067 42.667 174.933 12.8 260.267-29.909 89.6-93.909 157.867-174.933 196.267-81.067 38.4-174.976 42.667-260.309 12.8-46.891-17.067-93.867-46.933-128-81.067l-119.424-115.2h149.333c25.557 0 34.091-8.533 34.091-34.133s-17.024-42.667-42.667-42.667h-268.757l-4.267 4.267c-4.309 0-4.309 0-8.533 4.267-4.309 0-4.309 4.267-4.309 4.267 0 4.267-4.224 4.267-4.224 8.533v268.8c0 25.6 17.067 42.667 42.667 42.667 25.557 0 42.667-17.067 42.667-42.667v-157.867l128 119.467c42.667 42.667 98.091 76.8 157.867 98.133 106.667 38.4 221.867 34.133 324.224-17.067 102.443-51.2 179.243-136.533 217.643-243.2z" />
+<glyph unicode="&#xe92d;" glyph-name="save" d="M853.333 149.333c0-25.6-17.067-42.667-42.667-42.667h-42.667v298.667c0 25.6-17.067 42.667-42.667 42.667h-426.667c-25.6 0-42.667-17.067-42.667-42.667v-298.667h-42.667c-25.6 0-42.667 17.067-42.667 42.667v597.333c0 25.6 17.067 42.667 42.667 42.667h42.667v-170.667c0-25.6 17.067-42.667 42.667-42.667h341.333c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667h-298.667v128h324.267l187.733-187.733v-452.267zM341.333 106.667v256h341.333v-256h-341.333zM925.867 648.533l-213.333 213.333c-8.533 8.533-17.067 12.8-29.867 12.8h-469.333c-72.533 0-128-55.467-128-128v-597.333c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v469.333c0 12.8-4.267 21.333-12.8 29.867z" />
+<glyph unicode="&#xe92e;" glyph-name="search" d="M170.667 512c0 153.6 123.733 277.333 277.333 277.333s277.333-123.733 277.333-277.333c0-76.8-29.867-145.067-81.067-196.267s-119.467-81.067-196.267-81.067c-153.6 0-277.333 123.733-277.333 277.333zM925.867 93.867l-192 192c46.933 59.733 76.8 140.8 76.8 226.133 0 200.533-162.133 362.667-362.667 362.667s-362.667-162.133-362.667-362.667c0-200.533 162.133-362.667 362.667-362.667 85.333 0 162.133 29.867 226.133 76.8l192-192c8.533-8.533 21.333-12.8 29.867-12.8s21.333 4.267 29.867 12.8c17.067 17.067 17.067 42.667 0 59.733z" />
+<glyph unicode="&#xe92f;" glyph-name="setting" d="M512 362.658c-46.933 0-85.333 38.4-85.333 85.333 0 46.976 38.4 85.333 85.333 85.333s85.333-38.357 85.333-85.333c0-46.933-38.4-85.333-85.333-85.333zM512 618.658c-93.867 0-170.667-76.8-170.667-170.667s76.8-170.667 170.667-170.667c93.867 0 170.667 76.8 170.667 170.667s-76.8 170.667-170.667 170.667zM814.916 209.075c8.533-8.533 12.843-17.067 12.843-29.867s-4.309-21.333-12.843-29.867c-8.491-8.576-17.024-12.8-29.824-12.8-12.843 0-21.333 4.224-34.176 17.067-34.133 34.133-81.024 42.667-123.691 21.333-42.667-17.067-68.309-59.733-68.309-102.4v-8.533c0-25.6-17.024-42.667-42.667-42.667-25.6 0-42.667 17.067-42.667 42.667v4.267c0 46.933-29.824 85.333-72.491 102.4-12.843 8.533-29.867 8.533-46.976 8.533-29.867 0-59.691-12.8-81.024-34.133-17.109-17.067-38.443-17.067-55.509-4.309l-8.491 17.109h-4.309c-4.224 4.224-4.224 12.8-4.224 17.067 0 12.8 4.224 21.333 17.024 34.133 34.176 34.133 42.667 81.024 21.333 123.691-17.024 42.667-59.691 68.309-102.357 68.309h-8.576c-25.557 0-42.667 17.024-42.667 42.667 0 25.6 17.109 42.667 42.667 42.667h4.267c46.976 0 85.333 29.867 102.4 72.533 17.109 42.667 8.576 89.6-25.557 128-17.109 17.067-17.109 42.667 0 59.733 17.024 17.067 42.667 17.067 64-4.267 29.824-29.867 76.8-38.4 115.157-25.643l12.843 4.309c42.667 17.024 68.224 59.691 68.224 102.357v8.576c0 25.6 17.109 42.667 42.667 42.667 25.6 0 42.667-17.067 42.667-46.933 0-46.976 25.6-85.333 68.267-102.4s89.643-8.576 128 25.6c8.533 8.491 17.067 12.8 29.867 12.8s21.333-4.309 29.867-12.8c17.109-17.067 17.109-42.667-4.224-64-29.867-29.867-38.443-76.843-25.643-115.2l4.309-12.8c17.024-42.667 59.691-68.267 102.357-68.267h8.533c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-46.891-42.667c-46.976 0-85.333-25.6-102.443-68.267-21.333-42.667-8.533-89.643 25.6-128zM866.116 302.942c4.309 8.491 12.8 17.067 29.867 17.067 72.576 0 128 55.424 128 128 0 72.533-55.424 128-128 128h-8.533c-8.533 0-17.024 4.267-21.333 12.757l-4.224 8.576c-4.309 8.533-4.309 21.333 8.533 34.091 46.891 46.976 51.157 115.243 12.8 166.443v12.8l-17.109 8.533c-21.333 21.333-51.2 34.133-85.333 34.133s-68.224-12.8-93.867-38.4c-8.491-8.533-21.333-8.533-29.824-4.267-8.533-4.267-17.109 8.533-17.109 21.333 0 72.533-55.424 128-128 128-72.533 0-128-55.467-128-128v-8.576c0-8.491-4.224-17.024-12.757-21.333l-8.576-4.224c-8.533-4.267-21.333 0-34.091 8.533-51.243 51.2-132.309 51.2-179.243 0-51.2-51.2-51.2-132.309 4.267-183.467 8.533-8.533 8.533-21.333 4.309-34.176-4.309-8.491-17.109-17.024-29.909-17.024-72.533 0-128-55.467-128-128s55.467-128 128-128h8.576c12.757 0 21.333-8.533 25.557-17.067 4.309-8.576 4.309-21.333-8.533-34.133-25.6-25.6-38.357-55.467-38.357-89.6 0-29.867 12.757-59.733 34.091-85.333l4.267-4.267 12.843-12.8c51.157-38.443 119.467-34.133 170.667 12.8 8.491 8.533 21.333 8.533 34.133 4.267 12.757-4.267 17.024-12.843 17.024-29.867 0-72.533 55.509-128 128-128 72.533 0 128 55.467 128 128v8.533c0 12.8 8.533 21.333 17.067 25.6 8.576 4.224 21.333 4.224 34.133-8.533 51.2-51.243 132.309-51.243 179.2 0 51.243 51.2 51.243 132.267-4.224 183.424-4.309 12.843-8.533 25.643-4.309 34.176z" />
+<glyph unicode="&#xe930;" glyph-name="sub" d="M213.333 490.667h597.333c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667h-597.333c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667z" />
+<glyph unicode="&#xe931;" glyph-name="sub_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333zM682.667 490.667h-341.333c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h341.333c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667z" />
+<glyph unicode="&#xe932;" glyph-name="success" d="M815.403 732.877l-360.277-515.925-203.861 197.589c-18.987 18.347-47.445 18.347-66.389 0-18.944-18.389-18.944-45.952 0-64.341l237.056-229.76c9.472-9.173 18.944-13.781 33.195-13.781 14.208 0 23.723 4.608 33.152 13.781l393.515 548.139c18.944 18.347 18.944 45.909 0 64.299s-47.403 18.389-66.389 0z" />
+<glyph unicode="&#xe933;" glyph-name="success_f" d="M757.461 590.549l-298.667-341.333c-7.808-8.875-18.901-14.165-30.72-14.549-0.427 0-0.939 0-1.408 0-11.307 0-22.144 4.48-30.165 12.501l-170.667 170.667c-16.683 16.64-16.683 43.648 0 60.331 16.683 16.64 43.648 16.64 60.331 0l138.411-138.411 268.629 306.987c15.531 17.792 42.539 19.541 60.203 4.011 17.749-15.531 19.541-42.453 4.053-60.203zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333z" />
+<glyph unicode="&#xe934;" glyph-name="success_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333zM693.21 646.771l-268.629-307.029-138.411 138.411c-16.683 16.683-43.648 16.683-60.331 0-16.683-16.64-16.683-43.648 0-60.331l170.667-170.667c7.979-8.021 18.859-12.501 30.165-12.501 0.469 0 0.939 0 1.408 0.043 11.819 0.384 22.912 5.675 30.72 14.549l298.667 341.333c15.488 17.749 13.696 44.672-4.053 60.203-17.664 15.531-44.672 13.781-60.203-4.011z" />
+<glyph unicode="&#xe936;" glyph-name="sync" d="M878.933 358.4c21.333-4.267 34.176-29.867 29.867-55.467-21.333-59.733-59.691-115.2-102.357-157.867-81.109-81.067-187.776-123.733-302.976-123.733s-221.867 42.667-294.357 123.733l-123.776 119.467v-157.867c0-25.6-17.067-42.667-42.667-42.667-25.557 0-42.667 17.067-42.667 42.667v268.8c0 4.267 4.267 4.267 4.267 8.533 4.309 0 4.309 4.267 4.309 4.267 0 4.267 4.224 8.533 8.533 8.533 0 4.267 4.224 4.267 4.224 4.267h4.267c0 4.267 4.309 4.267 8.533 4.267h256c25.643 0 42.667-17.067 42.667-42.667s-17.024-42.667-42.667-42.667h-149.333l119.467-110.933c68.309-68.267 153.643-102.4 243.2-102.4 89.643 0 179.2 34.133 238.976 98.133 38.357 34.133 64 81.067 81.024 128 8.533 21.333 34.133 34.133 55.467 25.6zM958.406 831.276c25.6 0 42.667-17.067 42.667-42.667v-260.267c0-4.267 0-8.533-4.267-12.8 0-4.267-4.267-4.267-4.267-8.533-4.267 0-4.267-4.267-4.267-4.267-4.267-4.267-8.533-4.267-12.8-8.533s-12.8-4.267-17.067-4.267h-256c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h149.333l-119.467 115.2c-34.133 38.4-81.067 64-128 81.067-85.333 29.867-179.2 25.6-260.267-12.8-81.067-42.667-145.067-110.933-174.933-196.267-8.533-21.333-34.133-34.133-55.467-25.6-21.333 4.267-34.133 29.867-25.6 51.2 38.4 110.933 115.2 196.267 217.6 243.2 102.4 51.2 217.6 55.467 328.533 21.333 59.733-21.333 115.2-59.733 157.867-102.4l123.733-119.467v157.867c0 25.6 17.067 42.667 42.667 42.667z" />
+<glyph unicode="&#xe937;" glyph-name="trash" d="M768 106.667c0-25.6-17.067-42.667-42.667-42.667h-426.667c-25.6 0-42.667 17.067-42.667 42.667v554.667h512v-554.667zM384 789.333c0 25.6 17.067 42.667 42.667 42.667h170.667c25.6 0 42.667-17.067 42.667-42.667v-42.667h-256v42.667zM896 746.667h-170.667v42.667c0 72.533-55.467 128-128 128h-170.667c-72.533 0-128-55.467-128-128v-42.667h-170.667c-25.6 0-42.667-17.067-42.667-42.667s17.067-42.667 42.667-42.667h42.667v-554.667c0-72.533 55.467-128 128-128h426.667c72.533 0 128 55.467 128 128v554.667h42.667c25.6 0 42.667 17.067 42.667 42.667s-17.067 42.667-42.667 42.667zM426.667 191.996c25.6 0 42.667 17.067 42.667 42.667v256c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-256c0-25.6 17.067-42.667 42.667-42.667zM597.333 191.996c25.6 0 42.667 17.067 42.667 42.667v256c0 25.6-17.067 42.667-42.667 42.667s-42.667-17.067-42.667-42.667v-256c0-25.6 17.067-42.667 42.667-42.667z" />
+<glyph unicode="&#xe938;" glyph-name="undo" d="M955.733 588.856c-38.4 106.667-115.2 192-217.643 243.2-102.357 51.2-217.557 55.467-324.224 17.067-59.776-21.333-115.2-55.467-157.867-98.133l-128-119.467v157.867c0 25.6-17.109 42.667-42.667 42.667-25.6 0-42.667-17.067-42.667-42.667v-268.8c0-4.267 4.224-4.267 4.224-8.533 0 0 0-4.267 4.309-4.267 4.224-4.267 4.224-4.267 8.533-4.267l4.267-4.267h268.757c25.643 0 42.667 17.067 42.667 42.667s-8.533 34.133-34.091 34.133h-149.333l119.424 115.2c34.133 34.133 81.109 64 128 81.067 85.333 29.867 179.243 25.6 260.309-12.8 81.024-38.4 145.024-106.667 174.933-196.267 29.867-85.333 25.557-179.2-12.8-260.267-38.443-81.067-106.667-145.067-196.309-174.933-179.157-64-371.157 29.867-435.157 209.067-8.533 21.333-34.176 34.133-55.509 25.6s-34.133-34.133-25.557-55.467c64-174.933 230.4-285.867 405.333-285.867 46.891 0 93.867 8.533 140.757 25.6 221.909 76.8 341.333 320 260.309 541.867z" />
+<glyph unicode="&#xe939;" glyph-name="unlocked" d="M853.333 106.671c0-25.6-17.067-42.667-42.667-42.667h-597.333c-25.6 0-42.667 17.067-42.667 42.667v298.667c0 25.6 17.067 42.667 42.667 42.667h597.333c25.6 0 42.667-17.067 42.667-42.667v-298.667zM810.667 533.338h-469.333v128c0 46.933 17.067 89.6 51.2 119.467 29.867 34.133 72.533 51.2 119.467 51.2 81.067 0 149.333-55.467 166.4-136.533 4.267-21.333 29.867-38.4 51.2-34.133s38.4 25.6 34.133 51.2c-25.6 119.467-132.267 204.8-251.733 204.8-68.267 0-132.267-25.6-179.2-76.8-51.2-46.933-76.8-110.933-76.8-179.2v-128h-42.667c-72.533 0-128-55.467-128-128v-298.667c0-72.533 55.467-128 128-128h597.333c72.533 0 128 55.467 128 128v298.667c0 72.533-55.467 128-128 128z" />
+<glyph unicode="&#xe93a;" glyph-name="upload" d="M896 277.333c25.6 0 42.667-17.067 42.667-42.667v-128c0-72.533-55.467-128-128-128h-597.333c-72.533 0-128 55.467-128 128v128c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-128c0-25.6 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.067 42.667 42.667v128c0 25.6 17.067 42.667 42.667 42.667zM371.2 675.189c-17.067-17.024-42.667-17.024-59.733 0-17.067 17.067-17.067 42.667 0 59.733l170.667 170.667c4.267 4.267 8.533 4.267 12.757 8.576 12.843 4.224 25.643 4.224 34.176 0 4.267 0 8.491-4.309 12.8-8.576l170.667-170.667c17.024-17.067 17.024-42.667 0-59.733-8.533-8.533-17.067-12.8-29.867-12.8s-21.333 4.267-29.867 12.8l-98.133 98.133v-494.933c0-25.557-17.109-42.667-42.667-42.667-25.6 0-42.667 17.109-42.667 42.667v494.933l-98.133-98.133z" />
+<glyph unicode="&#xe93b;" glyph-name="view" d="M510.933 149.333c-230.4 0-379.733 230.4-422.4 298.667 38.4 68.267 192 298.667 422.4 298.667s379.733-230.4 422.4-298.667c-42.667-68.267-192-298.667-422.4-298.667zM1018.667 465.067c-8.533 17.067-187.733 366.933-507.733 366.933s-499.2-349.867-507.733-366.933c-4.267-12.8-4.267-25.6 0-38.4 8.533-12.8 187.733-362.667 507.733-362.667s499.2 349.867 507.733 366.933c4.267 8.533 4.267 25.6 0 34.133zM512 362.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM512 618.667c-93.867 0-170.667-76.8-170.667-170.667s76.8-170.667 170.667-170.667c93.867 0 170.667 76.8 170.667 170.667s-76.8 170.667-170.667 170.667z" />
+<glyph unicode="&#xe93c;" glyph-name="X_f" d="M512 917.333c260.267 0 469.333-209.067 469.333-469.333s-209.067-469.333-469.333-469.333c-260.267 0-469.333 209.067-469.333 469.333s209.067 469.333 469.333 469.333zM651.055 605.894c-17.067 17.024-42.667 17.024-59.733 0l-98.133-98.133-98.133 98.133c-17.067 17.024-42.667 17.024-59.733 0-17.067-17.067-17.067-42.667 0-59.733l98.091-98.133-98.091-98.133c-17.067-17.067-17.067-42.667 0-59.733 8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8l98.133 98.091 98.133-98.091c8.533-8.576 21.333-12.8 29.867-12.8s21.333 4.224 29.867 12.8c17.024 17.067 17.024 42.667 0 59.733l-98.133 98.133 98.133 98.133c17.024 17.067 17.024 42.667 0 59.733z" />
+<glyph unicode="&#xe93d;" glyph-name="X_o" d="M512 64c-213.333 0-384 170.667-384 384s170.667 384 384 384c213.333 0 384-170.667 384-384s-170.667-384-384-384zM512 917.333c-260.267 0-469.333-209.067-469.333-469.333s209.067-469.333 469.333-469.333c260.267 0 469.333 209.067 469.333 469.333s-209.067 469.333-469.333 469.333zM651.055 605.894c-17.067 17.024-42.667 17.024-59.733 0l-98.133-98.133-98.133 98.133c-17.067 17.024-42.667 17.024-59.733 0-17.067-17.067-17.067-42.667 0-59.733l98.091-98.133-98.091-98.133c-17.067-17.067-17.067-42.667 0-59.733 8.533-8.576 17.067-12.8 29.867-12.8s21.333 4.224 29.867 12.8l98.133 98.091 98.133-98.091c8.533-8.576 21.333-12.8 29.867-12.8s21.333 4.224 29.867 12.8c17.024 17.067 17.024 42.667 0 59.733l-98.133 98.133 98.133 98.133c17.024 17.067 17.024 42.667 0 59.733z" />
+</font></defs></svg> \ No newline at end of file
diff --git a/vid-webpack-master/src/style/fonts/icomoon.ttf b/vid-webpack-master/src/style/fonts/icomoon.ttf
new file mode 100644
index 000000000..4d82ec095
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/icomoon.ttf
Binary files differ
diff --git a/vid-webpack-master/src/style/fonts/icomoon.woff b/vid-webpack-master/src/style/fonts/icomoon.woff
new file mode 100644
index 000000000..451aaa8d0
--- /dev/null
+++ b/vid-webpack-master/src/style/fonts/icomoon.woff
Binary files differ
diff --git a/vid-webpack-master/src/styles.scss b/vid-webpack-master/src/styles.scss
new file mode 100644
index 000000000..905c79519
--- /dev/null
+++ b/vid-webpack-master/src/styles.scss
@@ -0,0 +1,171 @@
+/* You can add global styles to this file, and also import other style files */
+// styles in src/style directory are applied to the whole page
+
+@import "app/drawingBoard/drawing-board-tree/drawing-board-tree";
+@import "app/drawingBoard/available-models-tree/available-models-tree.component";
+@import "../node_modules/sdc-ui/css/style.css";
+//body {
+// [ui-view="content"] {
+// height: 100%;
+// }
+//}
+
+@font-face {
+ font-family: OpenSans-Bold;
+ src: url("../src/assets/fonts/OpenSans/OpenSans-Bold.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-BoldItlaic;
+ src: url("./assets/fonts/OpenSans/OpenSans-BoldItalic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-ExtraBold;
+ src: url("./assets/fonts/OpenSans/OpenSans-ExtraBold.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-ExtraBoldItalic;
+ src: url("./assets/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-Italic;
+ src: url("./assets/fonts/OpenSans/OpenSans-Italic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-Light;
+ src: url("./assets/fonts/OpenSans/OpenSans-Light.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-LightItalic;
+ src: url("./assets/fonts/OpenSans/OpenSans-LightItalic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-Regular;
+ src: url("./assets/fonts/OpenSans/OpenSans-Regular.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-Semibold;
+ src: url("./assets/fonts/OpenSans/OpenSans-Semibold.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: OpenSans-SemiboldItalic;
+ src: url("./assets/fonts/OpenSans/OpenSans-SemiboldItalic.ttf") format('truetype');
+}
+
+@font-face {
+ font-family: 'icomoon';
+ src: url('./assets/fonts/icomoon.eot?4cilop');
+ src: url('./assets/fonts/icomoon.eot?4cilop#iefix') format('embedded-opentype'),
+ url('./assets/fonts/icomoon.ttf?4cilop') format('truetype'),
+ url('./assets/fonts/icomoon.woff?4cilop') format('woff'),
+ url('./assets/fonts/icomoon.svg?4cilop#icomoon') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+
+[class^="icon-"], [class*=" icon-"] {
+ /* use !important to prevent issues with browser extensions that change fonts */
+ font-family: 'icomoon', serif !important;
+ speak: none;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+
+ /* Better Font Rendering =========== */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+html {
+ min-height: 100%;
+ height: 100%;
+ body {
+ height: 100%;
+ vid-app {
+ height: 100%;
+ display: flex !important;
+ flex-direction: column;
+ main {
+ &[_ngcontent-c0] {
+ font-family: OpenSans-Regular, serif;
+ }
+
+ display: flex !important;
+ flex-direction: column;
+ flex: 1;
+
+ }
+ }
+ }
+}
+a {
+ color: #03A9F4;
+}
+
+tooltip-content {
+ .tooltip.left .tooltip-arrow {
+ border-left-color: #171f2a;
+ }
+ .tooltip.bottom .tooltip-arrow {
+ border-bottom-color: #171f2a;
+ }
+ .tooltip-inner {
+ background-color: #171f2a;
+ text-align: left;
+ }
+}
+
+service-planning {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ border: 1px solid #d2d2d2;
+}
+
+.required:after {
+ content: " * ";
+ color: #cf2a2a;
+ margin-left: 3px;
+}
+
+
+.error-style {
+ border: solid 1px #cf2a2a !important;
+ color: #cf2a2a !important;
+ outline: none !important;
+}
+
+select option:disabled {
+ color: #959595;
+ cursor: default;
+}
+
+select option:disabled {
+ color: #959595 !important;
+ cursor: default;
+}
+
+select option {
+ color: black;
+}
+
+tooltip-content div {
+ word-wrap: break-word !important;
+}
+
+body {
+ -webkit-touch-callout: default !important;
+ -webkit-user-select: auto !important;
+ -moz-user-select: element !important;
+ -ms-user-select: element !important;
+ user-select: element !important;}
diff --git a/vid-webpack-master/src/test.ts b/vid-webpack-master/src/test.ts
new file mode 100644
index 000000000..16317897b
--- /dev/null
+++ b/vid-webpack-master/src/test.ts
@@ -0,0 +1,20 @@
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/zone-testing';
+import { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+declare const require: any;
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/vid-webpack-master/src/tsconfig.app.json b/vid-webpack-master/src/tsconfig.app.json
new file mode 100644
index 000000000..5e2507db5
--- /dev/null
+++ b/vid-webpack-master/src/tsconfig.app.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../out-tsc/app",
+ "module": "es2015",
+ "baseUrl": "",
+ "types": []
+ },
+ "exclude": [
+ "test.ts",
+ "**/*.spec.ts"
+ ]
+}
diff --git a/vid-webpack-master/src/tsconfig.spec.json b/vid-webpack-master/src/tsconfig.spec.json
new file mode 100644
index 000000000..ac22a298a
--- /dev/null
+++ b/vid-webpack-master/src/tsconfig.spec.json
@@ -0,0 +1,19 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../out-tsc/spec",
+ "baseUrl": "./",
+ "module": "commonjs",
+ "types": [
+ "jasmine",
+ "node"
+ ]
+ },
+ "files": [
+ "test.ts"
+ ],
+ "include": [
+ "**/*.spec.ts",
+ "**/*.d.ts"
+ ]
+}
diff --git a/vid-webpack-master/src/vendor.ts b/vid-webpack-master/src/vendor.ts
new file mode 100644
index 000000000..5abcda4bc
--- /dev/null
+++ b/vid-webpack-master/src/vendor.ts
@@ -0,0 +1,16 @@
+// Angular 2
+import '@angular/platform-browser';
+import '@angular/platform-browser-dynamic';
+import '@angular/core';
+import '@angular/common';
+import '@angular/http';
+import '@angular/router';
+import 'angular2-datatable';
+import 'rxjs';
+import '@angularclass/hmr';
+import 'ng2-bootstrap-modal';
+import 'redux';
+import 'ng2-redux';
+
+// Other vendors for example jQuery, Lodash or Bootstrap
+// You can import js, ts, css, sass, ...