Add data type view/workspace 14/131314/4
authorandre.schmid <andre.schmid@est.tech>
Fri, 23 Sep 2022 11:31:12 +0000 (12:31 +0100)
committerMichael Morris <michael.morris@est.tech>
Wed, 5 Oct 2022 08:18:25 +0000 (08:18 +0000)
Implements a data type workspace, based on the Service/VF workspace,
where it is possible to view a data type information.

Issue-ID: SDC-4193
Signed-off-by: André Schmid <andre.schmid@est.tech>
Change-Id: Ica341efa43e70b4ac85d42d22a1397e0ab6e2794

29 files changed:
catalog-ui/configurations/menu.js
catalog-ui/src/app/app.ts
catalog-ui/src/app/models/data-types.ts
catalog-ui/src/app/modules/directive-module.ts
catalog-ui/src/app/modules/view-model-module.ts
catalog-ui/src/app/ng2/app.module.ts
catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts
catalog-ui/src/app/ng2/config/sdc-menu.config.factory.ts
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.html [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.less [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.spec.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.less [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.html [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.less [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.spec.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/services/cookie.service.ts
catalog-ui/src/app/ng2/services/data-type.service.ts
catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts
catalog-ui/src/app/services/data-types-service.ts
catalog-ui/src/app/utils/constants.ts
catalog-ui/src/app/view-models/workspace/workspace-view-model.ts
catalog-ui/src/assets/languages/en_US.json
integration-tests/environments/plugins-configuration.yaml

index 38f504b..4b462b7 100644 (file)
@@ -299,6 +299,9 @@ const SDC_MENU_CONFIG = {
             {"text": "Deployment", "action": "onMenuItemPressed", "state": "workspace.deployment"},
             {"text": "Properties Assignment", "action": "onMenuItemPressed", "state": "workspace.properties_assignment"},
             {"text": "Attributes & Outputs", "action": "onMenuItemPressed", "state": "workspace.attributes_outputs"}
+        ],
+        "DataType": [
+            {"text": "General", "action": "onMenuItemPressed", "state": "general"},
         ]
     }
 
index e7e2828..ba9bd44 100644 (file)
@@ -29,12 +29,7 @@ import './modules/directive-module.ts';
 import './modules/service-module';
 import './modules/view-model-module.ts';
 import {SdcUiCommon, SdcUiComponents, SdcUiServices} from 'onap-ui-angular';
-import {
-  CookieService,
-  DataTypesService,
-  EcompHeaderService,
-  LeftPaletteLoaderService
-} from "./services";
+import {CookieService, DataTypesService, EcompHeaderService, LeftPaletteLoaderService} from "./services";
 import {CacheService, CatalogService, HomeService} from "./services-ng2";
 import {AuthenticationService} from "app/ng2/services/authentication.service";
 import {CHANGE_COMPONENT_CSAR_VERSION_FLAG, PREVIOUS_CSAR_COMPONENT, States} from "./utils";
@@ -216,7 +211,14 @@ ng1appModule.config([
     );
 
     $stateProvider.state(
-        'workspace', {
+        States.TYPE_WORKSPACE, {
+          url: '/:previousState/type-workspace/:type/:id/:subPage',
+          template: '<app-type-workspace></app-type-workspace>',
+      }
+    );
+
+    $stateProvider.state(
+        States.WORKSPACE, {
           url: '/:previousState/workspace/:id/:type/',
           params: {
             'importedFile': null,
@@ -228,7 +230,6 @@ ng1appModule.config([
           controller: viewModelsModuleName + '.WorkspaceViewModel',
           resolve: {
             injectComponent: ['$stateParams', 'ComponentFactory', 'workspaceService', 'Sdc.Services.CacheService', function ($stateParams, ComponentFactory: ComponentFactory, workspaceService: WorkspaceService, cacheService: CacheService) {
-
               if ($stateParams.id && $stateParams.id.length) { //need to check length in case ID is an empty string
                 return ComponentFactory.getComponentWithMetadataFromServer($stateParams.type.toUpperCase(), $stateParams.id).then(
                     (component: Component) => {
@@ -316,7 +317,6 @@ ng1appModule.config([
           parent: 'workspace',
           resolve: {
             componentData: ['injectComponent', '$stateParams', function (injectComponent: Component, $stateParams) {
-              //injectComponent.componentService = null; // this is for not passing the service so no one will use old api and start using new api
               $stateParams.component = injectComponent;
               return injectComponent;
             }],
@@ -401,7 +401,6 @@ ng1appModule.config([
           template: '<composition-page></composition-page>',
           resolve: {
             componentData: ['injectComponent', '$stateParams', function (injectComponent: Component, $stateParams) {
-              //injectComponent.componentService = null; // this is for not passing the service so no one will use old api and start using new api
               $stateParams.component = injectComponent;
               return injectComponent;
             }],
@@ -672,7 +671,6 @@ ng1appModule.run([
 
     //handle http config
     $http.defaults.withCredentials = true;
-    // $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
     $http.defaults.headers.common[cookieService.getUserIdSuffix()] = cookieService.getUserId();
 
     DataTypesService.loadDataTypesCache(null);
@@ -723,15 +721,15 @@ ng1appModule.run([
     };
 
     let onStateChangeStart: Function = (event, toState, toParams, fromState, fromParams): void => {
-      console.info((new Date()).getTime());
-      console.info('$stateChangeStart', toState.name);
+      console.debug((new Date()).getTime());
+      console.debug('$stateChangeStart', toState.name);
       if (toState.name !== 'error-403' && !authService.getLoggedinUser()) {
 
 
         authService.authenticate().subscribe((userInfo: IUserProperties) => {
           if (!doesUserHasAccess(toState, userInfo)) {
             $state.go('error-403');
-            console.info('User has no permissions');
+            console.debug('User has no permissions');
             return;
           }
           authService.setLoggedinUser(userInfo);
@@ -740,7 +738,6 @@ ng1appModule.run([
             removeLoader();
 
             if (authService.getLoggedinUser().role === 'ADMIN') {
-              // toState.name = "adminDashboard";
               $state.go("adminDashboard", toParams);
               return;
             }
@@ -769,11 +766,10 @@ ng1appModule.run([
         if (!doesUserHasAccess(toState, authService.getLoggedinUser())) {
           event.preventDefault();
           $state.go('error-403');
-          console.info('User has no permissions');
+          console.debug('User has no permissions');
         }
 
         if (authService.getLoggedinUser().role === 'ADMIN') {
-          // toState.name = "adminDashboard";
           $state.go("adminDashboard", toParams);
           return;
         }
@@ -798,7 +794,7 @@ ng1appModule.run([
     };
 
     let onStateChangeSuccess: Function = (event, toState, toParams, fromState, fromParams): void => {
-      console.info('$stateChangeSuccess', toState.name);
+      console.debug('$stateChangeSuccess', toState.name);
 
       // Workaround in case we are entering other state then workspace (user move to catalog)
       // remove the changeComponentCsarVersion, user should open again the VSP list and select one for update.
@@ -831,7 +827,7 @@ ng1appModule.run([
 
     let registerStateChangeStartWatcher: Function = (): void => {
       internalDeregisterStateChangeStartWatcher();
-      console.info('registerStateChangeStartWatcher $stateChangeStart');
+      console.debug('registerStateChangeStartWatcher $stateChangeStart');
       deregisterStateChangeStartWatcher = $rootScope.$on('$stateChangeStart', (event, toState, toParams, fromState, fromParams): void => {
         onStateChangeStart(event, toState, toParams, fromState, fromParams);
       });
index 7fc788b..3b0833b 100644 (file)
@@ -29,36 +29,39 @@ import {PROPERTY_DATA} from "../utils/constants";
 
 export class DataTypeModel {
 
-    //server data
-    name:string;
-    uniqueId:string;
-    derivedFromName:string;
-    derivedFrom:DataTypeModel;
-    creationTime:string;
-    modificationTime:string;
+    name: string;
+    uniqueId: string;
+    derivedFromName: string;
+    derivedFrom: DataTypeModel;
+    description: string;
+    creationTime: string;
+    modificationTime: string;
     properties: Array<PropertyBEModel>;
     attributes: Array<AttributeBEModel>;
     model: Model;
 
-    constructor(dataType: DataTypeModel) {
-        if (dataType) {
-            this.uniqueId = dataType.uniqueId;
-            this.name = dataType.name;
-            this.derivedFromName = dataType.derivedFromName;
-            if (dataType.derivedFrom) {
-                this.derivedFrom = new DataTypeModel(dataType.derivedFrom);
-            }
-            this.creationTime = dataType.creationTime;
-            this.modificationTime = dataType.modificationTime;
-            if (dataType.properties) {
-                this.properties = [];
-                dataType.properties.forEach(property => {
-                    this.properties.push(new PropertyBEModel(property));
-                });
-            }
-            this.attributes = dataType.attributes;
-            this.model = dataType.model;
+    constructor(dataType?: DataTypeModel) {
+        if (!dataType) {
+            return;
         }
+
+        this.uniqueId = dataType.uniqueId;
+        this.name = dataType.name;
+        this.description = dataType.description;
+        this.derivedFromName = dataType.derivedFromName;
+        if (dataType.derivedFrom) {
+            this.derivedFrom = new DataTypeModel(dataType.derivedFrom);
+        }
+        this.creationTime = dataType.creationTime;
+        this.modificationTime = dataType.modificationTime;
+        if (dataType.properties) {
+            this.properties = [];
+            dataType.properties.forEach(property => {
+                this.properties.push(new PropertyBEModel(property));
+            });
+        }
+        this.attributes = dataType.attributes;
+        this.model = dataType.model;
     }
 
     public toJSON = ():any => {
index 25d8607..70ceb0f 100644 (file)
@@ -96,6 +96,8 @@ import {DistributionComponent} from '../ng2/pages/workspace/disribution/distribu
 import {AttributesOutputsComponent} from "../ng2/pages/attributes-outputs/attributes-outputs.page.component";
 import {InterfaceDefinitionComponent} from "../ng2/pages/interface-definition/interface-definition.page.component";
 import {ToscaFunctionComponent} from '../ng2/pages/properties-assignment/tosca-function/tosca-function.component';
+import {TypeWorkspaceComponent} from "../ng2/pages/type-workspace/type-workspace.component";
+import {TypeWorkspaceGeneralComponent} from "../ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component";
 
 let moduleName: string = 'Sdc.Directives';
 let directiveModule: ng.IModule = angular.module(moduleName, []);
@@ -321,3 +323,15 @@ directiveModule.directive('toscaFunction', downgradeComponent({
   inputs: ['componentInstanceMap', 'property'],
   outputs: []
 }) as angular.IDirectiveFactory);
+
+directiveModule.directive('appTypeWorkspace', downgradeComponent({
+  component: TypeWorkspaceComponent,
+  inputs: [],
+  outputs: []
+}) as angular.IDirectiveFactory);
+
+directiveModule.directive('appTypeWorkspaceGeneral', downgradeComponent({
+  component: TypeWorkspaceGeneralComponent,
+  inputs: [],
+  outputs: []
+}) as angular.IDirectiveFactory);
index dd08135..084219a 100644 (file)
@@ -37,6 +37,11 @@ import {ManagementWorkflowViewModel} from "../view-models/workspace/tabs/managem
 import {InterfaceOperationViewModel} from "../view-models/workspace/tabs/interface-operation/interface-operation-view-model";
 import {NetworkCallFlowViewModel} from "../view-models/workspace/tabs/network-call-flow/network-call-flow-view-model";
 import {InterfaceDefinitionViewModel} from "../view-models/workspace/tabs/interface-definition/interface-definition-view-model";
+import {TypeWorkspaceComponent} from "../ng2/pages/type-workspace/type-workspace.component";
+import {downgradeComponent} from "@angular/upgrade/static";
+import {WorkspaceMenuComponent} from "../ng2/pages/type-workspace/workspace-menu/workspace-menu.component";
+import {TypeWorkspaceGeneralComponent} from "../ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component";
+
 let moduleName:string = 'Sdc.ViewModels';
 let viewModelModule:ng.IModule = angular.module(moduleName, []);
 
@@ -61,4 +66,7 @@ viewModelModule
   .controller(moduleName + '.ManagementWorkflowViewModel', ManagementWorkflowViewModel)
   .controller(moduleName + '.InterfaceOperationViewModel', InterfaceOperationViewModel)
   .controller(moduleName + '.InterfaceDefinitionViewModel', InterfaceDefinitionViewModel)
-  .controller(moduleName + '.NetworkCallFlowViewModel', NetworkCallFlowViewModel);
+  .controller(moduleName + '.NetworkCallFlowViewModel', NetworkCallFlowViewModel)
+  .controller(moduleName + '.TypeWorkspaceComponent', downgradeComponent({ component: TypeWorkspaceComponent }))
+  .controller(moduleName + '.WorkspaceMenuComponent', downgradeComponent({ component: WorkspaceMenuComponent }))
+  .controller(moduleName + '.TypeWorkspaceGeneralComponent', downgradeComponent({ component: TypeWorkspaceGeneralComponent }));
index 7153f0a..801b663 100644 (file)
@@ -108,6 +108,7 @@ import {ElementService} from "./services/element.service";
 import {ModelService} from "./services/model.service";
 import {ToscaArtifactService} from "./services/tosca-artifact.service";
 import {InterfaceDefinitionModule} from "./pages/interface-definition/interface-definition.module";
+import {TypeWorkspaceModule} from "./pages/type-workspace/type-workspace.module";
 
 declare const __ENV__: string;
 
@@ -172,6 +173,7 @@ export function configServiceFactory(config: ConfigService, authService: Authent
     ServiceDependenciesModule,
     ServiceDependenciesEditorModule,
     WorkspaceModule,
+    TypeWorkspaceModule,
     ModalsModule,
     CatalogModule,
     HomeModule,
index 3bd2255..2b7be9c 100644 (file)
  */
 
 import * as _ from "lodash";
-import {Component, Inject, Input, Output, EventEmitter, OnInit, OnDestroy, OnChanges} from "@angular/core";
-import {IHostedApplication, IUserProperties} from "app/models";
-import {MenuItemGroup, MenuItem} from "app/utils";
+import {Component, EventEmitter, Inject, Input, OnChanges, OnInit, Output} from "@angular/core";
+import {IHostedApplication, IUserProperties, Plugin, PluginsConfiguration} from "app/models";
+import {MenuItem, MenuItemGroup} from "app/utils";
 import {AuthenticationService} from "../../../services/authentication.service";
-import {SdcConfigToken, ISdcConfig} from "../../../config/sdc-config.config";
+import {ISdcConfig, SdcConfigToken} from "../../../config/sdc-config.config";
 import {TranslateService} from "../../../shared/translator/translate.service";
-import {PluginsConfiguration, Plugin} from "app/models";
-import { Subscription } from "rxjs";
-// import { Store } from "@ngrx/store";
-// import { AppState } from "app/ng2/store/app.state";
-// import * as unsavedChangesReducer from 'app/ng2/store/reducers/unsaved-changes.reducer';
+import {Subscription} from "rxjs";
 
 declare const window:any;
 @Component({
@@ -111,13 +107,13 @@ export class TopNavComponent implements OnInit, OnChanges {
 
     ngOnChanges(changes) {
         if (changes['menuModel']) {
-            console.log('menuModel was changed!');
+            console.debug('menuModel was changed!');
             this.generateMenu();
         }
     }
 
     ngOnInit() {
-        console.log('Nav is init!', this.menuModel);
+        console.debug('Nav is init!', this.menuModel);
         this.user = this.authService.getLoggedinUser();
         this.topNavPlugins = _.filter(PluginsConfiguration.plugins, (plugin: Plugin) => {
             return plugin.pluginDisplayOptions["tab"] !== undefined;
@@ -190,7 +186,7 @@ export class TopNavComponent implements OnInit, OnChanges {
 
         if (item.callback) {
             (item.callback.apply(undefined, item.params)).then(onSuccess, onFailed);
-        } else {
+        } else if (this[item.action]) {
             this[item.action](item.state, item.params).then(onSuccess, onFailed);
         }
     }
index 0e2b93d..d2dfc57 100644 (file)
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -- */
-  
+
 import {IAppMenu} from "app/models";
 
-export function getSdcMenu() : IAppMenu{
-    const sdcMenu:IAppMenu = require('./../../../../configurations/menu.js');
-    return sdcMenu;
+export function getSdcMenu(): IAppMenu {
+    return require('./../../../../configurations/menu.js');
 }
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
new file mode 100644 (file)
index 0000000..877c58b
--- /dev/null
@@ -0,0 +1,79 @@
+<!--
+  ~ -
+  ~  ============LICENSE_START=======================================================
+  ~  Copyright (C) 2022 Nordix Foundation.
+  ~  ================================================================================
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  ~  SPDX-License-Identifier: Apache-2.0
+  ~  ============LICENSE_END=========================================================
+  -->
+
+<div class="sdc-workspace-general-step">
+  <form class="w-sdc-form" [formGroup]="formGroup">
+    <div class="w-sdc-form-section-container">
+      <div class="w-sdc-form-columns-wrapper">
+        <div class="w-sdc-form-column">
+          <div class="upper-general-fields">
+            <div class="name-and-category-fields">
+              <div class="i-sdc-form-item" [ngClass]="{'error': false}">
+                <label class="i-sdc-form-label" [ngClass]="{'required': !isViewOnly}">{{'TYPE_LABEL' | translate}}:</label>
+                <span>{{dataType.name}}</span>
+              </div>
+
+              <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>
+              </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>
+              </div>
+            </div>
+          </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"
+                      formControlName="description"
+                      [ngClass]="{'view-mode': isViewOnly}"
+                      [required]="true"
+                      [attr.test-id]="description"
+                      [value]="dataType.description"></textarea>
+          </div>
+        </div>
+
+        <div class="w-sdc-form-column">
+          <div class="meta-data" data-ng-if="component.creationDate">
+            <div>
+              <strong>{{'CREATED_LABEL' | translate}}:</strong>
+            </div>
+            <div class="meta-data-item-value">{{dataType.creationTime | date:'MM/dd/yyyy'}}</div>
+            <div>
+              <strong>{{'MODIFIED_LABEL' | translate}}:</strong>
+            </div>
+            <div class="meta-data-item-value">
+              {{dataType.modificationTime | date:'MM/dd/yyyy'}}
+            </div>
+            <div>
+              <strong>{{'UNIQUE_ID_LABEL' | translate}}:</strong>
+            </div>
+            <div class="meta-data-item-value">{{dataType.uniqueId}}</div>
+          </div>
+        </div>
+
+      </div>
+    </div>
+  </form>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.less b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-general/type-workspace-general.component.less
new file mode 100644 (file)
index 0000000..3d9e984
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
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
new file mode 100644 (file)
index 0000000..fe7b070
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+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";
+
+describe('TypeWorkspaceGeneralComponent', () => {
+  let component: TypeWorkspaceGeneralComponent;
+  let fixture: ComponentFixture<TypeWorkspaceGeneralComponent>;
+  let translateServiceMock: Partial<TranslateService> = {
+    'translate': jest.fn()
+  };
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ TypeWorkspaceGeneralComponent ],
+      imports: [
+        ReactiveFormsModule,
+        TranslateModule
+      ],
+      providers: [
+        {provide: TranslateService, useValue: translateServiceMock}
+      ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(TypeWorkspaceGeneralComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
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
new file mode 100644 (file)
index 0000000..8728c30
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {Component, Input, OnInit} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {DataTypeModel} from "../../../../models/data-types";
+import { DEFAULT_MODEL_NAME } from "app/utils/constants";
+
+@Component({
+  selector: 'app-type-workspace-general',
+  templateUrl: './type-workspace-general.component.html',
+  styleUrls: ['./type-workspace-general.component.less']
+})
+export class TypeWorkspaceGeneralComponent implements OnInit {
+  @Input() isViewOnly = true;
+  @Input() dataType: DataTypeModel = new DataTypeModel();
+
+  DEFAULT_MODEL_NAME = DEFAULT_MODEL_NAME;
+
+  type: FormControl = new FormControl(undefined, [Validators.required, Validators.minLength(1), Validators.maxLength(300)]);
+  derivedFrom: FormControl = new FormControl(undefined, [Validators.required, Validators.minLength(1)]);
+  description: FormControl = new FormControl(undefined, [Validators.required, Validators.minLength(1)]);
+  model: FormControl = new FormControl(undefined, [Validators.required]);
+  formGroup: FormGroup = new FormGroup({
+    'type': this.type,
+    'description': this.description,
+    'model': this.model,
+    'derivedFrom': this.derivedFrom
+  });
+
+  ngOnInit(): void {
+    this.initForm();
+  }
+
+  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);
+  }
+}
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
new file mode 100644 (file)
index 0000000..8d6ae02
--- /dev/null
@@ -0,0 +1,53 @@
+<!--
+  ~ -
+  ~  ============LICENSE_START=======================================================
+  ~  Copyright (C) 2022 Nordix Foundation.
+  ~  ================================================================================
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  ~  SPDX-License-Identifier: Apache-2.0
+  ~  ============LICENSE_END=========================================================
+  -->
+
+<div class="sdc-workspace-container">
+  <loader [display]="isLoading"></loader>
+  <div class="w-sdc-main-container">
+    <app-workspace-menu [menuHeader]="dataType.name"
+                        (onMenuUpdate)="onMenuUpdate($event)"
+                        (onClick)="onMenuClick($event)">
+    </app-workspace-menu>
+
+    <div class="w-sdc-main-right-container">
+      <div class="sdc-workspace-top-bar">
+        <div class="progress-container">
+        </div>
+        <div class="sdc-workspace-top-bar-buttons">
+          <span class="sprite-new x-btn" (click)="goToBreadcrumbHome()" sdc-smart-tooltip="Close" [title]="'CLOSE_LABEL' | translate"></span>
+        </div>
+      </div>
+
+      <div class="w-sdc-main-container-body-content-wrapper">
+        <div class="w-sdc-main-container-body-content-header">
+          <div class="workspace-tab-title">
+            {{currentMenu.text}}
+          </div>
+        </div>
+        <div class="w-sdc-main-container-body-content">
+          <app-type-workspace-general *ngIf="currentMenu.state === 'general' && dataType" [dataType]="dataType"></app-type-workspace-general>
+        </div>
+      </div>
+
+    </div>
+  </div>
+  <top-nav [hideSearch]="true" [menuModel]="breadcrumbsModel" [version]="sdcVersion" [unsavedChanges]="false"></top-nav>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.less b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.less
new file mode 100644 (file)
index 0000000..4839b24
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+@import '../../../../assets/styles/variables.less';
+@import '../../../../assets/styles/mixins.less';
+@import '../../../../assets/styles/mixins_old.less';
+@import '../../../../assets/styles/sprite.less';
+
+.sdc-workspace-container {
+    .bg_p;
+
+    .w-sdc-main-right-container {
+
+        padding: 0;
+        background-color: @main_color_p;
+
+        .sdc-workspace-top-bar {
+            height: @action_nav_height;
+            padding: 12px 10px 0 50px;
+            border-bottom: 1px solid @main_color_o;
+            display: flex;
+            justify-content: space-between;
+            white-space: nowrap;
+            overflow-x: auto;
+            overflow-y: hidden;
+
+            .progress-container {
+                flex-grow: 4;
+                z-index: 1;
+                display: inline-block;
+
+                .general-view-top-progress {
+                    width: 30%;
+                    margin: 0 auto;
+                    min-width: 140px;
+                }
+            }
+
+            .not-latest {
+                position: absolute;
+                left: 24px;
+                top: 20px;
+                .sprite-new;
+                .asdc-warning;
+                display: inline-block;
+            }
+
+            .sdc-workspace-top-bar-buttons {
+
+                > button, > span:not(.delimiter) {
+                    margin-right: 10px;
+                    vertical-align: middle;
+                    .hand;
+
+                    &.sprite-new {
+                        text-indent: 100%;
+                    }
+
+                    &.disabled, &:hover.disabled {
+                        pointer-events: none;
+                    }
+                }
+
+                .delimiter {
+                    height: 32px;
+                    width: 1px;
+                    background-color: @main_color_o;
+                    display: inline-block;
+                    vertical-align: middle;
+                    margin-right: 20px;
+                }
+
+                display: inline-block;
+
+            }
+        }
+
+        .workspace-tab-title {
+            height: 110px;
+            padding-left: 100px;
+            line-height: 110px;
+            .f-type ._28;
+        }
+
+        .w-sdc-main-container-body-content {
+            align-items: center;
+            padding: 0 100px 20px 100px;
+
+            &.third-party {
+                text-align: left;
+                padding: 0;
+                position: absolute;
+                top: @action_nav_height + @tab_title;
+                left: 0;
+                right: 0;
+                bottom: 0;
+            }
+        }
+
+        .w-sdc-main-container-body-content-wrapper {
+            overflow: auto;
+            height: calc(~'100% - @{action_nav_height}');
+
+            .w-sdc-main-container-body-content-header {
+                display: flex;
+
+                .workspace-tab-title {
+                    flex-grow: 1;
+                }
+
+                .w-sdc-main-container-body-content-action-buttons {
+                    margin: 72px 100px 0 0;
+
+                    > * {
+                        display: inline-block;
+                        vertical-align: middle;
+                    }
+
+                    .revert-btn {
+                        text-indent: 100%;
+                    }
+
+                    .save-btn {
+                        text-indent: 100%;
+                    }
+                }
+            }
+        }
+    }
+}
+
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
new file mode 100644 (file)
index 0000000..8450da8
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {TypeWorkspaceComponent} from './type-workspace.component';
+import {ReactiveFormsModule} from "@angular/forms";
+import {TranslateModule} from "../../shared/translator/translate.module";
+import {UiElementsModule} from "../../components/ui/ui-elements.module";
+import {DataTypeService} from "../../services/data-type.service";
+import {TranslateService} from "../../shared/translator/translate.service";
+import {WorkspaceMenuComponent} from "./workspace-menu/workspace-menu.component";
+import {TypeWorkspaceGeneralComponent} from "./type-workspace-general/type-workspace-general.component";
+import {LayoutModule} from "../../components/layout/layout.module";
+import {CacheService} from "../../services/cache.service";
+import {IAppMenu, SdcMenuToken} from "../../config/sdc-menu.config";
+import {AuthenticationService} from "../../services/authentication.service";
+import {ISdcConfig, SdcConfigToken} from "../../config/sdc-config.config";
+import {States} from "../../../utils/constants";
+import {IUserProperties} from "../../../models/user";
+import {Observable} from "rxjs/Observable";
+
+describe('TypeWorkspaceComponent', () => {
+  let component: TypeWorkspaceComponent;
+  let fixture: ComponentFixture<TypeWorkspaceComponent>;
+  let translateServiceMock: Partial<TranslateService> = {
+    'languageChangedObservable': Observable.of(),
+    'translate': jest.fn()
+  };
+  let dataTypeServiceMock: Partial<DataTypeService>;
+  let cacheService: Partial<CacheService> = {
+    'get': jest.fn(param => {
+      if (param === 'version') {
+        return 'version';
+      }
+      if (param === 'user') {
+        return {};
+      }
+    })
+  };
+  let stateMock: Partial<ng.ui.IStateService> = {
+    'current': {
+      'name': States.TYPE_WORKSPACE
+    }
+  };
+  let stateParamsMock: Partial<ng.ui.IStateParamsService> = {};
+  let injectorMock: Partial<ng.auto.IInjectorService> = {
+    'get': jest.fn(param => {
+      if (param === '$state') {
+        return stateMock;
+      }
+    })
+  };
+  let sdcMenuMock: Partial<IAppMenu> = {
+    'component_workspace_menu_option': {
+      "DataType": [
+          {"text": "General", "action": "onMenuItemPressed", "state": "general"}
+      ]
+    }
+  };
+  let sdcConfigMock: Partial<ISdcConfig>;
+  let user: Partial<IUserProperties> = {
+    'role': 'DESIGNER'
+  }
+  let authenticationService: Partial<AuthenticationService> = {
+    'getLoggedinUser': jest.fn(() => {
+      return user;
+    })
+  };
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ TypeWorkspaceComponent, WorkspaceMenuComponent, TypeWorkspaceGeneralComponent ],
+      imports: [
+        ReactiveFormsModule,
+        TranslateModule,
+        UiElementsModule,
+        LayoutModule
+      ],
+      providers: [
+        {provide: DataTypeService, useValue: dataTypeServiceMock},
+        {provide: TranslateService, useValue: translateServiceMock},
+        {provide: CacheService, useValue: cacheService},
+        {provide: '$state', useValue: stateMock},
+        {provide: '$stateParams', useValue: stateParamsMock},
+        {provide: '$injector', useValue: injectorMock},
+        {provide: SdcMenuToken, useValue: sdcMenuMock},
+        {provide: SdcConfigToken, useValue: sdcConfigMock},
+        {provide: AuthenticationService, useValue: authenticationService},
+      ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(TypeWorkspaceComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
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
new file mode 100644 (file)
index 0000000..d0d5ae8
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {Component, Inject, 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";
+
+@Component({
+  selector: 'app-type-workspace',
+  templateUrl: './type-workspace.component.html',
+  styleUrls: ['./type-workspace.component.less']
+})
+export class TypeWorkspaceComponent implements OnInit {
+
+  private typeMenuItemGroup: MenuItemGroup;
+
+  isLoading: boolean;
+  disabled: boolean;
+  isViewOnly: boolean = true;
+  sdcVersion: string;
+  breadcrumbsModel: Array<MenuItemGroup> = [];
+  dataType: DataTypeModel = new DataTypeModel();
+  currentMenu: MenuItem;
+
+  constructor(private dataTypeService: DataTypeService, private cacheService: CacheService,
+              @Inject('$state') private $state: ng.ui.IStateService,
+              @Inject('$stateParams') private stateParams) { }
+
+  ngOnInit(): void {
+    this.sdcVersion = this.cacheService.get('version');
+    this.typeMenuItemGroup = this.createTypeBreadcrumb();
+    this.loadDataType();
+  }
+
+  private loadDataType(): void {
+    if (this.stateParams.id) {
+      this.dataTypeService.findById(this.stateParams.id).subscribe(dataType => {
+        this.dataType = dataType;
+        this.updateTypeBreadcrumb();
+      }, error => {
+        console.debug('Could not find data type %s', this.stateParams.id, error);
+        this.goToBreadcrumbHome();
+      });
+    } else {
+      this.dataType = new DataTypeModel();
+    }
+  }
+
+  private updateTypeBreadcrumb(): void {
+    this.typeMenuItemGroup.updateSelectedMenuItemText(`Data Type: ${this.dataType.name}`);
+  }
+
+  private createTypeBreadcrumb(): MenuItemGroup {
+    const menuItem = new MenuItem(`Data Type: ${this.dataType ? this.dataType.name : ''}`, undefined, undefined, undefined, [], [], false);
+    return new MenuItemGroup(0, [menuItem]);
+  }
+
+  goToBreadcrumbHome(): void {
+    const homeMenuItemGroup: MenuItemGroup = this.breadcrumbsModel[0];
+    this.$state.go(homeMenuItemGroup.menuItems[homeMenuItemGroup.selectedIndex].state);
+  }
+
+  onMenuUpdate(menuItemGroup: MenuItemGroup): void {
+    this.breadcrumbsModel.push(...[this.typeMenuItemGroup, menuItemGroup]);
+  }
+
+  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
new file mode 100644 (file)
index 0000000..d3f391d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {TypeWorkspaceComponent} from "./type-workspace.component";
+import {WorkspaceMenuComponent} from "./workspace-menu/workspace-menu.component";
+import {CacheService} from "../../services/cache.service";
+import {UiElementsModule} from "../../components/ui/ui-elements.module";
+import {LayoutModule} from "../../components/layout/layout.module";
+import {TypeWorkspaceGeneralComponent} from './type-workspace-general/type-workspace-general.component';
+import {UpgradeModule} from "@angular/upgrade/static";
+import {ReactiveFormsModule} from "@angular/forms";
+import {TranslateModule} from "../../shared/translator/translate.module";
+import {DataTypeService} from "../../services/data-type.service";
+
+@NgModule({
+    imports: [
+        CommonModule,
+        UiElementsModule,
+        LayoutModule,
+        UpgradeModule,
+        ReactiveFormsModule,
+        TranslateModule,
+    ],
+    declarations: [
+        TypeWorkspaceComponent,
+        WorkspaceMenuComponent,
+        TypeWorkspaceGeneralComponent
+    ],
+    providers: [
+        CacheService,
+        WorkspaceMenuComponent,
+        DataTypeService
+    ],
+    entryComponents: [TypeWorkspaceComponent],
+    exports: [TypeWorkspaceComponent]
+})
+export class TypeWorkspaceModule {
+}
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
new file mode 100644 (file)
index 0000000..18c6949
--- /dev/null
@@ -0,0 +1,34 @@
+<!--
+  ~ -
+  ~  ============LICENSE_START=======================================================
+  ~  Copyright (C) 2022 Nordix Foundation.
+  ~  ================================================================================
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  ~  SPDX-License-Identifier: Apache-2.0
+  ~  ============LICENSE_END=========================================================
+  -->
+
+<div class="w-sdc-left-sidebar">
+  <div class="menu-header" tooltips [attr.tooltip-content]="menuHeader" [title]="menuHeader">
+    {{menuHeader}}
+  </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 }">
+      <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>
+  </div>
+</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.less b/catalog-ui/src/app/ng2/pages/type-workspace/workspace-menu/workspace-menu.component.less
new file mode 100644 (file)
index 0000000..2df6e6a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+@import '../../../../../assets/styles/variables.less';
+@import '../../../../../assets/styles/mixins.less';
+
+.w-sdc-left-sidebar {
+    padding: 0;
+    background-color: @tlv_color_t;
+    box-shadow: none;
+    z-index: 2;
+    border-right: 1px solid @main_color_o;
+
+    .menu-header {
+        border-bottom: 1px solid @main_color_o;
+        height: 53px;
+        .f-type._16_m;
+        font-weight: 700;
+        line-height: 53px;
+        padding-left: 40px;
+        padding-right: 10px;
+        width: 100%;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: inline-block;
+        white-space: nowrap;
+    }
+
+    .i-sdc-designer-sidebar-section-content-item {
+        .f-type._13_m;
+        color: @main_color_m;
+        margin-left: 20px;
+        padding-left: 20px;
+        margin-top: 20px;
+        height: 17px;
+        .hand;
+
+        &:hover {
+            color: @func_color_s;
+            font-weight: 600;
+        }
+
+        &.selected {
+            border-left: 4px solid @main_color_a;
+            color: @main_color_a;
+            margin-left: 18px;
+            padding-left: 18px;
+            font-weight: 600;
+
+        }
+    }
+
+}
+
+.hand {
+    cursor: pointer;
+}
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
new file mode 100644 (file)
index 0000000..a91258c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {WorkspaceMenuComponent} from './workspace-menu.component';
+import {CacheService} from "../../../services/cache.service";
+import {States} from "../../../../utils/constants";
+import {IAppMenu} from "../../../../models/app-config";
+import {SdcMenuToken} from "../../../config/sdc-menu.config";
+
+describe('WorkspaceMenuComponent', () => {
+  let component: WorkspaceMenuComponent;
+  let fixture: ComponentFixture<WorkspaceMenuComponent>;
+  let cacheService: Partial<CacheService> = {
+    'get': jest.fn(param => {
+      if (param === 'version') {
+        return 'version';
+      }
+      if (param === 'user') {
+        return {};
+      }
+    })
+  };
+  let sdcMenuMock: Partial<IAppMenu> = {
+    'component_workspace_menu_option': {
+      "DataType": [
+        {"text": "General", "action": "onMenuItemPressed", "state": "general"}
+      ]
+    }
+  };
+  let stateMock: Partial<ng.ui.IStateService> = {
+    'current': {
+      'name': States.TYPE_WORKSPACE
+    }
+  };
+  let injectorMock: Partial<ng.auto.IInjectorService> = {
+    'get': jest.fn(param => {
+      if (param === '$state') {
+        return stateMock;
+      }
+    })
+  };
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ WorkspaceMenuComponent ],
+      providers: [
+        {provide: CacheService, useValue: cacheService},
+        {provide: '$injector', useValue: injectorMock},
+        {provide: SdcMenuToken, useValue: sdcMenuMock}
+      ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(WorkspaceMenuComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
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
new file mode 100644 (file)
index 0000000..c5e49d4
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {Component, EventEmitter, Inject, Input, OnInit, Output} from '@angular/core';
+import {MenuItem, MenuItemGroup} from "../../../../utils/menu-handler";
+import {CacheService} from "../../../services/cache.service";
+import {IAppMenu} from "../../../../models/app-config";
+import {IUserProperties} from "../../../../models/user";
+import {SdcMenuToken} from "../../../config/sdc-menu.config";
+
+@Component({
+    selector: 'app-workspace-menu',
+    templateUrl: './workspace-menu.component.html',
+    styleUrls: ['./workspace-menu.component.less']
+})
+export class WorkspaceMenuComponent implements OnInit {
+
+    @Input() menuHeader: string = '';
+    @Output() onMenuUpdate: EventEmitter<MenuItemGroup> = new EventEmitter<MenuItemGroup>();
+    @Output() onClick: EventEmitter<MenuItem> = new EventEmitter<MenuItem>();
+
+    private role: string;
+    private user: IUserProperties;
+    private $state: ng.ui.IStateService;
+    private $q: ng.IQService;
+
+    leftBarTabs: MenuItemGroup = new MenuItemGroup();
+
+    constructor(private cacheService: CacheService, @Inject(SdcMenuToken) private sdcMenu: IAppMenu, @Inject('$injector') $injector) {
+        this.$state = $injector.get('$state');
+        this.$q = $injector.get('$q');
+    }
+
+    ngOnInit(): void {
+        this.user = this.cacheService.get('user');
+        this.role = this.user.role;
+        this.initMenuItems();
+    }
+
+    private initMenuItems(): void {
+        this.leftBarTabs = new MenuItemGroup();
+        const menuItemsObjects: MenuItem[] = this.updateMenuItemByRole(this.sdcMenu.component_workspace_menu_option["DataType"], this.role);
+
+        this.leftBarTabs.menuItems = menuItemsObjects.map((item: MenuItem) => {
+            const menuCallback = () => this[menuItem.action](menuItem);
+            const menuItem = new MenuItem(item.text, menuCallback, item.state, item.action, item.params, item.blockedForTypes, item.disabledCategory);
+            if (menuItem.params) {
+                menuItem.params.state = menuItem.state;
+            } else {
+                menuItem.params = {state: menuItem.state};
+            }
+            return menuItem;
+        });
+        this.updateSelectedMenuItem();
+        this.onMenuUpdate.emit(this.leftBarTabs);
+    }
+
+    isSelected(menuItem: MenuItem): boolean {
+        return this.leftBarTabs.selectedIndex === this.leftBarTabs.menuItems.indexOf(menuItem);
+    }
+
+    private onMenuItemPressed(menuItem: MenuItem): angular.IPromise<boolean> {
+        this.leftBarTabs.selectedIndex = this.leftBarTabs.menuItems.indexOf(menuItem);
+        this.onClick.emit(this.leftBarTabs.menuItems[this.leftBarTabs.selectedIndex]);
+        const deferred: ng.IDeferred<boolean> = this.$q.defer();
+        deferred.resolve(true);
+        return deferred.promise;
+    }
+
+    private updateMenuItemByRole(menuItems: MenuItem[], role: string): MenuItem[] {
+        const filteredMenuItems: MenuItem[] = [];
+        menuItems.forEach((item: any) => {
+            if (!(item.disabledRoles && item.disabledRoles.indexOf(role) > -1)) {
+                filteredMenuItems.push(item);
+            }
+        });
+        return filteredMenuItems;
+    }
+
+    private updateSelectedMenuItem(): void {
+        const stateArray: Array<string> = this.$state.current.name.split('.', 2);
+        const stateWithoutInternalNavigate: string = stateArray[0] + '.' + stateArray[1];
+        const selectedItem: MenuItem = this.leftBarTabs.menuItems.find((item: MenuItem) => {
+            let itemStateArray: Array<string> = item.state.split('.', 2);
+            let itemStateWithoutNavigation: string = itemStateArray[0] + '.' + itemStateArray[1];
+            return (itemStateWithoutNavigation === stateWithoutInternalNavigate);
+        });
+        this.leftBarTabs.selectedIndex = selectedItem ? this.leftBarTabs.menuItems.indexOf(selectedItem) : 0;
+        this.onClick.emit(this.leftBarTabs.menuItems[this.leftBarTabs.selectedIndex]);
+    }
+
+}
index 61d1318..22c1dd3 100644 (file)
@@ -18,9 +18,9 @@
  * ============LICENSE_END=========================================================
  */
 
-import {Injectable, Inject} from '@angular/core';
+import {Inject, Injectable} from '@angular/core';
 import {ICookie} from "../../models/app-config";
-import {SdcConfigToken, ISdcConfig} from "../config/sdc-config.config";
+import {ISdcConfig, SdcConfigToken} from "../config/sdc-config.config";
 
 @Injectable()
 export class Cookie2Service {
@@ -36,7 +36,6 @@ export class Cookie2Service {
         if ((junctionName !== null) && (junctionName !== '')) {
             this.cookiePrefix = this.cookie.prefix + junctionName + '!';
         }
-        console.log("junctionName:" + junctionName);
     }
 
     private getCookieByName = (cookieName:string):string => {
index 70555a5..bf500ec 100644 (file)
  */
 
 import * as _ from "lodash";
-import { Injectable } from '@angular/core';
+import {Inject, Injectable} from '@angular/core';
 import { DataTypeModel, DataTypesMap, PropertyFEModel, DerivedFEProperty} from "app/models";
 import { DataTypesService } from "app/services/data-types-service";
 import { PROPERTY_DATA } from "app/utils";
 import {DerivedFEAttribute} from "../../models/attributes-outputs/derived-fe-attribute";
+import {ISdcConfig} from "../config/sdc-config.config.factory";
+import {SdcConfigToken} from "../config/sdc-config.config";
+import {HttpClient} from "@angular/common/http";
+import {Observable} from "rxjs/Observable";
 
 /** This is a new service for NG2, to eventually replace app/services/data-types-service.ts
  *
@@ -34,11 +38,16 @@ import {DerivedFEAttribute} from "../../models/attributes-outputs/derived-fe-att
 @Injectable()
 export class DataTypeService {
     public dataTypes: DataTypesMap;
+    private readonly baseUrl: string;
+    private readonly dataTypeUrl: string;
 
-    constructor(private dataTypeService: DataTypesService) {
+    constructor(private dataTypeService: DataTypesService, private httpClient: HttpClient, @Inject(SdcConfigToken) sdcConfig: ISdcConfig) {
         this.dataTypes = dataTypeService.getAllDataTypes(); //This should eventually be replaced by an NG2 call to the backend instead of utilizing Angular1 downgraded component.
+        this.baseUrl = sdcConfig.api.root + sdcConfig.api.component_api_root;
+        this.dataTypeUrl = `${this.baseUrl}data-types`
     }
 
+
     public getDataTypeByModelAndTypeName(modelName: string, typeName: string): DataTypeModel {
         this.dataTypes = this.dataTypeService.getAllDataTypesFromModel(modelName);
         let dataTypeFound = this.dataTypes[typeName];
@@ -64,6 +73,11 @@ export class DataTypeService {
         return this.dataTypeService.findAllDataTypesByModel(modelName);
     }
 
+    public findById(id: string): Observable<DataTypeModel> {
+        const url = `${this.dataTypeUrl}/${id}`
+        return this.httpClient.get<DataTypeModel>(url);
+    }
+
     public getConstraintsByParentTypeAndUniqueID(rootPropertyType, propertyName){
         // const property = this.dataTypes[rootPropertyType].properties.filter(property =>
         //     property.name == propertyName);
index aab531d..a3c04bc 100644 (file)
 /**
  * Created by rc2122 on 4/6/2017.
  */
-import { DataTypesService } from "../../services/data-types-service";
-import ICacheObject = angular.ICacheObject;
-import { CookieService } from "../../services/cookie-service";
+import {DataTypesService} from "../../services/data-types-service";
+import {CookieService} from "../../services/cookie-service";
 import {ComponentFactory} from "../../utils/component-factory"
-import { EventListenerService } from "app/services/event-listener-service";
-import { ModalsHandler } from "app/utils";
-import IScope = angular.IScope;
-import { SharingService } from "../services/sharing.service";
+import {EventListenerService} from "app/services/event-listener-service";
+import {ModalsHandler} from "app/utils";
+import {SharingService} from "../services/sharing.service";
+import ICacheObject = angular.ICacheObject;
 
 /** Services we need to upgrade from angular1 to angular2 - in the future we need to rewrite them all to angular2 **/
 
@@ -115,12 +114,6 @@ export const StateParamsServiceFactory = {
     useFactory: stateParamsServiceFactory,
     deps: ['$injector']
 };
-//
-// export const EventListenerServiceProvider = {
-//     provide: EventListenerService,
-//     useFactory: eventListenerServiceServiceFactory,
-//     deps: ['$injector']
-// };
 
 export const NotificationServiceProvider = {
     provide: 'Notification',
index ad8dc59..ca30259 100644 (file)
  */
 
 'use strict';
-import { DataTypePropertyModel } from "../models/data-type-properties";
+import {DataTypePropertyModel} from "../models/data-type-properties";
 import {
     ComponentInstance,
-    InputModel,
+    DataTypeModel,
     DataTypesMap,
-    PropertyModel,
-    InputPropertyBase,
     IAppConfigurtaion,
-    SchemaProperty, DataTypeModel
+    InputModel,
+    InputPropertyBase,
+    PropertyModel,
+    SchemaProperty
 } from "../models";
 import {PROPERTY_DATA} from "../utils/constants";
 
index 4e268f7..d6710ed 100644 (file)
@@ -281,6 +281,7 @@ export class GraphUIObjects {
 
 
 export class States {
+  public static WORKSPACE = 'workspace';
   public static WORKSPACE_GENERAL = 'workspace.general';
   public static WORKSPACE_ACTIVITY_LOG = 'workspace.activity_log';
   public static WORKSPACE_DEPLOYMENT_ARTIFACTS = 'workspace.deployment_artifacts';
@@ -303,6 +304,7 @@ export class States {
   public static WORKSPACE_REQUIREMENTS_AND_CAPABILITIES_EDITABLE = 'workspace.reqAndCapEditable';
   public static WORKSPACE_PLUGINS = 'workspace.plugins';
   public static WORKSPACE_NG2 = 'workspace.ng2';
+  public static TYPE_WORKSPACE = 'type-workspace';
 }
 
 export class EVENTS {
index 7bed071..0778b2d 100644 (file)
  */
 'use strict';
 import * as _ from 'lodash';
+import {Component, IAppMenu, IUserProperties, Plugin, PluginsConfiguration, Resource, Service} from 'app/models';
 import {
-    IUserProperties,
-    IAppMenu,
-    Resource,
-    Service, 
-    Component,
-    Plugin,
-    PluginsConfiguration,
-    PluginDisplayOptions
-} from 'app/models';
-import {
-    MenuItem, ModalsHandler, States, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FLAG, ResourceType, PREVIOUS_CSAR_COMPONENT,
-    WorkspaceMode, ComponentFactory, ChangeLifecycleStateHandler, Role, ComponentState, MenuItemGroup, MenuHandler
+    CHANGE_COMPONENT_CSAR_VERSION_FLAG,
+    ChangeLifecycleStateHandler,
+    ComponentFactory,
+    ComponentState,
+    EVENTS,
+    MenuHandler,
+    MenuItem,
+    MenuItemGroup,
+    PREVIOUS_CSAR_COMPONENT,
+    ResourceType,
+    Role,
+    States,
+    WorkspaceMode
 } from 'app/utils';
-import {
-    EventListenerService,
-    LeftPaletteLoaderService,
-    ProgressService
-} from 'app/services';
-import {
-    CacheService
-} from 'app/services-ng2';
-import { SdcUiCommon, SdcUiComponents, SdcUiServices } from 'onap-ui-angular';
-import { AutomatedUpgradeService } from '../../ng2/pages/automated-upgrade/automated-upgrade.service';
-import { CatalogService } from '../../ng2/services/catalog.service';
-import { ComponentServiceNg2 } from '../../ng2/services/component-services/component.service';
-import { EventBusService } from '../../ng2/services/event-bus.service';
-import { HomeService } from '../../ng2/services/home.service';
-import { PluginsService } from '../../ng2/services/plugins.service';
-import { IDependenciesServerResponse } from '../../ng2/services/responses/dependencies-server-response';
-import { WorkspaceNg1BridgeService } from '../../ng2/pages/workspace/workspace-ng1-bridge-service';
-import { WorkspaceService } from '../../ng2/pages/workspace/workspace.service';
+import {EventListenerService, LeftPaletteLoaderService, ProgressService} from 'app/services';
+import {CacheService} from 'app/services-ng2';
+import {SdcUiCommon, SdcUiComponents, SdcUiServices} from 'onap-ui-angular';
+import {AutomatedUpgradeService} from '../../ng2/pages/automated-upgrade/automated-upgrade.service';
+import {CatalogService} from '../../ng2/services/catalog.service';
+import {ComponentServiceNg2} from '../../ng2/services/component-services/component.service';
+import {EventBusService} from '../../ng2/services/event-bus.service';
+import {HomeService} from '../../ng2/services/home.service';
+import {PluginsService} from '../../ng2/services/plugins.service';
+import {IDependenciesServerResponse} from '../../ng2/services/responses/dependencies-server-response';
+import {WorkspaceNg1BridgeService} from '../../ng2/pages/workspace/workspace-ng1-bridge-service';
+import {WorkspaceService} from '../../ng2/pages/workspace/workspace.service';
 
 export interface IWorkspaceViewModelScope extends ng.IScope {
 
@@ -87,7 +83,6 @@ export interface IWorkspaceViewModelScope extends ng.IScope {
     progressService: ProgressService;
     progressMessage: string;
     ComponentServiceNg2: ComponentServiceNg2;
-    // leftPanelComponents:Array<Models.Components.Component>; //this is in order to load the left panel once, and not wait long time when moving to composition
     unsavedChanges: boolean;
     unsavedChangesCallback: Function;
     unsavedFile: boolean;
@@ -184,7 +179,6 @@ export class WorkspaceViewModel {
                 private workspaceService: WorkspaceService) {
 
                 this.initScope();
-                // this.initAfterScope();
                 this.$scope.updateSelectedMenuItem(this.$state.current.name);
     }
 
@@ -773,7 +767,7 @@ export class WorkspaceViewModel {
         };
 
         this.$scope.reload = (component: Component): void => {
-            const isGeneralTab = this.$state.current.name === 'workspace.general';
+            const isGeneralTab = this.$state.current.name === States.WORKSPACE_GENERAL;
             // nullify the componentCsar in case we are in general tab so we know we didnt came from updateVsp Modal
             if (isGeneralTab) {
                 this.$state.go(this.$state.current.name, {id: component.uniqueId, componentCsar: null}, {reload: true});
index 71f2b05..3f5a107 100644 (file)
   "VALUE_EXPRESSION_LABEL": "Value Expression",
   "OPERATOR_LABEL": "Operator",
   "CAPABILITY_LABEL": "Capability",
+  "DATA_TYPE_LABEL": "Data Type",
+  "MODEL_LABEL": "Model",
+  "DESCRIPTION_LABEL": "Description",
+  "DERIVED_FROM_LABEL": "Derived From",
+  "TYPE_LABEL": "Type",
+  "CREATED_LABEL": "Created",
+  "CREATE_LABEL": "Create",
+  "CLOSE_LABEL": "Close",
+  "MODIFIED_LABEL": "Modified",
+  "UNIQUE_ID_LABEL": "Unique Id",
   "=========== SERVICE IMPORT ===========": "",
   "IMPORT_FAILURE_MESSAGE_TEXT": "Import Failure - error reading CSAR"
 }
index e69de29..3dfa143 100644 (file)
@@ -0,0 +1,32 @@
+pluginsList:
+  - pluginId: POLICY
+    pluginDiscoveryUrl: http://192.168.86.21:9090/policy/
+    pluginSourceUrl: http://192.168.86.21:9090/policy/
+    pluginStateUrl: "policy"
+    pluginDisplayOptions:
+      tab:
+        displayName: "POLICY"
+        displayRoles: ["DESIGNER"]
+  - pluginId: POLICY_LIST
+    pluginDiscoveryUrl: http://192.168.86.21:8095/artifact
+    pluginSourceUrl: http://192.168.86.21:8095/artifact
+    pluginStateUrl: "policy_list"
+    pluginDisplayOptions:
+      context:
+        displayName: "Apex policy"
+        displayContext: ["SERVICE"]
+        displayRoles: ["DESIGNER"]
+  - pluginId: WORKFLOW
+    pluginDiscoveryUrl: http://192.168.86.21:8184/workflows
+    pluginSourceUrl: http://192.168.86.21:8184/workflows
+    pluginStateUrl: "workflowDesigner"
+    pluginDisplayOptions:
+      tab:
+        displayName: "WORKFLOW"
+        displayRoles: ["DESIGNER", "TESTER"]
+      context:
+        displayName: "Workflow Designer"
+        displayContext: ["VF"]
+        displayRoles: ["DESIGNER", "TESTER"]
+
+connectionTimeout: 1000