Show missing base template error in UI
[sdc.git] / openecomp-ui / src / sdc-app / onboarding / softwareProduct / attachments / validation / HeatValidationReducer.js
1 /*!
2  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13  * or implied. See the License for the specific language governing
14  * permissions and limitations under the License.
15  */
16 import { actionTypes as softwareProductsActionTypes } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
17 import { actionTypes, nodeFilters } from './HeatValidationConstants.js';
18
19 const mapNestedData = ({ fileName, env, errors }) => ({
20     name: fileName,
21     expanded: true,
22     type: 'heat',
23     children: env && [
24         {
25             name: env.fileName,
26             errors: env.errors,
27             type: 'env'
28         }
29     ],
30     errors
31 });
32
33 const mapVolumeData = ({ fileName, env, errors, nested }) => ({
34     name: fileName,
35     expanded: true,
36     type: 'volume',
37     children: [
38         ...(env
39             ? [
40                   {
41                       name: env.fileName,
42                       errors: env.errors,
43                       type: 'env'
44                   }
45               ]
46             : []),
47         ...(nested ? nested.map(mapNestedData) : [])
48     ],
49     errors
50 });
51
52 const mapNetworkData = ({ fileName, env, errors }) => ({
53     name: fileName,
54     expanded: true,
55     type: 'network',
56     children: env && [
57         {
58             name: env.fileName,
59             errors: env.errors,
60             type: 'env'
61         }
62     ],
63     errors
64 });
65
66 const mapArtifactsData = ({ fileName, errors }) => ({
67     name: fileName,
68     type: 'artifact',
69     errors
70 });
71
72 const mapOtherData = ({ fileName, errors }) => ({
73     name: fileName,
74     type: 'other',
75     errors
76 });
77
78 const mapHeatData = ({
79     fileName,
80     env,
81     nested,
82     volume,
83     network,
84     artifacts,
85     errors,
86     other
87 }) => ({
88     name: fileName,
89     expanded: true,
90     type: 'heat',
91     errors,
92     children: [
93         ...(volume ? volume.map(mapVolumeData) : []),
94         ...(network ? network.map(mapNetworkData) : []),
95         ...(env
96             ? [
97                   {
98                       name: env.fileName,
99                       errors: env.errors,
100                       type: 'env'
101                   }
102               ]
103             : []),
104         ...(artifacts ? artifacts.map(mapArtifactsData) : []),
105         ...(other ? other.map(mapOtherData) : []),
106         ...(nested ? nested.map(mapHeatData) : [])
107     ]
108 });
109
110 function createErrorList(node, parent, deep = 0, errorList = []) {
111     if (node.errors) {
112         errorList.push(
113             ...node.errors.map(error => ({
114                 level: error.level,
115                 errorMessage: error.message,
116                 name: node.name,
117                 hasParent: deep > 2,
118                 parentName: parent.name,
119                 type: node.type
120             }))
121         );
122     }
123     if (node.children && node.children.length) {
124         node.children.map(child =>
125             createErrorList(child, node, deep + 1, errorList)
126         );
127     }
128     return errorList;
129 }
130
131 const mapValidationDataToTree = (validationData, packageName) => {
132     let { errors, heat, nested, volume, network, artifacts, other } =
133         validationData.importStructure || {};
134     return {
135         children: [
136             {
137                 name: packageName,
138                 expanded: true,
139                 type: 'heat',
140                 header: true,
141                 errors: errors,
142                 children: heat
143                     ? heat.map(mapHeatData)
144                     : nested ? nested.map(mapHeatData) : []
145             },
146             ...(artifacts
147                 ? [
148                       {
149                           name: 'artifacts',
150                           expanded: true,
151                           type: 'artifact',
152                           children: artifacts
153                               ? artifacts.map(mapArtifactsData)
154                               : []
155                       }
156                   ]
157                 : []),
158             ...(network
159                 ? [
160                       {
161                           name: 'networks',
162                           expanded: true,
163                           type: 'network',
164                           children: network ? network.map(mapNetworkData) : []
165                       }
166                   ]
167                 : []),
168             ...(volume
169                 ? [
170                       {
171                           name: 'volume',
172                           expanded: true,
173                           type: 'volume',
174                           children: volume ? volume.map(mapVolumeData) : []
175                       }
176                   ]
177                 : []),
178             ...(other
179                 ? [
180                       {
181                           name: 'other',
182                           expanded: true,
183                           type: 'other',
184                           children: other ? other.map(mapOtherData) : []
185                       }
186                   ]
187                 : [])
188         ]
189     };
190 };
191
192 const toggleExpanded = (node, path) => {
193     let newNode = { ...node };
194     if (path.length === 0) {
195         newNode.expanded = !node.expanded;
196     } else {
197         let index = path[0];
198         newNode.children = [
199             ...node.children.slice(0, index),
200             toggleExpanded(node.children[index], path.slice(1)),
201             ...node.children.slice(index + 1)
202         ];
203     }
204     return newNode;
205 };
206
207 const expandSelected = (node, selectedNode) => {
208     let shouldExpand = node.name === selectedNode;
209     let children =
210         node.children &&
211         node.children.map(child => {
212             let {
213                 shouldExpand: shouldExpandChild,
214                 node: newChild
215             } = expandSelected(child, selectedNode);
216             shouldExpand = shouldExpand || shouldExpandChild;
217             return newChild;
218         });
219
220     return {
221         node: {
222             ...node,
223             expanded: node.expanded || shouldExpand,
224             children
225         },
226         shouldExpand
227     };
228 };
229
230 export default (state = { attachmentsTree: {} }, action) => {
231     switch (action.type) {
232         case softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED:
233             let currentSoftwareProduct = action.response;
234             const packageName = currentSoftwareProduct.networkPackageName;
235             let attachmentsTree = currentSoftwareProduct.validationData
236                 ? mapValidationDataToTree(
237                       currentSoftwareProduct.validationData,
238                       packageName
239                   )
240                 : {};
241             let errorList = createErrorList(attachmentsTree);
242             return {
243                 ...state,
244                 attachmentsTree,
245                 errorList,
246                 selectedNode: nodeFilters.ALL
247             };
248         case actionTypes.TOGGLE_EXPANDED:
249             return {
250                 ...state,
251                 attachmentsTree: toggleExpanded(
252                     state.attachmentsTree,
253                     action.path
254                 )
255             };
256         case actionTypes.SELECTED_NODE:
257             let selectedNode = action.nodeName;
258             return {
259                 ...state,
260                 attachmentsTree: expandSelected(
261                     state.attachmentsTree,
262                     selectedNode
263                 ).node,
264                 selectedNode
265             };
266         case actionTypes.UNSELECTED_NODE:
267             return {
268                 ...state,
269                 selectedNode: nodeFilters.ALL
270             };
271         default:
272             return state;
273     }
274 };