update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[osm/UI.git] / skyquake / plugins / composer / src / src / components / EditorForwardingGraph / EditForwardingGraphPaths.js
1 /*
2 *
3 * Copyright 2016 RIFT.IO Inc
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18 /**
19 * Created by onvelocity on 2/4/16.
20 */
21
22 'use strict';
23
24 import d3 from 'd3'
25 import React from 'react'
26 import Range from '../Range'
27 import Button from '../Button'
28 import ClassNames from 'classnames'
29 import changeCase from 'change-case'
30 import LayoutRow from '../LayoutRow'
31 import SelectionManager from '../../libraries/SelectionManager'
32 import PureRenderMixin from 'react-addons-pure-render-mixin'
33 import CatalogItemsActions from '../../actions/CatalogItemsActions'
34 import CanvasEditorActions from '../../actions/CanvasEditorActions'
35 import DescriptorModelFactory from '../../libraries/model/DescriptorModelFactory'
36 import ComposerAppActions from '../../actions/ComposerAppActions'
37 import DescriptorModelMetaFactory from '../../libraries/model/DescriptorModelMetaFactory'
38 import ComposerAppStore from '../../stores/ComposerAppStore'
39 import DeletionManager from '../../libraries/DeletionManager'
40 import ContentEditableDiv from '../ContentEditableDiv'
41 import TooltipManager from '../../libraries/TooltipManager'
42 import HighlightRecordServicePaths from '../../libraries/graph/HighlightRecordServicePaths'
43 import mapClassifier from './mapClassifier'
44 import mapRecordServicePath from './mapRecordServicePath'
45 import onCutDelegateToRemove from './onCutDelegateToRemove'
46 import onClickSelectAndShowInDetailsPanel from './onClickSelectAndShowInDetailsPanel'
47
48 import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
49 import ROLES from 'utils/roleConstants.js';
50 const PROJECT_ROLES = ROLES.PROJECT;
51 const PLATFORM = ROLES.PLATFORM;
52
53 import '../../styles/EditForwardingGraphPaths.scss'
54
55 import imgNSD from '../../images/default-catalog-icon.svg'
56 import imgFG from '../../../../node_modules/open-iconic/svg/infinity.svg'
57 import imgRemove from '../../../../node_modules/open-iconic/svg/trash.svg'
58 import imgAdd from '../../../../node_modules/open-iconic/svg/plus.svg'
59 import imgConnection from '../../../../node_modules/open-iconic/svg/random.svg'
60 import imgClassifier from '../../../../node_modules/open-iconic/svg/spreadsheet.svg'
61 import imgReorder from '../../../../node_modules/open-iconic/svg/menu.svg'
62
63 function mapFG(fg, i) {
64
65 const context = this;
66 context.vnffg = fg;
67
68 const colors = fg.colors;
69 const stylePrimary = {borderColor: colors.primary};
70 const styleSecondary = {borderColor: colors.secondary};
71
72 context.stylePrimary = stylePrimary;
73 context.styleSecondary = styleSecondary;
74
75 const rspMap = fg.rsp.reduce((map, rsp) => {
76 map[rsp.id] = rsp;
77 rsp.classifier = [];
78 return map;
79 }, {});
80
81 fg.classifier.forEach(classifier => {
82 const rsp = rspMap[classifier.model['rsp-id-ref']];
83 if (rsp) {
84 rsp.classifier.push(classifier);
85 }
86 });
87
88 function onClickRemoveForwardingGraph(fg, event) {
89 event.preventDefault();
90 const root = fg.getRoot();
91 fg.remove();
92 CatalogItemsActions.catalogItemDescriptorChanged(root);
93 }
94
95 function onClickAddClassifier(context, fg, event) {
96 event.preventDefault();
97 fg.createClassifier();
98 CatalogItemsActions.catalogItemDescriptorChanged(fg.getRoot());
99 }
100
101 function onClickToggleShowAllFGPaths(fg, event) {
102 //event.preventDefault();
103 event.stopPropagation();
104 fg.uiState.showPaths = event.target.checked;
105 fg.rsp.forEach(rsp => rsp.uiState.showPath = event.target.checked);
106 CatalogItemsActions.catalogItemMetaDataChanged(fg.getRoot().model);
107 }
108
109 if (!fg.uiState.hasOwnProperty('showPaths')) {
110 fg.uiState.showPaths = true;
111 fg.rsp.forEach(d => d.uiState.showPath = true);
112 }
113
114 const toggleSelectAllPaths = (
115 <input type="checkbox" name={'show-path' + fg.uid} checked={fg.uiState.showPaths} onChange={() => {}} onClick={onClickToggleShowAllFGPaths.bind(null, fg)} />
116 );
117
118 const srpFactory = DescriptorModelFactory.newRecordServicePathFactory({}, fg);
119 srpFactory.uid = fg.uid + i;
120
121 const hasServiceFunctionVNFDs = context.containers.filter(d => DescriptorModelFactory.isConstituentVnfdWithServiceChain(d, 'SF')).length > 0;
122
123 return (
124 <div key={i} className={fg.className} data-uid={fg.uid} data-offset-width="true" onClick={onClickSelectAndShowInDetailsPanel.bind(null, fg)} onCut={onCutDelegateToRemove.bind(null, fg)}>
125 <div key="outline-indicator" data-outline-indicator="true"></div>
126 <div className="header-actions">
127 {
128 this.isRBACValid ?
129 <Button className="remove-forwarding-graph" title="Remove" onClick={onClickRemoveForwardingGraph.bind(null, fg)} src={imgRemove}/>
130 : null
131 }
132 </div>
133 <LayoutRow primaryActionColumn={toggleSelectAllPaths} secondaryActionColumn={<img className="fg-icon" src={imgFG} width="20px" />}>
134 <small>{fg.title}</small>
135 </LayoutRow>
136 <div>
137 <h4>Rendered Service Paths</h4>
138 {hasServiceFunctionVNFDs ? fg.recordServicePaths.concat(srpFactory).map(mapRecordServicePath.bind(null, context)) : <small className="no-service-function-chain-msg hint">A VNFD with the chain SF is required to build Rendered Service Paths.</small>}
139 </div>
140 <div>
141 <h4>Classifiers</h4>
142 {fg.classifier.map(mapClassifier.bind(null, context))}
143 <div className="footer-actions">
144 <div className="row-action-column">
145 {
146 this.isRBACValid ?
147 <Button className="create-new-classifier" src={imgAdd} width="20px" onClick={onClickAddClassifier.bind(null, context, fg)} label="Add Classifier" />
148 : null
149 }
150 </div>
151 </div>
152 </div>
153 </div>
154 );
155
156 }
157
158 function mapNSD(nsd, i) {
159
160 const context = this;
161 context.nsd = nsd;
162
163 function onClickAddForwardingGraph(nsd, event) {
164 event.preventDefault();
165 nsd.createVnffgd();
166 CatalogItemsActions.catalogItemDescriptorChanged(nsd.getRoot());
167 }
168
169 const forwardingGraphs = nsd.forwardingGraphs.map(mapFG.bind(context));
170 if (forwardingGraphs.length === 0) {
171 forwardingGraphs.push(
172 <div key="1" className="welcome-message">
173 No Forwarding Graphs to model.
174 </div>
175 );
176 }
177
178 return (
179 <div key={i} className={nsd.className}>
180 {forwardingGraphs}
181 <div className="footer-actions">
182 <div className="row-action-column">
183 {
184 this.isRBACValid ?
185 <Button className="create-new-forwarding-graph" src={imgAdd} width="20px" onClick={onClickAddForwardingGraph.bind(null, nsd)} label="Add new Forwarding Graph" />
186 : null
187 }
188 </div>
189 </div>
190 </div>
191 );
192
193 }
194
195 const EditForwardingGraphPaths = React.createClass({
196 mixins: [PureRenderMixin],
197 getInitialState: function () {
198 return ComposerAppStore.getState();
199 },
200 getDefaultProps: function () {
201 return {
202 containers: []
203 };
204 },
205 componentWillMount: function () {
206 },
207 componentDidMount: function () {
208 },
209 componentDidUpdate: function () {
210 },
211 componentWillUnmount: function () {
212 },
213 contextTypes: {
214 userProfile: React.PropTypes.object
215 },
216 render() {
217 const containers = this.props.containers;
218 const context = {
219 component: this,
220 containers: containers,
221 isRBACValid: isRBACValid(this.context.userProfile, [PROJECT_ROLES.PROJECT_ADMIN, PROJECT_ROLES.CATALOG_ADMIN])
222 };
223 const networkService = containers.filter(d => d.type === 'nsd');
224 if (networkService.length === 0) {
225 return <p className="welcome-message">No <img src={imgNSD} width="20px" /> NSD open in the canvas. Try opening an NSD.</p>;
226 }
227
228 return (
229 <div className="EditForwardingGraphPaths -with-transitions" data-offset-parent="true">
230 <div key="outline-indicator" data-outline-indicator="true"></div>
231 {containers.filter(d => d.type === 'nsd').map(mapNSD.bind(context))}
232 </div>
233 );
234
235 }
236 });
237
238 export default EditForwardingGraphPaths;