diff --git a/embark-ui/package-lock.json b/embark-ui/package-lock.json index 8c3da60b9..d22c94f95 100644 --- a/embark-ui/package-lock.json +++ b/embark-ui/package-lock.json @@ -283,6 +283,11 @@ "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=" }, + "array-find": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz", + "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=" + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -1414,6 +1419,11 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "bowser": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.9.4.tgz", + "integrity": "sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==" + }, "boxen": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", @@ -2792,6 +2802,11 @@ } } }, + "dom-helpers": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.3.1.tgz", + "integrity": "sha512-2Sm+JaYn74OiTM2wHvxJOo3roiq/h25Yi69Fqk269cNUwIXsCvATB6CRSFC9Am/20G2b28hGv/+7NiWydIrPvg==" + }, "dom-serializer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", @@ -3476,6 +3491,11 @@ "strip-eof": "^1.0.0" } }, + "exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" + }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -5077,6 +5097,11 @@ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, + "hyphenate-style-name": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz", + "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es=" + }, "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", @@ -5169,6 +5194,15 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "inline-style-prefixer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz", + "integrity": "sha1-wVPH6I/YT+9cYC6VqBaLJ3BnH+c=", + "requires": { + "bowser": "^1.0.0", + "hyphenate-style-name": "^1.0.1" + } + }, "inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", @@ -6532,6 +6566,11 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.10.tgz", "integrity": "sha512-iesFYPmxYYGTcmQK0sL8bX3TGHyM6b2qREaB4kamHfQyfPJP0xgoGxp19nsH16nsfquLdiyKyX3mQkfiSGV8Rg==" }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", @@ -6562,11 +6601,31 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -8782,6 +8841,17 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz", "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==" }, + "radium": { + "version": "0.19.6", + "resolved": "https://registry.npmjs.org/radium/-/radium-0.19.6.tgz", + "integrity": "sha512-IABYntqCwYelUUIwA52maSCgJbqtJjHKIoD21wgpw3dGhIUbJ5chDShDGdaFiEzdF03hN9jfQqlmn0bF4YhfrQ==", + "requires": { + "array-find": "^1.0.0", + "exenv": "^1.2.1", + "inline-style-prefixer": "^2.0.5", + "prop-types": "^15.5.8" + } + }, "raf": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz", @@ -8950,6 +9020,11 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.0.tgz", "integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw==" }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, "react-popper": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.0.0.tgz", @@ -9090,6 +9165,30 @@ "prop-types": "^15.5.6" } }, + "react-transition-group": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.4.0.tgz", + "integrity": "sha512-Xv5d55NkJUxUzLCImGSanK8Cl/30sgpOEMGc5m86t8+kZwrPxPCPcFqyx83kkr+5Lz5gs6djuvE5By+gce+VjA==", + "requires": { + "dom-helpers": "^3.3.1", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + }, + "react-treebeard": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-treebeard/-/react-treebeard-2.1.0.tgz", + "integrity": "sha512-unoy8IJL1NR5jgTtK+CqOCZKZylh/Tlid0oYajW9bLZCbFelxzmCsF8Y2hyS6pvHqM4W501oOm5O/jvg3VZCrg==", + "requires": { + "babel-runtime": "^6.23.0", + "deep-equal": "^1.0.1", + "prop-types": "^15.5.8", + "radium": "^0.19.0", + "shallowequal": "^0.2.2", + "velocity-react": "^1.3.1" + } + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -9745,6 +9844,14 @@ "safe-buffer": "^5.0.1" } }, + "shallowequal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz", + "integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=", + "requires": { + "lodash.keys": "^3.1.2" + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -10839,6 +10946,22 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "velocity-animate": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/velocity-animate/-/velocity-animate-1.5.2.tgz", + "integrity": "sha512-m6EXlCAMetKztO1ppBhGU1/1MR3IiEevO6ESq6rcrSQ3Q77xYSW13jkfXW88o4xMrkXJhy/U7j4wFR/twMB0Eg==" + }, + "velocity-react": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/velocity-react/-/velocity-react-1.4.1.tgz", + "integrity": "sha512-ZyXBm+9C/6kNUNyc+aeNKEhtTu/Mn+OfpsNBGuTxU8S2DUcis/KQL0rTN6jWL+7ygdOrun18qhheNZTA7YERmg==", + "requires": { + "lodash": "^4.17.5", + "prop-types": "^15.5.8", + "react-transition-group": "^2.0.0", + "velocity-animate": "^1.4.0" + } + }, "vendors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", diff --git a/embark-ui/package.json b/embark-ui/package.json index 99671d5fa..bb04cb1b8 100644 --- a/embark-ui/package.json +++ b/embark-ui/package.json @@ -16,6 +16,7 @@ "react-router-dom": "^4.3.1", "react-scripts": "1.1.4", "react-scroll-to-component": "^1.0.2", + "react-treebeard": "^2.1.0", "redux": "^4.0.0", "redux-saga": "^0.16.0", "tabler-react": "^1.18.0" diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index 44bf658de..afc1a3057 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -193,6 +193,13 @@ export const fiddleFile = { failure: (error) => action(FIDDLE_FILE[FAILURE], {error}) }; +export const FILES = createRequestTypes('FILES'); +export const files = { + request: () => action(FILES[REQUEST]), + success: (files) => action(FILES[SUCCESS], {files: files}), + failure: (error) => action(FILES[FAILURE], {error}) +}; + // Web Socket export const WATCH_NEW_PROCESS_LOGS = 'WATCH_NEW_PROCESS_LOGS'; export const WATCH_NEW_CONTRACT_LOGS = 'WATCH_NEW_CONTRACT_LOGS'; diff --git a/embark-ui/src/api/index.js b/embark-ui/src/api/index.js index a4ac1641a..523795ae1 100644 --- a/embark-ui/src/api/index.js +++ b/embark-ui/src/api/index.js @@ -135,3 +135,7 @@ export function postFiddle(payload) { export function postFiddleDeploy(payload) { return post('/contract/deploy', {compiledContract: payload.compiledCode}); } + +export function fetchFiles() { + return get('/files'); +} diff --git a/embark-ui/src/components/FiddleLayout.js b/embark-ui/src/components/FiddleLayout.js new file mode 100644 index 000000000..43289bdca --- /dev/null +++ b/embark-ui/src/components/FiddleLayout.js @@ -0,0 +1,25 @@ +import React from 'react'; +import {Route, Switch} from 'react-router-dom'; +import { + Page, + Grid +} from "tabler-react"; + +import FiddleContainer from '../containers/FiddleContainer'; +import FileExplorerContainer from '../containers/FileExplorerContainer'; + +const ExplorerLayout = () => ( + + + Fiddle + + + + + + + + +); + +export default ExplorerLayout; diff --git a/embark-ui/src/components/FileExplorer.js b/embark-ui/src/components/FileExplorer.js new file mode 100644 index 000000000..d062ac435 --- /dev/null +++ b/embark-ui/src/components/FileExplorer.js @@ -0,0 +1,54 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Treebeard, decorators} from 'react-treebeard'; + +const Header = ({style, node}) => { + const iconType = node.children ? 'folder' : 'file'; + const iconClass = `fe fe-${iconType}`; + const iconStyle = {marginRight: '5px'}; + + return ( +
+
+ + {node.name} +
+
+ ); +}; + +Header.propTypes = { + style: PropTypes.object, + node: PropTypes.object +}; + +decorators.Header = Header; + +class FileExplorer extends React.Component { + constructor(props){ + super(props); + this.state = {}; + } + onToggle(node, toggled){ + node.active = true; + if(node.children) { + node.toggled = toggled; + } + this.setState({ cursor: node }); + } + render(){ + return ( + this.onToggle(node, toggled)} + /> + ); + } +} + +FileExplorer.propTypes = { + files: PropTypes.array +}; + +export default FileExplorer; diff --git a/embark-ui/src/containers/FileExplorerContainer.js b/embark-ui/src/containers/FileExplorerContainer.js new file mode 100644 index 000000000..10b819bf7 --- /dev/null +++ b/embark-ui/src/containers/FileExplorerContainer.js @@ -0,0 +1,37 @@ +import React, {Component} from 'react'; +import {connect} from 'react-redux'; +import PropTypes from 'prop-types'; +import {files as filesAction} from "../actions"; + +import FileExplorer from '../components/FileExplorer'; +import DataWrapper from "../components/DataWrapper"; +import {getFiles} from "../reducers/selectors"; + +class FileExplorerContainer extends Component { + componentDidMount() { + this.props.fetchFiles(); + } + + render() { + return ( + 0} {...this.props} render={({files}) => ( + + )} /> + ); + } +} + +function mapStateToProps(state) { + return {files: getFiles(state), error: state.errorMessage, loading: state.loading}; +} + +FileExplorerContainer.propTypes = { + files: PropTypes.array, + fetchFiles: PropTypes.func +}; + +export default connect( + mapStateToProps,{ + fetchFiles: filesAction.request + } +)(FileExplorerContainer); diff --git a/embark-ui/src/reducers/index.js b/embark-ui/src/reducers/index.js index 1d5ada53a..b9ef8f6d6 100644 --- a/embark-ui/src/reducers/index.js +++ b/embark-ui/src/reducers/index.js @@ -23,7 +23,8 @@ const entitiesDefaultState = { fiddleDeploys: [], versions: [], plugins: [], - ensRecords: [] + ensRecords: [], + files: [] }; const sorter = { @@ -44,6 +45,11 @@ const sorter = { }, commands: function(a, b) { return b.timestamp - a.timestamp; + }, + files: function(a, b) { + if (a.name < b.name) return -1; + if (a.name > b.name) return 1; + return 0; } }; @@ -72,6 +78,11 @@ const filtrer = { return record.name && record.address && record.address !== voidAddress && index === self.findIndex((r) => ( r.address=== record.address && r.name === record.name )); + }, + files: function(file, index, self) { + return index === self.findIndex((f) => ( + file.name === f.name + )); } }; diff --git a/embark-ui/src/reducers/selectors.js b/embark-ui/src/reducers/selectors.js index 94ec16b55..7f3474a35 100644 --- a/embark-ui/src/reducers/selectors.js +++ b/embark-ui/src/reducers/selectors.js @@ -135,3 +135,7 @@ export function getEnsErrors(state) { export function isEnsEnabled(state) { return Boolean(state.entities.plugins.find((plugin) => plugin.name === 'ens')); } + +export function getFiles(state) { + return state.entities.files; +} diff --git a/embark-ui/src/routes.js b/embark-ui/src/routes.js index dbae205f0..1764385ec 100644 --- a/embark-ui/src/routes.js +++ b/embark-ui/src/routes.js @@ -7,7 +7,7 @@ import ContractContainer from './containers/ContractLayoutContainer'; import NoMatch from './components/NoMatch'; import ExplorerLayout from './components/ExplorerLayout'; import ProcessesLayout from './components/ProcessesLayout'; -import FiddleContainer from './containers/FiddleContainer'; +import FiddleLayout from './components/FiddleLayout'; const routes = ( @@ -17,7 +17,7 @@ const routes = ( - } /> + diff --git a/embark-ui/src/sagas/index.js b/embark-ui/src/sagas/index.js index 5df868e24..4f51eb8cb 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -6,7 +6,7 @@ import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects'; const {account, accounts, block, blocks, transaction, transactions, processes, commands, processLogs, contracts, contract, contractProfile, messageSend, versions, plugins, messageListen, fiddle, fiddleDeploy, ensRecord, ensRecords, contractLogs, contractFile, contractFunction, contractDeploy, - fiddleFile} = actions; + fiddleFile, files} = actions; function *doRequest(entity, apiFn, payload) { const {response, error} = yield call(apiFn, payload); @@ -41,6 +41,7 @@ export const postFiddleDeploy = doRequest.bind(null, fiddleDeploy, api.postFiddl export const sendMessage = doRequest.bind(null, messageSend, api.sendMessage); export const fetchEnsRecord = doRequest.bind(null, ensRecord, api.fetchEnsRecord); export const postEnsRecord = doRequest.bind(null, ensRecords, api.postEnsRecord); +export const fetchFiles = doRequest.bind(null, files, api.fetchFiles); export function *watchFetchTransaction() { yield takeEvery(actions.TRANSACTION[actions.REQUEST], fetchTransaction); @@ -146,6 +147,10 @@ export function *watchPostFiddleDeploy() { yield takeEvery(actions.FIDDLE_DEPLOY[actions.REQUEST], postFiddleDeploy); } +export function *watchFetchFiles() { + yield takeEvery(actions.FILES[actions.REQUEST], fetchFiles); +} + function createChannel(socket) { return eventChannel(emit => { socket.onmessage = ((message) => { @@ -236,6 +241,7 @@ export default function *root() { fork(watchFetchLastFiddle), fork(watchFetchLastFiddleSuccess), fork(watchFetchEnsRecord), - fork(watchPostEnsRecords) + fork(watchPostEnsRecords), + fork(watchFetchFiles) ]); } diff --git a/lib/core/fs.js b/lib/core/fs.js index e596d094c..84ff83c56 100644 --- a/lib/core/fs.js +++ b/lib/core/fs.js @@ -59,6 +59,14 @@ function readFileSync() { return fs.readFileSync.apply(fs.readFileSync, arguments); } +function readdirSync() { + return fs.readdirSync.apply(fs.readdirSync, arguments); +} + +function statSync() { + return fs.statSync.apply(fs.statSync, arguments); +} + function readJSONSync() { let content = readFileSync.apply(readFileSync, arguments); try { @@ -149,6 +157,8 @@ module.exports = { moveSync, readFile, readFileSync, + readdirSync, + statSync, appendFileSync, writeFile, writeFileSync, diff --git a/lib/modules/pipeline/index.js b/lib/modules/pipeline/index.js index 9d24fb016..504bf52e6 100644 --- a/lib/modules/pipeline/index.js +++ b/lib/modules/pipeline/index.js @@ -1,4 +1,5 @@ const fs = require('../../core/fs.js'); +const path = require('path'); const async = require('async'); const utils = require('../../utils/utils.js'); const ProcessLauncher = require('../../core/processes/processLauncher'); @@ -57,6 +58,21 @@ class Pipeline { }); } ); + + plugin.registerAPICall( + 'get', + '/embark-api/files/', + (req, res) => { + const walk = (dir, filelist = []) => fs.readdirSync(dir).map(file => { + if (fs.statSync(path.join(dir, file)).isDirectory()) { + return {name: file, children: walk(path.join(dir, file), filelist)}; + } + return {name: file}; + }); + const files = walk(fs.dappPath()); + res.send(files); + } + ); } build({modifiedAssets}, callback) {