diff --git a/.eslintignore b/.eslintignore index 204111f..3d9cd50 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1 @@ client/bower_components -node_modules diff --git a/.eslintrc b/.eslintrc index b43c6d8..d4fdb05 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,14 +1,8 @@ env: - browser: true - jquery: true node: true -globals: - angular: false - rules: global-strict: 0 - no-alert: 1 no-process-exit: 0 no-shadow: 0 no-new: 0 diff --git a/.travis.yml b/.travis.yml index d0a30ef..9a57890 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,6 @@ node_js: - "0.12" sudo: false + +before_install: + - npm i -g grunt-cli diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..fb54ca7 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,12 @@ +'use strict'; + +module.exports = function (grunt) { + + // require('load-grunt-tasks')(grunt); + + grunt.initConfig({ + pkg: require('./package.json') + }); + + grunt.loadTasks('grunttasks'); +}; diff --git a/README.md b/README.md index bfbb4ea..6940b5e 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,13 @@ Web dashboard for Loads, v2. * Define load profiles (container sets) * Control load test runs +## Prerequisites + +Before you install loads-web, you'll need to have [Node.js](https://nodejs.org/) installed, as well as [Grunt](http://gruntjs.com/) and [Bower](http://bower.io/) modules installed globally: +```sh +$ npm install bower grunt-cli --global +``` + ## Development @@ -19,15 +26,15 @@ Setting the app up: $ npm install ``` -Watch and compile Stylus to CSS: +Compile Stylus to CSS: ```sh -$ ./node_modules/.bin/stylus --watch --compress client/static/assets/stylus/app.styl --out client/static/assets/css/ +$ grunt stylus ``` Starting the server: ```sh -$ node server # or `npm start` +$ npm start ``` diff --git a/client/.eslintrc b/client/.eslintrc new file mode 100644 index 0000000..24e32c9 --- /dev/null +++ b/client/.eslintrc @@ -0,0 +1,11 @@ +env: + browser: true + jquery: true + node: false + +globals: + angular: false + +rules: + no-alert: 1 + no-console: 0 diff --git a/client/static/assets/stylus/app.styl b/client/static/assets/stylus/app.styl index 85e87d8..623d34f 100644 --- a/client/static/assets/stylus/app.styl +++ b/client/static/assets/stylus/app.styl @@ -3,25 +3,29 @@ */ @import 'fonts.styl'; + /* Vars */ $media-query-tablet = 768px; -/* - Site structure + +/* + Site structure */ body { background: #e9eaed; - + > header { background: #c13832; - -webkit-box-shadow: 0 2px 2px -2px rgba(0, 0, 0, .52); - box-shadow: 0 2px 2px -2px rgba(0, 0, 0, .52); + -webkit-box-shadow: 0 2px 2px -2px rgba(0, 0, 0, 0.52); + box-shadow: 0 2px 2px -2px rgba(0, 0, 0, 0.52); } } -.top-bar, .top-bar-section li:not(.has-form) a:not(.button), .top-bar-section ul li { +.top-bar, +.top-bar-section li:not(.has-form) a:not(.button), +.top-bar-section ul li { background: none; } @@ -29,65 +33,72 @@ body { font-weight: bold; } -.top-bar-section > ul > .divider, .top-bar-section > ul > [role="separator"] { +.top-bar-section > ul > .divider, +.top-bar-section > ul > [role='separator'] { border-right-color: #ad0901; } nav.breadcrumbs { background: none; + border: 0; margin: 10px 0; padding: 0; - border: 0; - position: absolute; right: 15px; top: 8px; - + @media (max-width: $media-query-tablet) { - position: static; - margin-top: 20px; - } + margin-top: 20px; + position: static; + } } h2 .label { - float: right; - font-size: 1.3rem; background: transparent; color: #999; + float: right; + font-size: 1.3rem; } .two-column-row { display: -webkit-flex; display: flex; width: 100%; - + @media (max-width: $media-query-tablet) { - display: block; + display: block; } - + > div { width: 50%; - + @media (max-width: $media-query-tablet) { + float: none; width: 100%; - float: none; } - + &:first-child { margin-right: 20px; - + @media (max-width: $media-query-tablet) { + margin-right: 0; width: auto; - margin-right: 0; } } } } -/* - Tags + +/* + Tags */ -body, h1, h2, h3, h4, h5, h6 { +body, +h1, +h2, +h3, +h4, +h5, +h6 { color: #4d4e53; font-family: 'Open Sans', sans-serif; } @@ -95,7 +106,7 @@ body, h1, h2, h3, h4, h5, h6 { h1 { color: #222; margin-top: 20px; - + small { word-break: break-word; } @@ -105,8 +116,9 @@ h2 { font-size: 1.5em; } -/* - Runs styles + +/* + Runs styles */ .run-table { width: 100%; @@ -114,45 +126,45 @@ h2 { h2 { margin-bottom: 0; } - + caption { color: inherit; text-align: start; } - + tbody td { border-bottom: 1px solid #eee; } } .lastUpdated { - display: block; color: #999; - margin-bottom: 10px; - font-weight: normal; + display: block; font-size: 70%; + font-weight: normal; + margin-bottom: 10px; } .run-result { - position: relative; padding-right: 40px; - + position: relative; + div { - font-size: 85%; display: inline-block; + font-size: 85%; margin-right: 8px; } } .run-result-icon { position: absolute; - top: 35%; right: 20px; + top: 35%; } a.run-link { - font-weight: bold; display: block; + font-weight: bold; } .success { @@ -166,49 +178,52 @@ a.run-link { .success-text { color: green; } + .danger-text { color: red; } table.details-table { width: 100%; - + th { text-align: start; } - - tbody th[scope="row"] { + + tbody th[scope='row'] { width: 10em; } } + /* Projects Loader */ .result-destination { display: none; - - &.valid, &.error { + + &.valid, + &.error { display: block; } - + &.valid { .invalid-info { display: none; } } - + &.error { .valid-info { display: none; } } - + textarea { font-family: monospace; height: 200px; } - + .invalid-info { color: #f00; } @@ -219,8 +234,8 @@ table.details-table { } .gist-description { - font-style: italic; color: #777; + font-style: italic; } @@ -229,8 +244,8 @@ table.details-table { */ .button-group { button { - padding: .5rem 1rem; font-size: 90%; + padding: 0.5rem 1rem; } } @@ -254,4 +269,4 @@ table.details-table { .project-list { width: 100%; -} \ No newline at end of file +} diff --git a/client/static/assets/stylus/fonts.styl b/client/static/assets/stylus/fonts.styl index 840b4c6..0eddb80 100644 --- a/client/static/assets/stylus/fonts.styl +++ b/client/static/assets/stylus/fonts.styl @@ -2,57 +2,78 @@ Fonts, pulled from CDN for speed (global location for Mozilla fonts, used on Mozilla.org and MDN) */ @font-face { - font-family: 'Open Sans Light'; - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.eot'); - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.woff') format('woff'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.ttf') format('truetype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.svg#OpenSansLight') format('svg'); - font-weight: normal; - font-style: normal; + font-family: 'Open Sans Light'; + font-style: normal; + font-weight: normal; + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.eot'); + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.woff') format('woff'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.ttf') format('truetype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.svg#OpenSansLight') format('svg'); } @font-face { - font-family: 'Open Sans Light'; - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot'); - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.woff') format('woff'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.ttf') format('truetype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg'); - font-weight: bold; - font-style: normal; + font-family: 'Open Sans Light'; + font-style: normal; + font-weight: bold; + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot'); + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.woff') format('woff'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.ttf') format('truetype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg'); } @font-face { - font-family: 'Open Sans Light'; - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.eot'); - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.eot?#iefix') format('embedded-opentype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.woff') format('woff'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.ttf') format('truetype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.svg#OpenSansRegular') format('svg'); - font-weight: normal; - font-style: italic; + font-family: 'Open Sans Light'; + font-style: italic; + font-weight: normal; + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.eot'); + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.eot?#iefix') format('embedded-opentype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.woff') format('woff'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.ttf') format('truetype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.svg#OpenSansRegular') format('svg'); } @font-face { - font-family: 'Open Sans'; - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot'); - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.woff') format('woff'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.ttf') format('truetype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg'); - font-weight: normal; - font-style: normal; + font-family: 'Open Sans'; + font-style: normal; + font-weight: normal; + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot'); + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.woff') format('woff'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.ttf') format('truetype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg'); } @font-face { - font-family: 'Open Sans'; - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.eot'); - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.woff') format('woff'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.ttf') format('truetype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg'); - font-weight: bold; - font-style: normal; + font-family: 'Open Sans'; + font-style: normal; + font-weight: bold; + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.eot'); + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.woff') format('woff'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.ttf') format('truetype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg'); } @font-face { - font-family: 'Open Sans'; - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.eot'); - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.eot?#iefix') format('embedded-opentype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.woff') format('woff'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.ttf') format('truetype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.svg#OpenSansItalic') format('svg'); - font-weight: normal; - font-style: italic; + font-family: 'Open Sans'; + font-style: italic; + font-weight: normal; + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.eot'); + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.eot?#iefix') format('embedded-opentype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.woff') format('woff'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.ttf') format('truetype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.svg#OpenSansItalic') format('svg'); } @font-face { - font-family: 'Open Sans Extra Bold'; - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.eot'); - src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.eot?#iefix') format('embedded-opentype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.woff') format('woff'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.ttf') format('truetype'), url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.svg#OpenSansSemibold') format('svg'); - font-weight: bold; - font-style: normal; -} \ No newline at end of file + font-family: 'Open Sans Extra Bold'; + font-style: normal; + font-weight: bold; + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.eot'); + src: url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.eot?#iefix') format('embedded-opentype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.woff') format('woff'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.ttf') format('truetype'), + url('//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.svg#OpenSansSemibold') format('svg'); +} diff --git a/client/static/assets/views/_partials/footer-nav.html b/client/static/assets/views/_partials/footer-nav.html index 6cafffc..c4b6d27 100644 --- a/client/static/assets/views/_partials/footer-nav.html +++ b/client/static/assets/views/_partials/footer-nav.html @@ -8,7 +8,7 @@
Runs
-
Containers
+
Projects
Cluster Management
Reference
diff --git a/config/local.json b/config/local.json index 4947119..1c25377 100644 --- a/config/local.json +++ b/config/local.json @@ -6,5 +6,6 @@ "connection": { "port": 2000 } - } + }, + "compressCss": false } diff --git a/grunttasks/default.js b/grunttasks/default.js new file mode 100644 index 0000000..86cd1d9 --- /dev/null +++ b/grunttasks/default.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = function (grunt) { + grunt.registerTask('default', ['stylus', 'eslint']); +}; diff --git a/grunttasks/eslint.js b/grunttasks/eslint.js new file mode 100644 index 0000000..aad6d7f --- /dev/null +++ b/grunttasks/eslint.js @@ -0,0 +1,14 @@ +'use strict'; + +module.exports = function (grunt) { + grunt.loadNpmTasks('grunt-eslint'); + + grunt.config('eslint', { + app: { + src: [ + '{,client/**/,server/**/,grunttasks/}*.js', + '!client/bower_components/**' + ] + } + }); +}; diff --git a/grunttasks/stylus.js b/grunttasks/stylus.js new file mode 100644 index 0000000..22d2176 --- /dev/null +++ b/grunttasks/stylus.js @@ -0,0 +1,19 @@ +'use strict'; + +var conf = require('../server/config'); +var compressCss = conf.getCompressCss; + +module.exports = function (grunt) { + grunt.loadNpmTasks('grunt-contrib-stylus'); + + grunt.config('stylus', { + options: { + compress: compressCss + }, + app: { + files: { + 'client/static/assets/css/app.css': 'client/static/assets/stylus/app.styl' + } + } + }); +}; diff --git a/package.json b/package.json index 4df0236..3490771 100644 --- a/package.json +++ b/package.json @@ -6,24 +6,26 @@ "bugs": "https://github.com/loads/loads-web/issues", "dependencies": { "awstypes": "1.0.0", - "bower": "1.3.12", + "bower": "1.4.1", "convict": "0.6.1", - "hapi": "8.2.0", + "hapi": "8.4.0", "hapi-auth-cookie": "2.0.0", - "joi": "6.0.0", + "joi": "6.1.0", "json-mask": "0.3.4", - "mysql": "2.5.5", + "mysql": "2.6.1", "nunjucks-hapi": "1.1.0", - "octonode": "0.6.15", + "octonode": "0.6.16", "remarkable": "1.6.0", - "require-hapiroutes": "0.1.7", - "sequelize": "2.0.3", - "stylus": "0.50.0" + "require-hapiroutes": "0.1.9", + "sequelize": "2.0.5" }, "devDependencies": { "awsbox": "0.7.0", - "eslint": "0.15.1", - "nsp": "1.0.0" + "eslint": "0.18.0", + "grunt": "0.4.5", + "grunt-contrib-stylus": "0.21.0", + "grunt-eslint": "10.0.0", + "nsp": "1.0.1" }, "homepage": "https://github.com/loads/loads-web", "keywords": [ @@ -35,14 +37,14 @@ "repository": "loads/loads-web", "scripts": { "clean": "rm -rf ./{node_modules,client/bower_components} && npm i > /dev/null", - "lint": "eslint .", + "lint": "grunt eslint", "outdated": "npm outdated --depth 0", "postinstall": "bower update --config.interactive=false -s", "postshrinkwrap": "nsp audit-shrinkwrap", "prestart": "npm run stylus", "shrinkwrap": "npm shrinkwrap --dev", "start": "node server", - "stylus": "stylus --compress client/static/assets/stylus/app.styl --out client/static/assets/css/", + "stylus": "grunt stylus", "test": "npm run lint" } } diff --git a/server/config.js b/server/config.js index 9c3ed19..b4f7afe 100644 --- a/server/config.js +++ b/server/config.js @@ -29,6 +29,12 @@ var conf = convict({ } }, + compressCss: { + doc: 'Whether or not the generated CSS should be minimized.', + format: Boolean, + default: true + }, + server: { auth: { strategy: { diff --git a/server/routes/404.js b/server/routes/404.js index 2599d3d..f97a936 100644 --- a/server/routes/404.js +++ b/server/routes/404.js @@ -3,10 +3,10 @@ module.exports = { method: '*', path: '/{param*}', - handler: function (request, reply) { - reply.file('client/static/404.html').code(404); - }, config: { + handler: function (request, reply) { + reply.file('client/static/404.html').code(404); + }, description: 'Static route for the /static/ directory.', notes: 'This directory contains all the CSS, images, and scripts which are used by the app.', tags: ['static', 'assets'] diff --git a/server/routes/api.js b/server/routes/api.js index 79c5486..03063d1 100644 --- a/server/routes/api.js +++ b/server/routes/api.js @@ -4,8 +4,8 @@ module.exports = [ { method: 'GET', path: '/api/aws', - handler: require('../controllers/aws'), config: { + handler: require('../controllers/aws'), description: 'API to get AWS EC2 instance data and regions.', notes: 'This should make it easier for the front-end app to share the same data as the backend server.', tags: ['api', 'aws'] @@ -13,8 +13,8 @@ module.exports = [ }, { method: 'POST', path: '/api/schema/validate', - handler: require('../controllers/schema'), config: { + handler: require('../controllers/schema'), description: 'API to validate a load test JSON packet', notes: ' ', tags: ['api', 'schema'] diff --git a/server/routes/comments.js b/server/routes/comments.js index f60dbb1..464882d 100644 --- a/server/routes/comments.js +++ b/server/routes/comments.js @@ -7,8 +7,8 @@ var controller = require('../controllers/comments'); module.exports = [{ method: 'GET', path: '/api/comments/runId/{runId}', - handler: controller.getComments, config: { + handler: controller.getComments, validate: { params: { runId: Joi.string().required() diff --git a/server/routes/gist.js b/server/routes/gist.js index 3da8ddf..1377f50 100644 --- a/server/routes/gist.js +++ b/server/routes/gist.js @@ -3,8 +3,8 @@ module.exports = [{ method: 'GET', path: '/api/gist/{id}', - handler: require('../controllers/gist'), config: { + handler: require('../controllers/gist'), description: 'API to get gists from github and return the data', notes: 'This is a clever note', tags: ['api', 'gist'] diff --git a/server/routes/home.js b/server/routes/home.js index 2a38ea6..22e9e61 100644 --- a/server/routes/home.js +++ b/server/routes/home.js @@ -3,10 +3,10 @@ module.exports = { method: 'GET', path: '/', - handler: function (request, reply) { - reply.file('client/static/index.html'); - }, config: { + handler: function (request, reply) { + reply.file('client/static/index.html'); + }, description: 'Static route for the /static/ directory.', notes: 'This directory contains all the CSS, images, and scripts which are used by the app.', tags: ['static', 'assets'] diff --git a/server/routes/static.js b/server/routes/static.js index e7b4e16..74093f4 100644 --- a/server/routes/static.js +++ b/server/routes/static.js @@ -3,8 +3,8 @@ module.exports = [{ method: 'GET', path: '/assets/{param*}', - handler: require('../controllers/assets'), config: { + handler: require('../controllers/assets'), description: 'Static route for the /static/ directory.', notes: 'This directory contains all the CSS, images, and scripts which are used by the app.', tags: ['static', 'assets'] @@ -12,8 +12,8 @@ module.exports = [{ }, { method: 'GET', path: '/bower_components/{param*}', - handler: require('../controllers/bower_components'), config: { + handler: require('../controllers/bower_components'), description: 'Static route for the /bower_components/ directory.', notes: 'This directory contains all the bower dependencies.', tags: ['static', 'assets']