From b2369704a2b14ee4d7ba075c526caef8532f9238 Mon Sep 17 00:00:00 2001
From: catarak
Date: Fri, 1 Jul 2016 11:30:40 -0400
Subject: [PATCH 01/17] start sketch list view
---
client/components/Nav.js | 7 +++
client/constants.js | 1 +
client/modules/Sketch/actions.js | 20 ++++++++
client/modules/Sketch/pages/SketchListView.js | 50 +++++++++++++++++++
client/modules/Sketch/reducers.js | 12 +++++
client/reducers.js | 4 +-
client/routes.js | 2 +
server/controllers/project.controller.js | 15 ++++++
server/routes/project.routes.js | 2 +
9 files changed, 112 insertions(+), 1 deletion(-)
create mode 100644 client/modules/Sketch/actions.js
create mode 100644 client/modules/Sketch/pages/SketchListView.js
create mode 100644 client/modules/Sketch/reducers.js
diff --git a/client/components/Nav.js b/client/components/Nav.js
index 687f4b7a..ddccbc1a 100644
--- a/client/components/Nav.js
+++ b/client/components/Nav.js
@@ -21,6 +21,13 @@ function Nav(props) {
Save
+
+
+
+ Open
+
+
+
-
diff --git a/client/constants.js b/client/constants.js
index 2f5571d5..446a6c34 100644
--- a/client/constants.js
+++ b/client/constants.js
@@ -21,6 +21,7 @@ export const PROJECT_SAVE_FAIL = 'PROJECT_SAVE_FAIL';
export const NEW_PROJECT = 'NEW_PROJECT';
export const SET_PROJECT = 'SET_PROJECT';
+export const SET_PROJECTS = 'SET_PROJECTS';
// eventually, handle errors more specifically and better
export const ERROR = 'ERROR';
diff --git a/client/modules/Sketch/actions.js b/client/modules/Sketch/actions.js
new file mode 100644
index 00000000..ed980d4e
--- /dev/null
+++ b/client/modules/Sketch/actions.js
@@ -0,0 +1,20 @@
+import * as ActionTypes from '../../constants';
+import axios from 'axios';
+
+const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
+
+export function getProjects() {
+ return (dispatch) => {
+ axios.get(`${ROOT_URL}/projects`, { withCredentials: true })
+ .then(response => {
+ dispatch({
+ type: ActionTypes.SET_PROJECTS,
+ projects: response.data
+ });
+ })
+ .catch(response => dispatch({
+ type: ActionTypes.ERROR,
+ error: response.data
+ }));
+ };
+}
diff --git a/client/modules/Sketch/pages/SketchListView.js b/client/modules/Sketch/pages/SketchListView.js
new file mode 100644
index 00000000..caea9d76
--- /dev/null
+++ b/client/modules/Sketch/pages/SketchListView.js
@@ -0,0 +1,50 @@
+import React, { PropTypes } from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import Nav from '../../../components/Nav';
+import * as SketchActions from '../actions';
+import * as ProjectActions from '../../IDE/actions/project';
+
+class SketchListView extends React.Component {
+ componentDidMount() {
+ this.props.getProjects();
+ }
+
+ render() {
+ return (
+
+
+
+ {this.props.sketches.map(sketch =>
+ - {sketch.name}
+ )}
+
+
+ );
+ }
+}
+
+SketchListView.propTypes = {
+ user: PropTypes.object.isRequired,
+ createProject: PropTypes.func.isRequired,
+ saveProject: PropTypes.func.isRequired,
+ getProjects: PropTypes.func.isRequired,
+ sketches: PropTypes.array.isRequired
+};
+
+function mapStateToProps(state) {
+ return {
+ user: state.user,
+ sketches: state.sketches
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return bindActionCreators(Object.assign({}, SketchActions, ProjectActions), dispatch);
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(SketchListView);
diff --git a/client/modules/Sketch/reducers.js b/client/modules/Sketch/reducers.js
new file mode 100644
index 00000000..6f0d2e14
--- /dev/null
+++ b/client/modules/Sketch/reducers.js
@@ -0,0 +1,12 @@
+import * as ActionTypes from '../../constants';
+
+const sketches = (state = [], action) => {
+ switch (action.type) {
+ case ActionTypes.SET_PROJECTS:
+ return action.projects;
+ default:
+ return state;
+ }
+};
+
+export default sketches;
diff --git a/client/reducers.js b/client/reducers.js
index 839e4d75..64305956 100644
--- a/client/reducers.js
+++ b/client/reducers.js
@@ -4,6 +4,7 @@ import ide from './modules/IDE/reducers/ide';
import preferences from './modules/IDE/reducers/preferences';
import project from './modules/IDE/reducers/project';
import user from './modules/User/reducers';
+import sketches from './modules/Sketch/reducers';
import { reducer as form } from 'redux-form';
const rootReducer = combineReducers({
@@ -12,7 +13,8 @@ const rootReducer = combineReducers({
file,
preferences,
user,
- project
+ project,
+ sketches
});
export default rootReducer;
diff --git a/client/routes.js b/client/routes.js
index 12523a3d..e071eb7f 100644
--- a/client/routes.js
+++ b/client/routes.js
@@ -4,6 +4,7 @@ import App from './modules/App/App';
import IDEView from './modules/IDE/pages/IDEView';
import LoginView from './modules/User/pages/LoginView';
import SignupView from './modules/User/pages/SignupView';
+import SketchListView from './modules/Sketch/pages/SketchListView';
import { getUser } from './modules/User/actions';
const checkAuth = (store) => {
@@ -17,6 +18,7 @@ const routes = (store) =>
+
);
diff --git a/server/controllers/project.controller.js b/server/controllers/project.controller.js
index 656c884f..5afb8ca2 100644
--- a/server/controllers/project.controller.js
+++ b/server/controllers/project.controller.js
@@ -54,3 +54,18 @@ export function getProject(req, res) {
});
});
}
+
+export function getProjects(req, res) {
+ if (req.user) {
+ Project.find({user: req.user._id}) // eslint-disable-line no-underscore-dangle
+ .sort('-createdAt')
+ .select('name file _id')
+ .exec((err, projects) => {
+ res.json(projects);
+ });
+ } else {
+ // could just move this to client side
+ return res.json([]);
+ }
+
+}
diff --git a/server/routes/project.routes.js b/server/routes/project.routes.js
index 2a31e632..ee8f4654 100644
--- a/server/routes/project.routes.js
+++ b/server/routes/project.routes.js
@@ -9,4 +9,6 @@ router.route('/projects/:project_id').put(ProjectController.updateProject);
router.route('/projects/:project_id').get(ProjectController.getProject);
+router.route('/projects').get(ProjectController.getProjects);
+
export default router;
From 6563d9d90b9a2cb0d335860807e31f268fef6242 Mon Sep 17 00:00:00 2001
From: catarak
Date: Tue, 5 Jul 2016 16:04:14 -0400
Subject: [PATCH 02/17] add sketch list, with links
---
client/modules/Sketch/pages/SketchListView.js | 23 +++++++++++++++----
client/styles/base/_base.scss | 4 ++++
client/styles/base/_reset.scss | 4 ++++
client/styles/components/_sketch-list.scss | 9 ++++++++
client/styles/layout/_sketch-list.scss | 6 +++++
client/styles/main.scss | 2 ++
package.json | 1 +
server/controllers/project.controller.js | 2 +-
server/routes/server.routes.js | 4 ++++
9 files changed, 49 insertions(+), 6 deletions(-)
create mode 100644 client/styles/components/_sketch-list.scss
create mode 100644 client/styles/layout/_sketch-list.scss
diff --git a/client/modules/Sketch/pages/SketchListView.js b/client/modules/Sketch/pages/SketchListView.js
index caea9d76..fec25baf 100644
--- a/client/modules/Sketch/pages/SketchListView.js
+++ b/client/modules/Sketch/pages/SketchListView.js
@@ -1,6 +1,8 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
+import moment from 'moment';
+import { Link } from 'react-router';
import Nav from '../../../components/Nav';
import * as SketchActions from '../actions';
import * as ProjectActions from '../../IDE/actions/project';
@@ -18,11 +20,22 @@ class SketchListView extends React.Component {
createProject={this.props.createProject}
saveProject={this.props.saveProject}
/>
-
- {this.props.sketches.map(sketch =>
- - {sketch.name}
- )}
-
+
+
+ Name |
+ Created |
+ Last Updated |
+
+
+ {this.props.sketches.map(sketch =>
+
+ {sketch.name} |
+ {moment(sketch.createdAt).format('MMM D, YYYY')} |
+ {moment(sketch.updatedAt).format('MMM D, YYYY')} |
+
+ )}
+
+
);
}
diff --git a/client/styles/base/_base.scss b/client/styles/base/_base.scss
index 6a66bf88..f11b8d96 100644
--- a/client/styles/base/_base.scss
+++ b/client/styles/base/_base.scss
@@ -45,4 +45,8 @@ h2 {
h3 {
font-weight: normal;
+}
+
+thead {
+ text-align: left;
}
\ No newline at end of file
diff --git a/client/styles/base/_reset.scss b/client/styles/base/_reset.scss
index c36505ce..33cf3b32 100644
--- a/client/styles/base/_reset.scss
+++ b/client/styles/base/_reset.scss
@@ -14,4 +14,8 @@ ul, p {
h2, h3 {
margin: 0;
+}
+
+ul {
+ list-style: none;
}
\ No newline at end of file
diff --git a/client/styles/components/_sketch-list.scss b/client/styles/components/_sketch-list.scss
new file mode 100644
index 00000000..9ef6a786
--- /dev/null
+++ b/client/styles/components/_sketch-list.scss
@@ -0,0 +1,9 @@
+.sketches-table {
+ width: 100%;
+ padding: #{10 / $base-font-size}rem 0;
+ padding-left: #{170 / $base-font-size}rem;
+}
+
+.sketches-table__row {
+ margin: #{10 / $base-font-size}rem;
+}
\ No newline at end of file
diff --git a/client/styles/layout/_sketch-list.scss b/client/styles/layout/_sketch-list.scss
new file mode 100644
index 00000000..979c48d4
--- /dev/null
+++ b/client/styles/layout/_sketch-list.scss
@@ -0,0 +1,6 @@
+.sketch-list {
+ display: flex;
+ flex-wrap: wrap;
+ height: 100%;
+ flex-flow: column;
+}
\ No newline at end of file
diff --git a/client/styles/main.scss b/client/styles/main.scss
index 1e23ae9d..74e48bc4 100644
--- a/client/styles/main.scss
+++ b/client/styles/main.scss
@@ -13,5 +13,7 @@
@import 'components/preferences';
@import 'components/signup';
@import 'components/login';
+@import 'components/sketch-list';
@import 'layout/ide';
+@import 'layout/sketch-list';
diff --git a/package.json b/package.json
index 168f71b7..53f5d57d 100644
--- a/package.json
+++ b/package.json
@@ -68,6 +68,7 @@
"eslint-loader": "^1.3.0",
"express": "^4.13.4",
"express-session": "^1.13.0",
+ "moment": "^2.14.1",
"mongoose": "^4.4.16",
"passport": "^0.3.2",
"passport-github": "^1.1.0",
diff --git a/server/controllers/project.controller.js b/server/controllers/project.controller.js
index 5afb8ca2..bc621ed1 100644
--- a/server/controllers/project.controller.js
+++ b/server/controllers/project.controller.js
@@ -59,7 +59,7 @@ export function getProjects(req, res) {
if (req.user) {
Project.find({user: req.user._id}) // eslint-disable-line no-underscore-dangle
.sort('-createdAt')
- .select('name file _id')
+ .select('name file _id createdAt updatedAt')
.exec((err, projects) => {
res.json(projects);
});
diff --git a/server/routes/server.routes.js b/server/routes/server.routes.js
index ccff0582..90dda69d 100644
--- a/server/routes/server.routes.js
+++ b/server/routes/server.routes.js
@@ -21,4 +21,8 @@ router.route('/login').get((req, res) => {
res.sendFile(path.resolve(`${__dirname}/../../index.html`));
});
+router.route('/sketches').get((req, res) => {
+ res.sendFile(path.resolve(`${__dirname}/../../index.html`));
+});
+
export default router;
From e6d94a0db8ec5cc223661a79b74c218437b8460d Mon Sep 17 00:00:00 2001
From: catarak
Date: Wed, 6 Jul 2016 15:09:05 -0400
Subject: [PATCH 03/17] start to add multiple file functionality
---
client/constants.js | 2 +-
client/modules/IDE/components/Sidebar.js | 19 ++++++
client/modules/IDE/pages/IDEView.js | 12 ++--
client/modules/IDE/reducers/files.js | 74 +++++++++++++-----------
client/reducers.js | 4 +-
client/styles/abstracts/_variables.scss | 2 +-
client/styles/components/_editor.scss | 2 +-
client/styles/components/_sidebar.scss | 13 +++++
client/styles/layout/_ide.scss | 8 ++-
client/styles/main.scss | 1 +
server/models/project.js | 14 ++++-
11 files changed, 103 insertions(+), 48 deletions(-)
create mode 100644 client/modules/IDE/components/Sidebar.js
create mode 100644 client/styles/components/_sidebar.scss
diff --git a/client/constants.js b/client/constants.js
index 446a6c34..29d9f701 100644
--- a/client/constants.js
+++ b/client/constants.js
@@ -1,4 +1,4 @@
-export const CHANGE_SELECTED_FILE = 'CHANGE_SELECTED_FILE';
+export const UPDATE_FILE = 'UPDATE_FILE';
export const TOGGLE_SKETCH = 'TOGGLE_SKETCH';
export const START_SKETCH = 'START_SKETCH';
diff --git a/client/modules/IDE/components/Sidebar.js b/client/modules/IDE/components/Sidebar.js
new file mode 100644
index 00000000..bcf11473
--- /dev/null
+++ b/client/modules/IDE/components/Sidebar.js
@@ -0,0 +1,19 @@
+import React, { PropTypes } from 'react';
+
+function Sidebar(props) {
+ return (
+
+
+ {props.files.map(file =>
+ - {file.name}
+ )}
+
+
+ );
+}
+
+Sidebar.propTypes = {
+ files: PropTypes.array.isRequired
+};
+
+export default Sidebar;
diff --git a/client/modules/IDE/pages/IDEView.js b/client/modules/IDE/pages/IDEView.js
index cb4c2ce1..6b74c737 100644
--- a/client/modules/IDE/pages/IDEView.js
+++ b/client/modules/IDE/pages/IDEView.js
@@ -1,5 +1,6 @@
import React, { PropTypes } from 'react';
import Editor from '../components/Editor';
+import Sidebar from '../components/Sidebar';
import PreviewFrame from '../components/PreviewFrame';
import Toolbar from '../components/Toolbar';
import Preferences from '../components/Preferences';
@@ -44,13 +45,14 @@ class IDEView extends React.Component {
decreaseFont={this.props.decreaseFont}
fontSize={this.props.preferences.fontSize}
/>
+
}
@@ -86,15 +88,13 @@ IDEView.propTypes = {
closePreferences: PropTypes.func.isRequired,
increaseFont: PropTypes.func.isRequired,
decreaseFont: PropTypes.func.isRequired,
- file: PropTypes.shape({
- content: PropTypes.string.isRequired
- }).isRequired,
+ files: PropTypes.array.isRequired,
updateFile: PropTypes.func.isRequired
};
function mapStateToProps(state) {
return {
- file: state.file,
+ files: state.files,
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 3067b546..dc82f77b 100644
--- a/client/modules/IDE/reducers/files.js
+++ b/client/modules/IDE/reducers/files.js
@@ -1,50 +1,56 @@
import * as ActionTypes from '../../../constants';
-const initialState = {
- name: 'sketch.js',
- content: `function setup() {
+const defaultSketch = `function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
-}`
-};
+}`;
-const file = (state = initialState, action) => {
+const defaultHTML =
+`
+
+
+
+
+
+
+
+
+`;
+
+const initialState = [
+ {
+ name: 'sketch.js',
+ content: defaultSketch
+ },
+ {
+ name: 'index.html',
+ content: defaultHTML
+ }];
+
+
+const files = (state = initialState, action) => {
switch (action.type) {
- case ActionTypes.CHANGE_SELECTED_FILE:
- return {
- name: action.name,
- content: action.content
- };
+ case ActionTypes.UPDATE_FILE:
+ return state.map(file => {
+ if (file.name !== action.name) {
+ return file;
+ }
+
+ return {
+ name: file.name,
+ content: action.content
+ };
+ });
case ActionTypes.NEW_PROJECT:
- return {
- name: action.file.name,
- content: action.file.content
- };
+ return { ...action.files };
case ActionTypes.SET_PROJECT:
- return {
- name: action.file.name,
- content: action.file.content
- };
+ return { ...action.files };
default:
return state;
}
};
-export default file;
-
-// i'll add this in when there are multiple files
-// const files = (state = [], action) => {
-// switch (action.type) {
-// case ActionTypes.CHANGE_SELECTED_FILE:
-// //find the file with the name
-// //update it
-// //put in into the new array of files
-// default:
-// return state
-// }
-// }
-
-// export default files
+export default files;
diff --git a/client/reducers.js b/client/reducers.js
index 64305956..1dfafa9e 100644
--- a/client/reducers.js
+++ b/client/reducers.js
@@ -1,5 +1,5 @@
import { combineReducers } from 'redux';
-import file from './modules/IDE/reducers/files';
+import files from './modules/IDE/reducers/files';
import ide from './modules/IDE/reducers/ide';
import preferences from './modules/IDE/reducers/preferences';
import project from './modules/IDE/reducers/project';
@@ -10,7 +10,7 @@ import { reducer as form } from 'redux-form';
const rootReducer = combineReducers({
form,
ide,
- file,
+ files,
preferences,
user,
project,
diff --git a/client/styles/abstracts/_variables.scss b/client/styles/abstracts/_variables.scss
index 096ddd45..e07d9e55 100644
--- a/client/styles/abstracts/_variables.scss
+++ b/client/styles/abstracts/_variables.scss
@@ -35,6 +35,6 @@ $dark-button-background-active-color: #f10046;
$dark-button-hover-color: $white;
$dark-button-active-color: $white;
-$editor-border-color: #f4f4f4;
+$ide-border-color: #f4f4f4;
$editor-selected-line-color: #f3f3f3;
$input-border-color: #979797;
diff --git a/client/styles/components/_editor.scss b/client/styles/components/_editor.scss
index 65b8b2e8..5209e517 100644
--- a/client/styles/components/_editor.scss
+++ b/client/styles/components/_editor.scss
@@ -1,7 +1,7 @@
.CodeMirror {
font-family: Inconsolata, monospace;
height: 100%;
- border: 1px solid $editor-border-color;
+ border: 1px solid $ide-border-color;
}
.CodeMirror-linenumbers {
diff --git a/client/styles/components/_sidebar.scss b/client/styles/components/_sidebar.scss
new file mode 100644
index 00000000..afa53bc9
--- /dev/null
+++ b/client/styles/components/_sidebar.scss
@@ -0,0 +1,13 @@
+.sidebar__file-list {
+ padding: #{4 / $base-font-size}rem #{20 / $base-font-size}rem;
+ border-top: 1px solid $ide-border-color;
+}
+
+.sidebar__file-item {
+ padding: #{4 / $base-font-size}rem 0;
+ color: $light-inactive-text-color;
+}
+
+.sidebar__file-item--selected {
+ background-color: $ide-border-color;
+}
\ No newline at end of file
diff --git a/client/styles/layout/_ide.scss b/client/styles/layout/_ide.scss
index 6c90f921..ffb6561e 100644
--- a/client/styles/layout/_ide.scss
+++ b/client/styles/layout/_ide.scss
@@ -6,14 +6,18 @@
}
.editor-holder {
- width: 50%;
+ flex-grow: 1;
height: 100%;
}
.preview-frame {
- width: 50%;
+ flex-grow: 1;
}
.toolbar {
width: 100%;
}
+
+.sidebar {
+ width: #{140 / $base-font-size}rem;
+}
diff --git a/client/styles/main.scss b/client/styles/main.scss
index 74e48bc4..c16cff9d 100644
--- a/client/styles/main.scss
+++ b/client/styles/main.scss
@@ -14,6 +14,7 @@
@import 'components/signup';
@import 'components/login';
@import 'components/sketch-list';
+@import 'components/sidebar';
@import 'layout/ide';
@import 'layout/sketch-list';
diff --git a/server/models/project.js b/server/models/project.js
index 4dcac580..b5e5785f 100644
--- a/server/models/project.js
+++ b/server/models/project.js
@@ -9,6 +9,18 @@ draw() {
background(220);
}`
+const defaultHTML =
+`
+
+
+
+
+
+
+
+
+`
+
const fileSchema = new Schema({
name: { type: String, default: 'sketch.js' },
content: { type: String, default: defaultSketch }
@@ -17,7 +29,7 @@ const fileSchema = new Schema({
const projectSchema = new Schema({
name: { type: String, default: "Hello p5.js, it's the server" },
user: { type: Schema.Types.ObjectId, ref: 'User' },
- file: { type: fileSchema },
+ files: {type: [ fileSchema ], default: [{ name: 'sketch.js', content: defaultSketch }, { name: 'index.html', content: defaultHTML }]},
_id: { type: String, default: shortid.generate }
}, { timestamps: true });
From 6e12ed6524cfb217c9e2beb61dd9abfcbab20efa Mon Sep 17 00:00:00 2001
From: catarak
Date: Wed, 6 Jul 2016 17:29:07 -0400
Subject: [PATCH 04/17] fix default file on server, change file to files in
lots of places
---
client/modules/IDE/actions/project.js | 12 +++---------
client/modules/IDE/reducers/files.js | 4 ++--
server/controllers/project.controller.js | 15 +++------------
server/models/project.js | 4 ++--
4 files changed, 10 insertions(+), 25 deletions(-)
diff --git a/client/modules/IDE/actions/project.js b/client/modules/IDE/actions/project.js
index 1759c74b..3f5339d2 100644
--- a/client/modules/IDE/actions/project.js
+++ b/client/modules/IDE/actions/project.js
@@ -12,7 +12,7 @@ export function getProject(id) {
dispatch({
type: ActionTypes.SET_PROJECT,
project: response.data,
- file: response.data.file
+ files: response.data.files
});
})
.catch(response => dispatch({
@@ -54,10 +54,7 @@ export function saveProject() {
type: ActionTypes.NEW_PROJECT,
name: response.data.name,
id: response.data.id,
- file: {
- name: response.data.file.name,
- content: response.data.file.content
- }
+ files: response.data.files
});
})
.catch(response => dispatch({
@@ -78,10 +75,7 @@ export function createProject() {
type: ActionTypes.NEW_PROJECT,
name: response.data.name,
id: response.data.id,
- file: {
- name: response.data.file.name,
- content: response.data.file.content
- }
+ files: response.data.files
});
})
.catch(response => dispatch({
diff --git a/client/modules/IDE/reducers/files.js b/client/modules/IDE/reducers/files.js
index dc82f77b..eca66fb1 100644
--- a/client/modules/IDE/reducers/files.js
+++ b/client/modules/IDE/reducers/files.js
@@ -45,9 +45,9 @@ const files = (state = initialState, action) => {
};
});
case ActionTypes.NEW_PROJECT:
- return { ...action.files };
+ return [...action.files];
case ActionTypes.SET_PROJECT:
- return { ...action.files };
+ return [...action.files];
default:
return state;
}
diff --git a/server/controllers/project.controller.js b/server/controllers/project.controller.js
index bc621ed1..c4a4887a 100644
--- a/server/controllers/project.controller.js
+++ b/server/controllers/project.controller.js
@@ -13,10 +13,7 @@ export function createProject(req, res) {
return res.json({
id: newProject._id, // eslint-disable-line no-underscore-dangle
name: newProject.name,
- file: {
- name: newProject.file.name,
- content: newProject.file.content
- }
+ files: newProject.files
});
});
}
@@ -30,10 +27,7 @@ export function updateProject(req, res) {
return res.json({
id: updatedProject._id, // eslint-disable-line no-underscore-dangle
name: updatedProject.name,
- file: {
- name: updatedProject.file.name,
- content: updatedProject.file.content
- }
+ file: updatedProject.files
});
});
}
@@ -47,10 +41,7 @@ export function getProject(req, res) {
return res.json({
id: project._id, // eslint-disable-line no-underscore-dangle
name: project.name,
- file: {
- name: project.file.name,
- content: project.file.content
- }
+ files: project.files
});
});
}
diff --git a/server/models/project.js b/server/models/project.js
index b5e5785f..a1306dc7 100644
--- a/server/models/project.js
+++ b/server/models/project.js
@@ -2,10 +2,10 @@ import mongoose from 'mongoose';
const Schema = mongoose.Schema;
import shortid from 'shortid';
-const defaultSketch = `setup() {
+const defaultSketch = `function setup() {
createCanvas(400, 400);
}
-draw() {
+function draw() {
background(220);
}`
From 88531447ba3ed10168cb577d61b1c2a829d42042 Mon Sep 17 00:00:00 2001
From: catarak
Date: Thu, 7 Jul 2016 13:04:54 -0400
Subject: [PATCH 05/17] add ids to files, fix update file action/reducer
---
client/modules/IDE/actions/files.js | 2 +-
client/modules/IDE/actions/project.js | 2 +-
server/models/project.js | 6 ++++--
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js
index 40438b1e..3ceca1e1 100644
--- a/client/modules/IDE/actions/files.js
+++ b/client/modules/IDE/actions/files.js
@@ -2,7 +2,7 @@ import * as ActionTypes from '../../../constants';
export function updateFile(name, content) {
return {
- type: ActionTypes.CHANGE_SELECTED_FILE,
+ type: ActionTypes.UPDATE_FILE,
name,
content
};
diff --git a/client/modules/IDE/actions/project.js b/client/modules/IDE/actions/project.js
index 3f5339d2..8d4e1e56 100644
--- a/client/modules/IDE/actions/project.js
+++ b/client/modules/IDE/actions/project.js
@@ -34,7 +34,7 @@ export function saveProject() {
return (dispatch, getState) => {
const state = getState();
const formParams = Object.assign({}, state.project);
- formParams.file = state.file;
+ formParams.files = state.files;
if (state.project.id) {
axios.put(`${ROOT_URL}/projects/${state.project.id}`, formParams, { withCredentials: true })
.then(() => {
diff --git a/server/models/project.js b/server/models/project.js
index a1306dc7..1ad4b4ee 100644
--- a/server/models/project.js
+++ b/server/models/project.js
@@ -1,5 +1,7 @@
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
+const ObjectIdSchema = Schema.ObjectId;
+const ObjectId = mongoose.Types.ObjectId;
import shortid from 'shortid';
const defaultSketch = `function setup() {
@@ -24,12 +26,12 @@ const defaultHTML =
const fileSchema = new Schema({
name: { type: String, default: 'sketch.js' },
content: { type: String, default: defaultSketch }
-}, { timestamps: true });
+}, { timestamps: true, _id: true });
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 }, { name: 'index.html', content: defaultHTML }]},
+ 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 }
}, { timestamps: true });
From e06c82192300a215ebd259668c6f1ad12863f785 Mon Sep 17 00:00:00 2001
From: catarak
Date: Thu, 7 Jul 2016 13:50:52 -0400
Subject: [PATCH 06/17] fix updating file to return all file keys
---
client/constants.js | 2 +-
client/modules/IDE/actions/files.js | 4 ++--
client/modules/IDE/components/Editor.js | 4 ++--
client/modules/IDE/components/Sidebar.js | 5 ++++-
client/modules/IDE/pages/IDEView.js | 4 ++--
client/modules/IDE/reducers/files.js | 7 ++-----
server/controllers/project.controller.js | 18 +++---------------
server/models/project.js | 16 ++++++++++++++++
8 files changed, 32 insertions(+), 28 deletions(-)
diff --git a/client/constants.js b/client/constants.js
index 29d9f701..b69e22b2 100644
--- a/client/constants.js
+++ b/client/constants.js
@@ -1,4 +1,4 @@
-export const UPDATE_FILE = 'UPDATE_FILE';
+export const UPDATE_FILE_CONTENT = 'UPDATE_FILE_CONTENT';
export const TOGGLE_SKETCH = 'TOGGLE_SKETCH';
export const START_SKETCH = 'START_SKETCH';
diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js
index 3ceca1e1..f7ebd8f3 100644
--- a/client/modules/IDE/actions/files.js
+++ b/client/modules/IDE/actions/files.js
@@ -1,8 +1,8 @@
import * as ActionTypes from '../../../constants';
-export function updateFile(name, content) {
+export function updateFileContent(name, content) {
return {
- type: ActionTypes.UPDATE_FILE,
+ type: ActionTypes.UPDATE_FILE_CONTENT,
name,
content
};
diff --git a/client/modules/IDE/components/Editor.js b/client/modules/IDE/components/Editor.js
index e7cb8647..b028d705 100644
--- a/client/modules/IDE/components/Editor.js
+++ b/client/modules/IDE/components/Editor.js
@@ -14,7 +14,7 @@ class Editor extends React.Component {
mode: 'javascript'
});
this._cm.on('change', () => { // eslint-disable-line
- this.props.updateFile('sketch.js', this._cm.getValue());
+ this.props.updateFileContent('sketch.js', this._cm.getValue());
});
this._cm.getWrapperElement().style['font-size'] = `${this.props.fontSize}px`;
}
@@ -42,7 +42,7 @@ class Editor extends React.Component {
Editor.propTypes = {
content: PropTypes.string.isRequired,
- updateFile: PropTypes.func.isRequired,
+ updateFileContent: PropTypes.func.isRequired,
fontSize: PropTypes.number.isRequired
};
diff --git a/client/modules/IDE/components/Sidebar.js b/client/modules/IDE/components/Sidebar.js
index bcf11473..3c5d0fe6 100644
--- a/client/modules/IDE/components/Sidebar.js
+++ b/client/modules/IDE/components/Sidebar.js
@@ -5,7 +5,10 @@ function Sidebar(props) {
{props.files.map(file =>
- - {file.name}
+ - {file.name}
)}
diff --git a/client/modules/IDE/pages/IDEView.js b/client/modules/IDE/pages/IDEView.js
index 6b74c737..2278a095 100644
--- a/client/modules/IDE/pages/IDEView.js
+++ b/client/modules/IDE/pages/IDEView.js
@@ -48,7 +48,7 @@ class IDEView extends React.Component {
{
switch (action.type) {
- case ActionTypes.UPDATE_FILE:
+ case ActionTypes.UPDATE_FILE_CONTENT:
return state.map(file => {
if (file.name !== action.name) {
return file;
}
- return {
- name: file.name,
- content: action.content
- };
+ return Object.assign({}, file, { content: action.content });
});
case ActionTypes.NEW_PROJECT:
return [...action.files];
diff --git a/server/controllers/project.controller.js b/server/controllers/project.controller.js
index c4a4887a..03baa4e5 100644
--- a/server/controllers/project.controller.js
+++ b/server/controllers/project.controller.js
@@ -10,11 +10,7 @@ export function createProject(req, res) {
Project.create(projectValues, (err, newProject) => {
if (err) { return res.json({ success: false }); }
- return res.json({
- id: newProject._id, // eslint-disable-line no-underscore-dangle
- name: newProject.name,
- files: newProject.files
- });
+ return res.json(newProject);
});
}
@@ -24,11 +20,7 @@ export function updateProject(req, res) {
$set: req.body
}, (err, updatedProject) => {
if (err) { return res.json({ success: false }); }
- return res.json({
- id: updatedProject._id, // eslint-disable-line no-underscore-dangle
- name: updatedProject.name,
- file: updatedProject.files
- });
+ return res.json(updatedProject);
});
}
@@ -38,11 +30,7 @@ export function getProject(req, res) {
return res.status(404).send({ message: 'Project with that id does not exist' });
}
- return res.json({
- id: project._id, // eslint-disable-line no-underscore-dangle
- name: project.name,
- files: project.files
- });
+ return res.json(project);
});
}
diff --git a/server/models/project.js b/server/models/project.js
index 1ad4b4ee..709ea58d 100644
--- a/server/models/project.js
+++ b/server/models/project.js
@@ -28,6 +28,14 @@ const fileSchema = new Schema({
content: { type: String, default: defaultSketch }
}, { timestamps: true, _id: true });
+fileSchema.virtual('id').get(function(){
+ return this._id.toHexString();
+});
+
+fileSchema.set('toJSON', {
+ virtuals: true
+});
+
const projectSchema = new Schema({
name: { type: String, default: "Hello p5.js, it's the server" },
user: { type: Schema.Types.ObjectId, ref: 'User' },
@@ -35,4 +43,12 @@ const projectSchema = new Schema({
_id: { type: String, default: shortid.generate }
}, { timestamps: true });
+projectSchema.virtual('id').get(function(){
+ return this._id;
+});
+
+projectSchema.set('toJSON', {
+ virtuals: true
+});
+
export default mongoose.model('Project', projectSchema);
From 7a84137e9b03a986da4e77d86db489bf330e0c27 Mon Sep 17 00:00:00 2001
From: catarak
Date: Fri, 8 Jul 2016 14:57:22 -0400
Subject: [PATCH 07/17] 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 (
- {props.files.map(file =>
- - {file.name}
- )}
+ {props.files.map(file => {
+ let itemClass = classNames({
+ 'sidebar__file-item': true,
+ 'sidebar__file-item--selected': file.id === props.selectedFile.id
+ });
+ return (
+ - {file.name}
+ );
+ })}
);
}
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 =