From 7a84137e9b03a986da4e77d86db489bf330e0c27 Mon Sep 17 00:00:00 2001 From: catarak Date: Fri, 8 Jul 2016 14:57:22 -0400 Subject: [PATCH] start to add selected file stuff --- client/constants.js | 2 ++ client/modules/IDE/actions/project.js | 13 +++++++++++-- client/modules/IDE/components/Sidebar.js | 24 +++++++++++++++++------- client/modules/IDE/pages/IDEView.js | 18 ++++++++++++++---- client/modules/IDE/reducers/files.js | 10 ++++++++-- client/modules/IDE/reducers/ide.js | 7 ++++++- package.json | 1 + server/controllers/project.controller.js | 3 +-- server/models/project.js | 11 ++++++++++- 9 files changed, 70 insertions(+), 19 deletions(-) diff --git a/client/constants.js b/client/constants.js index b69e22b2..1a4f1741 100644 --- a/client/constants.js +++ b/client/constants.js @@ -23,5 +23,7 @@ export const NEW_PROJECT = 'NEW_PROJECT'; export const SET_PROJECT = 'SET_PROJECT'; export const SET_PROJECTS = 'SET_PROJECTS'; +export const SET_SELECTED_FILE = 'SET_SELECTED_FILE'; + // eventually, handle errors more specifically and better export const ERROR = 'ERROR'; diff --git a/client/modules/IDE/actions/project.js b/client/modules/IDE/actions/project.js index 8d4e1e56..8f820c30 100644 --- a/client/modules/IDE/actions/project.js +++ b/client/modules/IDE/actions/project.js @@ -12,7 +12,8 @@ export function getProject(id) { dispatch({ type: ActionTypes.SET_PROJECT, project: response.data, - files: response.data.files + files: response.data.files, + selectedFile: response.data.selectedFile }); }) .catch(response => dispatch({ @@ -34,7 +35,7 @@ export function saveProject() { return (dispatch, getState) => { const state = getState(); const formParams = Object.assign({}, state.project); - formParams.files = state.files; + formParams.files = [...state.files]; if (state.project.id) { axios.put(`${ROOT_URL}/projects/${state.project.id}`, formParams, { withCredentials: true }) .then(() => { @@ -47,6 +48,12 @@ export function saveProject() { error: response.data })); } else { + // this might be unnecessary, but to prevent collisions in mongodb + formParams.files.map(file => { + const newFile = Object.assign({}, file); + delete newFile.id; + return newFile; + }); axios.post(`${ROOT_URL}/projects`, formParams, { withCredentials: true }) .then(response => { browserHistory.push(`/projects/${response.data.id}`); @@ -54,6 +61,7 @@ export function saveProject() { type: ActionTypes.NEW_PROJECT, name: response.data.name, id: response.data.id, + selectedFile: response.data.selectedFile, files: response.data.files }); }) @@ -75,6 +83,7 @@ export function createProject() { type: ActionTypes.NEW_PROJECT, name: response.data.name, id: response.data.id, + selectedFile: response.data.selectedFile, files: response.data.files }); }) diff --git a/client/modules/IDE/components/Sidebar.js b/client/modules/IDE/components/Sidebar.js index 3c5d0fe6..4fe0b85b 100644 --- a/client/modules/IDE/components/Sidebar.js +++ b/client/modules/IDE/components/Sidebar.js @@ -1,22 +1,32 @@ import React, { PropTypes } from 'react'; +import classNames from 'classnames'; function Sidebar(props) { return (
); } Sidebar.propTypes = { - files: PropTypes.array.isRequired + files: PropTypes.array.isRequired, + selectedFile: PropTypes.shape({ + id: PropTypes.string.isRequired + }) }; export default Sidebar; diff --git a/client/modules/IDE/pages/IDEView.js b/client/modules/IDE/pages/IDEView.js index 2278a095..6d891791 100644 --- a/client/modules/IDE/pages/IDEView.js +++ b/client/modules/IDE/pages/IDEView.js @@ -11,6 +11,7 @@ import * as FileActions from '../actions/files'; import * as IDEActions from '../actions/ide'; import * as PreferencesActions from '../actions/preferences'; import * as ProjectActions from '../actions/project'; +import { getFile } from '../reducers/files'; class IDEView extends React.Component { componentDidMount() { @@ -45,14 +46,18 @@ class IDEView extends React.Component { decreaseFont={this.props.decreaseFont} fontSize={this.props.preferences.fontSize} /> - + } @@ -89,12 +94,17 @@ IDEView.propTypes = { increaseFont: PropTypes.func.isRequired, decreaseFont: PropTypes.func.isRequired, files: PropTypes.array.isRequired, - updateFileContent: PropTypes.func.isRequired + updateFileContent: PropTypes.func.isRequired, + selectedFile: PropTypes.shape({ + id: PropTypes.string, + content: PropTypes.string.isRequired + }) }; function mapStateToProps(state) { return { files: state.files, + selectedFile: getFile(state.files, state.ide.selectedFile), ide: state.ide, preferences: state.preferences, user: state.user, diff --git a/client/modules/IDE/reducers/files.js b/client/modules/IDE/reducers/files.js index 3a1a03d5..a8bb6991 100644 --- a/client/modules/IDE/reducers/files.js +++ b/client/modules/IDE/reducers/files.js @@ -20,14 +20,18 @@ const defaultHTML = `; + +// if the project has never been saved, const initialState = [ { name: 'sketch.js', - content: defaultSketch + content: defaultSketch, + id: '1' }, { name: 'index.html', - content: defaultHTML + content: defaultHTML, + id: '2' }]; @@ -50,4 +54,6 @@ const files = (state = initialState, action) => { } }; +export const getFile = (state, id) => state.filter(file => file.id === id)[0]; + export default files; diff --git a/client/modules/IDE/reducers/ide.js b/client/modules/IDE/reducers/ide.js index e89ffdee..5d80ca81 100644 --- a/client/modules/IDE/reducers/ide.js +++ b/client/modules/IDE/reducers/ide.js @@ -1,7 +1,8 @@ import * as ActionTypes from '../../../constants'; const initialState = { - isPlaying: false + isPlaying: false, + selectedFile: '1' }; const ide = (state = initialState, action) => { @@ -18,6 +19,10 @@ const ide = (state = initialState, action) => { return { isPlaying: false }; + case ActionTypes.SET_SELECTED_FILE: + case ActionTypes.SET_PROJECT: + case ActionTypes.NEW_PROJECT: + return Object.assign({}, state, { selectedFile: action.selectedFile }); default: return state; } diff --git a/package.json b/package.json index 53f5d57d..6d64719d 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "babel-core": "^6.8.0", "bcrypt-nodejs": "0.0.3", "body-parser": "^1.15.1", + "bson-objectid": "^1.1.4", "classnames": "^2.2.5", "codemirror": "^5.14.2", "connect-mongo": "^1.2.0", diff --git a/server/controllers/project.controller.js b/server/controllers/project.controller.js index 03baa4e5..6c8f55c4 100644 --- a/server/controllers/project.controller.js +++ b/server/controllers/project.controller.js @@ -2,8 +2,7 @@ import Project from '../models/project'; export function createProject(req, res) { const projectValues = { - user: req.user ? req.user._id : undefined, // eslint-disable-line no-underscore-dangle - file: {} + user: req.user ? req.user._id : undefined // eslint-disable-line no-underscore-dangle }; Object.assign(projectValues, req.body); diff --git a/server/models/project.js b/server/models/project.js index 709ea58d..b000843d 100644 --- a/server/models/project.js +++ b/server/models/project.js @@ -40,7 +40,8 @@ const projectSchema = new Schema({ name: { type: String, default: "Hello p5.js, it's the server" }, user: { type: Schema.Types.ObjectId, ref: 'User' }, files: {type: [ fileSchema ], default: [{ name: 'sketch.js', content: defaultSketch, _id: new ObjectId() }, { name: 'index.html', content: defaultHTML, _id: new ObjectId() }]}, - _id: { type: String, default: shortid.generate } + _id: { type: String, default: shortid.generate }, + selectedFile: Schema.Types.ObjectId }, { timestamps: true }); projectSchema.virtual('id').get(function(){ @@ -51,4 +52,12 @@ projectSchema.set('toJSON', { virtuals: true }); +projectSchema.pre('save', function createSelectedFile(next) { + const project = this; + if (!project.selectedFile) { + project.selectedFile = project.files[0]._id; // eslint-disable-line no-underscore-dangle + return next(); + } +}); + export default mongoose.model('Project', projectSchema);