Rift.IO OSM R1 Initial Submission
[osm/UI.git] / skyquake / plugins / composer / src / src / components / EditorForwardingGraph / mapClassifier.js
1 /**
2 * Created by onvelocity on 3/2/16.
3 */
4
5 'use strict';
6
7 import d3 from 'd3'
8 import React from 'react'
9 import Button from '../Button'
10 import LayoutRow from '../LayoutRow'
11 import ContentEditableDiv from '../ContentEditableDiv'
12 import changeCase from 'change-case'
13 import ClassNames from 'classnames'
14 import DescriptorModelFactory from '../../libraries/model/DescriptorModelFactory'
15 import DescriptorModelMetaFactory from '../../libraries/model/DescriptorModelMetaFactory'
16 import HighlightRecordServicePaths from '../../libraries/graph/HighlightRecordServicePaths'
17 import ComposerAppActions from '../../actions/ComposerAppActions'
18 import CatalogItemsActions from '../../actions/CatalogItemsActions'
19 import SelectionManager from '../../libraries/SelectionManager'
20 import DeletionManager from '../../libraries/DeletionManager'
21 import TooltipManager from '../../libraries/TooltipManager'
22 import ConnectionPointSelector from './ConnectionPointSelector'
23 import mapConnectionPoint from './mapConnectionPoint'
24 import EditableProperty from './EditableProperty'
25 import onCutDelegateToRemove from './onCutDelegateToRemove'
26 import onClickSelectAndShowInDetailsPanel from './onClickSelectAndShowInDetailsPanel'
27 import onFormInputChangedModifyContainerAndNotify from './onFormInputChangedModifyContainerAndNotify'
28
29 import imgNSD from '../../images/default-catalog-icon.svg'
30 import imgFG from '../../../../node_modules/open-iconic/svg/infinity.svg'
31 import imgRemove from '../../../../node_modules/open-iconic/svg/trash.svg'
32 import imgAdd from '../../../../node_modules/open-iconic/svg/plus.svg'
33 import imgConnection from '../../../../node_modules/open-iconic/svg/random.svg'
34 import imgClassifier from '../../../../node_modules/open-iconic/svg/spreadsheet.svg'
35 import imgReorder from '../../../../node_modules/open-iconic/svg/menu.svg'
36
37 export default function mapClassifier(context, classifier, i) {
38
39 // todo if a classifier is linked to an rsp then highlight it
40 //rsp.uiState.showPath = rsp.uiState.hasOwnProperty('showPath') ? rsp.uiState.showPath : true;
41
42 function onInputUpdateModel(context, attr, name, event) {
43 event.preventDefault();
44 attr.setFieldValue(name, event.target.value);
45 CatalogItemsActions.catalogItemDescriptorChanged(attr.getRoot());
46 }
47
48 function onClickAddNewMatchAttributes(context, classifier) {
49 event.preventDefault();
50 event.stopPropagation();
51 const newMatchAttr = classifier.createMatchAttributes();
52 SelectionManager.disableOutlineChanges();
53 CatalogItemsActions.catalogItemDescriptorChanged(classifier.getRoot());
54 setTimeout(() => {
55 SelectionManager.enableOutlineChanges();
56 SelectionManager.select(newMatchAttr);
57 SelectionManager.refreshOutline();
58 const input = Array.from(document.querySelectorAll(`tr[data-uid="${newMatchAttr.uid}"] input`)).forEach((element, index) => {
59 // index 0 is hidden id field
60 if (index === 1) {
61 element.focus();
62 }
63 });
64 }, 100);
65 }
66
67 function mapClassifierMatchAttributes(context, matchAttributes, key) {
68 const fields = matchAttributes.fieldNames.map((name, i) => {
69 return (
70 <td key={i} className={name + '-property'}>
71 <div className="match-attr-name">{name}</div>
72 <ContentEditableDiv value={matchAttributes.getFieldValue(name)}
73 onBlur={() => DeletionManager.addEventListeners()}
74 onClick={event => {
75 event.preventDefault();
76 SelectionManager.select(matchAttributes);
77 SelectionManager.refreshOutline();
78 }}
79 onCut={event => {
80 event.stopPropagation();
81 }}
82 onChange={onInputUpdateModel.bind(null, context, matchAttributes, name)}
83 className="match-attr-value"/>
84 </td>
85 );
86 });
87 return (
88 <tr key={key}
89 data-uid={matchAttributes.uid}
90 onCut={event => {
91 event.stopPropagation();
92 matchAttributes.remove();
93 CatalogItemsActions.catalogItemDescriptorChanged(matchAttributes.getRoot());
94 SelectionManager.refreshOutline();
95 }}>
96 {fields}
97 </tr>
98 )
99 }
100
101 function buildRecordServicePathSelector(classifier) {
102 const rspId = classifier.model['rsp-id-ref'];
103 const options = [{}].concat(classifier.parent.recordServicePaths).map((rsp, i) => {
104 return (
105 <option key={i} name="rsp-id-ref" value={rsp.id}>{rsp.title}</option>
106 )
107 });
108 return (
109 <select name="rsp-id-ref" value={rspId} onChange={onFormInputChangedModifyContainerAndNotify.bind(null, classifier)}>{options}</select>
110 )
111 }
112
113 function onClickExitPathEdithMode(component, event) {
114 event.preventDefault();
115 component.setState({editClassifierConnectionPointRef: false});
116 }
117
118 function onClickAddConnectionPointRef(component, classifier, connector, event) {
119 event.preventDefault();
120 classifier.addVnfdConnectionPoint(connector);
121 CatalogItemsActions.catalogItemDescriptorChanged(classifier.getRoot());
122 }
123
124 function onClickOpenConnectionPointSelector(component, classifier, event) {
125 component.setState({editClassifierConnectionPointRef: classifier.uid});
126 function closeAndRemoveHandler() {
127 component.setState({editClassifierConnectionPointRef: false});
128 document.body.removeEventListener('click', closeAndRemoveHandler, true);
129 }
130 document.body.addEventListener('click', closeAndRemoveHandler, true);
131 }
132
133 const attributeNames = DescriptorModelMetaFactory.getModelFieldNamesForType('nsd.vnffgd.classifier.match-attributes');
134
135 const selectedConnectionPoint = classifier.uiState.vnfdRef ? `${classifier.uiState.vnfdRef.name}/${classifier.vnfdConnectionPointRef.vnfdIndex}/${classifier.vnfdConnectionPointRef.vnfdConnectionPointName}` : '';
136
137 const isEditClassifierConnectionPointRef = context.component.state.editClassifierConnectionPointRef === classifier.uid;
138
139 const hasClassifierServiceFunctionVNFDs = context.containers.filter(d => DescriptorModelFactory.isConstituentVnfdWithServiceChain(d, 'CLASSIFIER')).length > 0;
140
141 return (
142 <LayoutRow key={classifier.uid}
143 data-uid={classifier.uid}
144 data-offset-width="true"
145 className={ClassNames('fg-classifier', classifier.className, {'-is-edit-classifier-connection-point-ref': isEditClassifierConnectionPointRef})}
146 onClick={onClickSelectAndShowInDetailsPanel.bind(null, classifier)}>
147 <div className="classifier-properties">
148 <div className="classifier-property">
149 <EditableProperty title="name">
150 <ContentEditableDiv name="name"
151 value={classifier.name}
152 autoPadRight="true"
153 onBlur={() => DeletionManager.addEventListeners()}
154 onChange={onFormInputChangedModifyContainerAndNotify.bind(null, classifier)}
155 className="classifier-name" />
156 </EditableProperty>
157 </div>
158 <div className="classifier-property">
159 <EditableProperty title="path">
160 {buildRecordServicePathSelector(classifier)}
161 </EditableProperty>
162 </div>
163 <div className="classifier-property">
164 <EditableProperty title="connection point ref" disabled={!hasClassifierServiceFunctionVNFDs}>
165 <ContentEditableDiv autoPadRight="true"
166 value={selectedConnectionPoint}
167 disabled={!hasClassifierServiceFunctionVNFDs}
168 onChange={() => {}}
169 onClick={onClickOpenConnectionPointSelector.bind(null, context.component, classifier)} />
170 </EditableProperty>
171 <div className="select-connection-point-ref">
172 <ConnectionPointSelector containers={context.containers}
173 style={context.styleSecondary}
174 serviceChain="CLASSIFIER"
175 isDisabled={!hasClassifierServiceFunctionVNFDs}
176 onExitEditPathMode={onClickExitPathEdithMode.bind(null, context.component)}
177 onAddConnectionPointRef={onClickAddConnectionPointRef.bind(null, context.component, classifier)}
178 />
179 </div>
180 {!hasClassifierServiceFunctionVNFDs ? <div className="hint">A VNFD with the chain CLASSIFIER is required to add a connection point ref.</div> : ''}
181 </div>
182 </div>
183 <table className="classifier-match-attributes">
184 <thead>
185 <tr>
186 {attributeNames.map((name, i) => <th key={i} className={ClassNames(name + '-property')}>{changeCase.title(name)}</th>)}
187 </tr>
188 </thead>
189 <tbody>
190 {classifier.matchAttributes.map(mapClassifierMatchAttributes.bind(null, context))}
191 </tbody>
192 <tfoot>
193 <tr className="xfooter-actions">
194 <th colSpan={attributeNames.length} className="row-action-column">
195 <Button className="create-new-match-attributes" src={imgAdd} width="20px" onClick={onClickAddNewMatchAttributes.bind(null, context, classifier)} label="Add Match Attributes" />
196 </th>
197 </tr>
198 </tfoot>
199 </table>
200 </LayoutRow>
201 );
202
203 }