diff options
Diffstat (limited to 'catalog-ui')
108 files changed, 1228 insertions, 1091 deletions
diff --git a/catalog-ui/karma.conf.js b/catalog-ui/karma.conf.js deleted file mode 100644 index 1f2613a346..0000000000 --- a/catalog-ui/karma.conf.js +++ /dev/null @@ -1,43 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/0.13/config/configuration-file.html - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', 'angular-cli'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-remap-istanbul'), - require('angular-cli/plugins/karma') - ], - files: [ - { pattern: './src/test.ts', watched: false } - ], - preprocessors: { - './src/test.ts': ['angular-cli'] - }, - mime: { - 'text/x-typescript': ['ts','tsx'] - }, - remapIstanbulReporter: { - reports: { - html: 'coverage', - lcovonly: './coverage/coverage.lcov' - } - }, - angularCli: { - config: './angular-cli.json', - environment: 'dev' - }, - reporters: config.angularCli && config.angularCli.codeCoverage - ? ['progress', 'karma-remap-istanbul'] - : ['progress'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false - }); -}; diff --git a/catalog-ui/package.json b/catalog-ui/package.json index 4fd1f46734..3e13e69a2b 100644 --- a/catalog-ui/package.json +++ b/catalog-ui/package.json @@ -17,18 +17,17 @@ "start": "webpack-dev-server", "build": "webpack --config webpack.config.js", "build:prod": "webpack --config webpack.production.js", - "test": "karma start ./karma.conf.js", "lint": "ng lint", - "e2e": "protractor ./protractor.conf.js", "pree2e": "webdriver-manager update --standalone false --gecko false --quiet" }, "devDependencies": { + "@angular/compiler": "^2.4.8", + "@angular/compiler-cli": "^2.4.8", "apache-server-configs": "^2.7.1", "autoprefixer": "^6.5.3", "copy-webpack-plugin": "^4.0.1", "cors": "2.7.1", "css-loader": "^0.26.1", - "cssnano": "^3.10.0", "exports-loader": "^0.6.3", "express": "^4.14.0", "extract-text-webpack-plugin": "^2.1.0", @@ -36,33 +35,19 @@ "html-loader": "^0.4.5", "html-webpack-plugin": "^2.28.0", "http-proxy-middleware": "^0.14.0", - "istanbul-instrumenter-loader": "^2.0.0", - "jasmine-core": "2.5.2", "jshint-stylish": "2.2.1", "json-loader": "^0.5.4", - "karma": "1.4.0", - "karma-chrome-launcher": "0.2.2", - "karma-coverage": "1.1.1", - "karma-jasmine": "1.1.0", - "karma-junit-reporter": "0.3.8", - "karma-mocha-reporter": "2.2.2", - "karma-ng-html2js-preprocessor": "1.0.0", - "karma-ng-scenario": "1.0.0", - "karma-phantomjs-launcher": "0.2.1", - "karma-sourcemap-loader": "^0.3.7", "less": "^2.7.2", "less-loader": "^2.2.3", "load-grunt-tasks": "3.5.2", - "phantomjs": "2.1.7", "postcss-loader": "^0.13.0", "postcss-url": "^5.1.2", "raw-loader": "^0.5.1", "sass-loader": "^4.1.1", "script-loader": "^0.7.0", + "sdc-ui": "^1.6.2", "source-map-loader": "^0.1.5", "style-loader": "^0.13.1", - "stylus-loader": "^2.4.0", - "time-grunt": "1.4.0", "url-loader": "^0.5.7", "webpack-dev-middleware": "^1.10.1", "webpack-dev-server": "~2.3.0" @@ -73,8 +58,6 @@ "dependencies": { "@angular/cli": "^1.0.0-rc.1", "@angular/common": "^2.4.8", - "@angular/compiler": "^2.4.8", - "@angular/compiler-cli": "^2.4.8", "@angular/core": "^2.4.8", "@angular/forms": "^2.4.8", "@angular/http": "^2.4.8", @@ -113,32 +96,27 @@ "checklist-model": "^0.11.0", "class-transformer": "^0.1.6", "clean-webpack-plugin": "^0.1.16", - "codelyzer": "^2.0.1", + "compression": "^1.6.2", + "compression-webpack-plugin": "^0.4.0", "core-js": "^2.4.1", "cytoscape": "^2.7.15", "cytoscape.js-undo-redo": "^1.0.1", - "express": "4.14.0", "jquery": "^2.2.4", "jqueryui": "^1.11.1", "js-md5": "^0.4.2", "lodash": "^4.17.2", - "multer": "1.2.1", - "ng-html2js": "2.0.0", "ng-infinite-scroll": "^1.3.0", - "ng2-interceptors": "^1.3.0-1", "perfect-scrollbar": "^0.6.16", "qtip2": "^3.0.3", "reflect-metadata": "^0.1.10", "restangular": "^1.6.1", "rxjs": "^5.2.0", "sdc-angular-dragdrop": "^1.0.14", - "ts-helpers": "^1.1.2", - "ts-node": "^2.1.0", - "tslint": "^4.4.2", "typescript": "2.3.4", "typings": "^2.1.0", "underscore": "^1.8.3", "webpack": "^2.2.1", + "webpack-bundle-analyzer": "^2.8.2", "webpack-dev-server": "^2.4.1", "webpack-merge": "^4.0.0", "zone.js": "^0.7.7" diff --git a/catalog-ui/pom.xml b/catalog-ui/pom.xml index 737ed33a41..80d534c669 100644 --- a/catalog-ui/pom.xml +++ b/catalog-ui/pom.xml @@ -254,28 +254,6 @@ </profile> - <profile> - <id>Fortify</id> - <activation> - <activeByDefault>false</activeByDefault> - </activation> - - <build> - <plugins> - <plugin> - <groupId>com.fortify.ps.maven.plugin</groupId> - <artifactId>sca-maven-plugin</artifactId> - <version>4.30</version> - <configuration> - <source>1.8</source> - <buildId>${project.parent.artifactId}</buildId> - <toplevelArtifactId>${project.parent.artifactId}</toplevelArtifactId> - </configuration> - </plugin> - </plugins> - </build> - </profile> - <profile> <id>not-minified</id> <activation> diff --git a/catalog-ui/protractor.conf.js b/catalog-ui/protractor.conf.js deleted file mode 100644 index ffded70180..0000000000 --- a/catalog-ui/protractor.conf.js +++ /dev/null @@ -1,32 +0,0 @@ -// Protractor configuration file, see link for more information -// https://github.com/angular/protractor/blob/master/lib/config.ts - -/*global jasmine */ -var SpecReporter = require('jasmine-spec-reporter'); - -exports.config = { - allScriptsTimeout: 11000, - specs: [ - './e2e/**/*.e2e-spec.ts' - ], - capabilities: { - 'browserName': 'chrome' - }, - directConnect: true, - baseUrl: 'http://localhost:4200/', - framework: 'jasmine', - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 30000, - print: function() {} - }, - useAllAngular2AppRoots: true, - beforeLaunch: function() { - require('ts-node').register({ - project: 'e2e' - }); - }, - onPrepare: function() { - jasmine.getEnv().addReporter(new SpecReporter()); - } -}; diff --git a/catalog-ui/src/app/app.ts b/catalog-ui/src/app/app.ts index 707d7e456e..805e5f0b5d 100644 --- a/catalog-ui/src/app/app.ts +++ b/catalog-ui/src/app/app.ts @@ -53,6 +53,7 @@ import {downgradeComponent} from "@angular/upgrade/static"; import {AppModule} from './ng2/app.module'; import {PropertiesAssignmentComponent} from "./ng2/pages/properties-assignment/properties-assignment.page.component"; +import { SearchWithAutoCompleteComponent } from "./ng2/shared/search-with-autocomplete/search-with-autocomplete.component"; import {Component} from "./models/components/component"; import {ComponentServiceNg2} from "./ng2/services/component-services/component.service"; import {ComponentMetadata} from "./models/component-metadata"; @@ -145,6 +146,13 @@ _.each(hostedApplications, (hostedApp)=> { export const ng1appModule:ng.IModule = angular.module(moduleName, dependentModules); angular.module('sdcApp').directive('propertiesAssignment', downgradeComponent({component: PropertiesAssignmentComponent}) as angular.IDirectiveFactory); +angular.module('sdcApp').directive('ng2SearchWithAutocomplete', + downgradeComponent({ + component: SearchWithAutoCompleteComponent, + inputs: ['searchPlaceholder', 'searchBarClass', 'autoCompleteValues'], + outputs: ['searchChanged', 'searchButtonClicked'] + }) as angular.IDirectiveFactory); + ng1appModule.config([ '$stateProvider', @@ -161,7 +169,7 @@ ng1appModule.config([ NotificationProvider:any):void => { NotificationProvider.setOptions({ - delay: 10000, + delay: 5000, startTop: 10, startRight: 10, closeOnClick: true, @@ -170,6 +178,7 @@ ng1appModule.config([ positionX: 'right', positionY: 'top' }); + NotificationProvider.options.templateUrl = 'notification-custom-template.html'; $translateProvider.useStaticFilesLoader({ prefix: pathPrefix + 'assets/languages/', @@ -617,6 +626,7 @@ ng1appModule.run([ 'LeftPaletteLoaderService', 'Sdc.Services.DataTypesService', 'AngularJSBridge', + '$templateCache', ($http:ng.IHttpService, cacheService:CacheService, cookieService:CookieService, @@ -632,8 +642,9 @@ ng1appModule.run([ ecompHeaderService:EcompHeaderService, LeftPaletteLoaderService:LeftPaletteLoaderService, DataTypesService:DataTypesService, - AngularJSBridge):void => { - + AngularJSBridge, + $templateCache:ng.ITemplateCacheService):void => { + $templateCache.put('notification-custom-template.html', require('./view-models/shared/notification-custom-template.html')); //handle cache data - version let initAsdcVersion:Function = ():void => { diff --git a/catalog-ui/src/app/directives/file-opener/file-opener.ts b/catalog-ui/src/app/directives/file-opener/file-opener.ts index c09d6fc553..4abd2573bb 100644 --- a/catalog-ui/src/app/directives/file-opener/file-opener.ts +++ b/catalog-ui/src/app/directives/file-opener/file-opener.ts @@ -51,8 +51,9 @@ export class FileOpenerDirective implements ng.IDirective { scope.onFileSelect = () => { scope.onFileUpload({file: scope.importFile}); - element.html('app/directives/file-opener/file-opener.html'); - this.$compile(element.contents())(scope); + // fix bug 311261 + // element.html('app/directives/file-opener/file-opener.html'); + // this.$compile(element.contents())(scope); }; scope.getExtensionsWithDot = ():string => { diff --git a/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts b/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts index 0dcc93dfa7..7e21f8293b 100644 --- a/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts +++ b/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -import {GraphColors} from "app/utils/constants"; +import { GraphColors, GraphUIObjects} from "app/utils/constants"; import constant = require("lodash/constant"); import {ImagesUrl} from "app/utils/constants"; import {AngularJSBridge} from "app/services/angular-js-bridge-service"; @@ -61,11 +61,11 @@ export class ComponentInstanceNodesStyle { 'shape': 'rectangle', 'label': 'data(displayName)', 'background-image': 'data(img)', - 'width': 65, - 'height': 65, + 'width': GraphUIObjects.DEFAULT_RESOURCE_WIDTH, + 'height': GraphUIObjects.DEFAULT_RESOURCE_WIDTH, 'background-opacity': 0, - "background-width": 65, - "background-height": 65, + "background-width": GraphUIObjects.DEFAULT_RESOURCE_WIDTH, + "background-height": GraphUIObjects.DEFAULT_RESOURCE_WIDTH, 'text-valign': 'bottom', 'text-halign': 'center', 'background-fit': 'cover', @@ -100,10 +100,10 @@ export class ComponentInstanceNodesStyle { 'shape': 'rectangle', 'label': 'data(displayName)', 'background-image': 'data(img)', - 'background-width': 21, - 'background-height': 21, - 'width': 21, - 'height': 21, + 'background-width': GraphUIObjects.SMALL_RESOURCE_WIDTH, + 'background-height': GraphUIObjects.SMALL_RESOURCE_WIDTH, + 'width': GraphUIObjects.SMALL_RESOURCE_WIDTH, + 'height': GraphUIObjects.SMALL_RESOURCE_WIDTH, 'text-valign': 'bottom', 'text-halign': 'center', 'background-opacity': 0, @@ -118,10 +118,10 @@ export class ComponentInstanceNodesStyle { 'shape': 'rectangle', 'label': 'data(displayName)', 'background-image': 'data(img)', - 'background-width': 21, - 'background-height': 21, - 'width': 21, - 'height': 21, + 'background-width': GraphUIObjects.SMALL_RESOURCE_WIDTH, + 'background-height': GraphUIObjects.SMALL_RESOURCE_WIDTH, + 'width': GraphUIObjects.SMALL_RESOURCE_WIDTH, + 'height': GraphUIObjects.SMALL_RESOURCE_WIDTH, 'text-valign': 'bottom', 'text-halign': 'center', 'background-opacity': 0, @@ -200,7 +200,7 @@ export class ComponentInstanceNodesStyle { css: { 'shape': 'rectangle', 'background-image': (ele:Cy.Collection) => { - return ele.data().initImage(ele) + return ele.data().initUncertifiedImage(ele, GraphUIObjects.NODE_OVERLAP_MIN_SIZE) }, "border-width": 0 } @@ -231,7 +231,7 @@ export class ComponentInstanceNodesStyle { public static getBasicNodeHanlde = () => { return { - positionX: "center", + positionX: "right", positionY: "top", offsetX: 15, offsetY: -20, @@ -248,7 +248,7 @@ export class ComponentInstanceNodesStyle { public static getBasicSmallNodeHandle = () => { return { - positionX: "center", + positionX: "right", positionY: "top", offsetX: 3, offsetY: -25, diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts index 651a4281fa..8b3a59ec1f 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts @@ -47,7 +47,8 @@ interface ICompositionGraphScope extends ng.IScope { component:Component; isLoading: boolean; - isViewOnly:boolean; + isViewOnly: boolean; + withSidebar: boolean; // Link menu - create link menu relationMenuDirectiveObj:RelationMenuDirectiveObj; isLinkMenuOpen:boolean; @@ -65,6 +66,14 @@ interface ICompositionGraphScope extends ng.IScope { //Links menus deleteRelation(link:Cy.CollectionEdges):void; hideRelationMenu(); + + //search,zoom in/out/all + componentInstanceNames: Array<string>; //id, name + zoom(zoomIn: boolean): void; + zoomAll(nodes?:Cy.CollectionNodes): void; + getAutoCompleteValues(searchTerm: string):void; + highlightSearchMatches(searchTerm: string): void; + /*//asset popover menu assetPopoverObj:AssetPopoverObj; assetPopoverOpen:boolean; @@ -101,7 +110,8 @@ export class CompositionGraph implements ng.IDirective { template = require('./composition-graph.html'); scope = { component: '=', - isViewOnly: '=' + isViewOnly: '=', + withSidebar: '=' }; link = (scope:ICompositionGraphScope, el:JQuery) => { @@ -147,7 +157,11 @@ export class CompositionGraph implements ng.IDirective { this._cy = cytoscape({ container: graphEl, style: ComponentInstanceNodesStyle.getCompositionGraphStyle(), - zoomingEnabled: false, + zoomingEnabled: true, + maxZoom: 1.2, + minZoom: .1, + userZoomingEnabled: false, + userPanningEnabled: true, selectionType: 'single', boxSelectionEnabled: true, autolock: isViewOnly, @@ -270,6 +284,42 @@ export class CompositionGraph implements ng.IDirective { this.loadGraphData(scope); }); + scope.zoom = (zoomIn: boolean):void => { + let currentZoom: number = this._cy.zoom(); + if (zoomIn) { + this.GeneralGraphUtils.zoomGraphTo(this._cy, currentZoom + .1); + } else { + this.GeneralGraphUtils.zoomGraphTo(this._cy, currentZoom - .1); + } + } + + //Zooms to fit all of the nodes in the collection passed in. If no nodes are passed in, will zoom to fit all nodes on graph + scope.zoomAll = (nodes?:Cy.CollectionNodes) => { + if (!nodes || !nodes.length) { + nodes = this._cy.nodes(); + } + + scope.withSidebar = false; + this._cy.animate({ + fit: { eles: nodes, padding: 20 }, + center: { eles: nodes } + }, { duration: 400 }); + }; + + scope.getAutoCompleteValues = (searchTerm: string) => { + if (searchTerm.length > 1) { //US requirement: only display search results after 2nd letter typed. + let nodes: Cy.CollectionNodes = this.NodesGraphUtils.getMatchingNodesByName(this._cy, searchTerm); + scope.componentInstanceNames = _.map(nodes, node => node.data('name')); + } else { + scope.componentInstanceNames = []; + } + }; + + scope.highlightSearchMatches = (searchTerm: string) => { + this.NodesGraphUtils.highlightMatchingNodesByName(this._cy, searchTerm); + let matchingNodes: Cy.CollectionNodes = this.NodesGraphUtils.getMatchingNodesByName(this._cy, searchTerm); + scope.zoomAll(matchingNodes); + }; scope.createLinkFromMenu = (chosenMatch:MatchBase):void => { scope.isLinkMenuOpen = false; @@ -367,7 +417,7 @@ export class CompositionGraph implements ng.IDirective { });*/ this._cy.on('handlemouseover', (event, payload) => { - if (payload.node.grabbed() /* || this._cy.scratch('_edge_editation_highlights') === true*/) { //no need to add opacity while we are dragging and hovering othe nodes- or if opacity was already calculated for these nodes + if (payload.node.grabbed() || this._cy.scratch('_edge_editation_highlights') === true) { //no need to add opacity while we are dragging and hovering othe nodes- or if opacity was already calculated for these nodes return; } let nodesData = this.NodesGraphUtils.getAllNodesData(this._cy.nodes()); @@ -377,9 +427,9 @@ export class CompositionGraph implements ng.IDirective { let filteredNodesData = this.matchCapabilitiesRequirementsUtils.findByMatchingCapabilitiesToRequirements(payload.node.data().componentInstance, linkableNodes, nodesLinks); this.matchCapabilitiesRequirementsUtils.highlightMatchingComponents(filteredNodesData, this._cy); this.matchCapabilitiesRequirementsUtils.fadeNonMachingComponents(filteredNodesData, nodesData, this._cy, payload.node.data()); - /* + this._cy.scratch()._edge_editation_highlights = true; - scope.hideAssetPopover();*/ + /*scope.hideAssetPopover();*/ }); this._cy.on('handlemouseout', () => { diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html index 1e69d3384a..248f19fb70 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html @@ -20,4 +20,11 @@ </div> + <div class="w-sdc-search-menu" data-ng-class="{'with-sidebar': withSidebar}"> + <ng2-search-with-autocomplete [search-placeholder]="'Type to search'" [auto-complete-values]="componentInstanceNames" (search-changed)="getAutoCompleteValues($event)" (search-button-clicked)="highlightSearchMatches($event)" + [search-bar-class]="'composition-search'"></ng2-search-with-autocomplete> + <div class="zoom-icons sprite-new canvas-fit-all" data-ng-click="zoomAll()"></div> + <div class="zoom-icons sprite-new zoom-plus" data-ng-click="zoom(true)"></div> + <div class="zoom-icons sprite-new zoom-minus" data-ng-click="zoom(false)"></div> + </div> <!--<asset-popover ng-if="assetPopoverOpen" asset-popover-obj="assetPopoverObj" delete-asset="deleteNode(assetPopoverObj.nodeId)"></asset-popover>--> diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts index 608031430b..0ea38af825 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts @@ -64,6 +64,14 @@ export class CompositionGraphGeneralUtils { }; + public zoomGraphTo = (cy:Cy.Instance, zoomLevel: number):void => { + let zy = cy.height() / 2; + let zx = cy.width() / 2; + cy.zoom({ + level: zoomLevel, + renderedPosition: { x: zx, y: zy } + }); + } /** * will return true/false if two nodes overlapping * diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts index feb6ac9a54..449d551cc0 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts @@ -48,6 +48,21 @@ export class CompositionGraphNodesUtils { }) }; + + public highlightMatchingNodesByName = (cy: Cy.Instance, nameToMatch: string) => { + + cy.batch(() => { + cy.nodes("[name !@^= '" + nameToMatch + "']").style({ 'background-image-opacity': 0.4 }); + cy.nodes("[name @^= '" + nameToMatch + "']").style({ 'background-image-opacity': 1 }); + }) + + } + + //Returns all nodes whose name starts with searchTerm + public getMatchingNodesByName = (cy: Cy.Instance, nameToMatch: string): Cy.CollectionNodes => { + return cy.nodes("[name @^= '" + nameToMatch + "']"); + }; + /** * Deletes component instances on server and then removes it from the graph as well * @param cy diff --git a/catalog-ui/src/app/directives/graphs-v2/image-creator/image-creator.service.ts b/catalog-ui/src/app/directives/graphs-v2/image-creator/image-creator.service.ts index 51a77d1272..6d6291d900 100644 --- a/catalog-ui/src/app/directives/graphs-v2/image-creator/image-creator.service.ts +++ b/catalog-ui/src/app/directives/graphs-v2/image-creator/image-creator.service.ts @@ -31,7 +31,7 @@ export class ImageCreatorService { body.appendChild(this._canvas); } - getImageBase64(imageBaseUri:string, imageLayerUri:string):ng.IPromise<string> { + getImageBase64(imageBaseUri:string, imageLayerUri:string, nodeWidth:number, canvasWidth:number, handleSize:number):ng.IPromise<string> { let deferred = this.$q.defer(); let imageBase = new Image(); let imageLayer = new Image(); @@ -42,14 +42,15 @@ export class ImageCreatorService { if (imagesLoaded < 2) { return; } - this._canvas.setAttribute('width', imageBase.width.toString()); - this._canvas.setAttribute('height', imageBase.height.toString()); + this._canvas.setAttribute('width', canvasWidth.toString()); + this._canvas.setAttribute('height', canvasWidth.toString()); let canvasCtx = this._canvas.getContext('2d'); canvasCtx.clearRect(0, 0, this._canvas.width, this._canvas.height); - canvasCtx.drawImage(imageBase, 0, 0, imageBase.width, imageBase.height); - canvasCtx.drawImage(imageLayer, imageBase.width - imageLayer.width, 0, imageLayer.width, imageLayer.height); + //Note: params below are: image, x to start drawing at, y to start drawing at, num of x pixels to draw, num of y pixels to draw + canvasCtx.drawImage(imageBase, 0, canvasWidth - nodeWidth, nodeWidth, nodeWidth); //Draw the node: When nodeWidth == canvasWidth, we'll start at point 0,0. Otherwise, x starts at 0 (but will end before end of canvas) and y starts low enough that node img ends at bottom of canvas. + canvasCtx.drawImage(imageLayer, canvasWidth - handleSize, 0, handleSize, handleSize); //Draw the icon: icon should be drawn in top right corner let base64Image = this._canvas.toDataURL(); deferred.resolve(base64Image); diff --git a/catalog-ui/src/app/models.ts b/catalog-ui/src/app/models.ts index f3eb5d5fa6..ec70ebe8b1 100644 --- a/catalog-ui/src/app/models.ts +++ b/catalog-ui/src/app/models.ts @@ -95,6 +95,7 @@ export * from './models/member'; export * from './models/modules/base-module'; export * from './models/properties'; export * from './models/requirement'; +export * from './models/server-error-response'; export * from './models/tab'; export * from './models/tooltip-data'; export * from './models/user'; diff --git a/catalog-ui/src/app/models/components/component.ts b/catalog-ui/src/app/models/components/component.ts index 9b2c942483..53e8f05cbe 100644 --- a/catalog-ui/src/app/models/components/component.ts +++ b/catalog-ui/src/app/models/components/component.ts @@ -923,16 +923,17 @@ export abstract class Component implements IComponent { } public toJSON = ():any => { - this.componentService = undefined; - this.filterTerm = undefined; - this.iconSprite = undefined; - this.mainCategory = undefined; - this.subCategory = undefined; - this.selectedInstance = undefined; - this.showMenu = undefined; - this.$q = undefined; - this.selectedCategory = undefined; - return this; + let temp = angular.copy(this); + temp.componentService = undefined; + temp.filterTerm = undefined; + temp.iconSprite = undefined; + temp.mainCategory = undefined; + temp.subCategory = undefined; + temp.selectedInstance = undefined; + temp.showMenu = undefined; + temp.$q = undefined; + temp.selectedCategory = undefined; + return temp; }; } diff --git a/catalog-ui/src/app/models/components/resource.ts b/catalog-ui/src/app/models/components/resource.ts index 138b413028..cd839786c5 100644 --- a/catalog-ui/src/app/models/components/resource.ts +++ b/catalog-ui/src/app/models/components/resource.ts @@ -163,17 +163,18 @@ export class Resource extends Component { }; public toJSON = ():any => { - this.componentService = undefined; - this.filterTerm = undefined; - this.iconSprite = undefined; - this.mainCategory = undefined; - this.subCategory = undefined; - this.selectedInstance = undefined; - this.showMenu = undefined; - this.$q = undefined; - this.selectedCategory = undefined; - this.importedFile = undefined; - return this; + let temp = angular.copy(this); + temp.componentService = undefined; + temp.filterTerm = undefined; + temp.iconSprite = undefined; + temp.mainCategory = undefined; + temp.subCategory = undefined; + temp.selectedInstance = undefined; + temp.showMenu = undefined; + temp.$q = undefined; + temp.selectedCategory = undefined; + temp.importedFile = undefined; + return temp; }; } diff --git a/catalog-ui/src/app/models/graph/nodes/base-common-node.ts b/catalog-ui/src/app/models/graph/nodes/base-common-node.ts index 153a18225d..fb43f46bbd 100644 --- a/catalog-ui/src/app/models/graph/nodes/base-common-node.ts +++ b/catalog-ui/src/app/models/graph/nodes/base-common-node.ts @@ -27,7 +27,8 @@ export abstract class CommonNodeBase { public displayName:string; public name:string; - public img:string; + public img: string; + public imgWidth: number; public certified:boolean; public isGroup:boolean; public imagesPath:string; diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-base.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-base.ts index 1e4a735a53..681cebc8d2 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-base.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-base.ts @@ -21,7 +21,7 @@ import {ComponentInstance} from "../../../componentsInstances/componentInstance"; import {CommonCINodeBase} from "../common-ci-node-base"; import {ImageCreatorService} from "app/directives/graphs-v2/image-creator/image-creator.service"; -import {ImagesUrl} from "app/utils"; +import {ImagesUrl, GraphUIObjects} from "app/utils"; import {AngularJSBridge} from "app/services"; export interface ICompositionCiNodeBase { @@ -51,13 +51,27 @@ export abstract class CompositionCiNodeBase extends CommonCINodeBase implements } - public initImage(node:Cy.Collection):string { - + public initUncertifiedImage(node:Cy.Collection, nodeMinSize:number):string { + + let uncertifiedIconWidth:number = GraphUIObjects.HANDLE_SIZE; + let nodeWidth:number = node.data('imgWidth') || node.width(); + let uncertifiedCanvasWidth: number = nodeWidth; + + if (nodeWidth < nodeMinSize) { //uncertified icon will overlap too much of the node, need to expand canvas. + uncertifiedCanvasWidth = nodeWidth + uncertifiedIconWidth/2; //expand canvas so that only half of the icon overlaps with the node + } + this.imageCreator.getImageBase64(this.imagesPath + ImagesUrl.RESOURCE_ICONS + this.componentInstance.icon + '.png', - this.imagesPath + ImagesUrl.RESOURCE_ICONS + 'uncertified.png') + this.imagesPath + ImagesUrl.RESOURCE_ICONS + 'uncertified.png', nodeWidth, uncertifiedCanvasWidth, uncertifiedIconWidth) .then(imageBase64 => { this.img = imageBase64; - node.style({'background-image': this.img}); + node.style({ + 'background-image': this.img, + 'background-width': uncertifiedCanvasWidth, + 'background-height': uncertifiedCanvasWidth, + 'width': uncertifiedCanvasWidth, + 'height': uncertifiedCanvasWidth + }); }); return this.img; diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-cp.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-cp.ts index 85534c78de..cded0ea104 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-cp.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-cp.ts @@ -22,7 +22,7 @@ import {CompositionCiNodeBase} from "./composition-ci-node-base"; import {ComponentInstance} from "../../../componentsInstances/componentInstance"; import {ImageCreatorService} from "../../../../directives/graphs-v2/image-creator/image-creator.service"; import {AngularJSBridge} from "../../../../services/angular-js-bridge-service"; -import {ImagesUrl} from "../../../../utils/constants"; +import { ImagesUrl, GraphUIObjects} from "../../../../utils/constants"; export class CompositionCiNodeCp extends CompositionCiNodeBase { @@ -35,6 +35,7 @@ export class CompositionCiNodeCp extends CompositionCiNodeBase { private initCp():void { let sdcConfig = AngularJSBridge.getAngularConfig(); this.img = sdcConfig.imagesPath + ImagesUrl.RESOURCE_ICONS + this.componentInstance.icon + '.png'; + this.imgWidth = GraphUIObjects.SMALL_RESOURCE_WIDTH; this.type = "basic-small-node"; //if the cp from type cpEndPointInstances create with another template if (sdcConfig.cpEndPointInstances.indexOf(this.componentInstance.icon) > -1) { diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service.ts index 3a9b8457fd..81ee61a14f 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service.ts @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -import {ImagesUrl} from "../../../../utils/constants"; +import { ImagesUrl, GraphUIObjects} from "../../../../utils/constants"; import {ComponentInstance, CompositionCiNodeBase} from "../../../../models"; import {ImageCreatorService} from "../../../../directives/graphs-v2/image-creator/image-creator.service"; export class CompositionCiNodeService extends CompositionCiNodeBase { @@ -32,6 +32,7 @@ export class CompositionCiNodeService extends CompositionCiNodeBase { private initService():void { this.img = this.imagesPath + ImagesUrl.SERVICE_ICONS + this.componentInstance.icon + '.png'; + this.imgWidth = GraphUIObjects.DEFAULT_RESOURCE_WIDTH; this.classes = 'service-node' if (!this.certified) { this.classes = this.classes + ' not-certified'; diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vf.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vf.ts index 5d37db30fc..005804c11f 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vf.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vf.ts @@ -20,7 +20,7 @@ import {CompositionCiNodeBase} from "./composition-ci-node-base"; import {ComponentInstance} from "../../../componentsInstances/componentInstance"; import {ImageCreatorService} from "../../../../directives/graphs-v2/image-creator/image-creator.service"; -import {ImagesUrl} from "../../../../utils/constants"; +import { ImagesUrl, GraphUIObjects} from "../../../../utils/constants"; export class CompositionCiNodeVf extends CompositionCiNodeBase { @@ -32,6 +32,7 @@ export class CompositionCiNodeVf extends CompositionCiNodeBase { private initVf():void { this.img = this.imagesPath + ImagesUrl.RESOURCE_ICONS + this.componentInstance.icon + '.png'; + this.imgWidth = GraphUIObjects.DEFAULT_RESOURCE_WIDTH; this.classes = 'vf-node'; if (!this.certified) { this.classes = this.classes + ' not-certified'; diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vl.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vl.ts index db46e48ad7..bf52ec0408 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vl.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vl.ts @@ -20,7 +20,7 @@ import {ComponentInstance} from "../../../componentsInstances/componentInstance"; import {ImageCreatorService} from "../../../../directives/graphs-v2/image-creator/image-creator.service"; import {CompositionCiNodeBase} from "./composition-ci-node-base"; -import {ImagesUrl} from "../../../../utils/constants"; +import { ImagesUrl, GraphUIObjects} from "../../../../utils/constants"; export class CompositionCiNodeVl extends CompositionCiNodeBase { private toolTipText:string; @@ -47,6 +47,7 @@ export class CompositionCiNodeVl extends CompositionCiNodeBase { } } this.img = this.imagesPath + ImagesUrl.RESOURCE_ICONS + 'vl.png'; + this.imgWidth = GraphUIObjects.SMALL_RESOURCE_WIDTH; this.classes = 'vl-node'; if (!this.certified) { diff --git a/catalog-ui/src/app/models/modal.ts b/catalog-ui/src/app/models/modal.ts index 51aa5e19a7..b7bdf251fe 100644 --- a/catalog-ui/src/app/models/modal.ts +++ b/catalog-ui/src/app/models/modal.ts @@ -5,12 +5,14 @@ export class ModalModel { title: string; content: any; buttons: Array<ButtonModel>; + type: string; 'standard|error|alert' - constructor(size?: string, title?: string, content?: any, buttons?: Array<ButtonModel>) { + constructor(size?: string, title?: string, content?: any, buttons?: Array<ButtonModel>, type?:string) { this.size = size; this.title = title; this.content = content; this.buttons = buttons; + this.type = type || 'standard'; } } diff --git a/catalog-ui/src/app/models/server-error-response.ts b/catalog-ui/src/app/models/server-error-response.ts new file mode 100644 index 0000000000..61d09af48b --- /dev/null +++ b/catalog-ui/src/app/models/server-error-response.ts @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +/** + * Created by ngordon on 7/27/2017. + */ + +import { Response } from '@angular/http'; +import { SEVERITY, ServerErrors } from "../utils/constants"; + +export class ServerErrorResponse { + + title: string; + message: string; + messageId: string; + status: number; + severity: SEVERITY; + + constructor(response?: Response) { + + if (response) { + let rejectionObj: any = {}; + if (response.text().length) { + let rejection = response.json(); + rejectionObj = rejection.serviceException || rejection.requestError && (rejection.requestError.serviceException || rejection.requestError.policyException); + rejectionObj.text = this.getFormattedMessage(rejectionObj.text || ServerErrors.MESSAGE_ERROR, rejectionObj.variables); + } + + this.title = ServerErrors.ERROR_TITLE; + this.message = rejectionObj.text || response.statusText || ServerErrors.DEFAULT_ERROR; + this.messageId = rejectionObj.messageId; + this.status = response.status; + this.severity = SEVERITY.ERROR; + } + } + + + private getFormattedMessage = (text: string, variables: Array<string>): string => { //OLD CODE + // Remove the "Error: " text at the begining + if (text.trim().indexOf("Error:") === 0) { + text = text.replace("Error:", "").trim(); + } + + //mshitrit DE199895 bug fix + let count: number = 0; + variables.forEach(function (item) { + variables[count] = item ? item.replace('<', '<').replace('>', '>') : ''; + count++; + }); + + // Format the message in case has array to <ul><li> + text = text.replace(/\[%(\d+)\]/g, function (_, m) { + let tmp = []; + let list = variables[--m].split(";"); + list.forEach(function (item) { + tmp.push("<li>" + item + "</li>"); + }); + return "<ul>" + tmp.join("") + "</ul>"; + }); + + // Format the message %1 %2 + text = text.format(variables); + + return text; + + }; +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/app.module.ts b/catalog-ui/src/app/ng2/app.module.ts index 09b40e920f..88c2d876c4 100644 --- a/catalog-ui/src/app/ng2/app.module.ts +++ b/catalog-ui/src/app/ng2/app.module.ts @@ -32,14 +32,15 @@ import { } from "./utils/ng1-upgraded-provider"; import {ConfigService} from "./services/config.service"; import {HttpModule} from '@angular/http'; +import {HttpService} from './services/http.service'; import {AuthenticationService} from './services/authentication.service'; import {Cookie2Service} from "./services/cookie.service"; import {ComponentServiceNg2} from "./services/component-services/component.service"; import {ServiceServiceNg2} from "./services/component-services/service.service"; import {ComponentInstanceServiceNg2} from "./services/component-instance-services/component-instance.service"; -import { InterceptorService } from 'ng2-interceptors'; import { XHRBackend, RequestOptions } from '@angular/http'; -import {HttpInterceptor} from "./services/http.interceptor.service"; +import { SearchBarComponent } from './shared/search-bar/search-bar.component'; +import { SearchWithAutoCompleteComponent } from './shared/search-with-autocomplete/search-with-autocomplete.component'; export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); @@ -47,20 +48,12 @@ export function configServiceFactory(config:ConfigService) { return () => config.loadValidationConfiguration(); } -export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions){ - let service = new InterceptorService(xhrBackend, requestOptions); - service.addInterceptor(new HttpInterceptor()); - return service; -} - - -// export function httpServiceFactory(backend: XHRBackend, options: RequestOptions) { -// return new HttpService(backend, options); -// } @NgModule({ declarations: [ - AppComponent + AppComponent, + SearchBarComponent, + SearchWithAutoCompleteComponent ], imports: [ BrowserModule, @@ -70,7 +63,7 @@ export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: Reque PropertiesAssignmentModule ], exports: [], - entryComponents: [], + entryComponents: [SearchWithAutoCompleteComponent], providers: [ DataTypesServiceProvider, SharingServiceProvider, @@ -83,6 +76,7 @@ export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: Reque ConfigService, ComponentServiceNg2, ServiceServiceNg2, + HttpService, ComponentInstanceServiceNg2, { provide: APP_INITIALIZER, @@ -90,11 +84,6 @@ export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: Reque deps: [ConfigService], multi: true }, - { - provide: InterceptorService, - useFactory: interceptorFactory, - deps: [XHRBackend, RequestOptions] - } ], bootstrap: [AppComponent] }) diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.ts b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.ts index 8b27ab7e3a..3339b605ca 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.ts +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.ts @@ -35,7 +35,7 @@ export class UiElementIntegerInputComponent extends UiElementBase implements UiE onSave() { if (!this.control.invalid){ - this.baseEmitter.emit(JSON.parse(this.value)); + this.baseEmitter.emit(this.value ? JSON.parse(this.value) : this.value); } } } diff --git a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.html b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.html index 38de3ce649..2b58d0f086 100644 --- a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.html +++ b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.html @@ -1,5 +1,5 @@ <div class="properties-table"> - <loader [display]="isLoading" size="large" [relative]="false"></loader> + <loader [display]="isLoading" [size]="'large'" [relative]="true"></loader> <div class="table-header"> <div class="table-cell col1">Property Name</div> <div class="table-cell col3">From Instance</div> diff --git a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less index 05378f0eb9..89c7287449 100644 --- a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less +++ b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less @@ -85,7 +85,7 @@ border-right:#d2d2d2 solid 1px; } &.col1 { - flex: 0 0 300px; + flex: 1 0 200px; max-width:300px; display: flex; justify-content: space-between; diff --git a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.ts b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.ts index 30cdb89d8e..736655f3f7 100644 --- a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.ts +++ b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.ts @@ -57,7 +57,7 @@ export class InputsTableComponent { openDeleteModal = (input:InputFEModel) => { this.selectedInputToDelete = input; - this.modalService.openActionModal("Delete Input", "Are you sure you want to delete this input?", "Delete", this.onDeleteInput, "Close"); + this.modalService.createActionModal("Delete Input", "Are you sure you want to delete this input?", "Delete", this.onDeleteInput, "Close").instance.open(); } } diff --git a/catalog-ui/src/app/ng2/components/loader/loader.component.html b/catalog-ui/src/app/ng2/components/loader/loader.component.html index 0e13cee674..a62aa114d9 100644 --- a/catalog-ui/src/app/ng2/components/loader/loader.component.html +++ b/catalog-ui/src/app/ng2/components/loader/loader.component.html @@ -1,4 +1,5 @@ -<div *ngIf="display" data-tests-id="tlv-loader"> +<div *ngIf="isVisible" data-tests-id="tlv-loader" [ngClass]="relative ? 'loader-relative' : 'loader-fixed'" + [style.top]="offset.top" [style.left]="offset.left" [style.width]="offset.width" [style.height]="offset.height"> <div class="tlv-loader-back" [ngClass]="{'tlv-loader-relative':relative}"></div> <div class="tlv-loader {{size}}"></div> </div> diff --git a/catalog-ui/src/app/ng2/components/loader/loader.component.less b/catalog-ui/src/app/ng2/components/loader/loader.component.less index 054b6021a1..ddb9915176 100644 --- a/catalog-ui/src/app/ng2/components/loader/loader.component.less +++ b/catalog-ui/src/app/ng2/components/loader/loader.component.less @@ -16,6 +16,22 @@ z-index: 10002; } +.loader-relative { + display: block; + position:absolute; + width: 100%; + height:100%; +} + +.loader-fixed { + display: block; + position:fixed; + top:0; + left:0; + width: 100%; + height:100%; +} + @keyframes fadein { from { opacity: 0; } to { opacity: 0.8; } diff --git a/catalog-ui/src/app/ng2/components/loader/loader.component.ts b/catalog-ui/src/app/ng2/components/loader/loader.component.ts index 92278d3ff5..f66aa551e2 100644 --- a/catalog-ui/src/app/ng2/components/loader/loader.component.ts +++ b/catalog-ui/src/app/ng2/components/loader/loader.component.ts @@ -21,7 +21,7 @@ /** * Created by rc2122 on 6/6/2017. */ -import {Component, Input, ElementRef, Renderer, SimpleChanges} from "@angular/core"; +import { Component, Input, ViewContainerRef, SimpleChanges} from "@angular/core"; @Component({ selector: 'loader', templateUrl: './loader.component.html', @@ -29,13 +29,20 @@ import {Component, Input, ElementRef, Renderer, SimpleChanges} from "@angular/co }) export class LoaderComponent { - @Input() display:boolean; - @Input() size:string;// small || medium || large - @Input() relative: boolean; - @Input() elementSelector: string; // optional. If is relative is set to true, option to pass in element that loader should be relative to. Otherwise, will be relative to parent element. + @Input() display: boolean; + @Input() size: string;// small || medium || large + @Input() relative: boolean; // If is relative is set to true, loader will appear over parent element. Otherwise, will be fixed over the entire page. + @Input() loaderDelay: number; //optional - number of ms to delay loader display. + private isVisible: boolean = false; + private offset : { + top: string; + left: string; + width: string; + height: string; + }; - constructor (private el: ElementRef, private renderer: Renderer){ + constructor(private viewContainerRef: ViewContainerRef) { } ngOnInit() { @@ -49,46 +56,31 @@ export class LoaderComponent { ngOnChanges(changes: SimpleChanges) { if(changes.display){ - if (this.display) { - this.changeLoaderDisplay(false); //display is set to true, so loader will appear unless we explicitly tell it not to. - window.setTimeout((): void => { - this.display && this.changeLoaderDisplay(true); //only show loader if we still need to display it. - }, 500); - } else { - window.setTimeout(():void => { - this.changeLoaderDisplay(false); - }, 0); - } + this.changeLoaderDisplay(this.display); } } - changeLoaderDisplay = (display: boolean): void => { + private changeLoaderDisplay = (display: boolean): void => { if (display) { - this.calculateLoaderPosition(); - this.renderer.setElementStyle(this.el.nativeElement, 'display', 'block'); + window.setTimeout((): void => { + this.display && this.showLoader(); //only show loader if this.display has not changed in the meanwhile. + }, this.loaderDelay || 0); } else { - this.renderer.setElementStyle(this.el.nativeElement, 'display', 'none'); + this.isVisible = false; } } - calculateLoaderPosition = () => { - if (this.relative === true) { // Can change the parent position to relative without causing style issues. - let parent = (this.elementSelector) ? angular.element(this.elementSelector).get(0) : this.el.nativeElement.parentElement; - this.renderer.setElementStyle(parent, 'position', 'relative'); - this.setLoaderPosition(0, 0); //will be relative to parent and appear over specified element - //TODO: DONT force parent to have position relative; set inner div's style instead of outer element - // let parentPos: ClientRect = this.el.nativeElement.parentElement.getBoundingClientRect(); - // this.setLoaderPosition(parentPos.top, parentPos.left, parentPos.width, parentPos.height); - } else { - this.setLoaderPosition(0, 0); //will appear over whole page + private showLoader = () => { + if (this.relative === true) { + let parentElement = this.viewContainerRef.element.nativeElement.parentElement; + this.offset = { + left: (parentElement.offsetLeft) ? parentElement.offsetLeft + "px" : undefined, + top: (parentElement.offsetTop) ? parentElement.offsetTop + "px" : undefined, + width: (parentElement.offsetWidth) ? parentElement.offsetWidth + "px" : undefined, + height: (parentElement.offsetHeight) ? parentElement.offsetHeight + "px" : undefined + }; } + this.isVisible = true; } - setLoaderPosition = (top:number, left:number, width?:number, height?:number): void => { - this.renderer.setElementStyle(this.el.nativeElement, 'position', 'absolute'); - this.renderer.setElementStyle(this.el.nativeElement, 'top', top? top.toString() : "0"); - this.renderer.setElementStyle(this.el.nativeElement, 'left', left? left.toString() : "0"); - this.renderer.setElementStyle(this.el.nativeElement, 'width', width? width.toString() : "100%"); - this.renderer.setElementStyle(this.el.nativeElement, 'height', height? height.toString() : "100%"); - }; } diff --git a/catalog-ui/src/app/ng2/components/modal/error-message/error-message.component.html b/catalog-ui/src/app/ng2/components/modal/error-message/error-message.component.html new file mode 100644 index 0000000000..433bd4fd6f --- /dev/null +++ b/catalog-ui/src/app/ng2/components/modal/error-message/error-message.component.html @@ -0,0 +1,5 @@ +<div class="error-message-component"> + <div>Error code: {{input.messageId}}</div> + <div>Status code: {{input.status}}</div> + <div class="error-message">{{input.message}}</div> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/modal/error-message/error-message.component.ts b/catalog-ui/src/app/ng2/components/modal/error-message/error-message.component.ts new file mode 100644 index 0000000000..c0d6673412 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/modal/error-message/error-message.component.ts @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +/** + * Created by ngordon on 7/30/2017. + */ +import { Component, Input } from '@angular/core'; +import { ServerErrorResponse } from 'app/models'; + +@Component({ + selector: 'error-message', + templateUrl: './error-message.component.html' +}) + +export class ErrorMessageComponent { + @Input() input: ServerErrorResponse; + + constructor() { + } + +} diff --git a/catalog-ui/src/app/ng2/components/modal/modal.component.html b/catalog-ui/src/app/ng2/components/modal/modal.component.html index cc411bc751..d843867cdb 100644 --- a/catalog-ui/src/app/ng2/components/modal/modal.component.html +++ b/catalog-ui/src/app/ng2/components/modal/modal.component.html @@ -1,10 +1,14 @@ <div class="custom-modal {{input.size}}"> <div class="ng2-modal-content"> - <div class="ng2-modal-header"> + <div class="ng2-modal-header modal-type-{{input.type}}"> <span class="title">{{ input.title }}</span> <span class="close-button" (click)="close()"></span> </div> - <div class="ng2-modal-body" >{{input.content}}</div> + <div class="ng2-modal-body" > + <div *ngIf="input.content">{{input.content}}</div> + <div #dynamicContentContainer></div> + </div> + <div class="ng2-modal-footer"> <button *ngFor="let button of input.buttons" class="tlv-btn {{button.cssClass}}" diff --git a/catalog-ui/src/app/ng2/components/modal/modal.component.less b/catalog-ui/src/app/ng2/components/modal/modal.component.less index a35f829e6a..c87162afb0 100644 --- a/catalog-ui/src/app/ng2/components/modal/modal.component.less +++ b/catalog-ui/src/app/ng2/components/modal/modal.component.less @@ -37,12 +37,25 @@ display: -ms-flexbox; display: flex; text-align: left; - border-bottom: solid 1px @main_color_o; -webkit-box-align: center; -ms-flex-align: center; align-items: center; margin: 0px 20px; + + &.modal-type-standard { + border-bottom: solid 3px @main_color_a; + } + + &.modal-type-error { + border-bottom: solid 3px @func_color_q; + } + + &.modal-type-alert{ + border-bottom: solid 3px @main_color_h; + } + .title{ + .s_18_m; -webkit-box-flex: 999; -ms-flex-positive: 999; flex-grow: 999; diff --git a/catalog-ui/src/app/ng2/components/modal/modal.component.ts b/catalog-ui/src/app/ng2/components/modal/modal.component.ts index 09fb9abdd1..89db8d1140 100644 --- a/catalog-ui/src/app/ng2/components/modal/modal.component.ts +++ b/catalog-ui/src/app/ng2/components/modal/modal.component.ts @@ -22,7 +22,7 @@ * Created by rc2122 on 6/1/2017. */ import { Component, ElementRef, Input, OnInit, OnDestroy } from '@angular/core'; -//import {ViewContainerRef, ViewChild} from '@angular/core'; +import {ViewContainerRef, ViewChild} from '@angular/core'; import * as $ from 'jquery'; import { ButtonsModelMap, ModalModel } from 'app/models'; @@ -34,9 +34,9 @@ import { ButtonsModelMap, ModalModel } from 'app/models'; export class ModalComponent implements OnInit, OnDestroy { @Input() input: ModalModel; + @Input() dynamicContent: any; + @ViewChild('dynamicContentContainer', { read: ViewContainerRef }) dynamicContentContainer: ViewContainerRef; //Allows for custom component as body instead of simple message. See ModalService.createActionModal for implementation details, and HttpService's catchError() for example. private modalElement: JQuery; - //@ViewChild('modalBody', { read: ViewContainerRef }) modalContainer: ViewContainerRef; //TODO: allow for custom component as body instead of simple message - constructor( el: ElementRef ) { this.modalElement = $(el.nativeElement); diff --git a/catalog-ui/src/app/ng2/components/modal/modal.module.ts b/catalog-ui/src/app/ng2/components/modal/modal.module.ts index d77be2cd23..892f6993dd 100644 --- a/catalog-ui/src/app/ng2/components/modal/modal.module.ts +++ b/catalog-ui/src/app/ng2/components/modal/modal.module.ts @@ -1,16 +1,19 @@ import { NgModule } from "@angular/core"; import { CommonModule } from '@angular/common'; import { ModalService } from 'app/ng2/services/modal.service'; -import { ModalComponent } from "app/ng2/components/modal/modal.component" +import { ModalComponent } from "app/ng2/components/modal/modal.component"; +import { ErrorMessageComponent } from "./error-message/error-message.component"; @NgModule({ declarations: [ ModalComponent, + ErrorMessageComponent ], imports: [CommonModule], exports: [], - entryComponents: [ - ModalComponent + entryComponents: [ //need to add anything that will be dynamically created + ModalComponent, + ErrorMessageComponent ], providers: [ModalService] }) diff --git a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html index 95cc79dce9..3ffc9c16be 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html +++ b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html @@ -10,7 +10,7 @@ </div> <div class="table-cell" *ngIf="!canBeDeclared && !property.isChildOfListOrMap">{{property.name}}</div> <!-- simple children of complex type within map or list --> <div class="table-cell map-entry" *ngIf="property.isChildOfListOrMap && propType == derivedPropertyTypes.MAP"><!-- map left cell --> - <input [value]="property.mapKey" #mapKey (change)="mapKeyChanged.emit(mapKey)" [readonly]="readonly" type="text" [ngClass]="{'disabled':readonly, 'error':!mapKey.validity.valid}" /> + <input [value]="property.mapKey" #mapKey (change)="mapKeyChanged.emit(mapKey)" [readonly]="readonly" type="text" [ngClass]="{'disabled':readonly, 'error':!mapKey.validity.valid}" required/> </div> </ng-container> <!-- RIGHT CELL OR FULL WIDTH CELL--> @@ -23,7 +23,7 @@ [name]="property.name" [path]="property.propertiesName" (valueChange)="valueChanged.emit();" - [readonly]="readonly||property.isDeclared||property.isDisabled" + [readonly]="readonly || property.isDeclared || property.isDisabled" ></dynamic-element> </div> </ng-container> @@ -38,7 +38,7 @@ <ng-container *ngIf="!property.isDeclared"> <a *ngIf="(propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && !property.isChildOfListOrMap" class="property-icon add-item" (click)="createNewChildProperty();" [ngClass]="{'disabled':readonly || preventInsertItem(property)}">Add value to list</a> <span *ngIf="property.isChildOfListOrMap" (click)="deleteItem.emit(property);" class="property-icon sprite-new delete-item-icon" [ngClass]="{'disabled':readonly}"></span> - <span *ngIf="!isPropertyFEModel && (propType == derivedPropertyTypes.COMPLEX || ((propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && hasChildren()))" (click)="expandChildById(propPath)" class="property-icon sprite-new round-expand-icon" [class.open]="expandedChildId.indexOf(propPath) == 0"></span> + <span *ngIf="!isPropertyFEModel && (propType == derivedPropertyTypes.COMPLEX || ((propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && hasChildren))" (click)="expandChildById(propPath)" class="property-icon sprite-new round-expand-icon" [class.open]="expandedChildId.indexOf(propPath) == 0"></span> </ng-container> </div> @@ -52,6 +52,7 @@ [expandedChildId]="expandedChildId" [propertyNameSearchText]="propertyNameSearchText" [readonly]="readonly" + [hasChildren]="getHasChildren(prop)" (valueChanged)="childValueChanged(prop)" (mapKeyChanged)="removeValueFromParent(prop, $event)" (expandChild)="expandChildById($event)" diff --git a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts index 59811b582d..9cf043098b 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts +++ b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts @@ -46,6 +46,7 @@ export class DynamicPropertyComponent { @Input() selectedPropertyId: string; @Input() propertyNameSearchText: string; @Input() readonly: boolean; + @Input() hasChildren: boolean; @Output() valueChanged: EventEmitter<any> = new EventEmitter<any>(); @Output() expandChild: EventEmitter<string> = new EventEmitter<string>(); @@ -83,8 +84,10 @@ export class DynamicPropertyComponent { this.checkProperty.emit(propName); } - hasChildren = (): number => { - return (this.property.valueObj && typeof this.property.valueObj == 'object') ? Object.keys(this.property.valueObj).length : 0; + getHasChildren = (property:DerivedFEProperty): boolean => {// enter to this function only from base property (PropertyFEModel) and check for child property if it has children + return _.filter((<PropertyFEModel>this.property).flattenedChildren,(prop:DerivedFEProperty)=>{ + return _.startsWith(prop.propertiesName + '#', property.propertiesName); + }).length > 1; } createNewChildProperty = (): void => { @@ -106,13 +109,26 @@ export class DynamicPropertyComponent { if(!newProps[0].schema.property.isSimpleType){ - angular.forEach(newProps, (prop:DerivedFEProperty):void => { //Update parent PropertyFEModel with value for each child, including nested props + if ( newProps[0].mapKey ) {//prevent update the new item value on parent property valueObj and saving on BE if it is map item, it will be updated and saved only after user enter key (when it is list item- the map key is the es type) + this.updateMapKeyValueOnMainParent(newProps); + if (this.property.getParentNamesArray(newProps[0].propertiesName, []).indexOf('') === -1) { + this.valueChanged.emit(this.property.name); + } + } + } + } + } + + updateMapKeyValueOnMainParent(childrenProps: Array<DerivedFEProperty>){ + if (this.property instanceof PropertyFEModel) { + //Update only if all this property parents has key name + if (this.property.getParentNamesArray(childrenProps[0].propertiesName, []).indexOf('') === -1){ + angular.forEach(childrenProps, (prop:DerivedFEProperty):void => { //Update parent PropertyFEModel with value for each child, including nested props (<PropertyFEModel>this.property).childPropUpdated(prop); },this); //grab the cumulative value for the new item from parent PropertyFEModel and assign that value to DerivedFEProp[0] (which is the list or map parent with UUID of the set we just added) - let parentNames = (<PropertyFEModel>this.property).getParentNamesArray(newProps[0].propertiesName, []); - newProps[0].valueObj = _.get(this.property.valueObj, parentNames.join('.')); - this.valueChanged.emit(this.property.name); + let parentNames = (<PropertyFEModel>this.property).getParentNamesArray(childrenProps[0].propertiesName, []); + childrenProps[0].valueObj = _.get(this.property.valueObj, parentNames.join('.')); } } } @@ -120,9 +136,11 @@ export class DynamicPropertyComponent { childValueChanged = (property: DerivedFEProperty) => { //value of child property changed if (this.property instanceof PropertyFEModel) { // will always be the case - this.property.childPropUpdated(property); - this.dataTypeService.checkForCustomBehavior(this.property); - this.valueChanged.emit(this.property.name); + if (this.property.getParentNamesArray(property.propertiesName, []).indexOf('') === -1) {//If one of the parents is empty key -don't save + this.property.childPropUpdated(property); + this.dataTypeService.checkForCustomBehavior(this.property); + this.valueChanged.emit(this.property.name); + } } } @@ -142,6 +160,9 @@ export class DynamicPropertyComponent { let oldKey = item.mapKey; if (target && typeof target.value == 'string') { //allow saving empty string let replaceKey:string = target.value; + if (!replaceKey) {//prevent delete map key + return; + } if(Object.keys(itemParent.valueObj).indexOf(replaceKey) > -1){//the key is exists target.setCustomValidity('This key is already exists.'); return; @@ -149,6 +170,14 @@ export class DynamicPropertyComponent { target.setCustomValidity(''); _.set(itemParent.valueObj, replaceKey, itemParent.valueObj[oldKey]); item.mapKey = replaceKey; + //If the map key was empty its valueObj was not updated on its prent property valueObj, and now we should update it. + if(!oldKey && !item.schema.property.isSimpleType){ + //Search this map item children and update these value on parent property valueOBj + let mapKeyFlattenChildren:Array<DerivedFEProperty> = _.filter(this.property.flattenedChildren, (prop:DerivedFEProperty) => { + return _.startsWith(prop.propertiesName, item.propertiesName); + }); + this.updateMapKeyValueOnMainParent(mapKeyFlattenChildren); + } } } delete itemParent.valueObj[oldKey]; @@ -156,11 +185,12 @@ export class DynamicPropertyComponent { let itemIndex: number = this.property.flattenedChildren.filter(prop => prop.parentName == item.parentName).map(prop => prop.propertiesName).indexOf(item.propertiesName); itemParent.valueObj.splice(itemIndex, 1); } - - if (itemParent instanceof PropertyFEModel) { //direct child - this.valueChanged.emit(this.property.name); - } else { //nested child - need to update parent prop by getting flattened name (recurse through parents and replace map/list keys, etc) - this.childValueChanged(itemParent); + if (item.mapKey) {//prevent going to BE if user tries to delete map item without key (it was not saved in BE) + if (itemParent instanceof PropertyFEModel) { //direct child + this.valueChanged.emit(this.property.name); + } else { //nested child - need to update parent prop by getting flattened name (recurse through parents and replace map/list keys, etc) + this.childValueChanged(itemParent); + } } } } diff --git a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.html b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.html index c57998af5e..a9dc499e7d 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.html +++ b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.html @@ -1,5 +1,5 @@ <div class="properties-table"> - <loader [display]="isLoading" size="large" [relative]="false"></loader> + <loader [display]="isLoading" [size]="'large'" [relative]="true" [loaderDelay]="500"></loader> <div class="table-header"> <div class="table-cell col1">Property Name</div> <div class="table-cell col2">Type</div> diff --git a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less index 3eb7e960ab..9ede84faff 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less +++ b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less @@ -91,7 +91,7 @@ border-right:#d2d2d2 solid 1px; } &.col1 { - flex: 0 0 300px; + flex: 1 0 210px; max-width:300px; display: flex; justify-content: space-between; @@ -100,7 +100,7 @@ .property-name { flex: 1; display: flex; - max-width: 270px; + max-width: 90%; } .property-description-icon { @@ -123,7 +123,7 @@ } &.valueCol { - flex: 1 0 350px; + flex: 2 0 300px; display: flex; @media @smaller-screen { flex: 1 0 40%;} } diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.module.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.module.ts index 3a5daba711..1c6f51314d 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.module.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.module.ts @@ -45,7 +45,6 @@ import { KeysPipe } from 'app/ng2/pipes/keys.pipe'; import {TooltipModule} from "../../components/tooltip/tooltip.module"; import { ComponentModeService } from "app/ng2/services/component-mode.service" import {LoaderComponent} from "app/ng2/components/loader/loader.component" -import {HttpInterceptor} from "../../services/http.interceptor.service"; @NgModule({ declarations: [ @@ -81,7 +80,7 @@ import {HttpInterceptor} from "../../services/http.interceptor.service"; // PopoverContentComponent, // PopoverComponent ], - providers: [PropertiesService, HierarchyNavService, PropertiesUtils, DataTypeService,HttpInterceptor, ContentAfterLastDotPipe, GroupByPipe, KeysPipe, ComponentModeService] + providers: [PropertiesService, HierarchyNavService, PropertiesUtils, DataTypeService, ContentAfterLastDotPipe, GroupByPipe, KeysPipe, ComponentModeService] }) export class PropertiesAssignmentModule { diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html index 0b50357a5c..be7e03dccd 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html @@ -43,7 +43,7 @@ <tabs #hierarchyNavTabs tabStyle="simple-tabs"> <tab tabTitle="Composition"> <div class="hierarchy-nav-container"> - <loader [display]="loadingInstances" size="medium" [relative]="true"></loader> + <loader [display]="loadingInstances" [size]="'medium'" [relative]="true" [loaderDelay]="500"></loader> <div class="hierarchy-header white-sub-header"> <span tooltip="{{component.name}}">{{component.name}}</span> </div> diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.less b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.less index 8151d001e8..03974bf723 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.less +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.less @@ -1,5 +1,5 @@ @import '../../../../assets/styles/variables'; -//@import url('https://fonts.googleapis.com/css?family=Open+Sans'); +@import '../../../../assets/styles/mixins'; @ng2-shadow-gray: #f8f8f8; @ng2-light-gray: #eaeaea; @ng2-medium-gray: #d2d2d2; @@ -36,7 +36,7 @@ /deep/ .tab { padding: 12px; flex: 1; - font-weight:bold; + font-family: @font-opensans-regular; &.active { color:#009fdb; @@ -44,6 +44,7 @@ border-top: solid 4px #009fdb; background-color: white; padding-top:9px; + font-family: @font-opensans-medium; } .tab-indication { @@ -129,8 +130,12 @@ flex: none; padding: 8px 20px 0; font-size: 14px; - font-weight:bold; line-height:30px; + font-family: @font-opensans-regular; + + &.active { + font-family: @font-opensans-medium; + } } } @@ -146,8 +151,6 @@ background-color: #fffefe; box-shadow: 0px 1px 0.99px 0.01px rgba(34, 31, 31, 0.15); border-bottom: #d2d2d2 solid 1px; - color:#009fdb; - font-weight:bold; font-size:14px; text-align:left; flex:0 0 auto; @@ -155,6 +158,8 @@ text-overflow: ellipsis; white-space: nowrap; overflow: hidden; + .a_13_r; + text-transform: uppercase; &.hierarchy-header { padding-left:20px; diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts index 6782b72fa2..82754f13f0 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts @@ -105,7 +105,7 @@ export class PropertiesAssignmentComponent { }); this.loadingInputs = false; - }); + }, error => {}); //ignore error this.componentServiceNg2 .getComponentResourceInstances(this.component) .subscribe(response => { @@ -120,7 +120,7 @@ export class PropertiesAssignmentComponent { this.loadingProperties = false; } this.selectFirstInstanceByDefault(); - }); + }, error => {}); //ignore error }; @@ -159,7 +159,7 @@ export class PropertiesAssignmentComponent { this.processInstancePropertiesResponse(instanceBePropertiesMap, true); this.loadingProperties = false; - }); + }, error => {}); //ignore error } else { this.componentInstanceServiceNg2 .getComponentInstanceProperties(this.component, resourceInstance.uniqueId) @@ -167,7 +167,7 @@ export class PropertiesAssignmentComponent { instanceBePropertiesMap[resourceInstance.uniqueId] = response; this.processInstancePropertiesResponse(instanceBePropertiesMap, false); this.loadingProperties = false; - }); + }, error => {}); //ignore error } if(resourceInstance.componentName === "vnfConfiguration") { @@ -203,16 +203,16 @@ export class PropertiesAssignmentComponent { this.componentInstanceServiceNg2 .updateInstanceInput(this.component, this.selectedInstanceData.uniqueId, inputToUpdate) .subscribe(response => { - console.log("update resource instance input and got this response: ", response); - }) + console.log("Update resource instance input response: ", response); + }, error => {}); //ignore error } else { let propertyBe = new PropertyBEModel(event); this.componentInstanceServiceNg2 .updateInstanceProperty(this.component, this.selectedInstanceData.uniqueId, propertyBe) .subscribe(response => { - console.log("updated resource instance property and got this response: ", response); - }); + console.log("Update resource instance property response: ", response); + }, error => {}); //ignore error console.log(event); } @@ -226,7 +226,7 @@ export class PropertiesAssignmentComponent { .updateComponentInput(this.component, inputToUpdate) .subscribe(response => { console.log("updated the component input and got this response: ", response); - }) + }, error => {}); //ignore error }; @@ -322,7 +322,7 @@ export class PropertiesAssignmentComponent { this.inputs.push(newInput); this.updatePropertyValueAfterDeclare(newInput); }); - }); + }, error => {}); //ignore error }; @@ -373,7 +373,7 @@ export class PropertiesAssignmentComponent { // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath); // } // } - }); + }, error => {}); //ignore error }; @@ -391,7 +391,7 @@ export class PropertiesAssignmentComponent { this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Composition']); this.propertiesNavigationData = []; this.displayClearSearch = true; - }); + }, error => {}); //ignore error }; diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties.utils.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties.utils.ts index a04d23a16a..d8d991d218 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties.utils.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties.utils.ts @@ -44,9 +44,7 @@ export class PropertiesUtils { let propertyFeArray: Array<PropertyFEModel> = []; _.forEach(properties, (property: PropertyBEModel) => { - if (!this.dataTypeService.getDataTypeByTypeName(property.type)) { // if type not exist in data types remove property from list - console.log("ERROR: missing type " + property.type + " in dataTypes , of property ", property); - } else { + if (this.dataTypeService.getDataTypeByTypeName(property.type)) { // if type not exist in data types remove property from list let newFEProp: PropertyFEModel = new PropertyFEModel(property); //Convert property to FE diff --git a/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts index 0c499facff..27de59de82 100644 --- a/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts +++ b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts @@ -25,14 +25,14 @@ import {sdc2Config} from "../../../../main"; import {PropertyBEModel} from "app/models"; import {CommonUtils} from "app/utils"; import {Component, ComponentInstance, InputModel} from "app/models"; -import {InterceptorService} from "ng2-interceptors/index"; +import { HttpService } from '../http.service'; @Injectable() export class ComponentInstanceServiceNg2 { protected baseUrl; - constructor(private http: InterceptorService) { + constructor(private http: HttpService) { this.baseUrl = sdc2Config.api.root + sdc2Config.api.component_api_root; } diff --git a/catalog-ui/src/app/ng2/services/component-services/component.service.ts b/catalog-ui/src/app/ng2/services/component-services/component.service.ts index cd593d5e3e..c648711d5d 100644 --- a/catalog-ui/src/app/ng2/services/component-services/component.service.ts +++ b/catalog-ui/src/app/ng2/services/component-services/component.service.ts @@ -30,8 +30,8 @@ import {ComponentGenericResponse} from "../responses/component-generic-response" import {sdc2Config} from "../../../../main"; import {InstanceBePropertiesMap} from "../../../models/properties-inputs/property-fe-map"; import {API_QUERY_PARAMS} from "app/utils"; -import {ComponentType, ServerTypeUrl} from "../../../utils/constants"; -import {InterceptorService} from "ng2-interceptors/index"; +import { ComponentType, ServerTypeUrl } from "../../../utils/constants"; +import { HttpService } from '../http.service'; declare var angular:angular.IAngularStatic; @@ -40,7 +40,7 @@ export class ComponentServiceNg2 { protected baseUrl; - constructor(private http:InterceptorService) { + constructor(private http:HttpService) { this.baseUrl = sdc2Config.api.root + sdc2Config.api.component_api_root; } @@ -54,7 +54,7 @@ export class ComponentServiceNg2 { return this.http.get(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/filteredDataByParams', {search: params}) .map((res:Response) => { return new ComponentGenericResponse().deserialize(res.json()); - }).do(error => console.log('server data:', error)); + }); } private getServerTypeUrl = (componentType:string):string => { diff --git a/catalog-ui/src/app/ng2/services/component-services/service.service.ts b/catalog-ui/src/app/ng2/services/component-services/service.service.ts index 1f5de18c04..ec912bbcf5 100644 --- a/catalog-ui/src/app/ng2/services/component-services/service.service.ts +++ b/catalog-ui/src/app/ng2/services/component-services/service.service.ts @@ -26,7 +26,7 @@ import { Response } from '@angular/http'; import {Service} from "app/models"; import { downgradeInjectable } from '@angular/upgrade/static'; import {sdc2Config} from "../../../../main"; -import {InterceptorService} from "ng2-interceptors/index"; +import { HttpService } from '../http.service'; @Injectable() @@ -34,7 +34,7 @@ export class ServiceServiceNg2 { protected baseUrl = ""; - constructor(private http: InterceptorService) { + constructor(private http: HttpService) { this.baseUrl = sdc2Config.api.root + sdc2Config.api.component_api_root; } diff --git a/catalog-ui/src/app/ng2/services/data-type.service.ts b/catalog-ui/src/app/ng2/services/data-type.service.ts index 48d32b7e69..30c02a4141 100644 --- a/catalog-ui/src/app/ng2/services/data-type.service.ts +++ b/catalog-ui/src/app/ng2/services/data-type.service.ts @@ -38,12 +38,14 @@ export class DataTypeService { } public getDataTypeByTypeName(typeName: string): DataTypeModel { + if (!this.dataTypes[typeName]) console.log("MISSING Datatype: " + typeName); return this.dataTypes[typeName]; } public getDerivedDataTypeProperties(dataTypeObj: DataTypeModel, propertiesArray: Array<DerivedFEProperty>, parentName: string) { //push all child properties to array + if (!dataTypeObj) return; if (dataTypeObj.properties) { dataTypeObj.properties.forEach((derivedProperty) => { if(dataTypeObj.name !== PROPERTY_DATA.OPENECOMP_ROOT || derivedProperty.name !== PROPERTY_DATA.SUPPLEMENTAL_DATA){//The requirement is to not display the property supplemental_data diff --git a/catalog-ui/src/app/ng2/services/http.interceptor.service.ts b/catalog-ui/src/app/ng2/services/http.interceptor.service.ts deleted file mode 100644 index c90bfd2848..0000000000 --- a/catalog-ui/src/app/ng2/services/http.interceptor.service.ts +++ /dev/null @@ -1,162 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/toPromise'; -import 'rxjs/Rx'; -import {sdc2Config} from './../../../main'; -import {Interceptor, InterceptedRequest, InterceptedResponse} from 'ng2-interceptors'; -import {SharingService} from "../../services/sharing-service"; -import {ReflectiveInjector} from '@angular/core'; -import {Cookie2Service} from "./cookie.service"; -import {UUID} from "angular2-uuid"; -import {Dictionary} from "../../utils/dictionary/dictionary"; -import {SEVERITY} from "../../utils/constants"; -import {IServerMessageModalModel} from "../../view-models/modals/message-modal/message-server-modal/server-message-modal-view-model"; - - -export class HttpInterceptor implements Interceptor { - - private cookieService:Cookie2Service; - private sharingService:SharingService; - - constructor() { - let injector = ReflectiveInjector.resolveAndCreate([Cookie2Service, SharingService]); - this.cookieService = injector.get(Cookie2Service); - this.sharingService = injector.get(SharingService); - } - - public interceptBefore(request:InterceptedRequest):InterceptedRequest { - /** - * For every request to the server, that the service id, or resource id is sent in the URL, need to pass UUID in the header. - * Check if the unique id exists in uuidMap, and if so get the UUID and add it to the header. - */ - request.options.headers.append(this.cookieService.getUserIdSuffix(), this.cookieService.getUserId()); - request.options.withCredentials = true; - var uuidValue = this.getUuidValue(request.url); - if (uuidValue != '') { - request.options.headers.set('X-ECOMP-ServiceID', uuidValue); - } - request.options.headers.set('X-ECOMP-RequestID', UUID.UUID()); - return request; - } - - public interceptAfter(response:InterceptedResponse):InterceptedResponse { - - if (response.response.status !== 200 && response.response.status !== 201) { - this.responseError(response.response.json()); - //console.log("Error from BE:",response); - } - return response; - } - - private getUuidValue = (url:string):string => { - let map:Dictionary<string, string> = this.sharingService.getUuidMap(); - if (map && url.indexOf(sdc2Config.api.root) > 0) { - map.forEach((key:string) => { - if (url.indexOf(key) !== -1) { - return this.sharingService.getUuidValue(key); - } - }); - } - return ''; - }; - - public formatMessageArrays = (message:string, variables:Array<string>)=> { - return message.replace(/\[%(\d+)\]/g, function (_, m) { - let tmp = []; - let list = variables[--m].split(";"); - list.forEach(function (item) { - tmp.push("<li>" + item + "</li>"); - }); - return "<ul>" + tmp.join("") + "</ul>"; - }); - }; - - public responseError = (rejection:any)=> { - - let text:string; - let variables; - let messageId:string = ""; - let isKnownException = false; - - if (rejection && rejection.serviceException) { - text = rejection.serviceException.text; - variables = rejection.serviceException.variables; - messageId = rejection.serviceException.messageId; - isKnownException = true; - } else if (rejection && rejection.requestError && rejection.requestError.serviceException) { - text = rejection.requestError.serviceException.text; - variables = rejection.requestError.serviceException.variables; - messageId = rejection.requestError.serviceException.messageId; - isKnownException = true; - } else if (rejection && rejection.requestError && rejection.requestError.policyException) { - text = rejection.requestError.policyException.text; - variables = rejection.requestError.policyException.variables; - messageId = rejection.requestError.policyException.messageId; - isKnownException = true; - } else if (rejection) { - text = 'Wrong error format from server'; - console.error(text); - isKnownException = false; - } - - let data:IServerMessageModalModel; - if (isKnownException) { - // Remove the "Error: " text at the begining - if (text.trim().indexOf("Error:") === 0) { - text = text.replace("Error:", "").trim(); - } - - //mshitrit DE199895 bug fix - let count:number = 0; - variables.forEach(function (item) { - variables[count] = item ? item.replace('<', '<').replace('>', '>') : ''; - count++; - }); - - // Format the message in case has array to <ul><li> - text = this.formatMessageArrays(text, variables); - - // Format the message %1 %2 - text = text.format(variables); - - // Need to inject the MessageService manually to prevent circular dependencies (because MessageService use $templateCache that use $http). - data = { - title: 'Error', - message: text, - messageId: messageId, - status: rejection.status, - severity: SEVERITY.ERROR - }; - } else { - // Need to inject the MessageService manually to prevent circular dependencies (because MessageService use $templateCache that use $http). - data = { - title: 'Error', - message: rejection.status !== -1 ? rejection.statusText : "Error getting response from server", - messageId: messageId, - status: rejection.status, - severity: SEVERITY.ERROR - }; - } - - console.error('ERROR data',data); - } -} diff --git a/catalog-ui/src/app/ng2/services/http.service.ts b/catalog-ui/src/app/ng2/services/http.service.ts index 5cd5a10000..21fe09023a 100644 --- a/catalog-ui/src/app/ng2/services/http.service.ts +++ b/catalog-ui/src/app/ng2/services/http.service.ts @@ -24,14 +24,18 @@ import {Observable} from 'rxjs/Observable'; import {UUID} from 'angular2-uuid'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; +import 'rxjs/add/observable/throw'; import {Dictionary} from "../../utils/dictionary/dictionary"; import {SharingService, CookieService} from "app/services"; import {sdc2Config} from './../../../main'; +import { ModalService } from "app/ng2/services/modal.service"; +import { ServerErrorResponse } from "app/models"; +import { ErrorMessageComponent } from 'app/ng2/components/modal/error-message/error-message.component'; @Injectable() export class HttpService extends Http { - constructor(backend:XHRBackend, options:RequestOptions, private sharingService:SharingService, private cookieService: CookieService) { + constructor(backend: XHRBackend, options: RequestOptions, private sharingService: SharingService, private cookieService: CookieService, private modalService: ModalService) { super(backend, options); this._defaultOptions.withCredentials = true; this._defaultOptions.headers.append(cookieService.getUserIdSuffix(), cookieService.getUserId()); @@ -64,7 +68,7 @@ export class HttpService extends Http { } request.headers.set('X-ECOMP-RequestID', UUID.UUID()); } - return super.request(request, options).catch(this.catchAuthError(this)); + return super.request(request, options).catch((err) => this.catchError(err)); } private getUuidValue = (url: string) :string => { @@ -79,15 +83,14 @@ export class HttpService extends Http { return ''; } - private catchAuthError(self:HttpService) { - // we have to pass HttpService's own instance here as `self` - return (res:Response) => { - console.log(res); - if (res.status === 401 || res.status === 403) { - // if not authenticated - console.log(res); - } - return Observable.throw(res); - }; - } + private catchError = (response: Response): Observable<any> => { + + let modalInstance = this.modalService.createErrorModal("OK"); + let errorResponse: ServerErrorResponse = new ServerErrorResponse(response); + this.modalService.addDynamicContentToModal(modalInstance, ErrorMessageComponent, errorResponse); + modalInstance.instance.open(); + + return Observable.throw(response); + }; + } diff --git a/catalog-ui/src/app/ng2/services/modal.service.ts b/catalog-ui/src/app/ng2/services/modal.service.ts index 32192f40c2..65ff870769 100644 --- a/catalog-ui/src/app/ng2/services/modal.service.ts +++ b/catalog-ui/src/app/ng2/services/modal.service.ts @@ -11,10 +11,10 @@ export class ModalService { constructor(private componentFactoryResolver: ComponentFactoryResolver, private applicationRef: ApplicationRef) { } - /* Shortcut method to open a simple modal with title, message, and close button that simply closes the modal. */ + /* Shortcut method to open an alert modal with title, message, and close button that simply closes the modal. */ public openAlertModal(title: string, message: string, closeButtonText?:string) { let closeButton: ButtonModel = new ButtonModel(closeButtonText || 'Close', 'grey', this.closeCurrentModal); - let modalModel: ModalModel = new ModalModel('sm', title, message, [closeButton]); + let modalModel: ModalModel = new ModalModel('sm', title, message, [closeButton], 'alert'); this.createCustomModal(modalModel).instance.open(); } @@ -22,19 +22,28 @@ export class ModalService { /** * Shortcut method to open a basic modal with title, message, and an action button with callback, as well as close button. * NOTE: To close the modal from within the callback, use modalService.closeCurrentModal() //if you run into zone issues with callbacks see:https://stackoverflow.com/questions/36566698/how-to-dynamically-create-bootstrap-modals-as-angular2-components + * NOTE: To add dynamic content to the modal, use modalService.addDynamicContentToModal(). First param is the return value of this function -- componentRef<ModalComponent>. * @param title Heading for modal * @param message Message for modal * @param actionButtonText Blue call to action button * @param actionButtonCallback function to invoke when button is clicked * @param cancelButtonText text for close/cancel button */ - public openActionModal = (title:string, message:string, actionButtonText:string, actionButtonCallback:Function, cancelButtonText:string) => { + public createActionModal = (title: string, message: string, actionButtonText: string, actionButtonCallback: Function, cancelButtonText: string): ComponentRef<ModalComponent> => { let actionButton: ButtonModel = new ButtonModel(actionButtonText, 'blue', actionButtonCallback); let cancelButton: ButtonModel = new ButtonModel(cancelButtonText, 'grey', this.closeCurrentModal); let modalModel: ModalModel = new ModalModel('sm', title, message, [actionButton, cancelButton]); - this.createCustomModal(modalModel).instance.open(); + let modalInstance: ComponentRef<ModalComponent> = this.createCustomModal(modalModel); + return modalInstance; + } + + + public createErrorModal = (closeButtonText?: string, errorMessage?: string):ComponentRef<ModalComponent> => { + let closeButton: ButtonModel = new ButtonModel(closeButtonText || 'Close', 'grey', this.closeCurrentModal); + let modalModel: ModalModel = new ModalModel('sm', 'Error', errorMessage, [closeButton], 'error'); + let modalInstance: ComponentRef<ModalComponent> = this.createCustomModal(modalModel); + return modalInstance; } - /* Use this method to create a modal with title, message, and completely custom buttons. Use response.instance.open() to open */ public createCustomModal = (customModalData: ModalModel): ComponentRef<ModalComponent> => { @@ -53,6 +62,14 @@ export class ModalService { } + public addDynamicContentToModal = (modalInstance: ComponentRef<ModalComponent>, dynamicComponentType: Type<any>, dynamicComponentInput: any) => { + + let dynamicContent = this.createDynamicComponent(dynamicComponentType, modalInstance.instance.dynamicContentContainer); + dynamicContent.instance.input = dynamicComponentInput; + modalInstance.instance.dynamicContent = dynamicContent; + return modalInstance; + } + //Creates a component dynamically (aka during runtime). If a view container is not specified, it will append the new component to the app root. //To subscribe to an event from invoking component: componentRef.instance.clicked.subscribe((m) => console.log(m.name)); private createDynamicComponent<T>(componentType: Type<T>, viewContainerRef?:ViewContainerRef): ComponentRef<any> { diff --git a/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.html b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.html new file mode 100644 index 0000000000..36629594b0 --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.html @@ -0,0 +1,5 @@ +<div class="search-bar-container {{class}}"> + <input class="search-bar-input" type="text" [placeholder]="placeholder" [(ngModel)]="searchQuery" (ngModelChange)="searchQueryChange($event)"/> + <span class="clear-search-x" *ngIf="searchQuery" (click)="clearSearchQuery()">x</span> + <button class="search-bar-button" (click)="searchButtonClick()"></button> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.less b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.less new file mode 100644 index 0000000000..cfeb8d3b01 --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.less @@ -0,0 +1,58 @@ +.search-bar-container { + display:flex; + border-radius: 4px; + box-shadow: 0px 2px 3.88px 0.12px rgba(0, 0, 0, 0.29); + + .search-bar-input { + border: 1px solid #cdcdcd; + border-radius: 4px; + border-right:none; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + outline:none; + padding:2px 50px 2px 10px; + color: #5a5a5a; + font-size: 1em; + font-style: italic; + } + + .clear-search-x { + position:absolute; + right:40px; + top:5px; + padding: 0 5px; + + &:hover { + border-radius:2px; + background-color: #ebebeb; + cursor:pointer; + } + } + + .search-bar-button { + //background: url('../../../../assets/styles/svg/source/search-magnify.svg') no-repeat 50%; + background: url('../../../../assets/styles/images/sprites/sprite-global.png') no-repeat -206px -1275px; + background-color: rgba(234, 234, 234, 0.88); + width: 30px; + height: 30px; + padding: 0; + cursor:pointer; + border:solid 1px #cdcdcd; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + + &:hover { + background-position:-126px -1275px; + } + + &:active { + background-color: rgba(31, 171, 223, 0.88); + background-position:-45px -1275px; + border-left:none; + } + &:focus { + outline:none; + } + + } +} diff --git a/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.ts b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.ts new file mode 100644 index 0000000000..08bdf2030f --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.ts @@ -0,0 +1,32 @@ +import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'search-bar', + templateUrl: './search-bar.component.html', + styleUrls: ['./search-bar.component.less'], + encapsulation: ViewEncapsulation.None +}) +export class SearchBarComponent { + + @Input() placeholder: string; + @Input() class: string; + @Input() searchQuery: string; + @Output() searchChanged: EventEmitter<any> = new EventEmitter<any>(); + @Output() searchButtonClicked: EventEmitter<string> = new EventEmitter<string>(); + + searchButtonClick = (): void => { + if (this.searchQuery) { //do not allow empty search + this.searchButtonClicked.emit(this.searchQuery); + } + } + + searchQueryChange = ($event): void => { + this.searchChanged.emit($event); + } + + private clearSearchQuery = (): void => { + this.searchQuery = ""; + this.searchButtonClicked.emit(this.searchQuery); + } +} + diff --git a/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.html b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.html new file mode 100644 index 0000000000..c9769ba5ae --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.html @@ -0,0 +1,6 @@ +<div class="search-with-autocomplete-container {{searchBarClass}}" [class.autocomplete-visible]="autoCompleteValues && autoCompleteValues.length" [class.active]="searchQuery && searchQuery.length"> + <search-bar [placeholder]="searchPlaceholder" [searchQuery]="searchQuery" (searchButtonClicked)="updateSearch($event)" (searchChanged)="searchChange($event)"></search-bar> + <div class="autocomplete-results"> + <div *ngFor="let item of autoCompleteValues" class="autocomplete-result-item" (click)="updateSearch(item)">{{item}}</div> + </div> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.less b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.less new file mode 100644 index 0000000000..92b054cd85 --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.less @@ -0,0 +1,35 @@ + +.search-with-autocomplete-container{ + &.autocomplete-visible { + + .search-bar-input { + border-bottom-left-radius: 0; + } + .search-bar-button { + border-bottom-right-radius: 0; + } + .autocomplete-results { + border: solid 1px #d2d2d2; + border-top:none; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + background-color: #fff; + padding: 10px 20px; + width:100%; + position:absolute; + max-height: 200px; + overflow-y: scroll; + } + + .autocomplete-result-item { + color:#5a5a5a; + padding: 5px 0; + cursor:pointer; + + &:hover { + color: #999; + } + } + } +} + diff --git a/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.ts b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.ts new file mode 100644 index 0000000000..ced056d1fc --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.ts @@ -0,0 +1,30 @@ +import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core'; +import { SearchBarComponent } from '../search-bar/search-bar.component'; + +@Component({ + selector: 'search-with-autocomplete', + templateUrl: './search-with-autocomplete.component.html', + styleUrls: ['./search-with-autocomplete.component.less'], + encapsulation: ViewEncapsulation.None +}) +export class SearchWithAutoCompleteComponent { + + @Input() searchPlaceholder: string; + @Input() searchBarClass: string; + @Input() searchQuery: string; + @Input() autoCompleteValues: Array<string>; + @Output() searchChanged: EventEmitter<any> = new EventEmitter<any>(); + @Output() searchButtonClicked: EventEmitter<string> = new EventEmitter<string>(); + + searchChange = (searchTerm: string) => { + this.searchQuery = searchTerm; + this.searchChanged.emit(searchTerm); + } + + updateSearch = (searchTerm: string) => { + this.searchQuery = searchTerm; + this.searchButtonClicked.emit(searchTerm); + this.autoCompleteValues = []; + } +} + diff --git a/catalog-ui/src/app/services/event-listener-service.ts b/catalog-ui/src/app/services/event-listener-service.ts index 1c796230c6..96f9e17641 100644 --- a/catalog-ui/src/app/services/event-listener-service.ts +++ b/catalog-ui/src/app/services/event-listener-service.ts @@ -48,7 +48,7 @@ export class EventListenerService implements IEventListenerService { // Only insert the callback if the callback is different from existing callbacks. for (let i = 0; i < callbacks.length; i++) { - if (callbacks[i].toString() === callback.toString()) { + if (callbacks[i].callback.toString() === callback.toString()) { return; // Do not add this callback. } } diff --git a/catalog-ui/src/app/services/onboarding-service.ts b/catalog-ui/src/app/services/onboarding-service.ts index db6c72699a..3dd7269326 100644 --- a/catalog-ui/src/app/services/onboarding-service.ts +++ b/catalog-ui/src/app/services/onboarding-service.ts @@ -44,11 +44,21 @@ export class OnboardingService implements IOnboardingService { this.api = sdcConfig.api; } - getOnboardingComponents = ():ng.IPromise<Array<IComponent>> => { - let defer = this.$q.defer<Array<IComponent>>(); + getOnboardingVSPs = ():ng.IPromise<Array<ICsarComponent>> =>{ + let defer = this.$q.defer<Array<ICsarComponent>>(); this.$http.get(this.api.GET_onboarding) .then((response:any) => { - let onboardingComponents:Array<ICsarComponent> = response.data.results; + defer.resolve(response.data.results); + },(response) => { + defer.reject(response); + }); + + return defer.promise; + }; + + getOnboardingComponents = ():ng.IPromise<Array<IComponent>> => { + let defer = this.$q.defer<Array<IComponent>>(); + this.getOnboardingVSPs().then((onboardingComponents:Array<ICsarComponent>) => { let componentsList:Array<IComponent> = new Array(); onboardingComponents.forEach((obc:ICsarComponent) => { diff --git a/catalog-ui/src/app/utils/constants.ts b/catalog-ui/src/app/utils/constants.ts index d239019455..6ec6a7762b 100644 --- a/catalog-ui/src/app/utils/constants.ts +++ b/catalog-ui/src/app/utils/constants.ts @@ -167,6 +167,12 @@ export class ModalType { static ALERT = 'alert'; } +export class ServerErrors { + static ERROR_TITLE = 'Error'; + static DEFAULT_ERROR = 'Error getting response from server'; + static MESSAGE_ERROR = 'Wrong error format from server'; +} + export class GraphColors { public static NOT_CERTIFIED_LINK = 'rgb(218,31,61)'; public static VL_LINK = 'rgb(216,216,216)'; @@ -188,6 +194,10 @@ export class GraphTransactionLogText { } export class GraphUIObjects { + public static HANDLE_SIZE = 18; + public static NODE_OVERLAP_MIN_SIZE = 30; + public static DEFAULT_RESOURCE_WIDTH = 65; + public static SMALL_RESOURCE_WIDTH = 21; public static LINK_MENU_HEIGHT = 420; public static TOP_HEADER_HEIGHT = 200; public static TOOLTIP_OFFSET_X = 50; diff --git a/catalog-ui/src/app/view-models/forms/property-forms/module-property-modal/module-property-model.ts b/catalog-ui/src/app/view-models/forms/property-forms/module-property-modal/module-property-model.ts index 4c3922264c..3a61371e85 100644 --- a/catalog-ui/src/app/view-models/forms/property-forms/module-property-modal/module-property-model.ts +++ b/catalog-ui/src/app/view-models/forms/property-forms/module-property-modal/module-property-model.ts @@ -86,7 +86,8 @@ export class ModulePropertyView extends PropertyFormBaseView { let property = _.find(this.selectedModule.properties, (property) => { return property.uniqueId === this.$scope.property.uniqueId; }); - if (property.value !== this.$scope.property.value) { + + if (!property.readonly && property.value !== this.$scope.property.value) { if (this.component.isResource()) { (<Resource>this.component).updateResourceGroupProperties(this.selectedModule, [this.$scope.property]).then(onSuccess, onFailed); // for now we only update one property at a time } @@ -101,6 +102,8 @@ export class ModulePropertyView extends PropertyFormBaseView { } } else { deferred.resolve(true); + this.$uibModalInstance.close(); + } return deferred.promise; } diff --git a/catalog-ui/src/app/view-models/forms/resource-instance-name-form/resource-instance-name-model.ts b/catalog-ui/src/app/view-models/forms/resource-instance-name-form/resource-instance-name-model.ts index 3f0838cabc..fa027296d6 100644 --- a/catalog-ui/src/app/view-models/forms/resource-instance-name-form/resource-instance-name-model.ts +++ b/catalog-ui/src/app/view-models/forms/resource-instance-name-form/resource-instance-name-model.ts @@ -109,7 +109,8 @@ export class ResourceInstanceNameViewModel { ]; this.$scope.$watch("[forms.editNameForm.$invalid,componentInstanceModel.name,isAlreadyPressed]", (newVal, oldVal) => { - this.$scope.footerButtons[0].disabled = this.$scope.forms.editNameForm.$invalid || this.$scope.isAlreadyPressed || this.$scope.componentInstanceModel.name === this.$scope.oldName; + //if the name is invalid or if user pressed ok and didn't try to change name again or the new name = source name + this.$scope.footerButtons[0].disabled = this.$scope.forms.editNameForm.$invalid || (this.$scope.isAlreadyPressed && newVal[1] === oldVal[1]) || this.$scope.componentInstanceModel.name === this.$scope.oldName; }); } } diff --git a/catalog-ui/src/app/view-models/onboard-vendor/onboard-vendor-view-model.ts b/catalog-ui/src/app/view-models/onboard-vendor/onboard-vendor-view-model.ts index 6d4e6d3c68..f77a29b003 100644 --- a/catalog-ui/src/app/view-models/onboard-vendor/onboard-vendor-view-model.ts +++ b/catalog-ui/src/app/view-models/onboard-vendor/onboard-vendor-view-model.ts @@ -22,6 +22,7 @@ import {IUserProperties} from "app/models"; import {MenuItemGroup, MenuItem} from "app/utils"; import {CacheService} from "app/services"; +declare var PunchOutRegistry; export class BreadcrumbsMenuItem { key:string; @@ -48,6 +49,7 @@ export interface IOnboardVendorViewModelScope extends ng.IScope { topNavRootMenu:MenuItemGroup; user:IUserProperties; version:string; + isLoading:boolean; } export class OnboardVendorViewModel { @@ -63,6 +65,15 @@ export class OnboardVendorViewModel { private $q:ng.IQService, private cacheService:CacheService) { + this.$scope.isLoading = true; + + PunchOutRegistry.loadOnBoarding(()=> { + this.$scope.isLoading = false; + }); + this.initScope(); + + } + private initScope = ():void => { this.$scope.vendorData = { breadcrumbs: { selectedKeys: [] @@ -82,6 +93,7 @@ export class OnboardVendorViewModel { this.$scope.topNavMenuModel = []; this.$scope.user = this.cacheService.get('user'); + } updateBreadcrumbsPath = (selectedKeys:Array<string>):ng.IPromise<boolean> => { @@ -133,6 +145,7 @@ export class OnboardVendorViewModel { let topNavRootMenu = topNavMenuModel[0]; let onboardItem = topNavRootMenu.menuItems[topNavRootMenu.selectedIndex]; let originalCallback = onboardItem.callback; + //noinspection TypeScriptValidateTypes onboardItem.callback = (...args) => { let ret = this.updateBreadcrumbsPath([]); return originalCallback && originalCallback.apply(undefined, args) || ret; diff --git a/catalog-ui/src/app/view-models/onboard-vendor/onboard-vendor-view.html b/catalog-ui/src/app/view-models/onboard-vendor/onboard-vendor-view.html index 734fb93daf..eec7c4758d 100644 --- a/catalog-ui/src/app/view-models/onboard-vendor/onboard-vendor-view.html +++ b/catalog-ui/src/app/view-models/onboard-vendor/onboard-vendor-view.html @@ -1,10 +1,6 @@ <div class="sdc-catalog-container"> - <loader data-display="gui.isLoading"></loader> -<!-- - <ecomp-header menu-data="menuItems" version="{{version}}"></ecomp-header> ---> - + <loader data-display="isLoading"></loader> <div class="w-sdc-main-container"> <punch-out name="'onboarding/vendor'" data="vendorData" user="user" on-event="onVendorEvent"></punch-out> </div> diff --git a/catalog-ui/src/app/view-models/shared/notification-custom-template.html b/catalog-ui/src/app/view-models/shared/notification-custom-template.html new file mode 100644 index 0000000000..d8fdf135b9 --- /dev/null +++ b/catalog-ui/src/app/view-models/shared/notification-custom-template.html @@ -0,0 +1,14 @@ +<div class="ui-notification"> + <div class="notification-container"> + <div class="icon-container"> + <div class="icon-circle"> + <div class="icon sprite-new"> + </div> + </div> + </div> + <div class="msg-content"> + <h3 ng-show="title" ng-bind-html="title"></h3> + <div class="message" ng-bind-html="message"></div> + </div> + </div> +</div> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/activity-log/activity-log.ts b/catalog-ui/src/app/view-models/workspace/tabs/activity-log/activity-log.ts index f4ce1d8bc4..5d22d65f52 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/activity-log/activity-log.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/activity-log/activity-log.ts @@ -54,7 +54,6 @@ export class ActivityLogViewModel { this.initScope(); this.$scope.setValidState(true); this.initSortedTableScope(); - this.$scope.updateSelectedMenuItem(); // Set default sorting this.$scope.sortBy = 'logDate'; diff --git a/catalog-ui/src/app/view-models/workspace/tabs/attributes/attributes-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/attributes/attributes-view-model.ts index ce7296cf04..312a663e8f 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/attributes/attributes-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/attributes/attributes-view-model.ts @@ -53,7 +53,6 @@ export class AttributesViewModel { private ComponentServiceNg2: ComponentServiceNg2) { this.initComponentAttributes(); - this.$scope.updateSelectedMenuItem(); } private initComponentAttributes = () => { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts index fbd32cc967..4b9dd6fc00 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts @@ -30,7 +30,8 @@ import {ResourceType} from "../../../../utils/constants"; export interface ICompositionViewModelScope extends IWorkspaceViewModelScope { currentComponent:Component; - selectedComponent:Component; + selectedComponent: Component; + componentInstanceNames: Array<string>; isLoading:boolean; graphApi:any; sharingService:SharingService; @@ -46,6 +47,7 @@ export interface ICompositionViewModelScope extends IWorkspaceViewModelScope { onBackgroundClick():void; setSelectedInstance(componentInstance:ComponentInstance):void; printScreen():void; + isPNF():boolean; cacheComponentsInstancesFullData:Component; } @@ -89,7 +91,6 @@ export class CompositionViewModel { this.$scope.setValidState(true); this.initScope(); this.initGraphData(); - this.$scope.updateSelectedMenuItem(); this.registerGraphEvents(this.$scope); } @@ -130,7 +131,6 @@ export class CompositionViewModel { private openUpdateComponentInstanceNameModal = ():void => { this.ModalsHandler.openUpdateComponentInstanceNameModal(this.$scope.currentComponent).then(()=> { this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_COMPONENT_INSTANCE_NAME_CHANGED, this.$scope.currentComponent.selectedInstance); - }); }; @@ -225,7 +225,7 @@ export class CompositionViewModel { this.$scope.openUpdateModal = ():void => { this.openUpdateComponentInstanceNameModal(); }; - + this.$scope.deleteSelectedComponentInstance = ():void => { let state = "deleteInstance"; let onOk = ():void => { @@ -242,7 +242,10 @@ export class CompositionViewModel { this.$scope.setComponent(this.$scope.currentComponent); this.$scope.updateSelectedComponent(); }; - + + this.$scope.isPNF = (): boolean => { + return this.$scope.selectedComponent.isResource() && (<Resource>this.$scope.selectedComponent).resourceType === ResourceType.PNF; + }; this.eventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.$scope.reload); diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html index cef942e853..e05574e8c8 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html @@ -6,7 +6,7 @@ is-loading="isLoading"></palette> <composition-graph component="currentComponent" data-tests-id="canvas" - is-view-only="isViewOnly"></composition-graph> + is-view-only="isViewOnly" with-sidebar="displayDesignerRightSidebar"></composition-graph> </div> <div class="w-sdc-designer-sidebar-toggle" data-ng-class="{'active': displayDesignerRightSidebar}" @@ -21,7 +21,7 @@ <div class="w-sdc-designer-sidebar-logo-ph"> <div class="large {{selectedComponent.iconSprite}} {{selectedComponent.icon}}"> <div ng-if="isComponentInstanceSelected()" - data-ng-class="{'non-certified':'CERTIFIED' !== selectedComponent.lifecycleState, 'smaller-icon': selectedComponent.icon==='vl' || selectedComponent.icon==='cp'}" + data-ng-class="{'non-certified':'CERTIFIED' !== selectedComponent.lifecycleState}" tooltips tooltip-side="top" tooltip-content="Not certified"></div> </div> </div> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less index 7a775bdb11..262dfd9be8 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less @@ -781,6 +781,71 @@ line-height: 18px; } + //Canvas search menu + .w-sdc-search-menu { + position:absolute; + right: 18px; + top:53px; + transition: right 0.2s; + display: flex; + flex-direction: column; + align-items: flex-end; + margin-right:10px; + + &.with-sidebar { + right:320px; + } + + .search-with-autocomplete-container.composition-search { + margin-top: 12px; + + .search-bar-input { + width: 250px; + padding:2px 50px 2px 10px; + transition:all 0.4s; + } + .clear-search-x { + top: 17px + } + + &:not(:hover):not(.autocomplete-visible):not(.active){ + border-radius: 0; + box-shadow:none; + + .search-bar-input:not(:focus){ + width: 0px; + padding:0; + border:none; + } + .clear-search-x { + display:none; + } + .search-bar-input:not(:focus) ~ .search-bar-button { + border-radius: 2px; + border:solid 1px #fff; + } + } + } + + .zoom-icons { + border:solid 1px #fff; + border-radius: 2px; + box-shadow: 0px 2px 3.88px 0.12px rgba(0, 0, 0, 0.29); + background-color: rgba(234, 234, 234, 0.88); + background-repeat: no-repeat; + margin-top: 10px; + + &:hover { + cursor:pointer; + } + + &:active { + border:none; + background-color: rgba(31, 171, 223, 0.88); + } + } + } + // --------------------------------------------------------------------------------------------------- // Canvas inline menu // --------------------------------------------------------------------------------------------------- diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts index 83e4653954..f0c8b1d86b 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts @@ -33,13 +33,14 @@ import {ICompositionViewModelScope} from "../../composition-view-model"; import {ArtifactsUtils, ModalsHandler, ArtifactGroupType} from "app/utils"; import {GRAPH_EVENTS} from "app/utils/constants"; import {EventListenerService} from "app/services/event-listener-service"; +import {Dictionary} from "../../../../../../utils/dictionary/dictionary"; export interface IArtifactsViewModelScope extends ICompositionViewModelScope { artifacts:Array<ArtifactModel>; artifactType:string; downloadFile:IFileDownload; isLoading:boolean; - + displayDeleteButtonMap:Dictionary<string, boolean>; getTitle():string; addOrUpdate(artifact:ArtifactModel):void; delete(artifact:ArtifactModel):void; @@ -125,6 +126,10 @@ export class ResourceArtifactsViewModel { } } this.$scope.artifacts = artifacts; + this.$scope.displayDeleteButtonMap = new Dictionary<string, boolean>(); + _.forEach(this.$scope.artifacts, (artifact:ArtifactModel)=>{ + this.$scope.displayDeleteButtonMap[artifact.artifactLabel] = this.displayDeleteButton(artifact); + }); this.$scope.isLoading = false; }; @@ -229,11 +234,21 @@ export class ResourceArtifactsViewModel { }); }; + private displayDeleteButton = (artifact:ArtifactModel):boolean => { + if(!this.$scope.isViewMode() && artifact.esId){ + if(this.$scope.isComponentInstanceSelected()){//is artifact of instance + return !this.$scope.selectedComponent.deploymentArtifacts || !this.$scope.selectedComponent.deploymentArtifacts[artifact.artifactLabel];//if the artifact is not from instance parent + }else{//is artifact of main component + return (!artifact.isHEAT() && !artifact.isThirdParty() && !this.$scope.isLicenseArtifact(artifact)); + } + } + return false; +}; + private initScope = ():void => { this.$scope.isLoading = false; this.$scope.artifactType = this.artifactsUtils.getArtifactTypeByState(this.$state.current.name); - this.loadArtifacts(); this.$scope.getTitle = ():string => { return this.artifactsUtils.getTitle(this.$scope.artifactType, this.$scope.currentComponent); }; @@ -319,5 +334,7 @@ export class ResourceArtifactsViewModel { this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_NODE_SELECTED, this.loadArtifacts); this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED, this.loadArtifacts); }); + + this.loadArtifacts(); } } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html index 8221c67eca..dfbd639eb4 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html @@ -36,7 +36,7 @@ <span class="i-sdc-designer-sidebar-section-content-item-artifact-details-desc-label" data-ng-show="artifact.description">Description:</span>{{artifact.description}} </div> </div> - <button ng-if="!isViewMode() && artifact.esId && !isComponentInstanceSelected() && !artifact.isHEAT() && !artifact.isThirdParty() && !isLicenseArtifact(artifact)" class="i-sdc-designer-sidebar-section-content-item-button delete sprite e-sdc-small-icon-delete" + <button ng-if="displayDeleteButtonMap[artifact.artifactLabel]" class="i-sdc-designer-sidebar-section-content-item-button delete sprite e-sdc-small-icon-delete" data-tests-id="delete_{{artifact.artifactDisplayName}}" data-ng-click="delete(artifact)" type="button"></button> <button ng-if="!isViewMode() && artifact.isHEAT() && isComponentInstanceSelected() && artifact.heatParameters.length" class="i-sdc-designer-sidebar-section-content-item-button attach sprite e-sdc-small-icon-pad" diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html index 8607d65964..0418515789 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html @@ -23,9 +23,9 @@ <span class="i-sdc-designer-sidebar-section-content-item-label">Version:</span> <span class="i-sdc-designer-sidebar-section-content-item-value" - data-ng-if="!isComponentInstanceSelected() || selectedComponent.isVl()" data-tests-id="rightTab_version" data-ng-bind="selectedComponent.version"></span> + data-ng-if="!isComponentInstanceSelected()" data-tests-id="rightTab_version" data-ng-bind="selectedComponent.version"></span> - <ng-form name="editForm" data-ng-if="isComponentInstanceSelected() && !selectedComponent.isVl()"> + <ng-form name="editForm" data-ng-if="isComponentInstanceSelected()"> <select data-ng-model="editResourceVersion.changeVersion" name="changeVersion" data-tests-id="changeVersion" data-ng-disabled="$parent.isViewOnly" class="i-sdc-designer-sidebar-section-content-item-value i-sdc-form-select" data-ng-class="{'minor': (editResourceVersion.changeVersion)%1}" diff --git a/catalog-ui/src/app/view-models/workspace/tabs/deployment-artifacts/deployment-artifacts-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/deployment-artifacts/deployment-artifacts-view-model.ts index 6990ad7241..86bc478048 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/deployment-artifacts/deployment-artifacts-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/deployment-artifacts/deployment-artifacts-view-model.ts @@ -74,7 +74,6 @@ export class DeploymentArtifactsViewModel { private ModalsHandler:ModalsHandler, private ComponentServiceNg2: ComponentServiceNg2) { this.initScope(); - this.$scope.updateSelectedMenuItem(); } private initDescriptions = ():void => { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view-model.ts index 76be6c1141..feda7fe17f 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view-model.ts @@ -86,7 +86,6 @@ export class DeploymentViewModel { this.$scope.setValidState(true); this.initScope(); this.initGraphData(); - this.$scope.updateSelectedMenuItem(); } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/distribution/distribution-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/distribution/distribution-view-model.ts index 1852b6a83e..663361cd85 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/distribution/distribution-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/distribution/distribution-view-model.ts @@ -48,7 +48,6 @@ export class DistributionViewModel { private ModalsHandler:ModalsHandler) { this.initScope(); this.$scope.setValidState(true); - this.$scope.updateSelectedMenuItem(); } private initScope = ():void => { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts index 1dc326a7c0..48fc9dbb42 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts @@ -21,9 +21,10 @@ 'use strict'; import {ModalsHandler, ValidationUtils, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FLAG, ComponentType, DEFAULT_ICON, ResourceType} from "app/utils"; -import {CacheService, EventListenerService, ProgressService} from "app/services"; -import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service} from "app/models"; +import {CacheService, EventListenerService, ProgressService, OnboardingService} from "app/services"; +import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service, ICsarComponent} from "app/models"; import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; +import {Dictionary} from "lodash"; export class Validation { componentNameValidationPattern:RegExp; @@ -91,7 +92,8 @@ export class GeneralViewModel { 'Sdc.Services.ProgressService', '$interval', '$filter', - '$timeout' + '$timeout', + 'Sdc.Services.OnboardingService' ]; constructor(private $scope:IGeneralScope, @@ -113,12 +115,12 @@ export class GeneralViewModel { private progressService:ProgressService, protected $interval:any, private $filter:ng.IFilterService, - private $timeout:ng.ITimeoutService) { + private $timeout:ng.ITimeoutService, + private onBoardingService:OnboardingService) { this.initScopeValidation(); this.initScopeMethods(); this.initScope(); - this.$scope.updateSelectedMenuItem(); } @@ -136,6 +138,40 @@ export class GeneralViewModel { this.$scope.validation.projectCodeValidationPattern = this.ProjectCodeValidationPattern; }; + private initImportedToscaBrowseFile = ():void =>{ + // Init the decision if to show onboarding + this.$scope.isShowOnboardingSelectionBrowse = false; + if (this.$scope.component.isResource() && + this.$scope.isEditMode() && + (<Resource>this.$scope.component).resourceType == ResourceType.VF && + (<Resource>this.$scope.component).csarUUID) { + this.$scope.isShowOnboardingSelectionBrowse = true; + let onboardCsarFilesMap:Dictionary<string> = this.cacheService.get('onboardCsarFilesMap'); + // The onboardCsarFilesMap in cache contains map of [packageId]:[vsp display name for brows] + // if the map is empty - Do request to BE + if(onboardCsarFilesMap) { + this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[(<Resource>this.$scope.component).csarUUID]; + } + if(!onboardCsarFilesMap || !this.$scope.importedToscaBrowseFileText){ + + let onSuccess = (vsps:Array<ICsarComponent>): void =>{ + onboardCsarFilesMap = {}; + _.each(vsps, (vsp:ICsarComponent)=>{ + onboardCsarFilesMap[vsp.packageId] = vsp.vspName + " (" + vsp.version + ")"; + }); + this.cacheService.set('onboardCsarFilesMap', onboardCsarFilesMap); + this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[(<Resource>this.$scope.component).csarUUID]; + }; + + let onError = (): void =>{ + console.log("Error getting onboarding list"); + }; + + this.onBoardingService.getOnboardingVSPs().then(onSuccess, onError); + } + } + }; + private initScope = ():void => { // Work around to change the csar version @@ -143,7 +179,6 @@ export class GeneralViewModel { (<Resource>this.$scope.component).csarVersion = this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG); } - this.$scope.importedToscaBrowseFileText = this.$scope.component.name + " (" + (<Resource>this.$scope.component).csarVersion + ")"; this.$scope.importCsarProgressKey = "importCsarProgressKey"; this.$scope.browseFileLabel = this.$scope.component.isResource() && (<Resource>this.$scope.component).resourceType === ResourceType.VF ? "Upload file" : "Upload VFC"; this.$scope.progressService = this.progressService; @@ -168,16 +203,8 @@ export class GeneralViewModel { this.$scope.isShowFileBrowse = true; } } - ; - // Init the decision if to show onboarding - this.$scope.isShowOnboardingSelectionBrowse = false; - if (this.$scope.component.isResource() && - this.$scope.isEditMode() && - (<Resource>this.$scope.component).resourceType == ResourceType.VF && - (<Resource>this.$scope.component).csarUUID) { - this.$scope.isShowOnboardingSelectionBrowse = true; - } + this.initImportedToscaBrowseFile(); //init file extensions based on the file that was imported. if (this.$scope.component.isResource() && (<Resource>this.$scope.component).importedFile) { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/information-artifacts/information-artifacts-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/information-artifacts/information-artifacts-view-model.ts index ceaba3c187..b2fd4d68c0 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/information-artifacts/information-artifacts-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/information-artifacts/information-artifacts-view-model.ts @@ -65,7 +65,6 @@ export class InformationArtifactsViewModel { private ModalsHandler:ModalsHandler, private ComponentServiceNg2: ComponentServiceNg2) { this.initInformationalArtifacts(); - this.$scope.updateSelectedMenuItem(); } private initInformationalArtifacts = ():void => { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts index 78865ac873..2e871a5f8d 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts @@ -45,7 +45,6 @@ export class ResourceInputsViewModel { constructor(private $scope:IInputsViewModelScope, private $q:ng.IQService, private ModalsHandler:ModalsHandler) { this.initScope(); - this.$scope.updateSelectedMenuItem(); } private initScope = ():void => { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts index 013a0023f9..00f3347b74 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts @@ -62,7 +62,6 @@ export class ServiceInputsViewModel { private ModalsHandler:ModalsHandler, private DataTypesService:DataTypesService) { this.initScope(); - this.$scope.updateSelectedMenuItem(); this.$scope.isViewOnly = this.$scope.isViewMode(); } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/management-workflow/management-workflow-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/management-workflow/management-workflow-view-model.ts index f8b29c4a9c..e44ed12c2a 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/management-workflow/management-workflow-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/management-workflow/management-workflow-view-model.ts @@ -18,130 +18,137 @@ * ============LICENSE_END========================================================= */ - 'use strict'; - import {ArtifactType} from "app/utils"; - import {ArtifactGroupModel} from "app/models"; - import {participant} from "app/view-models/workspace/tabs/network-call-flow/network-call-flow-view-model"; - import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; - import {ComponentGenericResponse} from "../../../../ng2/services/responses/component-generic-response"; - import {ComponentServiceNg2} from "../../../../ng2/services/component-services/component.service"; +'use strict'; +import {ArtifactType} from "app/utils"; +import {ArtifactGroupModel} from "app/models"; +import {participant} from "app/view-models/workspace/tabs/network-call-flow/network-call-flow-view-model"; +import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; +import {ComponentGenericResponse} from "../../../../ng2/services/responses/component-generic-response"; +import {ComponentServiceNg2} from "../../../../ng2/services/component-services/component.service"; +declare var PunchOutRegistry; - export interface IManagementWorkflowViewModelScope extends IWorkspaceViewModelScope { - vendorModel:VendorModel; - } +export interface IManagementWorkflowViewModelScope extends IWorkspaceViewModelScope { + vendorModel:VendorModel; + isLoading: boolean; +} - export class VendorModel { - artifacts: ArtifactGroupModel; - serviceID: string; - readonly: boolean; - sessionID: string; - requestID: string; - diagramType: string; - participants:Array<participant>; +export class VendorModel { + artifacts:ArtifactGroupModel; + serviceID:string; + readonly:boolean; + sessionID:string; + requestID:string; + diagramType:string; + participants:Array<participant>; - constructor(artifacts: ArtifactGroupModel, serviceID:string, readonly:boolean, sessionID:string, - requestID:string, diagramType:string, participants:Array<participant>){ - this.artifacts = artifacts; - this.serviceID = serviceID; - this.readonly = readonly; - this.sessionID = sessionID; - this.requestID = requestID; - this.diagramType = diagramType; - this.participants = participants; - } + constructor(artifacts:ArtifactGroupModel, serviceID:string, readonly:boolean, sessionID:string, + requestID:string, diagramType:string, participants:Array<participant>) { + this.artifacts = artifacts; + this.serviceID = serviceID; + this.readonly = readonly; + this.sessionID = sessionID; + this.requestID = requestID; + this.diagramType = diagramType; + this.participants = participants; } +} + +export class ManagementWorkflowViewModel { - export class ManagementWorkflowViewModel { + static '$inject' = [ + '$scope', + 'uuid4', + 'ComponentServiceNg2' + ]; - static '$inject' = [ - '$scope', - 'uuid4', - 'ComponentServiceNg2' - ]; + constructor(private $scope:IManagementWorkflowViewModelScope, + private uuid4:any, + private ComponentServiceNg2:ComponentServiceNg2) { - constructor(private $scope:IManagementWorkflowViewModelScope, - private uuid4:any, - private ComponentServiceNg2: ComponentServiceNg2) { + this.$scope.isLoading = true; + PunchOutRegistry.loadOnBoarding(()=> { + this.$scope.isLoading = false; this.initInformationalArtifacts(); - this.$scope.updateSelectedMenuItem(); - } + }); + } - private initInformationalArtifacts = ():void => { - if(!this.$scope.component.artifacts) { - this.$scope.isLoading = true; - this.ComponentServiceNg2.getComponentInformationalArtifacts(this.$scope.component).subscribe((response:ComponentGenericResponse) => { - this.$scope.component.artifacts = response.artifacts; - this.initScope(); - this.$scope.isLoading = false; - }); - } else { + private initInformationalArtifacts = ():void => { + if (!this.$scope.component.artifacts) { + this.$scope.isLoading = true; + this.ComponentServiceNg2.getComponentInformationalArtifacts(this.$scope.component).subscribe((response:ComponentGenericResponse) => { + this.$scope.component.artifacts = response.artifacts; this.initScope(); - } + this.$scope.isLoading = false; + }); + } else { + this.initScope(); } + } - private static getParticipants():Array<participant> { - return [ - { - "id": "1", - "name": "Customer"}, - { - "id": "2", - "name": "CCD" - }, - { - "id": "3", - "name": "Infrastructure" - }, - { - "id": "4", - "name": "MSO" - }, - { - "id": "5", - "name": "SDN-C" - }, - { - "id": "6", - "name": "A&AI" - }, - { - "id": "7", - "name": "APP-C" - }, - { - "id": "8", - "name": "Cloud" - }, - { - "id": "9", - "name": "DCAE" - }, - { - "id": "10", - "name": "ALTS" - }, - { - "id": "11", - "name": "VF" - } - ] - } + private static getParticipants():Array<participant> { + return [ + { + "id": "1", + "name": "Customer" + }, + { + "id": "2", + "name": "CCD" + }, + { + "id": "3", + "name": "Infrastructure" + }, + { + "id": "4", + "name": "MSO" + }, + { + "id": "5", + "name": "SDN-C" + }, + { + "id": "6", + "name": "A&AI" + }, + { + "id": "7", + "name": "APP-C" + }, + { + "id": "8", + "name": "Cloud" + }, + { + "id": "9", + "name": "DCAE" + }, + { + "id": "10", + "name": "ALTS" + }, + { + "id": "11", + "name": "VF" + } + ] + } - private initScope():void { - this.$scope.vendorModel = new VendorModel( - this.$scope.component.artifacts.filteredByType(ArtifactType.THIRD_PARTY_RESERVED_TYPES.WORKFLOW), - this.$scope.component.uniqueId, - this.$scope.isViewMode(), - this.$scope.user.userId, - this.uuid4.generate(), - ArtifactType.THIRD_PARTY_RESERVED_TYPES.WORKFLOW, - ManagementWorkflowViewModel.getParticipants() - ); + private initScope():void { + this.$scope.vendorModel = new VendorModel( + this.$scope.component.artifacts.filteredByType(ArtifactType.THIRD_PARTY_RESERVED_TYPES.WORKFLOW), + this.$scope.component.uniqueId, + this.$scope.isViewMode(), + this.$scope.user.userId, + this.uuid4.generate(), + ArtifactType.THIRD_PARTY_RESERVED_TYPES.WORKFLOW, + ManagementWorkflowViewModel.getParticipants() + ); - this.$scope.thirdParty = true; - this.$scope.setValidState(true); - } + this.$scope.thirdParty = true; + this.$scope.setValidState(true); } +} diff --git a/catalog-ui/src/app/view-models/workspace/tabs/management-workflow/management-workflow-view.html b/catalog-ui/src/app/view-models/workspace/tabs/management-workflow/management-workflow-view.html index bd196daec8..df570ccdca 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/management-workflow/management-workflow-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/management-workflow/management-workflow-view.html @@ -1,3 +1,4 @@ -<div class="workspace-management-workflow"> - <punch-out name="'sequence-diagram'" data="vendorModel" user="user" on-event="onVendorEvent"></punch-out> +<loader data-display="isLoading"></loader> +<div class="workspace-management-workflow" ng-if="vendorModel"> + <punch-out name="'sequence-diagram'" data="vendorModel" user="user" on-event="onVendorEvent"></punch-out> </div> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/network-call-flow/network-call-flow-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/network-call-flow/network-call-flow-view-model.ts index 6c7666d28c..488e4c774d 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/network-call-flow/network-call-flow-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/network-call-flow/network-call-flow-view-model.ts @@ -25,9 +25,11 @@ import {ResourceType, ArtifactType} from "app/utils"; import {ComponentInstance} from "app/models"; import {ComponentGenericResponse} from "../../../../ng2/services/responses/component-generic-response"; import {ComponentServiceNg2} from "../../../../ng2/services/component-services/component.service"; +declare var PunchOutRegistry; export interface INetworkCallFlowViewModelScope extends IWorkspaceViewModelScope { vendorMessageModel:VendorModel; + isLoading: boolean; } export class participant { @@ -53,8 +55,12 @@ export class NetworkCallFlowViewModel { private uuid4:any, private ComponentServiceNg2: ComponentServiceNg2) { - this.initComponentInstancesAndInformationalArtifacts(); - this.$scope.updateSelectedMenuItem(); + this.$scope.isLoading = true; + + PunchOutRegistry.loadOnBoarding(()=> { + this.$scope.isLoading = false; + this.initComponentInstancesAndInformationalArtifacts(); + }); } private getVFParticipantsFromInstances(instances:Array<ComponentInstance>):Array<participant> { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/network-call-flow/network-call-flow-view.html b/catalog-ui/src/app/view-models/workspace/tabs/network-call-flow/network-call-flow-view.html index 6ce3e8e2b7..bc2d0643e0 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/network-call-flow/network-call-flow-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/network-call-flow/network-call-flow-view.html @@ -1,3 +1,4 @@ -<div class="workspace-network-call-flow"> +<loader data-display="isLoading"></loader> +<div ng-if="vendorMessageModel" class="workspace-network-call-flow"> <punch-out name="'sequence-diagram'" data="vendorMessageModel" user="user" on-event="onVendorEvent"></punch-out> </div> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/properties/properties-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/properties/properties-view-model.ts index c9f2d0725f..3c9c7e9e4b 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/properties/properties-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/properties/properties-view-model.ts @@ -52,7 +52,6 @@ export class PropertiesViewModel { private ModalsHandler:ModalsHandler, private ComponentServiceNg2:ComponentServiceNg2) { this.initComponentProperties(); - this.$scope.updateSelectedMenuItem(); } private initComponentProperties = ():void => { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts index c02900a413..b6cbf65cf0 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts @@ -67,7 +67,6 @@ export class ReqAndCapabilitiesViewModel { private ComponentServiceNg2: ComponentServiceNg2) { this.initCapabilitiesAndRequirements(); - this.$scope.updateSelectedMenuItem(); } private initCapabilitiesAndRequirements = (): void => { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/tosca-artifacts/tosca-artifacts-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/tosca-artifacts/tosca-artifacts-view-model.ts index 5f724c48fd..77b5ab74eb 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/tosca-artifacts/tosca-artifacts-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/tosca-artifacts/tosca-artifacts-view-model.ts @@ -50,7 +50,6 @@ export class ToscaArtifactsViewModel { private $filter:ng.IFilterService, private ComponentServiceNg2:ComponentServiceNg2) { this.initToscaArtifacts(); - this.$scope.updateSelectedMenuItem(); } private initToscaArtifacts = (): void => { diff --git a/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts b/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts index ec8b04dbdb..a3af8ca68e 100644 --- a/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts @@ -87,7 +87,7 @@ export interface IWorkspaceViewModelScope extends ng.IScope { getLatestVersion():void; getStatus():string; showLifecycleIcon():boolean; - updateSelectedMenuItem():void; + updateSelectedMenuItem(state:string):void; uploadFileChangedInGeneralTab():void; updateMenuComponentName(ComponentName:string):void; getTabTitle():string; @@ -136,6 +136,7 @@ export class WorkspaceViewModel { this.initScope(); this.initAfterScope(); + this.$scope.updateSelectedMenuItem(this.$state.current.name); } private role:string; @@ -216,6 +217,7 @@ export class WorkspaceViewModel { this.$scope.onMenuItemPressed = (state:string):ng.IPromise<boolean> => { let deferred = this.$q.defer(); let goToState = ():void => { + this.$scope.updateSelectedMenuItem(state); this.$state.go(state, { id: this.$scope.component.uniqueId, type: this.$scope.component.componentType.toLowerCase(), @@ -613,9 +615,11 @@ export class WorkspaceViewModel { return result; }; - this.$scope.updateSelectedMenuItem = ():void => { + this.$scope.updateSelectedMenuItem = (state:string):void => { + let stateArray:Array<string> = state.split('.'); + let stateWithoutInternalNavigate:string = stateArray[0] + '.' + stateArray[1]; let selectedItem:MenuItem = _.find(this.$scope.leftBarTabs.menuItems, (item:MenuItem) => { - return item.state === this.$state.current.name; + return _.startsWith(item.state, stateWithoutInternalNavigate); }); this.$scope.leftBarTabs.selectedIndex = selectedItem ? this.$scope.leftBarTabs.menuItems.indexOf(selectedItem) : 0; }; @@ -636,7 +640,7 @@ export class WorkspaceViewModel { this.$scope.reload = (component:Component):void => { this.$state.go(this.$state.current.name,{id:component.uniqueId},{reload:true}); }; - + }; private initAfterScope = ():void => { diff --git a/catalog-ui/src/app/view-models/workspace/workspace.less b/catalog-ui/src/app/view-models/workspace/workspace.less index b7331b5f93..d0799f4bac 100644 --- a/catalog-ui/src/app/view-models/workspace/workspace.less +++ b/catalog-ui/src/app/view-models/workspace/workspace.less @@ -170,6 +170,9 @@ line-height: 110px; .f-type ._28; } + &.composition .w-sdc-main-container-body-content { + height: calc(~'100% - @{action_nav_height}'); //composition is the only tab without a tab title. need to exclude from calculation. + } .w-sdc-main-container-body-content { height:calc(~'100% - @{action_nav_height} - @{tab_title}'); align-items: center; diff --git a/catalog-ui/src/assets/styles/app.less b/catalog-ui/src/assets/styles/app.less index 13d88a388e..c19ace5823 100644 --- a/catalog-ui/src/assets/styles/app.less +++ b/catalog-ui/src/assets/styles/app.less @@ -8,6 +8,7 @@ @import 'mixins.less'; @import 'mixins_old.less'; @import 'global.less'; +@import '../../../node_modules/sdc-ui/css/style.css'; @import 'sprite-old.less'; @import 'sprite.less'; @@ -33,7 +34,7 @@ @import 'tooltips.less'; @import 'welcome-sprite.less'; @import 'welcome-style.less'; -@import 'sdc-ui.css'; +@import 'notification-template.less'; // Less insides specific files. @import '../../app/directives/ecomp-footer/ecomp-footer.less'; diff --git a/catalog-ui/src/assets/styles/global.less b/catalog-ui/src/assets/styles/global.less index 9faf4aeb0e..29e244e1a0 100644 --- a/catalog-ui/src/assets/styles/global.less +++ b/catalog-ui/src/assets/styles/global.less @@ -7,6 +7,7 @@ body { height: 100%; margin: auto; position: relative; + user-select: text; } * { diff --git a/catalog-ui/src/assets/styles/images/sprites/sprite-global.png b/catalog-ui/src/assets/styles/images/sprites/sprite-global.png Binary files differindex 962478fed3..87e5d43b4d 100644 --- a/catalog-ui/src/assets/styles/images/sprites/sprite-global.png +++ b/catalog-ui/src/assets/styles/images/sprites/sprite-global.png diff --git a/catalog-ui/src/assets/styles/images/welcome/002.png b/catalog-ui/src/assets/styles/images/welcome/002.png Binary files differindex e76c480ad8..d4fdae694a 100644 --- a/catalog-ui/src/assets/styles/images/welcome/002.png +++ b/catalog-ui/src/assets/styles/images/welcome/002.png diff --git a/catalog-ui/src/assets/styles/notification-template.less b/catalog-ui/src/assets/styles/notification-template.less new file mode 100644 index 0000000000..5baf10d411 --- /dev/null +++ b/catalog-ui/src/assets/styles/notification-template.less @@ -0,0 +1,53 @@ +.notification-container{ + display: flex; + padding: 15px 11px; + float: left; + .icon-container{ + flex-grow: 1; + margin-right: 20px; + .icon-circle{ + background-color: black; + height: 40px; + width: 40px; + border-radius: 50%; + display: flex; + align-items: center; + margin-right: 0; + background-color: rgba(255, 255, 255, 0.3); + .icon{ + margin: 0 auto; + display: block; + } + } + } + .msg-content{ + flex-grow: 3; + h3{ + border-bottom: none; + font-weight: 400; + .f-type._18_m; + } + .message{ + font-weight: 300; + .f-type._14_m; + } + } +} +.ui-notification.success{ + background-color: @main_color_d; + .icon{ + .notification-success-icon; + } +} +.ui-notification.error{ + background-color: @func_color_q; + .icon{ + .notification-error-icon; + } +} +.ui-notification.info{ + background-color: @main_color_a; + .icon{ + .notification-process-icon; + } +} diff --git a/catalog-ui/src/assets/styles/sdc-ui.css b/catalog-ui/src/assets/styles/sdc-ui.css deleted file mode 100644 index ad96e7762a..0000000000 --- a/catalog-ui/src/assets/styles/sdc-ui.css +++ /dev/null @@ -1,361 +0,0 @@ -@charset "UTF-8"; -/* Colors */ -.sdc-bc-blue { - background-color: #009fdb; } - -.sdc-bc-dark-blue { - background-color: #0568ae; } - -.sdc-bc-light-blue { - background-color: #71c5e8; } - -.sdc-bc-green { - background-color: #4ca90c; } - -.sdc-bc-dark-green { - background-color: #007a3e; } - -.sdc-bc-light-green { - background-color: #b5bd00; } - -.sdc-bc-orange { - background-color: #ea7400; } - -.sdc-bc-yellow { - background-color: #ffb81c; } - -.sdc-bc-dark-purple { - background-color: #702f8a; } - -.sdc-bc-purple { - background-color: #9063cd; } - -.sdc-bc-light-purple { - background-color: #caa2dd; } - -.sdc-bc-black { - background-color: #000000; } - -.sdc-bc-dark-gray { - background-color: #5a5a5a; } - -.sdc-bc-gray { - background-color: #959595; } - -.sdc-bc-light-gray { - background-color: #d2d2d2; } - -.sdc-bc-white { - background-color: #ffffff; } - -/* Prefix */ -/* Value Prefix*/ -/* Box sizing */ -/* Borders & Shadows */ -/* Opacity */ -/* Ellipsis */ -/* Vertical placement of multuple lines of text */ -/* transform-rotate */ -/* transform-translate */ -/* transform-scale */ -/**/ -/**/ -/*body {*/ - /*-webkit-touch-callout: none;*/ - /*-webkit-user-select: none;*/ - /*-moz-user-select: none;*/ - /*-ms-user-select: none;*/ - /*user-select: none; }*/ - -html { - font-size: 100%; - height: 100%; } - -body { - /* scrollbar styling for Internet Explorer */ - scrollbar-face-color: #191919; - scrollbar-track-color: #191919; - height: 100%; } - -/* scrollbar styling for Google Chrome | Safari | Opera */ -::-webkit-scrollbar { - width: 8px; - height: 8px; } - -::-webkit-scrollbar-track { - background-color: transparent; - border-radius: 10px; } - -::-webkit-scrollbar-thumb { - border-radius: 10px; - background-color: #d2d2d2; - border-right: 2px solid #ffffff; } - -/* Mozilla Firefox currently doesn't support scrollbar styling */ -ul { - list-style: none; } - -h1, h2, h3, h4, h5, h6, ul { - margin: 0; - padding: 0; } - -.disabled { - opacity: 0.7 !important; } - -fieldset { - border: none; } - -fieldset label { - display: inline-block; } - -.nav-tabs > li > a:focus, -.btn:focus, -.btn:active:focus, -.btn.active:focus { - outline: none; } - -/* Fonts */ -.text-lowercase { - text-transform: lowercase; } - -.text-uppercase, .heading-3-light, .heading-3, .heading-3-medium { - text-transform: uppercase; } - -.text-capitalize { - text-transform: capitalize; } - -.heading-1 { - font-weight: 300; - font-size: 36px; } - -.heading-2 { - font-weight: 300; - font-size: 24px; } - -.heading-3-light { - font-weight: 300; - font-size: 20px; } - -.heading-3 { - font-weight: 400; - font-size: 20px; } - -.heading-3-medium { - font-weight: 600; - font-size: 20px; } - -.heading-4 { - font-weight: 400; - font-size: 18px; } - -.heading-4-medium { - font-weight: 600; - font-size: 18px; } - -.heading-5 { - font-weight: 400; - font-size: 16px; } - -.heading-5-medium, .catalog-tile .catalog-tile-top .catalog-tile-item-name, .sdc-tile-catalog .sdc-tile-content .sdc-tile-content-info .sdc-tile-content-info-item-name { - font-weight: 400; - line-height: 16px; - font-size: 14px; } - -.body-1 { - font-weight: 400; - font-size: 14px; } - -.body-1-medium { - font-weight: 600; - font-size: 14px; } - -.body-1-light { - font-weight: 300; - font-size: 14px; } - -.body-2, .catalog-tile .catalog-tile-top .catalog-tile-entity-details .catalog-tile-version-info .catalog-tile-item-version, .catalog-tile .catalog-tile-content .catalog-tile-locking-user-name, .sdc-tile-catalog .sdc-tile-content .sdc-tile-content-info .sdc-tile-content-info-version-info .sdc-tile-content-info-version-info-text, .sdc-tile-catalog .sdc-tile-footer .sdc-tile-footer-text { - font-weight: 400; - font-size: 12px; } - -.body-2-medium, .catalog-tile .catalog-tile-content { - font-weight: 600; - font-size: 13px; } - -.body-3 { - font-weight: 400; - font-size: 12px; } - -.body-3-medium, .catalog-tile .catalog-tile-top .catalog-tile-entity-details .catalog-tile-vendor-name, .catalog-tile.vendor-type .catalog-tile-top .catalog-tile-vsp-count, .sdc-tile-catalog .sdc-tile-content .sdc-tile-content-info .sdc-tile-content-info-vendor-name { - font-weight: 600; - font-size: 12px; } - -.body-3-light { - font-weight: 300; - font-size: 12px; } - -.circle-icon-text { - font-weight: 600; - font-size: 14px; } - -.sdc-icon { - display: inline-block; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - width: 16px; - height: 16px; } - -.sdc-icon-locked { - background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='15' viewBox='0 0 11 15' id='locked_icon'> <metadata><?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?><x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 '> <rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'> <rdf:Description rdf:about=''/> </rdf:RDF></x:xmpmeta><?xpacket end='w'?></metadata><defs> <style> .cls-1 { fill: #959595; fill-rule: evenodd; } </style> </defs> <path id='Shape_77_copy_10' data-name='Shape 77 copy 10' class='cls-1' d='M445,359a16.71,16.71,0,0,0-2.1-.009c-1.945.045-3.195,0.049-3.9,0.009v-5a1.743,1.743,0,0,1,2-2h1a1.743,1.743,0,0,1,2,2v5c0.474,0.063.343-.073,1,0,0.266,0.029,0,.279,0,0v-5a2.726,2.726,0,0,0-3-3h-1.142c-1.72-.125-2.715,1.562-2.858,3,0.088,0.009,0,7.338,0,5h0a1.891,1.891,0,0,0-2,1.689v3.461A1.823,1.823,0,0,0,437.775,366h7.448A1.823,1.823,0,0,0,447,364.15v-3.461A2.018,2.018,0,0,0,445,359Z' transform='translate(-436 -351)'/></svg>"); - background-repeat: no-repeat; } - -.sdc-icon-plus { - background-image: url("data:image/svg+xml;utf8,<?xml version='1.0' encoding='utf-8'?><!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --><svg version='1.1' id='plus_icon' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 19 19' style='enable-background:new 0 0 19 19;' xml:space='preserve'><g><rect y='8' width='19' height='3'/><path id='Rectangle_2139_copy' d='M8,19V0h3v19H8z'/></g></svg>"); - background-repeat: no-repeat; } - -.sdc-icon-unlocked { - background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='18' viewBox='0 0 11 18' id='unlocked_icon'> <metadata><?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?><x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 '> <rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'> <rdf:Description rdf:about=''/> </rdf:RDF></x:xmpmeta><?xpacket end='w'?></metadata><defs> <style> .cls-1 { fill: #959595; fill-rule: evenodd; } </style> </defs> <path id='Shape_77_copy_16' data-name='Shape 77 copy 16' class='cls-1' d='M663,358a16.723,16.723,0,0,0-2.1-.009c-1.944.045-3.194,0.049-3.9,0.009v-7a1.743,1.743,0,0,1,2-2h1a1.743,1.743,0,0,1,2,2v2c0.474,0.064.343-.073,1,0,0.266,0.029,0,.279,0,0v-2a2.726,2.726,0,0,0-3-3h-1.142c-1.72-.125-2.715,1.562-2.858,3,0.088,0.009,0,9.338,0,7h0a1.891,1.891,0,0,0-2,1.689v4.461a1.823,1.823,0,0,0,1.775,1.85h7.448A1.823,1.823,0,0,0,665,364.15v-4.461A2.018,2.018,0,0,0,663,358Zm1.05,6.15a0.827,0.827,0,0,1-.8.836H655.8a0.827,0.827,0,0,1-.8-0.836l0-4.15a1.164,1.164,0,0,1,.8-1.147h7.448A1.129,1.129,0,0,1,664,360Z' transform='translate(-654 -348)'/></svg>"); - background-repeat: no-repeat; } - -.sdc-icon-vendor { - background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 53 47' id='vendor_icon'><title>vendor</title><g id='Layer_2' data-name='Layer 2'><g id='vlm_icon' data-name='vlm icon'><path d='M49,7,38.5,7V5.92A5.92,5.92,0,0,0,32.58,0H20.42A5.92,5.92,0,0,0,14.5,5.92V7.15L4,7.2a3.8,3.8,0,0,0-4,3.5V43.5C0,45.4,2,47,4.2,47L49,46.8a3.8,3.8,0,0,0,4-3.5V10.5A3.8,3.8,0,0,0,49,7ZM16.5,5.92A3.92,3.92,0,0,1,20.42,2H32.58A3.92,3.92,0,0,1,36.5,5.92V7.06l-20,.09ZM2,10.8A1.9,1.9,0,0,1,4,9l45-.2a1.9,1.9,0,0,1,2,1.8v8.87L32.94,24.18a6.49,6.49,0,0,0-12.89,0L2,19.51V10.8ZM31,25a4.5,4.5,0,1,1-4.5-4.5A4.5,4.5,0,0,1,31,25ZM49,45,4,45.2A1.9,1.9,0,0,1,2,43.4V21.57l18.13,4.73a6.5,6.5,0,0,0,12.74,0L51,21.53V43.21A1.9,1.9,0,0,1,49,45Z'/></g></g></svg>"); - background-repeat: no-repeat; } - -.sdc-icon-vlm { - background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 45 53'><title>vlm_new_icon</title><g id='Layer_2' data-name='Layer 2'><g id='vlm_icon' data-name='vlm icon'><path d='M41,2a2,2,0,0,1,2,2l.19,45a2,2,0,0,1-2,2H4a2,2,0,0,1-2-2L1.81,4a2,2,0,0,1,2-2H41m-.15-2H4A4.2,4.2,0,0,0,0,4.24L.19,49a4,4,0,0,0,4,4H41a4,4,0,0,0,4-4L44.81,4a4,4,0,0,0-4-4Z'/><rect x='14' y='11' width='17' height='2'/><rect x='14' y='18' width='10' height='2'/><polygon points='20.56 38.85 13.87 33.14 15.16 31.62 20.39 36.08 29.08 26.63 30.55 27.98 20.56 38.85'/></g></g></svg>"); - background-repeat: no-repeat; } - -.sdc-icon-vsp { - background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 59.5 40' id='vsp_icon'><title>vsp_new_icon</title><g id='Layer_2' data-name='Layer 2'><g id='vlm_icon' data-name='vlm icon'><path d='M58.28,30.74c-1.49-1.82-3-2.7-4.67-2.74a8.5,8.5,0,0,0-16.22-2.44,6.93,6.93,0,0,0-4.06.66A7.23,7.23,0,0,0,36.42,40H53.5a6,6,0,0,0,6-6A5.18,5.18,0,0,0,58.28,30.74ZM53.5,38H36.42a5.25,5.25,0,0,1-5.21-5.91,5.32,5.32,0,0,1,3-4.06,5,5,0,0,1,2.21-.53,5.25,5.25,0,0,1,1.35.18l.92.24L39,27A6.5,6.5,0,0,1,51.67,29v1.3l1.17-.2c1-.17,2.17-.17,3.91,2a3.18,3.18,0,0,1,.76,2A4,4,0,0,1,53.5,38Z'/><path d='M49,0,4,.17A3.79,3.79,0,0,0,0,3.69V7.94H0v2H0V36.31C0,38.35,2,40,4.25,40l20.84-.08a1,1,0,0,0,0-1.92L4,38.08a1.89,1.89,0,0,1-2-1.76V10H51v7a1,1,0,0,0,2,0V3.53A3.79,3.79,0,0,0,49,0ZM2,8V3.76A1.89,1.89,0,0,1,4,2l45-.16a1.89,1.89,0,0,1,2,1.76V8Z'/></g></g></svg>"); - background-repeat: no-repeat; } - -.svg-icon.purple { - fill: #9063cd; } - -.svg-icon.purple-hover { - fill: #9063cd; } - .svg-icon.purple-hover:hover { - fill: #caa2dd; } - -.svg-icon.blue { - fill: #009fdb; } - -.svg-icon.blue-hover { - fill: #009fdb; } - .svg-icon.blue-hover:hover { - fill: #71c5e8; } - -.svg-icon.gray { - fill: #959595; } - -.svg-icon.gray-hover { - fill: #000000; } - .svg-icon.gray-hover:hover { - fill: #d2d2d2; } - -.svg-icon.black { - fill: #000000; } - -.svg-icon.black-hover { - fill: #000000; } - .svg-icon.black-hover:hover { - fill: #d2d2d2; } - -.sdc-tile, .sdc-tile-catalog { - box-sizing: border-box; - background-color: #ffffff; - display: flex; - flex-direction: column; - padding: 10px; - cursor: pointer; - border: 1px solid #eaeaea; - -webkit-box-shadow: 0.5px 0.8px 4px 0 rgba(24, 24, 25, 0.05); - -moz-box-shadow: 0.5px 0.8px 4px 0 rgba(24, 24, 25, 0.05); - box-shadow: 0.5px 0.8px 4px 0 rgba(24, 24, 25, 0.05); } - .sdc-tile:active, .sdc-tile-catalog:active { - border: 1px solid #71c5e8; } - .sdc-tile:hover, .sdc-tile-catalog:hover { - box-shadow: 0.3px 5px 12.8px 1.3px rgba(24, 24, 25, 0.15); - border: 1px solid #d2d2d2; } - .sdc-tile .sdc-tile-header, .sdc-tile-catalog .sdc-tile-header { - position: relative; - flex-shrink: 0; - display: flex; - align-items: flex-start; - flex-direction: column; } - .sdc-tile .sdc-tile-content, .sdc-tile-catalog .sdc-tile-content { - position: relative; - flex: 1; - display: flex; - align-items: flex-start; - flex-direction: column; - overflow: auto; - justify-content: space-between; } - .sdc-tile .sdc-tile-footer, .sdc-tile-catalog .sdc-tile-footer { - position: relative; - flex-shrink: 0; - display: flex; - align-items: flex-start; - flex-direction: column; } - -.sdc-tile-catalog { - width: 204px; - height: 200px; } - .sdc-tile-catalog .sdc-tile-header { - line-height: 16px; } - .sdc-tile-catalog .sdc-tile-header .sdc-tile-header-type { - font-size: 14px; - text-transform: uppercase; } - .sdc-tile-catalog .sdc-tile-header .sdc-tile-header-type.purple { - color: #9063cd; } - .sdc-tile-catalog .sdc-tile-header .sdc-tile-header-type.blue { - color: #009fdb; } - .sdc-tile-catalog .sdc-tile-content .sdc-tile-content-icon { - align-items: center; - display: flex; - flex-direction: column; - width: 100%; - padding-top: 25px; } - .sdc-tile-catalog .sdc-tile-content .sdc-tile-content-icon svg { - width: 60px; - height: 40px; } - .sdc-tile-catalog .sdc-tile-content .sdc-tile-content-info { - padding-bottom: 4px; - width: 180px; - overflow: hidden; - text-overflow: ellipsis; - width: auto; - white-space: nowrap; - display: inline-block; - max-width: 178px; } - .sdc-tile-catalog .sdc-tile-content .sdc-tile-content-info .sdc-tile-content-info-vendor-name { - color: #959595; - line-height: 12px; } - .sdc-tile-catalog .sdc-tile-content .sdc-tile-content-info .sdc-tile-content-info-item-name { - color: #191919; } - .sdc-tile-catalog .sdc-tile-content .sdc-tile-content-info .sdc-tile-content-info-version-info { - display: flex; - justify-content: space-between; } - .sdc-tile-catalog .sdc-tile-footer { - display: flex; - flex-direction: row; - border-top: 1px solid #eaeaea; - padding: 0; - width: 180px; - height: 20px; } - .sdc-tile-catalog .sdc-tile-footer .sdc-tile-footer-text { - flex: 1; - padding-top: 5px; - overflow: hidden; - text-overflow: ellipsis; - width: auto; - white-space: nowrap; - display: inline-block; - max-width: 164px; } - .sdc-tile-catalog .sdc-tile-footer .sdc-tile-footer-icon { - flex-shrink: 1; - overflow: hidden; - padding-top: 5px; } - .sdc-tile-catalog .sdc-tile-footer .sdc-tile-footer-icon svg { - width: 16px; - height: 20px; } diff --git a/catalog-ui/src/assets/styles/sprite.less b/catalog-ui/src/assets/styles/sprite.less index 2076744854..3f82e488db 100644 --- a/catalog-ui/src/assets/styles/sprite.less +++ b/catalog-ui/src/assets/styles/sprite.less @@ -238,8 +238,12 @@ .round-expand-icon:hover { background-position: -100px -1188px; width: 15px; height: 15px; } .round-expand-icon.open { background-position: -50px -1216px; width: 15px; height: 15px; } .round-expand-icon.open:hover { background-position: -100px -1216px; width: 15px; height: 15px; } -.update-component-icon { background-position: -140px -1183px; width: 20px; height: 20px;} -.update-component-icon:hover { background-position: -170px -1183px; width: 20px; height: 20px;} +.update-component-icon { background-position: -140px -1213px; width: 20px; height: 20px;} +.update-component-icon:hover { background-position: -169px -1213px; width: 20px; height: 20px;} +.notification-user-icon{ background-position: -206px -1211px; width: 18px; height: 22px;} +.notification-error-icon{ background-position: -244px -1216px; width: 17px; height: 17px;} +.notification-success-icon{ background-position: -281px -1215px; width: 21px; height: 19px;} +.notification-process-icon{ background-position: -322px -1206px; width: 28px; height: 28px;} /* .sprite-new.expand-asset-icon { background-position: -740px -590px; width: 40px; height: 40px; } .sprite-new.view-info-icon { background-position: -739px -621px; width: 40px; height: 40px; } @@ -259,3 +263,20 @@ .sprite-new.vl-icon:active, .sprite-new.vl-icon.disabled-icon { background-position: -820px -682px; } .sprite-new.trash-icon:active, .sprite-new.trash-icon.disabled-icon { background-position: -820px -712px; } */ + + +.sprite-new.magnify-search { background-position: -206px -1276px; width: 30px; height: 30px; } +.sprite-new.magnify-search:hover { background-position: -125px -1276px; } +.sprite-new.magnify-search:active { background-position: -46px -1275px; } + +.sprite-new.zoom-plus { background-position: -208px -1380px; width: 30px; height: 30px; } +.sprite-new.zoom-plus:hover { background-position: -128px -1380px; } +.sprite-new.zoom-plus:active { background-position: -47px -1379px; } + +.sprite-new.zoom-minus { background-position: -208px -1433px; width: 30px; height: 30px; } +.sprite-new.zoom-minus:hover { background-position: -128px -1433px; } +.sprite-new.zoom-minus:active { background-position: -47px -1432px; } + +.sprite-new.canvas-fit-all { background-position: -208px -1326px; width: 30px; height: 30px;} +.sprite-new.canvas-fit-all:hover { background-position: -128px -1326px; } +.sprite-new.canvas-fit-all:active { background-position: -47px -1325px;} diff --git a/catalog-ui/src/assets/styles/svg/source/fit-all.svg b/catalog-ui/src/assets/styles/svg/source/fit-all.svg new file mode 100644 index 0000000000..dbea90963f --- /dev/null +++ b/catalog-ui/src/assets/styles/svg/source/fit-all.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="18px" height="19px" viewBox="0 0 18 19"> +<path fillRule="evenodd" d="M 17.94 18.86C 17.77 18.92 17.63 19 17.4 18.94 16.03 18.93 12.86 19 12.86 19 12.5 19 11.92 18.85 12 18 12.08 17.07 12.5 17 12.86 17 12.86 17 14.79 17 14.79 17 14.79 17 10.44 11.98 10.44 11.98 10.44 11.98 11.77 10.51 11.77 10.51 11.77 10.51 16.33 15.76 16.33 15.76 16.33 15.76 16.33 12.99 16.33 12.99 16.23 12.09 17.03 11.99 17.4 11.99 17.77 11.99 18.01 12.27 18.01 12.69 18.01 12.69 18.01 18.23 18.01 18.23 18.01 17.81 18 18.55 17.94 18.86ZM 17.33 7.36C 16.92 7.36 16.04 7.25 16.15 6.31 16.15 6.31 16.15 3.62 16.15 3.62 16.15 3.62 11.37 9 11.37 9 11.37 9 10.01 7.53 10.01 7.53 10.01 7.53 14.82 2.1 14.82 2.1 14.82 2.1 12.33 2.1 12.33 2.1 11.92 2.1 11.47 2.02 11.37 1.05 11.29 0.16 11.92-0 12.33-0 12.33-0 15.82 0.07 17.33 0.06 17.59 0 17.74 0.08 17.93 0.15 17.99 0.47 18 1.25 18 0.8 18 0.8 18 6.62 18 6.62 18 7.06 17.73 7.36 17.33 7.36ZM 5.67 16.9C 6.08 16.9 6.53 16.98 6.63 17.95 6.71 18.84 6.08 19 5.67 19 5.67 19 2.18 18.93 0.67 18.94 0.41 19 0.26 18.92 0.07 18.85 0.01 18.53-0 17.75-0 18.2-0 18.2-0 12.38-0 12.38-0 11.94 0.27 11.64 0.67 11.64 1.08 11.64 1.96 11.75 1.85 12.69 1.85 12.69 1.85 15.38 1.85 15.38 1.85 15.38 6.63 10 6.63 10 6.63 10 7.99 11.47 7.99 11.47 7.99 11.47 3.18 16.9 3.18 16.9 3.18 16.9 5.67 16.9 5.67 16.9ZM 6.63 9C 6.63 9 1.85 3.62 1.85 3.62 1.85 3.62 1.85 6.31 1.85 6.31 1.96 7.25 1.08 7.36 0.67 7.36 0.27 7.36-0 7.06-0 6.62-0 6.62-0 0.8-0 0.8-0 1.25 0.01 0.47 0.07 0.15 0.26 0.08 0.41 0 0.67 0.06 2.18 0.07 5.67-0 5.67-0 6.08-0 6.71 0.16 6.63 1.05 6.53 2.02 6.08 2.1 5.67 2.1 5.67 2.1 3.18 2.1 3.18 2.1 3.18 2.1 7.99 7.53 7.99 7.53 7.99 7.53 6.63 9 6.63 9Z" fill="rgb(89,89,89)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/minus.svg b/catalog-ui/src/assets/styles/svg/source/minus.svg new file mode 100644 index 0000000000..4ced110098 --- /dev/null +++ b/catalog-ui/src/assets/styles/svg/source/minus.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="16px" height="2px" viewBox="0 0 16 2"> +<path fillRule="evenodd" d="M 1-0C 1-0 15-0 15-0 15.55-0 16 0.45 16 1 16 1.55 15.55 2 15 2 15 2 1 2 1 2 0.45 2 0 1.55 0 1 0 0.45 0.45-0 1-0Z" fill="rgb(99,99,99)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/plus.svg b/catalog-ui/src/assets/styles/svg/source/plus.svg new file mode 100644 index 0000000000..dff172c54d --- /dev/null +++ b/catalog-ui/src/assets/styles/svg/source/plus.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="18px" height="18px" viewBox="0 0 18 18"> +<path fillRule="evenodd" d="M 17 10C 17 10 10 10 10 10 10 10 10 17 10 17 10 17.55 9.55 18 9 18 8.45 18 8 17.55 8 17 8 17 8 10 8 10 8 10 1 10 1 10 0.45 10 0 9.55 0 9 0 8.45 0.45 8 1 8 1 8 8 8 8 8 8 8 8 1 8 1 8 0.45 8.45 0 9 0 9.55 0 10 0.45 10 1 10 1 10 8 10 8 10 8 17 8 17 8 17.55 8 18 8.45 18 9 18 9.55 17.55 10 17 10Z" fill="rgb(99,99,99)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/search-magnify.svg b/catalog-ui/src/assets/styles/svg/source/search-magnify.svg new file mode 100644 index 0000000000..279c13fd52 --- /dev/null +++ b/catalog-ui/src/assets/styles/svg/source/search-magnify.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="23px" height="26px" viewBox="0 0 23 26"> +<path fillRule="evenodd" d="M 17.53 4.53C 14.5 0.28 8.55-0.71 4.3 2.32 0.05 5.36-0.94 11.31 2.09 15.56 3.56 17.63 5.74 18.99 8.25 19.41 10.42 19.77 12.58 19.38 14.48 18.32 14.48 18.32 20.28 25.23 20.28 25.23 20.44 25.47 20.7 25.61 20.93 25.65 21.16 25.69 21.45 25.64 21.68 25.47 22.15 25.13 22.26 24.5 21.92 24.06 21.92 24.06 16.11 17.15 16.11 17.15 17.73 15.7 18.81 13.79 19.17 11.61 19.58 9.14 19.01 6.6 17.53 4.53ZM 3.76 14.4C 1.37 11.04 2.14 6.4 5.5 4 7.18 2.8 9.16 2.41 11.07 2.73 12.97 3.05 14.73 4.07 15.92 5.74 17.09 7.38 17.52 9.34 17.19 11.32 16.86 13.29 15.79 15 14.18 16.17 12.58 17.35 10.58 17.77 8.61 17.44 6.65 17.08 4.9 16.03 3.76 14.4Z" fill="rgb(99,99,99)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/index.html b/catalog-ui/src/index.html index c41532e01c..044eb374a6 100644 --- a/catalog-ui/src/index.html +++ b/catalog-ui/src/index.html @@ -1,26 +1,29 @@ <!doctype html> <html> <head> - <meta charset="utf-8"> - <title>SDC</title> - <base href="/"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - - <link rel="icon" type="image/x-icon" href="favicon.ico"> + <meta charset="utf-8"> + <title>SDC</title> + <base href="/"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <link rel="icon" type="image/x-icon" href="favicon.ico"> + </head> <body data-ng-class="bodyClass"> - <!--<h1>Index.html</h1>--> - <app-root>Loading...</app-root> - <!--<h2>Before ui-view</h2>--> - <div ui-view style="height:100%"></div> - <!--<h2>After ui-view</h2>--> - <script type="text/javascript" src="/sdc1/scripts/inline.bundle.js"></script> - <script type="text/javascript" src="/sdc1/scripts/polyfills.bundle.js"></script> - <script type="text/javascript" src="/sdc1/scripts/vendor.bundle.js"></script> - <script type="text/javascript" src="/dcae/dcae-bundle.js"></script> - <script type="text/javascript" src="/sdc1/scripts/main.bundle.js"></script> - <script type="text/javascript" src="/sdc1/scripts/styles.bundle.js"></script></body> - <script type="text/javascript" src="/onboarding/punch-outs_en.js" async></script> +<!--<h1>Index.html</h1>--> +<app-root>Loading...</app-root> +<!--<h2>Before ui-view</h2>--> +<div ui-view style="height:100%"></div> +<!--<h2>After ui-view</h2>--> +<script src="/sdc1/scripts/inline.bundle.js"></script> +<script src="/sdc1/scripts/polyfills.bundle.js"></script> +<script src="/sdc1/scripts/vendor.bundle.js"></script> +<script src="/dcae/dcae-bundle.js"></script> +<script id="main-bundle" src="/sdc1/scripts/main.bundle.js"></script> +<script src="/sdc1/scripts/styles.bundle.js"></script> + +</body> </html> + diff --git a/catalog-ui/src/main.ts b/catalog-ui/src/main.ts index 20e4352901..9d25a34169 100644 --- a/catalog-ui/src/main.ts +++ b/catalog-ui/src/main.ts @@ -38,10 +38,10 @@ if (__ENV__==='prod') { // Ugliy fix because the cookie recieved from webseal change his value after some seconds. declare var __ENV__: string; -let timeout:number = 5000; +let timeout:number = 0; if (__ENV__==='dev'){ timeout=0; -} +} window.setTimeout(()=>{ platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; diff --git a/catalog-ui/src/third-party/PunchOutRegistry.js b/catalog-ui/src/third-party/PunchOutRegistry.js index db8e6875d6..506a785c79 100644 --- a/catalog-ui/src/third-party/PunchOutRegistry.js +++ b/catalog-ui/src/third-party/PunchOutRegistry.js @@ -18,7 +18,9 @@ * ============LICENSE_END========================================================= */ -(function(window) { + + +(function (window) { "use strict"; if (window.PunchOutRegistry) { @@ -29,9 +31,20 @@ var factoryPromises = new Map(); var instancePromises = new Map(); + function loadOnBoarding(callback) { + + if (factoryPromises.has("onboarding/vendor") && !queuedFactoryRequests.has("onboarding/vendor")) { + callback(); + } + else { + console.log("Load OnBoarding"); + $.getScript("/onboarding/punch-outs_en.js").then(callback); + } + } + function registerFactory(name, factory) { if (factoryPromises.has(name) && !queuedFactoryRequests.has(name)) { - console.error("PunchOut \"" + name + "\" has been already registered"); + // console.error("PunchOut \"" + name + "\" has been already registered"); return; } if (queuedFactoryRequests.has(name)) { @@ -58,7 +71,7 @@ var factoryPromise; var instancePromise = instancePromises.get(element); if (!instancePromise) { - instancePromise = getFactoryPromise(name).then(function(factory) { + instancePromise = getFactoryPromise(name).then(function (factory) { return factory(); }); instancePromises.set(element, instancePromise); @@ -69,7 +82,8 @@ function renderPunchOut(params, element) { var name = params.name; var options = params.options || {}; - var onEvent = params.onEvent || function () {}; + var onEvent = params.onEvent || function () { + }; getInstancePromise(name, element).then(function (punchOut) { punchOut.render({options: options, onEvent: onEvent}, element); @@ -81,7 +95,7 @@ console.error("There is no PunchOut in element", element); return; } - instancePromises.get(element).then(function(punchOut) { + instancePromises.get(element).then(function (punchOut) { punchOut.unmount(element); }); instancePromises.delete(element); @@ -90,7 +104,8 @@ var PunchOutRegistry = Object.freeze({ register: registerFactory, render: renderPunchOut, - unmount: unmountPunchOut + unmount: unmountPunchOut, + loadOnBoarding: loadOnBoarding }); window.PunchOutRegistry = PunchOutRegistry; diff --git a/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js b/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js index 2da6f786ea..0e6ca8b3c2 100644 --- a/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js +++ b/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js @@ -199,19 +199,7 @@ this._resizeCanvas(); - this._arrowEnd = this._cy.add({ - group: "nodes", - data: { - "id": this.ARROW_END_ID, - "position": {x: 150, y: 150} - } - }); - this._arrowEnd.css({ - "opacity": 0, - 'width': 0.0001, - 'height': 0.0001 - }); }, registerHandle: function (handle) { @@ -250,13 +238,14 @@ _drawHandle: function (handle, target) { var position = this._getHandlePosition(handle, target); - + var handleSize = this.HANDLE_SIZE * this._cy.zoom(); + this._ctx.beginPath(); if (handle.imageUrl) { var base_image = new Image(); base_image.src = handle.imageUrl; - this._ctx.drawImage(base_image, position.x, position.y, this.HANDLE_SIZE, this.HANDLE_SIZE); + this._ctx.drawImage(base_image, position.x, position.y, handleSize, handleSize); } else { this._ctx.arc(position.x, position.y, this.HANDLE_SIZE, 0, 2 * Math.PI, false); this._ctx.fillStyle = handle.color; @@ -272,6 +261,22 @@ if (this._hover) { toNode = this._hover; } else { + if (!this._arrowEnd) { + this._arrowEnd = this._cy.add({ + group: "nodes", + data: { + "id": this.ARROW_END_ID, + "position": { x: 150, y: 150 } + } + }); + + this._arrowEnd.css({ + "opacity": 0, + 'width': 0.0001, + 'height': 0.0001 + }); + } + this._arrowEnd.renderedPosition(toPosition); toNode = this._arrowEnd; } @@ -301,6 +306,11 @@ this._edge.remove(); this._edge = null; } + + if (this._arrowEnd) { + this._arrowEnd.remove(); + this._arrowEnd = null; + } }, _resizeCanvas: function () { this._$canvas @@ -449,7 +459,8 @@ var handle = handles[i]; var position = this._getHandlePosition(handle, this._hover); - if (VectorMath.distance(position, mousePoisition) < this.HANDLE_SIZE) { + var renderedHandleSize = this.HANDLE_SIZE * this._cy.zoom(); //actual number of pixels that handle uses. + if (VectorMath.distance(position, mousePoisition) < renderedHandleSize) { return { handle: handle, position: position @@ -459,19 +470,20 @@ } } }, - _getHandlePosition: function (handle, target) { + _getHandlePosition: function (handle, target) { //returns the upper left point at which to begin drawing the handle var position = target.renderedPosition(); - var width = target.renderedOuterWidth(); - var height = target.renderedOuterHeight(); + var width = target.renderedWidth(); + var height = target.renderedHeight(); + var renderedHandleSize = this.HANDLE_SIZE * this._cy.zoom(); //actual number of pixels that handle will use. var xpos = null; var ypos = null; switch (handle.positionX) { case "left": - xpos = position.x - width / 2 + this.HANDLE_SIZE; + xpos = position.x - width / 2; break; - case "right": - xpos = position.x + width / 2 - this.HANDLE_SIZE; + case "right": //position.x is the exact center of the node. Need to add half the width to get to the right edge. Then, subtract renderedHandleSize to get handle position + xpos = position.x + width / 2 - renderedHandleSize; break; case "center": xpos = position.x; @@ -480,19 +492,21 @@ switch (handle.positionY) { case "top": - ypos = position.y - height / 2 + this.HANDLE_SIZE; + ypos = position.y - height / 2; break; case "center": ypos = position.y; break; case "bottom": - ypos = position.y + height / 2 - this.HANDLE_SIZE; + ypos = position.y + height / 2; break; } - var offsetX = handle.offsetX ? handle.offsetX : 0; - var offsetY = handle.offsetY ? handle.offsetY : 0; - return {x: xpos + offsetX, y: ypos + offsetY}; + //Determine if handle will be too big and require offset to prevent it from covering too much of the node icon (in which case, move it over by 1/2 the renderedHandleSize, so half the handle overlaps). + //Need to use target.width(), which is the size of the node, unrelated to rendered size/zoom + var offsetX = (target.width() < 30) ? renderedHandleSize / 2 : 0; + var offsetY = (target.height() < 30) ? renderedHandleSize /2 : 0; + return {x: xpos + offsetX, y: ypos - offsetY}; }, _getEdgeCSSByHandle: function (handle) { var color = handle.lineColor ? handle.lineColor : handle.color; diff --git a/catalog-ui/webpack.common.js b/catalog-ui/webpack.common.js index fc2f5a4387..4482d0e014 100644 --- a/catalog-ui/webpack.common.js +++ b/catalog-ui/webpack.common.js @@ -9,7 +9,7 @@ const postcssUrl = require('postcss-url'); const {GlobCopyWebpackPlugin, BaseHrefWebpackPlugin} = require('@angular/cli/plugins/webpack'); const {CommonsChunkPlugin} = require('webpack').optimize; const {AotPlugin} = require('@ngtools/webpack'); - +var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const nodeModules = path.join(process.cwd(), 'node_modules'); const bundledScripts = [ @@ -196,6 +196,7 @@ module.exports = function(params) { }), new webpack.NoEmitOnErrorsPlugin(), new ProgressPlugin(), + // new BundleAnalyzerPlugin(), // new HtmlWebpackPlugin({ // template: "./src/index.html", // filename: "./index.html", diff --git a/catalog-ui/webpack.production.js b/catalog-ui/webpack.production.js index db33a94f3e..a593e37119 100644 --- a/catalog-ui/webpack.production.js +++ b/catalog-ui/webpack.production.js @@ -7,20 +7,10 @@ const ServerConfig = require('./webpack.server'); const webpackCommonConfig = require('./webpack.common'); const {GlobCopyWebpackPlugin, BaseHrefWebpackPlugin} = require('@angular/cli/plugins/webpack'); const CopyWebpackPlugin = require('copy-webpack-plugin'); - +var CompressionPlugin = require('compression-webpack-plugin'); var currentTime = new Date().getTime(); -const params = { - // entryPoints: [ - // '/sdc1/scripts/inline', - // '/sdc1/scripts/polyfills', - // '/sdc1/scripts/vendor', - // '/sdc1/scripts/main', - // '/sdc1/scripts/sw-register', - // '/sdc1/scripts/scripts', - // '/sdc1/scripts/styles' - // ] -}; +const params = {}; const webpackProdConfig = { module: { @@ -29,7 +19,7 @@ const webpackProdConfig = { { test: /\.(jpg|png|gif|otf|ttf|woff|woff2|cur|ani)$/, loader: "url-loader?name=/scripts/images/[name].[hash:20].[ext]&limit=10000" - } + } ] }, output: { @@ -47,9 +37,10 @@ const webpackProdConfig = { new CopyWebpackPlugin([ { from: './src/index.html', transform: function (content, path) { - content = (content + '').replace(/\.bundle/g, '.' + currentTime + '.bundle'); - return content; - } + content = (content + '').replace(/\.bundle.js/g, '.' + currentTime + '.bundle.jsgz'); + + return content; + } } ]), new webpack.optimize.UglifyJsPlugin({ @@ -63,6 +54,12 @@ const webpackProdConfig = { screw_ie8: true }, comments: false + }), + new webpack.optimize.AggressiveMergingPlugin(),//Merge chunks + new CompressionPlugin({ + asset: "[path]gz", + algorithm: "gzip", + test: /\.js$|\.css$|\.html$/ }) ] }; |