├── api
├── models
│ ├── .gitkeep
│ ├── Team.js
│ ├── Project.js
│ ├── Member.js
│ ├── Todo.js
│ └── Endpoint.js
├── services
│ └── .gitkeep
├── controllers
│ ├── .gitkeep
│ ├── IndexController.js
│ ├── MemberController.js
│ ├── ProjectController.js
│ ├── TeamController.js
│ ├── TodosController.js
│ └── EndpointController.js
├── utils
│ └── debug.js
├── policies
│ └── sessionAuth.js
└── responses
│ ├── ok.js
│ ├── created.js
│ ├── badRequest.js
│ ├── forbidden.js
│ ├── serverError.js
│ └── notFound.js
├── assets
├── images
│ ├── .gitkeep
│ └── nebulis-logo.png
├── templates
│ └── .gitkeep
├── favicon.ico
├── robots.txt
└── styles
│ └── importer.less
├── .node-version
├── src
├── routes
│ ├── members
│ │ ├── view.js
│ │ └── index.js
│ ├── NotFound.js
│ ├── Page2.js
│ ├── Page1.js
│ ├── Home.js
│ ├── Login.js
│ ├── Layout.js
│ ├── TodosPage.js
│ └── projects
│ │ └── index.js
├── styles
│ ├── about-page.css
│ └── styles.scss
├── components
│ ├── style.scss
│ ├── Counter.js
│ ├── MemberListItems.js
│ ├── Teams.js
│ ├── Todos.js
│ ├── AddTeam.js
│ ├── ProjectListItems.js
│ ├── Team.js
│ ├── Members.js
│ ├── Projects.js
│ └── Form.js
├── reducers
│ ├── initialState.js
│ ├── index.js
│ ├── todoReducers.js
│ ├── memberReducers.js
│ ├── teamReducers.js
│ └── projectReducers.js
├── App.js
├── .eslintrc
├── api
│ └── todos.js
├── routes.js
├── redux
│ ├── index.js
│ └── todos.js
├── constants
│ └── actionTypes.js
├── index.js
├── store
│ └── configureStore.js
├── actions
│ └── nebulisActions.js
└── utils
│ └── redux-helpers.js
├── test
├── server
│ ├── LoginController.test.js
│ ├── MembersController.test.js
│ ├── TeamsController.test.js
│ ├── config.js
│ ├── Member.test.js
│ ├── Team.test.js
│ ├── Todo.test.js
│ ├── ProjectsController.test.js
│ ├── TodosController.test.js
│ ├── Project.test.js
│ └── Endpoint.test.js
├── endpoint
│ ├── testingProject
│ │ ├── index.js
│ │ ├── .nebulis.json
│ │ ├── .gitignore
│ │ └── package.json
│ ├── sampleconfig
│ └── config.js
├── ghoulies
│ ├── config.js
│ └── todos.test.js
└── client
│ ├── projectsPage.test.js
│ ├── config.js
│ ├── Login.test.js
│ ├── Todos.test.js
│ ├── Projects.test.js
│ └── Members.test.js
├── .dockerignore
├── .sailsrc
├── Procfile
├── config
├── locales
│ ├── de.json
│ ├── en.json
│ ├── es.json
│ ├── fr.json
│ └── _README.md
├── bootstrap.js
├── env
│ ├── dev.js
│ └── prod.js
├── log.js
├── models.js
├── policies.js
├── i18n.js
├── csrf.js
├── globals.js
├── cors.js
└── routes.js
├── .babelrc
├── gitnetLifter.js
├── .eslintrc.json
├── tasks
├── createDevEnv.sh
├── config
│ ├── clean.js
│ ├── uglify.js
│ ├── coffee.js
│ ├── watch.js
│ ├── cssmin.js
│ ├── less.js
│ ├── sync.js
│ ├── concat.js
│ ├── copy.js
│ └── jst.js
├── register
│ ├── syncAssets.js
│ ├── compileAssets.js
│ ├── linkAssetsBuild.js
│ ├── linkAssetsBuildProd.js
│ ├── linkAssets.js
│ ├── prod.js
│ ├── buildProd.js
│ ├── build.js
│ └── default.js
├── pipeline.js
└── README.md
├── public
└── styles
│ └── global.css
├── docker-compose.yml
├── views
├── index.ejs
├── header.ejs
├── 403.ejs
├── layout.ejs
└── 404.ejs
├── .editorconfig
├── gitnet.js
├── Dockerfile
├── .travis.yml
├── nebugit
├── messages.js
└── index.js
├── Gruntfile.js
├── app.js
├── webpack.config.js
├── .gitignore
├── README.md
└── nginx.conf.template
/api/models/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/api/services/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/images/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.node-version:
--------------------------------------------------------------------------------
1 | v6.9.1
2 |
--------------------------------------------------------------------------------
/api/controllers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/templates/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/routes/members/view.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/server/LoginController.test.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/server/MembersController.test.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/server/TeamsController.test.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/.sailsrc:
--------------------------------------------------------------------------------
1 | {
2 | "generators": {
3 | "modules": {}
4 | }
5 | }
--------------------------------------------------------------------------------
/src/styles/about-page.css:
--------------------------------------------------------------------------------
1 | .alt-header {
2 | color: green;
3 | }
--------------------------------------------------------------------------------
/test/endpoint/testingProject/index.js:
--------------------------------------------------------------------------------
1 | const nebulis = require('nebulis-endpoint');
--------------------------------------------------------------------------------
/test/endpoint/testingProject/.nebulis.json:
--------------------------------------------------------------------------------
1 | {
2 | "server": "localhost",
3 | "port": 1337
4 | }
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | build: npm run build:prod
2 | web: npm run server:prod
3 | gitnet: npm run gitnet:prod
4 |
--------------------------------------------------------------------------------
/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NebulisAnalytics/nebulis-server/HEAD/assets/favicon.ico
--------------------------------------------------------------------------------
/config/locales/de.json:
--------------------------------------------------------------------------------
1 | {
2 | "Welcome": "Willkommen",
3 | "A brand new app.": "Eine neue App."
4 | }
5 |
--------------------------------------------------------------------------------
/config/locales/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "Welcome": "Welcome",
3 | "A brand new app.": "A brand new app."
4 | }
5 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-0", "react"],
3 | "plugins": ["react-hot-loader/babel"]
4 | }
5 |
--------------------------------------------------------------------------------
/config/locales/es.json:
--------------------------------------------------------------------------------
1 | {
2 | "Welcome": "Bienvenido",
3 | "A brand new app.": "Una nueva aplicación."
4 | }
5 |
--------------------------------------------------------------------------------
/gitnetLifter.js:
--------------------------------------------------------------------------------
1 | const nebugit = require('./gitnet');
2 |
3 | setTimeout(() => {
4 | nebugit.listen();
5 | }, 3500);
--------------------------------------------------------------------------------
/config/locales/fr.json:
--------------------------------------------------------------------------------
1 | {
2 | "Welcome": "Bienvenue",
3 | "A brand new app.": "Une toute nouvelle application."
4 | }
5 |
--------------------------------------------------------------------------------
/assets/images/nebulis-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NebulisAnalytics/nebulis-server/HEAD/assets/images/nebulis-logo.png
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "plugins": [
4 | "react",
5 | "jsx-a11y",
6 | "import"
7 | ]
8 | }
--------------------------------------------------------------------------------
/tasks/createDevEnv.sh:
--------------------------------------------------------------------------------
1 | echo export API_HOST=http://localhost:1337
2 | echo export GIT_HOST=localhost:7000
3 | echo export REPO_LOCATION=/tmp/repos
--------------------------------------------------------------------------------
/public/styles/global.css:
--------------------------------------------------------------------------------
1 | HTML, BODY {
2 | font-family: Roboto;
3 | background: white;
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | .appbar H1 {
9 | display: inline;
10 | }
11 |
--------------------------------------------------------------------------------
/src/routes/NotFound.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | export default class NotFound extends Component {
4 | render() {
5 | return (
Not found
);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/style.scss:
--------------------------------------------------------------------------------
1 | $nebula-blue: #5F6D99;
2 | $codesmith-blue: #3182E4;
3 | $tron-blue: #02C5FF;
4 | $tron-orange: #FF8442;
5 | $blood-orange: #CC4621;
6 |
7 | div.projects{
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | web:
4 | build: .
5 | ports:
6 | - "1337:1337"
7 | volumes:
8 | - .:/usr/src/app
9 | redis:
10 | image: "node:boron"
11 |
--------------------------------------------------------------------------------
/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = tab
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/api/controllers/IndexController.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | index: function (req, res) {
3 | //res.locals.layout = 'views/layoout.ejs';
4 | res.render('index', {
5 | NODE_ENV: process.env['NODE_ENV']
6 | });
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/gitnet.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const config = JSON.parse(fs.readFileSync('./.babelrc'));
3 |
4 | require('babel-core/register')(config);
5 | require('babel-polyfill');
6 |
7 | const nebugit = require('./nebugit');
8 |
9 | module.exports = nebugit;
--------------------------------------------------------------------------------
/src/reducers/initialState.js:
--------------------------------------------------------------------------------
1 | export default function getInitialState() {
2 | return {
3 | error: null,
4 | loading: false,
5 | projects: [],
6 | isAddingProject: false,
7 | project: null,
8 | teams: null,
9 | team: {},
10 | downloading:false
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/assets/robots.txt:
--------------------------------------------------------------------------------
1 | # The robots.txt file is used to control how search engines index your live URLs.
2 | # See http://sailsjs.org/documentation/anatomy/my-app/assets/robots-txt for more information.
3 |
4 |
5 |
6 | # To prevent search engines from seeing the site altogether, uncomment the next two lines:
7 | # User-Agent: *
8 | # Disallow: /
9 |
--------------------------------------------------------------------------------
/test/ghoulies/config.js:
--------------------------------------------------------------------------------
1 | // require the app
2 | require('../../app.js');
3 |
4 | var ghoulies = require('ghoulies');
5 |
6 | before(function(done) {
7 |
8 | // listen to server event defined in /config/http.js
9 |
10 | ghoulies.on('SERVER_LOADED', function(app) {
11 | ghoulies.app = app;
12 | done();
13 | });
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:boron
2 |
3 | # Create app directory
4 | RUN mkdir -p /usr/src/app
5 | WORKDIR /usr/src/app
6 |
7 | # Install app dependencies
8 | COPY package.json /usr/src/app/
9 | RUN npm install
10 |
11 | # Bundle app source
12 | COPY . /usr/src/app
13 |
14 | # This sails app will start at port 1337
15 | EXPOSE 1337
16 |
17 | # Start the sails backend server
18 | CMD ["npm", "run", "prod"]
19 |
--------------------------------------------------------------------------------
/test/endpoint/sampleconfig:
--------------------------------------------------------------------------------
1 | [core]
2 | repositoryformatversion = 0
3 | filemode = true
4 | bare = false
5 | logallrefupdates = true
6 | ignorecase = true
7 | precomposeunicode = true
8 | [remote "github-nebulis"]
9 | url = https://github.com/LabUser/coding-challenge-1.git
10 | fetch = +refs/heads/*:refs/remotes/github-nebulis/*
11 | [branch "master"]
12 | remote = user
13 | merge = refs/heads/master
--------------------------------------------------------------------------------
/test/endpoint/testingProject/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # OS X
3 | .DS_Store*
4 | Icon?
5 | ._*
6 |
7 | # Windows
8 | Thumbs.db
9 | ehthumbs.db
10 | Desktop.ini
11 |
12 | # Linux
13 | .directory
14 | *~
15 |
16 |
17 | # npm
18 | node_modules
19 | *.log
20 | *.gz
21 |
22 |
23 | # Coveralls
24 | coverage
25 |
26 | # Benchmarking
27 | benchmarks/graphs
28 | .nebugit
29 | /lib
30 | /yarn.lock
31 | /package-lock.json
32 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import routes from './routes';
3 | import { Route, Router, IndexRoute, browserHistory } from 'react-router';
4 |
5 | export default class App extends Component {
6 | constructor(props) {
7 | super(props);
8 | }
9 | render() {
10 | return (
11 |
12 | {routes}
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | notifications:
3 | email: true
4 | slack: codesmith-15:pJzGP558zsfbulY3uQSdl2n0
5 | node_js:
6 | - '8'
7 | cache:
8 | directories:
9 | - node_modules
10 | script:
11 | - npm run test:endpoint
12 | - npm run test:server
13 | - npm run test:client
14 | addons:
15 | apt:
16 | sources:
17 | - ubuntu-toolchain-r-test
18 | packages:
19 | - libstdc++-4.9-dev
--------------------------------------------------------------------------------
/src/routes/Page2.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import Layout from './Layout';
3 |
4 | export default class Page2 extends Component {
5 | constructor(props) {
6 | super(props);
7 | this.state = {
8 | page: 2
9 | };
10 | }
11 |
12 | render() {
13 | return (
14 |
15 |
16 | page { this.state.page }
17 |
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/routes/Page1.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import Layout from './Layout';
3 |
4 | export default class Page1 extends Component {
5 | constructor(props) {
6 | super(props);
7 | this.state = {
8 | page: 1
9 | };
10 | }
11 |
12 | render() {
13 | return (
14 |
15 |
16 | page { this.state.page }
17 |
18 | );
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/api/utils/debug.js:
--------------------------------------------------------------------------------
1 | var chalk = require('chalk');
2 |
3 | function debug(s) {
4 | if (process.env['NODE_DEBUG'] === 'true') {
5 | var args = Array.prototype.slice.call(arguments);
6 | args = args.map(function (arg) {
7 | if (typeof arg === 'object' || typeof arg === 'number') return arg;
8 | else return chalk.green(arg);
9 | });
10 | console.log.apply(null, args);
11 | }
12 | }
13 |
14 | module.exports = debug;
15 |
--------------------------------------------------------------------------------
/test/client/projectsPage.test.js:
--------------------------------------------------------------------------------
1 | import chai from 'chai';
2 | const expect = chai.expect;
3 | import React, {Component} from 'react';
4 | import ReactDOM from 'react-dom';
5 | import TestUtils from 'react-addons-test-utils';
6 | import { getStore } from '../../src/store/configureStore';
7 |
8 |
9 | describe('Store', () => {
10 | it('store console log', () => {
11 | console.log(getStore().getState().projectsModel.projects)
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/test/client/config.js:
--------------------------------------------------------------------------------
1 | var jsdom = require('jsdom');
2 |
3 | function createDOM(done) {
4 | jsdom.env(
5 | '',
6 | ["http://code.jquery.com/jquery.js"],
7 | function (err, window) {
8 | global.document = window.document;
9 | global.window = window;
10 | global.$ = window.jQuery;
11 | done();
12 | }
13 | );
14 | }
15 |
16 | before(function(done) {
17 | this.timeout(20000);
18 | createDOM(done);
19 | });
20 |
--------------------------------------------------------------------------------
/test/endpoint/testingProject/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "testingproject",
3 | "version": "1.0.0",
4 | "description": "a testing project",
5 | "main": "index.js",
6 | "scripts": {
7 | "track": "node index.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "The Project Author",
11 | "license": "ISC",
12 | "dependencies": {
13 | "colors": "^1.1.2",
14 | "nebulis-endpoint": "^0.4.1"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/api/controllers/MemberController.js:
--------------------------------------------------------------------------------
1 | /**
2 | * MemberController
3 | *
4 | * @description :: Server-side logic for managing members
5 | * @help :: See http://sailsjs.org/#!/documentation/concepts/Controllers
6 | */
7 |
8 | module.exports = {
9 | getMembers: function (req, res) {
10 | Member.find({}).exec(function (err, members) {
11 | if (err) {
12 | res.status(500);
13 | res.send(err);
14 | }
15 | else res.send(members);
16 | });
17 | }
18 |
19 | };
20 |
--------------------------------------------------------------------------------
/views/header.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/server/config.js:
--------------------------------------------------------------------------------
1 | const sails = require('sails');
2 | const nebugit = require('../../gitnet');
3 | const fs = require('fs');
4 | const rimraf = require('rimraf');
5 |
6 | before(function(done) {
7 | this.timeout(20000);
8 | rimraf('.tmp/localDiskTestingDb.db', () => {
9 | fs.mkdir(`${process.env['REPO_LOCATION']}`, function (err) {
10 | nebugit.listen();
11 | sails.lift(function() {
12 | done();
13 | });
14 | });
15 | });
16 | });
17 |
18 | after((done) => {
19 | nebugit.stop();
20 | done();
21 | });
--------------------------------------------------------------------------------
/tasks/config/clean.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `clean`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Remove the files and folders in your Sails app's web root
7 | * (conventionally a hidden directory called `.tmp/public`).
8 | *
9 | * For usage docs see:
10 | * https://github.com/gruntjs/grunt-contrib-clean
11 | *
12 | */
13 | module.exports = function(grunt) {
14 |
15 | grunt.config.set('clean', {
16 | dev: ['.tmp/public/**'],
17 | build: ['www']
18 | });
19 |
20 | grunt.loadNpmTasks('grunt-contrib-clean');
21 | };
22 |
--------------------------------------------------------------------------------
/tasks/config/uglify.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `uglify`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Minify client-side JavaScript files using UglifyJS.
7 | *
8 | * For usage docs see:
9 | * https://github.com/gruntjs/grunt-contrib-uglify
10 | *
11 | */
12 | module.exports = function(grunt) {
13 |
14 | grunt.config.set('uglify', {
15 | dist: {
16 | src: ['.tmp/public/concat/production.js'],
17 | dest: '.tmp/public/min/production.min.js'
18 | }
19 | });
20 |
21 | grunt.loadNpmTasks('grunt-contrib-uglify');
22 | };
23 |
--------------------------------------------------------------------------------
/test/endpoint/config.js:
--------------------------------------------------------------------------------
1 | const sails = require('sails');
2 | const nebugit = require('../../gitnet');
3 | const fs = require('fs');
4 | var rimraf = require('rimraf');
5 |
6 | before(function(done) {
7 | this.timeout(20000);
8 | rimraf(`.tmp/localDiskTestingDb.db`, () => {
9 | fs.mkdir(`${process.env['REPO_LOCATION']}`, function (err) {
10 | nebugit.listen();
11 | sails.lift(function() {
12 | done();
13 | });
14 | });
15 | });
16 | });
17 |
18 | after((done) => {
19 | nebugit.stop();
20 | done();
21 | });
22 |
23 | exports.nebugit = nebugit;
24 |
--------------------------------------------------------------------------------
/tasks/register/syncAssets.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `syncAssets`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This Grunt tasklist is not designed to be used directly-- rather
7 | * it is a helper called by the `watch` task (`tasks/config/watch.js`).
8 | *
9 | * For more information see:
10 | * http://sailsjs.org/documentation/anatomy/my-app/tasks/register/sync-assets-js
11 | *
12 | */
13 | module.exports = function(grunt) {
14 | grunt.registerTask('syncAssets', [
15 | 'jst:dev',
16 | 'less:dev',
17 | 'sync:dev',
18 | 'coffee:dev'
19 | ]);
20 | };
21 |
--------------------------------------------------------------------------------
/api/models/Team.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Team.js
3 | *
4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here.
5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models
6 | */
7 |
8 | module.exports = {
9 |
10 | attributes: {
11 | project: {
12 | model: 'project',
13 | },
14 | members: {
15 | collection: 'member',
16 | via: 'teams',
17 | dominant: true,
18 | },
19 | endpoints: {
20 | collection: 'endpoint',
21 | via: 'team',
22 | },
23 | name: {
24 | type: 'string',
25 | },
26 | },
27 | };
28 |
29 |
--------------------------------------------------------------------------------
/tasks/register/compileAssets.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `compileAssets`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This Grunt tasklist is not designed to be used directly-- rather
7 | * it is a helper called by the `default`, `prod`, `build`, and
8 | * `buildProd` tasklists.
9 | *
10 | * For more information see:
11 | * http://sailsjs.org/documentation/anatomy/my-app/tasks/register/compile-assets-js
12 | *
13 | */
14 | module.exports = function(grunt) {
15 | grunt.registerTask('compileAssets', [
16 | 'clean:dev',
17 | 'jst:dev',
18 | 'less:dev',
19 | 'copy:dev',
20 | 'coffee:dev'
21 | ]);
22 | };
23 |
--------------------------------------------------------------------------------
/config/bootstrap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Bootstrap
3 | * (sails.config.bootstrap)
4 | *
5 | * An asynchronous bootstrap function that runs before your Sails app gets lifted.
6 | * This gives you an opportunity to set up your data model, run jobs, or perform some special logic.
7 | *
8 | * For more information on bootstrapping your app, check out:
9 | * http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.bootstrap.html
10 | */
11 |
12 | module.exports.bootstrap = function(cb) {
13 |
14 | // It's very important to trigger this callback method when you are finished
15 | // with the bootstrap! (otherwise your server will never lift, since it's waiting on the bootstrap)
16 | cb();
17 | };
18 |
--------------------------------------------------------------------------------
/src/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "plugins": [
4 | "react"
5 | ],
6 | "rules": {
7 | "indent": 0,
8 | "no-script-url": 0,
9 | "react/jsx-indent-props": 0,
10 | "no-console": 0,
11 | "comma-dangle": 0,
12 | "prefer-template": 0,
13 | "semi": 0,
14 | "max-len": 0,
15 | "space-infix-ops": 0,
16 | "brace-style": 0,
17 | "react/jsx-space-before-closing": 0,
18 | "no-else-return": 0,
19 | "spaced-comment": 0,
20 | "no-trailing-spaces": 0,
21 | "padded-blocks": 0,
22 | "quotes": 0,
23 | "no-mixed-spaces-and-tabs": 0,
24 | "space-in-parens": 0,
25 | "arrow-body-style": 0,
26 | "one-var-declaration-per-line": 0
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/styles/styles.scss:
--------------------------------------------------------------------------------
1 | /* Variables */
2 | $vin-blue: #5bb7db;
3 | $vin-green: #60b044;
4 | $vin-red: #ff0000;
5 |
6 | /* Styles */
7 | body {
8 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
9 | line-height: 1.4em;
10 | color: #4d4d4d;
11 | min-width: 230px;
12 | max-width: 550px;
13 | margin: 0 auto;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-font-smoothing: antialiased;
16 | font-smoothing: antialiased;
17 | font-weight: 300;
18 | }
19 |
20 | td {
21 | padding: 12px;
22 | }
23 |
24 | h2 {
25 | color: $vin-blue;
26 | }
27 |
28 | .savings { color: $vin-green; }
29 | .loss { color: $vin-red; }
30 | input.small { width: 46px; }
31 | td.fuel-savings-label { width: 175px; }
32 |
--------------------------------------------------------------------------------
/tasks/register/linkAssetsBuild.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `linkAssetsBuild`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This Grunt tasklist is not designed to be used directly-- rather
7 | * it is a helper called by the `build` tasklist.
8 | *
9 | * For more information see:
10 | * http://sailsjs.org/documentation/anatomy/my-app/tasks/register/link-assets-build-js
11 | *
12 | */
13 | module.exports = function(grunt) {
14 | grunt.registerTask('linkAssetsBuild', [
15 | 'sails-linker:devJsRelative',
16 | 'sails-linker:devStylesRelative',
17 | 'sails-linker:devTpl',
18 | 'sails-linker:devJsRelativeJade',
19 | 'sails-linker:devStylesRelativeJade',
20 | 'sails-linker:devTplJade'
21 | ]);
22 | };
23 |
--------------------------------------------------------------------------------
/src/components/Counter.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | export default class Counter extends Component {
3 | constructor(props) {
4 | super(props);
5 | if (typeof window.counter === 'undefined') {
6 | window.counter = 0;
7 | }
8 | this.state = {
9 | value : window.counter,
10 | mounted : true
11 | };
12 |
13 | this.interval = setInterval(() => {
14 | if (this.state.mounted) {
15 | window.counter++;
16 | this.setState({
17 | value: window.counter
18 | });
19 | }
20 | },1000);
21 | }
22 | componentWillUnmount() {
23 | clearInterval(this.interval);
24 | this.setState({
25 | mounted : false
26 | });
27 | }
28 | render() {
29 | return (Counter: { this.state.value }
);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/api/models/Project.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Project.js
3 | *
4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here.
5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models
6 | */
7 |
8 | module.exports = {
9 |
10 | attributes: {
11 | name: {
12 | type: 'string',
13 | required: true
14 | },
15 | slug: {
16 | type: 'string',
17 | unique: true
18 | },
19 | gitLink: {
20 | type: 'url',
21 | required: true,
22 | unique: true
23 | },
24 | endpoints: {
25 | collection: 'endpoint',
26 | via: 'project',
27 | },
28 | teams: {
29 | collection: 'team',
30 | via: 'project',
31 | },
32 | }
33 | };
34 |
35 |
--------------------------------------------------------------------------------
/tasks/register/linkAssetsBuildProd.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `linkAssetsBuildProd`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This Grunt tasklist is not designed to be used directly-- rather
7 | * it is a helper called by the `buildProd` tasklist.
8 | *
9 | * For more information see:
10 | * http://sailsjs.org/documentation/anatomy/my-app/tasks/register/link-assets-build-prod-js
11 | *
12 | */
13 | module.exports = function(grunt) {
14 | grunt.registerTask('linkAssetsBuildProd', [
15 | 'sails-linker:prodJsRelative',
16 | 'sails-linker:prodStylesRelative',
17 | 'sails-linker:devTpl',
18 | 'sails-linker:prodJsRelativeJade',
19 | 'sails-linker:prodStylesRelativeJade',
20 | 'sails-linker:devTplJade'
21 | ]);
22 | };
23 |
--------------------------------------------------------------------------------
/tasks/register/linkAssets.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `linkAssets`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This Grunt tasklist is not designed to be used directly-- rather
7 | * it is a helper called by the `default` tasklist and the `watch` task
8 | * (but only if the `grunt-sails-linker` package is in use).
9 | *
10 | * For more information see:
11 | * http://sailsjs.org/documentation/anatomy/my-app/tasks/register/link-assets-js
12 | *
13 | */
14 | module.exports = function(grunt) {
15 | grunt.registerTask('linkAssets', [
16 | 'sails-linker:devJs',
17 | 'sails-linker:devStyles',
18 | 'sails-linker:devTpl',
19 | 'sails-linker:devJsJade',
20 | 'sails-linker:devStylesJade',
21 | 'sails-linker:devTplJade'
22 | ]);
23 | };
24 |
--------------------------------------------------------------------------------
/api/policies/sessionAuth.js:
--------------------------------------------------------------------------------
1 | /**
2 | * sessionAuth
3 | *
4 | * @module :: Policy
5 | * @description :: Simple policy to allow any authenticated user
6 | * Assumes that your login action in one of your controllers sets `req.session.authenticated = true;`
7 | * @docs :: http://sailsjs.org/#!/documentation/concepts/Policies
8 | *
9 | */
10 | module.exports = function(req, res, next) {
11 |
12 | // User is allowed, proceed to the next policy,
13 | // or if this is the last policy, the controller
14 | if (req.session.authenticated) {
15 | return next();
16 | }
17 |
18 | // User is not allowed
19 | // (default res.forbidden() behavior can be overridden in `config/403.js`)
20 | return res.forbidden('You are not permitted to perform this action.');
21 | };
22 |
--------------------------------------------------------------------------------
/api/models/Member.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Member.js
3 | *
4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here.
5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models
6 | */
7 |
8 | module.exports = {
9 |
10 | attributes: {
11 | gitAccess: {
12 | type: 'string'
13 | },
14 | admin: {
15 | type: 'boolean',
16 | required: true,
17 | defaultsTo: false
18 | },
19 | endpoints: {
20 | collection: 'endpoint',
21 | via: 'member',
22 | },
23 | username: {
24 | type: 'string',
25 | unique: true,
26 | },
27 | fullname: {
28 | type: 'string',
29 | },
30 | teams: {
31 | collection: 'team',
32 | via: 'members',
33 | },
34 | },
35 | };
36 |
--------------------------------------------------------------------------------
/tasks/register/prod.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `prod`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This Grunt tasklist will be executed instead of `default` when
7 | * your Sails app is lifted in a production environment (e.g. using
8 | * `NODE_ENV=production node app`).
9 | *
10 | * For more information see:
11 | * http://sailsjs.org/documentation/anatomy/my-app/tasks/register/prod-js
12 | *
13 | */
14 | module.exports = function(grunt) {
15 | grunt.registerTask('prod', [
16 | 'compileAssets',
17 | 'concat',
18 | 'uglify',
19 | 'cssmin',
20 | 'sails-linker:prodJs',
21 | 'sails-linker:prodStyles',
22 | 'sails-linker:devTpl',
23 | 'sails-linker:prodJsJade',
24 | 'sails-linker:prodStylesJade',
25 | 'sails-linker:devTplJade'
26 | ]);
27 | };
28 |
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import {responsiveStateReducer} from 'redux-responsive';
2 | import {combineReducers} from 'redux';
3 | import {responsiveDrawer} from 'material-ui-responsive-drawer';
4 | import {reducer as projectsModel} from './../reducers/projectReducers';
5 | import {reducer as teamsModel} from './../reducers/teamReducers';
6 | import {reducer as membersModel} from './../reducers/memberReducers';
7 |
8 | import ghoulie from 'ghoulie';
9 | // ghoulieReducer intercepts redux events and outputs them to console.log for debugging
10 | let ghoulieReducer = ghoulie.reducer();
11 |
12 | const rootReducer = combineReducers({
13 | browser: responsiveStateReducer,
14 | responsiveDrawer: responsiveDrawer,
15 | projectsModel,
16 | teamsModel,
17 | membersModel,
18 | ghoulieReducer
19 | });
20 |
21 | export default rootReducer;
22 |
--------------------------------------------------------------------------------
/tasks/config/coffee.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `coffee`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Compile CoffeeScript files located in `assets/js` into Javascript
7 | * and generate new `.js` files in `.tmp/public/js`.
8 | *
9 | * For usage docs see:
10 | * https://github.com/gruntjs/grunt-contrib-coffee
11 | *
12 | */
13 | module.exports = function(grunt) {
14 |
15 | grunt.config.set('coffee', {
16 | dev: {
17 | options: {
18 | bare: true,
19 | sourceMap: true,
20 | sourceRoot: './'
21 | },
22 | files: [{
23 | expand: true,
24 | cwd: 'assets/js/',
25 | src: ['**/*.coffee'],
26 | dest: '.tmp/public/js/',
27 | ext: '.js'
28 | }]
29 | }
30 | });
31 |
32 | grunt.loadNpmTasks('grunt-contrib-coffee');
33 | };
34 |
--------------------------------------------------------------------------------
/src/api/todos.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | // example of how to manually perform a fetch() outside of the redux-helpers lib
4 |
5 | import es6promise from 'es6-promise';
6 | es6promise.polyfill();
7 | import fetch from 'isomorphic-fetch';
8 |
9 | function createTodo(name, callback) {
10 | fetch('/api/todos', {
11 | method: 'POST',
12 | credentials: 'include',
13 | headers: {
14 | 'Accept': 'application/json',
15 | 'Content-Type': 'application/json'
16 | },
17 | body: JSON.stringify({
18 | name: name
19 | })
20 | })
21 | .then(function (response) {
22 | if (response.status >= 400) {
23 | throw new Error("Bad response from server");
24 | }
25 | return response.json();
26 | })
27 | .then(function (todos) {
28 | callback(null, todos);
29 | })
30 | .catch(function (err) {
31 | console.log(err);
32 | callback(err);
33 | });
34 | }
35 | */
36 |
--------------------------------------------------------------------------------
/tasks/config/watch.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `watch`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Run predefined tasks whenever watched file patterns are added, changed or deleted.
7 | *
8 | * Watch for changes on:
9 | * - files in the `assets` folder
10 | * - the `tasks/pipeline.js` file
11 | * and re-run the appropriate tasks.
12 | *
13 | * For usage docs see:
14 | * https://github.com/gruntjs/grunt-contrib-watch
15 | *
16 | */
17 | module.exports = function(grunt) {
18 |
19 | grunt.config.set('watch', {
20 | assets: {
21 |
22 | // Assets to watch:
23 | files: ['assets/**/*', 'tasks/pipeline.js', '!**/node_modules/**'],
24 |
25 | // When assets are changed:
26 | tasks: ['syncAssets' , 'linkAssets' ]
27 | }
28 | });
29 |
30 | grunt.loadNpmTasks('grunt-contrib-watch');
31 | };
32 |
--------------------------------------------------------------------------------
/src/routes/Home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router';
3 | import Layout from './Layout';
4 |
5 | export default class IndexPage extends Component {
6 | constructor(props) {
7 | super(props);
8 | }
9 |
10 | render() {
11 | const styles = {
12 | logoContainer: {
13 | opacity: 0.15,
14 | paddingTop: '100',
15 | margin: '0 auto',
16 | textAlign: 'center',
17 | objectPosition: '400px 50px'
18 | },
19 | logo: {
20 | height: '50%',
21 | width: '50%',
22 | }
23 | }
24 |
25 | return (
26 |
27 |
28 |
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tasks/config/cssmin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Compress CSS files.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Minify the intermediate concatenated CSS stylesheet which was
7 | * prepared by the `concat` task at `.tmp/public/concat/production.css`.
8 | *
9 | * Together with the `concat` task, this is the final step that minifies
10 | * all CSS files from `assets/styles/` (and potentially your LESS importer
11 | * file from `assets/styles/importer.less`)
12 | *
13 | * For usage docs see:
14 | * https://github.com/gruntjs/grunt-contrib-cssmin
15 | *
16 | */
17 | module.exports = function(grunt) {
18 |
19 | grunt.config.set('cssmin', {
20 | dist: {
21 | src: ['.tmp/public/concat/production.css'],
22 | dest: '.tmp/public/min/production.min.css'
23 | }
24 | });
25 |
26 | grunt.loadNpmTasks('grunt-contrib-cssmin');
27 | };
28 |
--------------------------------------------------------------------------------
/tasks/config/less.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `less`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Compile your LESS files into a CSS stylesheet.
7 | *
8 | * By default, only the `assets/styles/importer.less` is compiled.
9 | * This allows you to control the ordering yourself, i.e. import your
10 | * dependencies, mixins, variables, resets, etc. before other stylesheets)
11 | *
12 | * For usage docs see:
13 | * https://github.com/gruntjs/grunt-contrib-less
14 | *
15 | */
16 | module.exports = function(grunt) {
17 |
18 | grunt.config.set('less', {
19 | dev: {
20 | files: [{
21 | expand: true,
22 | cwd: 'assets/styles/',
23 | src: ['importer.less'],
24 | dest: '.tmp/public/styles/',
25 | ext: '.css'
26 | }]
27 | }
28 | });
29 |
30 | grunt.loadNpmTasks('grunt-contrib-less');
31 | };
32 |
--------------------------------------------------------------------------------
/tasks/register/buildProd.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `buildProd`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This Grunt tasklist will be executed instead of `build` if you
7 | * run `sails www` in a production environment, e.g.:
8 | * `NODE_ENV=production sails www`
9 | *
10 | * This generates a folder containing your compiled (and usually minified)
11 | * assets. The most common use case for this is bundling up files to
12 | * deploy to a CDN.
13 | *
14 | * For more information see:
15 | * http://sailsjs.org/documentation/anatomy/my-app/tasks/register/build-prod-js
16 | *
17 | */
18 | module.exports = function(grunt) {
19 | grunt.registerTask('buildProd', [
20 | 'compileAssets',
21 | 'concat',
22 | 'uglify',
23 | 'cssmin',
24 | 'linkAssetsBuildProd',
25 | 'clean:build',
26 | 'copy:build'
27 | ]);
28 | };
29 |
30 |
--------------------------------------------------------------------------------
/api/models/Todo.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | attributes: {
3 | name: {
4 | type: 'string',
5 | defaultsTo: 'null'
6 | },
7 | completed: {
8 | type: 'boolean',
9 | defaultsTo: false
10 | }
11 | },
12 | getAll: function (callback) {
13 | this.find({}).exec(callback);
14 | },
15 | createTodo: function (name, callback) {
16 | var values;
17 | if (name) {
18 | values = {
19 | name: name
20 | };
21 | }
22 | this.create(values).exec(callback);
23 | },
24 | deleteAll: function (callback) {
25 | this.destroy({}).exec(callback);
26 | },
27 | updateTodo: function (data, callback) {
28 | var id = data.id;
29 | this.update({
30 | id: id
31 | }, data).exec(callback);
32 | },
33 | deleteTodo: function (id, callback) {
34 | this.destroy({
35 | id: id
36 | }).exec(callback);
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/tasks/config/sync.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `sync`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Synchronize files from the `assets` folder to `.tmp/public`,
7 | * smashing anything that's already there.
8 | *
9 | * This task synchronizes one directory with another (like rsync).
10 | * In the default Sails asset pipeline, it plays very similar role
11 | * to `grunt-contrib-copy`, but copies only those files that have
12 | * actually changed since the last time the task was run.
13 | *
14 | * For usage docs see:
15 | * https://github.com/tomusdrw/grunt-sync
16 | *
17 | */
18 | module.exports = function(grunt) {
19 |
20 | grunt.config.set('sync', {
21 | dev: {
22 | files: [{
23 | cwd: './assets',
24 | src: ['**/*.!(coffee|less)'],
25 | dest: '.tmp/public'
26 | }]
27 | }
28 | });
29 |
30 | grunt.loadNpmTasks('grunt-sync');
31 | };
32 |
--------------------------------------------------------------------------------
/src/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, Router, IndexRoute, browserHistory } from 'react-router';
3 |
4 | import Home from './routes/Home';
5 | import Login from './routes/Login';
6 | import ProjectPage from './routes/projects/index';
7 | import ProjectContainer from './routes/projects/view';
8 | import MembersContainer from './routes/members/index';
9 | import MemberContainer from './routes/members/view';
10 | import Page2 from './routes/Page2';
11 | import NotFound from './routes/NotFound';
12 |
13 | export default (
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
--------------------------------------------------------------------------------
/config/env/dev.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Development environment settings
3 | *
4 | * This file can include shared settings for a development team,
5 | * such as API keys or remote database passwords. If you're using
6 | * a version control solution for your Sails app, this file will
7 | * be committed to your repository unless you add it to your .gitignore
8 | * file. If your repository will be publicly viewable, don't add
9 | * any private information to this file!
10 | *
11 | */
12 |
13 | module.exports = {
14 |
15 | /***************************************************************************
16 | * Set the default database connection for models in the development *
17 | * environment (see config/connections.js and config/models.js ) *
18 | ***************************************************************************/
19 |
20 | // models: {
21 | // connection: 'someMongodbServer'
22 | // }
23 |
24 | };
25 |
--------------------------------------------------------------------------------
/src/components/MemberListItems.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router';
3 | import { Members } from './Members';
4 | import { ListItem } from 'material-ui/List';
5 | import AccountPlus from 'material-ui/svg-icons/social/person';
6 | import Avatar from 'material-ui/Avatar';
7 |
8 | export default class MemberListItems extends Component {
9 | render() {
10 | const member = this.props.member;
11 | return (
12 | } />}>
17 |
18 | )}
19 | }
20 |
21 |
22 |
23 | //
24 | //
25 | //
26 | //
27 | //
28 | //
29 | //
30 | // ×
31 | //
32 |
--------------------------------------------------------------------------------
/src/redux/index.js:
--------------------------------------------------------------------------------
1 | import es6promise from 'es6-promise';
2 | es6promise.polyfill();
3 |
4 | import { combineReducers, createStore, applyMiddleware } from 'redux';
5 | import thunk from 'redux-thunk';
6 | import ghoulie from 'ghoulie';
7 |
8 | // REDUCERS ----------------------------
9 |
10 | // import the generated reducer and actions
11 | import {reducer as todosModel, actions as todosActions} from './todos';
12 |
13 | // export the actions so they can be used elsewhere in the app
14 | export {todosActions};
15 |
16 | // ghoulieReducer intercepts redux events and outputs them to console.log for debugging
17 | let ghoulieReducer = ghoulie.reducer();
18 |
19 | // combine the reducers
20 | const rootReducer = combineReducers({
21 | todosModel,
22 | ghoulieReducer
23 | });
24 |
25 | // create the redux store
26 | export const store = createStore(
27 | rootReducer,
28 | applyMiddleware(thunk)
29 | );
30 |
31 | export function getStore() {
32 | return store;
33 | }
34 |
35 | window.getStore = getStore;
36 |
--------------------------------------------------------------------------------
/tasks/register/build.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `build`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This Grunt tasklist will be executed if you run `sails www` or
7 | * `grunt build` in a development environment. It generates a
8 | * folder containing your compiled assets, e.g. for troubleshooting
9 | * issues with other Grunt plugins, bundling assets for an Electron
10 | * or PhoneGap app, or deploying your app's flat files to a CDN.
11 | *
12 | * Note that when running `sails www` in a production environment (with the
13 | * `NODE_ENV` environment variable set to 'production') the `buildProd` task
14 | * will be run instead of this one.
15 | *
16 | * For more information see:
17 | * http://sailsjs.org/documentation/anatomy/my-app/tasks/register/build-js
18 | *
19 | */
20 | module.exports = function(grunt) {
21 | grunt.registerTask('build', [
22 | 'compileAssets',
23 | 'linkAssetsBuild',
24 | 'clean:build',
25 | 'copy:build'
26 | ]);
27 | };
28 |
--------------------------------------------------------------------------------
/assets/styles/importer.less:
--------------------------------------------------------------------------------
1 | /**
2 | * importer.less
3 | *
4 | * By default, new Sails projects are configured to compile this file
5 | * from LESS to CSS. Unlike CSS files, LESS files are not compiled and
6 | * included automatically unless they are imported below.
7 | *
8 | * The LESS files imported below are compiled and included in the order
9 | * they are listed. Mixins, variables, etc. should be imported first
10 | * so that they can be accessed by subsequent LESS stylesheets.
11 | *
12 | * (Just like the rest of the asset pipeline bundled in Sails, you can
13 | * always omit, customize, or replace this behavior with SASS, SCSS,
14 | * or any other Grunt tasks you like.)
15 | */
16 |
17 |
18 |
19 | // For example:
20 | //
21 | // @import 'variables/colors.less';
22 | // @import 'mixins/foo.less';
23 | // @import 'mixins/bar.less';
24 | // @import 'mixins/baz.less';
25 | //
26 | // @import 'styleguide.less';
27 | // @import 'pages/login.less';
28 | // @import 'pages/signup.less';
29 | //
30 | // etc.
31 |
--------------------------------------------------------------------------------
/tasks/config/concat.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `concat`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Concatenates the contents of multiple JavaScript and/or CSS files
7 | * into two new files, each located at `concat/production.js` and
8 | * `concat/production.css` respectively in `.tmp/public/concat`.
9 | *
10 | * This is used as an intermediate step to generate monolithic files
11 | * that can then be passed in to `uglify` and/or `cssmin` for minification.
12 | *
13 | * For usage docs see:
14 | * https://github.com/gruntjs/grunt-contrib-concat
15 | *
16 | */
17 | module.exports = function(grunt) {
18 |
19 | grunt.config.set('concat', {
20 | js: {
21 | src: require('../pipeline').jsFilesToInject,
22 | dest: '.tmp/public/concat/production.js'
23 | },
24 | css: {
25 | src: require('../pipeline').cssFilesToInject,
26 | dest: '.tmp/public/concat/production.css'
27 | }
28 | });
29 |
30 | grunt.loadNpmTasks('grunt-contrib-concat');
31 | };
32 |
--------------------------------------------------------------------------------
/src/components/Teams.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import Team from './Team';
3 | import {Link} from 'react-router';
4 | import {List, ListItem } from 'material-ui/List';
5 | import Subheader from 'material-ui/Subheader';
6 |
7 | export default class Teams extends Component {
8 | render() {
9 | return (
10 |
11 | { this.renderTeams() }
12 |
);
13 | }
14 |
15 | renderTeams() {
16 | if (this.props.teams.length) {
17 | return (
18 |
19 | Teams
20 | { this.props.teams.map((team, index) => {
21 | let onTeamTouch = () => {
22 | this.props.onTeamTouch(team.id);
23 | };
24 | let onDownload = () => {
25 | this.props.onDownload(team.id);
26 | }
27 | return (
28 |
32 | );
33 | })}
34 |
35 | );
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/api/controllers/ProjectController.js:
--------------------------------------------------------------------------------
1 | /**
2 | * ProjectController
3 | *
4 | * @description :: Server-side logic for managing projects
5 | * @help :: See http://sailsjs.org/#!/documentation/concepts/Controllers
6 | */
7 |
8 | module.exports = {
9 | getProjects: function (req, res) {
10 | Project.find({}).exec(function (err, projects) {
11 | if (err) {
12 | res.status(500);
13 | res.send(err);
14 | }
15 | else res.send(projects);
16 | });
17 | },
18 | getProject: function (req, res) {
19 | Project.find({id: req.params.id}).exec(function (err, project) {
20 | if (err) {
21 | res.status(500);
22 | res.send(err);
23 | } else res.send(project);
24 | })
25 | },
26 |
27 | create: async (req, res) => {
28 | try {
29 | const name = req.body.name;
30 | const gitLink = req.body.gitLink;
31 | const slug = gitLink.split('/')[4];
32 | const project = await Project.create({ name, slug, gitLink });
33 | res.send(project);
34 | } catch (err) {
35 | res.send(err);
36 | }
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/api/controllers/TeamController.js:
--------------------------------------------------------------------------------
1 | /**
2 | * TeamController
3 | *
4 | * @description :: Server-side logic for managing teams
5 | * @help :: See http://sailsjs.org/#!/documentation/concepts/Controllers
6 | */
7 |
8 | module.exports = {
9 |
10 | //TODO: create test for this
11 | create: async (req, res) => {
12 | try {
13 | team = await Team.create({
14 | name: 'unnamed group',
15 | project: req.body.project
16 | });
17 | await team.members.add(req.body.members);
18 | await team.save();
19 | res.send(team);
20 | } catch (err) {
21 | sails.log(err);
22 | res.send(err);
23 | }
24 | },
25 | index: (req, res) => {
26 | sails.log('create team');
27 | sails.log(req.body);
28 | res.send('success');
29 | },
30 | projectIndex: (req, res) => {
31 | sails.log('view teams for project');
32 |
33 | Team.find({project: req.params['id']}).populate('members').exec((err, teams) => { res.send(teams)});
34 | },
35 | view: (req, res) => {
36 | sails.log('create team');
37 | sails.log(req.body);
38 | res.send('success');
39 | }
40 | };
41 |
42 |
--------------------------------------------------------------------------------
/tasks/register/default.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `default`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This is the default Grunt tasklist that will be executed if you
7 | * run `grunt` in the top level directory of your app. It is also
8 | * called automatically when you start Sails in development mode using
9 | * `sails lift` or `node app`.
10 | *
11 | * Note that when lifting your app with a custom environment setting
12 | * (i.e. `sails.config.environment`), Sails will look for a tasklist file
13 | * with the same name and run that instead of this one.
14 | *
15 | * > Note that as a special case for compatibility/historial reasons, if
16 | * > your environment is "production", and Sails cannot find a tasklist named
17 | * > `production.js`, it will attempt to run the `prod.js` tasklist as well
18 | * > before defaulting to `default.js`.
19 | *
20 | * For more information see:
21 | * http://sailsjs.org/documentation/anatomy/my-app/tasks/register/default-js
22 | *
23 | */
24 | module.exports = function (grunt) {
25 | grunt.registerTask('default', ['compileAssets', 'linkAssets', 'watch']);
26 | };
27 |
--------------------------------------------------------------------------------
/src/reducers/todoReducers.js:
--------------------------------------------------------------------------------
1 | import {createReducer} from '../utils/redux-helpers.js';
2 | import getInitialState from './initialState'
3 |
4 | // export default function getInitialState() {
5 | // return {
6 | // error: null,
7 | // loading: false,
8 | // todos: []
9 | // }
10 | // }
11 |
12 | // TODOS REDUCER
13 |
14 |
15 | const reducer = createReducer(getInitialState, {
16 | GET_TODOS: function(state, action) {
17 | return Object.assign({}, state, {
18 | loading: true
19 | });
20 | },
21 | GET_TODOS_SUCCESS: function(state, action) {
22 | return Object.assign({}, state, {
23 | loading: false,
24 | todos: action.results // response JSON body is available in action.results
25 | });
26 | },
27 |
28 | CREATE_TODO: function(state, action) {
29 | return Object.assign({}, state, {
30 | loading: true
31 | });
32 | },
33 | CREATE_TODO_SUCCESS: function(state, action) {
34 | return Object.assign({}, state, {
35 | loading: false
36 | });
37 | },
38 |
39 | TODOS_ERROR: function(state, action) {
40 | return Object.assign({}, state, {
41 | loading: false,
42 | error: action.error
43 | });
44 | },
45 | });
46 |
47 | export {reducer};
48 |
--------------------------------------------------------------------------------
/test/client/Login.test.js:
--------------------------------------------------------------------------------
1 | import chai from 'chai';
2 | const expect = chai.expect;
3 | import React, {Component} from 'react';
4 | import ReactDOM from 'react-dom';
5 | import TestUtils from 'react-addons-test-utils';
6 | import { shallow } from 'enzyme';
7 | import { assert } from 'chai';
8 |
9 | import Login from '../../src/routes/Login';
10 |
11 | let testComponent;
12 |
13 | describe('Login component', () => {
14 | // before(function(done) {
15 | // testComponent = TestUtils.renderIntoDocument(
16 | //
17 | // );
18 | // done();
19 | // });
20 | it('should render', () => {
21 | const wrapper = shallow( );
22 | assert.ok(wrapper);
23 | });
24 |
25 | // it('renders correctly', () => {
26 | //
27 | // let testNode = ReactDOM.findDOMNode(testComponent);
28 | //
29 | // expect(testNode.nodeName).to.be.equal('DIV');
30 | // expect(testNode.className).to.be.equal('loginButton');
31 | // expect(testNode.getElementsByTagName('A').length).to.be.equal(1);
32 | // expect(testNode.getElementsByTagName('BUTTON')[0]).to.be.an('object');
33 | // expect(testNode.getElementsByTagName('A')[0]).to.be.an('object');
34 | // });
35 | });
36 |
--------------------------------------------------------------------------------
/src/reducers/memberReducers.js:
--------------------------------------------------------------------------------
1 | import {createReducer} from '../utils/redux-helpers.js';
2 | import getInitialState from './initialState'
3 |
4 | // export default function getInitialState() {
5 | // return {
6 | // error: null,
7 | // loading: false,
8 | // members: []
9 | // }
10 | // }
11 |
12 | // MEMBERS REDUCER
13 |
14 |
15 | const reducer = createReducer(getInitialState, {
16 | GET_MEMBERS: function(state, action) {
17 | return Object.assign({}, state, {
18 | loading: true
19 | });
20 | },
21 | GET_MEMBERS_SUCCESS: function(state, action) {
22 | return Object.assign({}, state, {
23 | loading: false,
24 | members: action.results // response JSON body is available in action.results
25 | });
26 | },
27 | CREATE_MEMBER: function(state, action) {
28 | return Object.assign({}, state, {
29 | loading: true,
30 | });
31 | },
32 | CREATE_MEMBER_SUCCESS: function(state, action) {
33 | return Object.assign({}, state, {
34 | loading: false,
35 | });
36 | },
37 | DELETE_MEMBER: function(state, action) {
38 | return Object.assign({}, state, {
39 | // loading: false, TODO: Add functionality
40 |
41 | });
42 | },
43 | });
44 |
45 | export {reducer};
46 |
--------------------------------------------------------------------------------
/test/server/Member.test.js:
--------------------------------------------------------------------------------
1 | const chai = require('chai');
2 | const chaiHttp = require('chai-http');
3 |
4 | const should = chai.should();
5 | chai.use(chaiHttp);
6 | const expect = chai.expect;
7 |
8 | describe('Member Model Relationships', function() {
9 | let member;
10 | let endpoint;
11 | let team;
12 |
13 | before(async function() {
14 | member = await Member.create({username: 'trustyPartner'});
15 | endpoint = await Endpoint.create({member: member.id});
16 | team = await Team.create({name: 'greatness'});
17 | member.teams.add(team.id);
18 | await member.save();
19 | });
20 | after(async function() {
21 | await Endpoint.destroy(endpoint.id);
22 | await Member.destroy(member.id);
23 | await Team.destroy(team.id);
24 | });
25 | it('should be able to get a list of it\'s endpoints', async function() {
26 | const members = await Member.find(member.id).populate('endpoints');
27 | expect(members[0].endpoints.length).to.be.equal(1);
28 | });
29 | it('should be able to list it\'s team memberships', async function() {
30 | const members = await Member.find(member.id).populate('teams');
31 | expect(members[0].teams.length).to.be.equal(1);
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/src/components/Todos.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | export default class Todos extends Component {
4 | render() {
5 | return (
6 |
7 | { this.renderTodos() }
8 |
);
9 | }
10 |
11 | renderTodos() {
12 | if (this.props.todos.length) {
13 | return (
14 | { this.props.todos.map((todo, index) => {
15 | let completeHandler = () => {
16 | this.props.onToggleCompleted(todo.id, !todo.completed);
17 | };
18 | let deleteHandler = () => {
19 | this.props.onDelete(todo.id);
20 | };
21 | return ();
22 | }) }
23 | );
24 | }
25 | }
26 | }
27 |
28 | class Todo extends Component {
29 | render() {
30 | const todo = this.props.todo;
31 | const decoration = todo.completed ? 'line-through' : 'none';
32 | return (
33 |
34 |
35 | { todo.name }
36 |
37 |
38 |
39 | ✓
40 |
41 |
42 |
43 | ×
44 |
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/config/locales/_README.md:
--------------------------------------------------------------------------------
1 | # Internationalization / Localization Settings
2 |
3 | > Also see the official docs on internationalization/localization:
4 | > http://links.sailsjs.org/docs/config/locales
5 |
6 | ## Locales
7 | All locale files live under `config/locales`. Here is where you can add translations
8 | as JSON key-value pairs. The name of the file should match the language that you are supporting, which allows for automatic language detection based on request headers.
9 |
10 | Here is an example locale stringfile for the Spanish language (`config/locales/es.json`):
11 | ```json
12 | {
13 | "Hello!": "Hola!",
14 | "Hello %s, how are you today?": "¿Hola %s, como estas?",
15 | }
16 | ```
17 | ## Usage
18 | Locales can be accessed in controllers/policies through `res.i18n()`, or in views through the `__(key)` or `i18n(key)` functions.
19 | Remember that the keys are case sensitive and require exact key matches, e.g.
20 |
21 | ```ejs
22 | <%= __('Welcome to PencilPals!') %>
23 | <%= i18n('Hello %s, how are you today?', 'Pencil Maven') %>
24 | <%= i18n('That\'s right-- you can use either i18n() or __()') %>
25 | ```
26 |
27 | ## Configuration
28 | Localization/internationalization config can be found in `config/i18n.js`, from where you can set your supported locales.
29 |
--------------------------------------------------------------------------------
/src/components/AddTeam.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Dialog from 'material-ui/Dialog';
3 | import RaisedButton from 'material-ui/RaisedButton';
4 | import { List, ListItem } from 'material-ui/List';
5 | import Checkbox from 'material-ui/Checkbox';
6 |
7 | export default function AddTeam({members, open, onClose, onSave, handleMemberClick}) {
8 | console.log('model members', members)
9 | const renderModel = (
10 |
11 |
12 | {members && members.map((member, i) => {
13 | return (
14 | handleMemberClick(member)}/>}
17 | primaryText={`Username: ${member.username}`}
18 | />);
19 | })}
20 |
21 |
27 |
33 |
34 | );
35 | return (
36 |
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/tasks/config/copy.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `copy`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Copy files and/or folders from your `assets/` directory into
7 | * the web root (`.tmp/public`) so they can be served via HTTP,
8 | * and also for further pre-processing by other Grunt tasks.
9 | *
10 | * #### Normal usage (`sails lift`)
11 | * Copies all directories and files (except CoffeeScript and LESS)
12 | * from the `assets/` folder into the web root -- conventionally a
13 | * hidden directory located `.tmp/public`.
14 | *
15 | * #### Via the `build` tasklist (`sails www`)
16 | * Copies all directories and files from the .tmp/public directory into a www directory.
17 | *
18 | * For usage docs see:
19 | * https://github.com/gruntjs/grunt-contrib-copy
20 | *
21 | */
22 | module.exports = function(grunt) {
23 |
24 | grunt.config.set('copy', {
25 | dev: {
26 | files: [{
27 | expand: true,
28 | cwd: './assets',
29 | src: ['**/*.!(coffee|less)'],
30 | dest: '.tmp/public'
31 | }]
32 | },
33 | build: {
34 | files: [{
35 | expand: true,
36 | cwd: '.tmp/public',
37 | src: ['**/*'],
38 | dest: 'www'
39 | }]
40 | }
41 | });
42 |
43 | grunt.loadNpmTasks('grunt-contrib-copy');
44 | };
45 |
--------------------------------------------------------------------------------
/test/server/Team.test.js:
--------------------------------------------------------------------------------
1 | const chai = require('chai');
2 | const chaiHttp = require('chai-http');
3 |
4 | const should = chai.should();
5 | chai.use(chaiHttp);
6 | const expect = chai.expect;
7 |
8 | describe('Team Model Relationships', function() {
9 | let team;
10 | let member1;
11 | let member2;
12 | let endpoint;
13 |
14 | before(async function() {
15 | team = await Team.create({name: 'greatness'});
16 | member1 = await Member.create({username: 'user1'});
17 | member2 = await Member.create({username: 'user2'});
18 | endpoint = await Endpoint.create({team: team.id});
19 |
20 | await team.members.add([member1.id, member2.id]);
21 | await team.save();
22 | });
23 | after(async function() {
24 | await Team.destroy(team.id);
25 | await Member.destroy({username: 'user1'});
26 | await Member.destroy({username: 'user2'});
27 | await Endpoint.destroy({team: team.id});
28 | });
29 | it('should be able to get a list of it\'s members', async function() {
30 | const teams = await Team.find(team.id).populate('members')
31 | expect(teams[0].members.length).to.be.equal(2);
32 | });
33 | it('should be able to list it\'s endpoints', async function() {
34 | const teams = await Team.find(team.id).populate('endpoints');
35 | expect(teams[0].endpoints.length).to.be.equal(1);
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/api/models/Endpoint.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Endpoint.js
3 | *
4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here.
5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models
6 | */
7 | var rimraf = require('rimraf');
8 | const request = require('request-promise');
9 |
10 | module.exports = {
11 |
12 | attributes: {
13 | project: {
14 | model: 'project',
15 | },
16 | member: {
17 | model: 'member',
18 | },
19 | team: {
20 | model: 'team',
21 | },
22 | },
23 |
24 | //lifecycle callbacks
25 |
26 | afterCreate: (newRecord, cb) => {
27 | let res;
28 | const resetGit = async () => {
29 | try {
30 | res = await request.post(`http://localhost:7010/reset`);
31 | cb();
32 | } catch (err) {
33 | sails.log.info('waiting for git sub system');
34 | setTimeout(() => {
35 | resetGit();
36 | }, 250);
37 | };
38 | };
39 | resetGit();
40 | },
41 |
42 | //TODO: make this work for multiple records
43 | afterDestroy: function(destroyedRecords, cb) {
44 | try {
45 | rimraf(process.env['REPO_LOCATION'] + '/' + destroyedRecords[0].id + '.git', () => {
46 | cb();
47 | });
48 | }
49 | catch (err) {
50 | cb(err);
51 | }
52 | },
53 | };
--------------------------------------------------------------------------------
/src/constants/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const GET_PROJECTS = "GET_PROJECTS";
2 | export const GET_PROJECTS_SUCCESS = "GET_PROJECTS_SUCCESS";
3 | export const GET_PROJECT = "GET_PROJECT";
4 | export const GET_PROJECT_SUCCESS = "GET_PROJECT_SUCCESS";
5 | export const CREATE_PROJECT = "CREATE_PROJECT";
6 | export const CREATE_PROJECT_SUCCESS = "CREATE_PROJECT_SUCCESS";
7 | export const DOWNLOAD_PROJECT = "DOWNLOAD_PROJECT";
8 | export const DOWNLOAD_PROJECT_SUCCESS = "DOWNLOAD_PROJECT_SUCCESS";
9 | export const PROJECTS_ERROR = "PROJECTS_ERROR";
10 | export const ADD_PROJECT = "ADD_PROJECT";
11 | export const CLOSE_PROJECT = "CLOSE_PROJECT";
12 | export const GET_TEAMS = "GET_TEAMS";
13 | export const GET_TEAMS_SUCCESS = "GET_TEAMS_SUCCESS";
14 | export const CREATE_TEAM = "CREATE_TEAM";
15 | export const CREATE_TEAM_SUCCESS = "CREATE_TEAM_SUCCESS";
16 | export const ADD_TEAM_MEMBER = "ADD_TEAM_MEMBER";
17 | export const REMOVE_TEAM_MEMBER = "REMOVE_TEAM_MEMBER";
18 | export const CLOSE_ADD_TEAM = "CLOSE_ADD_TEAM";
19 | export const TEAMS_ERROR = "TEAMS_ERROR";
20 | export const GET_MEMBERS = "GET_MEMBERS";
21 | export const GET_MEMBERS_SUCCESS = "GET_MEMBERS_SUCCESS";
22 | export const CREATE_MEMBER = "CREATE_MEMBER";
23 | export const CREATE_MEMBER_SUCCESS = "CREATE_MEMBER_SUCCESS";
24 | export const MEMBERS_ERROR = "MEMBERS_ERROR";
25 | export const DELETE_MEMBER = "DELETE_MEMBER";
26 |
--------------------------------------------------------------------------------
/src/routes/Login.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import nebulisActions from './../actions/nebulisActions';
3 | import Layout from './Layout';
4 | import RaisedButton from 'material-ui/RaisedButton';
5 | import Paper from 'material-ui/Paper';
6 | import FontIcon from 'material-ui/FontIcon';
7 | import { GithubCircleIcon } from 'mdi-material-ui';
8 |
9 | const styles = {
10 | button: {
11 | margin: 'auto',
12 | },
13 | h1: {
14 | padding: 'auto',
15 | marginTop: '47px',
16 | color: '#02C5FF'
17 | },
18 | paper: {
19 | height: 300,
20 | width: 400,
21 | margin: 'auto',
22 | marginTop: '40px',
23 | textAlign: 'center',
24 | display: 'flex',
25 | flexDirection: 'column',
26 | justifyContent: 'space-around',
27 | alignItems: 'center'
28 | }
29 | }
30 |
31 | export default class Login extends Component {
32 | render() {
33 | return (
34 |
35 |
36 | Nebulis Analytics
37 | }
44 | />
45 |
46 |
47 | );
48 | }
49 |
50 | loginFunc() {
51 | nebulisActions.login(null);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/config/log.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Built-in Log Configuration
3 | * (sails.config.log)
4 | *
5 | * Configure the log level for your app, as well as the transport
6 | * (Underneath the covers, Sails uses Winston for logging, which
7 | * allows for some pretty neat custom transports/adapters for log messages)
8 | *
9 | * For more information on the Sails logger, check out:
10 | * http://sailsjs.org/#!/documentation/concepts/Logging
11 | */
12 |
13 | module.exports.log = {
14 |
15 | /***************************************************************************
16 | * *
17 | * Valid `level` configs: i.e. the minimum log level to capture with *
18 | * sails.log.*() *
19 | * *
20 | * The order of precedence for log levels from lowest to highest is: *
21 | * silly, verbose, info, debug, warn, error *
22 | * *
23 | * You may also set the level to "silent" to suppress all logs. *
24 | * *
25 | ***************************************************************************/
26 |
27 | // level: 'info'
28 |
29 | };
30 |
--------------------------------------------------------------------------------
/src/components/ProjectListItems.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router';
3 | import { List, ListItem } from 'material-ui/List';
4 | import Avatar from 'material-ui/Avatar';
5 | import Project from './Projects';
6 | import Team from './Teams'
7 | import FileFolder from 'material-ui/svg-icons/file/folder';
8 |
9 |
10 |
11 | export default class ProjectListItems extends Component {
12 |
13 | render() {
14 | const styles = {
15 | item: {
16 | textDecoration: 'none'
17 | }
18 | }
19 |
20 | const project = this.props.project;
21 | //format timestamp
22 | let dateArr = project.updatedAt.split('T')
23 | let date = dateArr[0]
24 | let time = dateArr[1].split('.')[0]
25 | return (
26 |
27 | } />}
33 | >
34 | {/* {project.name}
*/}
35 |
36 |
37 | );
38 |
39 | }
40 | }
41 |
42 |
43 | {/*
44 |
45 |
46 |
47 |
48 |
49 | */}
50 |
--------------------------------------------------------------------------------
/test/client/Todos.test.js:
--------------------------------------------------------------------------------
1 | import chai from 'chai';
2 | const expect = chai.expect;
3 | import React, {Component} from 'react';
4 | import ReactDOM from 'react-dom';
5 | import TestUtils from 'react-addons-test-utils';
6 |
7 | import Todos from '../../src/components/Todos';
8 |
9 | const todos = [{
10 | id: 1,
11 | name: "one",
12 | completed: false
13 | }];
14 |
15 | let testComponent;
16 |
17 | before(function(done) {
18 | const onDelete = function() {};
19 | const onComplete = function() {};
20 |
21 | testComponent = TestUtils.renderIntoDocument(
22 |
23 | );
24 |
25 | done();
26 | });
27 |
28 | describe('JSDom', () => {
29 | it('loads window, document, and jQuery', () => {
30 | expect(window).to.be.an('object');
31 | expect(document).to.be.an('object');
32 | expect($).to.be.a('function');
33 | });
34 | });
35 |
36 | describe('Todos component', () => {
37 | it('renders correctly', () => {
38 |
39 | let testNode = ReactDOM.findDOMNode(testComponent);
40 |
41 | expect(testNode.nodeName).to.be.equal('DIV');
42 | expect(testNode.className).to.be.equal('todos');
43 | expect(testNode.getElementsByTagName('LI').length).to.be.equal(1);
44 | expect(testNode.getElementsByTagName('LI')[0]).to.be.an('object');
45 | expect(testNode.getElementsByTagName('SPAN')[0].textContent).to.be.equal(todos[0].name);
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/src/components/Team.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ListItem } from 'material-ui/List';
3 | import FloatingActionButton from 'material-ui/FloatingActionButton';
4 | import { DownloadIcon } from 'mdi-material-ui';
5 |
6 | export default function Team ({team, onTeamOpen, onDownload}) {
7 | // const downloadButton = (
8 | //
9 | //
10 | //
11 | // )
12 |
13 | //format timestamp
14 | let dateArr = team.updatedAt.split('T')
15 | let date = dateArr[0]
16 | let time = dateArr[1].split('.')[0]
17 |
18 | return (
19 |
33 | )
34 | }
35 |
36 |
37 |
38 | const styles = {
39 | download : {
40 | float: 'right',
41 | marginRight: 15
42 | },
43 | container: {
44 | },
45 | button: {
46 | marginRight: '20px'
47 | },
48 | listItem: {
49 | textAlign: 'center',
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/config/env/prod.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Production environment settings
3 | *
4 | * This file can include shared settings for a production environment,
5 | * such as API keys or remote database passwords. If you're using
6 | * a version control solution for your Sails app, this file will
7 | * be committed to your repository unless you add it to your .gitignore
8 | * file. If your repository will be publicly viewable, don't add
9 | * any private information to this file!
10 | *
11 | */
12 |
13 | module.exports = {
14 |
15 | /***************************************************************************
16 | * Set the default database connection for models in the production *
17 | * environment (see config/connections.js and config/models.js ) *
18 | ***************************************************************************/
19 |
20 | models: {
21 | connection: 'productionPostgresqlServer'
22 | },
23 |
24 | /***************************************************************************
25 | * Set the port in the production environment to 80 *
26 | ***************************************************************************/
27 |
28 | port: 80,
29 |
30 | /***************************************************************************
31 | * Set the log level in production environment to "silent" *
32 | ***************************************************************************/
33 |
34 | // log: {
35 | // level: "silent"
36 | // }
37 |
38 | };
39 |
--------------------------------------------------------------------------------
/api/controllers/TodosController.js:
--------------------------------------------------------------------------------
1 | var debug = require('../utils/debug');
2 |
3 | module.exports = {
4 | getTodos: function (req, res) {
5 | Todo.getAll(function (err, todos) {
6 | if (err) {
7 | res.status(500);
8 | res.send(err);
9 | }
10 | else res.send(todos);
11 | });
12 | },
13 | getTodo: function (req, res) {
14 | var id = req.params.id;
15 | Todo.findOne({id: id}, function (err, todo) {
16 | debug('getTodo '+id, todo);
17 | res.send(todo);
18 | });
19 | },
20 | createTodo: function (req, res) {
21 | debug('creating', req.body);
22 |
23 | var name = req.body.name;
24 | Todo.createTodo(name, function (err, results) {
25 | debug('created todo', results);
26 | res.send(results);
27 | });
28 | },
29 | updateTodo: function (req, res) {
30 | var id = req.params.id;
31 | var values = req.body;
32 | var s = new Date().getTime();
33 | debug('updating todo', values);
34 | Todo.update(id, values).exec(function (err, results) {
35 | debug('updated Todo ' + id, results);
36 | res.send(results);
37 | var e = new Date().getTime();
38 | });
39 | },
40 | deleteTodo: function (req, res) {
41 | var id = req.params.id;
42 | Todo.deleteTodo(id, function (err, results) {
43 | res.send(results);
44 | });
45 | },
46 | deleteAll: function (req, res) {
47 | Todo.deleteAll(function (err, results) {
48 | debug('deleteAll', results);
49 | res.send(results);
50 | });
51 | }
52 | };
53 |
--------------------------------------------------------------------------------
/src/components/Members.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router';
3 | import { List, ListItem } from 'material-ui/List';
4 | import MemberListItems from './MemberListItems';
5 |
6 | export default class Members extends Component {
7 | render() {
8 | return (
9 |
10 | { this.renderMembers() }
11 |
);
12 | }
13 |
14 | renderMembers() {
15 | if (this.props.members && this.props.members.length) {
16 | return (
17 |
18 | { this.props.members.map((member, index) => {
19 | let adminHandler = () => {
20 | this.props.makeAdmin(member.admin, !member.added);
21 | };
22 | let deleteHandler = () => {
23 | this.props.onDelete(member.id);
24 | };
25 | return ();
26 | })
27 | }
28 |
);
29 | }
30 | }
31 | }
32 | //
33 | // class Member extends Component {
34 | // render() {
35 | // const member = this.props.member;
36 | // return (
37 | //
38 | //
39 | //
40 | // Name: { member.username }
41 | //
42 | //
43 | //
44 | // ✓
45 | //
46 | //
47 | //
48 | // ×
49 | //
50 | // );
51 | // }
52 | // }
53 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { AppContainer } from 'react-hot-loader';
2 | import React from 'react';
3 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
4 | import getMuiTheme from 'material-ui/styles/getMuiTheme';
5 | import ReactDOM from 'react-dom';
6 | import {store} from './store/configureStore'
7 | import { Provider } from 'react-redux'
8 |
9 |
10 | // http://stackoverflow.com/a/34015469/988941
11 | import injectTapEventPlugin from 'react-tap-event-plugin';
12 |
13 |
14 | import App from './App';
15 |
16 | injectTapEventPlugin();
17 | const muiTheme = getMuiTheme({
18 | palette: {
19 | primary1Color: '#FF6A1A',
20 | accent1Color: '#02C5FF',
21 | // textColor: '#00BCD4',
22 | }})
23 |
24 | const rootEl = document.getElementById('app');
25 |
26 | function render() {
27 | ReactDOM.render(
28 |
29 |
30 |
31 |
32 |
33 |
34 | ,
35 | rootEl
36 | );
37 | }
38 |
39 | if (rootEl) {
40 | render();
41 | }
42 | else {
43 | console.log('no rootEl');
44 | }
45 |
46 | if (module.hot) {
47 | module.hot.accept('./App', () => {
48 | const NextApp = require('./App').default;
49 | ReactDOM.render(
50 |
51 |
52 |
53 |
54 |
55 |
56 | ,
57 | rootEl
58 | );
59 | });
60 | }
61 |
--------------------------------------------------------------------------------
/src/reducers/teamReducers.js:
--------------------------------------------------------------------------------
1 | import {createReducer} from '../utils/redux-helpers.js';
2 | import getInitialState from './initialState'
3 |
4 |
5 | // TEAMS REDUCER
6 |
7 |
8 | const reducer = createReducer(getInitialState, {
9 | GET_TEAMS: function(state, action) {
10 | return {
11 | ...state,
12 | loading: true
13 | }
14 | },
15 | GET_TEAMS_SUCCESS: function(state, action) {
16 | return {
17 | ...state,
18 | loading: false,
19 | teams: action.results
20 | }
21 | },
22 | TEAMS_ERROR: function(state, action) {
23 | return {
24 | ...state,
25 | loading: false,
26 | error: action.error
27 | }
28 | },
29 | ADD_TEAM_MEMBER: function(state, action) {
30 | const newState = {
31 | ...state,
32 | team: {
33 | ...state.team
34 | }
35 | };
36 | newState.team[action.results.id] = action.results;
37 | return newState;
38 | },
39 | REMOVE_TEAM_MEMBER: function(state, action) {
40 | const newState = {
41 | ...state,
42 | team: {
43 | ...state.team
44 | }
45 | };
46 | delete newState.team[action.results.id];
47 | return newState;
48 | },
49 | CLOSE_ADD_TEAM: function(state, action) {
50 | return {
51 | ...state,
52 | team: {}
53 | }
54 | },
55 | DOWNLOAD_PROJECT: function(state, action) {
56 | return {
57 | ...state,
58 | downloading: true
59 | }
60 | },
61 | DOWNLOAD_PROJECT_SUCCESS: function(state, action) {
62 | return {
63 | ...state,
64 | downloading:false
65 | }
66 | }
67 | });
68 |
69 | export {reducer};
70 |
--------------------------------------------------------------------------------
/test/server/Todo.test.js:
--------------------------------------------------------------------------------
1 | const chai = require('chai');
2 | const chaiHttp = require('chai-http');
3 |
4 | const should = chai.should();
5 | chai.use(chaiHttp);
6 | const expect = chai.expect;
7 |
8 | describe('.getAll()', function() {
9 | it('should return array of todos', function(done) {
10 | Todo.getAll(function(err, todos) {
11 | expect(todos).to.be.an('array');
12 | done();
13 | });
14 | });
15 | });
16 |
17 | describe('.createTodo()', function() {
18 | it('creates a todo', function(done) {
19 | Todo.createTodo(null, function(err, todo) {
20 | expect(todo).to.be.an('object');
21 | expect(todo.name).to.be.equal('null');
22 | expect(todo.completed).to.be.equal(false);
23 | Todo.getAll(function(err, todos) {
24 | expect(todos.length).to.be.above(0);
25 | done();
26 | });
27 | });
28 | });
29 | });
30 |
31 | describe('.deleteTodo()', function() {
32 | it('deletes a todo', function(done) {
33 | Todo.createTodo('test', function(err, results) {
34 | var id = results.id;
35 | Todo.deleteTodo(id, function(err, results) {
36 | expect(results).to.have.length(1);
37 | Todo.findOne({id:id}, function(err, todo) {
38 | expect(todo).to.be.equal(undefined);
39 | done();
40 | });
41 | });
42 | })
43 | });
44 | });
45 |
46 | describe('.deleteAll()', function() {
47 | it('deletes all todos', function(done) {
48 | Todo.createTodo(null, function(err, todo) {
49 | Todo.deleteAll(function(err, results) {
50 | Todo.getAll(function(err, todos) {
51 | expect(todos.length).to.be.equal(0);
52 | done();
53 | });
54 | });
55 | });
56 | });
57 | });
58 |
--------------------------------------------------------------------------------
/src/components/Projects.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router';
3 | import { List, ListItem } from 'material-ui/List';
4 | import Subheader from 'material-ui/Subheader';
5 | import ProjectListItems from './ProjectListItems';
6 | // import s from './style.scss';
7 |
8 | export default class Projects extends Component {
9 | render() {
10 | return (
11 |
12 | { this.renderProjects() }
13 |
);
14 | }
15 |
16 | renderProjects() {
17 | if (this.props.projects.length) {
18 | return (
19 |
20 | Projects
21 | { this.props.projects.map((project, index) => {
22 | return ( );
23 | })}
24 |
25 | );
26 | }
27 | }
28 | }
29 |
30 |
31 | // project completed and delete functions
32 | // let completeHandler = () => {
33 | // this.props.onToggleCompleted(project.id, !project.completed);
34 | // };
35 | // let deleteHandler = () => {
36 | // this.props.onDelete(project.id);
37 | // };
38 |
39 | // export class Project extends Component {
40 | // render() {
41 | // const project = this.props.project;
42 | // return (
43 | //
44 | //
48 | // {/*
49 | //
50 | //
51 | //
52 | //
53 | //
54 | // */}
55 | //
56 | //
57 | // );
58 | //
59 | // }
60 | // }
61 |
--------------------------------------------------------------------------------
/config/models.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Default model configuration
3 | * (sails.config.models)
4 | *
5 | * Unless you override them, the following properties will be included
6 | * in each of your models.
7 | *
8 | * For more info on Sails models, see:
9 | * http://sailsjs.org/#!/documentation/concepts/ORM
10 | */
11 |
12 |
13 |
14 | module.exports.models = {
15 |
16 | /***************************************************************************
17 | * *
18 | * Your app's default connection. i.e. the name of one of your app's *
19 | * connections (see `config/connections.js`) *
20 | * *
21 | ***************************************************************************/
22 | connection: (() => {
23 | if(process.env['NODE_ENV'] === 'test') {
24 | return 'localDiskTestingDb';
25 | } else if (process.env['NODE_ENV'] === 'dev') {
26 | return 'localDiskDb';
27 | } else return 'productionPostgresqlServer';
28 | })(),
29 |
30 | /***************************************************************************
31 | * *
32 | * How and whether Sails will attempt to automatically rebuild the *
33 | * tables/collections/etc. in your schema. *
34 | * *
35 | * See http://sailsjs.org/#!/documentation/concepts/ORM/model-settings.html *
36 | * *
37 | ***************************************************************************/
38 | migrate: 'alter'
39 |
40 | };
--------------------------------------------------------------------------------
/nebugit/messages.js:
--------------------------------------------------------------------------------
1 | import colors from 'colors';
2 | const logoText = ` .,,,,
3 | ,;;;;;;,.
4 | Nebulis Analytics ,;;;;:
5 | Code Monitoring Server :;;;,
6 | v%s :;;;
7 | .;;;.
8 | .;;; .:;;;;;;;;;;.
9 | ;;;, ;;;';. ,;;;;;
10 | ;;;. :, :;;;
11 | :;; ;;;
12 | ;;; :;;;;;; ;;;
13 | .;;;; ;;;;;;;; ;;;
14 | ;;;;;, :;;;;;, .;, :;;
15 | ;;;; :;;.
16 | .;;;;: ;;;.
17 | ;;;;; ,;;:
18 | ' ,;;;;; ';,
19 | .;;; .;;;;;;. ';
20 | ;;;;;;::,,::;;;;;;;;;:.
21 | ,:;;;;;;;;;:,.\n`;
22 |
23 | const connectionText = `🔥 Nebulis git subsystem is listening on %s:%s`.magenta;
24 | const listenerConnectionText = '🔥 Nebulis Listener is listening on http://%s:%s'.magenta;
25 |
26 | const messages = {
27 | logo: () => { console.log(logoText, '0.1.0'); },
28 | connectionInfo: (ip, port) => { console.log(connectionText, ip, port)},
29 | listenerConnectionInfo: (host, port) => {console.log(listenerConnectionText, host, port)},
30 | killed: () => { console.log(killedText); }
31 | };
32 |
33 | export { messages as default };
--------------------------------------------------------------------------------
/test/client/Projects.test.js:
--------------------------------------------------------------------------------
1 | import chai from 'chai';
2 | const expect = chai.expect;
3 | import React, {Component} from 'react';
4 | import ReactDOM from 'react-dom';
5 | import TestUtils from 'react-addons-test-utils';
6 | import { shallow } from 'enzyme';
7 | import {List, ListItem } from 'material-ui/List';
8 | import {Link} from 'react-router';
9 |
10 | import Projects from '../../src/components/Projects';
11 | import ProjectListItems from '../../src/components/ProjectListItems';
12 |
13 | const projects = [{
14 | id: 1,
15 | name: "one",
16 | updatedAt: 'Sept 2, 1990'
17 | },
18 | {
19 | id: 2,
20 | name: "two",
21 | updatedAt: 'Feb 14, 1995'
22 | }];
23 |
24 | let testComponent;
25 |
26 | before(function(done) {
27 | const onDelete = function() {};
28 | const onClick = function() {};
29 |
30 | testComponent = shallow(
31 |
32 | );
33 |
34 | done();
35 | });
36 |
37 | describe('JSDom', () => {
38 | it('should render window, document, and jQuery', () => {
39 | expect(window).to.be.an('object');
40 | expect(document).to.be.an('object');
41 | expect($).to.be.a('function');
42 | });
43 | });
44 |
45 | // describe('Project component', () => { TODO:: Fix these
46 | // it(`should render 'ProjectListItems' correctly`, () => {
47 | // testComponent = shallow()
48 | // console.log('kenny loggin', testComponent.node)
49 | // // expect(testComponent.node.props.className).to.be.equal('project');
50 | // expect(testComponent.find(Link).find(ListItem).length).to.be.equal(1);
51 | // // expect(testComponent.find(Link).find(ListItem).props.
52 | // it('should render list of all projects in db', () => {
53 | // expect(testComponent.find(div).find(Link).length).to.be.equal(1);
54 | // });
55 | // });
56 | // })
57 |
--------------------------------------------------------------------------------
/src/components/Form.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TextField from 'material-ui/TextField';
3 | import RaisedButton from 'material-ui/RaisedButton';
4 |
5 | const Form = (props) => {
6 |
7 | const cancelButton = props.cancel ? : '';
12 |
13 | const handleSubmit = (e) => {
14 | e.preventDefault();
15 | props.handleSubmit(form);
16 | }
17 |
18 | let form;
19 |
20 | return (
21 |
54 | );
55 | }
56 |
57 | const styles = {
58 | form: {
59 | display: 'flex',
60 | flexDirection: 'column',
61 | alignItems: 'center',
62 | justifyContent: 'space-around'
63 | },
64 | button: {
65 | alignSelf: 'flex-end',
66 | marginLeft: 5,
67 | marginBottom: 20,
68 | marginTop: 14
69 | },
70 | validation : {
71 | color: 'red'
72 | }
73 | }
74 |
75 | export default Form;
76 |
--------------------------------------------------------------------------------
/tasks/config/jst.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `jst`
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Precompile HTML templates using Underscore/Lodash notation into
7 | * functions, creating a `.jst` file. This can be brought into your HTML
8 | * via a
94 |
95 |