diff --git a/client/constants.js b/client/constants.js index 2c4ab775..459fe4f5 100644 --- a/client/constants.js +++ b/client/constants.js @@ -65,5 +65,10 @@ export const SET_LINT_WARNING = 'SET_LINT_WARNING'; export const SET_PREFERENCES = 'SET_PREFERENCES'; export const SET_TEXT_OUTPUT = 'SET_TEXT_OUTPUT'; +export const OPEN_PROJECT_OPTIONS = 'OPEN_PROJECT_OPTIONS'; +export const CLOSE_PROJECT_OPTIONS = 'CLOSE_PROJECT_OPTIONS'; +export const SHOW_NEW_FOLDER_MODAL = 'SHOW_NEW_FOLDER_MODAL'; +export const CLOSE_NEW_FOLDER_MODAL = 'CLOSE_NEW_FOLDER_MODAL'; + // eventually, handle errors more specifically and better export const ERROR = 'ERROR'; diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js index aeba6588..5d839465 100644 --- a/client/modules/IDE/actions/files.js +++ b/client/modules/IDE/actions/files.js @@ -118,6 +118,51 @@ export function createFile(formProps) { }; } +export function createFolder(formProps) { + return (dispatch, getState) => { + const state = getState(); + const rootFile = state.files.filter(file => file.name === 'root')[0]; + if (state.project.id) { + const postParams = { + name: createUniqueName(formProps.name, state.files), + content: '', + parentId: rootFile.id, + fileType: 'folder' + }; + axios.post(`${ROOT_URL}/projects/${state.project.id}/files`, postParams, { withCredentials: true }) + .then(response => { + dispatch({ + type: ActionTypes.CREATE_FILE, + ...response.data, + parentId: rootFile.id + }); + dispatch({ + type: ActionTypes.CLOSE_NEW_FOLDER_MODAL + }); + }) + .catch(response => dispatch({ + type: ActionTypes.ERROR, + error: response.data + })); + } else { + const id = objectID().toHexString(); + dispatch({ + type: ActionTypes.CREATE_FILE, + name: createUniqueName(formProps.name, state.files), + id, + _id: id, + content: '', + // TODO pass parent id from File Tree + parentId: rootFile.id, + fileType: 'folder' + }); + dispatch({ + type: ActionTypes.CLOSE_NEW_FOLDER_MODAL + }); + } + }; +} + export function showFileOptions(fileId) { return { type: ActionTypes.SHOW_FILE_OPTIONS, diff --git a/client/modules/IDE/actions/ide.js b/client/modules/IDE/actions/ide.js index da636d05..1cc1fe1c 100644 --- a/client/modules/IDE/actions/ide.js +++ b/client/modules/IDE/actions/ide.js @@ -102,3 +102,27 @@ export function closePreferences() { type: ActionTypes.CLOSE_PREFERENCES }; } + +export function openProjectOptions() { + return { + type: ActionTypes.OPEN_PROJECT_OPTIONS + }; +} + +export function closeProjectOptions() { + return { + type: ActionTypes.CLOSE_PROJECT_OPTIONS + }; +} + +export function newFolder() { + return { + type: ActionTypes.SHOW_NEW_FOLDER_MODAL + }; +} + +export function closeNewFolderModal() { + return { + type: ActionTypes.CLOSE_NEW_FOLDER_MODAL + }; +} diff --git a/client/modules/IDE/components/FileNode.js b/client/modules/IDE/components/FileNode.js index ebd3abf1..46f3f488 100644 --- a/client/modules/IDE/components/FileNode.js +++ b/client/modules/IDE/components/FileNode.js @@ -65,14 +65,14 @@ export class FileNode extends React.Component {
setTimeout(() => this.props.hideFileOptions(this.props.id), 100)} + onBlur={() => setTimeout(() => this.props.hideFileOptions(this.props.id), 200)} > {(() => { // eslint-disable-line if (this.props.name !== 'root') { return (
{(() => { // eslint-disable-line - if (this.props.type === 'file') { + if (this.props.fileType === 'file') { return ( @@ -151,7 +151,7 @@ FileNode.propTypes = { parentId: PropTypes.string, children: PropTypes.array, name: PropTypes.string.isRequired, - type: PropTypes.string.isRequired, + fileType: PropTypes.string.isRequired, isSelected: PropTypes.bool, isOptionsOpen: PropTypes.bool, isEditingName: PropTypes.bool, diff --git a/client/modules/IDE/components/NewFileForm.js b/client/modules/IDE/components/NewFileForm.js index 782c13a4..8935ee44 100644 --- a/client/modules/IDE/components/NewFileForm.js +++ b/client/modules/IDE/components/NewFileForm.js @@ -1,20 +1,32 @@ import React, { PropTypes } from 'react'; -function NewFileForm(props) { - const { fields: { name }, handleSubmit } = props; - return ( -
- - - -
- ); +class NewFileForm extends React.Component { + constructor(props) { + super(props); + this.createFile = this.props.createFile.bind(this); + } + + componentDidMount() { + this.refs.fileName.focus(); + } + + render() { + const { fields: { name }, handleSubmit } = this.props; + return ( +
+ + + +
+ ); + } } NewFileForm.propTypes = { diff --git a/client/modules/IDE/components/NewFileModal.js b/client/modules/IDE/components/NewFileModal.js index b070ab9f..0c32293a 100644 --- a/client/modules/IDE/components/NewFileModal.js +++ b/client/modules/IDE/components/NewFileModal.js @@ -12,40 +12,35 @@ import FileUploader from './FileUploader'; // At some point this will probably be generalized to a generic modal // in which you can insert different content // but for now, let's just make this work -class NewFileModal extends React.Component { - componentDidMount() { - document.getElementById('name').focus(); - } - render() { - const modalClass = classNames({ - modal: true, - 'modal--reduced': !this.props.canUploadMedia - }); - return ( -
-
-
-

Add File

- -
- - {(() => { - if (this.props.canUploadMedia) { - return ( -
-

OR

- -
- ); - } - return ''; - })()} +function NewFileModal(props) { + const modalClass = classNames({ + modal: true, + 'modal--reduced': !props.canUploadMedia + }); + return ( +
+
+
+

Add File

+
-
- ); - } + + {(() => { + if (props.canUploadMedia) { + return ( +
+

OR

+ +
+ ); + } + return ''; + })()} +
+
+ ); } NewFileModal.propTypes = { @@ -53,10 +48,8 @@ NewFileModal.propTypes = { canUploadMedia: PropTypes.bool.isRequired }; -function mapStateToProps(state) { - return { - file: state.files - }; +function mapStateToProps() { + return {}; } function mapDispatchToProps(dispatch) { diff --git a/client/modules/IDE/components/NewFolderForm.js b/client/modules/IDE/components/NewFolderForm.js new file mode 100644 index 00000000..92007393 --- /dev/null +++ b/client/modules/IDE/components/NewFolderForm.js @@ -0,0 +1,36 @@ +import React, { PropTypes } from 'react'; + +class NewFolderForm extends React.Component { + constructor(props) { + super(props); + this.createFolder = this.props.createFolder.bind(this); + } + + render() { + const { fields: { name }, handleSubmit } = this.props; + return ( +
+ + + +
+ ); + } +} + +NewFolderForm.propTypes = { + fields: PropTypes.shape({ + name: PropTypes.string.isRequired + }).isRequired, + handleSubmit: PropTypes.func.isRequired, + createFolder: PropTypes.func.isRequired +}; + +export default NewFolderForm; diff --git a/client/modules/IDE/components/NewFolderModal.js b/client/modules/IDE/components/NewFolderModal.js new file mode 100644 index 00000000..776434a7 --- /dev/null +++ b/client/modules/IDE/components/NewFolderModal.js @@ -0,0 +1,31 @@ +import React, { PropTypes } from 'react'; +import { reduxForm } from 'redux-form'; +import InlineSVG from 'react-inlinesvg'; +const exitUrl = require('../../../images/exit.svg'); +import NewFolderForm from './NewFolderForm'; + +function NewFolderModal(props) { + return ( +
+
+
+

Add Folder

+ +
+ +
+
+ ); +} + +NewFolderModal.propTypes = { + closeModal: PropTypes.func.isRequired +}; + +export default reduxForm({ + form: 'new-folder', + fields: ['name'] +})(NewFolderModal); + diff --git a/client/modules/IDE/components/Sidebar.js b/client/modules/IDE/components/Sidebar.js index 64a2af52..fdd1fbb9 100644 --- a/client/modules/IDE/components/Sidebar.js +++ b/client/modules/IDE/components/Sidebar.js @@ -21,7 +21,8 @@ class Sidebar extends React.Component { render() { const sidebarClass = classNames({ sidebar: true, - 'sidebar--contracted': !this.props.isExpanded + 'sidebar--contracted': !this.props.isExpanded, + 'sidebar--project-options': this.props.projectOptionsVisible }); return ( @@ -35,12 +36,25 @@ class Sidebar extends React.Component {
+