update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[osm/UI.git] / skyquake / plugins / admin / src / admin.jsx
1 /*
2  *
3  *   Copyright 2016 RIFT.IO Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  *
17  */
18 import React from 'react';
19 import './admin.scss';
20 import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
21 import AppHeader from 'widgets/header/header.jsx';
22 import AdminStore from './AdminStore'
23 import ModelStore from './store/ModelStore'
24 import ModelExplorer from './components/ModelExplorer'
25
26 import 'style/layout.scss';
27
28 class Element {
29   constructor(explorerModel) {
30     this.explorerModel = explorerModel;
31     this.node = explorerModel.dataModel.path.split('/').pop().split(':').pop();
32     this.dataModel = explorerModel.dataModel;
33     if (this.dataModel.data && this.dataModel.schema[this.node].type === 'list' && !Array.isArray(this.dataModel.data)) {
34       this.dataModel.data = [this.dataModel.data];
35     }
36   }
37   get name() { return this.dataModel.path.split(':').pop() }
38   get type() { return this.dataModel.schema[this.node].type }
39   get value() { return this.dataModel.data }
40   get schema() { return this.dataModel.schema[this.node] }
41   getItemInfo(item) {
42     return ModelExplorer.getItemInfo(this.dataModel.schema[this.node].key, item);
43   }
44   // explore model methods
45   getElement = path => path.length > 1 ? this.explorerModel.getElement(path.slice(1)) : this;
46 }
47
48
49 class Admin extends React.Component {
50   constructor(props) {
51     super(props)
52     this.adminStore = props.flux.stores['AdminStore'] || props.flux.createStore(AdminStore, 'AdminStore');
53     this.adminStore.listen(this.updateAdminState);
54     this.state = { explorerModels: {}, ...this.adminStore.getState() };
55   }
56
57   componentDidMount() {
58     const storeList = this.state.modelList ? this.state.modelList.map((path, index) => {
59       const store = this.props.flux.stores[path] || this.props.flux.createStore(ModelStore, path, path);
60       store.listen(this.updateModelState);
61       store.get();
62       return store;
63     }) : [];
64     this.setState({ storeList });
65   }
66
67   componentWillUnmount() {
68     this.adminStore.unlisten(this.updateSchema);
69     this.state.storeList.forEach((store) => store.unlisten(this.updateModelState));
70   }
71
72   updateModelState = model => {
73     const explorerModels = Object.assign({}, this.state.explorerModels);
74     explorerModels[model.path] = new Element(ModelExplorer.getExplorerModel(model));
75     this.setState({ explorerModels });
76   }
77
78   updateAdminState = admin => {
79     // if storeList has changed then handle that
80   }
81
82   updateModel = (path, operation, data) => {
83     const store = this.props.flux.stores[path[1]] || this.props.flux.createStore(ModelStore, path[1]);
84     store[operation](path.slice(2), data);
85     return operation === 'delete'; // close column?
86   }
87
88   adminExplorerModel = new class {
89     constructor(admin) {
90       this.admin = admin;
91     }
92
93     getElement(path) {
94       if (path.length > 2) {
95         return this.admin.state.explorerModels[path[1]].getElement(path.slice(1))
96       } else if (path.length > 1) {
97         return this.admin.state.explorerModels[path[1]]
98       } else {
99         const data = Object.values(this.admin.state.explorerModels);
100         const properties = data.length ? 
101           data.map(e => ({
102             name: e.dataModel.path, 
103             type: ((e.dataModel.schema && e.dataModel.schema[e.node].type) || 'loading')
104           }))
105           : [];
106         const schema = {
107           name: "Configuration", 
108           type: 'container', 
109           properties
110         }
111         return {
112           schema,
113           value: data,
114           type: schema.type,
115           name: schema.name
116         }
117       }
118     }
119   }(this);
120
121   render() {
122     const { flux } = this.props;
123     const { storeList } = this.state;
124     const modelList = storeList && storeList.map(store => store.getState())
125     return (
126       <div className="admin-container">
127         <ModelExplorer model={this.adminExplorerModel} onUpdate={this.updateModel} />
128       </div>
129     )
130   }
131 }
132 export default SkyquakeComponent(Admin);