diff options
Diffstat (limited to 'openecomp-ui/src/sdc-app/heatvalidation')
9 files changed, 837 insertions, 0 deletions
diff --git a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreen.jsx b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreen.jsx new file mode 100644 index 0000000000..0bb496fc51 --- /dev/null +++ b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreen.jsx @@ -0,0 +1,182 @@ +import React from 'react'; +import {connect} from 'react-redux'; +import Button from 'react-bootstrap/lib/Button.js'; +import Dropzone from 'react-dropzone'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import ProgressBar from 'nfvo-components/progressBar/ProgressBar.jsx'; +import Modal from 'nfvo-components/modal/Modal.jsx'; +import UploadScreenActionHelper from './UploadScreenActionHelper.js'; +import Attachments from './attachments/Attachments.js'; + +const mapStateToProps = ({uploadScreen}) => { + let {upload} = uploadScreen; + return {uploadScreen: upload}; +}; + + +const mapActionsToProps = dispatch => { + return { + onUpload: (formData) => UploadScreenActionHelper.uploadFile(dispatch, formData), + openMainScreen: () => UploadScreenActionHelper.openMainScreen(dispatch) + }; +}; + + +class UploadScreen extends React.Component { + + state = { + complete: '10', + showModal: false, + fileName: '', + dragging: false, + files: [] + }; + + interval = ''; + + render() { + let {uploadScreen} = this.props; + let {showAttachments} = uploadScreen; + return( + <div className='heat-validation-stand-alone'> + {showAttachments ? this.renderTree() : this.renderUploadScreen()} + </div> + ); + } + + renderUploadModal() { + let {complete, showModal, fileName} = this.state; + return ( + <Modal show={showModal} animation={true}> + <Modal.Header> + <Modal.Title>{i18n('Uploading attachments')}</Modal.Title> + </Modal.Header> + <Modal.Body> + <div className='upload-modal-body-content'> + <div> + <span className='title'>{i18n('File:')}</span> + <span className='file-name'>{fileName}</span> + </div> + <ProgressBar now={complete} label={`${complete}%`}/> + <div>{i18n('Upload in progress')}</div> + </div> + <Modal.Footer> + <Button bsStyle='primary' onClick={() => this.onRunBackground()}> + {i18n('Run in Background')} + </Button> + <Button bsStyle='primary' onClick={() => this.onCancel()}>{i18n('Cancel')}</Button> + </Modal.Footer> + </Modal.Body> + </Modal> + ); + } + + renderUploadScreen() { + return( + <div className='upload-screen'> + <div className='row'> + <div className='title'> + <h1>HEAT VALIDATION APPLICATION</h1> + </div> + </div> + <div className='row'> + <div className='col-md-2 col-md-offset-5'> + <Dropzone + className={`upload-screen-drop-zone ${this.state.dragging ? 'active-dragging' : ''}`} + onDrop={files => this.handleImportSubmit(files)} + onDragEnter={() => this.setState({dragging:true})} + onDragLeave={() => this.setState({dragging:false})} + multiple={false} + disableClick={true} + ref='fileInput' + name='fileInput' + accept='.zip'> + <div + className='upload-screen-upload-block'> + <div className='drag-text'>{i18n('Drag & drop for upload')}</div> + <div className='or-text'>{i18n('or')}</div> + <div className='upload-btn primary-btn' onClick={() => this.refs.fileInput.open()}> + <span className='primary-btn-text'>{i18n('Select file')}</span> + </div> + </div> + </Dropzone> + </div> + {this.renderUploadModal()} + </div> + </div> + ); + } + + renderTree() { + let {openMainScreen} = this.props; + return( + <div className='attachments-screen'> + <Attachments/> + <div className='back-button'> + <div className='upload-btn primary-btn' onClick={() => openMainScreen()}> + <span className='primary-btn-text'>{i18n('Back')}</span> + </div> + </div> + </div> + ); + } + + handleImportSubmit(files) { + this.setState({ + showModal: true, + fileName: files[0].name, + dragging: false, + complete: '0', + files + }); + + + this.interval = setInterval(() => { + if (this.state.complete >= 90) { + clearInterval(this.interval); + this.setState({ + showModal: false, + fileName: '' + }); + this.startUploading(files); + } else { + this.setState({ + complete: (parseInt(this.state.complete) + 10).toString() + }); + } + }, 20); + + } + + onRunBackground() { + let {files} = this.state; + clearInterval(this.interval); + this.startUploading(files); + this.setState({showModal: false, files: []}); + } + + onCancel() { + clearInterval(this.interval); + this.setState({ + showModal: false, + fileName: '', + files: [] + }); + + } + + startUploading(files) { + let {onUpload} = this.props; + if (!(files && files.length)) { + return; + } + let file = files[0]; + let formData = new FormData(); + formData.append('upload', file); + this.refs.fileInput.value = ''; + onUpload(formData); + } + +} + +export default connect(mapStateToProps, mapActionsToProps)(UploadScreen); diff --git a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js new file mode 100644 index 0000000000..3b8de0f0d4 --- /dev/null +++ b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import NotificationConstants from 'nfvo-components/notifications/NotificationConstants.js'; +import {actionTypes} from './UploadScreenConstants.js'; +import {actionTypes as softwareProductsActionTypes} from '../onboarding/softwareProduct/SoftwareProductConstants.js'; + +function uploadFile(formData) { + return RestAPIUtil.create('/sdc1/feProxy/onboarding-api/v1.0/validation/HEAT/validate', formData); +} + +const UploadScreenActionHelper = { + uploadFile(dispatch, formData) { + + + Promise.resolve() + .then(() => uploadFile(formData)) + .then(response => { + dispatch({ + type: softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED, + response + }); + + dispatch({ + type: actionTypes.OPEN_UPLOAD_SCREEN + }); + }) + .catch(error => { + dispatch({ + type: NotificationConstants.NOTIFY_ERROR, + data: {title: 'File Upload Failed', msg: error.responseJSON.message} + }); + }); + }, + openMainScreen(dispatch) { + dispatch({ + type: actionTypes.OPEN_MAIN_SCREEN + }); + } +}; + +export default UploadScreenActionHelper; diff --git a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenConstants.js b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenConstants.js new file mode 100644 index 0000000000..2766a975ec --- /dev/null +++ b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenConstants.js @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +import keyMirror from 'nfvo-utils/KeyMirror.js'; + +export const actionTypes = keyMirror({ + FILE_UPLOADED: null, + OPEN_UPLOAD_SCREEN: null, + OPEN_ATTACHMENTS_SCREEN: null, + OPEN_MAIN_SCREEN: null +}); diff --git a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenReducer.js b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenReducer.js new file mode 100644 index 0000000000..e73e028233 --- /dev/null +++ b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenReducer.js @@ -0,0 +1,33 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './UploadScreenConstants.js'; + + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.OPEN_UPLOAD_SCREEN: + return {...state, showAttachments: true}; + case actionTypes.OPEN_MAIN_SCREEN: + return {...state, showAttachments: false}; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/heatvalidation/attachments/Attachments.js b/openecomp-ui/src/sdc-app/heatvalidation/attachments/Attachments.js new file mode 100644 index 0000000000..2a6a992844 --- /dev/null +++ b/openecomp-ui/src/sdc-app/heatvalidation/attachments/Attachments.js @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; +import AttachmentsView from './AttachmentsView.jsx'; +import AttachmentsActionHelper from './AttachmentsActionHelper.js'; + + +const mapStateToProps = ({uploadScreen: {attachments}}) => { + let {attachmentsTree = false, hoveredNode, selectedNode, errorList} = attachments; + return { + attachmentsTree, + hoveredNode, + selectedNode, + errorList + }; +}; + +const mapActionsToProps = (dispatch) => { + return { + + toggleExpanded: (path) => AttachmentsActionHelper.toggleExpanded(dispatch, {path}), + onSelectNode: (nodeName) => AttachmentsActionHelper.onSelectNode(dispatch, {nodeName}), + onUnselectNode: () => AttachmentsActionHelper.onUnselectNode(dispatch), + + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(AttachmentsView); diff --git a/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsActionHelper.js b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsActionHelper.js new file mode 100644 index 0000000000..15b0ffa4a9 --- /dev/null +++ b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsActionHelper.js @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './AttachmentsConstants.js'; + +export default { + + toggleExpanded(dispatch, {path}) { + dispatch({ + type: actionTypes.TOGGLE_EXPANDED, + path + }); + }, + + onSelectNode(dispatch, {nodeName}) { + dispatch({ + type: actionTypes.SELECTED_NODE, + nodeName + }); + }, + + onUnselectNode(dispatch) { + dispatch({ + type: actionTypes.UNSELECTED_NODE + }); + } +}; diff --git a/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsConstants.js b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsConstants.js new file mode 100644 index 0000000000..33af476d9c --- /dev/null +++ b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsConstants.js @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +import keyMirror from 'nfvo-utils/KeyMirror.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +export const actionTypes = keyMirror({ + TOGGLE_EXPANDED: null, + SELECTED_NODE: null, + UNSELECTED_NODE: null +}); + +export const errorTypes = keyMirror({ + MISSING_FILE_IN_ZIP: i18n('missing file in zip'), + MISSING_FILE_IN_MANIFEST: i18n('missing file in manifest'), + MISSING_OR_ILLEGAL_FILE_TYPE_IN_MANIFEST: i18n('missing or illegal file type in manifest'), + FILE_IS_YML_WITHOUT_YML_EXTENSION: i18n('file is defined as a heat file but it doesn\'t have .yml or .yaml extension'), + FILE_IS_ENV_WITHOUT_ENV_EXTENSION: i18n('file is defined as an env file but it doesn\'t have .env extension'), + ILLEGAL_YAML_FILE_CONTENT: i18n('illegal yaml file content'), + ILLEGAL_HEAT_YAML_FILE_CONTENT: i18n('illegal HEAT yaml file content'), + MISSING_FILE_NAME_IN_MANIFEST: i18n('a file is written in manifest without file name'), + MISSING_ENV_FILE_IN_ZIP: i18n('missing env file in zip'), + ARTIFACT_NOT_IN_USE: i18n('artifact not in use') +}); + +export const nodeTypes = keyMirror({ + heat: i18n('Heat'), + volume: i18n('Volume'), + network: i18n('Network'), + artifact: i18n('Artifact'), + env: i18n('Environment'), + other: i18n('') +}); + +export const mouseActions = keyMirror({ + MOUSE_BUTTON_CLICK: 0 +}); + diff --git a/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsReducer.js b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsReducer.js new file mode 100644 index 0000000000..01f68aede8 --- /dev/null +++ b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsReducer.js @@ -0,0 +1,199 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +import {actionTypes as softwareProductsActionTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import {actionTypes} from './AttachmentsConstants.js'; + +const mapVolumeData = ({fileName, env, errors}) => ({ + name: fileName, + expanded: true, + type: 'volume', + children: env && [{ + name: env.fileName, + errors: env.errors, + type: 'env' + }], + errors +}); + +const mapNetworkData = ({fileName, env, errors}) => ({ + name: fileName, + expanded: true, + type: 'network', + children: env && [{ + name: env.fileName, + errors: env.errors, + type: 'env' + }], + errors +}); + +const mapArtifactsData = ({fileName, errors}) => ({ + name: fileName, + type: 'artifact', + errors +}); + +const mapOtherData = ({fileName, errors}) => ({ + name: fileName, + type: 'other', + errors +}); + + +const mapHeatData = ({fileName, env, nested, volume, network, artifacts, errors, other}) => ({ + name: fileName, + expanded: true, + type: 'heat', + errors, + children: [ + ...(volume ? volume.map(mapVolumeData) : []), + ...(network ? network.map(mapNetworkData) : []), + ...(env ? [{ + name: env.fileName, + errors: env.errors, + type: 'env' + }] : []), + ...(artifacts ? artifacts.map(mapArtifactsData) : []), + ...(other ? other.map(mapOtherData) : []), + ...(nested ? nested.map(mapHeatData) : []) + ] +}); + +function createErrorList(node, parent, deep = 0, errorList = []) { + if (node.errors) { + errorList.push(...node.errors.map((error) => ({ + errorLevel: error.level, + errorMessage: error.message, + name: node.name, + hasParent: deep > 2, + parentName: parent.name, + type: node.type, + }))); + } + if (node.children && node.children.length) { + node.children.map((child) => createErrorList(child, node, deep + 1, errorList)); + } + return errorList; +} + +const mapValidationDataToTree = validationData => { + let {HEAT, volume, network, artifacts, other} = validationData.importStructure || {}; + return { + children: [ + { + name: 'HEAT', + expanded: true, + type: 'heat', + children: (HEAT ? HEAT.map(mapHeatData) : []) + }, + ...(artifacts ? [{ + name: 'artifacts', + expanded: true, + type: 'artifact', + children: (artifacts ? artifacts.map(mapArtifactsData) : []) + }] : []), + ...(network ? [{ + name: 'networks', + expanded: true, + type: 'network', + children: (network ? network.map(mapNetworkData) : []), + }] : []), + ...(volume ? [{ + name: 'volume', + expanded: true, + type: 'volume', + children: (volume ? volume.map(mapVolumeData) : []), + }] : []), + ...(other ? [{ + name: 'other', + expanded: true, + type: 'other', + children: (other ? other.map(mapOtherData) : []), + }] : []) + ] + }; +}; + +const toggleExpanded = (node, path) => { + let newNode = {...node}; + if (path.length === 0) { + newNode.expanded = !node.expanded; + } else { + let index = path[0]; + newNode.children = [ + ...node.children.slice(0, index), + toggleExpanded(node.children[index], path.slice(1)), + ...node.children.slice(index + 1) + ]; + } + return newNode; +}; + +const expandSelected = (node, selectedNode) => { + let shouldExpand = node.name === selectedNode; + let children = node.children && node.children.map(child => { + let {shouldExpand: shouldExpandChild, node: newChild} = expandSelected(child, selectedNode); + shouldExpand = shouldExpand || shouldExpandChild; + return newChild; + }); + + return { + node: { + ...node, + expanded: node.expanded || shouldExpand, + children + }, + shouldExpand + }; +}; + +export default (state = {attachmentsTree: {}}, action) => { + switch (action.type) { + case softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED: + let currentSoftwareProduct = action.response; + let attachmentsTree = currentSoftwareProduct.validationData ? mapValidationDataToTree(currentSoftwareProduct.validationData) : {}; + let errorList = createErrorList(attachmentsTree); + return { + ...state, + attachmentsTree, + errorList + }; + case actionTypes.TOGGLE_EXPANDED: + return { + ...state, + attachmentsTree: toggleExpanded(state.attachmentsTree, action.path) + }; + case actionTypes.SELECTED_NODE: + let selectedNode = action.nodeName; + return { + ...state, + attachmentsTree: expandSelected(state.attachmentsTree, selectedNode).node, + selectedNode + }; + case actionTypes.UNSELECTED_NODE: + return { + ...state, + selectedNode: undefined + }; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsView.jsx b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsView.jsx new file mode 100644 index 0000000000..7e2dda8d47 --- /dev/null +++ b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsView.jsx @@ -0,0 +1,190 @@ +import React from 'react'; +import FontAwesome from 'react-fontawesome'; +import classNames from 'classnames'; +import Collapse from 'react-bootstrap/lib/Collapse.js'; + +import i18n from 'nfvo-utils/i18n/i18n.js'; +import {nodeTypes, mouseActions} from './AttachmentsConstants'; + +const typeToIcon = Object.freeze({ + heat: 'building-o', + volume: 'database', + network: 'cloud', + artifact: 'gear', + env: 'server', + other: 'cube' +}); + +const leftPanelWidth = 250; + +class SoftwareProductAttachmentsView extends React.Component { + + static propTypes = { + attachmentsTree: React.PropTypes.object.isRequired + }; + state = { + treeWidth: '400', + }; + + render() { + let {attachmentsTree, errorList = []} = this.props; + + let {treeWidth} = this.state; + return ( + <div className='software-product-attachments'> + <div className='software-product-view'> + <div className='software-product-landing-view-right-side'> + <div className='software-product-attachments-main'> + <div className='software-product-attachments-tree' style={{'width' : treeWidth + 'px'}}> + <div className='tree-wrapper'> + { + attachmentsTree && attachmentsTree.children && attachmentsTree.children.map((child, ind) => this.renderNode(child, [ind])) + } + </div> + </div> + <div className='software-product-attachments-separator' onMouseDown={e => this.onChangeTreeWidth(e)} /> + <div className='software-product-attachments-error-list'> + {errorList.length ? this.renderErrorList(errorList) : <div className='no-errors'>{attachmentsTree.children ? + i18n('VALIDATION SUCCESS') : i18n('THERE IS NO HEAT DATA TO PRESENT') }</div>} + </div> + </div> + </div> + </div> + </div> + ); + } + + + + renderNode(node, path) { + let isFolder = node.children && node.children.length > 0; + let {onSelectNode} = this.props; + return ( + <div key={node.name} className='tree-block-inside'> + { + <div onDoubleClick={() => this.props.toggleExpanded(path)} className={this.getTreeRowClassName(node.name)}> + { + isFolder && + <div onClick={() => this.props.toggleExpanded(path)} className={classNames('tree-node-expander', {'tree-node-expander-collapsed': !node.expanded})}> + <FontAwesome name='caret-down'/> + </div> + } + { + + <span className='tree-node-icon'> + <FontAwesome name={typeToIcon[node.type]}/> + </span> + } + { + + <span onClick={() => onSelectNode(node.name)} className={this.getTreeTextClassName(node)}> + {node.name} + </span> + } + </div> + } + { + isFolder && + <Collapse in={node.expanded}> + <div className='tree-node-children'> + { + node.children.map((child, ind) => this.renderNode(child, [...path, ind])) + } + </div> + </Collapse> + } + </div> + ); + } + + createErrorList(errorList, node, parent) { + if (node.errors) { + node.errors.forEach(error => errorList.push({ + error, + name: node.name, + parentName: parent.name, + type: node.type + })); + } + if (node.children && node.children.length) { + node.children.map((child) => this.createErrorList(errorList, child, node)); + } + } + + renderErrorList(errors) { + let prevError = {}; + let {selectedNode} = this.props; + return errors.map(error => { + let isSameNodeError = error.name === prevError.name && error.parentName === prevError.parentName; + prevError = error; + + return ( + <div + key={error.name + error.errorMessage + error.parentName} + + onClick={() => this.selectNode(error.name)} + className={classNames('error-item', {'clicked': selectedNode === error.name, 'shifted': !isSameNodeError})}> + <span className={classNames('error-item-file-type', {'strong': !isSameNodeError})}> + { + error.hasParent ? + i18n('{type} {name} in {parentName}: ', { + type: nodeTypes[error.type], + name: error.name, + parentName: error.parentName + }) : + i18n('{type} {name}: ', { + type: nodeTypes[error.type], + name: error.name + }) + } + </span> + <span className={`error-item-file-type ${error.errorLevel}`}> {error.errorMessage} </span> + </div> + ); + }); + } + + selectNode(currentSelectedNode) { + let {onUnselectNode, onSelectNode, selectedNode} = this.props; + if (currentSelectedNode !== selectedNode) { + onSelectNode(currentSelectedNode); + }else{ + onUnselectNode(); + } + + } + + getTreeRowClassName(name) { + let {hoveredNode, selectedNode} = this.props; + return classNames({ + 'tree-node-row': true, + 'tree-node-selected': name === hoveredNode, + 'tree-node-clicked': name === selectedNode + }); + } + + getTreeTextClassName(node) { + let {selectedNode} = this.props; + return classNames({ + 'tree-element-text': true, + 'error-status': node.errors, + 'error-status-selected': node.name === selectedNode + }); + } + + onChangeTreeWidth(e) { + if (e.button === mouseActions.MOUSE_BUTTON_CLICK) { + let onMouseMove = (e) => { + this.setState({treeWidth: e.clientX - leftPanelWidth}); + }; + let onMouseUp = () => { + document.removeEventListener('mousemove', onMouseMove); + document.removeEventListener('mouseup', onMouseUp); + }; + document.addEventListener('mousemove', onMouseMove); + document.addEventListener('mouseup', onMouseUp); + } + } +} + +export default SoftwareProductAttachmentsView; |