diff options
author | AviZi <avi.ziv@amdocs.com> | 2017-06-09 02:39:56 +0300 |
---|---|---|
committer | AviZi <avi.ziv@amdocs.com> | 2017-06-09 02:39:56 +0300 |
commit | 280f8015d06af1f41a3ef12e8300801c7a5e0d54 (patch) | |
tree | 9c1d3978c04cd28068f02073038c936bb49ca9e0 /openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies | |
parent | fd3821dad11780d33c5373d74c957c442489945e (diff) |
[SDC-29] Amdocs OnBoard 1707 initial commit.
Change-Id: Ie4d12a3f574008b792899b368a0902a8b46b5370
Signed-off-by: AviZi <avi.ziv@amdocs.com>
Diffstat (limited to 'openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies')
6 files changed, 325 insertions, 0 deletions
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js new file mode 100644 index 0000000000..9540d3f869 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js @@ -0,0 +1,40 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + */ +import {connect} from 'react-redux'; + +import SoftwareProductDependenciesView from './SoftwareProductDependenciesView.jsx'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; +import SoftwareProductDependenciesActionHelper from './SoftwareProductDependenciesActionHelper.js'; + +export const mapStateToProps = ({softwareProduct}) => { + let {softwareProductEditor: {data: currentSoftwareProduct = {}}, softwareProductDependencies, softwareProductComponents: {componentsList}} = softwareProduct; + let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); + return { + isReadOnlyMode, + softwareProductDependencies: softwareProductDependencies.length ? softwareProductDependencies : [{sourceId: '', targetId: '', relationType: 'dependsOn', id: 'fake'}], + componentsOptions: componentsList.map(component => ({value: component.id, label: component.name})) + }; +}; + +const mapActionsToProps = (dispatch, {softwareProductId, version}) => { + return { + onDataChanged: dependenciesList => SoftwareProductDependenciesActionHelper.updateDependencyList(dispatch, {dependenciesList}), + onAddDependency: () => SoftwareProductDependenciesActionHelper.addDependency(dispatch), + onSubmit: (dependenciesList) => SoftwareProductDependenciesActionHelper.saveDependencies(dispatch, {softwareProductId, version, dependenciesList}) + }; +}; + +export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductDependenciesView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesActionHelper.js new file mode 100644 index 0000000000..e47b33a577 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesActionHelper.js @@ -0,0 +1,58 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + */ +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import {actionTypes} from './SoftwareProductDependenciesConstants.js'; +import uuid from 'uuid-js'; + +function baseUrl(softwareProductId, version) { + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/component-dependency-model`; +} + +function fetchDependency(softwareProductId, version) { + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); +} + +function postDependency(softwareProductId, version, dependenciesList) { + let modifedDependencyList = dependenciesList ? dependenciesList.filter(item => item.sourceId && item.targetId) + .map(item => ({sourceId: item.sourceId, targetId: item.targetId, relationType: item.relationType})) : []; + return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, {componentDependencyModels:modifedDependencyList}); +} + +const SoftwareProductDependenciesActionHelper = { + updateDependencyList(dispatch, {dependenciesList}) { + dispatch({type: actionTypes.SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE, dependenciesList}); + }, + addDependency(dispatch) { + dispatch({type: actionTypes.ADD_SOFTWARE_PRODUCT_DEPENDENCY}); + }, + fetchDependencies(dispatch, {softwareProductId, version}) { + return fetchDependency(softwareProductId, version).then( response => { + const dependenciesList = response.results ? response.results.map(item => {return {...item, id: uuid.create().toString()};}) : []; + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE, + dependenciesList + }); + }); + }, + saveDependencies(dispatch, {softwareProductId, version, dependenciesList}) { + return postDependency(softwareProductId, version, dependenciesList); + } +}; + +export default SoftwareProductDependenciesActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesConstants.js new file mode 100644 index 0000000000..1f27ed8311 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesConstants.js @@ -0,0 +1,29 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + */ +import keyMirror from 'nfvo-utils/KeyMirror.js'; + +export const actionTypes = keyMirror({ + SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE: null, + ADD_SOFTWARE_PRODUCT_DEPENDENCY: null +}); + +export const relationTypes = { + DEPENDS_ON: 'dependsOn' +}; + +export const relationTypesOptions = [ + {value: relationTypes.DEPENDS_ON, label: 'Depends On'} +]; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesReducer.js new file mode 100644 index 0000000000..3fb479eedc --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesReducer.js @@ -0,0 +1,36 @@ + +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + */ + +import {actionTypes, relationTypes} from './SoftwareProductDependenciesConstants.js'; +import {checkCyclesAndMarkDependencies} from './SoftwareProductDependenciesUtils.js'; +import uuid from 'uuid-js'; + +export default (state = [], action) => { + switch (action.type) { + case actionTypes.SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE: + return checkCyclesAndMarkDependencies(action.dependenciesList); + case actionTypes.ADD_SOFTWARE_PRODUCT_DEPENDENCY: + return [...state, { + sourceId: null, + relationType: relationTypes.DEPENDS_ON, + targetId: null, + id: uuid.create() + }]; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesUtils.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesUtils.js new file mode 100644 index 0000000000..94d21bd49d --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesUtils.js @@ -0,0 +1,64 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + */ + +import DirectedGraph from 'nfvo-utils/DirectedGraph.js'; + +function findCycles(graph, node, id, visited = {}, visitedConnections = {}, recursionStack = {}, connectionsWithCycle = {}) { + visited[node] = true; + recursionStack[node] = true; + if (id) { + visitedConnections[id] = true; + } + for (let edge of graph.getEdges(node)) { + if (!visited[edge.target]) { + findCycles(graph, edge.target, edge.id, visited, visitedConnections, recursionStack, connectionsWithCycle); + } else if (recursionStack[edge.target]) { + visitedConnections[edge.id] = true; + for (let connection in visitedConnections) { + connectionsWithCycle[connection] = true; + } + } + } + recursionStack[node] = false; + return {visitedNodes: visited, connectionsWithCycle: connectionsWithCycle}; +} + +export function checkCyclesAndMarkDependencies(dependenciesList) { + let overallVisitedNodes = {}; + let overallConnectionsWithCycles = {}; + + let g = new DirectedGraph(); + for (let dependency of dependenciesList) { + if (dependency.sourceId !== null && dependency.targetId !== null) { + g.addEdge(dependency.sourceId, dependency.targetId, {id: dependency.id}); + } + } + + for (let node in g.nodes) { + if (!overallVisitedNodes.node) { + let {visitedNodes, connectionsWithCycle} = findCycles(g, node, undefined); + overallVisitedNodes = {...overallVisitedNodes, ...visitedNodes}; + overallConnectionsWithCycles = {...overallConnectionsWithCycles, ...connectionsWithCycle}; + } + } + return dependenciesList.map(dependency => ( + { + ...dependency, + hasCycle: dependency.sourceId && dependency.targetId ? + overallConnectionsWithCycles.hasOwnProperty(dependency.id) + : undefined + })); +} diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx new file mode 100644 index 0000000000..da975a7be2 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx @@ -0,0 +1,98 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + */ + +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +import SelectActionTable from 'nfvo-components/table/SelectActionTable.jsx'; +import SelectActionTableRow from 'nfvo-components/table/SelectActionTableRow.jsx'; +import SelectActionTableCell from 'nfvo-components/table/SelectActionTableCell.jsx'; +import {relationTypesOptions} from './SoftwareProductDependenciesConstants.js'; + +export default class SoftwareProductDependenciesView extends React.Component { + filterTargets({componentsOptions, sourceToTargetMapping, selectedSourceId, selectedTargetId}) { + let isInMap = sourceToTargetMapping.hasOwnProperty(selectedSourceId); + return componentsOptions.filter(component => { + if (component.value === selectedTargetId) { + return true; + } else { + return component.value !== selectedSourceId && (isInMap ? sourceToTargetMapping[selectedSourceId].indexOf(component.value) < 0 : true); + } + }); + } + + filterSources({componentsOptions, sourceToTargetMapping, selectedSourceId, selectedTargetId}) { + return componentsOptions.filter(component => { + if (component.value === selectedSourceId) { + return true; + } else { + let isInMap = sourceToTargetMapping.hasOwnProperty(component.value); + return component.value !== selectedTargetId && (isInMap ? sourceToTargetMapping[component.value].indexOf(selectedTargetId) < 0 : true); + } + }); + } + + render() { + let {componentsOptions, softwareProductDependencies, onDataChanged, onAddDependency, isReadOnlyMode} = this.props; + let canAdd = softwareProductDependencies.length < componentsOptions.length * (componentsOptions.length - 1); + let sourceToTargetMapping = {}; + softwareProductDependencies.map(dependency => { + let isInMap = sourceToTargetMapping.hasOwnProperty(dependency.sourceId); + if (dependency.targetId) { + sourceToTargetMapping[dependency.sourceId] = isInMap ? [...sourceToTargetMapping[dependency.sourceId], dependency.targetId] : [dependency.targetId]; + } + }); + return ( + <div className='software-product-dependencies'> + <div className='software-product-dependencies-title'>{i18n('Dependencies')}</div> + <SelectActionTable + columns={['Source', 'Relation Type', 'Target']} + isReadOnlyMode={isReadOnlyMode} + onAdd={canAdd ? onAddDependency : undefined} + onAddItem={i18n('Add Rule')}> + {softwareProductDependencies.map(dependency => ( + <SelectActionTableRow + key={dependency.id} + onDelete={() => onDataChanged(softwareProductDependencies.filter(currentDependency => currentDependency.id !== dependency.id))} + overlayMsg={i18n('There is a loop between selections')} + hasError={dependency.hasCycle}> + <SelectActionTableCell + options={this.filterSources({componentsOptions, sourceToTargetMapping, selectedSourceId: dependency.sourceId, selectedTargetId: dependency.targetId})} + selected={dependency.sourceId} + placeholder={i18n('Select VFC...')} + onChange={newSourceId => onDataChanged(softwareProductDependencies.map(currentDependency => + ({...currentDependency, sourceId: currentDependency.id === dependency.id ? newSourceId : currentDependency.sourceId}) + ))} /> + <SelectActionTableCell options={relationTypesOptions} selected={dependency.relationType} clearable={false}/> + <SelectActionTableCell + placeholder={i18n('Select VFC...')} + options={this.filterTargets({componentsOptions, sourceToTargetMapping, selectedSourceId: dependency.sourceId, selectedTargetId: dependency.targetId})} + selected={dependency.targetId} + onChange={newTargetId => onDataChanged(softwareProductDependencies.map(currentDependency => + ({...currentDependency, targetId: currentDependency.id === dependency.id ? newTargetId : currentDependency.targetId}) + ))} /> + </SelectActionTableRow> + ))} + </SelectActionTable> + </div> + ); + } + + save() { + let {onSubmit, softwareProductDependencies} = this.props; + return onSubmit(softwareProductDependencies); + } +} |