3 * Copyright 2016 RIFT.IO Inc
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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 _uniqueId from 'lodash/uniqueId'
24 import React from 'react';
25 import ReactDOM from 'react-dom';
26 import TreeView from 'react-treeview';
27 import TextInput from 'widgets/form_controls/textInput.jsx';
28 import Button from '../Button';
29 import './FileMananger.scss';
30 import FileManagerActions from './FileManagerActions.js';
31 import imgSave from '../../../../node_modules/open-iconic/svg/data-transfer-upload.svg'
32 import { Panel, PanelWrapper } from 'widgets/panel/panel';
33 import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
34 import LoadingIndicator from 'widgets/loading-indicator/loadingIndicator.jsx';
36 import DropZone from 'dropzone'
37 import Utils from '../../libraries/utils'
38 import FileManagerUploadDropZone from '../../libraries/FileManagerUploadDropZone';
39 let API_SERVER = require('utils/rw.js').getSearchParams(window.location).api_server;
43 { id: 'ICONS', folder: 'icons', title: "Icons", allowFolders: false },
44 { id: 'SCRIPTS', folder: 'scripts', title: "scripts", allowFolders: true },
45 { id: 'NS_CONFIG', folder: 'ns_config', title: "NS Config", allowFolders: false },
46 { id: 'VNF_CONFIG', folder: 'vnf_config', title: "VNF Config", allowFolders: false },
47 { id: 'DOC', folder: 'doc', title: "Doc", allowFolders: false },
48 { id: 'TEST', folder: 'test', title: "Test", allowFolders: false }
51 { id: 'ICONS', folder: 'icons', title: "Icons", allowFolders: false },
52 { id: 'CHARMS', folder: 'charms', title: "charms", allowFolders: true },
53 { id: 'SCRIPTS', folder: 'scripts', title: "scripts", allowFolders: true },
54 { id: 'CLOUD_INIT', folder: 'cloud_init', title: "cloud_init", allowFolders: false },
55 { id: 'DOC', folder: 'doc', title: "Doc", allowFolders: false },
56 { id: 'TEST', folder: 'test', title: "Test", allowFolders: false },
57 { id: 'README', folder: '.', title: "readme", allowFolders: false }
61 const createDropZone = function (action, clickable, getUploadPropsCallback, dropTarget) {
62 const dropZone = new FileManagerUploadDropZone(ReactDOM.findDOMNode(dropTarget), [clickable], action, getUploadPropsCallback);
63 // dropZone.on('dragover', this.onDragOver);
64 // dropZone.on('dragend', this.onDragEnd);
65 // dropZone.on('addedfile', this.onFileAdded);
69 function normalizeAssets(packageType, assetInfo, filesStatus) {
71 let assetTypes = ASSET_TYPE[packageType];
72 assetTypes.forEach(assetGroup => {
73 const typeFolder = assetGroup.folder;
74 let folders = assetInfo.id.filter(name => name.startsWith(typeFolder));
77 assets[assetGroup.id] = folders.map(fullName => {
78 let path = fullName.slice(typeFolder.length + 1);
79 let files = assetInfo.data[fullName].reduce((assets, info) =>
81 let name = info.name.startsWith(fullName) ? info.name.slice(fullName.length + 1) : info.name;
82 let status = filesStatus[info.name];
83 if (fullName !== '.' || !(name.endsWith('.yaml') || name.startsWith('checksum'))) {
84 assets.push({ name, status });
89 return { path, files };
96 function sendDeleteFileRequest(assetType, path, name) {
97 path = path ? path + '/' + name : name;
98 FileManagerActions.deletePackageFile({ assetType, path });
101 class FileManager extends React.Component {
104 let assests = props.files;
106 componentWillMount() {
107 // FileManagerActions.openFileManagerSockets()
109 componentWillUnmount() {
110 // FileManagerActions.closeFileManagerSockets();
112 generateFolder(data, nesting) {
113 let nestingLevel = nesting || 1;
116 let { files, filesState, type, item, actions } = this.props;
120 let assets = normalizeAssets(type, files, filesState);
122 const User = this.props.User || {};
123 const ProjectID = User.projectId;
124 let assetTypes = ASSET_TYPE[type];
125 assetTypes.forEach(assetGroup => {
126 const typeFolder = assetGroup.folder;
127 let folders = assets[assetGroup.id];
128 let rootAssets = { path: '', files: [] };
129 let subFolders = null;
130 if (folders && folders.length) {
131 rootAssets = folders[0];
132 subFolders = folders.slice(1);
139 title={assetGroup.title}
140 assetGroup={assetGroup}
141 path={rootAssets.path}
142 files={rootAssets.files}
143 allowsFolders={assetGroup.allowFolders}
145 showNotification={actions.showNotification}
146 ProjectID={ProjectID}
152 <div className="FileManager">
153 <PanelWrapper style={{ flexDirection: 'column' }}>
163 function NewHierachy(props) {
165 <Panel className="addFileSection" style={{ backgroundColor: 'transparent' }} no-corners>
166 <div className="inputSection">
167 <TextInput placeholder="some/path" label="create a folder hierarchy" onChange={FileManagerActions.newPathNameUpdated} />
168 <Button label="Create" onClick={e => FileManagerActions.createDirectory(props.assetGroup.id)} />
174 class AssetGroup extends React.Component {
177 this.state = { downloadPath: "" };
181 let { title, packageType, packageId, assetGroup, files, allowsFolders, folders, path, inputState, showNotification } = this.props;
183 if (folders && folders.length) {
184 folders.map(function (folder, i) {
188 packageId={packageId}
190 packageType={packageType}
192 assetGroup={assetGroup}
194 showNotification={showNotification}
199 let folderCreateComponent = allowsFolders ? <NewHierachy assetGroup={assetGroup} /> : null;
202 function uploadFileFromUrl(url) {
203 if (!url || url == "") {
206 let splitUrl = url.split('/');
207 let fileName = splitUrl[splitUrl.length - 1];
208 if (files.findIndex(f => f.name === fileName) > -1) {
209 showNotification('It seems you\'re attempting to upload a file with a duplicate file name');
211 FileManagerActions.sendDownloadFileRequest({ url, assetType: assetGroup.id, path: path });
216 <Panel title={title} itemClassName="nested" no-corners>
217 {folderCreateComponent}
218 <div className="folder">
219 <FileAssetList files={files} path={path} packageId={packageId} packageType={packageType} assetGroup={assetGroup} ProjectID={this.props.ProjectID} />
220 <Panel className="addFileSection" no-corners>
221 <ItemUpload packageType={packageType} packageId={packageId} path={path} assetGroup={assetGroup} />
222 <div style={{ marginLeft: '0.5rem' }}>
225 <div className="inputSection">
226 <TextInput placeholder="URL" className="" label="External URL" value={this.state.downloadPath} onChange={e => this.setState({ downloadPath: e.target.value })} />
227 <Button className='ComposerAppSave' label="DOWNLOAD" onClick={e => uploadFileFromUrl(this.state.downloadPath)} />
239 function FileAssetList(props) {
240 let { packageType, packageId, assetGroup, files, path } = props;
243 children = files.map(function (file, i) {
244 if (!file.hasOwnProperty('contents')) {
245 return <FileAsset ProjectID={props.ProjectID} key={file.name} file={file} path={path} id={packageId} type={packageType} assetGroup={assetGroup} />
250 <div className='file-list'>
257 function FileAsset(props) {
258 let { file, path, type, assetGroup, id, ProjectID } = props;
259 const name = file.name;
260 const downloadHost = API_SERVER.match('localhost') || API_SERVER.match('127.0.0.1') ? `${window.location.protocol}//${window.location.hostname}` : API_SERVER;
261 //{`${window.location.protocol}//${API_SERVER}:4567/api/package${type}/${id}/${path}/${name}`}
263 <div className="file">
264 <div className="file-section">
265 <div className="file-info">
266 <div className="file-status"
267 style={{ display: (file.status && file.status.toLowerCase() != 'completed') ? 'inherit' : 'none', color: (file.status == 'FAILED' ? 'red' : 'inherit') }}>
268 {file.status && (file.status == 'IN_PROGRESS' || file.status == 'DOWNLOADING') ? <LoadingIndicator size={2} /> : file.status}
270 <div className="file-name">
271 <a target="_blank" href={`${downloadHost}:8008/mano/api/package/${type}/${ProjectID}/${id}/${assetGroup.folder}${path}/${name}`}>{name}</a>
274 <div className="file-action"
275 style={{ display: (!file.status || (file && file.status.toLowerCase() != 'loading...')) ? 'inherit' : 'none', cursor: 'pointer' }}
276 onClick={e => sendDeleteFileRequest(assetGroup.id, path, name)}>
284 class ItemUpload extends React.Component {
287 this.state = { dropzoneIdClass: 'DZ-' + _uniqueId() };
289 componentDidMount() {
291 FileManagerUploadDropZone.ACTIONS.onboard,
292 '.ComposerAppAddFile.' + this.state.dropzoneIdClass,
294 let theCode = 'crap';
296 packageType: this.props.packageType,
297 packageId: this.props.packageId,
298 assetGroup: this.props.assetGroup,
299 path: this.props.path
305 let { dropzoneIdClass } = this.props;
307 <div className="inputSection">
308 <label className="sqTextInput" style={{ flexDirection: 'row', alignItems: 'center' }}>
309 <span>Upload File</span>
310 <Button className={'ComposerAppAddFile ' + this.state.dropzoneIdClass} label="BROWSE" />
317 function stripPath(name, path, returnPath) {
318 let stripSlash = (name.indexOf('/') > -1) ? '/' : '';
319 // return name.split(path + stripSlash)[1].replace('/', '');
320 let split = name.split(path + stripSlash)[returnPath ? 0 : 1];
321 return split ? split.replace('/', '') : name;
326 export default SkyquakeComponent(FileManager)
334 // "name": "pong_vnfd",
337 // "name": "pong_vnfd/checksums.txt",
338 // "last_modified_time": 1474458399.6218443,
342 // "name": "pong_vnfd/pong_vnfd.yaml",
343 // "last_modified_time": 1474458399.6258445,
347 // "name": "pong_vnfd/icons",
350 // "name": "pong_vnfd/icons/rift_logo.png",
351 // "last_modified_time": 1474458399.6218443,
355 // "last_modified_time": 1474458399.6218443,
359 // "name": "pong_vnfd/cloud_init",
362 // "name": "pong_vnfd/cloud_init/pong_cloud_init.cfg",
363 // "last_modified_time": 1474458399.6258445,
367 // "last_modified_time": 1474458399.6258445,
371 // "last_modified_time": 1474458399.6258445,
375 // "last_modified_time": 1474458399.6218443,