diff options
author | ys9693 <ys9693@att.com> | 2020-01-19 13:50:02 +0200 |
---|---|---|
committer | Ofir Sonsino <ofir.sonsino@intl.att.com> | 2020-01-22 12:33:31 +0000 |
commit | 16a9fce0e104a38371a9e5a567ec611ae3fc7f33 (patch) | |
tree | 03a2aff3060ddb5bc26a90115805a04becbaffc9 /catalog-ui/src/app/ng2/pages/composition/palette | |
parent | aa83a2da4f911c3ac89318b8e9e8403b072942e1 (diff) |
Catalog alignment
Issue-ID: SDC-2724
Signed-off-by: ys9693 <ys9693@att.com>
Change-Id: I52b4aacb58cbd432ca0e1ff7ff1f7dd52099c6fe
Diffstat (limited to 'catalog-ui/src/app/ng2/pages/composition/palette')
20 files changed, 1028 insertions, 0 deletions
diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/__snapshots__/palette.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/composition/palette/__snapshots__/palette.component.spec.ts.snap new file mode 100644 index 0000000000..74517e1eb0 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/__snapshots__/palette.component.spec.ts.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`palette component should match current snapshot of palette component 1`] = ` +<composition-palette + buildPaletteByCategories={[Function Function]} + compositionPaletteService={[Function Object]} + eventListenerService={[Function Object]} + numberOfElements="0" + onDragStart={[Function Function]} + onDraggableMoved={[Function Function]} + onDrop={[Function Function]} + onMouseOut={[Function Function]} + onMouseOver={[Function Function]} + onSearchChanged={[Function Function]} + position={[Function Point]} +> + <div + class="composition-palette-component" + > + <div + class="palette-elements-count" + > + Elements + <span + class="palette-elements-count-value" + > + + </span> + </div> + <sdc-filter-bar + placeholder="Search..." + testid="searchAsset" + /> + <div + class="palette-elements-list" + > + <sdc-loader + name="palette-loader" + testid="palette-loader" + /> + + + </div> + </div><div + dnddropzone="" + id="draggable_element" + > + + </div> +</composition-palette> +`; diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.component.html b/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.component.html new file mode 100644 index 0000000000..efd619687c --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.component.html @@ -0,0 +1,20 @@ +<!-- + ~ Copyright (C) 2018 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. + --> + +<div class="palette-animation-wrapper" [style.top]="from.y + 50 + 'px'" [style.left]="from.x + 'px'" [style.transform]="transformStyle" [class.hidden]="!visible" + (transitionend)="animationComplete()"> +<div class="medium small sprite-resource-icons sprite-{{iconName}}-icons {{iconName}}" ></div> +</div> diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.component.less b/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.component.less new file mode 100644 index 0000000000..54f04189c0 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.component.less @@ -0,0 +1,5 @@ +.palette-animation-wrapper{ + position: absolute; + z-index: 100; + transition: all 2s ease-in-out; +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.component.ts b/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.component.ts new file mode 100644 index 0000000000..a445c87f42 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.component.ts @@ -0,0 +1,71 @@ +/*- + * ============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 {Component, Input } from '@angular/core'; +import {BrowserModule} from '@angular/platform-browser'; +import { setTimeout } from 'core-js/library/web/timers'; +import { EventListenerService } from 'app/services'; +import { GRAPH_EVENTS } from 'app/utils'; +import { Point } from 'app/models'; +import { ZoneInstanceType, ZoneInstance } from 'app/models/graph/zones/zone-instance'; + + + +@Component({ + selector: 'palette-animation', + templateUrl: './palette-animation.component.html', + styleUrls:['./palette-animation.component.less'], +}) + +export class PaletteAnimationComponent { + + @Input() from : Point; + @Input() to : Point; + @Input() type: ZoneInstanceType; + @Input() iconName : string; + @Input() zoneInstance : ZoneInstance; + + public animation; + private visible:boolean = false; + private transformStyle:string = ""; + + + constructor(private eventListenerService:EventListenerService) {} + + + ngOnDestroy(){ + this.zoneInstance.hidden = false; //if animation component is destroyed before animation is complete + } + + public runAnimation() { + this.visible = true; + let positionDiff:Point = new Point(this.to.x - this.from.x, this.to.y - this.from.y); + setTimeout(()=>{ + this.transformStyle = 'translate('+ positionDiff.x + 'px,' + positionDiff.y +'px)'; + }, 0); + }; + + public animationComplete = (e) => { + this.visible = false; + this.zoneInstance.hidden = false; + }; + + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.module.ts b/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.module.ts new file mode 100644 index 0000000000..8674571138 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-animation/palette-animation.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { PaletteAnimationComponent } from "./palette-animation.component"; + + +@NgModule({ + declarations: [ + PaletteAnimationComponent + ], + imports: [ CommonModule ], + exports: [ PaletteAnimationComponent ] +}) + +export class PaletteAnimationModule { + +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/__snapshots__/palette-element.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/__snapshots__/palette-element.component.spec.ts.snap new file mode 100644 index 0000000000..40df575519 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/__snapshots__/palette-element.component.spec.ts.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`palette element component should match current snapshot of palette element component 1`] = ` +<palette-element> + <div + class="palette-element" + > + <sdc-element-icon + class="palette-element-icon" + /> + <div + class="palette-element-text" + > + <div + class="palette-element-name" + sdc-tooltip="" + > + + </div> + <span> + V. + </span> + <span> + + </span> + </div> + </div> +</palette-element> +`; diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.html b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.html new file mode 100644 index 0000000000..3a6be5d082 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.html @@ -0,0 +1,11 @@ +<div class="palette-element" > + <sdc-element-icon class="palette-element-icon" [iconName]="paletteElement.icon" + [elementType]="paletteElement.componentSubType"[uncertified]="this.paletteElement.certifiedIconClass"></sdc-element-icon> + <div class="palette-element-text"> + <div class="palette-element-name" sdc-tooltip + tooltip-text='{{paletteElement.name | resourceName}}'>{{paletteElement.name | resourceName}} + </div> + <span> V.{{paletteElement.version}}</span> + <span>{{paletteElement.componentSubType}}</span> + </div> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.less b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.less new file mode 100644 index 0000000000..e9c3253fbd --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.less @@ -0,0 +1,32 @@ +@import "./../../../../../../assets/styles/override"; +.palette-element { + cursor: pointer; + display: flex; + flex-direction: row; + max-height: 65px; + border-bottom: 1px solid @sdcui_color_silver; + padding: 10px; + align-items: center; + .palette-element-icon { + min-width: 45px; + text-align: center; + } + + .palette-element-text { + display: flex; + flex-direction: column; + font-size: 13px; + line-height: 15px; + padding-left: 10px; + font-family: OpenSans-Regular, sans-serif; + overflow: hidden; + + .palette-element-name { + color: @sdcui_color_dark-gray; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + } + +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.spec.ts new file mode 100644 index 0000000000..64ed45ba9c --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.spec.ts @@ -0,0 +1,30 @@ +import {async, ComponentFixture} from "@angular/core/testing"; +import {ConfigureFn, configureTests} from "../../../../../../jest/test-config.helper"; +import {NO_ERRORS_SCHEMA} from "@angular/core"; +import {PaletteElementComponent} from "./palette-element.component"; +import {ResourceNamePipe} from "../../../../pipes/resource-name.pipe"; + +describe('palette element component', () => { + + let fixture: ComponentFixture<PaletteElementComponent>; + + beforeEach( + async(() => { + const configure: ConfigureFn = testBed => { + testBed.configureTestingModule({ + declarations: [PaletteElementComponent, ResourceNamePipe], + imports: [], + schemas: [NO_ERRORS_SCHEMA] + }); + }; + + configureTests(configure).then(testBed => { + fixture = testBed.createComponent(PaletteElementComponent); + }); + }) + ); + + it('should match current snapshot of palette element component', () => { + expect(fixture).toMatchSnapshot(); + }); +});
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.ts b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.ts new file mode 100644 index 0000000000..9e9e5a29da --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-element/palette-element.component.ts @@ -0,0 +1,35 @@ +/** + * Created by ob0695 on 6/28/2018. + */ +/*- + * ============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 {Component, Input} from "@angular/core"; +import {LeftPaletteComponent} from "app/models/components/displayComponent"; + +@Component({ + selector: 'palette-element', + templateUrl: './palette-element.component.html', + styleUrls: ['./palette-element.component.less'] +}) +export class PaletteElementComponent { + + @Input() paletteElement: LeftPaletteComponent; +} diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-popup-panel/palette-popup-panel.component.html b/catalog-ui/src/app/ng2/pages/composition/palette/palette-popup-panel/palette-popup-panel.component.html new file mode 100644 index 0000000000..86847eb28a --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-popup-panel/palette-popup-panel.component.html @@ -0,0 +1,30 @@ +<!-- + ~ Copyright (C) 2018 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. + --> + +<div class="popup-panel" [ngClass]="{'hide':!isShowPanel}" [style.left]="popupPanelPosition.x + 'px'" [style.top]="popupPanelPosition.y + 'px'" + (mousedown)="addZoneInstance()" + (mouseenter)="onMouseEnter()" + (mouseleave)="onMouseLeave()"> + <div class="popup-panel-group"> + <div class="popup-panel-plus">+</div> + <div class="popup-panel-title">{{panelTitle}}</div> + </div> +</div> +<!--<popup-menu-list [menuItemsData]="getMenuItems()">--> + + + +<!--</popup-menu-list>-->
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-popup-panel/palette-popup-panel.component.less b/catalog-ui/src/app/ng2/pages/composition/palette/palette-popup-panel/palette-popup-panel.component.less new file mode 100644 index 0000000000..24f0485e76 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-popup-panel/palette-popup-panel.component.less @@ -0,0 +1,37 @@ +.popup-panel { + position: absolute; + display: inline-block; + background-color: white; + border: solid 1px #d2d2d2; + border-top: solid 3px #13a7df; + left: 208px; top: 0px; + width: 140px; + height: 40px; + z-index: 10000; + + &:hover { + background-color: whitesmoke; + } + + .popup-panel-group { + padding-left: 8px; + padding-top: 8px; + cursor: pointer; + + .popup-panel-plus { + border-radius: 50%; + color: white; + background-color: #13a7df; + width: 20px; + text-align: center; + display: inline-block; + } + + .popup-panel-title { + padding-left: 10px; + display: inline-block; + } + + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette-popup-panel/palette-popup-panel.component.ts b/catalog-ui/src/app/ng2/pages/composition/palette/palette-popup-panel/palette-popup-panel.component.ts new file mode 100644 index 0000000000..5d98fc7f78 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette-popup-panel/palette-popup-panel.component.ts @@ -0,0 +1,98 @@ +import {Component, OnInit} from '@angular/core'; +import {GRAPH_EVENTS, SdcElementType} from "app/utils"; +import {LeftPaletteComponent, Point} from "app/models"; +import {EventListenerService} from "app/services"; +import {LeftPaletteMetadataTypes} from "app/models/components/displayComponent"; + +@Component({ + selector: 'app-palette-popup-panel', + templateUrl: './palette-popup-panel.component.html', + styleUrls: [ './palette-popup-panel.component.less' ], +}) +export class PalettePopupPanelComponent implements OnInit { + + public panelTitle: string; + public isShowPanel: boolean; + private component: Component; + private displayComponent: LeftPaletteComponent; + private popupPanelPosition:Point = new Point(0,0); + + constructor(private eventListenerService: EventListenerService) { + this.isShowPanel = false; + } + + ngOnInit() { + this.registerObserverCallbacks(); + } + + public onMouseEnter() { + this.isShowPanel = true; + } + + public getMenuItems = () => { + return [{ + text: 'Delete', + iconName: 'trash-o', + iconType: 'common', + iconMode: 'secondary', + iconSize: 'small', + type: '', + action: () => this.addZoneInstance() + }]; + } + + public onMouseLeave() { + this.isShowPanel = false; + } + + public addZoneInstance(): void { + if(this.displayComponent) { + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ADD_ZONE_INSTANCE_FROM_PALETTE, this.component, this.displayComponent, this.popupPanelPosition); + this.hidePopupPanel(); + } + } + + private registerObserverCallbacks() { + + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_SHOW_POPUP_PANEL, + (displayComponent: LeftPaletteComponent, sectionElem: HTMLElement) => { + this.showPopupPanel(displayComponent, sectionElem); + }); + + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HIDE_POPUP_PANEL, () => this.hidePopupPanel()); + } + + private getPopupPanelPosition (sectionElem: HTMLElement):Point { + let pos: ClientRect = sectionElem.getBoundingClientRect(); + let offsetX: number = -30; + const offsetY: number = pos.height / 2; + return new Point((pos.right + offsetX), (pos.top - offsetY + window.pageYOffset)); + }; + + private setPopupPanelTitle(component: LeftPaletteComponent): void { + if (component.componentSubType === SdcElementType.GROUP) { + this.panelTitle = "Add Group"; + return; + } + + if (component.componentSubType === SdcElementType.POLICY) { + this.panelTitle = "Add Policy"; + return; + } + } + + private showPopupPanel(displayComponent:LeftPaletteComponent, sectionElem: HTMLElement) { + if(!this.isShowPanel){ + this.displayComponent = displayComponent; + this.setPopupPanelTitle(displayComponent); + this.popupPanelPosition = this.getPopupPanelPosition(sectionElem); + this.isShowPanel = true; + } + }; + + private hidePopupPanel() { + if(this.isShowPanel){ + this.isShowPanel = false; + } + }; +} diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.html b/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.html new file mode 100644 index 0000000000..7963dd18b7 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.html @@ -0,0 +1,41 @@ +<div class="composition-palette-component"> + <div class="palette-elements-count">Elements + <span class="palette-elements-count-value">{{numberOfElements}}</span> + </div> + + <sdc-filter-bar placeholder="Search..." (valueChange)="onSearchChanged($event)" testId="searchAsset"></sdc-filter-bar> + + <div class="palette-elements-list"> + <sdc-loader [global]="false" name="palette-loader" testId="palette-loader" [active]="this.isPaletteLoading" [class.inactive]="!this.isPaletteLoading"></sdc-loader> + <div *ngIf="numberOfElements === 0 && searchText" class="no-elements-found">No Elements Found</div> + <sdc-accordion *ngFor="let mapByCategory of paletteElements | keyValue; let first = first" [attr.data-tests-id]="'leftPalette.category.'+mapByCategory.key" [title]="mapByCategory.key" [css-class]="'palette-category'"> + <div *ngFor="let mapBySubCategory of mapByCategory.value | keyValue"> + <div class="palette-subcategory">{{mapBySubCategory.key}}</div> + <ng-container *ngIf="!(isViewOnly$ | async)"> + <div *ngFor="let paletteElement of mapBySubCategory.value" + [dndDraggable]="paletteElement" + [dndDisableIf]="paletteElement.componentSubType == 'GROUP' && paletteElement.componentSubType == 'POLICY'" + (dndStart)="onDragStart($event, paletteElement)" + (drag)="onDraggableMoved($event)" + [dndEffectAllowed]="'copyMove'" + (mouseenter)="onMouseOver($event, paletteElement)" + (mouseleave)="onMouseOut(paletteElement)" + [attr.data-tests-id]="paletteElement.name"> + <palette-element [paletteElement]="paletteElement"></palette-element> + </div> + </ng-container> + <ng-container *ngIf="(isViewOnly$ | async)"> + <div *ngFor="let paletteElement of mapBySubCategory.value" + [attr.data-tests-id]="paletteElement.name"> + <palette-element [paletteElement]="paletteElement"></palette-element> + </div> + </ng-container> + </div> + </sdc-accordion> + </div> +</div> + +<div id="draggable_element" dndDropzone (dndDrop)="onDrop($event)" [dndAllowExternal]="true"> + <sdc-element-icon *ngIf="paletteDraggedElement" [iconName]="paletteDraggedElement.icon" + [elementType]="paletteDraggedElement.componentSubType" [uncertified]="paletteDraggedElement.certifiedIconClass"></sdc-element-icon> +</div> diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.less b/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.less new file mode 100644 index 0000000000..37461ba1c5 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.less @@ -0,0 +1,84 @@ +@import "./../../../../../assets/styles/override"; + +:host(composition-palette) { + display:flex; + flex: 0 0 244px; +} + +sdc-loader.inactive { + display:none; +} + +:host ::ng-deep .sdc-filter-bar .sdc-input { + margin-bottom:0px; +} +:host ::ng-deep .sdc-loader-wrapper { + position:static; +} + +.composition-palette-component { + background-color: @sdcui_color_white; + overflow-y: auto; + overflow-x: hidden; + display: flex; + flex-direction: column; + position:relative; + width: 244px; + box-shadow: 7px -3px 6px -8px @sdcui_color_gray; + + .palette-elements-count { + background-color: @sdcui_color_gray; + line-height: 40px; + padding: 0 17px; + color: @sdcui_color_white; + .palette-elements-count-value { + float: right; + } + } + + .palette-elements-list { + + .no-elements-found { + padding-left: 40px; + } + /deep/ .palette-category { + display: flex; + margin: 0px; + .sdc-accordion-header { + background-color: @sdcui_color_silver; + margin: 0px; + line-height: 40px; + padding: 0px 10px; + } + .sdc-accordion-body { + padding: 0px; + } + } + .palette-subcategory { + padding: 0 10px; + background-color: @sdcui_color_lighter-silver; + line-height: 35px; + } + } +} + +#draggable_element { + display: inline-block; + border-radius: 50%; + background: transparent; + position: absolute; + top: -9999px; + left: 0; + z-index: 100; +} + +.invalid-drag { + border: 7px solid @red-shadow; +} + +.valid-drag { + border: 7px solid @green-shadow; +} + +@green-shadow: rgba(29, 154, 149, 0.3); +@red-shadow: rgba(218, 31, 61, 0.3); diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.spec.ts new file mode 100644 index 0000000000..efa9cd3370 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.spec.ts @@ -0,0 +1,102 @@ +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import {NO_ERRORS_SCHEMA} from "@angular/core"; +import {CompositionPaletteService} from "./services/palette.service"; +import {EventListenerService} from "../../../../services/event-listener-service"; +import {PaletteElementComponent} from "./palette-element/palette-element.component"; +import {PaletteComponent} from "./palette.component"; +import {ConfigureFn, configureTests} from "../../../../../jest/test-config.helper"; +import {GRAPH_EVENTS} from "../../../../utils/constants"; +import {KeyValuePipe} from "../../../pipes/key-value.pipe"; +import {ResourceNamePipe} from "../../../pipes/resource-name.pipe"; +import {LeftPaletteComponent} from "../../../../models/components/displayComponent"; +import {Observable} from "rxjs/Observable"; +import {leftPaletteElements} from "../../../../../jest/mocks/left-paeltte-elements.mock"; +import {NgxsModule, Select} from '@ngxs/store'; +import { WorkspaceState } from 'app/ng2/store/states/workspace.state'; + + +describe('palette component', () => { + + const mockedEvent = <MouseEvent>{ target: {} } + let fixture: ComponentFixture<PaletteComponent>; + let eventServiceMock: Partial<EventListenerService>; + let compositionPaletteMockService: Partial<CompositionPaletteService>; + + beforeEach( + async(() => { + eventServiceMock = { + notifyObservers: jest.fn() + } + compositionPaletteMockService = { + subscribeToLeftPaletteElements: jest.fn().mockImplementation(()=> Observable.of(leftPaletteElements)), + getLeftPaletteElements: jest.fn().mockImplementation(()=> leftPaletteElements) + } + const configure: ConfigureFn = testBed => { + testBed.configureTestingModule({ + declarations: [PaletteComponent, PaletteElementComponent, KeyValuePipe, ResourceNamePipe], + imports: [NgxsModule.forRoot([WorkspaceState])], + schemas: [NO_ERRORS_SCHEMA], + providers: [ + {provide: CompositionPaletteService, useValue: compositionPaletteMockService}, + {provide: EventListenerService, useValue: eventServiceMock} + ], + }); + }; + + configureTests(configure).then(testBed => { + fixture = testBed.createComponent(PaletteComponent); + }); + }) + ); + + it('should match current snapshot of palette component', () => { + expect(fixture).toMatchSnapshot(); + }); + + it('should call on palette component hover in event', () => { + let paletteObject = <LeftPaletteComponent>{categoryType: 'COMPONENT'}; + fixture.componentInstance.onMouseOver(mockedEvent, paletteObject); + expect(eventServiceMock.notifyObservers).toHaveBeenCalledWith(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_IN, paletteObject); + }); + + it('should call on palette component hover out event', () => { + let paletteObject = <LeftPaletteComponent>{categoryType: 'COMPONENT'}; + fixture.componentInstance.onMouseOut(paletteObject); + expect(eventServiceMock.notifyObservers).toHaveBeenCalledWith(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_OUT); + }); + + it('should call show popup panel event', () => { + let paletteObject = <LeftPaletteComponent>{categoryType: 'GROUP'}; + fixture.componentInstance.onMouseOver(mockedEvent, paletteObject); + expect(eventServiceMock.notifyObservers).toHaveBeenCalledWith(GRAPH_EVENTS.ON_PALETTE_COMPONENT_SHOW_POPUP_PANEL, paletteObject, mockedEvent.target); + }); + + it('should call hide popup panel event', () => { + let paletteObject = <LeftPaletteComponent>{categoryType: 'GROUP'}; + fixture.componentInstance.onMouseOut(paletteObject); + expect(eventServiceMock.notifyObservers).toHaveBeenCalledWith(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HIDE_POPUP_PANEL); + }); + + it('should build Palette By Categories without searchText', () => { + fixture.componentInstance.buildPaletteByCategories(); + expect(fixture.componentInstance.paletteElements["Generic"]["Network"].length).toBe(5); + expect(fixture.componentInstance.paletteElements["Generic"]["Network"][0].searchFilterTerms).toBe("extvirtualmachineinterfacecp external port for virtual machine interface extvirtualmachineinterfacecp 3.0"); + expect(fixture.componentInstance.paletteElements["Generic"]["Network"][1].searchFilterTerms).toBe("newservice2 asdfasdfa newservice2 0.3"); + + expect(fixture.componentInstance.paletteElements["Generic"]["Configuration"].length).toBe(1); + expect(fixture.componentInstance.paletteElements["Generic"]["Configuration"][0].systemName).toBe("Extvirtualmachineinterfacecp"); + }); + + it('should build Palette By Categories with searchText', () => { + fixture.componentInstance.buildPaletteByCategories("testVal"); + expect(fixture.componentInstance.paletteElements["Generic"]["Network"].length).toBe(1); + expect(fixture.componentInstance.paletteElements["Generic"]["Network"][0].searchFilterTerms).toBe("testVal and other values"); + }); + + it('should change numbers of elements', () => { + fixture.componentInstance.buildPaletteByCategories(); + expect(fixture.componentInstance.numberOfElements).toEqual(6); + fixture.componentInstance.buildPaletteByCategories("testVal"); + expect(fixture.componentInstance.numberOfElements).toEqual(1); + }); +});
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.ts b/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.ts new file mode 100644 index 0000000000..02d270b39a --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette.component.ts @@ -0,0 +1,172 @@ +/** + * Created by ob0695 on 6/28/2018. + */ +/*- + * ============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 { Component, HostListener } from '@angular/core'; +import { Select } from '@ngxs/store'; +import { LeftPaletteComponent, LeftPaletteMetadataTypes } from 'app/models/components/displayComponent'; +import { Point } from 'app/models/graph/point'; +import { WorkspaceState } from 'app/ng2/store/states/workspace.state'; +import Dictionary = _.Dictionary; +import { EventListenerService } from 'app/services/event-listener-service'; +import { GRAPH_EVENTS } from 'app/utils/constants'; +import { DndDropEvent } from 'ngx-drag-drop/ngx-drag-drop'; +import { CompositionPaletteService } from './services/palette.service'; +import {PolicyMetadata} from "../../../../models/policy-metadata"; +import {GenericBrowserDomAdapter} from "@angular/platform-browser/src/browser/generic_browser_adapter"; + +@Component({ + selector: 'composition-palette', + templateUrl: './palette.component.html', + styleUrls: ['./palette.component.less'] +}) +export class PaletteComponent { + + constructor(private compositionPaletteService: CompositionPaletteService, private eventListenerService: EventListenerService) {} + + @Select(WorkspaceState.isViewOnly) isViewOnly$: boolean; + private paletteElements: Dictionary<Dictionary<LeftPaletteComponent[]>>; + public numberOfElements: number = 0; + public isPaletteLoading: boolean; + private paletteDraggedElement: LeftPaletteComponent; + public position: Point = new Point(); + + ngOnInit() { + this.isPaletteLoading = true; + + this.compositionPaletteService.subscribeToLeftPaletteElements((leftPaletteElementsResponse) => { + this.paletteElements = leftPaletteElementsResponse; + this.numberOfElements = this.countLeftPalleteElements(this.paletteElements); + this.isPaletteLoading = false; + }, () => { + this.isPaletteLoading = false; + }); + + } + + public buildPaletteByCategories = (searchText?: string) => { // create nested by category & subcategory, filtered by search parans + // Flat the object and run on its leaves + if (searchText) { + searchText = searchText.toLowerCase(); + const paletteElementsAfterSearch = {}; + this.paletteElements = this.compositionPaletteService.getLeftPaletteElements(); + for (const category in this.paletteElements) { + for (const subCategory in this.paletteElements[category]) { + const subCategoryToCheck = this.paletteElements[category][subCategory]; + const res = subCategoryToCheck.filter((item) => item.searchFilterTerms.toLowerCase().indexOf(searchText) >= 0) + if (res.length > 0) { + paletteElementsAfterSearch[category] = {}; + paletteElementsAfterSearch[category][subCategory] = res; + } + } + } + this.paletteElements = paletteElementsAfterSearch; + } else { + this.paletteElements = this.compositionPaletteService.getLeftPaletteElements(); + } + this.numberOfElements = this.countLeftPalleteElements(this.paletteElements); + } + + public onSearchChanged = (searchText: string) => { + + if (this.compositionPaletteService.getLeftPaletteElements()) { + this.buildPaletteByCategories(searchText); + } + } + + private countLeftPalleteElements(leftPalleteElements: Dictionary<Dictionary<LeftPaletteComponent[]>>) { + // Use _ & flat map + let counter = 0; + for (const category in leftPalleteElements) { + for (const subCategory in leftPalleteElements[category]) { + counter += leftPalleteElements[category][subCategory].length; + } + } + return counter; + } + + private isGroupOrPolicy(component: LeftPaletteComponent): boolean { + if (component && + (component.categoryType === LeftPaletteMetadataTypes.Group || + component.categoryType === LeftPaletteMetadataTypes.Policy)) { + return true; + } + return false; + } + @HostListener('document:dragover', ['$event']) + public onDrag(event) { + this.position.x = event.clientX; + this.position.y = event.clientY; + } + + //---------------------------------------Palette Events-----------------------------------------// + + public onDraggableMoved = (event:DragEvent) => { + let draggedElement = document.getElementById("draggable_element"); + draggedElement.style.top = (this.position.y - 80) + "px"; + draggedElement.style.left = (this.position.x - 30) + "px"; + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DRAG_ACTION, this.position); + } + + public onDragStart = (event, draggedElement:LeftPaletteComponent) => { // Applying the dragged svg component to the draggable element + + this.paletteDraggedElement = draggedElement; + event.dataTransfer.dropEffect = "copy"; + let hiddenImg = document.createElement("span"); + event.dataTransfer.setDragImage(hiddenImg, 0, 0); + } + + + public onDrop = (event:DndDropEvent) => { + let draggedElement = document.getElementById("draggable_element"); + draggedElement.style.top = "-9999px"; + if(draggedElement.classList.contains('valid-drag')) { + if(!event.data){ + event.data = this.paletteDraggedElement; + } + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DROP, event); + } else { + console.log("INVALID drop"); + } + this.paletteDraggedElement = undefined; + + } + + public onMouseOver = (sectionElem:MouseEvent, displayComponent:LeftPaletteComponent) => { + console.debug("On palette element MOUSE HOVER: ", displayComponent); + if (this.isGroupOrPolicy(displayComponent)) { + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_SHOW_POPUP_PANEL, displayComponent, sectionElem.target); + } else { + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_IN, displayComponent); + } + }; + + public onMouseOut = (displayComponent:LeftPaletteComponent) => { + console.debug("On palette element MOUSE OUT: ", displayComponent); + if (this.isGroupOrPolicy(displayComponent)) { + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HIDE_POPUP_PANEL); + } else { + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_OUT); + } + }; + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/palette.module.ts b/catalog-ui/src/app/ng2/pages/composition/palette/palette.module.ts new file mode 100644 index 0000000000..aeb4c4c60b --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/palette.module.ts @@ -0,0 +1,25 @@ +import { NgModule } from "@angular/core"; +import { CompositionPaletteService } from "./services/palette.service"; +import { PaletteComponent } from "./palette.component"; +import { SdcUiComponentsModule } from "onap-ui-angular"; +import { GlobalPipesModule } from "app/ng2/pipes/global-pipes.module"; +import { CommonModule } from "@angular/common"; +import { DndModule } from "ngx-drag-drop"; +import {PaletteElementComponent} from "./palette-element/palette-element.component"; +import {EventListenerService} from "app/services/event-listener-service"; +import {UiElementsModule} from "app/ng2/components/ui/ui-elements.module"; + +@NgModule({ + declarations: [PaletteComponent, PaletteElementComponent], + imports: [CommonModule, SdcUiComponentsModule, GlobalPipesModule, UiElementsModule, DndModule], + exports: [PaletteComponent], + entryComponents: [PaletteComponent], + providers: [CompositionPaletteService, EventListenerService] +}) +export class PaletteModule { + + constructor() { + + } + +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.spec.ts b/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.spec.ts new file mode 100644 index 0000000000..3a660c1de7 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.spec.ts @@ -0,0 +1,41 @@ +import {TestBed} from "@angular/core/testing"; +import {CompositionPaletteService} from "./palette.service"; +import {ISdcConfig, SdcConfigToken} from "../../../../config/sdc-config.config"; +import {WorkspaceService} from "../../../../pages/workspace/workspace.service"; +import { HttpClient } from "@angular/common/http"; +describe('palette component', () => { + + let service: CompositionPaletteService; + + let httpServiceMock: Partial<HttpClient> = { + get: jest.fn() + } + + let sdcConfigToken: Partial<ISdcConfig> = { + "api": { + "root": '' + } + } + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [], + providers: [CompositionPaletteService, + {provide: HttpClient, useValue: httpServiceMock}, + {provide: SdcConfigToken, useValue: sdcConfigToken}, + {provide: WorkspaceService, useValue{}} + ] + }); + + service = TestBed.get(CompositionPaletteService); + }); + + it('should create an instance', () => { + expect(service).toBeDefined(); + }); + + // it('should create an instance2', async () => { + // expect(await service.subscribeToLeftPaletteElements("resources")).toEqual([]); + // }); +}); + diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.ts b/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.ts new file mode 100644 index 0000000000..7587c5206f --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.ts @@ -0,0 +1,98 @@ +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Inject, Injectable } from '@angular/core'; +import { LeftPaletteComponent, LeftPaletteMetadataTypes } from 'app/models/components/displayComponent'; +import { GroupMetadata } from 'app/models/group-metadata'; +import { PolicyMetadata } from 'app/models/policy-metadata'; +import { SdcConfigToken } from 'app/ng2/config/sdc-config.config'; +import { ISdcConfig } from 'app/ng2/config/sdc-config.config.factory'; +import { WorkspaceService } from 'app/ng2/pages/workspace/workspace.service'; +import 'rxjs/add/observable/forkJoin'; +import { Observable } from 'rxjs/Rx'; +import Dictionary = _.Dictionary; + + + +@Injectable() +export class CompositionPaletteService { + + protected baseUrl = ''; + + private leftPaletteComponents: Dictionary<Dictionary<LeftPaletteComponent[]>>; + private facadeUrl: string; + constructor(protected http: HttpClient, @Inject(SdcConfigToken) sdcConfig: ISdcConfig, private workspaceService: WorkspaceService) { + this.baseUrl = sdcConfig.api.root + sdcConfig.api.component_api_root; + this.facadeUrl = sdcConfig.api.uicache_root + sdcConfig.api.GET_uicache_left_palette; + + } + + public subscribeToLeftPaletteElements(next, error) { + + let params = new HttpParams(); + params = params.append('internalComponentType', this.workspaceService.getMetadataType()); + + const loadInstances = this.http.get(this.facadeUrl, {params}); + const loadGroups = this.http.get(this.baseUrl + 'groupTypes', {params}); + const loadPolicies = this.http.get(this.baseUrl + 'policyTypes', {params}); + + Observable.forkJoin( + loadInstances, loadGroups, loadPolicies + ).subscribe( ([resInstances, resGrouops, resPolicies]) => { + const combinedDictionary = this.combineResoponses(resInstances, resGrouops, resPolicies); + this.leftPaletteComponents = combinedDictionary; + next(this.leftPaletteComponents); + }); + } + + public getLeftPaletteElements = (): Dictionary<Dictionary<LeftPaletteComponent[]>> => { + return this.leftPaletteComponents; + } + + + public convertPoliciesOrGroups = (paletteListResult, type: string ) => { + const components: LeftPaletteComponent[] = []; + + if (type === 'Policies') { + _.forEach(paletteListResult, (policyMetadata: PolicyMetadata) => { + components.push(new LeftPaletteComponent(LeftPaletteMetadataTypes.Policy, policyMetadata)); + }); + return { + Policies: components + }; + } + + if (type === 'Groups') { + _.forEach(paletteListResult, (groupMetadata: GroupMetadata) => { + const item = new LeftPaletteComponent(LeftPaletteMetadataTypes.Group, groupMetadata); + components.push(item); + }); + return { + Groups: components + }; + } + + return {}; + } + + private combineResoponses(resInstances: object, resGrouops: object, resPolicies: object) { + const retValObject = {}; + // Generic will be the 1st category in the left Pallete + if (resInstances['Generic']) { + retValObject['Generic'] = resInstances['Generic']; + } + // Add all other categories + for (const category in resInstances) { + if (category === 'Generic') { + continue; + } + retValObject[category] = resInstances[category]; + } + + // Add Groups + retValObject["Groups"] = this.convertPoliciesOrGroups(resGrouops, 'Groups'); + + // Add policies + retValObject["Policies"] = this.convertPoliciesOrGroups(resPolicies, 'Policies'); + + return retValObject; + } +} |