├── .gitignore
├── README.md
├── backend
├── .gitignore
├── .rspec
├── .rubocop.yml
├── Gemfile
├── Gemfile.lock
├── README.rdoc
├── Rakefile
├── app
│ ├── assets
│ │ └── images
│ │ │ └── .keep
│ ├── controllers
│ │ ├── application_controller.rb
│ │ ├── concerns
│ │ │ └── .keep
│ │ ├── sessions_controller.rb
│ │ ├── tasks_controller.rb
│ │ └── users_controller.rb
│ ├── mailers
│ │ └── .keep
│ └── models
│ │ ├── .keep
│ │ ├── concerns
│ │ └── .keep
│ │ ├── task.rb
│ │ └── user.rb
├── bin
│ ├── bundle
│ ├── rails
│ ├── rake
│ ├── setup
│ └── spring
├── config.ru
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── database.yml
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers
│ │ ├── filter_parameter_logging.rb
│ │ └── wrap_parameters.rb
│ ├── locales
│ │ └── en.yml
│ ├── routes.rb
│ └── secrets.yml
├── db
│ ├── migrate
│ │ ├── 20160323123002_create_tasks.rb
│ │ └── 20160324104001_create_users.rb
│ ├── schema.rb
│ └── seeds.rb
├── lib
│ ├── assets
│ │ └── .keep
│ └── tasks
│ │ └── .keep
├── log
│ └── .keep
├── public
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ ├── favicon.ico
│ └── robots.txt
└── spec
│ ├── controllers
│ ├── sessions_controller_spec.rb
│ ├── tasks_controller_spec.rb
│ └── users_controller_spec.rb
│ ├── factories
│ ├── tasks.rb
│ └── users.rb
│ ├── rails_helper.rb
│ ├── spec_helper.rb
│ └── support
│ ├── controller_macros.rb
│ └── request_helpers.rb
└── frontend
├── .editorconfig
├── .jshintrc
├── .stylelintrc
├── Procfile
├── README.md
├── app.js
├── gulpfile.ts
├── karma.conf.js
├── package.json
├── protractor.conf.js
├── test-main.js
├── tools
├── README.md
├── config.ts
├── config
│ ├── project.config.ts
│ ├── seed.config.interfaces.ts
│ └── seed.config.ts
├── debug.ts
├── manual_typings
│ ├── project
│ │ └── sample.package.d.ts
│ └── seed
│ │ ├── angular2-hot-loader.d.ts
│ │ ├── autoprefixer.d.ts
│ │ ├── colorguard.d.ts
│ │ ├── connect-livereload.d.ts
│ │ ├── cssnano.d.ts
│ │ ├── doiuse.d.ts
│ │ ├── istream.d.ts
│ │ ├── karma.d.ts
│ │ ├── merge-stream.d.ts
│ │ ├── open.d.ts
│ │ ├── postcss-reporter.d.ts
│ │ ├── slash.d.ts
│ │ ├── stylelint.d.ts
│ │ ├── systemjs-builder.d.ts
│ │ └── tiny-lr.d.ts
├── tasks
│ ├── project
│ │ └── sample.task.ts
│ └── seed
│ │ ├── build.assets.dev.ts
│ │ ├── build.assets.prod.ts
│ │ ├── build.bundles.app.ts
│ │ ├── build.bundles.ts
│ │ ├── build.docs.ts
│ │ ├── build.html_css.ts
│ │ ├── build.index.dev.ts
│ │ ├── build.index.prod.ts
│ │ ├── build.js.dev.ts
│ │ ├── build.js.e2e.ts
│ │ ├── build.js.prod.ts
│ │ ├── build.js.test.ts
│ │ ├── build.js.tools.ts
│ │ ├── check.versions.ts
│ │ ├── clean.all.ts
│ │ ├── clean.dev.ts
│ │ ├── clean.prod.ts
│ │ ├── clean.tools.ts
│ │ ├── copy.js.prod.ts
│ │ ├── css-lint.ts
│ │ ├── karma.start.ts
│ │ ├── serve.coverage.ts
│ │ ├── serve.docs.ts
│ │ ├── server.start.ts
│ │ ├── tslint.ts
│ │ ├── watch.dev.ts
│ │ ├── watch.e2e.ts
│ │ └── watch.test.ts
├── utils.ts
└── utils
│ ├── project.utils.ts
│ ├── project
│ └── sample_util.ts
│ ├── seed.utils.ts
│ └── seed
│ ├── clean.ts
│ ├── code_change_tools.ts
│ ├── server.ts
│ ├── tasks_tools.ts
│ ├── template_locals.ts
│ ├── tsproject.ts
│ └── watch.ts
├── tsconfig.json
├── tslint.json
├── typings.json
└── www
├── assets
├── main.css
└── svg
│ └── more.svg
├── components
├── app.ts
├── login.ts
├── navbar.ts
├── registration.ts
├── tasks.ts
└── tasks
│ ├── form.ts
│ └── list.ts
├── index.html
├── main.ts
├── models
└── task.ts
├── pipes
└── by_field.ts
├── services
├── auth.ts
└── task.ts
├── sw.js
└── templates
├── app.html
├── login.html
├── navbar.html
├── registration.html
├── tasks.html
└── tasks
├── form.html
└── list.html
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | frontend/build/Release
21 |
22 | # Dependency directory
23 | # Commenting this out is preferred by some people, see
24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
25 | frontend/node_modules/
26 | frontend/typings/
27 |
28 | # Users Environment Variables
29 | .lock-wscript
30 | .tsdrc
31 | .typingsrc
32 |
33 | #IDE configuration files
34 | .idea
35 | .vscode
36 | *.iml
37 |
38 | frontend/tools/**/*.js
39 | frontend/gulpfile.js
40 | frontend/dist
41 | frontend/dev
42 | frontend/docs
43 | frontend/lib
44 | frontend/test
45 | frontend/tmp
46 | /.bundle
47 | backend/log/*
48 | !backend/log/.keep
49 | backend/tmp
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Task manager Angular2 + rails api
2 |
3 | Setup
4 | -
5 | rake db:create
6 | rake db:migrate
7 | rails s
8 |
9 | Demo
10 | -
11 | [https://task-manager-angular2-rails.herokuapp.com](https://task-manager-angular2-rails.herokuapp.com)
12 |
--------------------------------------------------------------------------------
/backend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore all logfiles and tempfiles.
11 | /log/*
12 | !/log/.keep
13 | /tmp
14 |
--------------------------------------------------------------------------------
/backend/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 |
--------------------------------------------------------------------------------
/backend/.rubocop.yml:
--------------------------------------------------------------------------------
1 | AllCops:
2 | TargetRubyVersion: 2.3
3 | Exclude:
4 | - 'vendor/**/*'
5 | - 'db/**/*'
6 | - 'script/**/*'
7 | - 'bin/**/*'
8 | - 'log/**/*'
9 | - 'Gemfile'
10 | - 'spec/support/**/*'
11 | Metrics/LineLength:
12 | Enabled: false
13 | Style/Documentation:
14 | Enabled: false
15 | Style/ClassAndModuleChildren:
16 | Enabled: false
17 | Style/MutableConstant:
18 | Enabled: false
19 | Metrics/ParameterLists:
20 | Enabled: false
21 |
--------------------------------------------------------------------------------
/backend/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'rails', '4.2.6'
4 | gem 'rails-api'
5 | gem 'pg'
6 | gem 'active_model_serializers', github: 'rails-api/active_model_serializers'
7 | gem 'decent_exposure'
8 | gem 'rack-cors', require: 'rack/cors'
9 | gem 'bcrypt'
10 | gem 'jwt'
11 |
12 | group :development, :test do
13 | gem 'pry'
14 | gem 'spring'
15 | gem 'rubocop'
16 | gem 'rspec-rails'
17 | gem 'shoulda-matchers'
18 | gem 'rspec-collection_matchers'
19 | gem 'factory_girl_rails'
20 | gem 'database_cleaner'
21 | end
22 |
--------------------------------------------------------------------------------
/backend/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GIT
2 | remote: git://github.com/rails-api/active_model_serializers.git
3 | revision: c7b2916f37d2feadd46978ee88b568720d152da9
4 | specs:
5 | active_model_serializers (0.10.0.rc4)
6 | actionpack (>= 4.0)
7 | activemodel (>= 4.0)
8 | railties (>= 4.0)
9 |
10 | GEM
11 | remote: https://rubygems.org/
12 | specs:
13 | actionmailer (4.2.6)
14 | actionpack (= 4.2.6)
15 | actionview (= 4.2.6)
16 | activejob (= 4.2.6)
17 | mail (~> 2.5, >= 2.5.4)
18 | rails-dom-testing (~> 1.0, >= 1.0.5)
19 | actionpack (4.2.6)
20 | actionview (= 4.2.6)
21 | activesupport (= 4.2.6)
22 | rack (~> 1.6)
23 | rack-test (~> 0.6.2)
24 | rails-dom-testing (~> 1.0, >= 1.0.5)
25 | rails-html-sanitizer (~> 1.0, >= 1.0.2)
26 | actionview (4.2.6)
27 | activesupport (= 4.2.6)
28 | builder (~> 3.1)
29 | erubis (~> 2.7.0)
30 | rails-dom-testing (~> 1.0, >= 1.0.5)
31 | rails-html-sanitizer (~> 1.0, >= 1.0.2)
32 | activejob (4.2.6)
33 | activesupport (= 4.2.6)
34 | globalid (>= 0.3.0)
35 | activemodel (4.2.6)
36 | activesupport (= 4.2.6)
37 | builder (~> 3.1)
38 | activerecord (4.2.6)
39 | activemodel (= 4.2.6)
40 | activesupport (= 4.2.6)
41 | arel (~> 6.0)
42 | activesupport (4.2.6)
43 | i18n (~> 0.7)
44 | json (~> 1.7, >= 1.7.7)
45 | minitest (~> 5.1)
46 | thread_safe (~> 0.3, >= 0.3.4)
47 | tzinfo (~> 1.1)
48 | arel (6.0.3)
49 | ast (2.2.0)
50 | bcrypt (3.1.11)
51 | builder (3.2.2)
52 | coderay (1.1.1)
53 | concurrent-ruby (1.0.1)
54 | database_cleaner (1.5.1)
55 | decent_exposure (2.3.3)
56 | diff-lcs (1.2.5)
57 | erubis (2.7.0)
58 | factory_girl (4.5.0)
59 | activesupport (>= 3.0.0)
60 | factory_girl_rails (4.6.0)
61 | factory_girl (~> 4.5.0)
62 | railties (>= 3.0.0)
63 | globalid (0.3.6)
64 | activesupport (>= 4.1.0)
65 | i18n (0.7.0)
66 | json (1.8.3)
67 | jwt (1.5.4)
68 | loofah (2.0.3)
69 | nokogiri (>= 1.5.9)
70 | mail (2.6.4)
71 | mime-types (>= 1.16, < 4)
72 | method_source (0.8.2)
73 | mime-types (3.0)
74 | mime-types-data (~> 3.2015)
75 | mime-types-data (3.2016.0221)
76 | mini_portile2 (2.0.0)
77 | minitest (5.8.4)
78 | nokogiri (1.6.7.2)
79 | mini_portile2 (~> 2.0.0.rc2)
80 | parser (2.3.0.7)
81 | ast (~> 2.2)
82 | pg (0.18.4)
83 | powerpack (0.1.1)
84 | pry (0.10.3)
85 | coderay (~> 1.1.0)
86 | method_source (~> 0.8.1)
87 | slop (~> 3.4)
88 | rack (1.6.4)
89 | rack-cors (0.4.0)
90 | rack-test (0.6.3)
91 | rack (>= 1.0)
92 | rails (4.2.6)
93 | actionmailer (= 4.2.6)
94 | actionpack (= 4.2.6)
95 | actionview (= 4.2.6)
96 | activejob (= 4.2.6)
97 | activemodel (= 4.2.6)
98 | activerecord (= 4.2.6)
99 | activesupport (= 4.2.6)
100 | bundler (>= 1.3.0, < 2.0)
101 | railties (= 4.2.6)
102 | sprockets-rails
103 | rails-api (0.4.0)
104 | actionpack (>= 3.2.11)
105 | railties (>= 3.2.11)
106 | rails-deprecated_sanitizer (1.0.3)
107 | activesupport (>= 4.2.0.alpha)
108 | rails-dom-testing (1.0.7)
109 | activesupport (>= 4.2.0.beta, < 5.0)
110 | nokogiri (~> 1.6.0)
111 | rails-deprecated_sanitizer (>= 1.0.1)
112 | rails-html-sanitizer (1.0.3)
113 | loofah (~> 2.0)
114 | railties (4.2.6)
115 | actionpack (= 4.2.6)
116 | activesupport (= 4.2.6)
117 | rake (>= 0.8.7)
118 | thor (>= 0.18.1, < 2.0)
119 | rainbow (2.1.0)
120 | rake (11.1.2)
121 | rspec-collection_matchers (1.1.2)
122 | rspec-expectations (>= 2.99.0.beta1)
123 | rspec-core (3.4.4)
124 | rspec-support (~> 3.4.0)
125 | rspec-expectations (3.4.0)
126 | diff-lcs (>= 1.2.0, < 2.0)
127 | rspec-support (~> 3.4.0)
128 | rspec-mocks (3.4.1)
129 | diff-lcs (>= 1.2.0, < 2.0)
130 | rspec-support (~> 3.4.0)
131 | rspec-rails (3.4.2)
132 | actionpack (>= 3.0, < 4.3)
133 | activesupport (>= 3.0, < 4.3)
134 | railties (>= 3.0, < 4.3)
135 | rspec-core (~> 3.4.0)
136 | rspec-expectations (~> 3.4.0)
137 | rspec-mocks (~> 3.4.0)
138 | rspec-support (~> 3.4.0)
139 | rspec-support (3.4.1)
140 | rubocop (0.39.0)
141 | parser (>= 2.3.0.7, < 3.0)
142 | powerpack (~> 0.1)
143 | rainbow (>= 1.99.1, < 3.0)
144 | ruby-progressbar (~> 1.7)
145 | unicode-display_width (~> 1.0, >= 1.0.1)
146 | ruby-progressbar (1.7.5)
147 | shoulda-matchers (3.1.1)
148 | activesupport (>= 4.0.0)
149 | slop (3.6.0)
150 | spring (1.6.4)
151 | sprockets (3.5.2)
152 | concurrent-ruby (~> 1.0)
153 | rack (> 1, < 3)
154 | sprockets-rails (3.0.4)
155 | actionpack (>= 4.0)
156 | activesupport (>= 4.0)
157 | sprockets (>= 3.0.0)
158 | thor (0.19.1)
159 | thread_safe (0.3.5)
160 | tzinfo (1.2.2)
161 | thread_safe (~> 0.1)
162 | unicode-display_width (1.0.3)
163 |
164 | PLATFORMS
165 | ruby
166 |
167 | DEPENDENCIES
168 | active_model_serializers!
169 | bcrypt
170 | database_cleaner
171 | decent_exposure
172 | factory_girl_rails
173 | jwt
174 | pg
175 | pry
176 | rack-cors
177 | rails (= 4.2.6)
178 | rails-api
179 | rspec-collection_matchers
180 | rspec-rails
181 | rubocop
182 | shoulda-matchers
183 | spring
184 |
185 | BUNDLED WITH
186 | 1.11.2
187 |
--------------------------------------------------------------------------------
/backend/README.rdoc:
--------------------------------------------------------------------------------
1 | == README
2 |
3 | This README would normally document whatever steps are necessary to get the
4 | application up and running.
5 |
6 | Things you may want to cover:
7 |
8 | * Ruby version
9 |
10 | * System dependencies
11 |
12 | * Configuration
13 |
14 | * Database creation
15 |
16 | * Database initialization
17 |
18 | * How to run the test suite
19 |
20 | * Services (job queues, cache servers, search engines, etc.)
21 |
22 | * Deployment instructions
23 |
24 | * ...
25 |
26 |
27 | Please feel free to use a different markup language if you do not plan to run
28 | rake doc:app.
29 |
--------------------------------------------------------------------------------
/backend/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Add your own tasks in files placed in lib/tasks ending in .rake,
3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4 |
5 | require File.expand_path('../config/application', __FILE__)
6 |
7 | Rails.application.load_tasks
8 |
--------------------------------------------------------------------------------
/backend/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktor-shmigol/todo-angular2-rails-api/3d74693d00f320787447ed8a7dfe0b8a601e6a07/backend/app/assets/images/.keep
--------------------------------------------------------------------------------
/backend/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class ApplicationController < ActionController::API
3 | before_action :authenticate_user!
4 |
5 | decent_configuration do
6 | strategy DecentExposure::StrongParametersStrategy
7 | end
8 |
9 | expose(:current_user) do
10 | token = request.headers['Authorization'].to_s.split(' ').last
11 | User.find_by_token(token) if token
12 | end
13 |
14 | private
15 |
16 | def authenticate_user!
17 | unauthorized! unless current_user
18 | end
19 |
20 | def unauthorized!
21 | head :unauthorized
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/backend/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktor-shmigol/todo-angular2-rails-api/3d74693d00f320787447ed8a7dfe0b8a601e6a07/backend/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/backend/app/controllers/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class SessionsController < ApplicationController
3 | skip_before_action :authenticate_user!
4 | expose(:user) { User.find_by_email(params[:email]) }
5 |
6 | def create
7 | return render json: { token: user.authenticate! }, status: :ok if user && user.authenticate(params[:password])
8 | render json: { message: 'Invalid email or password.' }, status: 422
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/backend/app/controllers/tasks_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class TasksController < ApplicationController
3 | expose(:task)
4 | expose(:tasks) { current_user.tasks.order(created_at: :desc) }
5 |
6 | def index
7 | render json: tasks, status: :ok
8 | end
9 |
10 | def create
11 | return render json: task, status: :created if task.update(task_params)
12 | render json: { errors: task.errors.full_messages }, status: 422
13 | end
14 |
15 | def destroy
16 | task.destroy
17 | head(204)
18 | end
19 |
20 | alias update create
21 |
22 | private
23 |
24 | def task_params
25 | params.require(:task).permit(:name, :description, :done).merge(user_id: current_user.id)
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/backend/app/controllers/users_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class UsersController < ApplicationController
3 | skip_before_action :authenticate_user!, only: :create
4 | expose(:user)
5 |
6 | def create
7 | return render json: { token: user.authenticate! }, status: :created if user.update(user_params)
8 | render json: { status: :error, errors: user.errors.messages }, status: 422
9 | end
10 |
11 | private
12 |
13 | def user_params
14 | params.require(:user).permit(:email, :token, :password, :password_confirmation)
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/backend/app/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktor-shmigol/todo-angular2-rails-api/3d74693d00f320787447ed8a7dfe0b8a601e6a07/backend/app/mailers/.keep
--------------------------------------------------------------------------------
/backend/app/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktor-shmigol/todo-angular2-rails-api/3d74693d00f320787447ed8a7dfe0b8a601e6a07/backend/app/models/.keep
--------------------------------------------------------------------------------
/backend/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktor-shmigol/todo-angular2-rails-api/3d74693d00f320787447ed8a7dfe0b8a601e6a07/backend/app/models/concerns/.keep
--------------------------------------------------------------------------------
/backend/app/models/task.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class Task < ActiveRecord::Base
3 | belongs_to :user
4 | validates :name, :description, presence: true
5 | end
6 |
--------------------------------------------------------------------------------
/backend/app/models/user.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class User < ActiveRecord::Base
3 | has_secure_password
4 |
5 | has_many :tasks, dependent: :delete_all
6 |
7 | validates :password, :password_confirmation, presence: true, confirmation: true, length: { minimum: 8 }, on: :create
8 | validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }, uniqueness: true
9 |
10 | def authenticate!
11 | payload = { data: id }
12 | token = JWT.encode payload, Rails.application.secrets['secret_key_base'], 'HS256'
13 | update_attribute(:token, token)
14 | token
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/backend/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/backend/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | APP_PATH = File.expand_path('../../config/application', __FILE__)
8 | require_relative '../config/boot'
9 | require 'rails/commands'
10 |
--------------------------------------------------------------------------------
/backend/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require_relative '../config/boot'
8 | require 'rake'
9 | Rake.application.run
10 |
--------------------------------------------------------------------------------
/backend/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 |
4 | # path to your application root.
5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6 |
7 | Dir.chdir APP_ROOT do
8 | # This script is a starting point to setup your application.
9 | # Add necessary setup steps to this file:
10 |
11 | puts '== Installing dependencies =='
12 | system 'gem install bundler --conservative'
13 | system 'bundle check || bundle install'
14 |
15 | # puts "\n== Copying sample files =="
16 | # unless File.exist?("config/database.yml")
17 | # system "cp config/database.yml.sample config/database.yml"
18 | # end
19 |
20 | puts "\n== Preparing database =="
21 | system 'bin/rake db:setup'
22 |
23 | puts "\n== Removing old logs and tempfiles =="
24 | system 'rm -f log/*'
25 | system 'rm -rf tmp/cache'
26 |
27 | puts "\n== Restarting application server =="
28 | system 'touch tmp/restart.txt'
29 | end
30 |
--------------------------------------------------------------------------------
/backend/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m))
11 | Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) }
12 | gem 'spring', match[1]
13 | require 'spring/binstub'
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/backend/config.ru:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # This file is used by Rack-based servers to start the application.
3 |
4 | require ::File.expand_path('../config/environment', __FILE__)
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/backend/config/application.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require File.expand_path('../boot', __FILE__)
3 |
4 | require 'rails'
5 | # Pick the frameworks you want:
6 | require 'active_model/railtie'
7 | require 'active_job/railtie'
8 | require 'active_record/railtie'
9 | require 'action_controller/railtie'
10 | require 'action_mailer/railtie'
11 | require 'action_view/railtie'
12 | require 'sprockets/railtie'
13 | # require "rails/test_unit/railtie"
14 |
15 | # Require the gems listed in Gemfile, including any gems
16 | # you've limited to :test, :development, or :production.
17 | Bundler.require(*Rails.groups)
18 |
19 | module TaskManager
20 | class Application < Rails::Application
21 | # Settings in config/environments/* take precedence over those specified here.
22 | # Application configuration should go into files in config/initializers
23 | # -- all .rb files in that directory are automatically loaded.
24 |
25 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
26 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
27 | # config.time_zone = 'Central Time (US & Canada)'
28 |
29 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
30 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
31 | # config.i18n.default_locale = :de
32 |
33 | # Do not swallow errors in after_commit/after_rollback callbacks.
34 | config.active_record.raise_in_transactional_callbacks = true
35 |
36 | config.middleware.use Rack::Cors do
37 | allow do
38 | origins '*'
39 | resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head]
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/backend/config/boot.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 |
4 | require 'bundler/setup' # Set up gems listed in the Gemfile.
5 |
--------------------------------------------------------------------------------
/backend/config/database.yml:
--------------------------------------------------------------------------------
1 | default: &default
2 | adapter: postgresql
3 | encoding: unicode
4 | host: localhost
5 | pool: 5
6 | username: postgres
7 | password:
8 |
9 | development:
10 | <<: *default
11 | database: task_manager_development
12 |
13 | test:
14 | <<: *default
15 | database: task_manager_test
16 |
--------------------------------------------------------------------------------
/backend/config/environment.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Load the Rails application.
3 | require File.expand_path('../application', __FILE__)
4 |
5 | # Initialize the Rails application.
6 | Rails.application.initialize!
7 |
--------------------------------------------------------------------------------
/backend/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | Rails.application.configure do
3 | # Settings specified here will take precedence over those in config/application.rb.
4 |
5 | # In the development environment your application's code is reloaded on
6 | # every request. This slows down response time but is perfect for development
7 | # since you don't have to restart the web server when you make code changes.
8 | config.cache_classes = false
9 |
10 | # Do not eager load code on boot.
11 | config.eager_load = false
12 |
13 | # Show full error reports and disable caching.
14 | config.consider_all_requests_local = true
15 | config.action_controller.perform_caching = false
16 |
17 | # Don't care if the mailer can't send.
18 | config.action_mailer.raise_delivery_errors = false
19 |
20 | # Print deprecation notices to the Rails logger.
21 | config.active_support.deprecation = :log
22 |
23 | # Raise an error on page load if there are pending migrations.
24 | config.active_record.migration_error = :page_load
25 |
26 | # Debug mode disables concatenation and preprocessing of assets.
27 | # This option may cause significant delays in view rendering with a large
28 | # number of complex assets.
29 | config.assets.debug = true
30 |
31 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
32 | # yet still be able to expire them through the digest params.
33 | config.assets.digest = true
34 |
35 | # Adds additional error checking when serving assets at runtime.
36 | # Checks for improperly declared sprockets dependencies.
37 | # Raises helpful error messages.
38 | config.assets.raise_runtime_errors = true
39 |
40 | # Raises error for missing translations
41 | # config.action_view.raise_on_missing_translations = true
42 | end
43 |
--------------------------------------------------------------------------------
/backend/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | Rails.application.configure do
3 | # Settings specified here will take precedence over those in config/application.rb.
4 |
5 | # Code is not reloaded between requests.
6 | config.cache_classes = true
7 |
8 | # Eager load code on boot. This eager loads most of Rails and
9 | # your application in memory, allowing both threaded web servers
10 | # and those relying on copy on write to perform better.
11 | # Rake tasks automatically ignore this option for performance.
12 | config.eager_load = true
13 |
14 | # Full error reports are disabled and caching is turned on.
15 | config.consider_all_requests_local = false
16 | config.action_controller.perform_caching = true
17 |
18 | # Enable Rack::Cache to put a simple HTTP cache in front of your application
19 | # Add `rack-cache` to your Gemfile before enabling this.
20 | # For large-scale production use, consider using a caching reverse proxy like
21 | # NGINX, varnish or squid.
22 | # config.action_dispatch.rack_cache = true
23 |
24 | # Disable serving static files from the `/public` folder by default since
25 | # Apache or NGINX already handles this.
26 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
27 |
28 | # Compress JavaScripts and CSS.
29 | config.assets.js_compressor = :uglifier
30 | # config.assets.css_compressor = :sass
31 |
32 | # Do not fallback to assets pipeline if a precompiled asset is missed.
33 | config.assets.compile = false
34 |
35 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
36 | # yet still be able to expire them through the digest params.
37 | config.assets.digest = true
38 |
39 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
40 |
41 | # Specifies the header that your server uses for sending files.
42 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
43 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
44 |
45 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
46 | # config.force_ssl = true
47 |
48 | # Use the lowest log level to ensure availability of diagnostic information
49 | # when problems arise.
50 | config.log_level = :debug
51 |
52 | # Prepend all log lines with the following tags.
53 | # config.log_tags = [ :subdomain, :uuid ]
54 |
55 | # Use a different logger for distributed setups.
56 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
57 |
58 | # Use a different cache store in production.
59 | # config.cache_store = :mem_cache_store
60 |
61 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
62 | # config.action_controller.asset_host = 'http://assets.example.com'
63 |
64 | # Ignore bad email addresses and do not raise email delivery errors.
65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
66 | # config.action_mailer.raise_delivery_errors = false
67 |
68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
69 | # the I18n.default_locale when a translation cannot be found).
70 | config.i18n.fallbacks = true
71 |
72 | # Send deprecation notices to registered listeners.
73 | config.active_support.deprecation = :notify
74 |
75 | # Use default logging formatter so that PID and timestamp are not suppressed.
76 | config.log_formatter = ::Logger::Formatter.new
77 |
78 | # Do not dump schema after migrations.
79 | config.active_record.dump_schema_after_migration = false
80 | end
81 |
--------------------------------------------------------------------------------
/backend/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | Rails.application.configure do
3 | # Settings specified here will take precedence over those in config/application.rb.
4 |
5 | # The test environment is used exclusively to run your application's
6 | # test suite. You never need to work with it otherwise. Remember that
7 | # your test database is "scratch space" for the test suite and is wiped
8 | # and recreated between test runs. Don't rely on the data there!
9 | config.cache_classes = true
10 |
11 | # Do not eager load code on boot. This avoids loading your whole application
12 | # just for the purpose of running a single test. If you are using a tool that
13 | # preloads Rails for running tests, you may have to set it to true.
14 | config.eager_load = false
15 |
16 | # Configure static file server for tests with Cache-Control for performance.
17 | config.serve_static_files = true
18 | config.static_cache_control = 'public, max-age=3600'
19 |
20 | # Show full error reports and disable caching.
21 | config.consider_all_requests_local = true
22 | config.action_controller.perform_caching = false
23 |
24 | # Raise exceptions instead of rendering exception templates.
25 | config.action_dispatch.show_exceptions = false
26 |
27 | # Disable request forgery protection in test environment.
28 | config.action_controller.allow_forgery_protection = false
29 |
30 | # Tell Action Mailer not to deliver emails to the real world.
31 | # The :test delivery method accumulates sent emails in the
32 | # ActionMailer::Base.deliveries array.
33 | config.action_mailer.delivery_method = :test
34 |
35 | # Randomize the order test cases are executed.
36 | config.active_support.test_order = :random
37 |
38 | # Print deprecation notices to the stderr.
39 | config.active_support.deprecation = :stderr
40 |
41 | # Raises error for missing translations
42 | # config.action_view.raise_on_missing_translations = true
43 | end
44 |
--------------------------------------------------------------------------------
/backend/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # Configure sensitive parameters which will be filtered from the log file.
5 | Rails.application.config.filter_parameters += [:password]
6 |
--------------------------------------------------------------------------------
/backend/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 | #
4 | # This file contains settings for ActionController::ParamsWrapper
5 |
6 | # Enable parameter wrapping for JSON.
7 | # ActiveSupport.on_load(:action_controller) do
8 | # wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9 | # end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/backend/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
--------------------------------------------------------------------------------
/backend/config/routes.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | Rails.application.routes.draw do
3 | scope 'api' do
4 | resources :users, only: :create
5 | resources :sessions, only: :create
6 | resources :tasks
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/backend/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | development:
14 | secret_key_base: 52f35482b90081d2ac3f343ff24022e0e3340e4dedd05432707e1cefd2334dace3eca82c51bc15b2ba52135c1544a798cef9103ff738d597eae8f004715439ff
15 |
16 | test:
17 | secret_key_base: e44b4f77b1dc25463d9eaaba16f024cc811b9a5ccd9fe4600ce932fb225dfcaf795e0ff224f86bd07cfc6e687254017f4297e55a88a29bcde4dde19e1a9d7235
18 |
19 | # Do not keep production secrets in the repository,
20 | # instead read values from the environment.
21 | production:
22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
23 |
--------------------------------------------------------------------------------
/backend/db/migrate/20160323123002_create_tasks.rb:
--------------------------------------------------------------------------------
1 | class CreateTasks < ActiveRecord::Migration
2 | def change
3 | create_table :tasks do |t|
4 | t.string :name
5 | t.string :description
6 | t.boolean :done, default: false
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/backend/db/migrate/20160324104001_create_users.rb:
--------------------------------------------------------------------------------
1 | class CreateUsers < ActiveRecord::Migration
2 | def change
3 | create_table :users do |t|
4 | t.string :email
5 | t.string :token
6 | t.string :password_digest
7 |
8 | t.timestamps null: false
9 | end
10 | add_reference :tasks, :user, index: true
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/backend/db/schema.rb:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | # This file is auto-generated from the current state of the database. Instead
3 | # of editing this file, please use the migrations feature of Active Record to
4 | # incrementally modify your database, and then regenerate this schema definition.
5 | #
6 | # Note that this schema.rb definition is the authoritative source for your
7 | # database schema. If you need to create the application database on another
8 | # system, you should be using db:schema:load, not running all the migrations
9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 | # you'll amass, the slower it'll run and the greater likelihood for issues).
11 | #
12 | # It's strongly recommended that you check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(version: 20160324104001) do
15 |
16 | # These are extensions that must be enabled in order to support this database
17 | enable_extension "plpgsql"
18 |
19 | create_table "tasks", force: :cascade do |t|
20 | t.string "name"
21 | t.string "description"
22 | t.boolean "done", default: false
23 | t.datetime "created_at"
24 | t.datetime "updated_at"
25 | t.integer "user_id"
26 | end
27 |
28 | add_index "tasks", ["user_id"], name: "index_tasks_on_user_id", using: :btree
29 |
30 | create_table "users", force: :cascade do |t|
31 | t.string "email"
32 | t.string "token"
33 | t.string "password_digest"
34 | t.datetime "created_at", null: false
35 | t.datetime "updated_at", null: false
36 | end
37 |
38 | end
39 |
--------------------------------------------------------------------------------
/backend/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
7 | # Mayor.create(name: 'Emanuel', city: cities.first)
8 |
--------------------------------------------------------------------------------
/backend/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktor-shmigol/todo-angular2-rails-api/3d74693d00f320787447ed8a7dfe0b8a601e6a07/backend/lib/assets/.keep
--------------------------------------------------------------------------------
/backend/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktor-shmigol/todo-angular2-rails-api/3d74693d00f320787447ed8a7dfe0b8a601e6a07/backend/lib/tasks/.keep
--------------------------------------------------------------------------------
/backend/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktor-shmigol/todo-angular2-rails-api/3d74693d00f320787447ed8a7dfe0b8a601e6a07/backend/log/.keep
--------------------------------------------------------------------------------
/backend/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/backend/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/backend/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/backend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktor-shmigol/todo-angular2-rails-api/3d74693d00f320787447ed8a7dfe0b8a601e6a07/backend/public/favicon.ico
--------------------------------------------------------------------------------
/backend/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/backend/spec/controllers/sessions_controller_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'rails_helper'
3 |
4 | RSpec.describe SessionsController, type: :controller do
5 | let(:user) { create(:user) }
6 |
7 | context '#create' do
8 | it 'create sessions' do
9 | post :create, email: user.email, password: user.password, format: :json
10 | expect(response).to be_success
11 | expect(json['token']).to_not be_nil
12 | end
13 |
14 | it 'not create session' do
15 | post :create, email: '', format: :json
16 | expect(json['errors']).to be_nil
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/backend/spec/controllers/tasks_controller_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'rails_helper'
3 |
4 | RSpec.describe TasksController, type: :controller do
5 | let!(:user) { create(:user) }
6 | let!(:task) { create(:task, user: user) }
7 | let(:task_atributes) { attributes_for(:task) }
8 | let(:task_invalid_atributes) { attributes_for(:task, name: '') }
9 |
10 | before(:each) do
11 | allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user)
12 | end
13 |
14 | context '#index' do
15 | it do
16 | get :index
17 | expect(response).to be_success
18 | end
19 | end
20 |
21 | context '#create' do
22 | it 'create task' do
23 | expect { post :create, task: task_atributes }.to change(Task, :count).by(1)
24 | end
25 |
26 | it 'not create task' do
27 | expect { post :create, task: task_invalid_atributes }.to_not change(Task, :count)
28 | end
29 | end
30 |
31 | context '#update' do
32 | it 'update task' do
33 | put :update, id: task.id, task: { name: 'test' }
34 | expect(json['name']).to eq 'test'
35 | end
36 | end
37 |
38 | context '#destroy' do
39 | it do
40 | expect { delete :destroy, id: task.id }.to change(Task, :count).by(-1)
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/backend/spec/controllers/users_controller_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'rails_helper'
3 |
4 | RSpec.describe UsersController, type: :controller do
5 | let!(:user) { create(:user) }
6 | let(:user_atributes) { attributes_for(:user) }
7 | let(:user_invalid_atributes) { attributes_for(:user, email: '') }
8 |
9 | context '#create' do
10 | it 'create user' do
11 | expect { post :create, user: user_atributes, format: :json }.to change(User, :count).by(1)
12 | expect(json['token']).to_not be_nil
13 | end
14 |
15 | it 'not create user' do
16 | expect { post :create, user: user_invalid_atributes, format: :json }.to_not change(User, :count)
17 | expect(json['errors']).to_not be_nil
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/backend/spec/factories/tasks.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | FactoryGirl.define do
3 | factory :task do
4 | sequence(:name) { |n| "task#{n}" }
5 | description 'description'
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/backend/spec/factories/users.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | FactoryGirl.define do
3 | factory :user do
4 | sequence(:email) { |n| "person#{n}@example.com" }
5 | password 'password'
6 | password_confirmation 'password'
7 | token SecureRandom.urlsafe_base64(nil, false)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/backend/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | ENV['RAILS_ENV'] ||= 'test'
3 | require File.expand_path('../../config/environment', __FILE__)
4 | abort('The Rails environment is running in production mode!') if Rails.env.production?
5 | require 'spec_helper'
6 | require 'rspec/rails'
7 | require 'database_cleaner'
8 | require 'rspec/collection_matchers'
9 |
10 | ActiveRecord::Migration.maintain_test_schema!
11 |
12 | RSpec.configure do |config|
13 | Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
14 | config.fixture_path = "#{::Rails.root}/spec/fixtures"
15 | config.include FactoryGirl::Syntax::Methods
16 | config.extend ControllerMacros, type: :controller
17 | config.include Requests::JsonHelpers, type: :controller
18 | config.use_transactional_fixtures = true
19 | config.infer_spec_type_from_file_location!
20 | config.filter_rails_from_backtrace!
21 |
22 | config.before(:suite) do
23 | DatabaseCleaner.clean_with(:truncation)
24 | end
25 |
26 | config.before(:each) do
27 | DatabaseCleaner.strategy = :transaction
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/backend/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | RSpec.configure do |config|
3 | config.expect_with :rspec do |expectations|
4 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
5 | end
6 |
7 | config.mock_with :rspec do |mocks|
8 | mocks.verify_partial_doubles = true
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/backend/spec/support/controller_macros.rb:
--------------------------------------------------------------------------------
1 | module ControllerMacros
2 | def login_as_user
3 | before(:each) do
4 | @user = create(:user)
5 | allow_any_instance_of(V1::BaseController).to receive(:current_user).and_return(@user)
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/backend/spec/support/request_helpers.rb:
--------------------------------------------------------------------------------
1 | module Requests
2 | module JsonHelpers
3 | def json
4 | @json ||= JSON.parse(response.body)
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/frontend/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | insert_final_newline = false
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/frontend/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "bitwise": true,
3 | "camelcase": true,
4 | "curly": true,
5 | "eqeqeq": true,
6 | "es3": false,
7 | "forin": true,
8 | "freeze": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": "nofunc",
12 | "newcap": true,
13 | "noarg": true,
14 | "noempty": true,
15 | "nonbsp": true,
16 | "nonew": true,
17 | "plusplus": false,
18 | "quotmark": "single",
19 | "undef": true,
20 | "unused": false,
21 | "strict": false,
22 | "maxparams": 10,
23 | "maxdepth": 5,
24 | "maxstatements": 40,
25 | "maxcomplexity": 8,
26 | "maxlen": 140,
27 |
28 | "asi": false,
29 | "boss": false,
30 | "debug": false,
31 | "eqnull": true,
32 | "esnext": false,
33 | "evil": false,
34 | "expr": false,
35 | "funcscope": false,
36 | "globalstrict": false,
37 | "iterator": false,
38 | "lastsemic": false,
39 | "laxbreak": false,
40 | "laxcomma": false,
41 | "loopfunc": true,
42 | "maxerr": false,
43 | "moz": false,
44 | "multistr": false,
45 | "notypeof": false,
46 | "proto": false,
47 | "scripturl": false,
48 | "shadow": false,
49 | "sub": true,
50 | "supernew": false,
51 | "validthis": false,
52 | "noyield": false,
53 |
54 | "browser": true,
55 | "node": true,
56 |
57 | "globals": {
58 | "angular": false,
59 | "ng": false
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/frontend/.stylelintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "stylelint-config-standard",
3 | "rules": {
4 | "block-no-empty": null,
5 | "at-rule-empty-line-before": null,
6 | "rule-non-nested-empty-line-before": null
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/frontend/Procfile:
--------------------------------------------------------------------------------
1 | web: node app.js
2 |
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 | npm install
2 | npm start
3 |
--------------------------------------------------------------------------------
/frontend/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 | var request = require('request');
4 |
5 | app.use('/api', function(req, res) {
6 | var url = 'https://task-manager-api.herokuapp.com/api/' + req.url;
7 | req.pipe(request(url)).pipe(res);
8 | });
9 | app.use(express.static(__dirname + '/dist/prod'));
10 | app.get('/*', function(req, res){
11 | res.sendFile(__dirname + '/dist/prod/index.html');
12 | });
13 | app.listen(process.env.PORT || 3000);
14 |
--------------------------------------------------------------------------------
/frontend/gulpfile.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as runSequence from 'run-sequence';
3 | import {loadTasks} from './tools/utils';
4 | import {SEED_TASKS_DIR, PROJECT_TASKS_DIR} from './tools/config';
5 |
6 | loadTasks(SEED_TASKS_DIR);
7 | loadTasks(PROJECT_TASKS_DIR);
8 |
9 |
10 | // --------------
11 | // Build dev.
12 | gulp.task('build.dev', (done: any) =>
13 | runSequence('clean.dev',
14 | 'tslint',
15 | 'css-lint',
16 | 'build.assets.dev',
17 | 'build.html_css',
18 | 'build.js.dev',
19 | 'build.index.dev',
20 | done));
21 |
22 | // --------------
23 | // Build dev watch.
24 | gulp.task('build.dev.watch', (done: any) =>
25 | runSequence('build.dev',
26 | 'watch.dev',
27 | done));
28 |
29 | // --------------
30 | // Build e2e.
31 | gulp.task('build.e2e', (done: any) =>
32 | runSequence('clean.dev',
33 | 'tslint',
34 | 'build.assets.dev',
35 | 'build.js.e2e',
36 | 'build.index.dev',
37 | done));
38 |
39 | // --------------
40 | // Build prod.
41 | gulp.task('build.prod', (done: any) =>
42 | runSequence('clean.prod',
43 | 'tslint',
44 | 'css-lint',
45 | 'build.assets.prod',
46 | 'build.html_css',
47 | 'copy.js.prod',
48 | 'build.js.prod',
49 | 'build.bundles',
50 | 'build.bundles.app',
51 | 'build.index.prod',
52 | done));
53 |
54 | // --------------
55 | // Build test.
56 | gulp.task('build.test', (done: any) =>
57 | runSequence('clean.dev',
58 | 'tslint',
59 | 'build.assets.dev',
60 | 'build.js.test',
61 | 'build.index.dev',
62 | done));
63 |
64 | // --------------
65 | // Build test watch.
66 | gulp.task('build.test.watch', (done: any) =>
67 | runSequence('build.test',
68 | 'watch.test',
69 | done));
70 |
71 | // --------------
72 | // Build tools.
73 | gulp.task('build.tools', (done: any) =>
74 | runSequence('clean.tools',
75 | 'build.js.tools',
76 | done));
77 |
78 | // --------------
79 | // Docs
80 | gulp.task('docs', (done: any) =>
81 | runSequence('build.docs',
82 | 'serve.docs',
83 | done));
84 |
85 | // --------------
86 | // Serve dev
87 | gulp.task('serve.dev', (done: any) =>
88 | runSequence('build.dev',
89 | 'server.start',
90 | 'watch.dev',
91 | done));
92 |
93 | // --------------
94 | // Serve e2e
95 | gulp.task('serve.e2e', (done: any) =>
96 | runSequence('build.e2e',
97 | 'server.start',
98 | 'watch.e2e',
99 | done));
100 |
101 | // --------------
102 | // Test.
103 | gulp.task('test', (done: any) =>
104 | runSequence('build.test',
105 | 'karma.start',
106 | done));
107 |
--------------------------------------------------------------------------------
/frontend/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Wed Jul 15 2015 09:44:02 GMT+0200 (Romance Daylight Time)
3 | 'use strict';
4 |
5 | var argv = require('yargs').argv;
6 |
7 | module.exports = function(config) {
8 | config.set({
9 |
10 | // base path that will be used to resolve all patterns (eg. files, exclude)
11 | basePath: './',
12 |
13 |
14 | // frameworks to use
15 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
16 | frameworks: ['jasmine'],
17 |
18 |
19 | // list of files / patterns to load in the browser
20 | files: [
21 | 'node_modules/zone.js/dist/zone-microtask.js',
22 | 'node_modules/zone.js/dist/long-stack-trace-zone.js',
23 | 'node_modules/zone.js/dist/jasmine-patch.js',
24 | 'node_modules/es6-module-loader/dist/es6-module-loader.js',
25 | 'node_modules/traceur/bin/traceur-runtime.js', // Required by PhantomJS2, otherwise it shouts ReferenceError: Can't find variable: require
26 | 'node_modules/traceur/bin/traceur.js',
27 | 'node_modules/systemjs/dist/system.src.js',
28 | 'node_modules/reflect-metadata/Reflect.js',
29 | // beta.7 IE 11 polyfills from https://github.com/angular/angular/issues/7144
30 | 'node_modules/angular2/es6/dev/src/testing/shims_for_IE.js',
31 |
32 | { pattern: 'node_modules/angular2/**/*.js', included: false, watched: false },
33 | { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
34 | { pattern: 'dist/dev/**/*.js', included: false, watched: true },
35 | { pattern: 'node_modules/systemjs/dist/system-polyfills.js', included: false, watched: false }, // PhantomJS2 (and possibly others) might require it
36 |
37 | 'test-main.js'
38 | ],
39 |
40 |
41 | // list of files to exclude
42 | exclude: [
43 | 'node_modules/angular2/**/*spec.js'
44 | ],
45 |
46 |
47 | // preprocess matching files before serving them to the browser
48 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
49 | preprocessors: {
50 | 'dist/**/!(*spec).js': ['coverage']
51 | },
52 |
53 | // test results reporter to use
54 | // possible values: 'dots', 'progress'
55 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
56 | reporters: ['mocha', 'coverage'],
57 |
58 |
59 | // web server port
60 | port: 9876,
61 |
62 |
63 | // enable / disable colors in the output (reporters and logs)
64 | colors: true,
65 |
66 |
67 | // level of logging
68 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
69 | logLevel: config.LOG_INFO,
70 |
71 |
72 | // enable / disable watching file and executing tests whenever any file changes
73 | autoWatch: true,
74 |
75 |
76 | // start these browsers
77 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
78 | browsers: [
79 | 'PhantomJS',
80 | 'Chrome'
81 | ],
82 |
83 |
84 | customLaunchers: {
85 | Chrome_travis_ci: {
86 | base: 'Chrome',
87 | flags: ['--no-sandbox']
88 | }
89 | },
90 |
91 | coverageReporter: {
92 | dir: 'coverage/',
93 | reporters: [
94 | { type: 'text-summary' },
95 | { type: 'json', subdir: '.', file: 'coverage-final.json' },
96 | { type: 'html' }
97 | ]
98 | },
99 |
100 | // Continuous Integration mode
101 | // if true, Karma captures browsers, runs the tests and exits
102 | singleRun: false,
103 |
104 | // Passing command line arguments to tests
105 | client: {
106 | files: argv.files
107 | }
108 | });
109 |
110 | if (process.env.APPVEYOR) {
111 | config.browsers = ['IE'];
112 | config.singleRun = true;
113 | config.browserNoActivityTimeout = 90000; // Note: default value (10000) is not enough
114 | }
115 |
116 | if (process.env.TRAVIS || process.env.CIRCLECI) {
117 | config.browsers = ['Chrome_travis_ci'];
118 | config.singleRun = true;
119 | }
120 | };
121 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular2-seed",
3 | "version": "0.0.0",
4 | "description": "Seed for Angular 2 apps",
5 | "repository": {
6 | "url": "https://github.com/mgechev/angular2-seed"
7 | },
8 | "scripts": {
9 | "build.dev": "gulp build.dev",
10 | "build.dev.watch": "gulp build.dev.watch",
11 | "build.e2e": "gulp build.e2e",
12 | "build.prod": "gulp build.prod",
13 | "build.test": "gulp build.test",
14 | "build.test.watch": "gulp build.test.watch",
15 | "docs": "npm run gulp -- build.docs && npm run gulp -- serve.docs",
16 | "e2e": "protractor",
17 | "e2e.live": "protractor --elementExplorer",
18 | "gulp": "gulp",
19 | "karma": "karma",
20 | "karma.start": "karma start",
21 | "postinstall": "typings install && gulp check.versions && npm prune",
22 | "reinstall": "npm cache clean && npm install",
23 | "serve.coverage": "remap-istanbul -b src/ -i coverage/coverage-final.json -o coverage -t html && npm run gulp -- serve.coverage",
24 | "serve.dev": "gulp serve.dev",
25 | "serve.e2e": "gulp serve.e2e",
26 | "start": "gulp serve.dev",
27 | "tasks.list": "gulp --tasks-simple",
28 | "test": "gulp test",
29 | "webdriver-start": "webdriver-manager start",
30 | "webdriver-update": "webdriver-manager update"
31 | },
32 | "author": "Minko Gechev ",
33 | "license": "MIT",
34 | "devDependencies": {
35 | "async": "^1.4.2",
36 | "autoprefixer": "^6.3.3",
37 | "browser-sync": "~2.10.1",
38 | "chalk": "^1.1.1",
39 | "colorguard": "^1.0.1",
40 | "connect": "^3.4.1",
41 | "connect-history-api-fallback": "^1.1.0",
42 | "connect-livereload": "^0.5.3",
43 | "cssnano": "^3.5.2",
44 | "doiuse": "^2.3.0",
45 | "event-stream": "^3.3.2",
46 | "express": "~4.13.1",
47 | "extend": "^3.0.0",
48 | "gulp": "^3.9.1",
49 | "gulp-cached": "^1.1.0",
50 | "gulp-concat": "^2.6.0",
51 | "gulp-filter": "^4.0.0",
52 | "gulp-inject": "^4.0.0",
53 | "gulp-inline-ng2-template": "^1.1.2",
54 | "gulp-load-plugins": "^1.2.0",
55 | "gulp-plumber": "~1.1.0",
56 | "gulp-postcss": "^6.1.0",
57 | "gulp-shell": "~0.5.2",
58 | "gulp-sourcemaps": "git+https://github.com/floridoo/gulp-sourcemaps.git#master",
59 | "gulp-template": "^3.1.0",
60 | "gulp-tslint": "^4.3.3",
61 | "gulp-tslint-stylish": "^1.1.1",
62 | "gulp-typedoc": "^1.2.1",
63 | "gulp-typescript": "~2.12.1",
64 | "gulp-uglify": "^1.5.3",
65 | "gulp-util": "^3.0.7",
66 | "gulp-watch": "^4.3.5",
67 | "isstream": "^0.1.2",
68 | "jasmine-core": "~2.4.1",
69 | "jasmine-spec-reporter": "^2.4.0",
70 | "karma": "~0.13.22",
71 | "karma-chrome-launcher": "~0.2.2",
72 | "karma-coverage": "^0.5.5",
73 | "karma-ie-launcher": "^0.2.0",
74 | "karma-jasmine": "~0.3.8",
75 | "karma-mocha-reporter": "^2.0.0",
76 | "karma-phantomjs-launcher": "^1.0.0",
77 | "merge-stream": "^1.0.0",
78 | "ng2lint": "0.0.10",
79 | "open": "0.0.5",
80 | "phantomjs-prebuilt": "^2.1.4",
81 | "postcss-reporter": "^1.3.3",
82 | "protractor": "^3.0.0",
83 | "proxy-middleware": "^0.15.0",
84 | "remap-istanbul": "git+https://github.com/SitePen/remap-istanbul.git#master",
85 | "rimraf": "^2.5.2",
86 | "run-sequence": "^1.1.0",
87 | "semver": "^5.1.0",
88 | "serve-static": "^1.10.2",
89 | "slash": "~1.0.0",
90 | "stream-series": "^0.1.1",
91 | "stylelint": "^5.1.0",
92 | "stylelint-config-standard": "^4.0.1",
93 | "systemjs-builder": "^0.15.13",
94 | "tiny-lr": "^0.2.1",
95 | "traceur": "^0.0.91",
96 | "ts-node": "^0.6.2",
97 | "tslint": "^3.6.0",
98 | "typedoc": "^0.3.12",
99 | "typescript": "~1.8.7",
100 | "typings": "^0.7.9",
101 | "vinyl-buffer": "^1.0.0",
102 | "vinyl-source-stream": "^1.1.0",
103 | "yargs": "^4.2.0"
104 | },
105 | "dependencies": {
106 | "angular2": "2.0.0-beta.9",
107 | "angular2-jwt": "^0.1.8",
108 | "bower": "^1.7.7",
109 | "es6-module-loader": "^0.17.8",
110 | "es6-promise": "^3.1.2",
111 | "es6-shim": "0.33.3",
112 | "ng2-bootstrap": "^1.0.7",
113 | "reflect-metadata": "0.1.2",
114 | "rxjs": "5.0.0-beta.2",
115 | "systemjs": "~0.19.18",
116 | "zone.js": "0.5.15",
117 | "express": "^4.13.4",
118 | "request": "^2.69.0"
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/frontend/protractor.conf.js:
--------------------------------------------------------------------------------
1 | exports.config = {
2 | baseUrl: 'http://localhost:5555',
3 |
4 | specs: [
5 | 'dist/dev/**/*.e2e.js'
6 | ],
7 | exclude: [],
8 |
9 | framework: 'jasmine2',
10 |
11 | allScriptsTimeout: 110000,
12 |
13 | jasmineNodeOpts: {
14 | showTiming: true,
15 | showColors: true,
16 | isVerbose: false,
17 | includeStackTrace: false,
18 | defaultTimeoutInterval: 400000
19 | },
20 | directConnect: true,
21 |
22 | capabilities: {
23 | 'browserName': 'chrome'
24 | },
25 |
26 | onPrepare: function() {
27 | var SpecReporter = require('jasmine-spec-reporter');
28 | // add jasmine spec reporter
29 | jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: true}));
30 |
31 | browser.ignoreSynchronization = false;
32 | },
33 |
34 |
35 | /**
36 | * Angular 2 configuration
37 | *
38 | * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching
39 | * `rootEl`
40 | *
41 | */
42 | useAllAngular2AppRoots: true
43 | };
44 |
--------------------------------------------------------------------------------
/frontend/test-main.js:
--------------------------------------------------------------------------------
1 | if (!Object.hasOwnProperty('name')) {
2 | Object.defineProperty(Function.prototype, 'name', {
3 | get: function() {
4 | var matches = this.toString().match(/^\s*function\s*(\S*)\s*\(/);
5 | var name = matches && matches.length > 1 ? matches[1] : "";
6 | Object.defineProperty(this, 'name', {value: name});
7 | return name;
8 | }
9 | });
10 | }
11 |
12 | // Turn on full stack traces in errors to help debugging
13 | Error.stackTraceLimit = Infinity;
14 |
15 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
16 |
17 | // Cancel Karma's synchronous start,
18 | // we will call `__karma__.start()` later, once all the specs are loaded.
19 | __karma__.loaded = function() {};
20 |
21 | System.config({
22 | baseURL: '/base/',
23 | defaultJSExtensions: true,
24 | paths: {
25 | 'angular2/*': 'node_modules/angular2/*.js',
26 | 'rxjs/*': 'node_modules/rxjs/*.js'
27 | }
28 | });
29 |
30 | Promise.all([
31 | System.import('angular2/src/platform/browser/browser_adapter'),
32 | System.import('angular2/platform/testing/browser'),
33 | System.import('angular2/testing')
34 | ]).then(function (modules) {
35 | var browser_adapter = modules[0];
36 | var providers = modules[1];
37 | var testing = modules[2];
38 | testing.setBaseTestProviders(providers.TEST_BROWSER_PLATFORM_PROVIDERS,
39 | providers.TEST_BROWSER_APPLICATION_PROVIDERS);
40 |
41 | browser_adapter.BrowserDomAdapter.makeCurrent();
42 | }).then(function() {
43 | return Promise.all(
44 | Object.keys(window.__karma__.files) // All files served by Karma.
45 | .filter(onlySpecFiles)
46 | .map(file2moduleName)
47 | .map(function(path) {
48 | return System.import(path).then(function(module) {
49 | if (module.hasOwnProperty('main')) {
50 | module.main();
51 | } else {
52 | throw new Error('Module ' + path + ' does not implement main() method.');
53 | }
54 | });
55 | }));
56 | })
57 | .then(function() {
58 | __karma__.start();
59 | }, function(error) {
60 | console.error(error.stack || error);
61 | __karma__.start();
62 | });
63 |
64 | function onlySpecFiles(path) {
65 | // check for individual files, if not given, always matches to all
66 | var patternMatched = __karma__.config.files ?
67 | path.match(new RegExp(__karma__.config.files)) : true;
68 |
69 | return patternMatched && /[\.|_]spec\.js$/.test(path);
70 | }
71 |
72 | // Normalize paths to module names.
73 | function file2moduleName(filePath) {
74 | return filePath.replace(/\\/g, '/')
75 | .replace(/^\/base\//, '')
76 | .replace(/\.js/, '');
77 | }
78 |
--------------------------------------------------------------------------------
/frontend/tools/README.md:
--------------------------------------------------------------------------------
1 | # Tools documentation
2 |
3 | ## Configuration
4 |
5 | ## Tasks
6 |
7 | ## Utilities
8 |
9 |
--------------------------------------------------------------------------------
/frontend/tools/config.ts:
--------------------------------------------------------------------------------
1 | import {ProjectConfig} from './config/project.config';
2 |
3 | const config: ProjectConfig = new ProjectConfig();
4 | export = config;
5 |
--------------------------------------------------------------------------------
/frontend/tools/config/project.config.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {SeedConfig} from './seed.config';
3 | import {InjectableDependency} from './seed.config.interfaces';
4 |
5 | export class ProjectConfig extends SeedConfig {
6 | PROJECT_TASKS_DIR = join(process.cwd(), this.TOOLS_DIR, 'tasks', 'project');
7 |
8 | constructor() {
9 | super();
10 | // this.APP_TITLE = 'Put name of your app here';
11 | let additional_deps: InjectableDependency[] = [
12 | // {src: 'jquery/dist/jquery.min.js', inject: 'libs'},
13 | // {src: 'lodash/lodash.min.js', inject: 'libs'},
14 | ];
15 |
16 | const seedDependencies = this.NPM_DEPENDENCIES;
17 |
18 | this.NPM_DEPENDENCIES = seedDependencies.concat(additional_deps);
19 |
20 | this.APP_ASSETS = [
21 | // {src: `${this.ASSETS_SRC}/css/toastr.min.css`, inject: true},
22 | // {src: `${this.APP_DEST}/assets/scss/global.css`, inject: true},
23 | { src: `${this.ASSETS_SRC}/main.css`, inject: true },
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/frontend/tools/config/seed.config.interfaces.ts:
--------------------------------------------------------------------------------
1 | export interface InjectableDependency {
2 | src: string;
3 | inject: string | boolean;
4 | vendor?: boolean;
5 | env?: string[] | string;
6 | }
7 |
8 | export interface Environments {
9 | DEVELOPMENT: string;
10 | PRODUCTION: string;
11 | [key: string]: string;
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/frontend/tools/config/seed.config.ts:
--------------------------------------------------------------------------------
1 | import {readFileSync} from 'fs';
2 | import {argv} from 'yargs';
3 | import {normalize, join} from 'path';
4 | import {InjectableDependency, Environments} from './seed.config.interfaces';
5 |
6 | export const ENVIRONMENTS: Environments = {
7 | DEVELOPMENT: 'dev',
8 | PRODUCTION: 'prod'
9 | };
10 |
11 |
12 | export class SeedConfig {
13 | PORT = argv['port'] || 8100;
14 | PROJECT_ROOT = normalize(join(__dirname, '..'));
15 | ENV = getEnvironment();
16 | DEBUG = argv['debug'] || false;
17 | DOCS_PORT = argv['docs-port'] || 4003;
18 | COVERAGE_PORT = argv['coverage-port'] || 4004;
19 | APP_BASE = argv['base'] || '/';
20 |
21 | ENABLE_HOT_LOADING = argv['hot-loader'];
22 | HOT_LOADER_PORT = 5578;
23 |
24 | BOOTSTRAP_MODULE = this.ENABLE_HOT_LOADING ? 'hot_loader_main' : 'main';
25 |
26 | APP_TITLE = 'Task manager';
27 |
28 | APP_SRC = 'www';
29 | ASSETS_SRC = `${this.APP_SRC}/assets`;
30 |
31 | TOOLS_DIR = 'tools';
32 | SEED_TASKS_DIR = join(process.cwd(), this.TOOLS_DIR, 'tasks', 'seed');
33 | DOCS_DEST = 'docs';
34 | DIST_DIR = 'dist';
35 | DEV_DEST = `${this.DIST_DIR}/dev`;
36 | PROD_DEST = `${this.DIST_DIR}/prod`;
37 | TMP_DIR = `${this.DIST_DIR}/tmp`;
38 | APP_DEST = `${this.DIST_DIR}/${this.ENV}`;
39 | CSS_DEST = `${this.APP_DEST}/css`;
40 | JS_DEST = `${this.APP_DEST}/js`;
41 | APP_ROOT = this.ENV === 'dev' ? `${this.APP_BASE}${this.APP_DEST}/` : `${this.APP_BASE}`;
42 | VERSION = appVersion();
43 |
44 | CSS_PROD_BUNDLE = 'all.css';
45 | JS_PROD_SHIMS_BUNDLE = 'shims.js';
46 | JS_PROD_APP_BUNDLE = 'app.js';
47 |
48 | VERSION_NPM = '2.14.2';
49 | VERSION_NODE = '4.0.0';
50 |
51 | NG2LINT_RULES = customRules();
52 |
53 | NPM_DEPENDENCIES: InjectableDependency[] = [
54 | { src: 'systemjs/dist/system-polyfills.src.js', inject: 'shims' },
55 | { src: 'reflect-metadata/Reflect.js', inject: 'shims' },
56 | { src: 'es6-shim/es6-shim.js', inject: 'shims' },
57 | { src: 'systemjs/dist/system.src.js', inject: 'shims' },
58 | { src: 'angular2/bundles/angular2-polyfills.js', inject: 'shims' },
59 | { src: 'rxjs/bundles/Rx.js', inject: 'libs', env: ENVIRONMENTS.DEVELOPMENT },
60 | { src: 'angular2/bundles/angular2.js', inject: 'libs', env: ENVIRONMENTS.DEVELOPMENT },
61 | { src: 'angular2/bundles/router.js', inject: 'libs', env: ENVIRONMENTS.DEVELOPMENT },
62 | { src: 'angular2/bundles/http.js', inject: 'libs', env: ENVIRONMENTS.DEVELOPMENT }
63 | ];
64 |
65 | // Declare local files that needs to be injected
66 | APP_ASSETS: InjectableDependency[] = [
67 | { src: `${this.ASSETS_SRC}/main.css`, inject: true, vendor: false }
68 | ];
69 |
70 |
71 | get PROD_DEPENDENCIES(): InjectableDependency[] {
72 | console.warn('The property "PROD_DEPENDENCIES" is deprecated. Consider using "DEPENDENCIES" instead.');
73 | return normalizeDependencies(this.NPM_DEPENDENCIES.filter(filterDependency.bind(null, ENVIRONMENTS.PRODUCTION)))
74 | .concat(this.APP_ASSETS.filter(filterDependency.bind(null, ENVIRONMENTS.PRODUCTION)));
75 | }
76 |
77 | get DEV_DEPENDENCIES(): InjectableDependency[] {
78 | console.warn('The property "DEV_DEPENDENCIES" is deprecated. Consider using "DEPENDENCIES" instead.');
79 | return normalizeDependencies(this.NPM_DEPENDENCIES.filter(filterDependency.bind(null, ENVIRONMENTS.DEVELOPMENT)))
80 | .concat(this.APP_ASSETS.filter(filterDependency.bind(null, ENVIRONMENTS.DEVELOPMENT)));
81 | }
82 |
83 | set DEV_DEPENDENCIES(val: InjectableDependency[]) {
84 | console.warn('The property "DEV_DEPENDENCIES" is deprecated. Consider using "DEPENDENCIES" instead.');
85 | }
86 |
87 | set PROD_DEPENDENCIES(val: InjectableDependency[]) {
88 | console.warn('The property "PROD_DEPENDENCIES" is deprecated. Consider using "DEPENDENCIES" instead.');
89 | }
90 |
91 | get DEV_NPM_DEPENDENCIES(): InjectableDependency[] {
92 | console.warn('The property "DEV_NPM_DEPENDENCIES" is deprecated. Consider using "DEPENDENCIES" instead.');
93 | return normalizeDependencies(this.NPM_DEPENDENCIES.filter(filterDependency.bind(null, ENVIRONMENTS.DEVELOPMENT)));
94 | }
95 | get PROD_NPM_DEPENDENCIES(): InjectableDependency[] {
96 | console.warn('The property "PROD_NPM_DEPENDENCIES" is deprecated. Consider using "DEPENDENCIES" instead.');
97 | return normalizeDependencies(this.NPM_DEPENDENCIES.filter(filterDependency.bind(null, ENVIRONMENTS.PRODUCTION)));
98 | }
99 | set DEV_NPM_DEPENDENCIES(value: InjectableDependency[]) {
100 | console.warn('The property "DEV_NPM_DEPENDENCIES" is deprecated. Consider using "DEPENDENCIES" instead.');
101 | const notDev = this.NPM_DEPENDENCIES.filter(d => !filterDependency(ENVIRONMENTS.DEVELOPMENT, d));
102 | this.NPM_DEPENDENCIES = notDev.concat(value);
103 | }
104 | set PROD_NPM_DEPENDENCIES(value: InjectableDependency[]) {
105 | console.warn('The property "PROD_NPM_DEPENDENCIES" is deprecated. Consider using "DEPENDENCIES" instead.');
106 | const notProd = this.NPM_DEPENDENCIES.filter(d => !filterDependency(ENVIRONMENTS.PRODUCTION, d));
107 | this.NPM_DEPENDENCIES = notProd.concat(value);
108 | }
109 |
110 | get DEPENDENCIES(): InjectableDependency[] {
111 | return normalizeDependencies(this.NPM_DEPENDENCIES.filter(filterDependency.bind(null, this.ENV)))
112 | .concat(this.APP_ASSETS.filter(filterDependency.bind(null, this.ENV)));
113 | }
114 |
115 | // ----------------
116 | // SystemsJS Configuration.
117 | protected SYSTEM_CONFIG_DEV = {
118 | defaultJSExtensions: true,
119 | packageConfigPaths: [`${this.APP_BASE}node_modules/*/package.json`],
120 | paths: {
121 | [this.BOOTSTRAP_MODULE]: `${this.APP_BASE}${this.BOOTSTRAP_MODULE}`,
122 | 'angular2/*': `${this.APP_BASE}angular2/*`,
123 | 'rxjs/*': `${this.APP_BASE}rxjs/*`,
124 | '*': `${this.APP_BASE}node_modules/*`
125 | },
126 | packages: {
127 | angular2: { defaultExtension: false },
128 | rxjs: { defaultExtension: false }
129 | }
130 | };
131 |
132 | SYSTEM_CONFIG = this.SYSTEM_CONFIG_DEV;
133 |
134 | SYSTEM_BUILDER_CONFIG = {
135 | defaultJSExtensions: true,
136 | paths: {
137 | [`${this.TMP_DIR}/*`]: `${this.TMP_DIR}/*`,
138 | '*': 'node_modules/*'
139 | }
140 | };
141 |
142 | // ----------------
143 | // Autoprefixer configuration.
144 | BROWSER_LIST = [
145 | 'ie >= 10',
146 | 'ie_mob >= 10',
147 | 'ff >= 30',
148 | 'chrome >= 34',
149 | 'safari >= 7',
150 | 'opera >= 23',
151 | 'ios >= 7',
152 | 'android >= 4.4',
153 | 'bb >= 10'
154 | ];
155 | getEnvDependencies() {
156 | console.warn('The "getEnvDependencies" method is deprecated. Consider using "DEPENDENCIES" instead.');
157 | if (this.ENV === 'prod') {
158 | return this.PROD_DEPENDENCIES;
159 | } else {
160 | return this.DEV_DEPENDENCIES;
161 | }
162 | }
163 | }
164 |
165 |
166 |
167 |
168 | // --------------
169 | // Utils.
170 |
171 | function filterDependency(env: string, d: InjectableDependency): boolean {
172 | if (!d.env) {
173 | d.env = Object.keys(ENVIRONMENTS).map(k => ENVIRONMENTS[k]);
174 | }
175 | if (!(d.env instanceof Array)) {
176 | (d).env = [d.env];
177 | }
178 | return d.env.indexOf(env) >= 0;
179 | }
180 |
181 | export function normalizeDependencies(deps: InjectableDependency[]) {
182 | deps
183 | .filter((d:InjectableDependency) => !/\*/.test(d.src)) // Skip globs
184 | .forEach((d:InjectableDependency) => d.src = require.resolve(d.src));
185 | return deps;
186 | }
187 |
188 | function appVersion(): number|string {
189 | var pkg = JSON.parse(readFileSync('package.json').toString());
190 | return pkg.version;
191 | }
192 |
193 | function customRules(): string[] {
194 | var lintConf = JSON.parse(readFileSync('tslint.json').toString());
195 | return lintConf.rulesDirectory;
196 | }
197 |
198 | function getEnvironment() {
199 | let base:string[] = argv['_'];
200 | let prodKeyword = !!base.filter(o => o.indexOf(ENVIRONMENTS.PRODUCTION) >= 0).pop();
201 | if (base && prodKeyword || argv['env'] === ENVIRONMENTS.PRODUCTION) {
202 | return ENVIRONMENTS.PRODUCTION;
203 | } else {
204 | return ENVIRONMENTS.DEVELOPMENT;
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/frontend/tools/debug.ts:
--------------------------------------------------------------------------------
1 | import {argv} from 'yargs';
2 | import * as gulp from 'gulp';
3 |
4 | require('../gulpfile');
5 |
6 | const TASK = argv['task'];
7 |
8 | if (!TASK) {
9 | throw new Error('You must specify a task name.');
10 | }
11 |
12 | console.log('**********************');
13 | console.log('* angular2-seed tools ');
14 | console.log('* debugging task:', TASK);
15 | console.log('**********************');
16 |
17 | gulp.start(TASK);
18 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/project/sample.package.d.ts:
--------------------------------------------------------------------------------
1 | // declare module "moment/moment" {
2 | // export = moment;
3 | // }
4 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/angular2-hot-loader.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'angular2-hot-loader' {
2 | export interface Options {
3 | port?: number;
4 | path?: string;
5 | processPath?: Function;
6 | }
7 | export function listen(localConfig?: Options): void;
8 | export function onChange(files: string[]): void;
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/autoprefixer.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'autoprefixer' {
2 |
3 | interface IOptions {
4 | browsers: string[];
5 | }
6 |
7 | interface IAutoprefixer {
8 | (opts?: IOptions): NodeJS.ReadWriteStream;
9 | }
10 |
11 | const autoprefixer: IAutoprefixer;
12 | export = autoprefixer;
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/colorguard.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'colorguard' {
2 |
3 | interface IOptions {
4 | ignore?: string[];
5 | threshold?: number;
6 | whitelist?: string[];
7 | }
8 |
9 | interface IColorguard {
10 | (opts?: IOptions): NodeJS.ReadWriteStream;
11 | }
12 |
13 | const colorguard: IColorguard;
14 | export = colorguard;
15 | }
16 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/connect-livereload.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'connect-livereload' {
2 | function connectLivereload(options?: any): any;
3 | module connectLivereload {}
4 | export = connectLivereload;
5 | }
6 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/cssnano.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'cssnano' {
2 |
3 | interface IOptions {
4 | discardComments: {
5 | removeAll: boolean;
6 | };
7 | }
8 |
9 | interface ICssnano {
10 | (opts?: IOptions): NodeJS.ReadWriteStream;
11 | }
12 |
13 | const cssnano: ICssnano;
14 | export = cssnano;
15 | }
16 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/doiuse.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'doiuse' {
2 |
3 | interface IOptions {
4 | browsers?: string[];
5 | ignore?: string[];
6 | ignoreFiles?: string[];
7 | onFeatureUsage?: Function;
8 | }
9 |
10 | interface IDoiuse {
11 | (opts?: IOptions): NodeJS.ReadWriteStream;
12 | }
13 |
14 | const doiuse: IDoiuse;
15 | export = doiuse;
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/istream.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'isstream' {
2 | function istream(stream: any): boolean;
3 | interface Istream {
4 | isReadable(stream: any): boolean;
5 | isWritable(stream: any): boolean;
6 | isDuplex(stream: any): boolean;
7 | }
8 | module istream {}
9 | export = istream;
10 | }
11 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/karma.d.ts:
--------------------------------------------------------------------------------
1 | // Use this minimalistic definition file as bluebird dependency
2 | // generate a lot of errors.
3 |
4 | declare module 'karma' {
5 | var karma: IKarma;
6 | export = karma;
7 | interface IKarma {
8 | server: {
9 | start(options: any, callback: Function): void
10 | };
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/merge-stream.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'merge-stream' {
2 | function mergeStream(...streams: NodeJS.ReadWriteStream[]): MergeStream;
3 | interface MergeStream extends NodeJS.ReadWriteStream {
4 | add(stream: NodeJS.ReadWriteStream): MergeStream;
5 | }
6 | module mergeStream {}
7 | export = mergeStream;
8 | }
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/open.d.ts:
--------------------------------------------------------------------------------
1 | // https://github.com/borisyankov/DefinitelyTyped/tree/master/open
2 | // Does not support ES2015 import (import * as open from 'open').
3 |
4 | declare module 'open' {
5 | function open(target: string, app?: string): void;
6 | module open {}
7 | export = open;
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/postcss-reporter.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'postcss-reporter' {
2 |
3 | interface IOptions {
4 | clearMessages?: boolean;
5 | formatter?: Function;
6 | plugins?: string[];
7 | throwError?: boolean;
8 | sortByPosition?: boolean;
9 | positionless?: string;
10 | noIcon?: boolean;
11 | noPlugin?: boolean;
12 | }
13 |
14 | interface IPostcssReporter {
15 | (opts?: IOptions): NodeJS.ReadWriteStream;
16 | }
17 |
18 | const postcssReporter: IPostcssReporter;
19 | export = postcssReporter;
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/slash.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'slash' {
2 | function slash(path: string): string;
3 | module slash {}
4 | export = slash;
5 | }
6 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/stylelint.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'stylelint' {
2 |
3 | interface IOptions {
4 | config?: Object;
5 | configFile?: string;
6 | configBasedir?: string;
7 | configOverrides?: Object;
8 | }
9 |
10 | interface IStylelint {
11 | (opts?: IOptions): NodeJS.ReadWriteStream;
12 | }
13 |
14 | const stylelint: IStylelint;
15 | export = stylelint;
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/systemjs-builder.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'systemjs-builder' {
2 | class Builder {
3 | constructor(configObject?: any, baseUrl?: string, configPath?: string);
4 | bundle(source: string, target: string, options?: any): Promise;
5 | buildStatic(source: string, target: string, options?: any): Promise;
6 | }
7 |
8 | module Builder {}
9 | export = Builder;
10 | }
--------------------------------------------------------------------------------
/frontend/tools/manual_typings/seed/tiny-lr.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'tiny-lr' {
2 | function tinylr(): ITinylr;
3 | module tinylr {}
4 | export = tinylr;
5 |
6 | interface ITinylr {
7 | changed(options: any): void;
8 | listen(port: number): void;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/project/sample.task.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import {join} from 'path';
3 | import {APP_SRC, APP_DEST} from '../../config';
4 |
5 | /**
6 | * Sample tasks
7 | *
8 | */
9 |
10 | export = () => {
11 | return gulp.src(join(APP_SRC, '**/*.ts'))
12 | .pipe(gulp.dest(APP_DEST));
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.assets.dev.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import {join} from 'path';
3 | import {APP_SRC, APP_DEST} from '../../config';
4 |
5 | export = () => {
6 | return gulp.src([
7 | join(APP_SRC, '**'),
8 | '!' + join(APP_SRC, '**', '*.ts')
9 | ])
10 | .pipe(gulp.dest(APP_DEST));
11 | }
12 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.assets.prod.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import {join} from 'path';
3 | import {APP_SRC, APP_DEST, ASSETS_SRC} from '../../config';
4 |
5 | // TODO There should be more elegant to prevent empty directories from copying
6 | let es: any = require('event-stream');
7 | var onlyDirs = function (es: any) {
8 | return es.map(function (file: any, cb: any) {
9 | if (file.stat.isFile()) {
10 | return cb(null, file);
11 | } else {
12 | return cb();
13 | }
14 | });
15 | };
16 |
17 | export = () => {
18 | return gulp.src([
19 | join(APP_SRC, '**'),
20 | '!' + join(APP_SRC, '**', '*.ts'),
21 | '!' + join(APP_SRC, '**', '*.css'),
22 | '!' + join(APP_SRC, '**', '*.html'),
23 | '!' + join(ASSETS_SRC, '**', '*.js')
24 | ])
25 | .pipe(onlyDirs(es))
26 | .pipe(gulp.dest(APP_DEST));
27 | }
28 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.bundles.app.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import * as Builder from 'systemjs-builder';
3 | import {
4 | BOOTSTRAP_MODULE,
5 | JS_PROD_APP_BUNDLE,
6 | JS_DEST,
7 | SYSTEM_BUILDER_CONFIG,
8 | TMP_DIR
9 | } from '../../config';
10 |
11 | const BUNDLER_OPTIONS = {
12 | format: 'cjs',
13 | minify: true,
14 | mangle: false
15 | };
16 |
17 | export = (done: any) => {
18 | let builder = new Builder(SYSTEM_BUILDER_CONFIG);
19 | builder
20 | .buildStatic(join(TMP_DIR, BOOTSTRAP_MODULE),
21 | join(JS_DEST, JS_PROD_APP_BUNDLE),
22 | BUNDLER_OPTIONS)
23 | .then(() => done());
24 | };
25 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.bundles.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import * as merge from 'merge-stream';
4 | import {DEPENDENCIES, JS_PROD_SHIMS_BUNDLE, JS_DEST} from '../../config';
5 | const plugins = gulpLoadPlugins();
6 |
7 | export = () => merge(bundleShims());
8 |
9 | function getShims() {
10 | let libs = DEPENDENCIES
11 | .filter(d => /\.js$/.test(d.src));
12 |
13 | return libs.filter(l => l.inject === 'shims')
14 | .concat(libs.filter(l => l.inject === 'libs'))
15 | .concat(libs.filter(l => l.inject === true))
16 | .map(l => l.src);
17 | }
18 |
19 | function bundleShims() {
20 | return gulp.src(getShims())
21 | // Strip comments and sourcemaps
22 | .pipe(plugins.uglify({
23 | mangle: false
24 | }))
25 | .pipe(plugins.concat(JS_PROD_SHIMS_BUNDLE))
26 | .pipe(gulp.dest(JS_DEST));
27 | }
28 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.docs.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import {join} from 'path';
4 | import {APP_SRC, APP_TITLE, DOCS_DEST} from '../../config';
5 | const plugins = gulpLoadPlugins();
6 |
7 | export = () => {
8 |
9 | let src = [
10 | 'typings/main.d.ts',
11 | join(APP_SRC, '**/*.ts'),
12 | '!' + join(APP_SRC, '**/*.spec.ts'),
13 | '!' + join(APP_SRC, '**/*.e2e.ts')
14 | ];
15 |
16 | return gulp.src(src)
17 | .pipe(plugins.typedoc({
18 | // TypeScript options (see typescript docs)
19 | module: 'commonjs',
20 | target: 'es5',
21 | includeDeclarations: true,
22 | // Output options (see typedoc docs)
23 | out: DOCS_DEST,
24 | json: join(DOCS_DEST , 'data/docs.json' ),
25 | name: APP_TITLE,
26 | ignoreCompilerErrors: false,
27 | experimentalDecorators: true,
28 | version: true
29 | }));
30 | }
31 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.html_css.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import * as merge from 'merge-stream';
4 | import * as autoprefixer from 'autoprefixer';
5 | import * as cssnano from 'cssnano';
6 | import {join} from 'path';
7 | import {APP_SRC, TMP_DIR, CSS_PROD_BUNDLE, CSS_DEST, APP_DEST, BROWSER_LIST, ENV, DEPENDENCIES} from '../../config';
8 | const plugins = gulpLoadPlugins();
9 |
10 | const processors = [
11 | autoprefixer({
12 | browsers: BROWSER_LIST
13 | })
14 | ];
15 |
16 | const isProd = ENV === 'prod';
17 |
18 | if (isProd) {
19 | processors.push(
20 | cssnano({
21 | discardComments: {removeAll: true}
22 | })
23 | );
24 | }
25 |
26 | function prepareTemplates() {
27 | return gulp.src(join(APP_SRC, '**', '*.html'))
28 | .pipe(gulp.dest(TMP_DIR));
29 | }
30 |
31 | function processComponentCss() {
32 | return gulp.src([
33 | join(APP_SRC, '**', '*.css'),
34 | '!' + join(APP_SRC, 'assets', '**', '*.css')
35 | ])
36 | .pipe(isProd ? plugins.cached('process-component-css') : plugins.util.noop())
37 | .pipe(plugins.postcss(processors))
38 | .pipe(gulp.dest(isProd ? TMP_DIR: APP_DEST));
39 | }
40 |
41 | function processExternalCss() {
42 | return gulp.src(getExternalCss().map(r => r.src))
43 | .pipe(isProd ? plugins.cached('process-external-css') : plugins.util.noop())
44 | .pipe(plugins.postcss(processors))
45 | .pipe(isProd ? plugins.concat(CSS_PROD_BUNDLE) : plugins.util.noop())
46 | .pipe(gulp.dest(CSS_DEST));
47 | }
48 |
49 | function getExternalCss() {
50 | return DEPENDENCIES.filter(d => /\.css$/.test(d.src));
51 | }
52 |
53 |
54 | export = () => merge(processComponentCss(), prepareTemplates(), processExternalCss());
55 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.index.dev.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import {join} from 'path';
4 | import * as slash from 'slash';
5 | import {APP_SRC, APP_DEST, APP_BASE, DEPENDENCIES} from '../../config';
6 | import {templateLocals} from '../../utils';
7 | const plugins = gulpLoadPlugins();
8 |
9 | export = () => {
10 | return gulp.src(join(APP_SRC, 'index.html'))
11 | .pipe(inject('shims'))
12 | .pipe(inject('libs'))
13 | .pipe(inject())
14 | .pipe(plugins.template(templateLocals()))
15 | .pipe(gulp.dest(APP_DEST));
16 | };
17 |
18 |
19 | function inject(name?: string) {
20 | return plugins.inject(gulp.src(getInjectablesDependenciesRef(name), { read: false }), {
21 | name,
22 | transform: transformPath()
23 | });
24 | }
25 |
26 | function getInjectablesDependenciesRef(name?: string) {
27 | return DEPENDENCIES
28 | .filter(dep => dep['inject'] && dep['inject'] === (name || true))
29 | .map(mapPath);
30 | }
31 |
32 | function mapPath(dep: any) {
33 | let envPath = dep.src;
34 | if (envPath.startsWith(APP_SRC)) {
35 | envPath = join(APP_DEST, dep.src.replace(APP_SRC, ''));
36 | }
37 | return envPath;
38 | }
39 |
40 | function transformPath() {
41 | return function (filepath: string) {
42 | arguments[0] = join(APP_BASE, filepath) + `?${Date.now()}`;
43 | return slash(plugins.inject.transform.apply(plugins.inject.transform, arguments));
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.index.prod.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import {join, sep, normalize} from 'path';
4 | import * as slash from 'slash';
5 | import {templateLocals} from '../../utils';
6 | import {
7 | APP_SRC,
8 | APP_DEST,
9 | CSS_DEST,
10 | JS_DEST,
11 | CSS_PROD_BUNDLE,
12 | JS_PROD_APP_BUNDLE,
13 | JS_PROD_SHIMS_BUNDLE
14 | } from '../../config';
15 | const plugins = gulpLoadPlugins();
16 |
17 | export = () => {
18 | return gulp.src(join(APP_SRC, 'index.html'))
19 | .pipe(injectJs())
20 | .pipe(injectCss())
21 | .pipe(plugins.template(templateLocals()))
22 | .pipe(gulp.dest(APP_DEST));
23 | }
24 |
25 | function inject(...files: Array) {
26 | return plugins.inject(gulp.src(files, { read: false }), {
27 | files,
28 | transform: transformPath()
29 | });
30 | }
31 |
32 | function injectJs() {
33 | return inject(join(JS_DEST, JS_PROD_SHIMS_BUNDLE), join(JS_DEST, JS_PROD_APP_BUNDLE));
34 | }
35 |
36 | function injectCss() {
37 | return inject(join(CSS_DEST, CSS_PROD_BUNDLE));
38 | }
39 |
40 | function transformPath() {
41 | return function(filepath: string) {
42 | let path: Array = normalize(filepath).split(sep);
43 | arguments[0] = path.slice(3, path.length).join(sep) + `?${Date.now()}`;
44 | return slash(plugins.inject.transform.apply(plugins.inject.transform, arguments));
45 | };
46 | }
47 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.js.dev.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import {join} from 'path';
4 | import {APP_SRC, APP_DEST, TOOLS_DIR} from '../../config';
5 | import {templateLocals, makeTsProject} from '../../utils';
6 | const plugins = gulpLoadPlugins();
7 |
8 | export = () => {
9 | let tsProject = makeTsProject();
10 | let src = [
11 | 'typings/browser.d.ts',
12 | TOOLS_DIR + '/manual_typings/**/*.d.ts',
13 | join(APP_SRC, '**/*.ts'),
14 | '!' + join(APP_SRC, '**/*.spec.ts'),
15 | '!' + join(APP_SRC, '**/*.e2e.ts')
16 | ];
17 | let result = gulp.src(src)
18 | .pipe(plugins.plumber())
19 | .pipe(plugins.sourcemaps.init())
20 | .pipe(plugins.typescript(tsProject));
21 |
22 | return result.js
23 | .pipe(plugins.sourcemaps.write())
24 | .pipe(plugins.template(templateLocals()))
25 | .pipe(gulp.dest(APP_DEST));
26 | };
27 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.js.e2e.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import {join} from 'path';
4 | import {APP_SRC, APP_DEST, TOOLS_DIR} from '../../config';
5 | import {templateLocals, makeTsProject} from '../../utils';
6 | const plugins = gulpLoadPlugins();
7 |
8 |
9 | export = () => {
10 | let tsProject = makeTsProject();
11 | let src = [
12 | 'typings/browser.d.ts',
13 | TOOLS_DIR + '/manual_typings/**/*.d.ts',
14 | join(APP_SRC, '**/*.ts'),
15 | '!' + join(APP_SRC, '**/*.spec.ts')
16 | ];
17 | let result = gulp.src(src)
18 | .pipe(plugins.plumber())
19 | .pipe(plugins.sourcemaps.init())
20 | .pipe(plugins.typescript(tsProject));
21 |
22 | return result.js
23 | .pipe(plugins.sourcemaps.write())
24 | .pipe(plugins.template(templateLocals()))
25 | .pipe(gulp.dest(APP_DEST));
26 | }
27 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.js.prod.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import {join} from 'path';
4 | import {TMP_DIR, TOOLS_DIR} from '../../config';
5 | import {templateLocals, makeTsProject} from '../../utils';
6 | const plugins = gulpLoadPlugins();
7 |
8 | const INLINE_OPTIONS = {
9 | base: TMP_DIR,
10 | useRelativePaths: true,
11 | removeLineBreaks: true
12 | };
13 |
14 | export = () => {
15 | let tsProject = makeTsProject();
16 | let src = [
17 | 'typings/browser.d.ts',
18 | TOOLS_DIR + '/manual_typings/**/*.d.ts',
19 | join(TMP_DIR, '**/*.ts')
20 | ];
21 | let result = gulp.src(src)
22 | .pipe(plugins.plumber())
23 | .pipe(plugins.inlineNg2Template(INLINE_OPTIONS))
24 | .pipe(plugins.typescript(tsProject));
25 |
26 | return result.js
27 | .pipe(plugins.template(templateLocals()))
28 | .pipe(gulp.dest(TMP_DIR));
29 | }
30 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.js.test.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import {join} from 'path';
4 | import {BOOTSTRAP_MODULE, APP_SRC, APP_DEST, TOOLS_DIR} from '../../config';
5 | import {makeTsProject} from '../../utils';
6 | const plugins = gulpLoadPlugins();
7 |
8 | export = () => {
9 | let tsProject = makeTsProject();
10 | let src = [
11 | 'typings/browser.d.ts',
12 | TOOLS_DIR + '/manual_typings/**/*.d.ts',
13 | join(APP_SRC, '**/*.ts'),
14 | '!' + join(APP_SRC, '**/*.e2e.ts'),
15 | '!' + join(APP_SRC, `${BOOTSTRAP_MODULE}.ts`)
16 | ];
17 | let result = gulp.src(src)
18 | .pipe(plugins.plumber())
19 | .pipe(plugins.sourcemaps.init())
20 | .pipe(plugins.inlineNg2Template({base: APP_SRC, useRelativePaths: true}))
21 | .pipe(plugins.typescript(tsProject));
22 |
23 | return result.js
24 | .pipe(plugins.sourcemaps.write())
25 | .pipe(gulp.dest(APP_DEST));
26 | }
27 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/build.js.tools.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import {join} from 'path';
4 | import {TOOLS_DIR} from '../../config';
5 | import {templateLocals, makeTsProject} from '../../utils';
6 | const plugins = gulpLoadPlugins();
7 |
8 | export = () => {
9 | let tsProject = makeTsProject();
10 | let src = [
11 | 'typings/main.d.ts',
12 | TOOLS_DIR + '/manual_typings/**/*.d.ts',
13 | join(TOOLS_DIR, '**/*.ts')
14 | ];
15 | let result = gulp.src(src, {base: './'})
16 | .pipe(plugins.plumber())
17 | .pipe(plugins.sourcemaps.init())
18 | .pipe(plugins.typescript(tsProject));
19 |
20 | return result.js
21 | .pipe(plugins.sourcemaps.write())
22 | .pipe(plugins.template(templateLocals()))
23 | .pipe(gulp.dest('./'));
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/check.versions.ts:
--------------------------------------------------------------------------------
1 | import {VERSION_NPM, VERSION_NODE} from '../../config';
2 |
3 | function reportError(message: string) {
4 | console.error(require('chalk').white.bgRed.bold(message));
5 | process.exit(1);
6 | }
7 |
8 | export = () => {
9 | let exec = require('child_process').exec;
10 | let semver = require('semver');
11 |
12 | exec('npm --version',
13 | function (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) {
14 | if (error !== null) {
15 | reportError('npm preinstall error: ' + error + stderr);
16 | }
17 |
18 | if (!semver.gte(stdout, VERSION_NPM)) {
19 | reportError('NPM is not in required version! Required is ' + VERSION_NPM + ' and you\'re using ' + stdout);
20 | }
21 | });
22 |
23 | exec('node --version',
24 | function (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) {
25 | if (error !== null) {
26 | reportError('npm preinstall error: ' + error + stderr);
27 | }
28 |
29 | if (!semver.gte(stdout, VERSION_NODE)) {
30 | reportError('NODE is not in required version! Required is ' + VERSION_NODE + ' and you\'re using ' + stdout);
31 | }
32 | });
33 | }
34 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/clean.all.ts:
--------------------------------------------------------------------------------
1 | import {DIST_DIR} from '../../config';
2 | import {clean} from '../../utils';
3 |
4 | export = clean(DIST_DIR)
5 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/clean.dev.ts:
--------------------------------------------------------------------------------
1 | import {DEV_DEST} from '../../config';
2 | import {clean} from '../../utils';
3 |
4 | export = clean(DEV_DEST)
5 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/clean.prod.ts:
--------------------------------------------------------------------------------
1 | import {PROD_DEST, TMP_DIR} from '../../config';
2 | import {clean} from '../../utils';
3 |
4 | export = clean([PROD_DEST, TMP_DIR])
5 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/clean.tools.ts:
--------------------------------------------------------------------------------
1 | import * as util from 'gulp-util';
2 | import * as chalk from 'chalk';
3 | import * as rimraf from 'rimraf';
4 | import {readdirSync, lstatSync} from 'fs';
5 | import {join} from 'path';
6 | import {TOOLS_DIR} from '../../config';
7 |
8 | export = (done: any) => {
9 | deleteAndWalk(TOOLS_DIR);
10 | done();
11 | }
12 |
13 | function walk(path: any) {
14 | let files = readdirSync(path);
15 | for (let i = 0; i < files.length; i += 1) {
16 | let curPath = join(path, files[i]);
17 | if (lstatSync(curPath).isDirectory()) { // recurse
18 | deleteAndWalk(curPath);
19 | }
20 | }
21 | }
22 |
23 | function deleteAndWalk(path: any) {
24 | try {
25 | rimraf.sync(join(path, '*.js'));
26 | util.log('Deleted', chalk.yellow(`${path}/*.js`));
27 | } catch (e) {
28 | util.log('Error while deleting', chalk.yellow(`${path}/*.js`), e);
29 | }
30 | walk(path);
31 | }
32 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/copy.js.prod.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import {join} from 'path';
3 | import {APP_SRC, TMP_DIR} from '../../config';
4 |
5 | export = () => {
6 | return gulp.src([
7 | join(APP_SRC, '**/*.ts'),
8 | '!' + join(APP_SRC, '**/*.spec.ts'),
9 | '!' + join(APP_SRC, '**/*.e2e.ts')
10 | ])
11 | .pipe(gulp.dest(TMP_DIR));
12 | };
13 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/css-lint.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import * as merge from 'merge-stream';
4 | import * as reporter from 'postcss-reporter';
5 | import * as stylelint from 'stylelint';
6 | import * as doiuse from 'doiuse';
7 | import * as colorguard from 'colorguard';
8 | import {join} from 'path';
9 | import {APP_SRC, APP_ASSETS, BROWSER_LIST, ENV} from '../../config';
10 | const plugins = gulpLoadPlugins();
11 |
12 | const isProd = ENV === 'prod';
13 |
14 | const processors = [
15 | doiuse({
16 | browsers: BROWSER_LIST,
17 | }),
18 | colorguard(),
19 | stylelint(),
20 | reporter({clearMessages: true})
21 | ];
22 |
23 | function lintComponentCss() {
24 | return gulp.src([
25 | join(APP_SRC, '**', '*.css'),
26 | '!' + join(APP_SRC, 'assets', '**', '*.css')
27 | ])
28 | .pipe(isProd ? plugins.cached('css-lint') : plugins.util.noop())
29 | .pipe(plugins.postcss(processors));
30 | }
31 |
32 | function lintExternalCss() {
33 | return gulp.src(getExternalCss().map(r => r.src))
34 | .pipe(isProd ? plugins.cached('css-lint') : plugins.util.noop())
35 | .pipe(plugins.postcss(processors));
36 | }
37 |
38 | function getExternalCss() {
39 | return APP_ASSETS.filter(d => /\.css$/.test(d.src) && !d.vendor);
40 | }
41 |
42 |
43 | export = () => merge(lintComponentCss(), lintExternalCss());
44 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/karma.start.ts:
--------------------------------------------------------------------------------
1 | import * as karma from 'karma';
2 | import {join} from 'path';
3 |
4 | export = (done: any) => {
5 | new (karma).Server({
6 | configFile: join(process.cwd(), 'karma.conf.js'),
7 | singleRun: true
8 | }).start(done);
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/serve.coverage.ts:
--------------------------------------------------------------------------------
1 | import {serveCoverage} from '../../utils';
2 |
3 | export = serveCoverage
4 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/serve.docs.ts:
--------------------------------------------------------------------------------
1 | import {serveDocs} from '../../utils';
2 |
3 | export = serveDocs
4 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/server.start.ts:
--------------------------------------------------------------------------------
1 | import {serveSPA} from '../../utils';
2 |
3 | export = serveSPA
4 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/tslint.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as gulpLoadPlugins from 'gulp-load-plugins';
3 | import {join} from 'path';
4 | import {APP_SRC, TOOLS_DIR, NG2LINT_RULES} from '../../config';
5 | const plugins = gulpLoadPlugins();
6 |
7 | export = () => {
8 | let src = [
9 | join(APP_SRC, '**/*.ts'),
10 | '!' + join(APP_SRC, '**/*.d.ts'),
11 | join(TOOLS_DIR, '**/*.ts'),
12 | '!' + join(TOOLS_DIR, '**/*.d.ts')
13 | ];
14 |
15 | return gulp.src(src)
16 | .pipe(plugins.tslint({
17 | rulesDirectory: NG2LINT_RULES
18 | }))
19 | .pipe(plugins.tslint.report(plugins.tslintStylish, {
20 | emitError: true,
21 | sort: true,
22 | bell: true
23 | }));
24 | };
25 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/watch.dev.ts:
--------------------------------------------------------------------------------
1 | import {watch} from '../../utils';
2 |
3 | export = watch('build.dev')
4 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/watch.e2e.ts:
--------------------------------------------------------------------------------
1 | import {watch} from '../../utils';
2 |
3 | export = watch('build.e2e')
4 |
--------------------------------------------------------------------------------
/frontend/tools/tasks/seed/watch.test.ts:
--------------------------------------------------------------------------------
1 | import {watch} from '../../utils';
2 |
3 | export = watch('build.test')
4 |
--------------------------------------------------------------------------------
/frontend/tools/utils.ts:
--------------------------------------------------------------------------------
1 | export * from './utils/seed.utils';
2 | export * from './utils/project.utils';
3 |
--------------------------------------------------------------------------------
/frontend/tools/utils/project.utils.ts:
--------------------------------------------------------------------------------
1 | export * from './project/sample_util';
2 |
--------------------------------------------------------------------------------
/frontend/tools/utils/project/sample_util.ts:
--------------------------------------------------------------------------------
1 | export function myUtil() {
2 | // ...
3 | }
4 |
--------------------------------------------------------------------------------
/frontend/tools/utils/seed.utils.ts:
--------------------------------------------------------------------------------
1 | export * from './seed/clean';
2 | export * from './seed/code_change_tools';
3 | export * from './seed/server';
4 | export * from './seed/tasks_tools';
5 | export * from './seed/template_locals';
6 | export * from './seed/tsproject';
7 | export * from './seed/watch';
8 |
--------------------------------------------------------------------------------
/frontend/tools/utils/seed/clean.ts:
--------------------------------------------------------------------------------
1 | import * as util from 'gulp-util';
2 | import * as chalk from 'chalk';
3 | import * as rimraf from 'rimraf';
4 |
5 | export function clean(paths: string|string[]): (done: () => void) => void {
6 | return done => {
7 | let pathsArray: string[];
8 | if (!(paths instanceof Array)) {
9 | pathsArray = [paths];
10 | } else pathsArray = paths;
11 | let promises = pathsArray.map(p => {
12 | return new Promise(resolve => {
13 | rimraf(p, e => {
14 | if (e) {
15 | util.log('Clean task failed with', e);
16 | } else {
17 | util.log('Deleted', chalk.yellow(p || '-'));
18 | }
19 | resolve();
20 | });
21 | });
22 | });
23 | Promise.all(promises).then(() => done());
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/frontend/tools/utils/seed/code_change_tools.ts:
--------------------------------------------------------------------------------
1 | import {PORT, APP_DEST, APP_BASE, DIST_DIR} from '../../config';
2 | import * as browserSync from 'browser-sync';
3 | const proxy = require('proxy-middleware');
4 |
5 | let runServer = () => {
6 | let baseDir = APP_DEST;
7 | let routes:any = {
8 | [`${APP_BASE}${APP_DEST}`]: APP_DEST,
9 | [`${APP_BASE}node_modules`]: 'node_modules',
10 | };
11 |
12 | if (APP_BASE !== '/') {
13 | routes[`${APP_BASE}`] = APP_DEST;
14 | baseDir = `${DIST_DIR}/empty/`;
15 | }
16 |
17 | browserSync({
18 | port: PORT,
19 | startPath: APP_BASE,
20 | server: {
21 | baseDir: baseDir,
22 | middleware: [
23 | proxy({
24 | protocol: 'http:',
25 | hostname: 'localhost',
26 | port: 3000,
27 | pathname: '/api',
28 | route: '/api'
29 | }),
30 | require('connect-history-api-fallback')({index: `${APP_BASE}index.html`})
31 | ],
32 | routes: routes
33 | }
34 | });
35 | };
36 |
37 | let listen = () => {
38 | // if (ENABLE_HOT_LOADING) {
39 | // ng2HotLoader.listen({
40 | // port: HOT_LOADER_PORT,
41 | // processPath: file => {
42 | // return file.replace(join(PROJECT_ROOT, APP_SRC), join('dist', 'dev'));
43 | // }
44 | // });
45 | // }
46 | runServer();
47 | };
48 |
49 | let changed = (files: any) => {
50 | if (!(files instanceof Array)) {
51 | files = [files];
52 | }
53 | // if (ENABLE_HOT_LOADING) {
54 | // ng2HotLoader.onChange(files);
55 | // } else {
56 | //TODO: Figure out why you can't pass a file to reload
57 | browserSync.reload(files.path);
58 | //}
59 | };
60 |
61 | export { listen, changed };
62 |
--------------------------------------------------------------------------------
/frontend/tools/utils/seed/server.ts:
--------------------------------------------------------------------------------
1 | import * as express from 'express';
2 | import * as openResource from 'open';
3 | import * as serveStatic from 'serve-static';
4 | import * as codeChangeTool from './code_change_tools';
5 | import {resolve} from 'path';
6 | import {APP_BASE, DOCS_DEST, DOCS_PORT, COVERAGE_PORT} from '../../config';
7 |
8 | export function serveSPA() {
9 | codeChangeTool.listen();
10 | }
11 |
12 | export function notifyLiveReload(e:any) {
13 | let fileName = e.path;
14 | codeChangeTool.changed(fileName);
15 | }
16 |
17 | export function serveDocs() {
18 | let server = express();
19 |
20 | server.use(
21 | APP_BASE,
22 | serveStatic(resolve(process.cwd(), DOCS_DEST))
23 | );
24 |
25 | server.listen(DOCS_PORT, () =>
26 | openResource('http://localhost:' + DOCS_PORT + APP_BASE)
27 | );
28 | }
29 |
30 | export function serveCoverage() {
31 | let server = express();
32 |
33 | server.use(
34 | APP_BASE,
35 | serveStatic(resolve(process.cwd(), 'coverage'))
36 | );
37 |
38 | server.listen(COVERAGE_PORT, () =>
39 | openResource('http://localhost:' + COVERAGE_PORT + APP_BASE)
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/frontend/tools/utils/seed/tasks_tools.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as util from 'gulp-util';
3 | import * as chalk from 'chalk';
4 | import * as isstream from 'isstream';
5 | import {readdirSync, existsSync, lstatSync} from 'fs';
6 | import {join} from 'path';
7 |
8 |
9 | export function loadTasks(path: string): void {
10 | util.log('Loading tasks folder', chalk.yellow(path));
11 | readDir(path, taskname => registerTask(taskname, path));
12 | }
13 |
14 | function registerTask(taskname: string, path: string): void {
15 | const TASK = join(path, taskname);
16 | util.log('Registering task', chalk.yellow(TASK));
17 |
18 | gulp.task(taskname, (done: any) => {
19 | const task = require(TASK);
20 | if (task.length > 0) {
21 | return task(done);
22 | }
23 |
24 | const taskReturnedValue = task();
25 | if (isstream(taskReturnedValue)) {
26 | return taskReturnedValue;
27 | }
28 |
29 | // TODO: add promise handling if needed at some point.
30 |
31 | done();
32 | });
33 | }
34 |
35 | function readDir(root: string, cb: (taskname: string) => void) {
36 | if (!existsSync(root)) return;
37 |
38 | walk(root);
39 |
40 | function walk(path: string) {
41 | let files = readdirSync(path);
42 | for (let i = 0; i < files.length; i += 1) {
43 | let file = files[i];
44 | let curPath = join(path, file);
45 | if (lstatSync(curPath).isFile() && /\.ts$/.test(file)) {
46 | let taskname = file.replace(/(\.ts)/, '');
47 | cb(taskname);
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/frontend/tools/utils/seed/template_locals.ts:
--------------------------------------------------------------------------------
1 | import * as CONFIG from '../../config';
2 |
3 | // TODO: Add an interface to register more template locals.
4 | export function templateLocals() {
5 | return CONFIG;
6 | }
7 |
--------------------------------------------------------------------------------
/frontend/tools/utils/seed/tsproject.ts:
--------------------------------------------------------------------------------
1 | import * as gulpLoadPlugins from 'gulp-load-plugins';
2 | const plugins = gulpLoadPlugins();
3 |
4 | let _tsProject: any;
5 |
6 | export function makeTsProject() {
7 | if (!_tsProject) {
8 | _tsProject = plugins.typescript.createProject('tsconfig.json', {
9 | typescript: require('typescript')
10 | });
11 | }
12 | return _tsProject;
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/tools/utils/seed/watch.ts:
--------------------------------------------------------------------------------
1 | import * as runSequence from 'run-sequence';
2 | import {notifyLiveReload} from '../../utils';
3 | import * as gulpLoadPlugins from 'gulp-load-plugins';
4 | import {join} from 'path';
5 | import {APP_SRC} from '../../config';
6 | const plugins = gulpLoadPlugins();
7 |
8 | export function watch(taskname: string) {
9 | return function () {
10 | plugins.watch(join(APP_SRC, '**'), (e:any) =>
11 | runSequence(taskname, () => notifyLiveReload(e))
12 | );
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "declaration": false,
6 | "removeComments": true,
7 | "noLib": false,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "sourceMap": true,
11 | "pretty": true,
12 | "allowUnreachableCode": false,
13 | "allowUnusedLabels": false,
14 | "noImplicitAny": false,
15 | "noImplicitReturns": true,
16 | "noImplicitUseStrict": false,
17 | "noFallthroughCasesInSwitch": true
18 | },
19 | "exclude": [
20 | "node_modules",
21 | "typings/browser.d.ts",
22 | "typings/browser"
23 | ],
24 | "compileOnSave": false
25 | }
26 |
--------------------------------------------------------------------------------
/frontend/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": ["node_modules/ng2lint/dist/src"],
3 | "rules": {
4 | "class-name": true,
5 | "curly": false,
6 | "eofline": true,
7 | "indent": ["spaces"],
8 | "max-line-length": [true, 140],
9 | "member-ordering": [true,
10 | "public-before-private",
11 | "static-before-instance",
12 | "variables-before-functions"
13 | ],
14 | "no-arg": true,
15 | "no-construct": true,
16 | "no-duplicate-key": true,
17 | "no-duplicate-variable": true,
18 | "no-empty": true,
19 | "no-eval": true,
20 | "no-trailing-whitespace": true,
21 | "no-unused-expression": true,
22 | "no-unused-variable": true,
23 | "no-unreachable": true,
24 | "no-use-before-declare": true,
25 | "one-line": [true,
26 | "check-open-brace",
27 | "check-catch",
28 | "check-else",
29 | "check-whitespace"
30 | ],
31 | "quotemark": [true, "single"],
32 | "semicolon": true,
33 | "trailing-comma": true,
34 | "triple-equals": true,
35 | "variable-name": false,
36 |
37 | "component-selector-name": [true, "kebab-case"],
38 | "component-selector-type": [true, "element"],
39 | "host-parameter-decorator": true,
40 | "input-parameter-decorator": true,
41 | "output-parameter-decorator": true,
42 | "attribute-parameter-decorator": true,
43 | "input-property-directive": true,
44 | "output-property-directive": true
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/frontend/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "xhr2": "github:gdi2290/typed-xhr2#69f2b8d40d0cd407c1b2a2f2f41fecc6852cabbb"
4 | },
5 | "devDependencies": {},
6 | "ambientDependencies": {
7 | "Q": "github:DefinitelyTyped/DefinitelyTyped/q/Q.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
8 | "angular-protractor": "github:DefinitelyTyped/DefinitelyTyped/angular-protractor/angular-protractor.d.ts#64b25f63f0ec821040a5d3e049a976865062ed9d",
9 | "async": "github:DefinitelyTyped/DefinitelyTyped/async/async.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
10 | "browser-sync": "github:DefinitelyTyped/DefinitelyTyped/browser-sync/browser-sync.d.ts#d9b5b35ba3a79ac778c5890531393442439df5dd",
11 | "chalk": "github:DefinitelyTyped/DefinitelyTyped/chalk/chalk.d.ts#5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff",
12 | "chokidar": "github:DefinitelyTyped/DefinitelyTyped/chokidar/chokidar.d.ts#ae81e340a9e897167cfef3122a5a3aed04293814",
13 | "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#6697d6f7dadbf5773cb40ecda35a76027e0783b2",
14 | "express": "github:DefinitelyTyped/DefinitelyTyped/express/express.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
15 | "glob": "github:DefinitelyTyped/DefinitelyTyped/glob/glob.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
16 | "gulp": "github:DefinitelyTyped/DefinitelyTyped/gulp/gulp.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
17 | "gulp-load-plugins": "github:DefinitelyTyped/DefinitelyTyped/gulp-load-plugins/gulp-load-plugins.d.ts#e081148d88b857d66509e3b46edbd08b3f75f96a",
18 | "gulp-shell": "github:DefinitelyTyped/DefinitelyTyped/gulp-shell/gulp-shell.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
19 | "gulp-util": "github:DefinitelyTyped/DefinitelyTyped/gulp-util/gulp-util.d.ts#5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff",
20 | "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#26c98c8a9530c44f8c801ccc3b2057e2101187ee",
21 | "micromatch": "github:DefinitelyTyped/DefinitelyTyped/micromatch/micromatch.d.ts#7cda84786520fd0673c934fde1aa722083e05f7b",
22 | "mime": "github:DefinitelyTyped/DefinitelyTyped/mime/mime.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
23 | "minimatch": "github:DefinitelyTyped/DefinitelyTyped/minimatch/minimatch.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
24 | "ng2": "github:gdi2290/typings-ng2/ng2.d.ts#32998ff5584c0eab0cd9dc7704abb1c5c450701c",
25 | "node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#138ad74b9e8e6c08af7633964962835add4c91e2",
26 | "orchestrator": "github:DefinitelyTyped/DefinitelyTyped/orchestrator/orchestrator.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
27 | "parse-glob": "github:DefinitelyTyped/DefinitelyTyped/parse-glob/parse-glob.d.ts#1ae2ddf27c6e9b98ad7e7fa496788f1aadf37933",
28 | "rimraf": "github:DefinitelyTyped/DefinitelyTyped/rimraf/rimraf.d.ts#09f3d7a8dc79f448b538862c3ad5872f75112d60",
29 | "run-sequence": "github:DefinitelyTyped/DefinitelyTyped/run-sequence/run-sequence.d.ts#052725d74978d6b8d7c4ff537b5a3b21ee755a49",
30 | "selenium-webdriver": "github:DefinitelyTyped/DefinitelyTyped/selenium-webdriver/selenium-webdriver.d.ts#a83677ed13add14c2ab06c7325d182d0ba2784ea",
31 | "serve-static": "github:DefinitelyTyped/DefinitelyTyped/serve-static/serve-static.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
32 | "systemjs": "github:DefinitelyTyped/DefinitelyTyped/systemjs/systemjs.d.ts#5c3e47967affa3c4128a3875d1664ba206ae1b0f",
33 | "through2": "github:DefinitelyTyped/DefinitelyTyped/through2/through2.d.ts#5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff",
34 | "vinyl": "github:DefinitelyTyped/DefinitelyTyped/vinyl/vinyl.d.ts#5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff",
35 | "vinyl-source-stream": "github:DefinitelyTyped/DefinitelyTyped/vinyl-source-stream/vinyl-source-stream.d.ts#ffceea9dd124d277c4597c7bd12930666ec074c5",
36 | "yargs": "github:DefinitelyTyped/DefinitelyTyped/yargs/yargs.d.ts#6a287502dab374e7d4cbf18ea1ac5dff7f74726a",
37 | "zone.js": "github:DefinitelyTyped/DefinitelyTyped/zone.js/zone.js.d.ts#b923a5aaf013ac84c566f27ba6b5843211981c7a"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/frontend/www/assets/main.css:
--------------------------------------------------------------------------------
1 | /* Reset */
2 | html,
3 | body,
4 | div {
5 | border: 0;
6 | margin: 0;
7 | padding: 0;
8 | }
9 |
10 | /* Box-sizing border-box */
11 | * {
12 | box-sizing: border-box;
13 | }
14 |
15 | /* Set up a default font and some padding to provide breathing room */
16 | body {
17 | font-family: Roboto, "Helvetica Neue", sans-serif;
18 | font-size: 16px;
19 | -webkit-font-smoothing: antialiased;
20 | -moz-osx-font-smoothing: grayscale;
21 | }
22 |
23 | p {
24 | font-weight: 400;
25 | letter-spacing: 0.01em;
26 | line-height: 20px;
27 | margin-bottom: 1em;
28 | margin-top: 1em;
29 | }
30 |
31 | ul {
32 | margin: 10px 0 0 0;
33 | padding: 0 0 0 20px;
34 | }
35 |
36 | li {
37 | font-weight: 400;
38 | margin-top: 4px;
39 | }
40 |
41 | input {
42 | border: 1px solid #106cc8;
43 | font-size: 14px;
44 | height: 40px;
45 | outline: none;
46 | padding: 8px;
47 | }
48 |
49 | button {
50 | background-color: #106cc8;
51 | border-style: none;
52 | color: rgba(255, 255, 255, 0.87);
53 | cursor: pointer;
54 | display: inline-block;
55 | font-size: 14px;
56 | height: 40px;
57 | padding: 8px 18px;
58 | text-decoration: none;
59 | }
60 |
61 | button:hover {
62 | background-color: #28739e;
63 | }
64 |
65 | .form-signin { margin-top: 90px; }
66 |
67 | .top-buffer { margin-top: 20px; }
68 |
69 | .block { width: 100%; }
70 |
--------------------------------------------------------------------------------
/frontend/www/assets/svg/more.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/frontend/www/components/app.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {ROUTER_DIRECTIVES, RouteConfig} from 'angular2/router';
3 | import {TasksComponent} from './tasks';
4 | import {LoginComponent} from './login';
5 | import {RegistrationComponent} from './registration';
6 |
7 | @Component({
8 | selector: 'app',
9 | moduleId: module.id,
10 | templateUrl: '../templates/app.html',
11 | directives: [ROUTER_DIRECTIVES]
12 | })
13 |
14 | @RouteConfig([
15 | { path: '/tasks', name: 'Tasks', component: TasksComponent, useAsDefault: true },
16 | { path: '/login', name: 'Login', component: LoginComponent },
17 | { path: '/registration', name: 'Registration', component: RegistrationComponent }
18 | ])
19 |
20 | export class AppComponent {
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/www/components/login.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {ROUTER_DIRECTIVES} from 'angular2/router';
3 | import {AuthService} from '../services/auth';
4 |
5 | @Component({
6 | moduleId: module.id,
7 | templateUrl: '../templates/login.html',
8 | directives: [ROUTER_DIRECTIVES]
9 | })
10 |
11 | export class LoginComponent {
12 | user: {};
13 |
14 | constructor(private _authService: AuthService) {
15 | this.user = {};
16 | }
17 |
18 | login() {
19 | this._authService.login(this.user);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/www/components/navbar.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {ROUTER_DIRECTIVES} from 'angular2/router';
3 | import {AuthService} from '../services/auth';
4 |
5 | @Component({
6 | selector: 'navbar',
7 | moduleId: module.id,
8 | templateUrl: '../templates/navbar.html',
9 | directives: [ROUTER_DIRECTIVES]
10 | })
11 |
12 | export class NavbarComponent {
13 | constructor(private _authService: AuthService) {
14 | }
15 |
16 | logout() {
17 | this._authService.logout();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/frontend/www/components/registration.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {AuthService} from '../services/auth';
3 | import {ROUTER_DIRECTIVES} from 'angular2/router';
4 | import {FORM_BINDINGS,FormBuilder,ControlGroup,Validators} from 'angular2/common';
5 |
6 | @Component({
7 | moduleId: module.id,
8 | templateUrl: '../templates/registration.html',
9 | directives: [ROUTER_DIRECTIVES],
10 | viewBindings: [FORM_BINDINGS]
11 | })
12 |
13 | export class RegistrationComponent {
14 | registerForm: ControlGroup;
15 |
16 | constructor(private _authService: AuthService, fb: FormBuilder) {
17 | this.registerForm = fb.group({
18 | email: ['', Validators.required],
19 | password: ['', Validators.compose([Validators.required, Validators.minLength(8)])],
20 | password_confirmation: ['', Validators.compose([Validators.required, Validators.minLength(8)])]
21 | }, {validator: this.matchingPasswords('password', 'password_confirmation')});
22 | }
23 |
24 | registration() {
25 | this._authService.registration(this.registerForm.value);
26 | }
27 |
28 | matchingPasswords(passwordKey: string, passwordConfirmationKey: string) {
29 | return (group: ControlGroup) => {
30 | let passwordInput = group.controls[passwordKey];
31 | let passwordConfirmationInput = group.controls[passwordConfirmationKey];
32 | if (passwordInput.value !== passwordConfirmationInput.value) {
33 | return passwordConfirmationInput.setErrors({notEquivalent: true});
34 | }
35 | };
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/frontend/www/components/tasks.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {CanActivate} from 'angular2/router';
3 | import {TaskListComponent} from './tasks/list';
4 | import {TaskFormComponent} from './tasks/form';
5 | import {NavbarComponent} from './navbar';
6 |
7 | @Component({
8 | moduleId: module.id,
9 | templateUrl: '../templates/tasks.html',
10 | directives: [TaskListComponent, TaskFormComponent, NavbarComponent]
11 | })
12 |
13 | @CanActivate(()=> {
14 | if(!localStorage.getItem('token')) {
15 | window.location.pathname = '/login';
16 | return false;
17 | }
18 | return true;
19 | })
20 |
21 | export class TasksComponent {
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/www/components/tasks/form.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {Task} from '../../models/task';
3 | import {TaskService} from '../../services/task';
4 |
5 | @Component({
6 | selector: 'task-form',
7 | moduleId: module.id,
8 | templateUrl: '../../templates/tasks/form.html',
9 | })
10 |
11 | export class TaskFormComponent {
12 | task: Task;
13 |
14 | constructor(private _taskService: TaskService) {
15 | this.task = new Task('', '');
16 | }
17 |
18 | submit() {
19 | this._taskService.create(this.task);
20 | this.task = new Task('', '');
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/www/components/tasks/list.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {Observable} from 'rxjs/Observable';
3 | import {Task} from '../../models/task';
4 | import {TaskService} from '../../services/task';
5 | import {ByFieldPipe} from '../../pipes/by_field';
6 |
7 | @Component({
8 | selector: 'task-list',
9 | pipes: [ByFieldPipe],
10 | moduleId: module.id,
11 | templateUrl: '../../templates/tasks/list.html',
12 | })
13 |
14 | export class TaskListComponent {
15 | tasks: Observable;
16 | editForm: {};
17 |
18 | constructor(private _taskService: TaskService) {
19 | this.editForm = {};
20 | this.tasks = this._taskService.tasks$;
21 | this._taskService.load();
22 | }
23 |
24 | delete(task) {
25 | if (confirm('Are you sure?')) {
26 | this._taskService.delete(task.id);
27 | };
28 | return false;
29 | }
30 |
31 | update (task) {
32 | this._taskService.update(task);
33 | return false;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/frontend/www/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= APP_TITLE %>
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Loading...
17 |
18 |
35 |
36 |
40 |
41 |
42 |
43 |
44 | <% if (ENV === 'dev') { %>
45 |
50 | <% } %>
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | <% if (ENV === 'dev') { %>
59 |
66 | <% } %>
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/frontend/www/main.ts:
--------------------------------------------------------------------------------
1 | import {provide, enableProdMode} from 'angular2/core';
2 | import {bootstrap} from 'angular2/platform/browser';
3 | import {ROUTER_PROVIDERS, APP_BASE_HREF} from 'angular2/router';
4 | import {HTTP_PROVIDERS, HTTP_BINDINGS, Http} from 'angular2/http';
5 | import {AuthHttp, AuthConfig} from 'angular2-jwt/angular2-jwt';
6 | import 'rxjs/add/operator/map';
7 | import {AppComponent} from './components/app';
8 | import {TaskService} from './services/task';
9 | import {AuthService} from './services/auth';
10 |
11 | if ('<%= ENV %>' === 'prod') { enableProdMode(); }
12 |
13 | bootstrap(AppComponent, [
14 | ROUTER_PROVIDERS,
15 | HTTP_PROVIDERS,
16 | HTTP_BINDINGS,
17 | TaskService,
18 | AuthService,
19 | provide(APP_BASE_HREF, { useValue: '<%= APP_BASE %>' }),
20 | provide(AuthHttp, {
21 | useFactory: (http) => {
22 | return new AuthHttp(new AuthConfig({
23 | headerName: 'Authorization',
24 | headerPrefix: 'Bearer',
25 | tokenName: 'token',
26 | tokenGetter: (() => localStorage.getItem('token')),
27 | noJwtError: false
28 | }), http);
29 | },
30 | deps: [Http]
31 | })
32 | ]);
33 |
--------------------------------------------------------------------------------
/frontend/www/models/task.ts:
--------------------------------------------------------------------------------
1 | export class Task {
2 | id: number;
3 | name: string;
4 | description: string;
5 | done: boolean;
6 |
7 | constructor(name: string, description: string, done?: boolean, id?: number) {
8 | this.id = id || null;
9 | this.name = name;
10 | this.description = description;
11 | this.done = done || false;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/www/pipes/by_field.ts:
--------------------------------------------------------------------------------
1 | import {Pipe} from 'angular2/core';
2 |
3 | @Pipe({
4 | name: 'byField',
5 | pure: false
6 | })
7 |
8 | export class ByFieldPipe {
9 | transform(items, arg) {
10 | if(items) {
11 | return items.filter((item)=> item[arg[0]] === arg[1]);
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/www/services/auth.ts:
--------------------------------------------------------------------------------
1 | import {Injectable} from 'angular2/core';
2 | import {Http, Headers} from 'angular2/http';
3 | import {Router} from 'angular2/router';
4 |
5 | @Injectable()
6 | export class AuthService {
7 | private headers;
8 |
9 | constructor(public router: Router, public http: Http) {
10 | this.headers = new Headers({'Content-Type': 'application/json'});
11 | }
12 |
13 | login(user) {
14 | let body = JSON.stringify(user);
15 | this.http.post('/api/sessions', body, { headers: this.headers }).subscribe(
16 | response => {
17 | localStorage.setItem('token', response.json().token);
18 | this.router.navigate(['Tasks']);
19 | },
20 | error => {
21 | alert(error.text());
22 | }
23 | );
24 | }
25 |
26 | logout() {
27 | localStorage.clear();
28 | this.router.navigate(['Login']);
29 | }
30 |
31 | registration(user) {
32 | let body = JSON.stringify({user: user});
33 | this.http.post('/api/users', body, { headers: this.headers }).subscribe(
34 | response => {
35 | localStorage.setItem('token', response.json().token);
36 | this.router.navigate(['Tasks']);
37 | },
38 | error => {
39 | alert(error.text());
40 | }
41 | );
42 | }
43 |
44 | isCurrentUser() {
45 | if(!localStorage.getItem('token')) {
46 | this.router.navigate(['Login']);
47 | return false;
48 | }
49 | return true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/frontend/www/services/task.ts:
--------------------------------------------------------------------------------
1 | import {Injectable} from 'angular2/core';
2 | import {Headers} from 'angular2/http';
3 | import {AuthHttp} from 'angular2-jwt/angular2-jwt';
4 | import {Observable} from 'rxjs/Observable';
5 | import {Observer} from 'rxjs/Observer';
6 | import 'rxjs/add/operator/share';
7 | import 'rxjs/add/operator/map';
8 | import {Task} from '../models/task';
9 |
10 | @Injectable()
11 | export class TaskService {
12 | tasks$: Observable;
13 | private _tasksObserver: Observer;
14 | private _dataStore: {
15 | tasks: Task[];
16 | };
17 | private headers;
18 |
19 | constructor(private authHttp: AuthHttp) {
20 | this.headers = new Headers({'Content-Type': 'application/json'});
21 | this.tasks$ = new Observable(observer =>
22 | this._tasksObserver = observer).share();
23 | this._dataStore = { tasks: [] };
24 | }
25 |
26 | load() {
27 | this.authHttp.get('/api/tasks').map(response => response.json()).subscribe(data => {
28 | this._dataStore.tasks = data;
29 | this._tasksObserver.next(this._dataStore.tasks);
30 | }, error => console.log('Could not load tasks.'));
31 | }
32 |
33 | create(task) {
34 | this.authHttp.post('/api/tasks', JSON.stringify({task: task}), { headers: this.headers })
35 | .map(response => response.json()).subscribe(data => {
36 | this._dataStore.tasks.unshift(data);
37 | this._tasksObserver.next(this._dataStore.tasks);
38 | }, error => console.log('Could not create task.'));
39 | }
40 |
41 | update(task) {
42 | this.authHttp.put(`/api/tasks/${task.id}`, JSON.stringify({task: task}), { headers: this.headers })
43 | .map(response => response.json()).subscribe(data => {
44 | this._dataStore.tasks.forEach((task, i) => {
45 | if (task.id === data.id) { this._dataStore.tasks[i] = data; }
46 | });
47 |
48 | this._tasksObserver.next(this._dataStore.tasks);
49 | }, error => console.log('Could not update task.'));
50 | }
51 |
52 | delete(taskId: number) {
53 | this.authHttp.delete(`/api/tasks/${taskId}`).subscribe(response => {
54 | this._dataStore.tasks.forEach((t, index) => {
55 | if (t.id === taskId) { this._dataStore.tasks.splice(index, 1); }
56 | });
57 |
58 | this._tasksObserver.next(this._dataStore.tasks);
59 | }, error => console.log('Could not delete task.'));
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/frontend/www/sw.js:
--------------------------------------------------------------------------------
1 | // Cache then network strategy
2 | // https://jakearchibald.com/2014/offline-cookbook/#cache-then-network
3 | self.addEventListener('fetch', function(event) {
4 | event.respondWith(
5 | caches.open('angular2-seed').then(function(cache) {
6 | return fetch(event.request).then(function(response) {
7 | cache.put(event.request, response.clone());
8 | return response;
9 | });
10 | })
11 | );
12 | });
13 |
--------------------------------------------------------------------------------
/frontend/www/templates/app.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/frontend/www/templates/login.html:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/frontend/www/templates/navbar.html:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/frontend/www/templates/registration.html:
--------------------------------------------------------------------------------
1 |
25 |
--------------------------------------------------------------------------------
/frontend/www/templates/tasks.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Create a new task
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/frontend/www/templates/tasks/form.html:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/frontend/www/templates/tasks/list.html:
--------------------------------------------------------------------------------
1 | My tasks
2 | Active
3 |
25 |
26 | Done
27 |
42 |
--------------------------------------------------------------------------------