summaryrefslogtreecommitdiffstats
path: root/cds-ui/designer-client
diff options
context:
space:
mode:
authorAhmed Abbas <ahmad.helmy@orange.com>2020-02-28 18:18:36 +0200
committerKAPIL SINGAL <ks220y@att.com>2020-02-28 18:20:27 +0000
commit886d352ec99fe5281c281c16f8d4b9908fb0dcc3 (patch)
treeec279d227f4e58f6cfe60c6a2aa3f5b0d9c7df78 /cds-ui/designer-client
parentdc3e41335d7ceb42901b8fd4ccace72825552302 (diff)
add designer funcionality - declarative workflow
- save source editor to store - generate graph based on json data from source editor - make functions retrieved from server - prevent multible functions inside action if the first fn is not dg-generic - dg generic case (mutli functions inside single action) - arrange elements that are generated automcatilly using DirectedGraph lib dagree Issue-ID: CCSDK-1779 Issue-ID: CCSDK-1783 Issue-ID: CCSDK-2017 Signed-off-by: Ahmed Abbas <ahmad.helmy@orange.com> Change-Id: Ief3579e4a9716475c9aaf85b5a349bc2af466cdb
Diffstat (limited to 'cds-ui/designer-client')
-rw-r--r--cds-ui/designer-client/package.json2
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.css37
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.html34
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts359
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.store.ts102
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions.store.ts48
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.css0
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.html21
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.spec.ts25
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.ts28
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.generator.util.ts79
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.util.ts214
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.dashboard.state.ts3
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.topologyTemplate.model.ts8
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/desinger.nodeTemplate.model.ts5
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/functions.state.ts31
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.css580
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.html80
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.ts45
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.module.ts4
-rw-r--r--cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.routing.module.ts2
-rw-r--r--cds-ui/designer-client/tslint.json7
22 files changed, 1367 insertions, 347 deletions
diff --git a/cds-ui/designer-client/package.json b/cds-ui/designer-client/package.json
index 5149300d1..89e107fec 100644
--- a/cds-ui/designer-client/package.json
+++ b/cds-ui/designer-client/package.json
@@ -29,10 +29,12 @@
"angular-material-expansion-panel": "^0.7.2",
"backbone": "^1.4.0",
"bootstrap": "^4.3.1",
+ "dagre": "^0.8.5",
"datatables.net": "^1.10.20",
"datatables.net-dt": "^1.10.20",
"file-saver": "^2.0.2",
"font-awesome": "^4.7.0",
+ "graphlib": "^2.1.8",
"jointjs": "^3.0.4",
"jquery": "^3.4.1",
"json2typescript": "^1.2.3",
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.css
index 799407093..37a6f9235 100644
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.css
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.css
@@ -268,7 +268,7 @@ p.compType-4{
color: #fff;
}
.actionBtns .btn:last-child{
- padding-left: 34px;
+ padding-left: 34px !important;
background: url(src/assets/img/icon-import-blue.svg) 12px center #fff no-repeat;
border: solid 1px #D0DFF1;
color: #1B3E6F;
@@ -279,6 +279,8 @@ p.compType-4{
}
.componentsList{
padding-bottom: 0;
+ height: calc( 100vh - 218px)!important;
+ overflow: scroll;
}
.custom-control.custom-checkbox:hover,
.custom-control-label:hover{
@@ -342,11 +344,11 @@ p.compType-4{
/*CANVAS*/
.editBar{
- width: 350px;
+ width: 200px;
margin: 0 auto 0;
padding: 6px 10px;
background:#F4F9FE;
- border: solid 1px #E8EFF8;
+ /* border: solid 1px #E8EFF8; */
box-shadow: 0 2px 6px rgba(47, 83, 151, .1);
}
.editBar .btn-group{
@@ -366,7 +368,7 @@ p.compType-4{
}
.viewBtns .btn{
background-position: 10px center;
- padding-left: 30px;
+ padding-left: 30px!important;
}
.viewBtns .topologySource{
background-image: url(src/assets/img/icon-topologyView-active.svg);
@@ -548,3 +550,30 @@ p.compType-4{
font-size: 10px;
}
+.source-button{
+ position: absolute;
+ z-index: 9999999;
+ top: 69px;
+ left: 50%;
+}
+/*jointjs paper*/
+/* #board-paper {
+ position: relative;
+ border: 1px solid gray;
+ display: inline-block;
+ background: transparent;
+ overflow: hidden;
+}
+#board-paper svg {
+ background: transparent;
+}
+#board-paper svg .link {
+ z-index: 2;
+}
+.html-element {
+ position: absolute;
+ background: #F4F9FE;
+ pointer-events: none;
+ -webkit-user-select: none;
+ z-index: 2;
+} */
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.html
index 311ce7ad9..1a2219bab 100644
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.html
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.html
@@ -55,18 +55,19 @@
</div>
</div>
</header>
+<div class="source-button editBar">
+ <div class="btn-group viewBtns" role="group">
+ <button type="button" class="btn btn-secondary topologySource active">Designer</button>
+ <button [routerLink]="['/designer/source']" type="button" class="btn btn-secondary topologyView">Scripting</button>
+ </div>
+</div>
<ng-sidebar-container class="sidebar-container">
<!-- Controller SideBar -->
<ng-sidebar [(opened)]="controllerSideBar" [sidebarClass]="'demo-sidebar controllerSidebar container-fluid'"
[mode]="'push'"
#sidebarLeft>
<div class="row">
- <!-- <div class="col-12 p-0">
- <form>
- <input type="text" class="form-control input-search-controller"
- placeholder="Search actions and functions">
- </form>
- </div> -->
+
<h1 class="col-12">Actions</h1>
<div class="col-12 text-center p-0">
<div class="btn-group actionBtns" role="group">
@@ -109,29 +110,13 @@
</div> -->
<h1 class="col-12">Functions</h1>
+ <b>Drag and drop function to Action’s box</b>
<div id="palette-paper" class="col-12 componentsList">
- <b>Drag and drop function to Action’s box</b>
- <ul class="list-group actions-scroll">
- <!-- <li class="list-group-item" *ngFor="let function of viewedFunctions">
- <p class="compType-1">{{function.modelName}}</p>
- </li> -->
- <li class="list-group-item">
- <p class="compType-2">component-netconf-executor</p>
- </li>
- <li class="list-group-item">
- <p class="compType-3">component-remote-ansible-executor</p>
- </li>
- <li class="list-group-item">
- <p class="compType-4">dg-generic</p>
- </li>
- <li class="list-group-item">
- <p class="compType-1">component-resource-resolution</p>
- </li>
- </ul>
</div>
</div>
</ng-sidebar>
<!-- Page content -->
+
<div ng-sidebar-content id="board-paper">
<button class="rotate" (click)="_toggleSidebar1()">
<span>
@@ -139,6 +124,7 @@
<i class="fa fa-angle-double-left"></i>
</span>
</button>
+
<!-- Canvas -->
<div class="editBar text-center">
<div class="btn-group mr-2" role="group" aria-label="First group">
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)'
- // });
- // }
- // });
-
- // }
}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.store.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.store.ts
index f2972d03b..c37accdb4 100644
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.store.ts
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.store.ts
@@ -22,7 +22,6 @@ limitations under the License.
import {Injectable} from '@angular/core';
import {Store} from '../../../../common/core/stores/Store';
import {DesignerService} from './designer.service';
-import {ModelType} from './model/ModelType.model';
import {DesignerDashboardState} from './model/designer.dashboard.state';
import { DeclarativeWorkflow } from './model/designer.workflow';
import { NodeTemplate } from './model/desinger.nodeTemplate.model';
@@ -37,18 +36,6 @@ export class DesignerStore extends Store<DesignerDashboardState> {
super(new DesignerDashboardState());
}
- public retrieveFuntions() {
- const modelDefinitionType = 'node_type';
- this.designerService.getFunctions(modelDefinitionType).subscribe(
- (modelTypeList: ModelType[]) => {
- console.log(modelTypeList);
- this.setState({
- ...this.state,
- serverFunctions: modelTypeList,
- });
- });
- }
-
/**
* adds empty workflow with name only.
* called when blank action is added to the board
@@ -59,37 +46,98 @@ export class DesignerStore extends Store<DesignerDashboardState> {
...this.state,
template: {
...this.state.template,
- workflows:
- this.state.template.workflows.set(workflowName, new DeclarativeWorkflow())
+ workflows: {
+ ...this.state.template.workflows,
+ [workflowName]: new DeclarativeWorkflow()
+ }
}
});
}
- addStepToDeclarativeWorkFlow(workflowName: string, stepType: string) {
- const currentWorkflow: DeclarativeWorkflow = this.state.template.workflows.get(workflowName);
- currentWorkflow.steps = {
- target: stepType,
- description: ''
- };
- const allNewWorkflowsMap =
- this.state.template.workflows.set(workflowName, currentWorkflow);
+ addStepToDeclarativeWorkFlow(workflowName: string, stepName: string, stepType: string) {
this.setState({
...this.state,
template: {
...this.state.template,
- workflows: allNewWorkflowsMap
+ workflows: {
+ ...this.state.template.workflows,
+ [workflowName]: {
+ ...this.state.template.workflows[workflowName],
+ steps: {
+ [stepName]: {
+ target: stepType,
+ description: ''
+ }
+ }
+ }
+ }
}
});
}
+ saveSourceContent(code: string) {
+ const topologtTemplate = JSON.parse(code);
+ this.setState({
+ ...this.state,
+ sourceContent: code,
+ template: topologtTemplate
+ });
+ }
+
+
+ /**
+ * adding node tempates is a separate action of adding the steps to the workflow
+ * you can add node template and don't add workflow step when you add dependencies for the
+ * dg-generic function for example
+ */
+ addNodeTemplate(nodeTemplateName: string, type: string) {
+ this.setState({
+ ...this.state,
+ template: {
+ ...this.state.template,
+ node_templates: {
+ ...this.state.template.node_templates,
+ [nodeTemplateName]: new NodeTemplate(type)
+ }
+ }
+ });
+ }
+
+ addDgGenericNodeTemplate(nodeTemplateName: string) {
+ const node = new NodeTemplate('dg-generic');
+ node.properties = {
+ 'dependency-node-template': []
+ };
+ this.setState({
+ ...this.state,
+ template: {
+ ...this.state.template,
+ node_templates: {
+ ...this.state.template.node_templates,
+ [nodeTemplateName]: node
+ }
+ }
+ });
+ }
- addNodeTemplate(nodeTemplateName: string) {
+ addDgGenericDependency(dgGenericNodeName: string, dependency: string) {
+ const props = this.state.template.node_templates[dgGenericNodeName].properties;
this.setState({
...this.state,
template: {
...this.state.template,
- node_templates:
- this.state.template.node_templates.set(nodeTemplateName, new NodeTemplate())
+ node_templates: {
+ ...this.state.template.node_templates,
+ [dgGenericNodeName]: {
+ ...this.state.template.node_templates[dgGenericNodeName],
+ properties: {
+ 'dependency-node-template': [
+ ...props['dependency-node-template'],
+ dependency
+ ]
+ }
+ }
+ }
}
});
}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions.store.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions.store.ts
new file mode 100644
index 000000000..86814179d
--- /dev/null
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions.store.ts
@@ -0,0 +1,48 @@
+/*
+============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 {Injectable} from '@angular/core';
+import {Store} from '../../../../common/core/stores/Store';
+import {DesignerService} from './designer.service';
+import {ModelType} from './model/ModelType.model';
+import { FunctionsState } from './model/functions.state';
+
+
+@Injectable({
+ providedIn: 'root'
+})
+export class FunctionsStore extends Store<FunctionsState> {
+
+ constructor(private designerService: DesignerService) {
+ super(new FunctionsState());
+ }
+
+ public retrieveFuntions() {
+ const modelDefinitionType = 'node_type';
+ this.designerService.getFunctions(modelDefinitionType).subscribe(
+ (modelTypeList: ModelType[]) => {
+ this.setState({
+ ...this.state,
+ serverFunctions: modelTypeList,
+ });
+ });
+ }
+}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.css
deleted file mode 100644
index e69de29bb..000000000
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.css
+++ /dev/null
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.html
deleted file mode 100644
index b27f91f49..000000000
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<h1 class="col-12">Functions</h1>
-<div class="col-12 componentsList">
- <b>Drag and drop function to Action’s box</b>
- <ul class="list-group actions-scroll" >
- <li class="list-group-item" *ngFor="let function of viewedFunctions">
- <p class="compType-1">{{function.modelName}}</p>
- </li>
- <!--<li class="list-group-item">
- <p class="compType-2">component-netconf-executor</p>
- </li>
- <li class="list-group-item">
- <p class="compType-3">component-remote-ansible-executor</p>
- </li>
- <li class="list-group-item">
- <p class="compType-4">dg-generic</p>
- </li>
- <li class="list-group-item">
- <p class="compType-1">component-resource-resolution</p>
- </li>-->
- </ul>
-</div>
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.spec.ts
deleted file mode 100644
index eec909b01..000000000
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { FunctionsComponent } from './functions.component';
-
-describe('FunctionsComponent', () => {
- let component: FunctionsComponent;
- let fixture: ComponentFixture<FunctionsComponent>;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- declarations: [ FunctionsComponent ]
- })
- .compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(FunctionsComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.ts
deleted file mode 100644
index e1e980ed9..000000000
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import {Component, OnInit} from '@angular/core';
-import {DesignerStore} from '../designer.store';
-import {ModelType} from '../model/ModelType.model';
-
-
-@Component({
- selector: 'app-functions',
- templateUrl: './functions.component.html',
- styleUrls: ['./functions.component.css']
-})
-export class FunctionsComponent implements OnInit {
- viewedFunctions: ModelType[] = [];
-
- constructor(private designerStore: DesignerStore) {
-
- this.designerStore.state$.subscribe(state => {
- console.log(state);
- if (state.serverFunctions) {
- this.viewedFunctions = state.serverFunctions;
- }
- });
- }
-
- ngOnInit() {
- this.designerStore.retrieveFuntions();
- }
-
-}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.generator.util.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.generator.util.ts
new file mode 100644
index 000000000..17596bd33
--- /dev/null
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.generator.util.ts
@@ -0,0 +1,79 @@
+import { TopologyTemplate } from './model/designer.topologyTemplate.model';
+import { Injectable } from '@angular/core';
+import { GraphUtil } from './graph.util';
+
+/*
+============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============================================
+*/
+
+@Injectable({
+ providedIn: 'root'
+})
+export class GraphGenerator {
+
+ constructor(private graphUtil: GraphUtil) {
+ }
+
+ /**
+ * loops over workflows
+ * create action element
+ * from steps --> create function element
+ * add function element to action element
+ */
+ public populate(topologyTempalte: TopologyTemplate,
+ boardGraph: joint.dia.Graph) {
+
+ Object.keys(topologyTempalte.workflows).forEach(workFlowName => {
+ console.log('drawing workflow item --> ', workFlowName);
+
+ // create action element
+ const actionElement =
+ this.graphUtil.createCustomActionWithName(workFlowName, boardGraph);
+
+ // create board function elements
+ const workflow = topologyTempalte.workflows[workFlowName].steps;
+ const stepName = Object.keys(workflow)[0];
+ if (stepName) {
+ const functionType = workflow[stepName].target;
+ console.log('draw function with ', stepName, functionType);
+
+ const functionElementForBoard = this.graphUtil.dropFunctionOverActionRelativeToParent(
+ actionElement,
+ stepName , functionType, boardGraph);
+
+ // TODO handle dg-generic case (multi-step in the same action)
+ if (functionType === 'dg-generic') {
+ const props = topologyTempalte.node_templates[stepName].properties;
+ console.log('dg props', props);
+ props['dependency-node-template'].forEach(dependencyStepName => {
+ const dependencyType = topologyTempalte.node_templates[dependencyStepName].type;
+ console.log('dependencyType', dependencyType);
+ this.graphUtil.dropFunctionOverActionRelativeToParent(
+ actionElement,
+ dependencyStepName, dependencyType, boardGraph);
+
+ });
+ }
+ }
+ });
+
+ }
+
+}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.util.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.util.ts
new file mode 100644
index 000000000..9ba7271fb
--- /dev/null
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.util.ts
@@ -0,0 +1,214 @@
+/*
+============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 * as joint from 'jointjs';
+import { Injectable } from '@angular/core';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class GraphUtil {
+
+ actionIdCounter = 0;
+ // to generate Ids for dragged function elements
+ private fuctionIdCounter = 0;
+
+ createCustomAction(boardGraph: joint.dia.Graph) {
+ const actionName = this.generateNewActionName();
+ const actionId = this.generateNewActionId();
+ const element = new joint.shapes.app.ActionElement({
+ id: actionId
+ });
+ element.attr('#label/text', actionName);
+ boardGraph.addCell(element);
+ return element;
+ }
+
+ generateNewActionName() {
+ this.actionIdCounter++;
+ const actionName = 'Action' + this.actionIdCounter;
+ return actionName;
+ }
+
+ private generateNewActionId() {
+ const actionName =
+ (Date.now().toString(36) + Math.random().toString(36).substr(2, 5))
+ .toUpperCase();
+ return actionName;
+ }
+
+ createCustomActionWithName(actionName: string, boardGraph: joint.dia.Graph) {
+ const actionId = this.generateNewActionId();
+ const element = new joint.shapes.app.ActionElement({
+ id: actionId
+ });
+ element.attr('#label/text', actionName);
+ boardGraph.addCell(element);
+ return element;
+ }
+
+ buildPaletteGraphFromList(list: any) {
+ const elements = [];
+ 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( label: string, type: string) {
+ this.fuctionIdCounter++;
+ const id = 'fucntion_' + this.fuctionIdCounter;
+ const boardElement = new joint.shapes.board.FunctionElement({
+ id
+ });
+ boardElement.attr('#label/text', label);
+ boardElement.attr('#type/text', type);
+ return boardElement;
+ }
+
+ getParent(functionElementForBoard: joint.shapes.board.FunctionElement, boardPaper: joint.dia.Paper) {
+ const cellViewsBelow = 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
+ */
+ dropFunctionOverActionWithPosition(
+ label: string, type: string,
+ mouseupX: number, mouseupY: number,
+ target: JQuery.Coordinates, offset: { x: number; y: number; },
+ boardGraph: joint.dia.Graph) {
+
+ const functionElementForBoard = this.dropFunctionOverAction(label, type, boardGraph);
+ functionElementForBoard.position(mouseupX - target.left - offset.x, mouseupY - target.top - offset.y);
+
+ return functionElementForBoard;
+ }
+
+
+ dropFunctionOverActionRelativeToParent(
+ parent: joint.shapes.app.ActionElement,
+ label: string, type: string,
+ boardGraph: joint.dia.Graph) {
+
+ const functionElementForBoard = this.dropFunctionOverAction(label, type, boardGraph);
+ parent.embed(functionElementForBoard);
+ functionElementForBoard.position({ parentRelative: true });
+
+ return functionElementForBoard;
+ }
+
+
+ dropFunctionOverAction(
+ label: string, type: string,
+ boardGraph: joint.dia.Graph) {
+
+ // function name is the same as function type
+ // actually functionName here refers step name in CDS tosca model
+ // and function type is the nodeTempalteName
+ const functionElementForBoard =
+ this.createFuctionElementForBoard(label, type);
+ boardGraph.addCell(functionElementForBoard);
+ return functionElementForBoard;
+ }
+
+ getFunctionTypeFromPaletteFunction(cell: joint.shapes.palette.FunctionElement) {
+ return cell.attributes.attrs.type;
+ }
+
+ getFunctionTypeFromBoardFunction(cell: joint.shapes.board.FunctionElement) {
+ return cell.attributes.attrs['#type'].text;
+ }
+
+ getFunctionNameFromBoardFunction(cell: joint.shapes.board.FunctionElement) {
+ return cell.attributes.attrs['#label'].text;
+ }
+
+ canEmpedMoreChildern(parentCell: joint.shapes.app.ActionElement, boardGraph: joint.dia.Graph): boolean {
+ if (!parentCell.get('embeds')) {
+ return true;
+ }
+ const types = this.getChildernTypes(parentCell, boardGraph);
+ return parentCell.get('embeds').length < 1 ||
+ types.includes('dg-generic');
+ }
+
+
+ getChildernTypes(parentCell: joint.shapes.app.ActionElement,
+ boardGraph: joint.dia.Graph): string[] {
+ if (parentCell.get('embeds')) {
+ return parentCell.get('embeds').map((cellName) => {
+ const child = boardGraph.getCell(cellName) as joint.shapes.board.FunctionElement;
+ const functionType = this.getFunctionTypeFromBoardFunction(child);
+ console.log('functionType', functionType);
+ return functionType;
+ });
+ } else {
+ return [];
+ }
+ }
+
+ getDgGenericChild(parentCell: joint.shapes.app.ActionElement,
+ boardGraph: joint.dia.Graph):
+ joint.shapes.board.FunctionElement[] {
+ if (parentCell.get('embeds')) {
+ return parentCell.get('embeds')
+ .filter((cellName) => {
+ const child = boardGraph.getCell(cellName) as joint.shapes.board.FunctionElement;
+ const functionType = this.getFunctionTypeFromBoardFunction(child);
+ return functionType === 'dg-generic';
+ })
+ .map((cellName) => {
+ const child = boardGraph.getCell(cellName) as joint.shapes.board.FunctionElement;
+ return child;
+ });
+ } else {
+ return [];
+ }
+ }
+
+ isEmptyParent(parentCell: joint.shapes.app.ActionElement): boolean {
+ return !parentCell.get('embeds') || parentCell.get('embeds').length < 1;
+ }
+
+}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.dashboard.state.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.dashboard.state.ts
index 5ae62d84a..1a14021f4 100644
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.dashboard.state.ts
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.dashboard.state.ts
@@ -24,11 +24,10 @@ import { TopologyTemplate } from './designer.topologyTemplate.model';
export class DesignerDashboardState {
- serverFunctions: ModelType[];
template: TopologyTemplate;
+ sourceContent: string;
constructor() {
- this.serverFunctions = [];
this.template = new TopologyTemplate();
}
}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.topologyTemplate.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.topologyTemplate.model.ts
index 4e73c7986..b85a6139a 100644
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.topologyTemplate.model.ts
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.topologyTemplate.model.ts
@@ -3,11 +3,11 @@ import { NodeTemplate } from './desinger.nodeTemplate.model';
export class TopologyTemplate {
- workflows: Map<string, DeclarativeWorkflow>;
- 'node_templates': Map<string, NodeTemplate>;
+ workflows: {};
+ 'node_templates': {};
constructor() {
- this.workflows = new Map();
- this.node_templates = new Map();
+ this.workflows = {};
+ this.node_templates = {};
}
}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/desinger.nodeTemplate.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/desinger.nodeTemplate.model.ts
index 7f8556535..9bd56e5d5 100644
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/desinger.nodeTemplate.model.ts
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/desinger.nodeTemplate.model.ts
@@ -7,4 +7,9 @@ export class NodeTemplate {
artifacts?: {};
cabapilities?: {};
requirements?: {};
+
+ constructor(type) {
+ this.type = type;
+ this.properties = {};
+ }
}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/functions.state.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/functions.state.ts
new file mode 100644
index 000000000..329c38deb
--- /dev/null
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/functions.state.ts
@@ -0,0 +1,31 @@
+/*
+============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 {ModelType} from './ModelType.model';
+
+export class FunctionsState {
+
+ serverFunctions: ModelType[];
+
+ constructor() {
+ this.serverFunctions = [];
+ }
+}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.css
new file mode 100644
index 000000000..01ae599a4
--- /dev/null
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.css
@@ -0,0 +1,580 @@
+.dsl-editor {
+ height: 500px;
+}
+
+body{
+ background-image: linear-gradient(-45deg, #000 9%, #fff 0) !important;
+ background-size: 6px 6px !important;
+}
+
+
+/*Header*/
+header{
+ height: 60px;
+ background-color: #1B3E6F;
+ box-shadow: 0 4px 10px rgba(238, 240, 245, 1.0);
+}
+.logo{
+ float: left;
+ width: 50px;
+ height: 60px;
+ background: url(/assets/img/logo-icon.svg) center center #fff no-repeat;
+}
+
+/**Bread Crumb**/
+.breadcrumb{
+ padding: 9px 20px;
+ background: transparent;
+ line-height: 40px;
+}
+.breadcrumb a,
+.breadcrumb a:hover{
+ color: #fff;
+}
+.breadcrumb .breadcrumb-item{
+ font-size: 12px;
+ font-weight: bold;
+}
+.breadcrumb .breadcrumb-item:first-child{
+ font-size: 16px;
+}
+.breadcrumb-item + .breadcrumb-item::before{
+ color: #fff;
+}
+.breadcrumb .breadcrumb-item.active p{
+ display: inline;
+ padding: 4px 10px;
+ background: #F4F9FE;
+ border-radius: 10px;
+ color: #C3CDDB;
+ font-size: 10px;
+}
+.sidebar-container{
+ height: calc(100vh - 60px) !important;
+}
+/**Topology Actions**/
+.topology-actions{
+ margin: 0;
+ height: 60px;
+}
+.topology-actions > li{
+ height: 59px;
+ display: inline-block;
+ padding: 0 20px;
+}
+.topology-actions > li:first-child{
+ border-right: solid 1px #16396A;
+}
+.topology-actions .btn-group{
+ margin-top: 11px;
+}
+.btn-topology-action,
+.btn-topology-action:hover{
+ margin: 0 6px;
+ padding: 6px 10px;
+ color: #fff;
+ border-radius: 50%;
+ border: solid .5px #fff;
+}
+.btn-topology-action:last-child{
+ margin-right: 0;
+}
+.btn-topology-action .fa{
+ width: 16px;
+ height: 16px;
+ text-align: center;
+}
+.topology-actions .dropdown-text,
+.dropdown-toggle:hover ~ .dropdown-text,
+.dropdown-toggle:focus ~ .dropdown-text{
+ top: 7px;
+ text-indent: 15px;
+ background: #1273EB;
+ border-radius: 15px;
+ border: 0;
+ box-shadow: none;
+ color: #fff;
+ font-weight: bold;
+ font-size: 13px;
+}
+.topology-actions .dropdown-text::after{
+ right: 15px;
+ top: 13px;
+ border-width: 6px 6px 0 6px;
+ border-color: #fff transparent transparent transparent;
+}
+.topology-actions .dropdown-toggle:focus ~ .dropdown-text::after{
+ top: 13px;
+ border-width: 0 6px 6px 6px;
+ border-color: transparent transparent #fff transparent
+}
+.topology-actions .dropdown-content:hover,
+.topology-actions .dropdown-toggle:focus ~ .dropdown-content{
+ padding: 12px 0;
+ text-indent: 0;
+ background: #fff;
+ border: 0;
+ border-radius: 2px;
+ box-shadow: 0 2px 6px rgba(47, 83, 151, .15)
+}
+.topology-actions .dropdown-content a{
+ padding: 0 20px;
+ color: #1B3E6F;
+ font-size: 13px;
+}
+.topology-actions .dropdown-content a:hover{
+ background: #F4F9FE;
+ text-decoration: none;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*Rotated Text*/
+button.rotate{
+ position: absolute;
+ margin-top: 1px;
+ padding: 0;
+ background: transparent;
+ border: 0;
+}
+.rotate{
+ vertical-align: bottom;
+ /* text-align: center; */
+}
+.rotate span{
+ display: inline-table !important;
+ -ms-writing-mode: tb-rl;
+ -webkit-writing-mode: vertical-rl;
+ writing-mode: vertical-rl !important;
+ transform: rotate(180deg);
+ white-space: nowrap;
+ background: #1B3E6F;
+ padding: 15px 12px;
+ font-weight: bold;
+ font-size: 12px;
+ color:#fff;
+ /* border-bottom-left-radius: 2px; */
+ border-top-left-radius: 2px;
+}
+.rotate i{
+ margin-right: 3px;
+ margin-top: 9px;
+ font-size: 15px;
+}
+.rotate span:first-child{
+ margin-bottom: 0;
+}
+.rotate a:hover{
+ text-decoration: none;
+}
+
+/*ACTIONS & COMPONENTS MENU*/
+.input-search-controller{
+ height: 50px;
+ padding-left: 30px;
+ background: url(src/assets/img/icon-search-light.svg) #fff 10px center no-repeat;
+ border-radius: 0;
+ border: 0;
+ border-bottom: solid 1px #D7E7F9;
+ color: #1B3E6F;
+ font-size: 13px;
+}
+.input-search-controller::placeholder{
+ color: #D0D7E4;
+ font-size: 11px;
+}
+.input-search-controller:focus{
+
+ box-shadow: 0 2px 6px 0 rgba(47, 83, 151, .15);
+ border-color: #DEE8F3;
+}
+.actions-scroll{
+ max-height: 29vh;
+ overflow-y: auto;
+ margin-top: 12px;
+ margin-bottom: 20px;
+}
+.componentsList p{
+ margin-bottom: 0;
+ padding-left: 30px;
+ background-position: left center;
+ background-repeat: no-repeat;
+}
+p.compType-1{
+ background-image: url(/assets/img/icon-comType1-sm.svg);
+}
+p.compType-2{
+ background-image: url(/assets/img/icon-comType2-sm.svg);
+}
+p.compType-3{
+ background-image: url(/assets/img/icon-comType3-sm.svg);
+}
+p.compType-4{
+ background-image: url(/assets/img/icon-comType4-sm.svg);
+}
+/*Actions Wrapper*/
+.actions-wrapper{
+ position: absolute;
+ width: 100%;
+ top: 0;
+}
+.actions-container{
+ width: 92%;
+ margin: 0 auto;
+ background: red;
+}
+
+.controllerSidebar{
+ width: 320px;
+ background: #F4F9FE;
+ border: solid 1px #C1CDDD;
+ box-shadow: 0 2px 6px rgba(47, 83, 151, .10);
+}
+.controllerSidebar h1{
+ margin-bottom: 15px;
+ padding: 12px 0 12px 12px;
+ background: #fff;
+ font-size: 12px;
+ font-weight: bold;
+ text-transform: uppercase;
+ color: #C3CDDB;
+}
+.controllerSidebar b{
+ font-size: 12px;
+ color: #C3CDDB;
+}
+.actionBtns .btn{
+ margin: 0 15px 12px;
+ padding: 9px 20px;
+ border-radius: 2px !important;
+ font-size: 12px;
+ font-weight: bold;
+}
+.actionBtns .btn:first-child{
+ background: #1B3E6F;
+ border: solid 1px #1B3E6F;
+ color: #fff;
+}
+.actionBtns .btn:last-child{
+ padding-left: 34px !important;
+ background: url(src/assets/img/icon-import-blue.svg) 12px center #fff no-repeat;
+ border: solid 1px #D0DFF1;
+ color: #1B3E6F;
+}
+.actionsList,
+.componentsList{
+ padding: 0 12px 20px;
+}
+.componentsList{
+ padding-bottom: 0;
+}
+.custom-control.custom-checkbox:hover,
+.custom-control-label:hover{
+ cursor: pointer;
+}
+.actionsList .custom-checkbox,
+.componentsList .list-group-item{
+ margin-bottom: 10px;
+ padding-left: 40px;
+ background: #fff;
+ box-shadow: 0 2px 6px rgba(47, 83, 151, .15);
+ border-radius: 2px;
+}
+.actionsList .custom-control-label{
+ width: 100%;
+ padding: 6px;
+ vertical-align: unset;
+ color: #1B3E6F;
+ font-size: 14px;
+ line-height: 20px;
+ border-top-right-radius: 2px;
+ border-bottom-right-radius: 2px;
+}
+.actionsList .custom-control-label::before,
+.actionsList .custom-control-label::after{
+ top: 1.25rem;
+}
+.actionsList .custom-control-label p{
+ color: #C7D0DD;
+ font-size: 12px;
+}
+.custom-control-input:checked ~ .custom-control-label{
+ background-color: #1B3E6F !important;
+ color: #fff;
+}
+.inserActionBtns .btn{
+ border-radius: 15px !important;
+ padding: 6px 20px;
+ font-size: 12px;
+ font-weight: bold;
+ border: 0;
+
+}
+.inserActionBtns .btn:first-child{
+ background: #1273EB;
+ border: solid 1px #1273EB;
+ color: #fff;
+}
+.inserActionBtns .btn:last-child{
+ background: #fff;
+ border: solid 1px #D9E6F2;
+ color: #C3CDDB;
+}
+/*Components List*/
+.componentsList .list-group-item{
+ padding-left: 36px;
+ border: 0;
+ font-size: 14px;
+ background: url(src/assets/img/icon-drag.svg) #fff 20px center no-repeat;
+}
+
+/*CANVAS*/
+.editBar{
+ width: 200px;
+ margin: 0 auto 0;
+ padding: 6px 10px;
+ background:#F4F9FE;
+ /* border: solid 1px #E8EFF8; */
+ box-shadow: 0 2px 6px rgba(47, 83, 151, .1);
+}
+.editBar .btn-group{
+ box-shadow: 0 2px 6px rgba(47, 83, 151, .15);
+}
+.editBar .btn{
+ background-color: #fff;
+ background-repeat: no-repeat;
+ background-position: left center;
+ border: 0;
+ color: #1B3E6F;
+ font-size: 10px;
+}
+.editBar .btn.active{
+ background-color: #1B3E6F !important;
+ color: #fff;
+}
+.viewBtns .btn{
+ background-position: 10px center;
+ padding-left: 30px!important;
+}
+.viewBtns .topologySource{
+ background-image: url(src/assets/img/icon-topologyView-active.svg);
+}
+.viewBtns .topologyView{
+ background-image: url(src/assets/img/icon-topologySource.svg);
+}
+.card.actionContainer{
+ margin: 20px 20px 40px 60px;
+ background: transparent;
+ border: 0;
+}
+.actionContainer .card-header{
+ padding: 0;
+ background: transparent;
+ border: 0;
+}
+.actionContainer .card-header span{
+ padding: 12px 20px;
+ border-top-left-radius: 2px;
+ border-top-right-radius: 2px;
+ font-size: 12px;
+ line-height: 38px;
+ font-weight: bold;
+ color: #1B3E6F;
+ background: #C3CDDB;
+}
+.actionContainer .card-body{
+ min-height: 170px;
+ padding: 15px 20px !important;
+ border: solid 1px #C3CDDB;
+ background: #fff;
+ box-shadow: 0 2px 6px rgba(18, 115, 235, .1);
+}
+.actionContainer a{
+ display: inline-block;
+ width: 230px;
+ height: 130px;
+ margin: 20px;
+ padding: 24px;
+ background: #1B3E6F;
+ color: #fff !important;
+ text-align: center;
+ border-radius: 2px;
+ border: solid 1px #1B3E6F;
+}
+.actionContainer a:hover{
+ cursor: pointer;
+ border: dashed 1px #E9FCC6;
+}.componentContainer img{
+ height: 38px;
+}
+.componentContainer h2{
+ margin-top: 9px;
+ font-size: 14px;
+ font-weight: bold;
+}
+.componentContainer p{
+ font-size: 12px;
+}
+
+/*ATTRIBUTES SIDE BAR*/
+.attributesSideBar{
+ width: 396px;
+ padding: 0;
+}
+.attributesSideBar .attributesContainer{
+ background: #fff;
+ border: solid 1px #C1CDDD;
+ box-shadow: 0 2px 6px rgba(47, 83, 151, .1);
+}
+.closeBar{
+ float: right;
+ width: 90%;
+ height: 40px;
+ background: url(/assets/img/icon-close.svg) center center #DCE8F4 no-repeat ;
+ border: 0;
+ outline: 0;
+}
+.closeBar:focus{
+ outline: none;
+}
+.attributesContainer h1{
+ margin-bottom: 10px;
+ padding: 12px 0 12px 15px;
+ background: #DEE8F3;
+ font-size: 12px;
+ font-weight: bold;
+ text-transform: uppercase;
+ color: #1B3E6F;
+}
+.actionName{
+ margin-bottom: 21px;
+}
+.attributesContainer label{
+ color: #1B3E6F;
+ text-transform: uppercase;
+ font-size: 11px;
+ font-weight: bold;
+}
+.attributesContainer .form-group{
+ margin-bottom: 9px;
+}
+.attributesContainer .form-control{
+ border-color: #F0F5FC;
+ border-radius: 2px;
+ box-shadow: 0 2px 6px rgba(47, 83, 151, .1);
+ color: #103D73;
+ font-size: 13px;
+}
+.attributesContainer .form-control:focus{
+ border-color: #66bfff;
+ box-shadow: 0 0 0 4px rgba(0,149,255,0.15);
+}
+.attributesContainer .form-control::placeholder{
+ color: #CFD7E5;
+}
+.scrolll{
+ max-height: 88.75vh;
+ overflow-y: auto;
+}
+.accordion > .card{
+ margin-bottom: 0 !important;
+ border: 0;
+}
+.accordion > .card .card-header{
+ margin: 0;
+ padding: 0;
+ background-color: #F4F9FE;
+ border: 0;
+ border-radius: 0;
+}
+.accordion > .card .card-body{
+ padding-bottom: 10px !important;
+}
+.accordion .btn-link{
+ padding: 0;
+ color: #C3CDDB;
+ font-weight: bold;
+ font-size: 13px;
+ text-transform: uppercase;
+ line-height: 38px;
+}
+.accordion .btn-link:hover{
+ color: #103D73;
+ text-decoration: unset;
+}
+.accordion .card-header .btn-link[aria-expanded="true"]:after,
+.accordion .card-header .btn-link[aria-expanded="false"]:after{
+ margin-right: 9px;
+ font-family: 'FontAwesome';
+ float: left;
+ font-weight: normal;
+ font-size: 12px;
+}
+.accordion .card-header .btn-link[aria-expanded="true"]:after{
+ content: "\f078";
+}
+.accordion .card-header .btn-link[aria-expanded="false"]:after{
+ content: "\f054";
+}
+.btn-addAttribute{
+ width: 20px;
+ height: 20px;
+ background-image: url(/assets/img/icon-add.svg);
+ background-position: center center;
+ background-repeat: no-repeat;
+ vertical-align: sub;
+}
+.btn-addAttribute:hover{
+ background-image: url(/assets/img/icon-add-hover.svg);
+}
+.btn-deleteAttribute{
+ padding: 5px 10px;
+ background: #FFE6E7;
+ border: solid .5px #FFC9CB;
+ border-radius: 2px;
+ color: #FF6469;
+ font-size: 10px;
+
+}
+.source-button{
+ position: absolute;
+ z-index: 9999999;
+ top: 69px;
+ left: 50%;
+}
+/*jointjs paper*/
+/* #board-paper {
+ position: relative;
+ border: 1px solid gray;
+ display: inline-block;
+ background: transparent;
+ overflow: hidden;
+}
+#board-paper svg {
+ background: transparent;
+}
+#board-paper svg .link {
+ z-index: 2;
+}
+.html-element {
+ position: absolute;
+ background: #F4F9FE;
+ pointer-events: none;
+ -webkit-user-select: none;
+ z-index: 2;
+} */
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.html
new file mode 100644
index 000000000..2a558517c
--- /dev/null
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.html
@@ -0,0 +1,80 @@
+<header>
+ <div class="row m-0">
+ <div class="col pl-0">
+ <p class="logo mb-0"></p>
+ <nav aria-label="breadcrumb">
+ <ol class="breadcrumb mb-0">
+ <li class="breadcrumb-item">
+ <a href="#">CBA Packages</a>
+ </li>
+ <li class="breadcrumb-item">
+ <a href="#">Package Name</a>
+ </li>
+ <li class="breadcrumb-item active" aria-current="page">
+ <p class="mb-0">Topology View</p>
+ </li>
+ </ol>
+ </nav>
+ </div>
+ <div class="col pr-0 text-right">
+ <ul class="topology-actions">
+ <li>
+ <div class="btn-group" role="group" aria-label="Basic example">
+ <a href="#" role="button" aria-pressed="true" class="btn-topology-action float tooltip-bottom"
+ data-tooltip="Preview">
+ <i class="fa fa-eye"></i>
+ </a>
+ <a href="#" role="button" aria-pressed="true" class="btn-topology-action float tooltip-bottom"
+ data-tooltip="Download">
+ <i class="fa fa-download"></i>
+ </a>
+ <a href="#" role="button" aria-pressed="true" class="btn-topology-action float tooltip-bottom"
+ data-tooltip="Share">
+ <i class="fa fa-share-square"></i>
+ </a>
+ </div>
+ </li>
+ <li>
+ <div class="dropdown">
+ <input class="dropdown-toggle" type="text">
+ <div class="dropdown-text">Save</div>
+ <ul class="dropdown-content">
+ <li>
+ <a href="">Save</a>
+ </li>
+ <li>
+ <a href="">Save &amp; Deploy</a>
+ </li>
+ </ul>
+ </div>
+ </li>
+ </ul>
+
+
+ </div>
+ </div>
+</header>
+<div class="source-button editBar">
+ <div class="btn-group viewBtns" role="group">
+ <button (click)="convertAndOpenInDesingerView()" type="button" class="btn btn-secondary topologySource">Designer</button>
+ <button type="button"
+ class="btn btn-secondary topologyView active">Scripting</button>
+ </div>
+</div>
+<ng-sidebar-container class="sidebar-container">
+ <!-- Controller SideBar -->
+ <ng-sidebar [(opened)]="controllerSideBar" [sidebarClass]="'demo-sidebar controllerSidebar container-fluid'"
+ [mode]="'push'" #sidebarLeft>
+ <div class="row">
+
+ <h1 class="col-12">Actions</h1>
+
+
+ </div>
+ </ng-sidebar>
+<div ng-sidebar-content id="board-paper">
+ <ace-editor [(text)]="content" [mode]="'json'" [autoUpdateContent]="true" [durationBeforeCallback]="1000"
+ [theme]="'tomorrow_night_bright'" #editor style="height:500px">
+ </ace-editor>
+
+ </div>
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.ts
new file mode 100644
index 000000000..34194e42f
--- /dev/null
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.ts
@@ -0,0 +1,45 @@
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { DesignerStore } from '../designer.store';
+import { PackageCreationUtils } from '../../package-creation/package-creation.utils';
+import { RouterLink, Router } from '@angular/router';
+import { Subject } from 'rxjs';
+
+@Component({
+ selector: 'app-designer-source-view',
+ templateUrl: './source-view.component.html',
+ styleUrls: ['./source-view.component.css']
+})
+export class DesignerSourceViewComponent implements OnInit, OnDestroy {
+
+ content = '';
+ lang = 'json';
+ private controllerSideBar: boolean;
+ private ngUnsubscribe = new Subject();
+
+ constructor(private store: DesignerStore,
+ private packageCreationUtils: PackageCreationUtils,
+ private router: Router) {
+ this.controllerSideBar = true;
+ }
+
+ ngOnInit() {
+ this.store.state$.subscribe(
+ state => {
+ console.log(state);
+ this.content = this.packageCreationUtils.transformToJson(state.template);
+ });
+
+ }
+
+ convertAndOpenInDesingerView() {
+ // TODO validate json against scheme
+ console.log('convertAndOpenInDesingerView ...', this.content);
+ this.store.saveSourceContent(this.content);
+ this.router.navigateByUrl('/packages/designer');
+ }
+
+ ngOnDestroy() {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
+ }
+}
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.module.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.module.ts
index 0d56014b5..66c7b498a 100644
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.module.ts
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.module.ts
@@ -14,7 +14,6 @@ import { PackagesHeaderComponent } from './packages-dashboard/packages-header/pa
import { PackagesSearchComponent } from './packages-dashboard/search-by-packages/search-by-packages.component';
import { TagsFilteringComponent } from './packages-dashboard/filter-by-tags/filter-by-tags.component';
import { ConfigurationDashboardComponent } from './configuration-dashboard/configuration-dashboard.component';
-import { FunctionsComponent } from './designer/functions/functions.component';
import { ActionsComponent } from './designer/actions/actions.component';
import { PackageCreationComponent } from './package-creation/package-creation.component';
import { FormsModule } from '@angular/forms';
@@ -29,6 +28,7 @@ import { DslDefinitionsTabComponent } from './package-creation/dsl-definitions-t
import { TemplMappCreationComponent } from './package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component';
import { TemplMappListingComponent } from './package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component';
import { DataTablesModule } from 'angular-datatables';
+import { DesignerSourceViewComponent } from './designer/source-view/source-view.component';
@NgModule({
declarations: [PackagesDashboardComponent,
@@ -40,7 +40,6 @@ import { DataTablesModule } from 'angular-datatables';
SortPackagesComponent,
ConfigurationDashboardComponent,
PackagesHeaderComponent,
- FunctionsComponent,
ActionsComponent,
PackageCreationComponent,
ImportsTabComponent,
@@ -51,6 +50,7 @@ import { DataTablesModule } from 'angular-datatables';
ScriptsTabComponent,
MetadataTabComponent,
DslDefinitionsTabComponent,
+ DesignerSourceViewComponent,
],
imports: [
CommonModule,
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.routing.module.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.routing.module.ts
index 913bb1081..ad06cf15f 100644
--- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.routing.module.ts
+++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.routing.module.ts
@@ -4,6 +4,7 @@ import {PackagesDashboardComponent} from './packages-dashboard/packages-dashboar
import {DesignerComponent} from './designer/designer.component';
import {PackageCreationComponent} from './package-creation/package-creation.component';
import {ConfigurationDashboardComponent} from './configuration-dashboard/configuration-dashboard.component';
+import { DesignerSourceViewComponent } from './designer/source-view/source-view.component';
const routes: Routes = [
@@ -12,6 +13,7 @@ const routes: Routes = [
component: PackagesDashboardComponent
},
{path: 'designer', component: DesignerComponent},
+ { path: 'designer/source', component: DesignerSourceViewComponent },
{path: 'package/:id', component: ConfigurationDashboardComponent},
{path: 'createPackage', component: PackageCreationComponent},
];
diff --git a/cds-ui/designer-client/tslint.json b/cds-ui/designer-client/tslint.json
index ecbd7cf88..f85fc68d9 100644
--- a/cds-ui/designer-client/tslint.json
+++ b/cds-ui/designer-client/tslint.json
@@ -87,10 +87,5 @@
},
"rulesDirectory": [
"codelyzer"
- ],
- "linterOptions": {
- "exclude": [
- "src/app/modules/feature-modules/packages/designer/designer.component.ts"
- ]
- }
+ ]
}