├── .editorconfig
├── .gitignore
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── angular.json
├── e2e
├── app.e2e-spec.ts
├── app.po.ts
└── tsconfig.e2e.json
├── karma.conf.js
├── package.json
├── protractor.conf.js
├── scripts
├── backup_branches.sh
├── backup_to_meta.sh
├── delete_backups.sh
├── publish_branches_and_tags.sh
├── publish_jump_start.sh
├── publish_starter.sh
├── rebase.sh
├── reset_local_branches.sh
├── retag.sh
├── rollback_backups.sh
├── safetycheck.js
└── the_magic_button.sh
├── server
├── .jshintrc
├── contacts-server.html
├── contacts-server.js
├── data
│ └── contacts.js
└── voting-server.js
├── src
├── app
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.scss
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── contacts-material.module.ts
│ ├── data
│ │ ├── contact-data.ts
│ │ ├── contact-manager.ts
│ │ ├── countries-data.ts
│ │ └── gender.ts
│ ├── models
│ │ └── contact.ts
│ └── shared
│ │ └── index.ts
├── assets
│ ├── .gitkeep
│ ├── .npmignore
│ ├── favicons
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── mstile-150x150.png
│ │ ├── safari-pinned-tab.svg
│ │ └── site.webmanifest
│ └── images
│ │ ├── 0.jpg
│ │ ├── 1.jpg
│ │ ├── 10.jpg
│ │ ├── 11.jpg
│ │ ├── 2.jpg
│ │ ├── 3.jpg
│ │ ├── 4.jpg
│ │ ├── 5.jpg
│ │ ├── 6.jpg
│ │ ├── 7.jpg
│ │ ├── 8.jpg
│ │ ├── 9.jpg
│ │ ├── placeholder.png
│ │ └── team.jpg
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.scss
├── test.ts
├── testing
│ ├── custom-matchers.ts
│ └── helpers.ts
└── typings.d.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
├── tslint.json
├── webpack.config.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /dist-server
6 | /tmp
7 | /out-tsc
8 |
9 | # dependencies
10 | /node_modules
11 |
12 | # IDEs and editors
13 | /.idea
14 | .project
15 | .classpath
16 | .c9/
17 | *.launch
18 | .settings/
19 | *.sublime-workspace
20 |
21 | # IDE - VSCode
22 | .vscode/*
23 | !.vscode/settings.json
24 | !.vscode/tasks.json
25 | !.vscode/launch.json
26 | !.vscode/extensions.json
27 |
28 | # misc
29 | /.sass-cache
30 | /connect.lock
31 | /coverage
32 | /libpeerconnection.log
33 | npm-debug.log
34 | yarn-error.log
35 | testem.log
36 | /typings
37 |
38 | # e2e
39 | /e2e/*.js
40 | /e2e/*.map
41 |
42 | # System Files
43 | .DS_Store
44 | Thumbs.db
45 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | package.json
3 | package-lock.json
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "singleQuote": true,
4 | "useTabs": false,
5 | "tabWidth": 2,
6 | "semi": true,
7 | "bracketSpacing": true
8 | }
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | thoughtram Training Material License (TTML 1.0)
2 |
3 | Copyright (c) 2016 thoughtram GmbH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in the
7 | Software with very limited restrictions. Any person has the right to use, copy,
8 | modify, merge, publish, distribute, sublicense. It’s not permitted to use the
9 | Software to run or support trainings without exclusive allowance from thoughtram GmbH.
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular Master Class by thoughtram
2 |
3 | This is the Angular Master Class exercise repository. Here's where you'll build your Angular application throughout this training.
4 |
5 | Please make sure to follow our [Preparation Guide](http://thoughtram.io/prepare-for-your-training.html) to set up your machine **before** you come to the class.
6 |
7 | If not done already, clone this repository using:
8 |
9 | ```
10 | $ git clone https://github.com/thoughtram/angular-master-class-starter.git
11 | ```
12 |
13 | Done? Great, now install the dependencies (this might take a little while):
14 |
15 | ```
16 | $ cd angular-master-class-starter
17 | $ npx yarn install
18 | ```
19 |
20 | Then run the application by executing:
21 |
22 | ```
23 | $ ng serve
24 | ```
25 |
26 | Then open up your browser at `http://localhost:4200`
27 |
28 | Have fun and good luck!
29 |
30 | Christoph & Pascal & Dominic
31 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "contacts-app": {
7 | "root": "",
8 | "sourceRoot": "src",
9 | "projectType": "application",
10 | "prefix": "trm",
11 | "schematics": {
12 | "@schematics/angular:component": {
13 | "style": "scss"
14 | }
15 | },
16 | "architect": {
17 | "build": {
18 | "builder": "@angular-devkit/build-angular:browser",
19 | "options": {
20 | "outputPath": "dist/contacts-app",
21 | "index": "src/index.html",
22 | "main": "src/main.ts",
23 | "polyfills": "src/polyfills.ts",
24 | "tsConfig": "tsconfig.app.json",
25 | "assets": [
26 | "src/favicon.ico",
27 | "src/assets"
28 | ],
29 | "styles": [
30 | "src/styles.scss"
31 | ],
32 | "scripts": [
33 | "./node_modules/hammerjs/hammer.js"
34 | ]
35 | },
36 | "configurations": {
37 | "production": {
38 | "fileReplacements": [
39 | {
40 | "replace": "src/environments/environment.ts",
41 | "with": "src/environments/environment.prod.ts"
42 | }
43 | ],
44 | "optimization": true,
45 | "outputHashing": "all",
46 | "sourceMap": false,
47 | "extractCss": true,
48 | "namedChunks": false,
49 | "aot": true,
50 | "extractLicenses": true,
51 | "vendorChunk": false,
52 | "buildOptimizer": true
53 | }
54 | }
55 | },
56 | "serve": {
57 | "builder": "@angular-devkit/build-angular:dev-server",
58 | "options": {
59 | "browserTarget": "contacts-app:build"
60 | },
61 | "configurations": {
62 | "production": {
63 | "browserTarget": "contacts-app:build:production"
64 | }
65 | }
66 | },
67 | "extract-i18n": {
68 | "builder": "@angular-devkit/build-angular:extract-i18n",
69 | "options": {
70 | "browserTarget": "contacts-app:build"
71 | }
72 | },
73 | "test": {
74 | "builder": "@angular-devkit/build-angular:karma",
75 | "options": {
76 | "main": "src/test.ts",
77 | "polyfills": "src/polyfills.ts",
78 | "tsConfig": "tsconfig.spec.json",
79 | "karmaConfig": "karma.conf.js",
80 | "styles": [
81 | "src/styles.scss"
82 | ],
83 | "scripts": [],
84 | "assets": [
85 | "src/favicon.ico",
86 | "src/assets"
87 | ]
88 | }
89 | },
90 | "lint": {
91 | "builder": "@angular-devkit/build-angular:tslint",
92 | "options": {
93 | "tsConfig": [
94 | "tsconfig.app.json",
95 | "tsconfig.spec.json",
96 | "e2e/tsconfig.json"
97 | ],
98 | "exclude": [
99 | "**/node_modules/**"
100 | ]
101 | }
102 | }
103 | }
104 | },
105 | "contacts-app-e2e": {
106 | "root": "e2e/",
107 | "projectType": "application",
108 | "architect": {
109 | "e2e": {
110 | "builder": "@angular-devkit/build-angular:protractor",
111 | "options": {
112 | "protractorConfig": "e2e/protractor.conf.js",
113 | "devServerTarget": "contacts-app:serve"
114 | }
115 | },
116 | "lint": {
117 | "builder": "@angular-devkit/build-angular:tslint",
118 | "options": {
119 | "tsConfig": "e2e/tsconfig.e2e.json",
120 | "exclude": [
121 | "**/node_modules/**"
122 | ]
123 | }
124 | }
125 | }
126 | }
127 | },
128 | "defaultProject": "contacts-app"
129 | }
130 |
--------------------------------------------------------------------------------
/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 |
3 | describe('amc-solutions App', () => {
4 | let page: AppPage;
5 |
6 | beforeEach(() => {
7 | page = new AppPage();
8 | });
9 |
10 | it('should display welcome message', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('Welcome to app!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/e2e/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/e2e/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/e2e",
5 | "baseUrl": "./",
6 | "module": "commonjs",
7 | "target": "es5",
8 | "types": [
9 | "jasmine",
10 | "jasminewd2",
11 | "node"
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-mocha-reporter'),
13 | require('karma-coverage-istanbul-reporter'),
14 | require('@angular-devkit/build-angular/plugins/karma')
15 | ],
16 | client:{
17 | clearContext: false // leave Jasmine Spec Runner output visible in browser
18 | },
19 | coverageIstanbulReporter: {
20 | dir: require('path').join(__dirname, '../coverage'),
21 | reports: [ 'html', 'lcovonly' ],
22 | fixWebpackSourcePaths: true
23 | },
24 | reporters: ['mocha', 'kjhtml'],
25 | port: 9876,
26 | colors: true,
27 | logLevel: config.LOG_INFO,
28 | autoWatch: true,
29 | browsers: ['Chrome'],
30 | singleRun: false
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-master-class-app",
3 | "version": "5.1.1",
4 | "license": "thoughtram Training Material License (TTML 1.0)",
5 | "scripts": {
6 | "ng": "ng",
7 | "start": "ng serve",
8 | "serve:ssr": "npm run build:ssr && node dist/server.js",
9 | "build": "ng build --prod",
10 | "build:server": "ng run contacts-app:server -- --output-hashing=none",
11 | "build:ssr": "npm run build && npm run build:server && npm run webpack:server",
12 | "webpack:server": "webpack --config webpack.config.js --progress --colors",
13 | "prettier": "prettier --config .prettierrc --ignore-path .prettierignore",
14 | "format:base": "npm run prettier -- \"{src,e2e}/**/*{.ts,.js,.json,.css,.scss}\"",
15 | "format:check": "npm run format:base -- --list-different",
16 | "format:fix": "npm run format:base -- --write",
17 | "test": "ng test",
18 | "lint": "ng lint",
19 | "e2e": "ng e2e",
20 | "vote-server": "node server/voting-server.js",
21 | "rest-api": "node server/contacts-server.js"
22 | },
23 | "private": true,
24 | "dependencies": {
25 | "@angular/animations": "~12.1.1",
26 | "@angular/cdk": "~12.1.1",
27 | "@angular/common": "~12.1.1",
28 | "@angular/compiler": "~12.1.1",
29 | "@angular/core": "~12.1.1",
30 | "@angular/flex-layout": "12.0.0-beta.34",
31 | "@angular/forms": "~12.1.1",
32 | "@angular/http": "8.0.0-beta.10",
33 | "@angular/material": "~12.1.1",
34 | "@angular/platform-browser": "~12.1.1",
35 | "@angular/platform-browser-dynamic": "~12.1.1",
36 | "@angular/platform-server": "~12.1.1",
37 | "@angular/router": "~12.1.1",
38 | "@angular/service-worker": "~12.1.1",
39 | "@ngrx/effects": "7.0.0",
40 | "@ngrx/store": "7.0.0",
41 | "@ngrx/store-devtools": "7.0.0",
42 | "@nguniversal/express-engine": "9.1.0",
43 | "@nguniversal/module-map-ngfactory-loader": "7.0.2",
44 | "@thoughtram/amc-demo-lib": "1.0.1",
45 | "ngrx-store-freeze": "0.2.4",
46 | "redux": "4.0.5",
47 | "redux-thunk": "2.3.0",
48 | "rxjs": "6.6.3",
49 | "tslib": "2.1.0",
50 | "zone.js": "~0.11.4"
51 | },
52 | "devDependencies": {
53 | "@angular-devkit/build-angular": "~12.1.1",
54 | "@angular/cli": "~12.1.1",
55 | "@angular/compiler-cli": "~12.1.1",
56 | "@angular/language-service": "~12.1.1",
57 | "@angular/pwa": "12.1.1",
58 | "@types/jasmine": "~3.6.0",
59 | "@types/jasminewd2": "~2.0.2",
60 | "@types/node": "13.13.5",
61 | "codelyzer": "6.0.1",
62 | "cors": "2.8.0",
63 | "hammerjs": "2.0.8",
64 | "jasmine-core": "~3.7.0",
65 | "jasmine-spec-reporter": "~5.0.0",
66 | "karma": "~6.3.0",
67 | "karma-chrome-launcher": "~3.1.0",
68 | "karma-coverage-istanbul-reporter": "^1.2.1",
69 | "karma-jasmine": "~4.0.0",
70 | "karma-jasmine-html-reporter": "^1.5.0",
71 | "karma-mocha-reporter": "2.2.3",
72 | "ng-packagr": "^2.1.0",
73 | "prettier": "1.14.2",
74 | "protractor": "~7.0.0",
75 | "semver": "^5.3.0",
76 | "ts-loader": "^4.4.1",
77 | "ts-node": "~8.3.0",
78 | "tslint": "~6.1.0",
79 | "typescript": "~4.3.2",
80 | "webpack-cli": "^3.0.4"
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // Protractor configuration file, see link for more information
2 | // https://github.com/angular/protractor/blob/master/lib/config.ts
3 |
4 | const { SpecReporter } = require('jasmine-spec-reporter');
5 |
6 | exports.config = {
7 | allScriptsTimeout: 11000,
8 | specs: [
9 | './e2e/**/*.e2e-spec.ts'
10 | ],
11 | capabilities: {
12 | 'browserName': 'chrome'
13 | },
14 | directConnect: true,
15 | baseUrl: 'http://localhost:4200/',
16 | framework: 'jasmine',
17 | jasmineNodeOpts: {
18 | showColors: true,
19 | defaultTimeoutInterval: 30000,
20 | print: function() {}
21 | },
22 | onPrepare() {
23 | require('ts-node').register({
24 | project: 'e2e/tsconfig.e2e.json'
25 | });
26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/scripts/backup_branches.sh:
--------------------------------------------------------------------------------
1 | git branch -f observables_backup observables
2 | git branch -f architecture_backup architecture
3 | git branch -f forms_backup forms
4 | git branch -f routing_backup routing
5 | git branch -f redux_backup redux
6 | git branch -f ngrx_backup ngrx
7 | git branch -f testing_backup testing
8 | #git branch -f reusable-libraries_backup reusable-libraries
9 | git branch -f pwa_backup pwa
10 | git branch -f universal_backup universal
11 |
--------------------------------------------------------------------------------
/scripts/backup_to_meta.sh:
--------------------------------------------------------------------------------
1 | DATE=`date +%d-%m-%Y_%H-%M-%S`
2 |
3 | git push -f meta jump-start:amc_jump-start_$DATE
4 | git push -f meta architecture:amc_architecture_$DATE
5 | git push -f meta observables:amc_observables_$DATE
6 | git push -f meta forms:amc_forms_$DATE
7 | git push -f meta routing:amc_routing_$DATE
8 | git push -f meta redux:amc_redux_$DATE
9 | git push -f meta ngrx:amc_ngrx_$DATE
10 | git push -f meta testing:amc_testing_$DATE
11 | #git push -f meta reusable-libraries:amc_reusable-libraries_$DATE
12 | git push -f meta pwa:amc_pwa_$DATE
13 | git push -f meta universal:amc_universal_$DATE
14 |
--------------------------------------------------------------------------------
/scripts/delete_backups.sh:
--------------------------------------------------------------------------------
1 | git branch -D architecture_backup
2 | git branch -D forms_backup
3 | git branch -D observables_backup
4 | git branch -D routing_backup
5 | git branch -D redux_backup
6 | git branch -D ngrx_backup
7 | git branch -D testing_backup
8 | #git branch -D reusable-libraries_backup
9 | git branch -D pwa_backup
10 | git branch -D universal_backup
11 |
--------------------------------------------------------------------------------
/scripts/publish_branches_and_tags.sh:
--------------------------------------------------------------------------------
1 | # We need the set -e to abort the script when the safetycheck fails
2 | # http://stackoverflow.com/questions/821396/aborting-a-shell-script-if-any-command-returns-a-non-zero-value/821419#821419
3 |
4 | set -e
5 | ./scripts/safetycheck.js
6 |
7 | git push -f --tags origin
8 | git push -f origin jump-start-step-0:master
9 | git push -f origin jump-start
10 | git push -f origin architecture
11 | git push -f origin observables
12 | git push -f origin forms
13 | git push -f origin routing
14 | git push -f origin redux
15 | git push -f origin ngrx
16 | git push -f origin testing
17 | #git push -f origin reusable-libraries
18 | git push -f origin pwa
19 | git push -f origin universal
20 |
--------------------------------------------------------------------------------
/scripts/publish_jump_start.sh:
--------------------------------------------------------------------------------
1 | git checkout jump-start
2 | git push -f jump-start refs/heads/jump-start:refs/heads/master
3 |
--------------------------------------------------------------------------------
/scripts/publish_starter.sh:
--------------------------------------------------------------------------------
1 | git checkout $(git rev-list HEAD | tail -n 1)
2 | git branch -D starter
3 | git checkout -b starter
4 | mv README_starter.md README.md
5 | git add -A .
6 | git commit --amend --no-edit
7 | git push -f starter starter:refs/heads/master
8 | git checkout $(git rev-list redux | tail -n 2 | head -1)
9 | git branch -D redux-starter
10 | git checkout -b redux-starter
11 | git push -f starter redux-starter
12 | git checkout jump-start
13 |
--------------------------------------------------------------------------------
/scripts/rebase.sh:
--------------------------------------------------------------------------------
1 | # create backups first without branch switching. Much safer. Trust me.
2 | ./scripts/backup_branches.sh
3 |
4 | root_commit="$(git rev-list --max-parents=0 jump-start)"
5 |
6 | git checkout observables
7 | git rebase --onto jump-start HEAD~5 HEAD
8 | git branch -f observables
9 |
10 | git checkout architecture
11 | git rebase --onto jump-start HEAD~5 HEAD
12 | git branch -f architecture
13 |
14 | git checkout forms
15 | git rebase --onto jump-start HEAD~9 HEAD
16 | git branch -f forms
17 |
18 | git checkout routing
19 | git rebase --onto jump-start HEAD~5 HEAD
20 | git branch -f routing
21 |
22 | git checkout ngrx
23 | git rebase --onto jump-start HEAD~8 HEAD
24 | git branch -f ngrx
25 |
26 | git checkout pwa
27 | git rebase --onto jump-start HEAD~4 HEAD
28 | git branch -f pwa
29 |
30 | git checkout universal
31 | git rebase --onto jump-start HEAD~2 HEAD
32 | git branch -f universal
33 |
34 | git checkout testing
35 | git rebase --onto architecture HEAD~10 HEAD
36 | git branch -f testing
37 |
38 | git checkout redux
39 | git rebase --onto "${root_commit}" HEAD~7 HEAD
40 | git branch -f redux
41 |
42 | # git checkout reusable-libraries
43 | # git rebase --onto "${root_commit}" HEAD~5 HEAD
44 | # git branch -f reusable-libraries
45 |
46 | git checkout jump-start
47 |
--------------------------------------------------------------------------------
/scripts/reset_local_branches.sh:
--------------------------------------------------------------------------------
1 | resetBranches () {
2 | git fetch --tags origin
3 | echo "checking out origin/jump-start in order be able to reset all local branches"
4 | git checkout origin/jump-start
5 | git branch -f jump-start origin/jump-start
6 | git branch -f observables origin/observables
7 | git branch -f architecture origin/architecture
8 | git branch -f forms origin/forms
9 | git branch -f routing origin/routing
10 | git branch -f redux origin/redux
11 | git branch -f ngrx origin/ngrx
12 | git branch -f testing origin/testing
13 | #git branch -f reusable-libraries origin/reusable-libraries
14 | git branch -f pwa origin/pwa
15 | git branch -f universal origin/universal
16 | }
17 |
18 | echo -n "You are about to *reset* all local branches with latest version from Github. Proceed? (y/n)? "
19 | read answer
20 | if echo "$answer" | grep -iq "^y" ;then
21 | resetBranches
22 | else
23 | echo "kthxbye"
24 | fi
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/scripts/retag.sh:
--------------------------------------------------------------------------------
1 | tagIt () {
2 | git checkout jump-start
3 | gtag root.. jump-start-step-##i $1
4 | git checkout architecture
5 | gtag HEAD~4.. architecture-step-##ii $1
6 | git checkout observables
7 | gtag HEAD~4.. observables-step-##ii $1
8 | git checkout forms
9 | gtag HEAD~8.. forms-step-##ii $1
10 | git checkout routing
11 | gtag HEAD~4.. routing-step-##ii $1
12 | git checkout ngrx
13 | gtag HEAD~7.. ngrx-step-##ii $1
14 | git checkout redux
15 | gtag HEAD~6.. redux-step-##i $1
16 | git checkout testing
17 | gtag HEAD~9.. testing-step-##ii $1
18 | #git checkout reusable-libraries
19 | #gtag HEAD~4.. reusable-libraries-step-##ii $1
20 | git checkout pwa
21 | gtag HEAD~3.. pwa-step-##ii $1
22 | git checkout universal
23 | gtag HEAD~1.. universal-step-##ii $1
24 |
25 | #going back to jump-start as the default branch
26 | git checkout jump-start
27 | }
28 |
29 | echo -n "Wanna do a dry-run first (y/n)? "
30 | read answer
31 | if echo "$answer" | grep -iq "^y" ;then
32 | tagIt --dryrun
33 | else
34 | tagIt
35 | fi
36 |
--------------------------------------------------------------------------------
/scripts/rollback_backups.sh:
--------------------------------------------------------------------------------
1 | git branch -f --move observables_backup observables
2 | git branch -f --move forms_backup forms
3 | git branch -f --move routing_backup routing
4 | git branch -f --move architecture_backup architecture
5 | git branch -f --move redux_backup redux
6 | git branch -f --move ngrx_backup ngrx
7 | git branch -f --move testing_backup testing
8 | #git branch -f --move reusable-libraries_backup reusable-libraries
9 | git branch -f --move pwa_backup pwa
10 | git branch -f --move universal_backup universal
11 |
--------------------------------------------------------------------------------
/scripts/safetycheck.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | let semver = require('semver');
4 | let execSync = require('child_process').execSync;
5 | let chalk = require('chalk');
6 | let spawnOptions = { stdio: 'pipe' };
7 |
8 | let execute = (cmd, supress) => {
9 | try {
10 | let output = execSync(cmd, spawnOptions).toString();
11 | if (!supress) {
12 | console.log(output);
13 | }
14 | return output;
15 | }
16 | catch (e) {
17 | //Doesn't feel write to swallow the exceptions but there doesn't seem
18 | //to be a built in way to supress exceptions if git add and git push fail
19 | }
20 | }
21 |
22 | function getVersionFromRef(ref) {
23 | return JSON.parse(execute(`git show ${ref}:package.json`, true)).version;
24 | }
25 |
26 | const branches = [
27 | 'jump-start',
28 | 'observables',
29 | 'architecture',
30 | 'forms',
31 | 'routing',
32 | 'redux',
33 | 'ngrx',
34 | 'testing',
35 | /*'reusable-libraries',*/
36 | 'pwa',
37 | 'universal'
38 | ]
39 |
40 |
41 | console.log(chalk.green('Fetching from origin to read upstream version...'));
42 | execute(`git fetch origin`)
43 |
44 | let fail = false;
45 |
46 | branches.forEach(branch => {
47 | console.log(chalk.green.bold(`${branch} versions:`));
48 | let remoteVersion = getVersionFromRef(`origin/${branch}`);
49 | let localVersion = getVersionFromRef(branch);
50 |
51 | console.log(chalk.green(`Remote version: ${remoteVersion}`));
52 | console.log(chalk.green(`Local version: ${localVersion}\n`));
53 |
54 | if (semver.lt(localVersion, remoteVersion)){
55 | console.log(chalk.red(`It appears that the local version of your courseware is behind upstream.
56 | Please make sure to base your work on top the latest courseware.
57 | An easy way to reset all your local branches would be ./reset_local_branches.sh
58 | But keep in mind that this will reset all courseware branches to the state
59 | that is on latest GitHub.`));
60 |
61 | fail = true;
62 | }
63 | else if (localVersion === remoteVersion) {
64 | console.log(chalk.green(`The version number of your local courseware matches the one upstream.
65 | This is good! The only thing left to do is to increase the local version number before you deploy.`));
66 | fail = true;
67 | }
68 | });
69 |
70 | if (fail){
71 | process.exit(1);
72 | }
73 |
74 |
75 |
--------------------------------------------------------------------------------
/scripts/the_magic_button.sh:
--------------------------------------------------------------------------------
1 | # We need the set -e to abort the script when the safetycheck fails
2 | # http://stackoverflow.com/questions/821396/aborting-a-shell-script-if-any-command-returns-a-non-zero-value/821419#821419
3 |
4 | set -e
5 |
6 | ./scripts/rebase.sh
7 | ./scripts/retag.sh
8 | ./scripts/publish_branches_and_tags.sh
9 | ./scripts/publish_starter.sh
10 | ./scripts/publish_jump_start.sh
11 | ./scripts/backup_to_meta.sh
12 |
--------------------------------------------------------------------------------
/server/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true
3 | }
4 |
--------------------------------------------------------------------------------
/server/contacts-server.html:
--------------------------------------------------------------------------------
1 |
37 |
38 |
Contacts Server
39 | REST API documentation for the Contacts HTTP server (used in thoughtram AMC).
40 |
41 | -
42 |
43 |
44 | getContacts()
45 |
46 |
47 | /api/contacts
48 | GET
49 | -
50 |
51 |
52 | getContact(id)
53 |
54 |
55 | /api/contacts/:id
57 | GET
58 | -
59 |
60 |
61 | searchContacts(query)
62 |
63 |
64 | /api/search?text==<xxx>
66 | GET
67 | -
68 |
69 |
70 | checkEmail(email)
71 |
72 |
73 | /api/check-email?email=<xxx>
74 | GET
75 |
76 | -
77 | createContact(contact)
78 | /api/contacts/:id
80 | PUT
81 |
82 | -
83 | updateContact(contact)
84 | /api/contacts
86 | PUT
87 |
88 | - deleteContact(id)
89 | /api/contacts/:id
91 | DELETE
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/server/contacts-server.js:
--------------------------------------------------------------------------------
1 | /**
2 | * REST Server for Contacts application
3 | *
4 | * getContacts() '/api/contacts' GET
5 | * getContact(id) '/api/contacts/:id' GET
6 | * searchContacts(query) '/api/search' GET
7 | * checkEmail(email) '/api/check-email' GET
8 | *
9 | * createContact(contact) '/api/contacts/:id' PUT
10 | * updateContact(contact) '/api/contacts' POST
11 | * deleteContact(id) '/api/contacts/:id' DELETE
12 | *
13 | */
14 |
15 | const PATH_API_HTML = './contacts-server.html';
16 |
17 | const fs = require('fs');
18 | const url = require('url');
19 | const db = require('./data/contacts');
20 | const bodyParser = require('body-parser');
21 | const express = require('express');
22 | const cors = require('cors');
23 |
24 | let unorderedResponse = process.argv.includes('--unordered-response');
25 | if (unorderedResponse) {
26 | console.log('Serving search results unordered')
27 | }
28 |
29 | let maxId = db.length;
30 |
31 | const multipleResponse = (items) => { return { items: items } };
32 | const singleResponse = (item) => { return { item: item } };
33 | const getNextId = () => { return maxId++ };
34 | const isContact = (contact) => contact.name !== undefined;
35 | const emailIsAvailable = (email) => {
36 | if (email === '') {
37 | return true;
38 | }
39 | let contact = db.find(contact => contact.email == email);
40 | return contact ? false : true;
41 | }
42 |
43 | // ******************************************************************
44 | // REST Server
45 | // ******************************************************************
46 |
47 | let app = express();
48 | app.use(cors());
49 | app.use(bodyParser.json());
50 |
51 |
52 | /**
53 | * Redirect 'null' path to get all contacts
54 | */
55 | app.get('/', (req, res) =>{
56 | let file = require.resolve(PATH_API_HTML);
57 | res.send( fs.readFileSync(file).toString() )
58 | });
59 |
60 | // ******************************************************************
61 | // REST API
62 | // ******************************************************************
63 |
64 | /**
65 | * getContacts() RESTful endpoint
66 | */
67 | app.get('/api/contacts', function (req, res) {
68 | res.json(multipleResponse(db));
69 | });
70 |
71 | let delayedRequest = false;
72 |
73 | /**
74 | * searchContacts() RESTful endpoint
75 | */
76 | app.get('/api/search', function (req, res) {
77 | let text = req.query.text;
78 | let matches = db.filter(contact => contact.name
79 | .toLowerCase().indexOf(text.toLowerCase()) > -1);
80 |
81 | if (unorderedResponse && delayedRequest) {
82 | console.log(`Serving delayed for: ${text}`);
83 | setTimeout(() => res.json(multipleResponse(matches)), 2000)
84 | } else {
85 | console.log(`Serving instantly for: ${text}`);
86 | res.json(multipleResponse(matches));
87 | }
88 | delayedRequest = !delayedRequest;
89 | });
90 |
91 | /**
92 | * getContact() RESTful endpoint
93 | */
94 | app.get('/api/contacts/:id', function (req, res) {
95 | let contact = db.find(contact => contact.id == req.params.id);
96 | contact ? res.json(singleResponse(contact)) : res.status(404).json({ error: 'contact not found' });
97 | });
98 |
99 | /**
100 | * updateContact() RESTful endpoint
101 | */
102 | app.post('/api/contacts', function (req, res) {
103 | if (isContact(req.body)) {
104 | req.body.id = getNextId();
105 | req.body.image = '/assets/images/placeholder.png';
106 | db.push(req.body);
107 | res.json(singleResponse(req.body));
108 | }
109 | else {
110 | res.status(404).json({ error: 'invalid structure' });
111 | }
112 | });
113 |
114 |
115 | /**
116 | * createContact() RESTful endpoint
117 | */
118 | app.put('/api/contacts/:id', function (req, res) {
119 | let contact = db.find(contact => contact.id == req.params.id);
120 | if (contact) {
121 | Object.assign(contact, req.body);
122 | res.json(singleResponse(contact));
123 | } else {
124 | res.status(404).json({ error: 'contact not found' });
125 | }
126 | });
127 |
128 | /**
129 | * deleteContact() RESTful endpoint
130 | */
131 | app.delete('/api/contacts/:id', function (req, res) {
132 | let contact = db.find(contact => contact.id == req.params.id);
133 | if (contact) {
134 | let index = db.indexOf(contact);
135 | db.splice(index, 1);
136 | res.json(singleResponse(contact));
137 | } else {
138 | res.status(404).json({ error: 'contact not found' });
139 | }
140 | });
141 |
142 | /**
143 | * checkEmail() RESTful endpoint
144 | */
145 | app.get('/api/check-email', function (req, res) {
146 | if (emailIsAvailable(req.query.email)) {
147 | res.json({ msg: 'AVAILABLE' });
148 | } else {
149 | res.json({ error: 'NOT_AVAILABLE' });
150 | }
151 | });
152 |
153 | app.listen(4201, () => console.log('REST API running on port 4201'));
154 |
155 |
156 |
--------------------------------------------------------------------------------
/server/data/contacts.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | id: 0,
4 | name: 'Christoph Burgdorf',
5 | email: 'christoph@thoughtram.io',
6 | phone: '+49 000 1111',
7 | birthday: '1984-01-02',
8 | website: 'thoughtram.io',
9 | image: '/assets/images/0.jpg',
10 | address: {
11 | street: 'thoughtram road 1',
12 | zip: '65222',
13 | city: 'Hanover',
14 | country: 'Germany'
15 | }
16 | },
17 | {
18 | id: 1,
19 | name: 'Pascal Precht',
20 | email: 'pascal@thoughtram.io',
21 | phone: '+49 000 222',
22 | birthday: '1991-03-31',
23 | website: 'thoughtram.io',
24 | image: '/assets/images/1.jpg',
25 | address: {
26 | street: 'thoughtram road 1',
27 | zip: '65222',
28 | city: 'Hanover',
29 | country: 'Germany'
30 | }
31 | },
32 | {
33 | id: 2,
34 | name: 'Nicole Hansen',
35 | email: 'who@car.es',
36 | phone: '+49 000 333',
37 | birthday: '1981-03-31',
38 | website: '',
39 | image: '/assets/images/3.jpg',
40 | address: {
41 | street: 'Who Cares Street 42',
42 | zip: '65222',
43 | city: 'Sun Funcisco',
44 | country: 'United States'
45 | }
46 | },
47 | {
48 | id: 3,
49 | name: 'Zoe Moore',
50 | email: 'zoe@moore.com',
51 | phone: '+49 000 000',
52 | birthday: '1990-02-18',
53 | website: '',
54 | image: '/assets/images/4.jpg',
55 | address: {
56 | street: '3745 denny street',
57 | zip: '86337',
58 | city: 'Ballinasloe',
59 | country: 'United States'
60 | }
61 | },
62 | {
63 | id: 4,
64 | name: 'Diane Hale',
65 | email: '',
66 | phone: '',
67 | birthday: '',
68 | website: '',
69 | image: '/assets/images/5.jpg',
70 | address: {
71 | street: '1459 tara street',
72 | zip: '18371',
73 | city: 'Bray',
74 | country: 'United States'
75 | }
76 | },
77 | {
78 | id: 5,
79 | name: 'Barry Ford',
80 | email: '',
81 | phone: '',
82 | birthday: '',
83 | website: '',
84 | image: '/assets/images/6.jpg',
85 | address: {
86 | street: '6503 tara street',
87 | zip: '43378',
88 | city: 'Dungarvan',
89 | country: 'United States'
90 | }
91 | },
92 | {
93 | id: 6,
94 | name: 'Diana Ellis',
95 | email: '',
96 | phone: '',
97 | birthday: '',
98 | website: '',
99 | image: '/assets/images/7.jpg',
100 | address: {
101 | street: '6554 park lane',
102 | zip: '43378',
103 | city: 'Rush',
104 | country: 'United States'
105 | }
106 | },
107 | {
108 | id: 7,
109 | name: 'Ella Grant',
110 | email: '',
111 | phone: '',
112 | birthday: '',
113 | website: '',
114 | image: '/assets/images/8.jpg',
115 | address: {
116 | street: '2749 church road',
117 | zip: '87125',
118 | city: 'Clonakilty',
119 | country: 'United States'
120 | }
121 | },
122 | {
123 | id: 8,
124 | name: 'Brent Mason',
125 | email: '',
126 | phone: '',
127 | birthday: '',
128 | website: '',
129 | image: '/assets/images/9.jpg',
130 | address: {
131 | street: '8436 tara street',
132 | zip: '59949',
133 | city: 'Dundalk',
134 | country: 'United States'
135 | }
136 | },
137 | {
138 | id: 9,
139 | name: 'Sam Thomas',
140 | email: '',
141 | phone: '',
142 | birthday: '',
143 | website: '',
144 | image: '/assets/images/10.jpg',
145 | address: {
146 | street: '2523 park road',
147 | zip: '59949',
148 | city: 'Drogheda',
149 | country: 'United States'
150 | }
151 | },
152 | {
153 | id: 10,
154 | name: 'Vicky Roberts',
155 | email: '',
156 | phone: '',
157 | birthday: '',
158 | website: '',
159 | image: '/assets/images/11.jpg',
160 | address: {
161 | street: '9791 grafton street',
162 | zip: '30165',
163 | city: 'Galway',
164 | country: 'London'
165 | }
166 | }
167 | ];
168 |
--------------------------------------------------------------------------------
/server/voting-server.js:
--------------------------------------------------------------------------------
1 | let bodyParser = require('body-parser');
2 | let express = require('express');
3 | let cors = require('cors');
4 |
5 | const delay = 200;
6 | let votes = 0;
7 | let app = express();
8 |
9 | app.use(cors());
10 | app.use(bodyParser.json());
11 |
12 | app.get('/api/votes', getAllVotes);
13 | app.get('/api/votes/increment', addVote);
14 | app.get('/api/votes/decrement', removeVote);
15 |
16 | app.listen(4201, () => console.log('REST API running on port 4201'));
17 |
18 |
19 | // *************************************************
20 | // Internal REST methods
21 | // *************************************************
22 |
23 | function getAllVotes(req, res) {
24 | setTimeout(() => res.json({votes}), delay);
25 | }
26 |
27 | function addVote(req, res) {
28 | setTimeout(() => {
29 | votes += 1;
30 | res.json({votes});
31 | }, delay);
32 | }
33 |
34 | function removeVote(req, res) {
35 | setTimeout(() => {
36 | votes -= 1;
37 | res.json({votes});
38 | }, delay);
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/app/app.component.css
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Welcome to {{ title }}!
5 |
6 |

7 |
8 | Here are some links to help you start:
9 |
10 | -
11 |
12 |
13 | -
14 |
15 |
16 | -
17 |
18 |
19 | -
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/app/app.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | display: block;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'trm-contacts-app',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.scss']
7 | })
8 | export class ContactsAppComponent {
9 | title = 'Angular Master Class';
10 | }
11 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
3 | import { NgModule } from '@angular/core';
4 | import { FlexLayoutModule } from '@angular/flex-layout';
5 | import { ContactsMaterialModule } from './contacts-material.module';
6 |
7 | import { ContactsAppComponent } from './app.component';
8 |
9 |
10 | @NgModule({
11 | declarations: [ContactsAppComponent],
12 | imports: [
13 | BrowserModule,
14 | BrowserAnimationsModule,
15 | ContactsMaterialModule,
16 | FlexLayoutModule
17 | ],
18 | bootstrap: [ContactsAppComponent]
19 | })
20 | export class ContactsModule {
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/app/contacts-material.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { MatButtonModule } from '@angular/material/button';
3 | import { MatCardModule } from '@angular/material/card';
4 | import { MatCheckboxModule } from '@angular/material/checkbox';
5 | import { MatDialogModule } from '@angular/material/dialog';
6 | import { MatInputModule } from '@angular/material/input';
7 | import { MatIconModule } from '@angular/material/icon';
8 | import { MatListModule } from '@angular/material/list';
9 | import { MatSelectModule } from '@angular/material/select';
10 | import { MatSidenavModule } from '@angular/material/sidenav';
11 | import { MatRadioModule } from '@angular/material/radio';
12 | import { MatTabsModule } from '@angular/material/tabs';
13 | import { MatToolbarModule } from '@angular/material/toolbar';
14 |
15 | @NgModule({
16 | exports: [
17 | MatButtonModule,
18 | MatCardModule,
19 | MatCheckboxModule,
20 | MatDialogModule,
21 | MatInputModule,
22 | MatIconModule,
23 | MatListModule,
24 | MatRadioModule,
25 | MatSelectModule,
26 | MatSidenavModule,
27 | MatTabsModule,
28 | MatToolbarModule
29 | ]
30 | })
31 | export class ContactsMaterialModule {}
32 |
--------------------------------------------------------------------------------
/src/app/data/contact-data.ts:
--------------------------------------------------------------------------------
1 | export const CONTACT_DATA = [
2 | {
3 | id: 0,
4 | name: 'Christoph Burgdorf',
5 | email: 'christoph@thoughtram.io',
6 | phone: '+49 000 1111',
7 | birthday: '1984-01-02',
8 | website: 'thoughtram.io',
9 | image: '/assets/images/0.jpg',
10 | address: {
11 | street: 'thoughtram road 1',
12 | zip: '65222',
13 | city: 'Hanover',
14 | country: 'Germany'
15 | }
16 | },
17 | {
18 | id: 1,
19 | name: 'Pascal Precht',
20 | email: 'pascal@thoughtram.io',
21 | phone: '+49 000 222',
22 | birthday: '1991-03-31',
23 | website: 'thoughtram.io',
24 | image: '/assets/images/1.jpg',
25 | address: {
26 | street: 'thoughtram road 1',
27 | zip: '65222',
28 | city: 'Hanover',
29 | country: 'Germany'
30 | }
31 | },
32 | {
33 | id: 2,
34 | name: 'Nicole Hansen',
35 | email: 'who@car.es',
36 | phone: '+49 000 333',
37 | birthday: '1981-03-31',
38 | website: '',
39 | image: '/assets/images/3.jpg',
40 | address: {
41 | street: 'Who Cares Street 42',
42 | zip: '65222',
43 | city: 'Sun Funcisco',
44 | country: 'United States'
45 | }
46 | },
47 | {
48 | id: 3,
49 | name: 'Zoe Moore',
50 | email: 'zoe@moore.com',
51 | phone: '+49 000 000',
52 | birthday: '1990-02-18',
53 | website: '',
54 | image: '/assets/images/4.jpg',
55 | address: {
56 | street: '3745 denny street',
57 | zip: '86337',
58 | city: 'Ballinasloe',
59 | country: 'United States'
60 | }
61 | },
62 | {
63 | id: 4,
64 | name: 'Diane Hale',
65 | email: '',
66 | phone: '',
67 | birthday: '',
68 | website: '',
69 | image: '/assets/images/5.jpg',
70 | address: {
71 | street: '1459 tara street',
72 | zip: '18371',
73 | city: 'Bray',
74 | country: 'United States'
75 | }
76 | },
77 | {
78 | id: 5,
79 | name: 'Barry Ford',
80 | email: '',
81 | phone: '',
82 | birthday: '',
83 | website: '',
84 | image: '/assets/images/6.jpg',
85 | address: {
86 | street: '6503 tara street',
87 | zip: '43378',
88 | city: 'Dungarvan',
89 | country: 'United States'
90 | }
91 | },
92 | {
93 | id: 6,
94 | name: 'Diana Ellis',
95 | email: '',
96 | phone: '',
97 | birthday: '',
98 | website: '',
99 | image: '/assets/images/7.jpg',
100 | address: {
101 | street: '6554 park lane',
102 | zip: '43378',
103 | city: 'Rush',
104 | country: 'United States'
105 | }
106 | },
107 | {
108 | id: 7,
109 | name: 'Ella Grant',
110 | email: '',
111 | phone: '',
112 | birthday: '',
113 | website: '',
114 | image: '/assets/images/8.jpg',
115 | address: {
116 | street: '2749 church road',
117 | zip: '87125',
118 | city: 'Clonakilty',
119 | country: 'United States'
120 | }
121 | },
122 | {
123 | id: 8,
124 | name: 'Brent Mason',
125 | email: '',
126 | phone: '',
127 | birthday: '',
128 | website: '',
129 | image: '/assets/images/9.jpg',
130 | address: {
131 | street: '8436 tara street',
132 | zip: '59949',
133 | city: 'Dundalk',
134 | country: 'United States'
135 | }
136 | },
137 | {
138 | id: 9,
139 | name: 'Sam Thomas',
140 | email: '',
141 | phone: '',
142 | birthday: '',
143 | website: '',
144 | image: '/assets/images/10.jpg',
145 | address: {
146 | street: '2523 park road',
147 | zip: '59949',
148 | city: 'Drogheda',
149 | country: 'United States'
150 | }
151 | },
152 | {
153 | id: 10,
154 | name: 'Vicky Roberts',
155 | email: '',
156 | phone: '',
157 | birthday: '',
158 | website: '',
159 | image: '/assets/images/11.jpg',
160 | address: {
161 | street: '9791 grafton street',
162 | zip: '30165',
163 | city: 'Galway',
164 | country: 'London'
165 | }
166 | }
167 | ];
168 |
--------------------------------------------------------------------------------
/src/app/data/contact-manager.ts:
--------------------------------------------------------------------------------
1 | import { Contact} from '../models/contact';
2 |
3 | export class ContactManager {
4 |
5 | private _contacts: Array = [];
6 |
7 | get contacts() {
8 | return [...this._contacts];
9 | }
10 |
11 | constructor(data: Array) {
12 | this._contacts = [...data];
13 | }
14 |
15 | add(contact: Contact) {
16 | this._contacts.push(contact);
17 | }
18 |
19 | update(contact: Contact) {
20 | let index = this._contacts.findIndex(c => c.id == contact.id);
21 | if (index === -1) {
22 | throw new Error(`Trying to update contact that doesn't exist with ID: ${contact.id}!`);
23 | }
24 | this._contacts[index] = contact;
25 | }
26 |
27 | get(id: number) {
28 | let contact = this.contacts.find(c => c.id === id);
29 | return contact ? contact : null;
30 | }
31 |
32 | getAll() {
33 | return this.contacts;
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/src/app/data/gender.ts:
--------------------------------------------------------------------------------
1 | export const GENDER = [
2 | 'Female',
3 | 'Male',
4 | 'Transgender Female',
5 | 'Transgender Male',
6 | 'Gender Variant / Non-Conforming',
7 | 'Prefer Not to Answer'
8 | ];
9 |
--------------------------------------------------------------------------------
/src/app/models/contact.ts:
--------------------------------------------------------------------------------
1 | export interface Address {
2 | street?: string;
3 | city?: string;
4 | zip?: string;
5 | country?: string;
6 | }
7 |
8 | export interface Contact {
9 | id: number | string;
10 | name?: string;
11 | email?: string;
12 | phone?: string | string[];
13 | birthday?: string;
14 | website?: string;
15 | image?: string;
16 | address?: Address;
17 | }
18 |
--------------------------------------------------------------------------------
/src/app/shared/index.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/app/shared/index.ts
--------------------------------------------------------------------------------
/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/.gitkeep
--------------------------------------------------------------------------------
/src/assets/.npmignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/.npmignore
--------------------------------------------------------------------------------
/src/assets/favicons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/favicons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/src/assets/favicons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/favicons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/src/assets/favicons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/favicons/apple-touch-icon.png
--------------------------------------------------------------------------------
/src/assets/favicons/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #2b5797
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/assets/favicons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/favicons/favicon-16x16.png
--------------------------------------------------------------------------------
/src/assets/favicons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/favicons/favicon-32x32.png
--------------------------------------------------------------------------------
/src/assets/favicons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/favicons/favicon.ico
--------------------------------------------------------------------------------
/src/assets/favicons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/favicons/mstile-150x150.png
--------------------------------------------------------------------------------
/src/assets/favicons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
41 |
--------------------------------------------------------------------------------
/src/assets/favicons/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/src/assets/images/0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/0.jpg
--------------------------------------------------------------------------------
/src/assets/images/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/1.jpg
--------------------------------------------------------------------------------
/src/assets/images/10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/10.jpg
--------------------------------------------------------------------------------
/src/assets/images/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/11.jpg
--------------------------------------------------------------------------------
/src/assets/images/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/2.jpg
--------------------------------------------------------------------------------
/src/assets/images/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/3.jpg
--------------------------------------------------------------------------------
/src/assets/images/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/4.jpg
--------------------------------------------------------------------------------
/src/assets/images/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/5.jpg
--------------------------------------------------------------------------------
/src/assets/images/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/6.jpg
--------------------------------------------------------------------------------
/src/assets/images/7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/7.jpg
--------------------------------------------------------------------------------
/src/assets/images/8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/8.jpg
--------------------------------------------------------------------------------
/src/assets/images/9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/9.jpg
--------------------------------------------------------------------------------
/src/assets/images/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/placeholder.png
--------------------------------------------------------------------------------
/src/assets/images/team.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/assets/images/team.jpg
--------------------------------------------------------------------------------
/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false
8 | };
9 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtram/angular-master-class-starter/266904791ef466ec3335de02b91a4049c2d5f734/src/favicon.ico
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Contacts
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { ContactsModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(ContactsModule)
12 | .catch(err => console.log(err));
13 |
--------------------------------------------------------------------------------
/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
22 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
23 |
24 | /**
25 | * Web Animations `@angular/platform-browser/animations`
26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28 | */
29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
30 |
31 | /**
32 | * By default, zone.js will patch all possible macroTask and DomEvents
33 | * user can disable parts of macroTask/DomEvents patch by setting following flags
34 | * because those flags need to be set before `zone.js` being loaded, and webpack
35 | * will put import in the top of bundle, so user need to create a separate file
36 | * in this directory (for example: zone-flags.ts), and put the following flags
37 | * into that file, and then add the following code before importing zone.js.
38 | * import './zone-flags.ts';
39 | *
40 | * The flags allowed in zone-flags.ts are listed here.
41 | *
42 | * The following flags will work for all browsers.
43 | *
44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
47 | *
48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
50 | *
51 | * (window as any).__Zone_enable_cross_context_check = true;
52 | *
53 | */
54 |
55 | /***************************************************************************************************
56 | * Zone JS is required by default for Angular itself.
57 | */
58 | import 'zone.js/dist/zone'; // Included with Angular CLI.
59 |
60 |
61 | /***************************************************************************************************
62 | * APPLICATION IMPORTS
63 | */
64 |
65 |
66 |
--------------------------------------------------------------------------------
/src/styles.scss:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @import '../node_modules/@angular/material/prebuilt-themes/indigo-pink.css';
3 |
4 | body, html {
5 | background-color: #f6f6f6;
6 | position: relative;
7 | }
8 |
9 | html, body, trm-contacts-app, mat-drawer-container, .main-content {
10 | margin: 0;
11 | width: 100%;
12 | height: 100%;
13 | }
14 |
15 | .mat-form-field {
16 | width: 100%;
17 | }
18 |
19 | .mat-list-base {
20 | background-color: white;
21 | padding-top: 0!important;
22 | }
23 |
24 | .mat-list-base .mat-list-item {
25 | border-bottom: 1px solid #ddd;
26 | text-decoration: none;
27 |
28 | &:hover {
29 | background-color: #f0f0f0;
30 | }
31 |
32 | &.active {
33 | background-color: #e9e9e9;
34 | }
35 | }
36 |
37 | .trm-floating-button {
38 | position: absolute!important;
39 | right: 2em;
40 | bottom: 2em;
41 | color: #fff;
42 | }
43 |
44 | .trm-contacts-detail,
45 | .trm-contacts-creator,
46 | .trm-contacts-editor,
47 | .trm-about {
48 | .mat-card {
49 | max-width: 500px;
50 | margin: 0 auto;
51 | margin-top: 2em;
52 |
53 | img {
54 | border-radius: 50%;
55 | }
56 | }
57 |
58 | .mat-card-title-group.fullBleed {
59 | background-color: #afbafc;
60 | padding: 30px;
61 | margin-top: -24px;
62 | margin-left: -16px;
63 | margin-right: -16px;
64 | margin-bottom: 24px;
65 |
66 | &.editing {
67 | background-color: #fdecbb;
68 | }
69 | }
70 |
71 | .mat-card-content {
72 | dl {
73 | margin-top: 2em;
74 | border-bottom: 1px solid rgba(221, 221, 221, 0.15);
75 | padding-top: 1em;
76 | padding-bottom: 1.5em;
77 | }
78 |
79 | dt, dd {
80 | display: inline-block;
81 | margin-top: 0.5em;
82 |
83 | &:first-child {
84 | margin-top: 0;
85 | }
86 | }
87 |
88 | dt {
89 | width: 25%;
90 | font-weight: bold;
91 | }
92 |
93 | dd {
94 | margin-left: 0;
95 | width: 70%;
96 | }
97 |
98 | dt:first-child + dd {
99 | margin-top: 0;
100 | }
101 | }
102 |
103 | fieldset {
104 | legend { color: #ccc; }
105 | border: 1px solid #ddd;
106 | margin-top: 1em;
107 | padding-left: 1em;
108 | padding-right: 1em;
109 |
110 | mat-input-container, mat-select {
111 | margin-top: 2em;
112 | }
113 |
114 | }
115 |
116 | .mat-form-field {
117 |
118 | &.ng-invalid {
119 |
120 | .mat-hint {
121 | color: rgb(215, 65, 57);
122 | }
123 |
124 | &.ng-touched:not(.ng-pristine) {
125 | .mat-input-underline {
126 | border-color: rgb(215, 65, 57);
127 | }
128 | }
129 | }
130 | }
131 |
132 | mat-radio-button {
133 | display: block;
134 | color: #666;
135 | }
136 |
137 | .gender-label {
138 | color: #ccc;
139 | }
140 | .mat-radio-outer-circle {
141 | border-color: rgba(0,0,0,.12);
142 | }
143 |
144 | .mat-radio-label {
145 | margin-top: 0.5em;
146 | }
147 | }
148 |
149 | .trm-about .mat-card img {
150 | border-radius: 0;
151 | max-height: 400px;
152 | }
153 |
154 | .trm-search-container {
155 | width: 100%;
156 | }
157 |
158 | mat-dialog-container {
159 | font-family: Roboto,"Helvetica Neue",sans-serif;
160 |
161 | [mat-dialog-title] {
162 | margin-left: -24px;
163 | margin-right: -24px;
164 | margin-top: -24px;
165 | padding: 0.5em;
166 | text-align: center;
167 | color: #fff;
168 | background-color: #3f51b5;
169 | font-weight: normal;
170 | }
171 |
172 | [mat-dialog-content] {
173 | margin-bottom: 12px;
174 | margin-top: 36px;
175 | font-size: 14px;
176 | }
177 | }
178 |
179 | mat-dialog-actions {
180 | padding: 8px 0;
181 | [mat-button],[mat-raised-button] {
182 | margin: 0 4px;
183 | }
184 | }
185 |
186 | trm-tab > mat-input-container:first-child {
187 | padding-top: 25px;
188 | }
189 |
190 |
--------------------------------------------------------------------------------
/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone-testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | declare const require: any;
11 |
12 | // First, initialize the Angular testing environment.
13 | getTestBed().initTestEnvironment(
14 | BrowserDynamicTestingModule,
15 | platformBrowserDynamicTesting()
16 | );
17 | // Then we find all the tests.
18 | const context = require.context('./', true, /\.spec\.ts$/);
19 | // And load the modules.
20 | context.keys().map(context);
21 |
--------------------------------------------------------------------------------
/src/testing/custom-matchers.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare const global: any;
4 |
5 | const _global = (typeof window === 'undefined' ? global : window);
6 |
7 | export const expect: (actual: any) => NgMatchers = _global.expect;
8 |
9 | export interface NgMatchers extends jasmine.Matchers {
10 | toHaveMap(expected: { [k: string]: string }): boolean;
11 | }
12 |
13 | export const CUSTOM_MATCHERS: jasmine.CustomMatcherFactories = {
14 | toHaveMap: () => {
15 | return {
16 | compare: (actual: { [k: string]: string }, map: { [k: string]: string }) => {
17 | let allPassed = Object.keys(map).length !== 0;
18 |
19 | Object.keys(map).forEach(key => {
20 | allPassed = allPassed && actual[key] === map[key];
21 | });
22 |
23 | return {
24 | pass: allPassed,
25 | get message() {
26 | return `
27 | Expected ${JSON.stringify(actual)} ${!allPassed ? ' ' : 'not '} to contain the
28 | "${JSON.stringify(map)}"
29 | `;
30 | }
31 | };
32 | }
33 | };
34 | }
35 | };
36 |
--------------------------------------------------------------------------------
/src/testing/helpers.ts:
--------------------------------------------------------------------------------
1 | import { Type, DebugElement } from '@angular/core';
2 | import { By } from '@angular/platform-browser';
3 | import { ComponentFixture, TestBed } from '@angular/core/testing';
4 |
5 | export function createFixture(component: Type, detectChanges = true): ComponentFixture {
6 | const fixture = TestBed.createComponent(component);
7 |
8 | if (detectChanges) {
9 | fixture.detectChanges();
10 | }
11 |
12 | return fixture;
13 | }
14 |
15 | export function queryFor(fixture: ComponentFixture, selector: string): DebugElement[] {
16 | return fixture.debugElement.queryAll(By.css(selector));
17 | }
18 |
--------------------------------------------------------------------------------
/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | /* SystemJS module definition */
2 | declare var module: NodeModule;
3 | interface NodeModule {
4 | id: string;
5 | }
6 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts",
10 | "src/polyfills.ts"
11 | ],
12 | "exclude": [
13 | "src/test.ts",
14 | "src/**/*.spec.ts"
15 | ]
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "downlevelIteration": true,
9 | "experimentalDecorators": true,
10 | "module": "esnext",
11 | "moduleResolution": "node",
12 | "importHelpers": true,
13 | "target": "es2015",
14 | "typeRoots": [
15 | "node_modules/@types"
16 | ],
17 | "lib": [
18 | "es2018",
19 | "dom"
20 | ]
21 | },
22 | "angularCompilerOptions": {
23 | "fullTemplateTypeCheck": true,
24 | "strictInjectionParameters": true
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./out-tsc/spec",
5 | "types": [
6 | "jasmine",
7 | "node"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts",
12 | "src/polyfills.ts"
13 | ],
14 | "include": [
15 | "src/**/*.spec.ts",
16 | "src/**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "arrow-return-shorthand": true,
7 | "callable-types": true,
8 | "class-name": true,
9 | "comment-format": [
10 | true,
11 | "check-space"
12 | ],
13 | "curly": true,
14 | "deprecation": {
15 | "severity": "warn"
16 | },
17 | "eofline": true,
18 | "forin": true,
19 | "import-blacklist": [
20 | true,
21 | "rxjs/Rx"
22 | ],
23 | "import-spacing": true,
24 | "indent": [
25 | true,
26 | "spaces"
27 | ],
28 | "interface-over-type-literal": true,
29 | "label-position": true,
30 | "max-line-length": [
31 | true,
32 | 140
33 | ],
34 | "member-access": false,
35 | "member-ordering": [
36 | true,
37 | {
38 | "order": [
39 | "static-field",
40 | "instance-field",
41 | "static-method",
42 | "instance-method"
43 | ]
44 | }
45 | ],
46 | "no-arg": true,
47 | "no-bitwise": true,
48 | "no-console": [
49 | true,
50 | "debug",
51 | "info",
52 | "time",
53 | "timeEnd",
54 | "trace"
55 | ],
56 | "no-construct": true,
57 | "no-debugger": true,
58 | "no-duplicate-super": true,
59 | "no-empty": false,
60 | "no-empty-interface": true,
61 | "no-eval": true,
62 | "no-inferrable-types": [
63 | true,
64 | "ignore-params"
65 | ],
66 | "no-misused-new": true,
67 | "no-non-null-assertion": true,
68 | "no-shadowed-variable": true,
69 | "no-string-literal": false,
70 | "no-string-throw": true,
71 | "no-switch-case-fall-through": true,
72 | "no-trailing-whitespace": true,
73 | "no-unnecessary-initializer": true,
74 | "no-unused-expression": true,
75 | "no-use-before-declare": true,
76 | "no-var-keyword": true,
77 | "object-literal-sort-keys": false,
78 | "one-line": [
79 | true,
80 | "check-open-brace",
81 | "check-catch",
82 | "check-else",
83 | "check-whitespace"
84 | ],
85 | "prefer-const": true,
86 | "quotemark": [
87 | true,
88 | "single"
89 | ],
90 | "radix": true,
91 | "semicolon": [
92 | true,
93 | "always"
94 | ],
95 | "triple-equals": [
96 | true,
97 | "allow-null-check"
98 | ],
99 | "typedef-whitespace": [
100 | true,
101 | {
102 | "call-signature": "nospace",
103 | "index-signature": "nospace",
104 | "parameter": "nospace",
105 | "property-declaration": "nospace",
106 | "variable-declaration": "nospace"
107 | }
108 | ],
109 | "unified-signatures": true,
110 | "variable-name": false,
111 | "whitespace": [
112 | true,
113 | "check-branch",
114 | "check-decl",
115 | "check-operator",
116 | "check-separator",
117 | "check-type"
118 | ],
119 | "directive-selector": [
120 | true,
121 | "attribute",
122 | "trm",
123 | "camelCase"
124 | ],
125 | "component-selector": [
126 | true,
127 | "element",
128 | "trm",
129 | "kebab-case"
130 | ],
131 | "no-output-on-prefix": true,
132 | "use-input-property-decorator": true,
133 | "use-output-property-decorator": true,
134 | "use-host-property-decorator": true,
135 | "no-input-rename": true,
136 | "no-output-rename": true,
137 | "use-life-cycle-interface": true,
138 | "use-pipe-transform-interface": true,
139 | "component-class-suffix": true,
140 | "directive-class-suffix": true
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 |
4 | module.exports = {
5 | entry: { server: path.join(__dirname, 'server', 'server.ts') },
6 | resolve: { extensions: ['.js', '.ts'] },
7 | target: 'node',
8 | mode: 'none',
9 | // This makes sure we include node_modules and other 3rd party libraries
10 | externals: [/(node_modules|main\..*\.js)/],
11 | output: {
12 | path: path.join(__dirname, 'dist'),
13 | filename: '[name].js'
14 | },
15 | module: {
16 | rules: [{ test: /\.ts$/, loader: 'ts-loader' }]
17 | },
18 | plugins: [
19 | // Temporary Fix for issue: https://github.com/angular/angular/issues/11580
20 | // for 'WARNING Critical dependency: the request of a dependency is an expression'
21 | new webpack.ContextReplacementPlugin(
22 | /(.+)?angular(\\|\/)core(.+)?/,
23 | path.join(__dirname, 'src'), // location of your src
24 | {} // a map of your routes
25 | ),
26 | new webpack.ContextReplacementPlugin(/(.+)?express(\\|\/)(.+)?/, path.join(__dirname, 'src'), {})
27 | ]
28 | };
29 |
--------------------------------------------------------------------------------