diff --git a/client/es6-shims.js b/client/es6-shims.js
new file mode 100644
index 0000000000..43abd2ed1a
--- /dev/null
+++ b/client/es6-shims.js
@@ -0,0 +1,2 @@
+require('object.assign').shim();
+require('es6-map/implement');
diff --git a/client/index.js b/client/index.js
index 95be7ca9ae..79c5c541c1 100644
--- a/client/index.js
+++ b/client/index.js
@@ -1,3 +1,4 @@
+import unused from './es6-shims'; // eslint-disable-line
import Rx from 'rx';
import React from 'react';
import Fetchr from 'fetchr';
diff --git a/common/app/app-stream.jsx b/common/app/app-stream.jsx
index dcba9b7ca0..25ae2a6300 100644
--- a/common/app/app-stream.jsx
+++ b/common/app/app-stream.jsx
@@ -1,5 +1,4 @@
import Rx from 'rx';
-import assign from 'object.assign';
import { Router } from 'react-router';
import App from './App.jsx';
import AppCat from './Cat';
@@ -8,7 +7,7 @@ import childRoutes from './routes';
const router$ = Rx.Observable.fromNodeCallback(Router.run, Router);
-const routes = assign({ components: App }, childRoutes);
+const routes = Object.assign({ components: App }, childRoutes);
export default function app$(location) {
return router$(routes, location)
diff --git a/common/app/routes/Hikes/flux/Actions.js b/common/app/routes/Hikes/flux/Actions.js
index 94f3403590..2d9d44a4fd 100644
--- a/common/app/routes/Hikes/flux/Actions.js
+++ b/common/app/routes/Hikes/flux/Actions.js
@@ -1,5 +1,4 @@
import { Actions } from 'thundercats';
-import assign from 'object.assign';
import debugFactory from 'debug';
const debug = debugFactory('freecc:hikes:actions');
@@ -45,7 +44,7 @@ export default Actions({
dashedName,
oldState.currentHike
);
- return assign({}, oldState, { currentHike });
+ return Object.assign({}, oldState, { currentHike });
}
});
}
diff --git a/common/app/routes/Jobs/components/Jobs.jsx b/common/app/routes/Jobs/components/Jobs.jsx
index 4b37571eb2..a6bc6a9a9f 100644
--- a/common/app/routes/Jobs/components/Jobs.jsx
+++ b/common/app/routes/Jobs/components/Jobs.jsx
@@ -1,23 +1,39 @@
import React, { cloneElement, PropTypes } from 'react';
import { contain } from 'thundercats-react';
+import { Navigation } from 'react-router';
import { Button, Jumbotron, Row } from 'react-bootstrap';
import ListJobs from './List.jsx';
export default contain(
{
store: 'jobsStore',
- fetchAction: 'jobActions.getJobs'
+ fetchAction: 'jobActions.getJobs',
+ actions: 'jobActions'
},
React.createClass({
displayName: 'Jobs',
+
propTypes: {
children: PropTypes.element,
+ jobActions: PropTypes.object,
jobs: PropTypes.array
},
+ mixins: [Navigation],
- renderList(jobs) {
+ handleJobClick(id) {
+ const { jobActions } = this.props;
+ if (!id) {
+ return null;
+ }
+ jobActions.findJob(id);
+ this.transitionTo(`/jobs/${id}`);
+ },
+
+ renderList(handleJobClick, jobs) {
return (
-
+
);
},
@@ -53,7 +69,7 @@ export default contain(
{ this.renderChild(children, jobs) ||
- this.renderList(jobs) }
+ this.renderList(this.handleJobClick, jobs) }
);
diff --git a/common/app/routes/Jobs/components/List.jsx b/common/app/routes/Jobs/components/List.jsx
index b90050aa74..ec8325a98b 100644
--- a/common/app/routes/Jobs/components/List.jsx
+++ b/common/app/routes/Jobs/components/List.jsx
@@ -1,81 +1,83 @@
import React, { PropTypes } from 'react';
-import { contain } from 'thundercats-react';
import { PanelGroup, Thumbnail, Panel, Well } from 'react-bootstrap';
import moment from 'moment';
-export default contain(
- {
+export default React.createClass({
+ displayName: 'ListJobs',
+
+ propTypes: {
+ handleClick: PropTypes.func,
+ jobs: PropTypes.array
},
- React.createClass({
- displayName: 'ListJobs',
- propTypes: {
- jobs: PropTypes.array
- },
+ renderJobs(handleClick, jobs =[]) {
+ const thumbnailStyle = {
+ backgroundColor: 'white',
+ maxHeight: '100px',
+ maxWidth: '100px'
+ };
- renderJobs(jobs =[]) {
- const thumbnailStyle = {
- backgroundColor: 'white',
- maxHeight: '100px',
- maxWidth: '100px'
- };
- return jobs.map((
- {
- id,
- company,
- position,
- description,
- logo,
- city,
- state,
- email,
- phone,
- postedOn
- },
- index
- ) => {
- const header = (
-
-
{ company }
-
- { position }
-
-
- );
- return (
-
-
-
-
- Position: { position }
- Location: { city }, { state }
-
- Contact: { email || phone || 'N/A' }
-
- Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
-
- { description }
-
-
- );
- });
- },
-
- render() {
- const { jobs } = this.props;
- return (
-
- { this.renderJobs(jobs) }
-
+ return jobs.map((
+ {
+ id,
+ company,
+ position,
+ description,
+ logo,
+ city,
+ state,
+ email,
+ phone,
+ postedOn
+ },
+ index
+ ) => {
+ const header = (
+
+
{ company }
+
+ { position }
+
+
);
- }
- })
-);
+ return (
+
+
+
+
+ Position: { position }
+ Location: { city }, { state }
+
+ Contact: { email || phone || 'N/A' }
+
+ Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
+
+ handleClick(id) }>{ description }
+
+
+ );
+ });
+ },
+
+ render() {
+ const {
+ handleClick,
+ jobs
+ } = this.props;
+
+ return (
+
+ { this.renderJobs(handleClick, jobs) }
+
+ );
+ }
+});
diff --git a/common/app/routes/Jobs/components/Show.jsx b/common/app/routes/Jobs/components/Show.jsx
index 209917cff7..0baedb82b3 100644
--- a/common/app/routes/Jobs/components/Show.jsx
+++ b/common/app/routes/Jobs/components/Show.jsx
@@ -1,5 +1,6 @@
import React, { PropTypes } from 'react';
-import { Thumbnail, Panel, Well } from 'react-bootstrap';
+import { contain } from 'thundercats-react';
+import { Row, Thumbnail, Panel, Well } from 'react-bootstrap';
import moment from 'moment';
const thumbnailStyle = {
@@ -7,53 +8,81 @@ const thumbnailStyle = {
maxHeight: '100px',
maxWidth: '100px'
};
-export default React.createClass({
- displayName: 'ShowJob',
- propTypes: {
- job: PropTypes.object
+
+export default contain(
+ {
+ store: 'jobsStore',
+ fetchAction: 'jobActions.getJob',
+ map({ currentJob }) {
+ return { job: currentJob };
+ },
+ getPayload({ params: { id }, job = {} }) {
+ return {
+ id,
+ isPrimed: job.id === id
+ };
+ },
+ // using es6 destructuring
+ shouldContainerFetch({ job = {} }, { params: { id } }
+ ) {
+ return job.id !== id;
+ }
},
+ React.createClass({
+ displayName: 'ShowJob',
+ propTypes: {
+ job: PropTypes.object,
+ params: PropTypes.object
+ },
- renderHeader({ company, position }) {
- return (
-
-
{ company }
-
- { position }
-
-
- );
- },
+ renderHeader({ company, position }) {
+ return (
+
+
{ company }
+
+ { position }
+
+
+ );
+ },
- render() {
- const { job } = this.props;
- const {
- logo,
- position,
- city,
- state,
- email,
- phone,
- postedOn,
- description
- } = job;
+ render() {
+ const { job = {} } = this.props;
+ const {
+ logo,
+ position,
+ city,
+ company,
+ state,
+ email,
+ phone,
+ postedOn,
+ description
+ } = job;
- return (
-
-
-
- Position: { position }
- Location: { city }, { state }
-
- Contact: { email || phone || 'N/A' }
-
- Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
-
- { description }
-
- );
- }
-});
+ return (
+
+
+
+
+
+ Position: { position }
+ Location: { city }, { state }
+
+ Contact: { email || phone || 'N/A' }
+
+ Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
+
+ { description }
+
+
+
+ );
+ }
+ })
+);
diff --git a/common/app/routes/Jobs/flux/Actions.js b/common/app/routes/Jobs/flux/Actions.js
index 68d5eeae57..4df2ae42c6 100644
--- a/common/app/routes/Jobs/flux/Actions.js
+++ b/common/app/routes/Jobs/flux/Actions.js
@@ -5,9 +5,30 @@ const debug = debugFactory('freecc:jobs:actions');
export default Actions({
setJobs: null,
- getJob(id) {
- return { id };
+ // findJob assumes that the job is already in the list of jobs
+ findJob(id) {
+ return oldState => {
+ const { currentJob = {}, jobs = [] } = oldState;
+ // currentJob already set
+ // do nothing
+ if (currentJob.id === id) {
+ return null;
+ }
+ const foundJob = jobs.reduce((newJob, job) => {
+ if (job.id === id) {
+ return job;
+ }
+ return newJob;
+ }, null);
+
+ // if no job found this will be null which is a op noop
+ return foundJob ?
+ Object.assign({}, oldState, { currentJob: foundJob }) :
+ null;
+ };
},
+ setError: null,
+ getJob: null,
getJobs(params) {
return { params };
}
@@ -15,13 +36,28 @@ export default Actions({
.refs({ displayName: 'JobActions' })
.init(({ instance: jobActions, args: [services] }) => {
jobActions.getJobs.subscribe(() => {
- services.read('job', null, null, (err, jobs) => {
+ services.read('jobs', null, null, (err, jobs) => {
if (err) {
debug('job services experienced an issue', err);
- jobActions.setJobs({ jobs: [] });
+ return jobActions.setError({ err });
}
jobActions.setJobs({ jobs });
});
});
+
+ jobActions.getJob.subscribe(({ id, isPrimed }) => {
+ // job is already set, do nothing.
+ if (isPrimed) {
+ debug('job is primed');
+ return;
+ }
+ services.read('jobs', { id }, null, (err, job) => {
+ if (err) {
+ debug('job services experienced an issue', err);
+ return jobActions.setError({ err });
+ }
+ jobActions.setJobs({ currentJob: job });
+ });
+ });
return jobActions;
});
diff --git a/common/app/routes/Jobs/flux/Store.js b/common/app/routes/Jobs/flux/Store.js
index 803bc7b0bd..2fdfa50207 100644
--- a/common/app/routes/Jobs/flux/Store.js
+++ b/common/app/routes/Jobs/flux/Store.js
@@ -1,10 +1,17 @@
import { Store } from 'thundercats';
-const { setter } = Store;
+const {
+ createRegistrar,
+ setter,
+ transformer
+} = Store;
export default Store()
.refs({ displayName: 'JobsStore' })
.init(({ instance: jobsStore, args: [cat] }) => {
- let jobActions = cat.getActions('JobActions');
- jobsStore.register(setter(jobActions.setJobs));
+ const { setJobs, findJob, setError } = cat.getActions('JobActions');
+ const register = createRegistrar(jobsStore);
+ register(setter(setJobs));
+ register(transformer(findJob));
+ register(setter(setError));
});
diff --git a/common/app/routes/Jobs/index.js b/common/app/routes/Jobs/index.js
index 9d52bf2b53..ac6b07f866 100644
--- a/common/app/routes/Jobs/index.js
+++ b/common/app/routes/Jobs/index.js
@@ -1,14 +1,18 @@
import Jobs from './components/Jobs.jsx';
+import Show from './components/Show.jsx';
/*
- * show: /jobs
- * showOne: /jobs/:id
- * edit /jobs/:id
- * delete /jobs/:id
- * createOne /jobs/new
+ * index: /jobs list jobs
+ * show: /jobs/:id show one job
+ * create /jobs/new create a new job
*/
export default {
- path: 'jobs',
- component: Jobs
+ childRoutes: [{
+ path: '/jobs',
+ component: Jobs
+ }, {
+ path: 'jobs/:id',
+ component: Show
+ }]
};
diff --git a/gulpfile.js b/gulpfile.js
index b5eee5417a..afe9b421f5 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -1,3 +1,6 @@
+// enable debug for gulp
+process.env.DEBUG = process.env.DEBUG || 'freecc:*';
+
require('babel-core/register');
var Rx = require('rx'),
gulp = require('gulp'),
@@ -6,6 +9,7 @@ var Rx = require('rx'),
// utils
plumber = require('gulp-plumber'),
notify = require('gulp-notify'),
+ gutil = require('gulp-util'),
reduce = require('gulp-reduce-file'),
sortKeys = require('sort-keys'),
debug = require('debug')('freecc:gulp'),
@@ -25,6 +29,7 @@ var Rx = require('rx'),
// rev
rev = require('gulp-rev'),
revReplace = require('gulp-rev-replace'),
+ revDel = require('rev-del'),
// lint
jsonlint = require('gulp-jsonlint'),
@@ -33,6 +38,7 @@ var Rx = require('rx'),
Rx.config.longStackSupport = true;
+var __DEV__ = process.env.NODE_ENV !== 'production';
var reloadDelay = 1000;
var reload = sync.reload;
var paths = {
@@ -43,6 +49,7 @@ var paths = {
'!public/js/bundle*',
'node_modules/',
'client/',
+ 'server/manifests/*.json',
'server/rev-manifest.json'
],
@@ -67,8 +74,7 @@ var paths = {
],
dependents: [
- 'client/commonFramework.js',
- 'client/sandbox.js'
+ 'client/commonFramework.js'
],
less: './client/less/main.less',
@@ -107,11 +113,22 @@ function errorHandler() {
this.emit('end');
}
+function delRev(dest, manifestName) {
+ // in production do not delete old revisions
+ if (!__DEV__) {
+ return gutil.noop();
+ }
+ return revDel({
+ oldManifest: path.join(paths.manifest, manifestName),
+ dest: dest
+ });
+}
+
gulp.task('serve', function(cb) {
var called = false;
nodemon({
script: paths.server,
- ext: '.js .json',
+ ext: '.jsx .js .json',
ignore: paths.serverIgnore,
exec: path.join(__dirname, 'node_modules/.bin/babel-node'),
env: {
@@ -143,7 +160,7 @@ var syncDepenedents = [
'js',
'less',
'dependents',
- 'pack-client',
+ 'pack-watch',
'build-manifest'
];
@@ -173,6 +190,9 @@ gulp.task('lint-json', function() {
gulp.task('test-challenges', ['lint-json']);
gulp.task('pack-client', function() {
+ var manifestName = 'react-manifest.json';
+ var dest = webpackConfig.output.path;
+
return gulp.src(webpackConfig.entry)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(webpack(Object.assign(
@@ -180,30 +200,73 @@ gulp.task('pack-client', function() {
webpackConfig,
webpackOptions
)))
- .pipe(gulp.dest(webpackConfig.output.path))
+ .pipe(gulp.dest(dest))
.pipe(rev())
// copy files to public
- .pipe(gulp.dest(webpackConfig.output.path))
- // create and merge manifest
- .pipe(rev.manifest('react-manifest.json'))
+ .pipe(gulp.dest(dest))
+ // create manifest
+ .pipe(rev.manifest(manifestName))
+ // delete old rev
+ .pipe(delRev(
+ dest,
+ manifestName
+ ))
.pipe(gulp.dest(paths.manifest));
});
-gulp.task('pack-watch', function() {
- return gulp.src(webpackConfig.entry)
+var defaultStatsOptions = {
+ colors: gutil.colors.supportsColor,
+ hash: false,
+ timings: false,
+ chunks: false,
+ chunkModules: false,
+ modules: false,
+ children: true,
+ version: true,
+ cached: false,
+ cachedAssets: false,
+ reasons: false,
+ source: false,
+ errorDetails: false
+};
+
+gulp.task('pack-watch', function(cb) {
+ var called = false;
+ gulp.src(webpackConfig.entry)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(webpack(Object.assign(
{},
webpackConfig,
webpackOptions,
{ watch: true }
- )))
- .pipe(gulp.dest(webpackConfig.output.path))
+ ), null, function(notUsed, stats) {
+ if (stats) {
+ gutil.log(stats.toString(defaultStatsOptions));
+ }
+
+ if (!called) {
+ debug('webpack watch completed');
+ called = true;
+ cb();
+ }
+
+ }))
+ .pipe(gulp.dest(webpackConfig.output.path));
+});
+
+gulp.task('pack-watch-manifest', function() {
+ var manifestName = 'react-manifest.json';
+ var dest = webpackConfig.output.path;
+ return gulp.src(dest + '/bundle.js')
.pipe(rev())
// copy files to public
- .pipe(gulp.dest(webpackConfig.output.path))
+ .pipe(gulp.dest(dest))
// create manifest
- .pipe(rev.manifest('react-manifest.json'))
+ .pipe(rev.manifest(manifestName))
+ .pipe(delRev(
+ dest,
+ manifestName
+ ))
.pipe(gulp.dest(paths.manifest));
});
@@ -217,32 +280,45 @@ gulp.task('pack-node', function() {
gulp.task('pack', ['pack-client', 'pack-node']);
gulp.task('less', function() {
+ var manifestName = 'css-manifest.json';
+ var dest = paths.css;
return gulp.src(paths.less)
.pipe(plumber({ errorHandler: errorHandler }))
// copile
.pipe(less({
paths: [ path.join(__dirname, 'less', 'includes') ]
}))
- .pipe(gulp.dest(paths.css))
+ .pipe(gulp.dest(dest))
// add revision
.pipe(rev())
// copy files to public
- .pipe(gulp.dest(paths.css))
+ .pipe(gulp.dest(dest))
// create and merge manifest
- .pipe(rev.manifest('css-manifest.json'))
+ .pipe(rev.manifest(manifestName))
+ .pipe(delRev(
+ dest,
+ manifestName
+ ))
.pipe(gulp.dest(paths.manifest));
});
gulp.task('js', function() {
+ var manifestName = 'js-manifest.json';
+ var dest = paths.publicJs;
+
return gulp.src(paths.js)
.pipe(plumber({ errorHandler: errorHandler }))
- .pipe(gulp.dest(paths.publicJs))
+ .pipe(gulp.dest(dest))
// create registry file
.pipe(rev())
// copy revisioned assets to dest
- .pipe(gulp.dest(paths.publicJs))
+ .pipe(gulp.dest(dest))
// create manifest file
- .pipe(rev.manifest('js-manifest.json'))
+ .pipe(rev.manifest(manifestName))
+ .pipe(delRev(
+ dest,
+ manifestName
+ ))
// copy manifest file to dest
.pipe(gulp.dest(paths.manifest));
});
@@ -250,6 +326,9 @@ gulp.task('js', function() {
// commonFramework depend on iFrameScripts
// sandbox depends on plugin
gulp.task('dependents', ['js'], function() {
+ var manifestName = 'dependents-manifest.json';
+ var dest = paths.publicJs;
+
var manifest = gulp.src(
path.join(__dirname, paths.manifest, 'js-manifest.json')
);
@@ -257,9 +336,14 @@ gulp.task('dependents', ['js'], function() {
return gulp.src(paths.dependents)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(revReplace({ manifest: manifest }))
+ .pipe(gulp.dest(dest))
.pipe(rev())
- .pipe(gulp.dest(paths.publicJs))
- .pipe(rev.manifest('dependents-manifest.json'))
+ .pipe(gulp.dest(dest))
+ .pipe(rev.manifest(manifestName))
+ .pipe(delRev(
+ dest,
+ manifestName
+ ))
.pipe(gulp.dest(paths.manifest));
});
@@ -301,7 +385,9 @@ var watchDependents = [
'dependents',
'serve',
'sync',
- 'build-manifest'
+ 'build-manifest',
+ 'pack-watch',
+ 'pack-watch-manifest'
];
gulp.task('watch', watchDependents, function() {
@@ -311,7 +397,15 @@ gulp.task('watch', watchDependents, function() {
gulp.watch(paths.js, ['js', 'dependents']);
gulp.watch(paths.dependents, ['dependents']);
gulp.watch(paths.manifest + '/*.json', ['build-manifest-watch']);
+ gulp.watch(webpackConfig.output.path + '/bundle.js', ['pack-watch-manifest']);
});
-gulp.task('default', ['less', 'serve', 'sync', 'watch', 'pack-watch']);
+gulp.task('default', [
+ 'less',
+ 'serve',
+ 'pack-watch',
+ 'pack-watch-manifest',
+ 'watch',
+ 'sync'
+]);
diff --git a/package.json b/package.json
index 44833cc65d..901b54ea3a 100644
--- a/package.json
+++ b/package.json
@@ -17,9 +17,9 @@
"dependencies": {
"accepts": "~1.2.5",
"async": "~0.9.0",
- "babel": "5.6.14",
- "babel-core": "5.6.15",
- "babel-eslint": "^4.0.5",
+ "babel": "5.8.23",
+ "babel-core": "5.8.23",
+ "babel-eslint": "4.1.1",
"babel-loader": "5.2.2",
"bcrypt-nodejs": "~0.0.3",
"body-parser": "^1.13.2",
@@ -36,6 +36,7 @@
"dedent": "^0.4.0",
"dotenv": "~0.4.0",
"errorhandler": "~1.3.0",
+ "es6-map": "^0.1.1",
"eslint": "^1.1.0",
"eslint-plugin-react": "^3.2.1",
"express": "~4.10.4",
@@ -53,6 +54,7 @@
"gulp-reduce-file": "0.0.1",
"gulp-rev": "^6.0.1",
"gulp-rev-replace": "^0.4.2",
+ "gulp-util": "^3.0.6",
"gulp-webpack": "^1.5.0",
"helmet": "~0.9.0",
"helmet-csp": "^0.2.3",
@@ -85,11 +87,12 @@
"pmx": "^0.3.16",
"ramda": "~0.10.0",
"react": "^0.13.3",
- "react-bootstrap": "^0.23.7",
+ "react-bootstrap": "~0.23.7",
"react-motion": "~0.1.0",
"react-router": "https://github.com/BerkeleyTrue/react-router#freecodecamp",
"react-vimeo": "^0.0.3",
"request": "~2.53.0",
+ "rev-del": "^1.0.5",
"rx": "^2.5.3",
"sanitize-html": "~1.6.1",
"sort-keys": "^1.1.1",
@@ -103,15 +106,12 @@
"yui": "~3.18.1"
},
"devDependencies": {
- "babel-eslint": "^3.1.7",
"blessed": "~0.0.37",
"bower-main-files": "~0.0.4",
"browser-sync": "~1.8.1",
"browserify": "^10.2.4",
"chai": "~1.10.0",
"envify": "^3.4.0",
- "eslint": "^0.21.2",
- "eslint-plugin-react": "^2.3.0",
"gulp": "~3.8.8",
"gulp-eslint": "~0.9.0",
"gulp-inject": "~1.0.2",
diff --git a/server/boot/a-react.js b/server/boot/a-react.js
index 286a356b5b..6c0cd04819 100644
--- a/server/boot/a-react.js
+++ b/server/boot/a-react.js
@@ -13,7 +13,8 @@ const debug = debugFactory('freecc:react-server');
const routes = [
'/hikes',
'/hikes/*',
- '/jobs'
+ '/jobs',
+ '/jobs/*'
];
export default function reactSubRouter(app) {
diff --git a/server/middlewares/revision-helpers.js b/server/middlewares/revision-helpers.js
index aa8a7bfed8..3f84fe9c90 100644
--- a/server/middlewares/revision-helpers.js
+++ b/server/middlewares/revision-helpers.js
@@ -1,6 +1,8 @@
import manifest from '../rev-manifest.json';
const __DEV__ = process.env.NODE_ENV === 'development';
+const manifestPath = '../rev-manifest.json';
+
export default function({ globalPrepend = '' } = {}) {
function rev(manifest, scopedPrepend, asset) {
@@ -13,7 +15,10 @@ export default function({ globalPrepend = '' } = {}) {
// this means we do not need to restart server on every change to
// client code
if (__DEV__) {
- const manifest = require('../rev-manifest.json');
+ // we first need to remove the manifest from require cache
+ delete require.cache[require.resolve(manifestPath)];
+ // and re-require
+ const manifest = require(manifestPath);
res.locals.rev = rev.bind(null, manifest);
return next();
}
diff --git a/server/services/job.js b/server/services/job.js
index 8c38a3661a..fe54d0064c 100644
--- a/server/services/job.js
+++ b/server/services/job.js
@@ -2,8 +2,12 @@ export default function getJobServices(app) {
const { Job } = app.models;
return {
- name: 'job',
+ name: 'jobs',
read: (req, resource, params, config, cb) => {
+ const id = params ? params.id : null;
+ if (id) {
+ return Job.findById(id, cb);
+ }
Job.find({}, (err, jobs) => {
cb(err, jobs);
});