const ComposerApp = React.createClass({
- mixins: [PureRenderMixin],
- getInitialState() {
- return ComposerAppStore.getState();
- },
- getDefaultProps() {
- return {};
- },
- componentWillMount() {
- if (clearLocalStorage) {
- window.localStorage.clear();
- }
+ mixins: [PureRenderMixin],
+ getInitialState() {
+ return ComposerAppStore.getState();
+ },
+ getDefaultProps() {
+ return {};
+ },
+ componentWillMount() {
+ if (clearLocalStorage) {
+ window.localStorage.clear();
+ }
if(this.item) {
FileManagerActions.openFileManagerSockets();
}
- this.state.isLoading = CatalogDataStore.getState().isLoading;
- ComposerAppStore.listen(this.onChange);
- CatalogDataStore.listen(this.onCatalogDataChanged);
- window.addEventListener('resize', this.resize);
- window.onbeforeunload = this.onBeforeUnload;
- // prevent browser from downloading any drop outside of our specific drop zones
- window.addEventListener('dragover', preventDefault);
- window.addEventListener('drop', preventDefault);
- // ensure drags initiated in the app clear the state on drop
- window.addEventListener('drop', clearDragState);
- DeletionManager.addEventListeners();
- },
- componentWillUnmount() {
- window.removeEventListener('resize', this.resize);
- window.removeEventListener('dragover', preventDefault);
- window.removeEventListener('drop', preventDefault);
- window.removeEventListener('drop', clearDragState);
+ this.state.isLoading = CatalogDataStore.getState().isLoading;
+ ComposerAppStore.listen(this.onChange);
+ CatalogDataStore.listen(this.onCatalogDataChanged);
+ window.addEventListener('resize', this.resize);
+ window.onbeforeunload = this.onBeforeUnload;
+ // prevent browser from downloading any drop outside of our specific drop zones
+ window.addEventListener('dragover', preventDefault);
+ window.addEventListener('drop', preventDefault);
+ // ensure drags initiated in the app clear the state on drop
+ window.addEventListener('drop', clearDragState);
+ DeletionManager.addEventListeners();
+ },
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.resize);
+ window.removeEventListener('dragover', preventDefault);
+ window.removeEventListener('drop', preventDefault);
+ window.removeEventListener('drop', clearDragState);
FileManagerActions.closeFileManagerSockets();
- // resizeManager automatically registered its event handlers
- resizeManager.removeAllEventListeners();
- ComposerAppStore.unlisten(this.onChange);
- CatalogDataStore.unlisten(this.onCatalogDataChanged);
- DeletionManager.removeEventListeners();
- TooltipManager.removeEventListeners();
- },
- componentDidMount() {
- resizeManager.addAllEventListeners();
- const snapshot = window.localStorage.getItem('composer');
- if (snapshot) {
- alt.bootstrap(snapshot);
- }
- document.body.addEventListener('keydown', (event) => {
- // prevent details editor form from blowing up the app
- const ENTER_KEY = 13;
- if (event.which === ENTER_KEY) {
- event.preventDefault();
- return false;
- }
- });
- const appRootElement = ReactDOM.findDOMNode(this.refs.appRoot);
- TooltipManager.addEventListeners(appRootElement);
- SelectionManager.onClearSelection = () => {
- if (this.state.item) {
- CatalogItemsActions.catalogItemMetaDataChanged.defer(this.state.item);
- }
- };
- },
- componentDidUpdate() {
- if (this.state.fullScreenMode) {
- document.body.classList.add('-is-full-screen');
- } else {
- document.body.classList.remove('-is-full-screen');
- }
- SelectionManager.refreshOutline();
- },
- resize(e) {
- PanelResizeAction.resize(e);
- },
- getModel() {
- let html;
- let self = this;
- DescriptorModelMetaFactory.init().then(function(){
+ // resizeManager automatically registered its event handlers
+ resizeManager.removeAllEventListeners();
+ ComposerAppStore.unlisten(this.onChange);
+ CatalogDataStore.unlisten(this.onCatalogDataChanged);
+ DeletionManager.removeEventListeners();
+ TooltipManager.removeEventListeners();
+ },
+ componentDidMount() {
+ resizeManager.addAllEventListeners();
+ const snapshot = window.localStorage.getItem('composer');
+ if (snapshot) {
+ alt.bootstrap(snapshot);
+ }
+ document.body.addEventListener('keydown', (event) => {
+ // prevent details editor form from blowing up the app
+ const ENTER_KEY = 13;
+ if (event.which === ENTER_KEY) {
+ event.preventDefault();
+ return false;
+ }
+ });
+ const appRootElement = ReactDOM.findDOMNode(this.refs.appRoot);
+ TooltipManager.addEventListeners(appRootElement);
+ SelectionManager.onClearSelection = () => {
+ if (this.state.item) {
+ CatalogItemsActions.catalogItemMetaDataChanged.defer(this.state.item);
+ }
+ };
+ },
+ componentDidUpdate() {
+ if (this.state.fullScreenMode) {
+ document.body.classList.add('-is-full-screen');
+ } else {
+ document.body.classList.remove('-is-full-screen');
+ }
+ SelectionManager.refreshOutline();
+ },
+ resize(e) {
+ PanelResizeAction.resize(e);
+ },
+ getModel() {
+ let html;
+ let self = this;
+ DescriptorModelMetaFactory.init().then(function(){
- self.setState({
- hasModel: true
- })
- });
- },
- render() {
- let html = null;
- let self = this;
- if(this.state.hasModel) {
+ self.setState({
+ hasModel: true
+ })
+ });
+ },
+ render() {
+ let html = null;
+ let self = this;
+ if(this.state.hasModel) {
- function onClickUpdateSelection(event) {
- if (event.defaultPrevented) {
- return
- }
- const element = SelectionManager.getClosestElementWithUID(event.target);
- if (element) {
- SelectionManager.select(element);
- SelectionManager.refreshOutline();
- event.preventDefault();
- } else {
- SelectionManager.clearSelectionAndRemoveOutline();
- }
- }
+ function onClickUpdateSelection(event) {
+ if (event.defaultPrevented) {
+ return
+ }
+ const element = SelectionManager.getClosestElementWithUID(event.target);
+ if (element) {
+ SelectionManager.select(element);
+ SelectionManager.refreshOutline();
+ event.preventDefault();
+ } else {
+ if(event.target.offsetParent && !event.target.offsetParent.classList.contains("tray-body")) {
+ SelectionManager.clearSelectionAndRemoveOutline();
+ }
+ }
+ }
- let cpNumber = 0;
- let AppHeader = (<div className="AppHeader">
- <RiftHeader />
- </div>);
- // AppHeader = null;
- const classNames = ClassNames('ComposerApp');
- const isNew = self.state.item && self.state.item.uiState.isNew;
- const hasItem = self.state.item && self.state.item.uiState;
- const isModified = self.state.item && self.state.item.uiState.modified;
- const isEditingNSD = self.state.item && self.state.item.uiState && /nsd/.test(self.state.item.uiState.type);
- const isEditingVNFD = self.state.item && self.state.item.uiState && /vnfd/.test(self.state.item.uiState.type);
- const containers = [self.state.item].reduce(DescriptorModelFactory.buildCatalogItemFactory(CatalogDataStore.getState().catalogs), []);
+ let cpNumber = 0;
+ let AppHeader = (<div className="AppHeader">
+ <RiftHeader />
+ </div>);
+ // AppHeader = null;
+ const classNames = ClassNames('ComposerApp');
+ const isNew = self.state.item && self.state.item.uiState.isNew;
+ const hasItem = self.state.item && self.state.item.uiState;
+ const isModified = self.state.item && self.state.item.uiState.modified;
+ const isEditingNSD = self.state.item && self.state.item.uiState && /nsd/.test(self.state.item.uiState.type);
+ const isEditingVNFD = self.state.item && self.state.item.uiState && /vnfd/.test(self.state.item.uiState.type);
+ const containers = [self.state.item].reduce(DescriptorModelFactory.buildCatalogItemFactory(CatalogDataStore.getState().catalogs), []);
- containers.filter(d => DescriptorModelFactory.isConnectionPoint(d)).forEach(d => {
- d.cpNumber = ++cpNumber;
- containers.filter(d => DescriptorModelFactory.isVnfdConnectionPointRef(d)).filter(ref => ref.key === d.key).forEach(ref => ref.cpNumber = d.cpNumber);
- });
- const canvasTitle = containers.length ? containers[0].model.name : '';
- const hasNoCatalogs = CatalogDataStore.getState().catalogs.length === 0;
- const isLoading = self.state.isLoading;
+ containers.filter(d => DescriptorModelFactory.isConnectionPoint(d)).forEach(d => {
+ d.cpNumber = ++cpNumber;
+ containers.filter(d => DescriptorModelFactory.isVnfdConnectionPointRef(d)).filter(ref => ref.key === d.key).forEach(ref => ref.cpNumber = d.cpNumber);
+ });
+ const canvasTitle = containers.length ? containers[0].model.name : '';
+ const hasNoCatalogs = CatalogDataStore.getState().catalogs.length === 0;
+ const isLoading = self.state.isLoading;
//Bridge element for Crouton fix. Should eventually put Composer on same flux context
const Bridge = this.state.ComponentBridgeElement;
- html = (
- <div ref="appRoot" id="RIFT_wareLaunchpadComposerAppRoot" className="AppRoot" onClick={onClickUpdateSelection}>
+ html = (
+ <div ref="appRoot" id="RIFT_wareLaunchpadComposerAppRoot" className="AppRoot" onClick={onClickUpdateSelection}>
<Bridge />
- <i className="corner-accent top left" />
- <i className="corner-accent top right" />
- <i className="corner-accent bottom left" />
- <i className="corner-accent bottom right" />
- {AppHeader}
- <div className="AppBody">
- <div className={classNames}>
- <CatalogPanel layout={self.state.layout}
- isLoading={isLoading}
- hasNoCatalogs={hasNoCatalogs}
- filterByType={self.state.filterCatalogByTypeValue} />
- <CanvasPanel layout={self.state.layout}
- hasNoCatalogs={hasNoCatalogs}
- showMore={self.state.showMore}
- containers={containers}
- title={canvasTitle}
- zoom={self.state.zoom}
- panelTabShown={self.state.panelTabShown}
- files={self.state.files}
- filesState={self.state.filesState}
- item={self.state.item}
- type={self.state.filterCatalogByTypeValue}
- displayedPanel={self.state.displayedPanel}
- />
- {
- (self.state.panelTabShown == 'descriptor') ?
- <DetailsPanel layout={self.state.layout}
- hasNoCatalogs={hasNoCatalogs}
- showMore={self.state.showMore}
- containers={containers}
- showJSONViewer={self.state.showJSONViewer} />
- : null
- }
+ <i className="corner-accent top left" />
+ <i className="corner-accent top right" />
+ <i className="corner-accent bottom left" />
+ <i className="corner-accent bottom right" />
+ {AppHeader}
+ <div className="AppBody">
+ <div className={classNames}>
+ <CatalogPanel layout={self.state.layout}
+ isLoading={isLoading}
+ hasNoCatalogs={hasNoCatalogs}
+ filterByType={self.state.filterCatalogByTypeValue} />
+ <CanvasPanel layout={self.state.layout}
+ hasNoCatalogs={hasNoCatalogs}
+ showMore={self.state.showMore}
+ containers={containers}
+ title={canvasTitle}
+ zoom={self.state.zoom}
+ panelTabShown={self.state.panelTabShown}
+ files={self.state.files}
+ filesState={self.state.filesState}
+ item={self.state.item}
+ type={self.state.filterCatalogByTypeValue}
+ displayedPanel={self.state.displayedPanel}
+ />
+ {
+ (self.state.panelTabShown == 'descriptor') ?
+ <DetailsPanel layout={self.state.layout}
+ hasNoCatalogs={hasNoCatalogs}
+ showMore={self.state.showMore}
+ containers={containers}
+ showJSONViewer={self.state.showJSONViewer} />
+ : null
+ }
- <ComposerAppToolbar layout={self.state.layout}
- showMore={self.state.showMore}
- isEditingNSD={isEditingNSD}
- isEditingVNFD={isEditingVNFD}
- isModified={isModified}
- isNew={isNew}
- disabled={!hasItem}
- onClick={event => event.stopPropagation()}
- panelTabShown={self.state.panelTabShown}/>
- </div>
- </div>
- <ModalOverlay />
- </div>
- );
- } else {
- this.getModel();
- }
- return html;
- },
- onChange(state) {
- this.setState(state);
- },
- onCatalogDataChanged(catalogDataState) {
- const catalogs = catalogDataState.catalogs;
- const unsavedChanges = catalogs.reduce((result, catalog) => {
- if (result) {
- return result;
- }
- return catalog.descriptors.reduce((result, descriptor) => {
- if (result) {
- return result;
- }
- return descriptor.uiState.modified;
- }, false);
- }, false);
- this.setState({
- unsavedChanges: unsavedChanges,
- isLoading: catalogDataState.isLoading
- });
- },
- onBeforeUnload() {
- // https://trello.com/c/c8v321Xx/160-prompt-user-to-save-changes
- //const snapshot = alt.takeSnapshot();
- //window.localStorage.setItem('composer', snapshot);
- if (this.state.unsavedChanges) {
- return 'You have unsaved changes. If you do not onboard (or update) your changes they will be lost.';
- }
- }
+ <ComposerAppToolbar layout={self.state.layout}
+ showMore={self.state.showMore}
+ isEditingNSD={isEditingNSD}
+ isEditingVNFD={isEditingVNFD}
+ isModified={isModified}
+ isNew={isNew}
+ disabled={!hasItem}
+ onClick={event => event.stopPropagation()}
+ panelTabShown={self.state.panelTabShown}/>
+ </div>
+ </div>
+ <ModalOverlay />
+ </div>
+ );
+ } else {
+ this.getModel();
+ }
+ return html;
+ },
+ onChange(state) {
+ this.setState(state);
+ },
+ onCatalogDataChanged(catalogDataState) {
+ const catalogs = catalogDataState.catalogs;
+ const unsavedChanges = catalogs.reduce((result, catalog) => {
+ if (result) {
+ return result;
+ }
+ return catalog.descriptors.reduce((result, descriptor) => {
+ if (result) {
+ return result;
+ }
+ return descriptor.uiState.modified;
+ }, false);
+ }, false);
+ this.setState({
+ unsavedChanges: unsavedChanges,
+ isLoading: catalogDataState.isLoading
+ });
+ },
+ onBeforeUnload() {
+ // https://trello.com/c/c8v321Xx/160-prompt-user-to-save-changes
+ //const snapshot = alt.takeSnapshot();
+ //window.localStorage.setItem('composer', snapshot);
+ if (this.state.unsavedChanges) {
+ return 'You have unsaved changes. If you do not onboard (or update) your changes they will be lost.';
+ }
+ }
});
'use strict';
+import _ from 'lodash'
import d3 from 'd3'
import React from 'react'
import Range from '../Range'
import imgConnection from '../../../../node_modules/open-iconic/svg/random.svg'
import imgClassifier from '../../../../node_modules/open-iconic/svg/spreadsheet.svg'
import imgReorder from '../../../../node_modules/open-iconic/svg/menu.svg'
-import EditConfigParameterMap from '../EditConfigParameterMap'
+import CatalogDataStore from '../../stores/CatalogDataStore'
+import utils from '../../libraries/utils'
+import getEventPath from '../../libraries/getEventPath'
+import guid from '../../libraries/guid'
+
+import '../../styles/EditDescriptorModelProperties.scss'
+import '../../styles/EditConfigParameterMap.scss';
+
function configParameterMapMap(ap, i) {
const context = this;
}
+
+function startEditing() {
+ event.stopPropagation();
+ DeletionManager.removeEventListeners();
+ }
+
+function endEditing() {
+ DeletionManager.addEventListeners();
+}
+
+
const ConfigPrimitiveParameters = React.createClass({
mixins: [PureRenderMixin],
getInitialState: function () {
render() {
const self = this;
const containers = this.props.containers;
+ let NSContainer = containers.filter(function(c) {
+ return c.className == "NetworkService"
+ })[0]
const context = {
component: this,
containers: containers
if (networkService.length === 0) {
return <p className="welcome-message">No <img src={imgNSD} width="20px" /> NSD open in the canvas. Try opening an NSD.</p>;
}
+ let MapData = constructRequestSourceData(containers);
+ let mapCounter = 1;
+
+
+
return (
<div className="ConfigParameterMap">
<div className="config-parameter-map">
Source
</div>
</div>
- {
- containers.map(function(c, i) {
- if(c.className == 'ConfigParameterMap') {
- return <EditConfigParameterMap key={i} container={c} width={self.props.width} />
- }
- })
- }
- <div className="toggle-bottom-spacer" style={{visibility: 'hidden', 'height': '50%', position: 'absolute'}}>We need this so when the user closes the panel it won't shift away and scare the bj out of them!</div>
+ <div className="config-parameter-map">
+ {
+ MapData.Requests.map(function(r, i) {
+ let currentValue = {};
+ let SourceOptions = [<option value={JSON.stringify({
+ requestValue: r.name,
+ requestIndex: r.vnfdIndex
+ })} key="reset">No Source Selected</option>]
+ MapData.Sources.map(function(s, j) {
+ let value = {
+ value: s.name,
+ index: s.vnfdIndex,
+ requestValue: r.name,
+ requestIndex: r.vnfdIndex
+ }
+ SourceOptions.push(<option value={JSON.stringify(value)} key={`${j}-${i}`} >{`${s.vnfdName} (${s.vnfdIndex}) / ${s.name}`}</option>)
+ })
+ //Finds current value
+ NSContainer.model['config-parameter-map'] && NSContainer.model['config-parameter-map'].map((c)=>{
+ if(
+ c['config-parameter-request'] &&
+ (c['config-parameter-request']['config-parameter-request-ref'] == r.name)
+ && (c['config-parameter-request']['member-vnf-index-ref'] == r.vnfdIndex)
+ ) {
+ currentValue = {
+ value: c['config-parameter-source']['config-parameter-source-ref'],
+ index: c['config-parameter-source']['member-vnf-index-ref'],
+ requestValue: r.name,
+ requestIndex: r.vnfdIndex
+ };
+ }
+ })
+ currentValue.hasOwnProperty('value') ? mapCounter++ : mapCounter--;
+ let currentMapIndex = (mapCounter > 0) ? (mapCounter) - 1: 0;
+ return (
+ <div key={i} className="EditDescriptorModelProperties -is-tree-view config-parameter config-parameter-group">
+ <div className="config-parameter-request" >{`${r.vnfdName} (${r.vnfdIndex}) / ${r.parameter && r.parameter[0]['config-primitive-name-ref']} / ${r.parameter && r.parameter[0]['config-primitive-parameter-ref']}`}</div>
+ <div className="config-parameter-source">
+ <select
+ onChange={onFormFieldValueChanged.bind(NSContainer, i)}
+ onBlur={endEditing}
+ onMouseDown={startEditing}
+ onMouseOver={startEditing}
+ value={JSON.stringify(currentValue)}
+ >
+ }
+ {SourceOptions}
+ </select>
+ </div>
+ </div>
+ )
+ })
+ }
+ </div>
</div>
</div>
)
}
});
+ function onFormFieldValueChanged(index, event) {
+ if (DescriptorModelFactory.isContainer(this)) {
+ event.preventDefault();
+ const name = event.target.name;
+ const value = JSON.parse(event.target.value);
+
+ let ConfigMap = utils.resolvePath(this.model, 'config-parameter-map');
+ let ConfigMapIndex = false;
+ let id = guid().substring(0, 8);
+ //Check current map, if request is present, assign map index.
+ ConfigMap.map(function(c, i) {
+ let req = c['config-parameter-request'];
+ if((req['config-parameter-request-ref'] == value.requestValue) &&
+ (req['member-vnf-index-ref'] == value.requestIndex)) {
+ ConfigMapIndex = i;
+ id = c.id;
+ }
+ });
+ if(!ConfigMapIndex && _.isBoolean(ConfigMapIndex)) {
+ ConfigMapIndex = ConfigMap.length;
+ }
+ if(value.value) {
+ utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.config-parameter-source.config-parameter-source-ref', value.value);
+ utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.config-parameter-source.member-vnf-index-ref', value.index);
+ utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.config-parameter-request.config-parameter-request-ref', value.requestValue);
+ utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.config-parameter-request.member-vnf-index-ref', value.requestIndex);
+ utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.id', id);
+ CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot());
+ } else {
+ utils.removePathValue(this.model, 'config-parameter-map.' + ConfigMapIndex)
+ CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot());
+
+ }
+ }
+ }
+
+
+//Values from
+//
+
+//To update
+//Container:NSD
+//path
+//["config-parameter", "config-parameter-source"]
+//{config-parameter-source-ref: "service_port", member-vnf-index-ref: 2}
+
+function constructRequestSourceData(containers) {
+ let cds = CatalogDataStore;
+ let catalogs = cds.getTransientCatalogs();
+ let Requests = [];
+ let Sources = [];
+ let vnfdData = {
+ index:[],
+ vnfdIDs:[],
+ indexRefs: {},
+ vnfdRefs:{}
+ };
+
+ //Init VNFD map
+ //{
+ //
+ // index:[1], //member-vnfd-index-ref
+ // vnfdIDs:[],
+ // indexRefs: {
+ // 1: vnfdID
+ // },
+ // vnfdRefs: {
+ // {1.id} : {...}
+ // }
+ //}
+
+ containers.map(function(c, i) {
+ if(c.className == 'ConstituentVnfd') {
+ vnfdData.index.push(c.vnfdIndex);
+ vnfdData.vnfdIDs.push(c.vnfdId);
+ vnfdData.indexRefs[c.vnfdIndex] = c.vnfdId;
+ vnfdData.vnfdRefs[c.vnfdId] = {
+ id: c.vnfdId,
+ name: c.name,
+ 'short-name': c['short-name']
+ };
+ }
+ });
+
+ //Decorate VNFDMap with descriptor data;
+ catalogs[1].descriptors
+ .filter((v) => vnfdData.vnfdIDs.indexOf(v.id) > -1)
+ .map(constructVnfdMap.bind(this, vnfdData));
+
+
+ vnfdData.index.map(function(vnfdIndex) {
+ let vnfdId = vnfdData.indexRefs[vnfdIndex];
+ let vnfd = vnfdData.vnfdRefs[vnfdId];
+ let vnfdShortName = vnfd['short-name'];
+ vnfd.requests && vnfd.requests.map(function(request) {
+ Requests.push(_.merge({
+ id: vnfdId,
+ vnfdIndex: vnfdIndex,
+ vnfdName: vnfdShortName,
+ }, request))
+ });
+ vnfd.sources && vnfd.sources.map(function(source) {
+ Sources.push(_.merge({
+ id: vnfdId,
+ vnfdIndex: vnfdIndex,
+ vnfdName: vnfdShortName,
+ }, source));
+ });
+ })
+
+ return {Requests, Sources};
+
+ function constructVnfdMap(vnfdData, vnfd) {
+ let data = {
+ requests: vnfd['config-parameter']['config-parameter-request'],
+ sources: vnfd['config-parameter']['config-parameter-source']
+ };
+ vnfdData.vnfdRefs[vnfd.id] = _.merge(vnfdData.vnfdRefs[vnfd.id], data);
+ }
+
+}
+
export default ConfigPrimitiveParameters;
-//<EditDescriptorModelProperties container={DescriptorModelMetaFactory.createModelInstanceForType('nsd.vnffgd.rsp')} width={this.props.width} />