diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js
index 5d839465..17b5cf1c 100644
--- a/client/modules/IDE/actions/files.js
+++ b/client/modules/IDE/actions/files.js
@@ -69,14 +69,21 @@ export function getBlobUrl(file) {
export function createFile(formProps) {
return (dispatch, getState) => {
const state = getState();
- const rootFile = state.files.filter(file => file.name === 'root')[0];
+ const selectedFile = state.files.find(file => file.isSelected);
+ const rootFile = state.files.find(file => file.name === 'root');
+ let parentId;
+ if (selectedFile.fileType === 'folder') {
+ parentId = selectedFile.id;
+ } else {
+ parentId = rootFile.id;
+ }
if (state.project.id) {
const postParams = {
name: createUniqueName(formProps.name, state.files),
url: formProps.url,
content: formProps.content || '',
// TODO pass parent id to API, once there are folders
- parentId: rootFile.id
+ parentId
};
axios.post(`${ROOT_URL}/projects/${state.project.id}/files`, postParams, { withCredentials: true })
.then(response => {
@@ -86,7 +93,7 @@ export function createFile(formProps) {
dispatch({
type: ActionTypes.CREATE_FILE,
...response.data,
- parentId: rootFile.id
+ parentId
});
dispatch({
type: ActionTypes.HIDE_MODAL
@@ -109,7 +116,7 @@ export function createFile(formProps) {
url: formProps.url,
content: formProps.content || '',
// TODO pass parent id from File Tree
- parentId: rootFile.id
+ parentId
});
dispatch({
type: ActionTypes.HIDE_MODAL
@@ -121,12 +128,20 @@ export function createFile(formProps) {
export function createFolder(formProps) {
return (dispatch, getState) => {
const state = getState();
- const rootFile = state.files.filter(file => file.name === 'root')[0];
+ const selectedFile = state.files.find(file => file.isSelected);
+ const rootFile = state.files.find(file => file.name === 'root');
+ let parentId;
+ if (selectedFile.fileType === 'folder') {
+ parentId = selectedFile.id;
+ } else {
+ parentId = rootFile.id;
+ }
if (state.project.id) {
const postParams = {
name: createUniqueName(formProps.name, state.files),
content: '',
- parentId: rootFile.id,
+ children: [],
+ parentId,
fileType: 'folder'
};
axios.post(`${ROOT_URL}/projects/${state.project.id}/files`, postParams, { withCredentials: true })
@@ -134,7 +149,7 @@ export function createFolder(formProps) {
dispatch({
type: ActionTypes.CREATE_FILE,
...response.data,
- parentId: rootFile.id
+ parentId
});
dispatch({
type: ActionTypes.CLOSE_NEW_FOLDER_MODAL
@@ -153,8 +168,9 @@ export function createFolder(formProps) {
_id: id,
content: '',
// TODO pass parent id from File Tree
- parentId: rootFile.id,
- fileType: 'folder'
+ parentId,
+ fileType: 'folder',
+ children: []
});
dispatch({
type: ActionTypes.CLOSE_NEW_FOLDER_MODAL
diff --git a/client/modules/IDE/components/FileNode.js b/client/modules/IDE/components/FileNode.js
index 0ddf21f9..c68dda89 100644
--- a/client/modules/IDE/components/FileNode.js
+++ b/client/modules/IDE/components/FileNode.js
@@ -56,6 +56,7 @@ export class FileNode extends React.Component {
render() {
let itemClass = classNames({
+ 'sidebar__root-item': this.props.name === 'root',
'sidebar__file-item': this.props.name !== 'root',
'sidebar__file-item--selected': this.props.isSelected,
'sidebar__file-item--open': this.props.isOptionsOpen,
@@ -71,6 +72,7 @@ export class FileNode extends React.Component {
if (this.props.name !== 'root') {
return (
+
{(() => { // eslint-disable-line
if (this.props.fileType === 'file') {
return (
@@ -157,7 +159,7 @@ export class FileNode extends React.Component {
{(() => { // eslint-disable-line
if (this.props.children) {
return (
-
+
{this.props.children.map(this.renderChild)}
);
diff --git a/client/modules/IDE/components/NewFileModal.js b/client/modules/IDE/components/NewFileModal.js
index 0c32293a..784ec2a7 100644
--- a/client/modules/IDE/components/NewFileModal.js
+++ b/client/modules/IDE/components/NewFileModal.js
@@ -1,8 +1,6 @@
import React, { PropTypes } from 'react';
-import { bindActionCreators } from 'redux';
import { reduxForm } from 'redux-form';
import NewFileForm from './NewFileForm';
-import * as FileActions from '../actions/files';
import classNames from 'classnames';
import InlineSVG from 'react-inlinesvg';
const exitUrl = require('../../../images/exit.svg');
@@ -48,14 +46,6 @@ NewFileModal.propTypes = {
canUploadMedia: PropTypes.bool.isRequired
};
-function mapStateToProps() {
- return {};
-}
-
-function mapDispatchToProps(dispatch) {
- return bindActionCreators(FileActions, dispatch);
-}
-
function validate(formProps) {
const errors = {};
@@ -73,4 +63,4 @@ export default reduxForm({
form: 'new-file',
fields: ['name'],
validate
-}, mapStateToProps, mapDispatchToProps)(NewFileModal);
+})(NewFileModal);
diff --git a/client/modules/IDE/pages/IDEView.js b/client/modules/IDE/pages/IDEView.js
index 2a0bceef..4d8274c7 100644
--- a/client/modules/IDE/pages/IDEView.js
+++ b/client/modules/IDE/pages/IDEView.js
@@ -258,6 +258,7 @@ class IDEView extends React.Component {
);
}
@@ -393,7 +394,8 @@ IDEView.propTypes = {
closeProjectOptions: PropTypes.func.isRequired,
newFolder: PropTypes.func.isRequired,
closeNewFolderModal: PropTypes.func.isRequired,
- createFolder: PropTypes.func.isRequired
+ createFolder: PropTypes.func.isRequired,
+ createFile: PropTypes.func.isRequired,
};
function mapStateToProps(state) {
diff --git a/client/modules/IDE/reducers/files.js b/client/modules/IDE/reducers/files.js
index 1bc4a369..7fd7353a 100644
--- a/client/modules/IDE/reducers/files.js
+++ b/client/modules/IDE/reducers/files.js
@@ -111,6 +111,7 @@ const files = (state, action) => {
_id: action._id,
content: action.content,
url: action.url,
+ children: action.children,
fileType: action.fileType || 'file' }];
}
case ActionTypes.SHOW_FILE_OPTIONS:
diff --git a/client/styles/components/_sidebar.scss b/client/styles/components/_sidebar.scss
index 103bb3c7..05b36de2 100644
--- a/client/styles/components/_sidebar.scss
+++ b/client/styles/components/_sidebar.scss
@@ -35,25 +35,49 @@
}
}
+.sidebar__root-item {
+ position: relative;
+}
+
.sidebar__file-item {
font-size: #{16 / $base-font-size}rem;
- padding: #{8 / $base-font-size}rem #{20 / $base-font-size}rem;
+ padding: #{8 / $base-font-size}rem 0;
color: $light-inactive-text-color;
cursor: pointer;
&--selected {
background-color: $ide-border-color;
}
- &:hover .sidebar__file-item-name {
+ &:hover > .file-item__content .sidebar__file-item-name {
color: $light-primary-text-color;
}
- &:hover .sidebar__file-item-icon g {
+ &:hover > .file-item__content .sidebar__file-item-icon g {
fill: $light-primary-text-color;
}
}
+// to indent each row in the file tree
+// not sure how to do this in a better way
+// it won't work if the file tree is too nested
+.file-item__spacer {
+ .sidebar__file-item & {
+ width: #{20 / $base-font-size}rem;
+ .sidebar__file-item & {
+ width: #{40 / $base-font-size}rem;
+ .sidebar__file-item & {
+ width: #{60 / $base-font-size}rem;
+ .sidebar__file-item & {
+ width: #{80 / $base-font-size}rem;
+ .sidebar__file-item & {
+ width: #{100 / $base-font-size}rem;
+ }
+ }
+ }
+ }
+ }
+}
+
.file-item__content {
display: flex;
- // justify-content: space-between;
position: relative;
}
@@ -66,9 +90,9 @@
.sidebar__file-item-show-options {
@extend %icon;
display: none;
- margin-left: auto;
- margin-right: 0;
- .sidebar__file-item--selected & {
+ position: absolute;
+ right: #{20 / $base-font-size}rem;
+ .sidebar__file-item--selected > .file-item__content & {
display: inline-block;
}
}
@@ -84,7 +108,7 @@
padding: #{8 / $base-font-size}rem #{16 / $base-font-size}rem;
background-color: $light-modal-background-color;
z-index: 100;
- .sidebar__file-item--open & {
+ .sidebar__file-item--open > .file-item__content & {
display: block;
}
}