diff --git a/package-lock.json b/package-lock.json index f6ad7b53ddfd875145a2638967d18ddf8294d453..036fbda074cc84742c6ee22e35a3ec6ca94aa304 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,9 +31,11 @@ "@fullcalendar/timegrid": "~5.11.2", "@iplab/ngx-file-upload": "~13.0.0", "@ng-bootstrap/ng-bootstrap": "~11.0.1", + "ang-jsoneditor": "^1.10.5", "angular-oauth2-oidc": "~13.0.1", "blockly": "git://github.com/google/blockly.git#6.20210701.0", "bootstrap": "~4.6.0", + "jsoneditor": "^9.10.0", "jwt-decode": "~2.2.0", "ngx-markdown": "~13.1.0", "ngx-progressbar": "~8.0.0", @@ -2987,6 +2989,11 @@ "dev": true, "license": "MIT" }, + "node_modules/@sphinxxxx/color-conversion": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz", + "integrity": "sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw==" + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "dev": true, @@ -3353,6 +3360,11 @@ "node": ">= 0.6" } }, + "node_modules/ace-builds": { + "version": "1.34.1", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.34.1.tgz", + "integrity": "sha512-hwRzr6BkRwsq5A19yA9E36KNNtn0+zESYolnWK3TADJsWVQS0T24nvbgdjXwqk2JEMQXE4PlqAw+ZgprvFtKjw==" + }, "node_modules/acorn": { "version": "7.4.1", "license": "MIT", @@ -3509,6 +3521,24 @@ "ajv": "^8.8.2" } }, + "node_modules/ang-jsoneditor": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/ang-jsoneditor/-/ang-jsoneditor-1.10.5.tgz", + "integrity": "sha512-i4sPCpKUN7DQzNctcJcEoMRex850iGvweaL3AYuFOJUWADyJ3BVMjv3GprUzA+jqURs83NucPFsIE1v1iMT2jA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "*", + "@angular/core": "*", + "jsoneditor": "^9.1.8" + } + }, + "node_modules/ang-jsoneditor/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/angular-oauth2-oidc": { "version": "13.0.1", "license": "MIT", @@ -7404,6 +7434,11 @@ "node": ">= 6.9.x" } }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==" + }, "node_modules/jest-worker": { "version": "27.5.1", "dev": true, @@ -7439,6 +7474,14 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/jquery": { "version": "3.6.1", "license": "MIT", @@ -7560,6 +7603,11 @@ "dev": true, "license": "MIT" }, + "node_modules/json-source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/json-source-map/-/json-source-map-0.6.1.tgz", + "integrity": "sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==" + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "license": "ISC" @@ -7580,6 +7628,42 @@ "dev": true, "license": "MIT" }, + "node_modules/jsoneditor": { + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/jsoneditor/-/jsoneditor-9.10.0.tgz", + "integrity": "sha512-vmVSD3ubZ8jwkiDKVW5MB5ESI/MUm4trVUw5WnT4j5FV6m81liA2YfQ0l84PlN4qJ3DCeYWFWfprOUoCjzkDhQ==", + "dependencies": { + "ace-builds": "^1.15.2", + "ajv": "^6.12.6", + "javascript-natural-sort": "^0.7.1", + "jmespath": "^0.16.0", + "json-source-map": "^0.6.1", + "jsonrepair": "^3.0.2", + "mobius1-selectr": "^2.4.13", + "picomodal": "^3.0.0", + "vanilla-picker": "^2.12.1" + } + }, + "node_modules/jsoneditor/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/jsoneditor/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, "node_modules/jsonfile": { "version": "4.0.0", "dev": true, @@ -7596,6 +7680,14 @@ ], "license": "MIT" }, + "node_modules/jsonrepair": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/jsonrepair/-/jsonrepair-3.8.0.tgz", + "integrity": "sha512-89lrxpwp+IEcJ6kwglF0HH3Tl17J08JEpYfXnvvjdp4zV4rjSoGu2NdQHxBs7yTOk3ETjTn9du48pBy8iBqj1w==", + "bin": { + "jsonrepair": "bin/cli.js" + } + }, "node_modules/jsprim": { "version": "1.4.2", "license": "MIT", @@ -8501,6 +8593,11 @@ "node": ">=10" } }, + "node_modules/mobius1-selectr": { + "version": "2.4.13", + "resolved": "https://registry.npmjs.org/mobius1-selectr/-/mobius1-selectr-2.4.13.tgz", + "integrity": "sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw==" + }, "node_modules/moment": { "version": "2.29.4", "license": "MIT", @@ -9566,6 +9663,11 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/picomodal": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/picomodal/-/picomodal-3.0.0.tgz", + "integrity": "sha512-FoR3TDfuLlqUvcEeK5ifpKSVVns6B4BQvc8SDF6THVMuadya6LLtji0QgUDSStw0ZR2J7I6UGi5V2V23rnPWTw==" + }, "node_modules/pify": { "version": "3.0.0", "dev": true, @@ -12498,6 +12600,14 @@ "builtins": "^1.0.3" } }, + "node_modules/vanilla-picker": { + "version": "2.12.3", + "resolved": "https://registry.npmjs.org/vanilla-picker/-/vanilla-picker-2.12.3.tgz", + "integrity": "sha512-qVkT1E7yMbUsB2mmJNFmaXMWE2hF8ffqzMMwe9zdAikd8u2VfnsVY2HQcOUi2F38bgbxzlJBEdS1UUhOXdF9GQ==", + "dependencies": { + "@sphinxxxx/color-conversion": "^2.2.2" + } + }, "node_modules/vary": { "version": "1.1.2", "dev": true, @@ -15220,6 +15330,11 @@ "version": "3.1.0", "dev": true }, + "@sphinxxxx/color-conversion": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz", + "integrity": "sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw==" + }, "@tootallnate/once": { "version": "1.1.2", "dev": true @@ -15530,6 +15645,11 @@ "negotiator": "0.6.3" } }, + "ace-builds": { + "version": "1.34.1", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.34.1.tgz", + "integrity": "sha512-hwRzr6BkRwsq5A19yA9E36KNNtn0+zESYolnWK3TADJsWVQS0T24nvbgdjXwqk2JEMQXE4PlqAw+ZgprvFtKjw==" + }, "acorn": { "version": "7.4.1" }, @@ -15629,6 +15749,21 @@ "fast-deep-equal": "^3.1.3" } }, + "ang-jsoneditor": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/ang-jsoneditor/-/ang-jsoneditor-1.10.5.tgz", + "integrity": "sha512-i4sPCpKUN7DQzNctcJcEoMRex850iGvweaL3AYuFOJUWADyJ3BVMjv3GprUzA+jqURs83NucPFsIE1v1iMT2jA==", + "requires": { + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + } + } + }, "angular-oauth2-oidc": { "version": "13.0.1", "requires": { @@ -18120,6 +18255,11 @@ "version": "2.2.0", "dev": true }, + "javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==" + }, "jest-worker": { "version": "27.5.1", "dev": true, @@ -18142,6 +18282,11 @@ } } }, + "jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" + }, "jquery": { "version": "3.6.1", "peer": true @@ -18235,6 +18380,11 @@ "version": "1.0.0", "dev": true }, + "json-source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/json-source-map/-/json-source-map-0.6.1.tgz", + "integrity": "sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==" + }, "json-stringify-safe": { "version": "5.0.1" }, @@ -18247,6 +18397,40 @@ "version": "3.0.0", "dev": true }, + "jsoneditor": { + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/jsoneditor/-/jsoneditor-9.10.0.tgz", + "integrity": "sha512-vmVSD3ubZ8jwkiDKVW5MB5ESI/MUm4trVUw5WnT4j5FV6m81liA2YfQ0l84PlN4qJ3DCeYWFWfprOUoCjzkDhQ==", + "requires": { + "ace-builds": "^1.15.2", + "ajv": "^6.12.6", + "javascript-natural-sort": "^0.7.1", + "jmespath": "^0.16.0", + "json-source-map": "^0.6.1", + "jsonrepair": "^3.0.2", + "mobius1-selectr": "^2.4.13", + "picomodal": "^3.0.0", + "vanilla-picker": "^2.12.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + } + } + }, "jsonfile": { "version": "4.0.0", "dev": true, @@ -18258,6 +18442,11 @@ "version": "1.3.1", "dev": true }, + "jsonrepair": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/jsonrepair/-/jsonrepair-3.8.0.tgz", + "integrity": "sha512-89lrxpwp+IEcJ6kwglF0HH3Tl17J08JEpYfXnvvjdp4zV4rjSoGu2NdQHxBs7yTOk3ETjTn9du48pBy8iBqj1w==" + }, "jsprim": { "version": "1.4.2", "requires": { @@ -18841,6 +19030,11 @@ "version": "1.0.4", "dev": true }, + "mobius1-selectr": { + "version": "2.4.13", + "resolved": "https://registry.npmjs.org/mobius1-selectr/-/mobius1-selectr-2.4.13.tgz", + "integrity": "sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw==" + }, "moment": { "version": "2.29.4", "peer": true @@ -19542,6 +19736,11 @@ "picomatch": { "version": "2.3.1" }, + "picomodal": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/picomodal/-/picomodal-3.0.0.tgz", + "integrity": "sha512-FoR3TDfuLlqUvcEeK5ifpKSVVns6B4BQvc8SDF6THVMuadya6LLtji0QgUDSStw0ZR2J7I6UGi5V2V23rnPWTw==" + }, "pify": { "version": "3.0.0", "dev": true @@ -21322,6 +21521,14 @@ "builtins": "^1.0.3" } }, + "vanilla-picker": { + "version": "2.12.3", + "resolved": "https://registry.npmjs.org/vanilla-picker/-/vanilla-picker-2.12.3.tgz", + "integrity": "sha512-qVkT1E7yMbUsB2mmJNFmaXMWE2hF8ffqzMMwe9zdAikd8u2VfnsVY2HQcOUi2F38bgbxzlJBEdS1UUhOXdF9GQ==", + "requires": { + "@sphinxxxx/color-conversion": "^2.2.2" + } + }, "vary": { "version": "1.1.2", "dev": true diff --git a/package.json b/package.json index fc2831e00df7304c511f754a5dc0a7461e107ee7..cdbc5e26fcd28b2be242aba5d77da395927f7ecb 100644 --- a/package.json +++ b/package.json @@ -34,9 +34,11 @@ "@fullcalendar/timegrid": "~5.11.2", "@iplab/ngx-file-upload": "~13.0.0", "@ng-bootstrap/ng-bootstrap": "~11.0.1", + "ang-jsoneditor": "^1.10.5", "angular-oauth2-oidc": "~13.0.1", "blockly": "git://github.com/google/blockly.git#6.20210701.0", "bootstrap": "~4.6.0", + "jsoneditor": "^9.10.0", "jwt-decode": "~2.2.0", "ngx-markdown": "~13.1.0", "ngx-progressbar": "~8.0.0", diff --git a/src/app/app-services.module.ts b/src/app/app-services.module.ts index 1b6f18f09ae483c85df5a018a8c969bbb4e374ff..d8fc418d86b64c597bcc1bbc0b14c6d364324957 100644 --- a/src/app/app-services.module.ts +++ b/src/app/app-services.module.ts @@ -27,7 +27,6 @@ import { AssignServiceRelationshipsComponent } from './p_services/admin/catalogM import { ServiceOrderCheckoutComponent } from './p_services/orderCheckout/service-order-checkout/service-order-checkout.component'; import { ListServiceOrdersComponent } from './p_services/admin/orderManagement/list-service-orders/list-service-orders.component'; import { PreviewServiceOrderComponent } from './p_services/admin/orderManagement/preview-service-order/preview-service-order.component'; -import { PreviewSupportingServicesComponent } from './p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component'; import { ListNsdComponent } from './p_services/admin/serviceDescriptorsImport/list-nsd.component'; import { ImportNsdDialogComponent } from './p_services/admin/serviceDescriptorsImport/import-nsd-dialog/import-nsd-dialog.component'; import { DeleteServiceOrderComponent } from './p_services/admin/orderManagement/delete-service-order/delete-service-order.component'; @@ -74,6 +73,7 @@ import resourceTimelinePlugin from '@fullcalendar/resource-timeline'; import { ServiceOrdersCalendarComponent } from './p_services/admin/orderManagement/service-order-calendar/service-order-calendar.component'; import { AssignResourceRelationshipsComponent } from './p_services/admin/catalogManagement/edit-service-specs/assign-resource-relationships/assign-resource-relationships.component'; +import { ExecuteManoServicePrimitiveComponent } from './p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component'; FullCalendarModule.registerPlugins([ // register FullCalendar plugins dayGridPlugin, @@ -109,7 +109,6 @@ FullCalendarModule.registerPlugins([ // register FullCalendar plugins ListServiceOrdersComponent, PreviewServiceOrderComponent, EditOrdersServiceSpecCharacteristicsComponent, - PreviewSupportingServicesComponent, ListNsdComponent, ImportNsdDialogComponent, DeleteServiceOrderComponent, @@ -135,7 +134,8 @@ FullCalendarModule.registerPlugins([ // register FullCalendar plugins ImportTestDialogComponent, ImportLcmruleComponent, ServiceOrdersCalendarComponent, - AssignResourceRelationshipsComponent + AssignResourceRelationshipsComponent, + ExecuteManoServicePrimitiveComponent // ListOrganizationsComponent, // EditOrganizationsComponent, // EditPartyCharacteristicsComponent, @@ -164,7 +164,6 @@ FullCalendarModule.registerPlugins([ // register FullCalendar plugins AssignServiceRelationshipsComponent, PreviewMarketplaceItemComponent, EditOrdersServiceSpecCharacteristicsComponent, - PreviewSupportingServicesComponent, ImportNsdDialogComponent, DeleteServiceOrderComponent, DeleteAttachmentComponent, @@ -178,7 +177,8 @@ FullCalendarModule.registerPlugins([ // register FullCalendar plugins EditActionSpecsComponent, DeleteLcmruleComponent, ImportTestDialogComponent, - ImportLcmruleComponent + ImportLcmruleComponent, + ExecuteManoServicePrimitiveComponent // EditPartyCharacteristicsComponent, // DeletePartyCharacteristicComponent, // DeleteOrganizationComponent, diff --git a/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.html b/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.html deleted file mode 100644 index 8182b2a9e1306bc5272b2b47620dc842f7265c9b..0000000000000000000000000000000000000000 --- a/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.html +++ /dev/null @@ -1,109 +0,0 @@ -<div class="container"> - - <h4 mat-dialog-title class="shadowed mb-3"> - <i class="fa fa-tasks mr-2"></i> - <span>Supporting Service Information</span> - </h4> - - <mat-dialog-content> - <form class="row justify-content-center" [formGroup]="editForm"> - <div class="col-lg-4"> - <h6>ID</h6> - <p>{{supportingService?.id}}</p> - </div> - <div class="col-lg-4"> - <h6>Name</h6> - <p>{{supportingService?.name}}</p> - </div> - <div class="col-lg-4"> - <h6>Desc</h6> - <p>{{supportingService?.description}}</p> - </div> - <div class="col-lg-4"> - <h6>Service Type</h6> - <p>{{supportingService?.serviceType}}</p> - </div> - <div class="col-lg-4"> - <h6>Category</h6> - <p>{{supportingService?.category}}</p> - </div> - <div class="col-lg-4"> - <h6>Specification</h6> - <p><a routerLink='/{{appService.portalDomain}}/service_spec_update/{{supportingService?.serviceSpecification.id}}'>{{supportingService?.serviceSpecification.name}}</a></p> - </div> - <div class="col-lg-4"> - <h6>Start Date</h6> - <p [class.mb-0]="supportingService?.startDate">{{supportingService?.startDate | date:'d MMM y, h:mm a'}} - Local Time</p> - <p>{{supportingService?.startDate | date:'d MMM y, h:mm a':'UTC'}} - UTC</p> - </div> - <div class="col-lg-4"> - <h6>Start Mode</h6> - <p>{{supportingService?.startMode}}</p> - </div> - <div class="col-lg-4"> - - <mat-form-field> - <mat-label>State</mat-label> - <mat-select formControlName="state"> - <mat-option *ngFor="let state of availableStates" [value]="state">{{state}}</mat-option> - </mat-select> - </mat-form-field> - </div> - <div class="col-lg-6"> - <h6>Supporting Resources</h6> - <p *ngIf="supportingService?.supportingResource.length === 0"> There are not supporting resources allocated </p> - <p *ngFor="let resource of supportingService?.supportingResource" class="mb-2">{{resource.name}}</p> - </div> - <div class="col-lg-6"> - <h6>Supporting Services</h6> - <p *ngIf="supportingService?.supportingService.length === 0"> There are not supporting services allocated </p> - <p *ngFor="let service of supportingService?.supportingService" class="mb-2">{{service.name}}</p> - </div> - <div class="col-12"> - <h6>Service Characteristics</h6> - <p *ngFor="let characteristic of supportingService?.serviceCharacteristic; let last = last" [ngClass]="{'mb-0':!last}"> - {{characteristic.name}}: <dfn>{{characteristic.value.value}}</dfn> - </p> - </div> - <div class="col-lg-12"> - <h6>Notes</h6> - <div class="notes-container"> - <div *ngFor="let note of supportingService?.note"> - <div class="card card-paper mb-2 bg-light"> - <div class="note-card-body"> - {{note.text}} - <div class="small">written by {{note.author}} @ {{note.date | date:'d MMM y, h:mm a'}}</div> - </div> - </div> - </div> - </div> - - <button type="button" *ngIf="!newNote" class="btn btn-primary btn-sm btn-block mb-2" - (click)="triggerNewNote()"><i class="far fa-sticky-note mr-2"></i>Add Note</button> - - <div class="card card-paper mb-2 bg-light" *ngIf="newNote"> - <div class="note-card-body pb-0"> - <div class="d-flex justify-content-center align-items-center"> - <mat-form-field> - <mat-label>New Note</mat-label> - <textarea cdkTextareaAutosize #autosize="cdkTextareaAutosize" cdkAutosizeMinRows="2" matInput formControlName="note"></textarea> - </mat-form-field> - <button type="button" class="btn btn-danger btn-sm ml-2 mb-1" (click)="triggerNewNote()"><i - class="fas fa-times"></i></button> - </div> - </div> - </div> - - - </div> - </form> - - </mat-dialog-content> - - <div class="container-fluid"> - <div class="row justify-content-end"> - <button type="button" class="btn btn-danger m-2" (click)="closeDialog()">Cancel</button> - <button type="submit" class="btn btn-success m-2" (click)="submitDialog()" *ngIf="!editForm.pristine">Submit</button> - </div> - </div> -</div> \ No newline at end of file diff --git a/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.scss b/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.scss deleted file mode 100644 index 4246535e119be8194ccbe62350a557d95fc1722f..0000000000000000000000000000000000000000 --- a/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -// .notes-container { -// max-height: 200px; -// overflow-y: auto; -// } - -.note-card-body { - padding: .5rem; -} - -mat-form-field { - width: 100%; -} \ No newline at end of file diff --git a/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.spec.ts b/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.spec.ts deleted file mode 100644 index 071e5308dd5eaf9326cbb0818dd8b00fdc0785d4..0000000000000000000000000000000000000000 --- a/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PreviewSupportingServicesComponent } from './preview-supporting-services.component'; - -describe('PreviewSupportingServicesComponent', () => { - let component: PreviewSupportingServicesComponent; - let fixture: ComponentFixture<PreviewSupportingServicesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ PreviewSupportingServicesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(PreviewSupportingServicesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.ts b/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.ts deleted file mode 100644 index 2eea49fa017f3a029998da05c90e04478b9076bc..0000000000000000000000000000000000000000 --- a/src/app/p_services/admin/inventoryManagement/preview-supporting-services/preview-supporting-services.component.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { Component, OnInit, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { ServiceRef } from 'src/app/openApis/serviceOrderingManagement/models'; -import { ServiceService } from 'src/app/openApis/serviceInventoryManagement/services'; -import { Service, ServiceUpdate } from 'src/app/openApis/serviceInventoryManagement/models'; -import { ToastrService } from 'ngx-toastr'; -import { FormGroup, FormControl } from '@angular/forms'; -import { AuthService } from 'src/app/shared/services/auth.service'; -import { AppService } from 'src/app/shared/services/app.service'; - -@Component({ - selector: 'app-preview-supporting-services', - templateUrl: './preview-supporting-services.component.html', - styleUrls: ['./preview-supporting-services.component.scss'] -}) -export class PreviewSupportingServicesComponent implements OnInit { - - constructor( - @Inject(MAT_DIALOG_DATA) public data: { - serviceRef: ServiceRef - }, - private dialogRef: MatDialogRef<PreviewSupportingServicesComponent>, - private inventoryService: ServiceService, - private toastr: ToastrService, - private authService: AuthService, - public appService: AppService - ) { } - - supportingService: Service - - newNote: boolean = false - - editForm = new FormGroup ({ - state: new FormControl(), - note: new FormControl() - }) - - availableStates = ['feasibilityChecked', 'designed', 'reserved', 'inactive', 'active', 'terminated'] - ngOnInit() { - if (this.data.serviceRef) { - this.inventoryService.retrieveService(this.data.serviceRef).subscribe( - data => { this.supportingService = data }, - error => { console.error(error); this.toastr.error("An error occurred retrieving supporting Service information")}, - () => { - this.editForm.patchValue({ - state: this.supportingService.state - }) - } - ) - } - } - - stateClassSelector(state:'feasibilityChecked' | 'designed' | 'reserved' | 'inactive' | 'active' | 'terminated') { - let cssClass: string = 'badge' - switch (state) { - case 'active': - cssClass += ' badge-success' - break; - case 'inactive': - cssClass += ' badge-secondary' - break; - case 'terminated': - cssClass += ' badge-danger' - break; - default: - cssClass += ' badge-warning' - } - return cssClass - } - - triggerNewNote() { - if (this.newNote) this.editForm.get('note').reset() - this.newNote = !this.newNote - } - - closeDialog() { - this.dialogRef.close() - } - - submitDialog() { - - let updateServiceObj: ServiceUpdate = {} - - if (!this.editForm.get('state').pristine) - updateServiceObj['state'] = this.editForm.get('state').value - if (!this.editForm.get('note').pristine) - updateServiceObj['note'] = [{ - author: this.authService.portalUserJWT.preferred_username, - text: this.editForm.get('note').value - }] - - this.inventoryService.patchService({service: updateServiceObj, id: this.supportingService.id}).subscribe( - data => { }, - error => { console.error(error), this.toastr.error("An error occurred updating this Supporting Service") }, - () => { this.dialogRef.close('updated') } - ) - } - -} diff --git a/src/app/p_services/admin/orderManagement/preview-service-order/preview-service-order.component.ts b/src/app/p_services/admin/orderManagement/preview-service-order/preview-service-order.component.ts index 85aab756f183624d358ef7c10c95f5d75b9cf059..69c43d678ea6f93ee88347b741bd36c09ae098bb 100644 --- a/src/app/p_services/admin/orderManagement/preview-service-order/preview-service-order.component.ts +++ b/src/app/p_services/admin/orderManagement/preview-service-order/preview-service-order.component.ts @@ -16,7 +16,6 @@ import { trigger } from '@angular/animations'; import { fadeIn, simpleFade } from 'src/app/shared/animations/animations'; import { SelectionModel } from '@angular/cdk/collections'; import { EditServiceOrderItemsComponent } from './edit-service-order-items/edit-service-order-items.component'; -import { PreviewSupportingServicesComponent } from '../../inventoryManagement/preview-supporting-services/preview-supporting-services.component'; import { TerminateServiceOrderItemsComponent } from './terminate-service-order-items/terminate-service-order-items.component'; import { AppService } from 'src/app/shared/services/app.service'; import { relative } from 'path'; @@ -231,23 +230,6 @@ export class PreviewServiceOrderComponent implements OnInit { this.editModeNotes = !this.editModeNotes } - openSupportingServiceDialog(supportingServiceRef: ServiceRef) { - const dialogRef = this.dialog.open(PreviewSupportingServicesComponent, { - data : { serviceRef: supportingServiceRef }, - disableClose: true - }) - - dialogRef.afterClosed().subscribe( - result => { - if (result) { - this.toast.success("Supporting Service was successfully updated") - - this.enableOrderRefreshTimer() - } - } - ) - } - // openOrdersSpecCharacteristicsDialog(orderItem: ServiceOrderItem) { // const dialogRef = this.dialog.open(EditOrdersServiceSpecCharacteristicsComponent, { diff --git a/src/app/p_services/admin/serviceActivationAndConfiguration/edit-service-characteristics/edit-service-characteristics.component.html b/src/app/p_services/admin/serviceActivationAndConfiguration/edit-service-characteristics/edit-service-characteristics.component.html index c7c0adce7ffc6222818f13731abd8987462213be..11a47b295f901639c28e6caae6262fc763d6748c 100644 --- a/src/app/p_services/admin/serviceActivationAndConfiguration/edit-service-characteristics/edit-service-characteristics.component.html +++ b/src/app/p_services/admin/serviceActivationAndConfiguration/edit-service-characteristics/edit-service-characteristics.component.html @@ -4,9 +4,17 @@ <span>Edit Service Characteristics</span> </h4> - <mat-dialog-content *ngIf="!serviceSpec" class="d-flex align-items-center justify-content-center"> - <mat-progress-spinner color="primary" mode="indeterminate" diameter="100"></mat-progress-spinner> + <mat-dialog-content *ngIf="!serviceSpec" > + <div *ngIf="!serviceSpecificationNotFound" class="d-flex align-items-center justify-content-center"> + <mat-progress-spinner color="primary" mode="indeterminate" diameter="100"></mat-progress-spinner> + </div> + <div *ngIf="serviceSpecificationNotFound" class="mt-3" [@fadeIn]> + The Service Specification, which the Service is based upon, cannot be found or is deleted. The Service Characteristics cannot be edited. + </div> + </mat-dialog-content> + + <mat-dialog-content *ngIf="serviceSpec"> diff --git a/src/app/p_services/admin/serviceActivationAndConfiguration/edit-service-characteristics/edit-service-characteristics.component.ts b/src/app/p_services/admin/serviceActivationAndConfiguration/edit-service-characteristics/edit-service-characteristics.component.ts index 4e0bb74185cf9f8391282be50ff01a3581a10c8a..e08cd917e2dd724bde4a13e226ecec5e76891816 100644 --- a/src/app/p_services/admin/serviceActivationAndConfiguration/edit-service-characteristics/edit-service-characteristics.component.ts +++ b/src/app/p_services/admin/serviceActivationAndConfiguration/edit-service-characteristics/edit-service-characteristics.component.ts @@ -30,6 +30,7 @@ export class EditServiceCharacteristicsComponent implements OnInit { ) { } serviceSpec: ServiceSpecification + serviceSpecificationNotFound: boolean servCharFormArray = new FormArray([]) specCharFormArray = new FormArray([]) @@ -55,17 +56,26 @@ export class EditServiceCharacteristicsComponent implements OnInit { const specCharFA = this.specCharFormArray as FormArray const servCharFA = this.servCharFormArray as FormArray - this.specificationCharacteristics = this.serviceSpec.serviceSpecCharacteristic.filter( char => {return this.injectedData.service.serviceCharacteristic.some (specChar => specChar.name === char.name) }) - this.specificationCharacteristics.sort(this.sortingService.ascStringSortingFunctionByNameProperty()) - - this.serviceCharacteristics = this.injectedData.service.serviceCharacteristic.filter( char => {return !this.serviceSpec.serviceSpecCharacteristic.some (specChar => specChar.name === char.name) }) - this.serviceCharacteristics.sort(this.sortingService.ascStringSortingFunctionByNameProperty()) + // First check if the Service Specification, which the Service is based on, is still present and not deleted. + if (this.serviceSpec) { + this.specificationCharacteristics = this.serviceSpec.serviceSpecCharacteristic.filter( char => {return this.injectedData.service.serviceCharacteristic.some (specChar => specChar.name === char.name) }) + this.specificationCharacteristics.sort(this.sortingService.ascStringSortingFunctionByNameProperty()) + + this.serviceCharacteristics = this.injectedData.service.serviceCharacteristic.filter( char => {return !this.serviceSpec.serviceSpecCharacteristic.some (specChar => specChar.name === char.name) }) + this.serviceCharacteristics.sort(this.sortingService.ascStringSortingFunctionByNameProperty()) + + this.specificationCharacteristics.forEach ( specChar => { + // if (this.injectedData.serviceCharacteristic.some(char => char.name === specChar.name)) { + specCharFA.push(this.updateFAItem(specChar)) + // } + }) + } + // If the Service Specification is deleted, then it is not anymore possible to edit the service characteristics as the template is missing (data types, predefined values, etc). + // This might have happen if the user tries to edit an "old" service, which its Specification has been deleted. + else { + this.serviceSpecificationNotFound = true + } - this.specificationCharacteristics.forEach ( specChar => { - // if (this.injectedData.serviceCharacteristic.some(char => char.name === specChar.name)) { - specCharFA.push(this.updateFAItem(specChar)) - // } - }) } updateFAItem (characteristic: ServiceSpecCharacteristic): FormGroup { diff --git a/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.html b/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.html new file mode 100644 index 0000000000000000000000000000000000000000..38daee21bb922d1f97df00d8df6cbeb177c6c264 --- /dev/null +++ b/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.html @@ -0,0 +1,57 @@ +<div class="container"> + <h4 mat-dialog-title class="row shadowed mb-3"> + <i class="fas fa-scroll mr-2"></i> + <span>Execute MANO primitives</span> + </h4> + + <form [formGroup]="primitivesParamsForm"> + <mat-dialog-content> + <div class="row"> + <div class="col-12"> + <h6>Primitive Type</h6> + <p>{{data.primitiveType}}</p> + </div> + + <div class="col-12"> + <h6>VNF Profile ID</h6> + <p>{{data.primitive.vnf_id}}</p> + </div> + + <div class="col-12"> + <h6>Primitive</h6> + <p>{{data.primitive.primitive.name}}</p> + </div> + + <div class="col-12" *ngIf="data.primitive.primitive?.parameter?.length"> + <div class="row"> + <mat-form-field class="col-md-6"> + <mat-label>Primitive Parameter Name</mat-label> + <mat-select formControlName="parameter"> + <mat-option *ngFor="let parameter of data.primitive.primitive.parameter" [value]="parameter"> + {{parameter.name}} + </mat-option> + </mat-select> + </mat-form-field> + + <mat-form-field class="col-md-6"> + <mat-label>Primitive Parameter Value</mat-label> + <input matInput formControlName="value" [placeholder]="primitivesParamsForm.controls.parameter.value['data-type']"> + </mat-form-field> + + </div> + </div> + </div> + + + + + </mat-dialog-content> + <div class="container-fluid"> + <div class="row justify-content-end"> + <button type="button" class="btn btn-danger m-2" (click)="closeDialog()">Cancel</button> + <button type="submit" class="btn btn-success m-2" (click)="submitDialog()">Submit</button> + </div> + </div> + </form> + +</div> \ No newline at end of file diff --git a/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.scss b/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.spec.ts b/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae48253aa29f4ace2155ab688a879b6ffdc9c686 --- /dev/null +++ b/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ExecuteManoServicePrimitiveComponent } from './execute-mano-service-primitive.component'; + +describe('ExecuteManoServicePrimitiveComponent', () => { + let component: ExecuteManoServicePrimitiveComponent; + let fixture: ComponentFixture<ExecuteManoServicePrimitiveComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ExecuteManoServicePrimitiveComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ExecuteManoServicePrimitiveComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.ts b/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee146f36ee09176d41fc31c0110fb246c3edf055 --- /dev/null +++ b/src/app/p_services/admin/serviceActivationAndConfiguration/execute-mano-service-primitive/execute-mano-service-primitive.component.ts @@ -0,0 +1,82 @@ +import { trigger } from '@angular/animations'; +import { Component, Inject, OnInit } from '@angular/core'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Characteristic, Service, ServiceUpdate } from 'src/app/openApis/serviceInventoryManagement/models'; +import { ServiceService } from 'src/app/openApis/serviceInventoryManagement/services'; +import { fadeIn, simpleFade } from 'src/app/shared/animations/animations'; + +@Component({ + selector: 'app-execute-mano-service-primitive', + templateUrl: './execute-mano-service-primitive.component.html', + styleUrls: ['./execute-mano-service-primitive.component.scss'], + animations: [ [ trigger('fadeIn', fadeIn()), trigger('simpleFade', simpleFade()) ]] +}) +export class ExecuteManoServicePrimitiveComponent implements OnInit { + + constructor( + @Inject(MAT_DIALOG_DATA) public data: { + primitiveType: string + primitive: {"vnf_id":string, "primitive":{"name":string, "parameter"?:{"name":string, "data-type":string}}}, + serviceToBeUpdated: Service + }, + private dialogRef: MatDialogRef<ExecuteManoServicePrimitiveComponent>, + private serviceService: ServiceService + ) { } + + ngOnInit(): void { + this.initFormControlSubscriptions() + } + + parameterSelectionCtrl + primitivesParamsForm = new FormGroup({ + parameter: new FormControl(""), + value: new FormControl("") + }) + + initFormControlSubscriptions() { + this.primitivesParamsForm.get("parameter").valueChanges.subscribe( + _ => this.primitivesParamsForm.get("value").reset() + ) + } + + + closeDialog() { + this.dialogRef.close() + } + + submitDialog() { + // To execute the primitive, we need to add it as a Service Characteristic with name "Primitive::{{name}}" + let primitiveObjectValue = [ + {alias: "member_vnf_index", value: this.data.primitive.vnf_id}, + {alias: "primitive", value: this.data.primitive.primitive.name} + ] + + const paramName = this.primitivesParamsForm.get("parameter").value.name; + const paramValue = this.primitivesParamsForm.get("value").value; + + if (this.primitivesParamsForm.get("parameter").value) { + // Add the parameter directly with its own alias and value + primitiveObjectValue.push({ alias: paramName, value: paramValue }); + } + + // this is the new Primitive Service Characteristics + let primitiveCharacteristic: Characteristic = { + name: "Primitive::"+this.data.primitive.primitive.name, + valueType: "ARRAY", + value: {value: JSON.stringify(primitiveObjectValue), alias:""} + } + + this.data.serviceToBeUpdated.serviceCharacteristic.push(primitiveCharacteristic) + + let serviceUpdate: ServiceUpdate = { + serviceCharacteristic: this.data.serviceToBeUpdated.serviceCharacteristic + } + + this.serviceService.patchService({service: serviceUpdate, id: this.data.serviceToBeUpdated.id}).subscribe( + data => { }, + error => { console.error(error); this.dialogRef.close(error)}, + () => { this.dialogRef.close("updated") } + ) + } +} diff --git a/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.html b/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.html index 54473ed51a175171fd33174b1a3910e94804f31d..7296ad1752769f069bfd7f1f5c53f76ea3df3b46 100644 --- a/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.html +++ b/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.html @@ -43,6 +43,7 @@ <div class="col-xl-10 col-lg-9"> <div class="tab-content"> + <!-- Main Properties tab view --> <div class="tab-pane active" *ngIf="activeListItem === 'Main Properties'" role="tabpanel" [@fadeIn]> <form [formGroup]="editForm"> @@ -236,6 +237,10 @@ </div> + <!-- ENDOF Main Properties tab view --> + + + <!-- Service Characteristics tab view --> <div class="tab-pane active" *ngIf="activeListItem === 'Service Characteristics'" role="tabpanel" [@fadeIn]> <div class="card mat-elevation-z1 bg-light"> @@ -332,7 +337,9 @@ </div> </div> + <!-- ENDOF Service Characteristics tab view --> + <!-- Supporting Services tab view --> <div class="tab-pane active" *ngIf="activeListItem === 'Supporting Services'" role="tabpanel" [@fadeIn]> <div class="card mat-elevation-z1 bg-light"> @@ -348,7 +355,10 @@ </div> </div> + <!-- ENDOF Supporting Services tab view --> + + <!-- Supporting Resources tab view --> <div class="tab-pane active" *ngIf="activeListItem === 'Supporting Resources'" role="tabpanel" [@fadeIn]> <div class="card mat-elevation-z1 bg-light"> @@ -365,6 +375,119 @@ </div> </div> + <!-- ENDOF Service Characteristics tab view --> + + <div class="tab-pane active" *ngIf="activeListItem === 'Contextual Features'" + role="tabpanel" [@fadeIn]> + <div class="card mat-elevation-z1 bg-light"> + <div class="card-body"> + <!-- <div *ngIf="service?.supportingResource.length === 0"> + There are not any Supporting Resources allocated. + </div> + <p *ngFor="let resource of service?.supportingResource" class="mb-2"> + <a *ngIf="resource.id" routerLink='/resources/resource/{{resource.id}}'>{{resource.name}}</a> + <span *ngIf="!resource.id">{{resource.name}}</span> + </p> --> + <div *ngIf="!(vnfPrimListDatasource.data.length || this.NSLCMCharacteristic)"> + There not any Contextual Features available at this service. + </div> + <mat-accordion multi="true" *ngIf="vnfPrimListDatasource.data"> + + <mat-expansion-panel expanded="true" class="no-shadow" *ngIf="this.NSLCMCharacteristic" > + <mat-expansion-panel-header> + <mat-panel-title> + MANO NSLCM + </mat-panel-title> + </mat-expansion-panel-header> + <div style="min-height: auto;"> + <json-editor [options]="jsonEditorOptions" [data]="NSLCMObject" #editor></json-editor> + + </div> + </mat-expansion-panel> + + <mat-expansion-panel expanded="true" class="no-shadow" *ngIf="vnfPrimListDatasource.data.length"> + <mat-expansion-panel-header> + <mat-panel-title> + MANO Primitives List + </mat-panel-title> + </mat-expansion-panel-header> + <div> + + <mat-accordion multi="true" > + + <mat-expansion-panel expanded="true" class="no-shadow"> + <mat-expansion-panel-header> + <mat-panel-title> + VNF-Level Primitives + </mat-panel-title> + </mat-expansion-panel-header> + <div class="filter-container px-3 row"> + <!-- <input class="form-control " (keyup)="applyFilter($event.target.value)" placeholder="Apply Filter..."> --> + <mat-form-field appearance="" class="white-background col-12"> + <mat-label>Apply Filter to VNF Profile IDs...</mat-label> + <input matInput (keyup)="applyVNFPrimListFilter($event.target.value)"> + </mat-form-field> + </div> + <div class="table-responsive mat-elevation-z1" [@fadeIn]> + <table mat-table [dataSource]="vnfPrimListDatasource" matSort class="table table-generic"> + + + <ng-container matColumnDef="VNF Profile ID"> + <th mat-header-cell *matHeaderCellDef> VNF Profile ID </th> + <td mat-cell *matCellDef="let element"> <span *ngIf="element.vnf_id">{{element.vnf_id}}</span> </td> + </ng-container> + + + <ng-container matColumnDef="Primitive"> + <th mat-header-cell *matHeaderCellDef> Primitive </th> + <td mat-cell *matCellDef="let element"> + <span *ngIf="element.primitive?.name">{{element.primitive.name}}</span> + </ng-container> + + + <ng-container matColumnDef="Primitive Parameters"> + <th mat-header-cell *matHeaderCellDef> Primitive Parameters </th> + <td mat-cell *matCellDef="let element"> + <!-- {{element.primitive_params.name}} --> + <div *ngIf="element.primitive?.parameter?.length"> + <div *ngFor="let param of element.primitive.parameter"> + <span *ngIf="param?.name">{{param?.name}}</span> + <span *ngIf="param['data-type']"> ({{param['data-type']}})</span> + </div> + </div> + </td> + </ng-container> + + <ng-container matColumnDef="Actions"> + <th mat-header-cell *matHeaderCellDef>Actions</th> + <td mat-cell *matCellDef="let element"> + + <button class="btn btn-primary btn-sm" matTooltipClass="universal-tooltip" matTooltip="Execute Primitive" + matTooltipPosition="right" (click)="openExecutePrimitiveDialog(element)"><i class="fas fa-scroll"></i></button> + + </td> + </ng-container> + + + <tr mat-header-row *matHeaderRowDef="vnfPrimListDisplayColumns"></tr> + <tr mat-row *matRowDef="let row; columns: vnfPrimListDisplayColumns;"></tr> + </table> + + <mat-paginator [pageSizeOptions]="[20, 50, 100]" showFirstLastButtons></mat-paginator> + </div> + + + + </mat-expansion-panel> + </mat-accordion> + </div> + </mat-expansion-panel> + + </mat-accordion> + </div> + <div class="card-footer"></div> + </div> + </div> </div> </div> </div> diff --git a/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.scss b/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.scss index b102c49acc1a7235c255794b14d240ec3463eb06..471ddc04795775033c4a1d2a84e9d5f0a17543cf 100644 --- a/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.scss +++ b/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.scss @@ -36,4 +36,8 @@ table.table-borderless tbody tr td { mat-form-field { width: 100%; +} + +.no-shadow { + box-shadow: none; } \ No newline at end of file diff --git a/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.ts b/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.ts index 325247e986eef9d2cfe67462ba8b9b1ce67d906c..715e06314352506b5eb4caa1d39134ff3ea3f7c3 100644 --- a/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.ts +++ b/src/app/p_services/admin/serviceActivationAndConfiguration/preview-service/preview-service.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router, ActivationEnd } from '@angular/router'; import { ServiceService } from 'src/app/openApis/serviceInventoryManagement/services'; import { ToastrService } from 'ngx-toastr'; @@ -12,6 +12,12 @@ import { SortingService } from 'src/app/shared/functions/sorting.service'; import { AuthService } from 'src/app/shared/services/auth.service'; import { EditServiceCharacteristicsComponent } from '../edit-service-characteristics/edit-service-characteristics.component'; import { AppService } from 'src/app/shared/services/app.service'; +import { MatTableDataSource } from '@angular/material/table'; +import { MatPaginator } from '@angular/material/paginator'; +import { JsonEditorOptions } from 'ang-jsoneditor'; +import { ExecuteManoServicePrimitiveComponent } from '../execute-mano-service-primitive/execute-mano-service-primitive.component'; +import { HttpErrorResponse } from '@angular/common/http'; + @Component({ selector: 'app-preview-service', @@ -52,10 +58,10 @@ export class PreviewServiceComponent implements OnInit { subscriptions = new Subscription() - listItems = ["Main Properties", "Service Characteristics", "Supporting Services", "Supporting Resources"] + listItems = ["Main Properties", "Service Characteristics", "Supporting Services", "Supporting Resources", "Contextual Features"] activeListItem = "Main Properties" - + jsonEditorOptions = new JsonEditorOptions() ngOnInit() { @@ -65,9 +71,11 @@ export class PreviewServiceComponent implements OnInit { { this.serviceID = this.activatedRoute.snapshot.params.id this.retrieveService() + this.configureJSONEditor() } else { this.newService = true } + } initSubscriptions() { @@ -81,6 +89,45 @@ export class PreviewServiceComponent implements OnInit { )) } + configureJSONEditor() { + this.jsonEditorOptions.mode = "view" + this.jsonEditorOptions.sortObjectKeys = true + this.jsonEditorOptions.name = "NSLCM" + } + + + retrieveService() { + this.serviceService.retrieveService({id: this.serviceID}).subscribe( + data => { + this.service = data + }, + error => { + console.error(error) + }, + () => { + this.finishedLoading = true + if (!this.service) { + this.serviceNotFound = true + } + this.service.serviceCharacteristic.sort(this.sortingService.ascStringSortingFunctionByNameProperty()) + this.service.note.sort(this.sortingService.ascDateSortingFuncByDateProperty()) + this.editForm.patchValue({ + state: this.service.state, + startDate: this.service.startDate, + endDate: this.service.endDate + }) + + // only populate contextual features tab if the service = RFS. "ResourceFacingServiceSpecification" check remains for backwards compatibility, as it has been correctly changed to "ResourceFacingService" + if (this.service.category === "ResourceFacingService" || "ResourceFacingServiceSpecification") { + this.populateContextualFeatures() + } + } + ) + } + + // Main properties Tab block + // + triggerNewNote() { if (this.newNote) this.editForm.get('note').reset() this.newNote = !this.newNote @@ -118,7 +165,6 @@ export class PreviewServiceComponent implements OnInit { }] } - this.serviceService.patchService({service: serviceUpdate, id: this.serviceID}).subscribe( data => { this.toast.success("Service is successfully updated") }, error => { console.error(error), this.toastr.error("An error occurred updating this Service") }, @@ -127,33 +173,35 @@ export class PreviewServiceComponent implements OnInit { this.retrieveService() } ) - } - retrieveService() { - this.serviceService.retrieveService({id: this.serviceID}).subscribe( - data => { - this.service = data - }, - error => { - console.error(error) - }, - () => { - this.finishedLoading = true - if (!this.service) { - this.serviceNotFound = true - } - this.service.serviceCharacteristic.sort(this.sortingService.ascStringSortingFunctionByNameProperty()) - this.service.note.sort(this.sortingService.ascDateSortingFuncByDateProperty()) - this.editForm.patchValue({ - state: this.service.state, - startDate: this.service.startDate, - endDate: this.service.endDate - }) - } - ) + serviceStateClassSelector(state:'feasibilityChecked'| 'designed'| 'reserved'| 'inactive'| 'active'| 'terminated') { + let cssClass: string = 'badge' + switch (state) { + case 'feasibilityChecked': + cssClass += ' badge-primary' + break; + case 'inactive': + cssClass += ' badge-secondary' + break; + case 'terminated': + cssClass += ' badge-danger' + break; + case 'active': + cssClass += ' badge-success' + break; + default: + cssClass += ' badge-warning' + } + return cssClass } + // + // ENDOF Main properties Tab block + + + // Service Characteristics Tab block + // openCharacteristicsEditDialog() { const dialogRef = this.dialog.open(EditServiceCharacteristicsComponent, { data: { @@ -172,26 +220,105 @@ export class PreviewServiceComponent implements OnInit { ) } - serviceStateClassSelector(state:'feasibilityChecked'| 'designed'| 'reserved'| 'inactive'| 'active'| 'terminated') { - let cssClass: string = 'badge' - switch (state) { - case 'feasibilityChecked': - cssClass += ' badge-primary' - break; - case 'inactive': - cssClass += ' badge-secondary' - break; - case 'terminated': - cssClass += ' badge-danger' - break; - case 'active': - cssClass += ' badge-success' - break; - default: - cssClass += ' badge-warning' + // + // ENDOF Service Characteristics Tab block + + + // Contextual Features Tab block + // + NSLCMCharacteristic + NSLCMObject + primitivesListCharacteristic + + vnfPrimListDisplayColumns = ["VNF Profile ID", "Primitive", "Primitive Parameters", "Actions"] + vnfPrimListDatasource = new MatTableDataSource() + @ViewChild(MatPaginator, {static: true}) paginator: MatPaginator; + + populateContextualFeatures() { + this.NSLCMCharacteristic = this.service.serviceCharacteristic.find(el => el.name === "NSLCM") + this.primitivesListCharacteristic = this.service.serviceCharacteristic.find(el => el.name === "PrimitivesList") + + // NSLCM display feature + const NSLCMCharacteristicValue = this.NSLCMCharacteristic?.value?.value + if (NSLCMCharacteristicValue) { + try { + this.NSLCMObject = JSON.parse(NSLCMCharacteristicValue) + } + catch { + this.NSLCMObject = {} + } } - return cssClass + + // Primitives List feature + const primitivesListObjectValue = this.primitivesListCharacteristic?.value?.value + + let primitivesListObject + if (primitivesListObjectValue) { + try { + primitivesListObject = JSON.parse(primitivesListObjectValue) + } + catch { + primitivesListObject = {} + } + } + + if (this.primitivesListCharacteristic && primitivesListObject) { + + // list VNF-level primitives + const vnfPrimitives = primitivesListObject['vnfs'] + if (vnfPrimitives && vnfPrimitives.length) { + let primListDataSource: { "vnf_id":string, "primitive":{"name":string, "parameter"?:{"name":string, "data-type":string}[]} }[] = [] + vnfPrimitives.forEach( vnf => { + if (vnf['config-primitive'] && vnf['config-primitive'].length) { + vnf['config-primitive'].forEach ( primitive => { + // if the vnf primitive has parameters + if (primitive?.parameter && primitive?.parameter?.length) { + primListDataSource.push({"vnf_id":vnf.id, "primitive": {"name":primitive.name, "parameter": primitive.parameter}}) + } + // if the vnf primitive does not have parameters + else { + primListDataSource.push({"vnf_id":vnf.id, "primitive": {"name":primitive.name}}) + } + }) + } + }) + this.vnfPrimListDatasource.data = primListDataSource + this.vnfPrimListDatasource.paginator = this.paginator + } + } + } + + openExecutePrimitiveDialog(element: {"vnf_id":string, "primitive":{"name":string, "parameter"?:{"name":string, "data-type":string}[]}}) { + const dialogRef = this.dialog.open(ExecuteManoServicePrimitiveComponent, { + data: { + primitiveType: "VNF-level Primitive", + serviceToBeUpdated: this.service, + primitive: element + } + }) + + dialogRef.afterClosed().subscribe ( + result => { + if (result instanceof HttpErrorResponse) { + this.toast.error("An error occurred while attempting to queue the service primitive for execution") + } else { + // check if something is returned from the dialog (updated service object) or the dialog is cancelled + if (result) { + this.toast.success("The service primitive was successfully queued for execution. Please check NSLCM for updates.") + this.retrieveService() + } + } + } + ) + } + + applyVNFPrimListFilter(filterValue: string) { + filterValue = filterValue.trim(); + filterValue = filterValue.toLowerCase(); + this.vnfPrimListDatasource.filter = filterValue; } + // + // Contextual Features Tab block ngOnDestroy() { this.subscriptions.unsubscribe() diff --git a/src/app/shared.module.ts b/src/app/shared.module.ts index c09c7d566ec3d5f7b60c5d2a86a81939ee372939..45535914b3f53e2e70b4553397834c665ea93051 100644 --- a/src/app/shared.module.ts +++ b/src/app/shared.module.ts @@ -57,6 +57,7 @@ import {DragDropModule} from '@angular/cdk/drag-drop'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { NgJsonEditorModule } from 'ang-jsoneditor'; @NgModule({ @@ -109,6 +110,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; // OAuthModule.forRoot(), FileUploadModule, MarkdownModule.forRoot(), + NgJsonEditorModule ], entryComponents : [ @@ -162,7 +164,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; ToastrModule, OAuthModule, FileUploadModule, - MarkdownModule + MarkdownModule, + NgJsonEditorModule ], }) export class SharedModule { } diff --git a/src/styles.scss b/src/styles.scss index 54839f3b7f6ddf66c56ecfac1de0d715e776fb40..e5cdf13843eec39cb95fa642700bd58996f916d7 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -3,6 +3,7 @@ // @import "@angular/material/prebuilt-themes/indigo-pink.css"; @import "~@danielmoncada/angular-datetime-picker/assets/style/picker.min.css"; +@import "~jsoneditor/dist/jsoneditor.min.css"; /* override bootstrap's 4 blue color */ $primary: #428bca;