498cd2aec4f69c759de96e0cdb98792588f7aa61
[osm/UI.git] / skyquake / plugins / composer / src / src / components / filemanager / FileManager.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
19
20 //https://raw.githubusercontent.com/RIFTIO/RIFT.ware/master/rift-shell
21 import _cloneDeep from 'lodash/cloneDeep'
22 import _findIndex from 'lodash/findIndex'
23 import React from 'react';
24 import ReactDOM from 'react-dom';
25 import TreeView from 'react-treeview';
26 import TextInput from 'widgets/form_controls/textInput.jsx';
27 import Button from '../Button';
28 import './FileMananger.scss';
29 import FileManagerActions from './FileManagerActions.js';
30 import imgSave from '../../../../node_modules/open-iconic/svg/data-transfer-upload.svg'
31 import {Panel, PanelWrapper} from 'widgets/panel/panel';
32 import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
33 import LoadingIndicator from 'widgets/loading-indicator/loadingIndicator.jsx';
34
35 import DropZone from 'dropzone'
36 import Utils from '../../libraries/utils'
37 import FileManagerUploadDropZone from '../../libraries/FileManagerUploadDropZone';
38 let API_SERVER = require('utils/rw.js').getSearchParams(window.location).api_server;
39
40 const createDropZone = function (action, clickable, type, id, path, dropTarget) {
41     const dropZone = new FileManagerUploadDropZone(ReactDOM.findDOMNode(dropTarget), [clickable], action, type, id, path);
42     // dropZone.on('dragover', this.onDragOver);
43     // dropZone.on('dragend', this.onDragEnd);
44     // dropZone.on('addedfile', this.onFileAdded);
45     return dropZone;
46 };
47 //updateFileLocationInput
48 class FileManager extends React.Component {
49     constructor(props) {
50         super(props)
51     }
52     componentWillMount() {
53         // FileManagerActions.openFileManagerSockets()
54     }
55     componentWillUnmount() {
56         // FileManagerActions.closeFileManagerSockets();
57     }
58     generateFolder(data, nesting) {
59         let nestingLevel = nesting || 1;
60
61     }
62     deleteFile(name) {
63         return function(e) {
64             FileManagerActions.deletePackageFile(name);
65         }
66
67     }
68     updateFileLocationInput(name) {
69         return function(e) {
70             FileManagerActions.updateFileLocationInput({
71                 name: name,
72                 value: e.target.value
73             });
74         }
75     }
76     sendDownloadFileRequst = (url, path) => {
77         let self = this;
78         return function(e) {
79             if(!url || url == "") {
80                 return self.props.actions.showNotification.defer({type: 'error', msg: 'Value missing in download request'});;
81             }
82             let files = self.props.files.data;
83             let folder = path.split('/');
84             let splitUrl = url.split('/');
85             let fileName = splitUrl[splitUrl.length - 1];
86             folder.pop;
87             let fullPath = _cloneDeep(folder);
88             fullPath.push(fileName);
89             fullPath = fullPath.join('/');
90             folder = folder.join('/');
91             let fileIndex = _findIndex(files[folder], function(f) {
92                 return f.name == fullPath;
93             })
94             if (fileIndex == -1) {
95                 FileManagerActions.sendDownloadFileRequst({
96                     url: url,
97                     path: path
98                 });
99             } else {
100                 self.props.actions.showNotification('It seems you\'re attempting to upload a file with a duplicate file name');
101             }
102         }
103     }
104     render() {
105         let self = this;
106         let html = (
107             <div className="FileManager">
108                 <PanelWrapper style={{flexDirection: 'column'}}>
109                 <Panel className="addFileSection" style={{backgroundColor: 'transparent'}} no-corners>
110                     <div className="inputSection">
111                         <TextInput placeholder="some/path" value={this.props.newPathName} label="create a new directory" onChange={FileManagerActions.newPathNameUpdated} />
112                         <Button label="Create" onClick={FileManagerActions.createDirectory} />
113                     </div>
114                 </Panel>
115                 {self.props.files && self.props.files.id && buildList(self, self.props.files) }
116                 </PanelWrapper>
117             </div>
118         )
119         return html;
120     }
121
122 }
123
124 function buildList(self, data) {
125     let toReturn = [];
126     data.id.map(function(k,i) {
127         toReturn.push (contentFolder(self, data.data[k], k, k+i, self.props.filesState, self.updateFileLocationInput, self.sendDownloadFileRequst, self.deleteFile));
128     });
129     return toReturn.reverse();
130 }
131
132 function contentFolder(context, folder, path, key, inputState, updateFn, sendDownloadFileRequst, deleteFn) {
133     let type = context.props.type;
134     let id = context.props.item.id;
135     let classId = `DZ-${path.replace(/\//g, '-')}`;
136     const onboardDropZone = createDropZone.bind(this, FileManagerUploadDropZone.ACTIONS.onboard, '.ComposerAppAddFile.' + classId, type, id, path);
137     return (
138         <Panel title={path} key={key} itemClassName="nested" no-corners>
139         <div className="folder">
140             {
141                 folder.map(function(f, i) {
142                     if( !f.hasOwnProperty('contents') ){
143                         return contentFile(context, f, path, i, deleteFn);
144                     }
145                 })
146             }
147             <Panel className="addFileSection" no-corners>
148                 <ItemUpload type={type} id={id} path={path} key={key} dropZone={onboardDropZone} />
149                 <div style={{marginLeft: '0.5rem'}}>
150                     OR
151                 </div>
152                 <div className="inputSection">
153                     <TextInput placeholder="URL" className="" label="External URL" value={inputState[path]} onChange={updateFn(path)} />
154                     <Button className='ComposerAppSave' label="DOWNLOAD" onClick={sendDownloadFileRequst(inputState[path], path)}/>
155                 </div>
156             </Panel>
157
158             </div>
159         </Panel>
160     );
161 }
162 class ItemUpload extends React.Component {
163     constructor(props) {
164         super(props);
165     }
166     componentDidMount() {
167         if (this.props.dropZone) {
168             const dropTarget = this;
169             const dropZone = this.props.dropZone(dropTarget);
170         }
171     }
172     render() {
173         let {type, id, path, key, ...props} = this.props;
174         let classId = `DZ-${path.replace(/\//g, '-')}`;
175         return (
176             <div className="inputSection">
177                 <label className="sqTextInput" style={{flexDirection: 'row', alignItems:'center'}}>
178                     <span>Upload File</span>
179                     <Button className={'ComposerAppAddFile ' + classId} label="BROWSE"/>
180                 </label>
181             </div>
182         )
183     }
184 }
185 function contentFile(context, file, path, key, deleteFn) {
186     const name = stripPath(file.name, path);
187     const id = context.props.item.id;
188     const type = context.props.type;
189     const downloadHost = API_SERVER.match('localhost') || API_SERVER.match('127.0.0.1') ? `${window.location.protocol}//${window.location.hostname}` : API_SERVER;
190     //{`${window.location.protocol}//${API_SERVER}:4567/api/package${type}/${id}/${path}/${name}`}
191     return (
192         <div className="file" key={key}>
193             <div className="file-section">
194                 <div className="file-info">
195                     <div className="file-status" style={{display: (file.status && file.status.toLowerCase() != 'completed') ? 'inherit' : 'none', color: (file.status == 'FAILED' ? 'red' : 'inherit')}}>
196                         {file.status && (file.status == 'IN_PROGRESS' || file.status == 'DOWNLOADING'  )  ? <LoadingIndicator size={2} /> : file.status }
197                     </div>
198                     <div className="file-name">
199                         <a target="_blank" href={`${downloadHost}:4567/api/package/${type}/${id}/${path}/${name}`}>{name}</a>
200                     </div>
201                 </div>
202                 <div className="file-action" style={{display: (!file.status || (file && file.status.toLowerCase() != 'loading...')) ? 'inherit' : 'none', cursor: 'pointer'}} onClick={deleteFn(file.name)}>X</div>
203             </div>
204         </div>
205     )
206 }
207
208 function stripPath(name, path, returnPath) {
209     let stripSlash = (name.indexOf('/') > -1) ? '/' : '';
210     // return name.split(path + stripSlash)[1].replace('/', '');
211     let split = name.split(path + stripSlash)[returnPath ? 0 : 1];
212     return split ? split.replace('/', '') : name;
213 }
214
215
216
217 export default SkyquakeComponent(FileManager)
218 /**
219  * Sample Data
220  */
221 // let files = {
222 //   "name": ".",
223 //   "contents": [
224 //     {
225 //       "name": "pong_vnfd",
226 //       "contents": [
227 //         {
228 //           "name": "pong_vnfd/checksums.txt",
229 //           "last_modified_time": 1474458399.6218443,
230 //           "byte_size": 168
231 //         },
232 //         {
233 //           "name": "pong_vnfd/pong_vnfd.yaml",
234 //           "last_modified_time": 1474458399.6258445,
235 //           "byte_size": 3514
236 //         },
237 //         {
238 //           "name": "pong_vnfd/icons",
239 //           "contents": [
240 //             {
241 //               "name": "pong_vnfd/icons/rift_logo.png",
242 //               "last_modified_time": 1474458399.6218443,
243 //               "byte_size": 1658
244 //             }
245 //           ],
246 //           "last_modified_time": 1474458399.6218443,
247 //           "byte_size": 3
248 //         },
249 //         {
250 //           "name": "pong_vnfd/cloud_init",
251 //           "contents": [
252 //             {
253 //               "name": "pong_vnfd/cloud_init/pong_cloud_init.cfg",
254 //               "last_modified_time": 1474458399.6258445,
255 //               "byte_size": 227
256 //             }
257 //           ],
258 //           "last_modified_time": 1474458399.6258445,
259 //           "byte_size": 3
260 //         }
261 //       ],
262 //       "last_modified_time": 1474458399.6258445,
263 //       "byte_size": 6
264 //     }
265 //   ],
266 //   "last_modified_time": 1474458399.6218443,
267 //   "byte_size": 3
268 // };