From 39a4e0cb1b805470ad85ed4cf4fdeb69610ae98c Mon Sep 17 00:00:00 2001 From: Michael Lando Date: Tue, 18 Jul 2017 20:46:42 +0300 Subject: [SDC] rebase 1710 Change-Id: I07fced02f40a57700d9d35ed3ba498bca351fb13 Signed-off-by: Michael Lando --- catalog-ui/src/app/app.ts | 17 +++++- .../style/component-instances-nodes-style.ts | 4 +- .../composition-graph.directive.ts | 60 ++++++++++++++++++-- .../composition-graph/composition-graph.html | 7 +++ .../utils/composition-graph-general-utils.ts | 8 +++ .../utils/composition-graph-nodes-utils.ts | 15 +++++ catalog-ui/src/app/models/components/component.ts | 21 +++---- catalog-ui/src/app/models/components/resource.ts | 23 ++++---- catalog-ui/src/app/ng2/app.module.ts | 8 ++- .../inputs-table/inputs-table.component.less | 2 +- .../properties-table.component.less | 6 +- .../shared/search-bar/search-bar.component.html | 5 ++ .../shared/search-bar/search-bar.component.less | 58 +++++++++++++++++++ .../ng2/shared/search-bar/search-bar.component.ts | 30 ++++++++++ .../search-with-autocomplete.component.html | 6 ++ .../search-with-autocomplete.component.less | 35 ++++++++++++ .../search-with-autocomplete.component.ts | 30 ++++++++++ .../shared/notification-custom-template.html | 14 +++++ .../tabs/composition/composition-view-model.ts | 6 +- .../tabs/composition/composition-view.html | 4 +- .../workspace/tabs/composition/composition.less | 65 ++++++++++++++++++++++ .../tabs/artifacts/artifacts-view-model.ts | 18 +++++- .../composition/tabs/artifacts/artifacts-view.html | 2 +- .../composition/tabs/details/details-view.html | 4 +- .../src/app/view-models/workspace/workspace.less | 3 + 25 files changed, 404 insertions(+), 47 deletions(-) create mode 100644 catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.html create mode 100644 catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.less create mode 100644 catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.ts create mode 100644 catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.html create mode 100644 catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.less create mode 100644 catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.ts create mode 100644 catalog-ui/src/app/view-models/shared/notification-custom-template.html (limited to 'catalog-ui/src/app') 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/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..64197594e2 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 @@ -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..9aa7941272 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; //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: 2.5, + minZoom: .1, + userZoomingEnabled: false, + userPanningEnabled: true, selectionType: 'single', boxSelectionEnabled: true, autolock: isViewOnly, @@ -270,6 +284,40 @@ 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) => { + 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) => { + if (searchTerm === undefined) return; //dont zoom & highlight if click on Search initially (searchTerm will be undefined). However, allow highlights to be cleared after subsequent search (searchTerm will be "") + + 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 +415,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 +425,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 @@ +
+ +
+
+
+
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/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/ng2/app.module.ts b/catalog-ui/src/app/ng2/app.module.ts index 09b40e920f..57adb8fd66 100644 --- a/catalog-ui/src/app/ng2/app.module.ts +++ b/catalog-ui/src/app/ng2/app.module.ts @@ -40,6 +40,8 @@ import {ComponentInstanceServiceNg2} from "./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)); @@ -60,7 +62,9 @@ export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: Reque @NgModule({ declarations: [ - AppComponent + AppComponent, + SearchBarComponent, + SearchWithAutoCompleteComponent ], imports: [ BrowserModule, @@ -70,7 +74,7 @@ export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: Reque PropertiesAssignmentModule ], exports: [], - entryComponents: [], + entryComponents: [SearchWithAutoCompleteComponent], providers: [ DataTypesServiceProvider, SharingServiceProvider, 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/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/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 @@ +
+ + x + +
\ 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..2835d20ba4 --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.ts @@ -0,0 +1,30 @@ +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 = new EventEmitter(); + @Output() searchButtonClicked: EventEmitter = new EventEmitter(); + + searchButtonClick = (): void => { + this.searchButtonClicked.emit(this.searchQuery); + } + + searchQueryChange = ($event): void => { + this.searchChanged.emit($event); + } + + private clearSearchQuery = (): void => { + this.searchQuery = ""; + this.searchButtonClick(); + } +} + 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 @@ +
+ +
+
{{item}}
+
+
\ 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; + @Output() searchChanged: EventEmitter = new EventEmitter(); + @Output() searchButtonClicked: EventEmitter = new EventEmitter(); + + 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/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 @@ +
+
+
+
+
+
+
+
+
+

+
+
+
+
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..0e5a5fcd6c 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; isLoading:boolean; graphApi:any; sharingService:SharingService; @@ -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 => { 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"> + is-view-only="isViewOnly" with-sidebar="displayDesignerRightSidebar">
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..c4c63fae06 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; artifactType:string; downloadFile:IFileDownload; isLoading:boolean; - + displayDeleteButtonMap:Dictionary; 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(); + _.forEach(this.$scope.artifacts, (artifact:ArtifactModel)=>{ + this.$scope.displayDeleteButtonMap[artifact.artifactLabel] = this.displayDeleteButton(artifact); + }); this.$scope.isLoading = false; }; @@ -229,6 +234,17 @@ 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; 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 @@ Description:{{artifact.description}} -