SDNR UI don't process list which has more than one key
[ccsdk/features.git] / sdnr / wt / odlux / apps / configurationApp / src / pluginConfiguration.tsx
1 /**
2  * ============LICENSE_START========================================================================
3  * ONAP : ccsdk feature sdnr wt odlux
4  * =================================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
6  * =================================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software distributed under the License
13  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing permissions and limitations under
15  * the License.
16  * ============LICENSE_END==========================================================================
17  */
18
19 import * as React from "react";
20 import { withRouter, RouteComponentProps, Route, Switch, Redirect } from 'react-router-dom';
21
22 import { faAdjust } from '@fortawesome/free-solid-svg-icons';  // select app icon
23
24 import connect, { Connect, IDispatcher } from '../../../framework/src/flux/connect';
25 import applicationManager from '../../../framework/src/services/applicationManager';
26 import { IApplicationStoreState } from "../../../framework/src/store/applicationStore";
27 import { configurationAppRootHandler } from "./handlers/configurationAppRootHandler";
28 import { NetworkElementSelector } from "./views/networkElementSelector";
29
30 import ConfigurationApplication from "./views/configurationApplication";
31 import { updateNodeIdAsyncActionCreator, updateViewActionAsyncCreator } from "./actions/deviceActions";
32 import { DisplayModeType } from "./handlers/viewDescriptionHandler";
33 import { ViewSpecification } from "./models/uiModels";
34
35 let currentNodeId: string | null | undefined = undefined;
36 let currentVirtualPath: string | null | undefined = undefined;
37 let lastUrl: string | undefined = undefined;
38
39 const mapDisp = (dispatcher: IDispatcher) => ({
40   updateNodeId: (nodeId: string) => dispatcher.dispatch(updateNodeIdAsyncActionCreator(nodeId)),
41   updateView: (vPath: string) => dispatcher.dispatch(updateViewActionAsyncCreator(vPath)),
42 });
43
44 const ConfigurationApplicationRouteAdapter = connect(undefined, mapDisp)((props: RouteComponentProps<{ nodeId?: string, 0: string }> & Connect<undefined, typeof mapDisp>) => {
45   React.useEffect(() => {
46     return () => {
47       lastUrl = undefined;
48       currentNodeId = undefined;
49       currentVirtualPath = undefined;
50     }
51   }, []);
52   if (props.location.pathname !== lastUrl) {
53     // ensure the asynchronus update will only be called once per path
54     lastUrl = props.location.pathname;
55     window.setTimeout(async () => {
56
57       // check if the nodeId has changed
58       let dump = false;
59       if (currentNodeId !== props.match.params.nodeId) {
60         currentNodeId = props.match.params.nodeId || undefined;
61         if (currentNodeId && currentNodeId.endsWith("|dump")) {
62           dump = true;
63           currentNodeId = currentNodeId.replace(/\|dump$/i, '');
64         }
65         currentVirtualPath = null;
66         currentNodeId && (await props.updateNodeId(currentNodeId));
67       }
68
69       if (currentVirtualPath !== props.match.params[0]) {
70         currentVirtualPath = props.match.params[0];
71         if (currentVirtualPath && currentVirtualPath.endsWith("|dump")) {
72           dump = true;
73           currentVirtualPath = currentVirtualPath.replace(/\|dump$/i, '');
74         }
75         await props.updateView(currentVirtualPath);
76       }
77
78       if (dump) {
79         const device = props.state.configuration.deviceDescription;
80         const ds = props.state.configuration.viewDescription.displaySpecification;
81
82         const createDump = (view: ViewSpecification | null, level: number = 0) => {
83           if (view === null) return "Empty";
84           const indention = Array(level * 4).fill(' ').join('');
85           let result = '';
86
87           if (!view) debugger;
88           // result += `${indention}  [${view.canEdit ? 'rw' : 'ro'}] ${view.ns}:${view.name} ${ds.displayMode === DisplayModeType.displayAsList ? '[LIST]' : ''}\r\n`;
89           result += Object.keys(view.elements).reduce((acc, cur) => {
90             const elm = view.elements[cur];
91             acc += `${indention}  [${elm.uiType === "rpc" ? "x" : elm.config ? 'rw' : 'ro'}:${elm.id}] (${elm.module}:${elm.label}) {${elm.uiType}} ${elm.uiType === "object" && elm.isList ? `as LIST with KEY [${elm.key}]` : ""}\r\n`;
92             // acc += `${indention}    +${elm.mandatory ? "mandetory" : "none"} - ${elm.path} \r\n`;
93             
94             switch (elm.uiType) {
95               case "object":
96                 acc += createDump(device.views[(elm as any).viewId], level + 1);
97                 break;
98               default:
99             }
100             return acc;
101           }, "");
102           return `${result}`;
103         }
104
105         const dump = createDump(ds.displayMode === DisplayModeType.displayAsObject || ds.displayMode === DisplayModeType.displayAsList ? ds.viewSpecification : null, 0);
106         var element = document.createElement('a');
107         element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(dump));
108         element.setAttribute('download', currentNodeId + ".txt");
109
110         element.style.display = 'none';
111         document.body.appendChild(element);
112
113         element.click();
114
115         document.body.removeChild(element);
116       }
117
118     });
119   }
120   return (
121     <ConfigurationApplication />
122   );
123 });
124
125 const App = withRouter((props: RouteComponentProps) => (
126   <Switch>
127     <Route path={`${props.match.url}/:nodeId/*`} component={ConfigurationApplicationRouteAdapter} />
128     <Route path={`${props.match.url}/:nodeId`} component={ConfigurationApplicationRouteAdapter} />
129     <Route path={`${props.match.url}`} component={NetworkElementSelector} />
130     <Redirect to={`${props.match.url}`} />
131   </Switch>
132 ));
133
134 export function register() {
135   applicationManager.registerApplication({
136     name: "configuration",
137     icon: faAdjust,
138     rootComponent: App,
139     rootActionHandler: configurationAppRootHandler,
140     menuEntry: "Configuration"
141   });
142 }