diff options
author | franciscovila <javier.paradela.vila@est.tech> | 2022-11-24 10:29:04 +0000 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2023-01-26 23:32:10 +0000 |
commit | 701e441228724c5b701d94cc3f1e520ce656398a (patch) | |
tree | 5900482086d86f8b8e465e6d4b57db4bd7a94184 /catalog-ui/src/app/ng2/pages | |
parent | 1bbecd7edbdd907a53812d303d378236d23d071e (diff) |
Import data type in UI
Develop all necessary changes in the UI to allow importing a data type from a yaml file
Issue-ID: SDC-4279
Signed-off-by: franciscovila <javier.paradela.vila@est.tech>
Change-Id: Id413386fad8b362e8c4a1d25c859a22178189074
Diffstat (limited to 'catalog-ui/src/app/ng2/pages')
17 files changed, 374 insertions, 39 deletions
diff --git a/catalog-ui/src/app/ng2/pages/home/__snapshots__/home.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/home/__snapshots__/home.component.spec.ts.snap index 42686c1567..dd864d48f7 100644 --- a/catalog-ui/src/app/ng2/pages/home/__snapshots__/home.component.spec.ts.snap +++ b/catalog-ui/src/app/ng2/pages/home/__snapshots__/home.component.spec.ts.snap @@ -12,7 +12,9 @@ exports[`home component should match current snapshot 1`] = ` isDefaultFilter={[Function Function]} loaderService={[Function Object]} modalService={[Function Object]} + modalServiceSdc="undefined" modalsHandler={[Function Object]} + openModalImportType={[Function Function]} resourceService={[Function Object]} sdcConfig={[Function Object]} sdcMenu={[Function Object]} diff --git a/catalog-ui/src/app/ng2/pages/home/home.component.html b/catalog-ui/src/app/ng2/pages/home/home.component.html index 0c2e41eb11..b16b30b2b2 100644 --- a/catalog-ui/src/app/ng2/pages/home/home.component.html +++ b/catalog-ui/src/app/ng2/pages/home/home.component.html @@ -58,6 +58,7 @@ (fileUpload)="onImportService($event)" [convertToBase64]="true" ></sdc-button-file-opener> + <sdc-button *ngIf="roles[user.role].dashboard.showCreateNew" testId="importTypebutton" size="medium" type="secondary" text="Import Type" (click)="openModalImportType()"></sdc-button> </div> </div> </div> diff --git a/catalog-ui/src/app/ng2/pages/home/home.component.spec.ts b/catalog-ui/src/app/ng2/pages/home/home.component.spec.ts index 1c03790e04..2642b9e41b 100644 --- a/catalog-ui/src/app/ng2/pages/home/home.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/home/home.component.spec.ts @@ -7,7 +7,7 @@ import {HomeComponent} from "./home.component"; import {ConfigureFn, configureTests} from "../../../../jest/test-config.helper"; import {NO_ERRORS_SCHEMA} from "@angular/core"; import {TranslateService} from "../../shared/translator/translate.service"; -import {AuthenticationService, CacheService, HomeService, ImportVSPService, ResourceServiceNg2} from '../../../../app/services-ng2'; +import {AuthenticationService, CacheService, HomeService, ImportVSPService, ModalService, ResourceServiceNg2} from '../../../../app/services-ng2'; import {ModalsHandler} from "../../../../app/utils"; import {SdcUiServices} from "onap-ui-angular"; import {ComponentType, ResourceType} from "../../../utils/constants"; @@ -23,6 +23,7 @@ describe('home component', () => { let importVspService: Partial<ImportVSPService>; let mockStateService; let modalServiceMock :Partial<SdcUiServices.ModalService>; + let modalServiceMock_ :Partial<ModalService>; let translateServiceMock : Partial<TranslateService>; let foldersItemsMenuMock; let homeFilterMock :Partial<HomeFilter>; @@ -79,6 +80,7 @@ describe('home component', () => { {provide: TranslateService, useValue: translateServiceMock}, {provide: ModalsHandler, useValue: {}}, {provide: SdcUiServices.ModalService, useValue: modalServiceMock}, + {provide: ModalService, useValue: modalServiceMock_}, {provide: SdcUiServices.LoaderService, useValue: loaderServiceMock}, {provide: ImportVSPService, useValue: {}}, {provide: ResourceServiceNg2, useValue: resourceServiceNg2Mock} diff --git a/catalog-ui/src/app/ng2/pages/home/home.component.ts b/catalog-ui/src/app/ng2/pages/home/home.component.ts index 784823eacd..666b36eb8e 100644 --- a/catalog-ui/src/app/ng2/pages/home/home.component.ts +++ b/catalog-ui/src/app/ng2/pages/home/home.component.ts @@ -19,10 +19,20 @@ */ 'use strict'; import {Component as NgComponent, Inject, OnInit} from '@angular/core'; -import {Component, ComponentMetadata, IConfigRoles, IUserProperties, Resource, Service} from 'app/models'; +import { + ButtonModel, + Component, + ComponentMetadata, + IConfigRoles, + IUserProperties, + ModalModel, + Resource, + Service +} from 'app/models'; +import {ModalService} from "../../services/modal.service"; import {HomeFilter} from 'app/models/home-filter'; import {AuthenticationService, CacheService, HomeService, ResourceServiceNg2} from 'app/services-ng2'; -import {ComponentState, ModalsHandler} from 'app/utils'; +import {ComponentState, ModalsHandler, States} from 'app/utils'; import {SdcUiServices} from 'onap-ui-angular'; import {CHANGE_COMPONENT_CSAR_VERSION_FLAG, ComponentType, ResourceType} from '../../../utils/constants'; import {ImportVSPService} from '../../components/modals/onboarding-modal/import-vsp.service'; @@ -33,6 +43,7 @@ import {TranslateService} from '../../shared/translator/translate.service'; import {FoldersItemsMenu, FoldersItemsMenuGroup, FoldersMenu} from './folders'; import {ImportVSPdata} from "../../components/modals/onboarding-modal/onboarding-modal.component"; import {DataTypeCatalogComponent} from "../../../models/data-type-catalog-component"; +import {ModalImportTypeComponent} from "../../components/ui/modal-import-type/modal-import-type.component"; @NgComponent({ selector: 'home-page', @@ -64,6 +75,7 @@ export class HomeComponent implements OnInit { private translateService: TranslateService, private modalsHandler: ModalsHandler, private modalService: SdcUiServices.ModalService, + private modalServiceSdc: ModalService, private loaderService: SdcUiServices.LoaderService, private importVSPService: ImportVSPService, private resourceService: ResourceServiceNg2 @@ -398,4 +410,41 @@ export class HomeComponent implements OnInit { this.notificationIconCallback = this.notificationIconCallback.bind(this); } + openModalImportType = () => { + let modalTitle = 'Import Type'; + let modal = this.modalServiceSdc.createCustomModal(new ModalModel( + 'sm', + modalTitle, + null, + [ + new ButtonModel('Import', 'blue', () => + { this.uploadDataTypeFile(modal.instance.dynamicContent.instance.file); modal.instance.close();}, () => false), + new ButtonModel('Cancel', 'outline grey', () => { + modal.instance.close(); + }), + ], + null + )); + this.modalServiceSdc.addDynamicContentToModal(modal, ModalImportTypeComponent, {}); + modal.instance.open(); + } + + private uploadDataTypeFile(file: any): void { + if (file && file.name) { + // Check that the file has valid extension. + const fileExtension: string = file.name.split('.').pop(); + if (this.sdcConfig.toscaFileExtension.indexOf(fileExtension.toLowerCase()) !== -1) { + this.$state.go(States.TYPE_WORKSPACE, { + type: "datatype", + subPage: "general", + id: "import", + importedFile: file + }); + } else { + const title: string = this.translateService.translate('NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS_TITLE'); + const message: string = this.translateService.translate('NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS', {extensions: this.sdcConfig.toscaFileExtension}); + this.modalService.openWarningModal(title, message, 'error-invalid-tosca-ext'); + } + } + } } diff --git a/catalog-ui/src/app/ng2/pages/home/home.module.ts b/catalog-ui/src/app/ng2/pages/home/home.module.ts index 1a397b44be..acfc299a31 100644 --- a/catalog-ui/src/app/ng2/pages/home/home.module.ts +++ b/catalog-ui/src/app/ng2/pages/home/home.module.ts @@ -7,6 +7,7 @@ import { GlobalPipesModule } from "../../pipes/global-pipes.module"; import { TranslateModule } from "../../shared/translator/translate.module"; import { SdcUiComponentsModule } from "onap-ui-angular"; import { ResourceServiceNg2 } from "../../services/component-services/resource.service"; +import {ModalImportTypeComponent} from "../../components/ui/modal-import-type/modal-import-type.component"; @NgModule({ declarations: [ @@ -19,12 +20,14 @@ import { ResourceServiceNg2 } from "../../services/component-services/resource.s UiElementsModule, GlobalPipesModule, TranslateModule + ], exports: [ HomeComponent ], entryComponents: [ - HomeComponent + HomeComponent, + ModalImportTypeComponent ], providers: [ResourceServiceNg2] }) diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.html b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.html index 877c58bd58..04c334eee1 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.html +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.html @@ -33,9 +33,14 @@ <div class="i-sdc-form-item"> <label class="i-sdc-form-label" [ngClass]="{'required': !isViewOnly}">{{'MODEL_LABEL' | translate}}:</label> - <span>{{dataType.model ? dataType.model : DEFAULT_MODEL_NAME}}</span> + <span *ngIf="isViewOnly">{{dataType.model ? dataType.model : DEFAULT_MODEL_NAME}}</span> + <select *ngIf="!isViewOnly" formControlName="model" (change)="onModelChange()"> + <option *ngFor="let model of models" + [value]="model.name">{{model.name}}</option> + </select> </div> + <div class="i-sdc-form-item"> <label class="i-sdc-form-label" [ngClass]="{'required': !isViewOnly}">{{'DERIVED_FROM_LABEL' | translate}}:</label> <span>{{dataType.derivedFromName}}</span> @@ -44,12 +49,12 @@ </div> <div class="i-sdc-form-item description-field"> - <label class="i-sdc-form-label" [ngClass]="{'required': !isViewOnly}">{{'DESCRIPTION_LABEL' | translate}}:</label> - <textarea class="description" + <label class="i-sdc-form-label">{{'DESCRIPTION_LABEL' | translate}}:</label> + <textarea class="description" #description formControlName="description" - [ngClass]="{'view-mode': isViewOnly}" - [required]="true" + [ngClass]="{'view-mode': true}" [attr.test-id]="description" + [(ngModel)]="dataType.description" [value]="dataType.description"></textarea> </div> </div> diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.spec.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.spec.ts index fe7b070354..1484954e4b 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.spec.ts @@ -25,22 +25,53 @@ import {TypeWorkspaceGeneralComponent} from './type-workspace-general.component' import {ReactiveFormsModule} from "@angular/forms"; import {TranslateModule} from "../../../shared/translator/translate.module"; import {TranslateService} from "../../../shared/translator/translate.service"; +import {SdcUiComponentsModule} from "onap-ui-angular/dist"; +import {Observable} from "rxjs/Observable"; +import {DataTypeModel} from "../../../../models/data-types"; +import {DataTypeService} from "../../../services/data-type.service"; +import {ModelService} from "../../../services/model.service"; +import {IWorkspaceViewModelScope} from "../../../../view-models/workspace/workspace-view-model"; +import {IScope} from "angular"; +import {States} from "../../../../utils/constants"; describe('TypeWorkspaceGeneralComponent', () => { let component: TypeWorkspaceGeneralComponent; let fixture: ComponentFixture<TypeWorkspaceGeneralComponent>; + let dataTypeServiceMock: Partial<DataTypeService>; + let modelServiceMock: Partial<ModelService>; let translateServiceMock: Partial<TranslateService> = { 'translate': jest.fn() }; + let importedFileMock: File = null; + let stateParamsMock: Partial<ng.ui.IStateParamsService> = { + 'importedFile': importedFileMock + }; + let resolveMock = {"$stateParams": stateParamsMock}; + let parentScopeMock: Partial<IScope> = { + '$resolve': resolveMock + }; + let scopeMock_: Partial<IWorkspaceViewModelScope> = { + '$parent': parentScopeMock, + 'current': { + 'name': States.TYPE_WORKSPACE + } + } + beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ TypeWorkspaceGeneralComponent ], imports: [ ReactiveFormsModule, + SdcUiComponentsModule, TranslateModule ], providers: [ + {provide: TranslateService, useValue: translateServiceMock}, + {provide: "$scope", useValue: scopeMock_ }, + {provide: "$state", useValue: {}}, + {provide: DataTypeService, useValue: dataTypeServiceMock}, + {provide: ModelService, useValue: modelServiceMock}, {provide: TranslateService, useValue: translateServiceMock} ] }) @@ -50,6 +81,7 @@ describe('TypeWorkspaceGeneralComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(TypeWorkspaceGeneralComponent); component = fixture.componentInstance; + component.dataTypeMap$ = new Observable<Map<string, DataTypeModel>>(); fixture.detectChanges(); }); diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.ts index 8728c3020e..a6e4d1efeb 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.ts @@ -19,10 +19,20 @@ * ============LICENSE_END========================================================= */ -import {Component, Input, OnInit} from '@angular/core'; +import {Component, EventEmitter, Inject, Input, OnInit, Output} from '@angular/core'; import {FormControl, FormGroup, Validators} from "@angular/forms"; import {DataTypeModel} from "../../../../models/data-types"; -import { DEFAULT_MODEL_NAME } from "app/utils/constants"; +import {DEFAULT_MODEL_NAME} from "app/utils/constants"; +import {IWorkspaceViewModelScope} from "../../../../view-models/workspace/workspace-view-model"; +import {ServiceDataTypeReader} from "../../../../utils/service-data-type-reader"; +import {TranslateService} from "../../../shared/translator/translate.service"; +import {SdcUiServices} from "onap-ui-angular/dist"; +import {ModelService} from "../../../services/model.service"; +import {Model} from "../../../../models/model"; +import {DataTypesMap} from "../../../../models/data-types-map"; +import {DataTypeService} from "../../../services/data-type.service"; +import {Observable} from "rxjs/Observable"; +import {IDropDownOption} from "onap-ui-angular/dist/form-elements/dropdown/dropdown-models"; @Component({ selector: 'app-type-workspace-general', @@ -30,9 +40,18 @@ import { DEFAULT_MODEL_NAME } from "app/utils/constants"; styleUrls: ['./type-workspace-general.component.less'] }) export class TypeWorkspaceGeneralComponent implements OnInit { + @Input() isViewOnly = true; @Input() dataType: DataTypeModel = new DataTypeModel(); - + @Output() onImportedType = new EventEmitter<any>(); + importedFile: File; + models: Array<Model>; + selectedModelName: string; + dataTypes: DataTypesMap; + derivedFromName: string; + dataTypeMap$: Observable<Map<string, DataTypeModel>>; + dataTypeMap: Map<string, DataTypeModel>; + typeOptions: Array<IDropDownOption>; DEFAULT_MODEL_NAME = DEFAULT_MODEL_NAME; type: FormControl = new FormControl(undefined, [Validators.required, Validators.minLength(1), Validators.maxLength(300)]); @@ -46,17 +65,92 @@ export class TypeWorkspaceGeneralComponent implements OnInit { 'derivedFrom': this.derivedFrom }); + constructor(@Inject('$scope') private $scope: IWorkspaceViewModelScope, + @Inject('$state') private $state: ng.ui.IStateService, + protected dataTypeService: DataTypeService, + private modalServiceSdcUI: SdcUiServices.ModalService, + private modelService: ModelService, + private translateService: TranslateService) { + this.typeOptions = []; + } + ngOnInit(): void { + this.getImportedFile(); + if (!this.isViewOnly) { + console.log("file size: " + this.importedFile.size); + console.log("file type: " + this.importedFile.type); + console.log("file lastModifiedDate: " + this.importedFile.lastModifiedDate); + + new ServiceDataTypeReader().read(this.importedFile).then( + (serviceType) => { + this.dataType = serviceType; + this.dataType.modificationTime = this.importedFile.lastModifiedDate; + this.dataType.creationTime = this.importedFile.lastModifiedDate; + this.derivedFromName = serviceType.derivedFromName; + this.dataType.uniqueId = this.dataType.model ? this.dataType.model + "." + this.dataType.name : this.dataType.name + ".datatype"; + this.$scope.dataType = this.dataType; + this.onImportedType.emit(this.dataType); + + this.models = []; + this.modelService.getDataTypeModels(this.derivedFromName).subscribe((modelsFound: any) => { + modelsFound.sort().forEach(modelName => { + let model:Model; + if (modelName === null || "" === modelName) { + model = new Model({"name": DEFAULT_MODEL_NAME, "derivedFrom": "", "modelType": "normative"}); + } + else { + model = new Model({"name": modelName, "derivedFrom": "", "modelType": "normative"}); + } + this.models.push(model); + }); + this.onModelChange(); + this.$scope.dataType = this.dataType; + }); + + }, + (error) => { + const errorMsg = this.translateService.translate('IMPORT_DATA_TYPE_FAILURE_MESSAGE_TEXT'); + console.error(errorMsg, error); + const errorDetails = { + 'Error': error.reason, + 'Details': error.message + }; + console.error(error.reason); + this.modalServiceSdcUI.openErrorDetailModal('Error', errorMsg, + 'error-modal', errorDetails); + this.$state.go('dashboard'); + }); + } this.initForm(); } + onModelChange(): void { + this.selectedModelName = this.models.filter(x => x.name == this.model.value).pop().name; + console.log("selected model: " + this.selectedModelName); + this.dataType.model = new Model({"name": this.selectedModelName, "derivedFrom": "", "modelType": "normative"}); + this.dataType.uniqueId = this.dataType.model.name === DEFAULT_MODEL_NAME ? + this.dataType.name + ".datatype" : this.dataType.model.name + "." + this.dataType.name + ".datatype"; + this.$scope.dataType.derivedFromName = this.derivedFromName; + this.$scope.dataType = this.dataType; + this.$scope.dataType.model = this.dataType.model; + } + + private getImportedFile(): void { + let importedFile = this.$scope["$parent"]["$resolve"]["$stateParams"]["importedFile"]; + this.importedFile = <File>importedFile; + this.$scope.importFile = this.importedFile; + if (this.importedFile) { + this.isViewOnly = false; + } + } + private initForm(): void { if (!this.dataType) { return; } this.type.setValue(this.dataType.name); this.description.setValue(this.dataType.description); - this.model.setValue(this.dataType.model); - this.derivedFrom.setValue(this.dataType.derivedFrom); + this.model.setValue(this.dataType.model ? this.dataType.model : this.$scope.dataType && this.$scope.dataType.model ? this.$scope.dataType.model : DEFAULT_MODEL_NAME); + this.derivedFrom.setValue(this.dataType.derivedFromName); } } diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts index e6e9c12d14..f89be56359 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts @@ -31,6 +31,10 @@ import {DataTypeModel} from "../../../../models/data-types"; import {Component, ViewChild} from "@angular/core"; import {PropertyBEModel} from "../../../../models/properties-inputs/property-be-model"; import {ModalService} from "../../../services/modal.service"; +import {IScope} from "../../../../../typings/angularjs/angular"; +import {IWorkspaceViewModelScope} from "../../../../view-models/workspace/workspace-view-model"; +import {States} from "../../../../utils/constants"; +import {SdcUiServices} from "onap-ui-angular/dist"; describe('TypeWorkspacePropertiesComponent', () => { const messages = require("../../../../../assets/languages/en_US.json"); @@ -54,6 +58,28 @@ describe('TypeWorkspacePropertiesComponent', () => { return messages[translateKey]; }) }; + let importedFileMock: File = null; + let stateParamsMock: Partial<ng.ui.IStateParamsService> = { + 'importedFile': importedFileMock + }; + let resolveMock = {"$stateParams": stateParamsMock}; + let parentScopeMock: Partial<IScope> = { + '$resolve': resolveMock + }; + let scopeMock_: Partial<IWorkspaceViewModelScope> = { + '$parent': parentScopeMock, + 'current': { + 'name': States.TYPE_WORKSPACE + } + } + let stateMock: Partial<ng.ui.IStateService> = { + 'current': { + 'name': States.TYPE_WORKSPACE + } + }; + + let modalServiceSdcUIMock: Partial<SdcUiServices.ModalService>; + let modalServiceMock: Partial<ModalService>; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -65,6 +91,10 @@ describe('TypeWorkspacePropertiesComponent', () => { providers: [ {provide: DataTypeService, useValue: dataTypeServiceMock}, {provide: TranslateService, useValue: translateServiceMock}, + {provide: SdcUiServices.ModalService, useValue: modalServiceSdcUIMock}, + {provide: ModalService, useValue: modalServiceMock}, + {provide: "$scope", useValue: scopeMock_}, + {provide: '$state', useValue: stateMock}, {provide: ModalService, useValue: modalService} ] }) diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts index f53ad5b376..bcc5fe9c28 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts @@ -19,7 +19,7 @@ * ============LICENSE_END========================================================= */ -import {Component, Input, OnInit} from '@angular/core'; +import {Component, Inject, Input, OnInit} from '@angular/core'; import {DataTypeModel} from "../../../../models/data-types"; import {DataTypeService} from "../../../services/data-type.service"; import {PropertyBEModel} from "../../../../models/properties-inputs/property-be-model"; @@ -30,6 +30,8 @@ import {ModalModel} from "../../../../models/modal"; import {ButtonModel} from "../../../../models/button"; import {TranslateService} from "../../../shared/translator/translate.service"; import {AddPropertyComponent, PropertyValidationEvent} from "./add-property/add-property.component"; +import {IWorkspaceViewModelScope} from "../../../../view-models/workspace/workspace-view-model"; +import {SdcUiServices} from "onap-ui-angular/dist"; @Component({ selector: 'app-type-workspace-properties', @@ -40,6 +42,8 @@ export class TypeWorkspacePropertiesComponent implements OnInit { @Input() isViewOnly = true; @Input() dataType: DataTypeModel = new DataTypeModel(); + importedFile: File; + derivedFromName: string; properties: Array<PropertyBEModel> = []; filteredProperties: Array<PropertyBEModel> = []; tableHeadersList: Array<TableHeader> = []; @@ -48,7 +52,12 @@ export class TypeWorkspacePropertiesComponent implements OnInit { tableFilterTerm: string = undefined; tableSearchTermUpdate = new Subject<string>(); - constructor(private dataTypeService: DataTypeService, private modalService: ModalService, private translateService: TranslateService) { + constructor(@Inject('$scope') private $scope: IWorkspaceViewModelScope, + @Inject('$state') private $state: ng.ui.IStateService, + protected dataTypeService: DataTypeService, + private modalServiceSdcUI: SdcUiServices.ModalService, + private modalService: ModalService, + private translateService: TranslateService) { } ngOnInit(): void { @@ -70,22 +79,12 @@ export class TypeWorkspacePropertiesComponent implements OnInit { {title: 'Required', property: 'required'}, {title: 'Description', property: 'description'}, ]; - this.tableSortBy = this.tableHeadersList[0].property; } private initProperties(): void { this.dataTypeService.findAllProperties(this.dataType.uniqueId).subscribe(properties => { - this.properties = properties.map(value => { - const property = new PropertyBEModel(value); - if (property.defaultValue) { - property.defaultValue = JSON.parse(property.defaultValue); - } - - return property; - }); - this.filteredProperties = Array.from(this.properties); - this.sort(); + this.showPropertiesMap(properties); }); } @@ -188,6 +187,19 @@ export class TypeWorkspacePropertiesComponent implements OnInit { onRowClick(property: PropertyBEModel) { this.openAddPropertyModal(property, true); } + + private showPropertiesMap(properties: Array<PropertyBEModel>): void { + this.properties = properties.map(value => { + const property = new PropertyBEModel(value); + if (property.defaultValue) { + property.defaultValue = JSON.parse(property.defaultValue); + } + + return property; + }); + this.filteredProperties = Array.from(this.properties); + this.sort(); + } } interface TableHeader { diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html index 105c89d7a4..cdd8e41503 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html @@ -32,6 +32,8 @@ <div class="progress-container"> </div> <div class="sdc-workspace-top-bar-buttons"> + <button *ngIf="!isViewOnly" data-ng-disabled="!isValidForm || isDisableMode() || isLoading || unsavedChanges" (click)="createImportType()" class="tlv-btn outline green" data-tests-id="create/save">Create</button> + <span *ngIf="!isViewOnly" class="delimiter"></span> <span class="sprite-new x-btn" (click)="goToBreadcrumbHome()" sdc-smart-tooltip="Close" [title]="'CLOSE_LABEL' | translate"></span> </div> </div> @@ -43,7 +45,7 @@ </div> </div> <div class="w-sdc-main-container-body-content" *ngIf="dataType"> - <app-type-workspace-general *ngIf="currentMenu.state === 'general'" [dataType]="dataType"></app-type-workspace-general> + <app-type-workspace-general *ngIf="currentMenu.state === 'general'" [dataType]="dataType" (onImportedType)="onImportedType($event)"></app-type-workspace-general> <app-type-workspace-properties *ngIf="currentMenu.state === 'properties'" [dataType]="dataType" [isViewOnly]="dataType.normative"></app-type-workspace-properties> <app-type-workspace-tosca-artifact *ngIf="currentMenu.state === 'tosca_artifacts'" [dataType]="dataType"></app-type-workspace-tosca-artifact> </div> diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts index 3db2504564..a5cf20f4e9 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts @@ -41,6 +41,10 @@ import {TypeWorkspacePropertiesComponent} from "./type-workspace-properties/type import {TypeWorkspaceToscaArtifactPageComponent} from "./type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component"; import {NgxDatatableModule} from "@swimlane/ngx-datatable"; import {SvgIconModule} from "onap-ui-angular/dist/svg-icon/svg-icon.module"; +import {NO_ERRORS_SCHEMA} from "@angular/core"; +import {IScope} from "angular"; +import {IWorkspaceViewModelScope} from "../../../view-models/workspace/workspace-view-model"; +import {ModelService} from "../../services/model.service"; describe('TypeWorkspaceComponent', () => { let component: TypeWorkspaceComponent; @@ -50,6 +54,7 @@ describe('TypeWorkspaceComponent', () => { 'translate': jest.fn() }; let dataTypeServiceMock: Partial<DataTypeService>; + let notificationMock: Partial<any>; let cacheService: Partial<CacheService> = { 'get': jest.fn(param => { if (param === 'version') { @@ -65,7 +70,7 @@ describe('TypeWorkspaceComponent', () => { 'name': States.TYPE_WORKSPACE } }; - let stateParamsMock: Partial<ng.ui.IStateParamsService> = {}; + let injectorMock: Partial<ng.auto.IInjectorService> = { 'get': jest.fn(param => { if (param === '$state') { @@ -89,6 +94,21 @@ describe('TypeWorkspaceComponent', () => { return user; }) }; + let importedFileMock: File = null; + let stateParamsMock: Partial<ng.ui.IStateParamsService> = { + 'importedFile': importedFileMock + }; + let resolveMock = {"$stateParams": stateParamsMock}; + let parentScopeMock: Partial<IScope> = { + '$resolve': resolveMock + }; + let scopeMock_: Partial<IWorkspaceViewModelScope> = { + '$parent': parentScopeMock, + 'current': { + 'name': States.TYPE_WORKSPACE + } + } + let modelServiceMock: Partial<ModelService>; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -102,10 +122,14 @@ describe('TypeWorkspaceComponent', () => { NgxDatatableModule, SvgIconModule ], + schemas: [NO_ERRORS_SCHEMA], providers: [ {provide: DataTypeService, useValue: dataTypeServiceMock}, {provide: TranslateService, useValue: translateServiceMock}, {provide: CacheService, useValue: cacheService}, + {provide: "Notification", useValue: notificationMock }, + {provide: ModelService, useValue: modelServiceMock}, + {provide: "$scope", useValue: scopeMock_ }, {provide: '$state', useValue: stateMock}, {provide: '$stateParams', useValue: stateParamsMock}, {provide: '$injector', useValue: injectorMock}, diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.ts index d0d5ae8c69..e0f7ac77a0 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.ts @@ -19,11 +19,17 @@ * ============LICENSE_END========================================================= */ -import {Component, Inject, OnInit} from '@angular/core'; +import {Component, Inject, Injector, OnInit} from '@angular/core'; import {MenuItem, MenuItemGroup} from "../../../utils/menu-handler"; import {CacheService} from "../../services/cache.service"; import {DataTypeModel} from "../../../models/data-types"; import {DataTypeService} from "../../services/data-type.service"; +import {IWorkspaceViewModelScope} from "../../../view-models/workspace/workspace-view-model"; +import {TranslateService} from "../../shared/translator/translate.service"; +import {HttpErrorResponse} from "@angular/common/http"; +import {ServerErrorResponse} from "../../../models/server-error-response"; +import {Observable} from "rxjs/Observable"; +import {SdcUiServices} from "onap-ui-angular/dist"; @Component({ selector: 'app-type-workspace', @@ -33,27 +39,32 @@ import {DataTypeService} from "../../services/data-type.service"; export class TypeWorkspaceComponent implements OnInit { private typeMenuItemGroup: MenuItemGroup; - isLoading: boolean; disabled: boolean; isViewOnly: boolean = true; sdcVersion: string; breadcrumbsModel: Array<MenuItemGroup> = []; dataType: DataTypeModel = new DataTypeModel(); + importedDataType: DataTypeModel = new DataTypeModel(); currentMenu: MenuItem; - constructor(private dataTypeService: DataTypeService, private cacheService: CacheService, + constructor(@Inject('$scope') private $scope: IWorkspaceViewModelScope, + private dataTypeService: DataTypeService, private cacheService: CacheService, + @Inject('Notification') private Notification: any, + private translateService: TranslateService, @Inject('$state') private $state: ng.ui.IStateService, - @Inject('$stateParams') private stateParams) { } + @Inject('$stateParams') private stateParams, + private injector: Injector) { } ngOnInit(): void { this.sdcVersion = this.cacheService.get('version'); this.typeMenuItemGroup = this.createTypeBreadcrumb(); + this.loadDataType(); } private loadDataType(): void { - if (this.stateParams.id) { + if (this.stateParams.id && this.stateParams.id != "import") { this.dataTypeService.findById(this.stateParams.id).subscribe(dataType => { this.dataType = dataType; this.updateTypeBreadcrumb(); @@ -61,11 +72,49 @@ export class TypeWorkspaceComponent implements OnInit { console.debug('Could not find data type %s', this.stateParams.id, error); this.goToBreadcrumbHome(); }); + this.isViewOnly = true; } else { + + this.isViewOnly = false; this.dataType = new DataTypeModel(); } } + onImportedType(dataType) { + this.typeMenuItemGroup.updateSelectedMenuItemText(`Data Type: ${dataType.name}`); + } + + private createImportType() { + if (this.$scope.dataType.derivedFromName != undefined && this.$scope.dataType.model != undefined) { + this.dataTypeService.createImportedType(this.$scope.dataType.model.name, this.$scope.importFile) + .subscribe(response => { + this.importedDataType = new DataTypeModel(response); + this.Notification.success({ + message: this.$scope.dataType.name + ' ' + this.translateService.translate('IMPORT_DATA_TYPE_SUCCESS_MESSAGE_TEXT'), + title: this.translateService.translate('IMPORT_DATA_TYPE_TITLE_TEXT') + }); + this.$state.go(this.$state.current.name, {importedFile: null, id: this.$scope.dataType.uniqueId, isViewOnly: true}, {reload: true}); + }, error => {//because overriding http interceptor + if (error instanceof HttpErrorResponse) { + const errorResponse: ServerErrorResponse = new ServerErrorResponse(error); + const modalService = this.injector.get(SdcUiServices.ModalService); + const errorDetails = { + 'Error Code': errorResponse.status != 409 ? errorResponse.messageId : "Data Type already exists", + 'Status Code': errorResponse.status + }; + modalService.openErrorDetailModal('Error', errorResponse.status != 409 ? errorResponse.message : "Data Type already exists", 'error-modal', errorDetails); + return Observable.throwError(error); + } + }); + } + else { + this.Notification.error({ + message: this.$scope.dataType.name + ' ' + "Derived from is invalid in file", + title: this.translateService.translate('IMPORT_DATA_TYPE_TITLE_TEXT') + }); + } + } + private updateTypeBreadcrumb(): void { this.typeMenuItemGroup.updateSelectedMenuItemText(`Data Type: ${this.dataType.name}`); } @@ -82,10 +131,15 @@ export class TypeWorkspaceComponent implements OnInit { onMenuUpdate(menuItemGroup: MenuItemGroup): void { this.breadcrumbsModel.push(...[this.typeMenuItemGroup, menuItemGroup]); + if (!this.isViewOnly) { + this.$scope.leftBarTabs.menuItems.forEach((item: MenuItem) => { + item.isDisabled = ('general' !== item.state); + item.disabledCategory = ('general' !== item.state); + }); + } } onMenuClick(menuItem: MenuItem): void { this.currentMenu = menuItem; } - } diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts index 87b29b615d..e7ddb46602 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts @@ -38,6 +38,7 @@ import {TypeWorkspaceToscaArtifactPageComponent} from "./type-workspace-tosca-ar import {ModalService} from "../../services/modal.service"; import {AddPropertyComponent} from './type-workspace-properties/add-property/add-property.component'; import {InterfaceOperationHandlerModule} from "../composition/interface-operatons/operation-creator/interface-operation-handler.module"; +import {AutoCompleteModule} from "onap-ui-angular/dist/autocomplete/autocomplete.module"; @NgModule({ imports: [ @@ -51,6 +52,7 @@ import {InterfaceOperationHandlerModule} from "../composition/interface-operaton InterfaceOperationHandlerModule, NgxDatatableModule, SvgIconModule, + AutoCompleteModule ], declarations: [ TypeWorkspaceComponent, @@ -64,7 +66,8 @@ import {InterfaceOperationHandlerModule} from "../composition/interface-operaton CacheService, WorkspaceMenuComponent, DataTypeService, - ModalService + ModalService, + FileReader ], entryComponents: [TypeWorkspaceComponent, AddPropertyComponent], exports: [TypeWorkspaceComponent] diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.html b/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.html index 18c6949b46..02d2683c9d 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.html +++ b/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.html @@ -25,8 +25,8 @@ </div> <div class="i-sdc-designer-sidebar-section-content-item" [ngClass]="{'selected': isSelected(menuItem)}" - *ngFor="let menuItem of leftBarTabs.menuItems"> - <div class="expand-collapse-menu-box-item-text" ng-class="{'disabled': menuItem.isDisabled }"> + *ngFor="let menuItem of $scope.leftBarTabs.menuItems"> + <div class="expand-collapse-menu-box-item-text" [ngClass]="{ 'disabled': menuItem.isDisabled }"> <button [attr.data-tests-id]="menuItem.text + 'LeftSideMenu'" type="button" class="i-sdc-designer-sidebar-section-content-item-service-cat" (click)="menuItem.callback()" [disabled]="menuItem.disabledCategory">{{menuItem.text}}</button> </div> diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.spec.ts b/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.spec.ts index a91258c00e..d9bb8833cd 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.spec.ts @@ -26,6 +26,8 @@ import {CacheService} from "../../../services/cache.service"; import {States} from "../../../../utils/constants"; import {IAppMenu} from "../../../../models/app-config"; import {SdcMenuToken} from "../../../config/sdc-menu.config"; +import {IScope} from "../../../../../typings/angularjs/angular"; +import {IWorkspaceViewModelScope} from "../../../../view-models/workspace/workspace-view-model"; describe('WorkspaceMenuComponent', () => { let component: WorkspaceMenuComponent; @@ -59,6 +61,20 @@ describe('WorkspaceMenuComponent', () => { } }) }; + let importedFileMock: File = null; + let stateParamsMock: Partial<ng.ui.IStateParamsService> = { + 'importedFile': importedFileMock + }; + let resolveMock = {"$stateParams": stateParamsMock}; + let parentScopeMock: Partial<IScope> = { + '$resolve': resolveMock + }; + let scopeMock_: Partial<IWorkspaceViewModelScope> = { + '$parent': parentScopeMock, + 'current': { + 'name': States.TYPE_WORKSPACE + } + } beforeEach(async(() => { TestBed.configureTestingModule({ @@ -66,6 +82,7 @@ describe('WorkspaceMenuComponent', () => { providers: [ {provide: CacheService, useValue: cacheService}, {provide: '$injector', useValue: injectorMock}, + {provide: "$scope", useValue: scopeMock_ }, {provide: SdcMenuToken, useValue: sdcMenuMock} ] }) diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.ts b/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.ts index c5e49d4d7d..ee4f3a84bd 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.ts @@ -25,6 +25,7 @@ import {CacheService} from "../../../services/cache.service"; import {IAppMenu} from "../../../../models/app-config"; import {IUserProperties} from "../../../../models/user"; import {SdcMenuToken} from "../../../config/sdc-menu.config"; +import {IWorkspaceViewModelScope} from "../../../../view-models/workspace/workspace-view-model"; @Component({ selector: 'app-workspace-menu', @@ -44,7 +45,10 @@ export class WorkspaceMenuComponent implements OnInit { leftBarTabs: MenuItemGroup = new MenuItemGroup(); - constructor(private cacheService: CacheService, @Inject(SdcMenuToken) private sdcMenu: IAppMenu, @Inject('$injector') $injector) { + constructor(private cacheService: CacheService, + @Inject('$scope') private $scope: IWorkspaceViewModelScope, + @Inject(SdcMenuToken) private sdcMenu: IAppMenu, + @Inject('$injector') $injector) { this.$state = $injector.get('$state'); this.$q = $injector.get('$q'); } @@ -70,6 +74,7 @@ export class WorkspaceMenuComponent implements OnInit { return menuItem; }); this.updateSelectedMenuItem(); + this.$scope.leftBarTabs = this.leftBarTabs; this.onMenuUpdate.emit(this.leftBarTabs); } |