summaryrefslogtreecommitdiffstats
path: root/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts
diff options
context:
space:
mode:
Diffstat (limited to 'cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts')
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts359
1 files changed, 155 insertions, 204 deletions
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts
index 130e0ae19..56b5dcbbc 100644
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts
@@ -1,11 +1,39 @@
-import { Component, OnInit, ViewEncapsulation } from '@angular/core';
+/*
+============LICENSE_START==========================================
+===================================================================
+Copyright (C) 2019 Orange. All rights reserved.
+===================================================================
+
+Unless otherwise specified, all software contained herein is licensed
+under the Apache License, Version 2.0 (the License);
+you may not use this software 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 dagre from 'dagre';
+import graphlib from 'graphlib';
+import { Component, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core';
import * as joint from 'jointjs';
import './jointjs/elements/palette.function.element';
import './jointjs/elements/action.element';
import './jointjs/elements/board.function.element';
import { DesignerStore } from './designer.store';
import { ActionElementTypeName } from 'src/app/common/constants/app-constants';
-
+import { GraphUtil } from './graph.util';
+import { GraphGenerator } from './graph.generator.util';
+import { FunctionsStore } from './functions.store';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { distinctUntilChanged } from 'rxjs/operators';
@Component({
@@ -14,23 +42,25 @@ import { ActionElementTypeName } from 'src/app/common/constants/app-constants';
styleUrls: ['./designer.component.css'],
encapsulation: ViewEncapsulation.None
})
-export class DesignerComponent implements OnInit {
+export class DesignerComponent implements OnInit, OnDestroy {
private controllerSideBar: boolean;
private attributesSideBar: boolean;
- //to generate Ids for dragged function elements
- private fuctionIdCounter=0;
- private actionIdCounter=0;
boardGraph: joint.dia.Graph;
boardPaper: joint.dia.Paper;
paletteGraph: joint.dia.Graph;
palettePaper: joint.dia.Paper;
+ private ngUnsubscribe = new Subject();
- constructor(private designerStore: DesignerStore) {
+ constructor(private designerStore: DesignerStore,
+ private functionStore: FunctionsStore,
+ private graphUtil: GraphUtil,
+ private graphGenerator: GraphGenerator) {
this.controllerSideBar = true;
this.attributesSideBar = false;
+
}
private _toggleSidebar1() {
this.controllerSideBar = !this.controllerSideBar;
@@ -55,38 +85,65 @@ export class DesignerComponent implements OnInit {
ngOnInit() {
this.initializeBoard();
this.initializePalette();
- // this.createEditBarOverThePaper();
-
- //functions list is contants for now
- const list = [
- { modelName: 'component-netconf-executor'},
- { modelName: 'component-remote-ansible-executor' },
- { modelName: 'dg-generic' },
- { modelName: 'component-resource-resolution' }];
- const cells = this.buildPaletteGraphFromList(list);
- this.paletteGraph.resetCells(cells);
-
- let idx = 0;
- cells.forEach(cell => {
- console.log(cell);
- cell.translate(5, (cell.attributes.size.height + 5) * idx++);
+ this.stencilPaperEventListeners();
+
+ /**
+ * the code to retrieve from server is commented
+ */
+ this.functionStore.state$
+ .pipe(x => { console.log('value on way to distinct', x); return x; })
+ .pipe(
+ distinctUntilChanged((a: any, b: any) => JSON.stringify(a) === JSON.stringify(b)),
+ takeUntil(this.ngUnsubscribe))
+ .subscribe(state => {
+
+ if (state.serverFunctions) {
+ console.log('inside subscriotn on functions store -->', state.serverFunctions);
+ console.log(state);
+ // this.viewedFunctions = state.functions;
+ const list = state.serverFunctions;
+
+ const cells = this.graphUtil.buildPaletteGraphFromList(list);
+ this.paletteGraph.resetCells(cells);
+
+ let idx = 0;
+ cells.forEach(cell => {
+ cell.translate(5, (cell.attributes.size.height + 5) * idx++);
+ });
+ }
+ });
+ this.designerStore.state$
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(state => {
+ if (state.sourceContent) {
+ console.log('inside desinger.component---> ', state);
+ // generate graph from store objects if exist
+ const topologtTemplate = JSON.parse(state.sourceContent);
+ console.log(topologtTemplate);
+ delete state.sourceContent;
+ this.graphGenerator.populate(topologtTemplate, this.boardGraph);
+ /**
+ * auto arrange elements in graph
+ * https://resources.jointjs.com/docs/jointjs/v3.1/joint.html#layout.DirectedGraph
+ */
+ joint.layout.DirectedGraph.layout( this.boardGraph.getCells(), {
+ dagre,
+ graphlib,
+ // nodeSep: 50,
+ // setLinkVertices: false,
+ // rankDir: 'LR',
+ marginX: 100,
+ marginY: 100,
+ clusterPadding: { top: 100, left: 10, right: 10, bottom: 100 },
+ rankDir: 'TB'
+ });
+ }
});
- this.stencilPaperEventListeners();
- /**
- * the code to retrieve from server is commented
- */
- // this.designerStore.state$.subscribe(state => {
- // console.log(state);
- // if (state.functions) {
- // console.log('functions-->' , state.functions);
- // // this.viewedFunctions = state.functions;
- // const list = state.functions;
- // }
- // });
- //action triggering
- // this.designerStore.getFuntions();
-
+
+ // action triggering
+ this.functionStore.retrieveFuntions();
+
}
initializePalette() {
@@ -95,27 +152,31 @@ export class DesignerComponent implements OnInit {
this.palettePaper = new joint.dia.Paper({
el: $('#palette-paper'),
model: this.paletteGraph,
- height: 300,
width: 300,
- gridSize: 1,
+ height: $('#palette-paper').height(),
+ // background: {
+ // color: 'rgba(0, 255, 0, 0.3)'
+ // },
interactive: false
+ // elements in paletter need to be fixed, please refer to flying paper concept
});
}
}
initializeBoard() {
if (!this.boardGraph) {
+ console.log('initializeBoard...');
this.boardGraph = new joint.dia.Graph();
this.boardPaper = new joint.dia.Paper({
el: $('#board-paper'),
model: this.boardGraph,
height: 720,
- width: 1200,
+ width: 1100,
gridSize: 10,
drawGrid: true,
- // background: {
- // color: 'rgba(0, 255, 0, 0.3)'
- // },
+ background: {
+ color: 'rgba(0, 255, 0, 0.3)'
+ },
cellViewNamespace: joint.shapes
});
@@ -137,19 +198,20 @@ export class DesignerComponent implements OnInit {
this.boardGraph.on('change:position', (cell) => {
- var parentId = cell.get('parent');
- if (!parentId) return;
+ const parentId = cell.get('parent');
+ if (!parentId) {
+ return;
+ }
+
+ const parent = this.boardGraph.getCell(parentId);
- var parent = this.boardGraph.getCell(parentId);
-
- var parentBbox = parent.getBBox();
- var cellBbox = cell.getBBox();
+ const parentBbox = parent.getBBox();
+ const cellBbox = cell.getBBox();
if (parentBbox.containsPoint(cellBbox.origin()) &&
parentBbox.containsPoint(cellBbox.topRight()) &&
parentBbox.containsPoint(cellBbox.corner()) &&
parentBbox.containsPoint(cellBbox.bottomLeft())) {
-
// All the four corners of the child are inside
// the parent area.
return;
@@ -159,55 +221,16 @@ export class DesignerComponent implements OnInit {
cell.set('position', cell.previous('position'));
});
}
+ console.log('done initializing Board...');
}
insertCustomActionIntoBoard() {
- this.actionIdCounter++;
- const actionId = "action_" + this.actionIdCounter;
- const actionName = 'Action' + this.actionIdCounter;
- const element = this.createCustomAction(actionId , actionName);
- this.boardGraph.addCell(element);
console.log('saving action to store action workflow....');
+ const actionName = this.graphUtil.generateNewActionName();
+ this.graphUtil.createCustomActionWithName(actionName, this.boardGraph);
this.designerStore.addDeclarativeWorkFlow(actionName);
}
- createCustomAction(id: string, label: string) {
- const element = new joint.shapes.app.ActionElement({
- id: id
- });
- element.attr('#label/text', label);
- return element;
- }
-
- buildPaletteGraphFromList(list: any) {
- const elements = [];
-
- console.log(list);
- list.forEach(element => {
- elements.push(this.createFuctionElementForPalette(element.modelName));
- });
-
- return elements;
- }
-
- createFuctionElementForPalette(label: string) {
- const element = new joint.shapes.palette.FunctionElement({
- id: label
- });
- element.attr('#label/text', label);
- element.attr('type', label);
- return element;
- }
-
- createFuctionElementForBoard(id :String, label :string, type :string) {
- const boardElement = new joint.shapes.board.FunctionElement({
- id: id
- });
- boardElement.attr('#label/text', label);
- boardElement.attr('#type/text', type);
- return boardElement;
- }
-
stencilPaperEventListeners() {
this.palettePaper.on('cell:pointerdown', (draggedCell, pointerDownEvent, x, y) => {
@@ -249,28 +272,49 @@ export class DesignerComponent implements OnInit {
if (mouseupX > target.left &&
mouseupX < target.left + this.boardPaper.$el.width() &&
mouseupY > target.top && y < target.top + this.boardPaper.$el.height()) {
- const functionType = flyShape.attributes.attrs.type;
- console.log(functionType);
- const functionElementForBoard = this.dropFunctionOverAction(functionType, mouseupX, target, offset, mouseupY);
-
- let parentCell = this.getParent(functionElementForBoard);
-
- console.log("parentCell -->", parentCell);
+ const functionType = this.graphUtil.getFunctionTypeFromPaletteFunction(flyShape);
+ // step name is CDS realted terminology, please refer to tosca types
+ const stepName = functionType;
+ const functionElementForBoard = this.graphUtil.dropFunctionOverActionWithPosition(
+ stepName, functionType,
+ mouseupX, mouseupY,
+ target, offset,
+ this.boardGraph);
+
+ const parentCell = this.graphUtil.getParent(functionElementForBoard, this.boardPaper);
+
+ if (parentCell &&
+ parentCell.model.attributes.type === ActionElementTypeName &&
+ this.graphUtil.canEmpedMoreChildern(parentCell.model, this.boardGraph)) {
+
+ if (this.graphUtil.isEmptyParent(parentCell.model)) {
+ // first function in action
+ const actionName = parentCell.model.attributes.attrs['#label'].text;
+ this.designerStore.addStepToDeclarativeWorkFlow(actionName, stepName, functionType);
+ if (functionType === 'dg-generic') {
+ this.designerStore.addDgGenericNodeTemplate(stepName);
+ } else {
+ this.designerStore.addNodeTemplate(stepName, functionType);
+ }
+ } else {
+ // second action means there was a dg-generic node before
+ this.designerStore.addNodeTemplate(stepName, functionType);
+ // this will fail if multiple dg-generic were added
+ // TODO prevent multi functions of the same type inside the same action
+ const dgGenericNode = this.graphUtil.getDgGenericChild(parentCell.model, this.boardGraph)[0];
+ const dgGenericNodeName = this.graphUtil.getFunctionNameFromBoardFunction(dgGenericNode);
+ this.designerStore.addDgGenericDependency(dgGenericNodeName, stepName);
+ }
- if (parentCell &&
- parentCell.model.attributes.type === ActionElementTypeName){
-
- const actionName = parentCell.model.attributes.attrs['#label'].text;
- this.designerStore.addStepToDeclarativeWorkFlow(actionName, functionType);
- this.designerStore.addNodeTemplate(functionType);
// Prevent recursive embedding.
if (parentCell &&
parentCell.model.get('parent') !== functionElementForBoard.id) {
parentCell.model.embed(functionElementForBoard);
}
- }else{
- console.log('function dropped outside action, rolling back...');
+ } else {
+ console.log('function dropped outside action or not allowed, rolling back...');
+ alert('function dropped outside action or not allowed, rolling back...');
functionElementForBoard.remove();
}
}
@@ -279,104 +323,11 @@ export class DesignerComponent implements OnInit {
$('#flyPaper').remove();
});
});
+ console.log('done stencilPaperEventListeners()...');
}
- private getParent(functionElementForBoard: joint.shapes.board.FunctionElement) {
- const cellViewsBelow = this.boardPaper.findViewsFromPoint(functionElementForBoard.getBBox().center());
- let cellViewBelow;
- if (cellViewsBelow.length) {
- cellViewsBelow.forEach(cellItem => {
- if (cellItem.model.id !== functionElementForBoard.id) {
- cellViewBelow = cellItem;
- }
- });
- }
- return cellViewBelow;
- }
-
- /**
- * trigger actions related to Function dropped over the board:
- * - create board function element of the same type of palette function
- * as board function element is different from the palette function element
- * - save function to parent action in store
- */
- private dropFunctionOverAction(functionType: any, mouseupX: number, target: JQuery.Coordinates, offset: { x: number; y: number; }, mouseupY: number) {
- this.fuctionIdCounter++;
- const functionElementForBoard = this.createFuctionElementForBoard("fucntion_" + this.fuctionIdCounter, 'execute', functionType);
- functionElementForBoard.position(mouseupX - target.left - offset.x, mouseupY - target.top - offset.y);
- this.boardGraph.addCell(functionElementForBoard);
- return functionElementForBoard;
+ ngOnDestroy() {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
}
- /**
- * this is a way to add the button like zoom in , zoom out , and source over jointjs paper
- * may be used if no other way is found
- */
- // createEditBarOverThePaper() {
- // joint.shapes["html"] = {};
- // joint.shapes["html"].Element = joint.shapes.basic.Rect.extend({
- // defaults: joint.util.deepSupplement({
- // type: 'html.Element'
- // }, joint.shapes.basic.Rect.prototype.defaults)
- // });
- // joint.shapes["html"].ElementView = joint.dia.ElementView.extend({
-
- // template: [
- // '<div>',
- // '<div id="editbar" class="editBar text-center">',
- // '<div class="btn-group mr-2" role="group" aria-label="First group">',
- // '<button type="button" class="btn btn-secondary tooltip-bottom" data-tooltip="Undo">',
- // '<img src="/assets/img/icon-undoActive.svg">',
- // '</button>',
- // '<button type="button" class="btn btn-secondary tooltip-bottom" data-tooltip="Redo">',
- // '<img src="/assets/img/icon-redo.svg">',
- // '</button>',
- // '</div>',
- // '<div class="btn-group mr-2" role="group" aria-label="Second group">',
- // '<button type="button" class="btn btn-secondary tooltip-bottom" data-tooltip="Zoom Out">',
- // '<img src="/assets/img/icon-zoomOut.svg">',
- // '</button>',
- // '<button type="button" class="btn btn-secondary pl-0 pr-0">100%</button>',
- // '<button type="button" class="btn btn-secondary tooltip-bottom" data-tooltip="Zoom In">',
- // '<img src="/assets/img/icon-zoomIn.svg">',
- // '</button>',
- // '</div>',
- // '<div class="btn-group viewBtns" role="group" aria-label="Third group">',
- // '<button type="button" class="btn btn-secondary topologySource active">View</button>',
- // '<button type="button" class="btn btn-secondary topologyView">Source</button>',
- // '</div>',
- // '</div>',
- // '</div>'
- // ].join(''),
- // initialize: function () {
- // _.bindAll(this, 'updateBox');
- // joint.dia.ElementView.prototype.initialize.apply(this, arguments);
-
- // this.$box = $(_.template(this.template)());
- // // Prevent paper from handling pointerdown.
- // this.$box.find('input,select').on('mousedown click', function (evt) {
- // evt.stopPropagation();
- // });
- // this.model.on('change', this.updateBox, this);
- // this.updateBox();
- // },
- // render: function () {
- // joint.dia.ElementView.prototype.render.apply(this, arguments);
- // this.paper.$el.prepend(this.$box);
- // this.updateBox();
- // return this;
- // },
- // updateBox: function () {
- // // Set the position and dimension of the box so that it covers the JointJS element.
- // var bbox = this.model.getBBox();
- // this.$box.css({
- // width: bbox.width,
- // height: bbox.height,
- // left: bbox.x,
- // top: bbox.y,
- // transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)'
- // });
- // }
- // });
-
- // }
}