Initial transition to @angular/cli and webpack

All unit tests need to be reworked to use the official Angular testing
setup. API tests are fine.
This commit is contained in:
Matthew Ross 2018-03-09 20:05:40 -05:00
parent 9577890993
commit bdbe3de2c3
57 changed files with 11803 additions and 9519 deletions

89
.angular-cli.json Normal file
View File

@ -0,0 +1,89 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "TaskBoard"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
{
"glob": "**/!(composer*)*.*",
"input": "api",
"output": "api",
"allowOutsideOutDir": false
},
{
"glob": "*.json",
"input": "json",
"output": "strings"
},
".htaccess",
"images",
"fonts"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"scss/main.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"../node_modules/bourbon/app/assets/stylesheets/",
"../node_modules/bourbon-neat/app/assets/stylesheets/",
"../node_modules/bourbon-neat/app/assets/stylesheets/",
"../node_modules/scss-base/src/",
"../node_modules/chartist/dist/scss/"
]
},
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json",
"exclude": "**/node_modules/**"
},
{
"project": "src/tsconfig.spec.json",
"exclude": "**/node_modules/**"
},
{
"project": "e2e/tsconfig.e2e.json",
"exclude": "**/node_modules/**"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "scss",
"build": {
"showCircularDependencies": false
},
"component": {
}
},
"warnings": {
"typescriptMismatch": false
}
}

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

52
.gitignore vendored
View File

@ -1,8 +1,46 @@
build
coverage
dist
node_modules
src/api/vendor
tests.db
tests.log
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/dist-server
/tmp
/out-tsc
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# e2e
/e2e/*.js
/e2e/*.map
# System Files
.DS_Store
Thumbs.db
/src/api/vendor

View File

@ -1,12 +0,0 @@
linters:
ColorVariable:
enabled: false
Indentation:
width: 4
NestingDepth:
max_depth: 5
SelectorDepth:
max_depth: 5

View File

@ -1,23 +1,24 @@
language: php
php:
- '5.6'
- '7.0.15'
- '7.0'
- '7.1'
- '7.2'
before_script:
- nvm install 4
- nvm use 4
- npm i -g npm@4
- npm i -g gulp
- npm i
- touch tests.db
- chmod a+w tests.db
script:
- ./src/api/vendor/phpunit/phpunit/phpunit -c test/api/phpunit.xml
- gulp test-app && gulp coverage
- ng test -cc
# - gulp test-app && gulp coverage
after_success:
- echo -e "<?php\n print phpversion();" > version.php
- curl "https://raw.githubusercontent.com/andreafabrizi/Dropbox-Uploader/master/dropbox_uploader.sh" -o dropbox_uploader.sh
- chmod +x dropbox_uploader.sh
- ./dropbox_uploader.sh -f /dev/null upload coverage/api coverage-$(php version.php)/
- ./dropbox_uploader.sh -f /dev/null upload coverage/app coverage-$(php version.php)/
# - ./dropbox_uploader.sh -f /dev/null upload coverage/app coverage-$(php version.php)/

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014-2017 Matthew Ross
Copyright (c) 2014-2018 Matthew Ross
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,278 +0,0 @@
'use strict';
let gulp = require('gulp'),
fs = require('fs'),
del = require('del'),
touch = require('touch'),
merge = require('merge-stream'),
SystemBuilder = require('systemjs-builder'),
mocha = require('gulp-mocha'),
coverage = require('gulp-istanbul'),
phpunit = require('gulp-phpunit'),
concat = require('gulp-concat'),
imageMin = require('gulp-imagemin'),
composer = require('gulp-composer'),
tsc = require('gulp-typescript'),
tsLint = require('gulp-tslint'),
tsProject = tsc.createProject('tsconfig.json'),
jsMinify = require('gulp-uglify'),
scssLint = require('gulp-scss-lint'),
sass = require('gulp-sass'),
cssImport = require('gulp-cssimport'),
cssPrefixer = require('gulp-autoprefixer'),
cssMinify = require('gulp-cssnano'),
paths = {
bourbon: 'node_modules/bourbon/app/assets/stylesheets',
neat: 'node_modules/bourbon-neat/app/assets/stylesheets',
scss_base: 'node_modules/scss-base/src',
chartist: 'node_modules/chartist/dist/scss',
normalize: require('node-normalize-scss').includePaths,
hljs: 'node_modules/highlight.js/styles',
tests_app: 'test/app/**/*.spec.js',
tests_api: 'test/api/**/*.php',
ts: 'src/app/**/*.ts',
html: [
'src/**/*.html',
'src/.htaccess'
],
json: 'src/json/**/*.json',
images: 'src/images/**/*.*',
scss: 'src/scss/**/*.scss',
scssMain: 'src/scss/main.scss',
api: [
'src/api/**/*.*',
'src/api/.htaccess',
'!src/api/composer.*'
]
};
gulp.task('clean', () => {
return del([
'dist',
'build',
'tests.db',
'coverage',
'src/api/vendor/'
]);
});
gulp.task('html', () => {
return gulp.src(paths.html)
.pipe(gulp.dest('dist/'));
});
gulp.task('json', () => {
return gulp.src(paths.json)
.pipe(gulp.dest('dist/strings/'));
});
gulp.task('fonts', () => {
return gulp.src('src/fonts/fontello.*')
.pipe(gulp.dest('dist/css/fonts/'));
});
gulp.task('images', () => {
return gulp.src(paths.images)
.pipe(imageMin())
.pipe(gulp.dest('dist/images/'));
});
gulp.task('scss-lint', () => {
return gulp.src(paths.scss)
.pipe(scssLint({ config: './.scss-lint.yml' }));
});
gulp.task('scss', () => {
return gulp.src(paths.scssMain)
.pipe(sass({
precision: 10,
includePaths: [
paths.bourbon,
paths.neat,
paths.scss_base,
paths.chartist,
paths.normalize
]
}))
.pipe(concat('styles.css'))
.pipe(cssImport({}))
.pipe(cssPrefixer())
.pipe(gulp.dest('dist/css/'));
});
gulp.task('ts-lint', () => {
return gulp.src(paths.ts)
.pipe(tsLint({ formatter: 'prose' }))
.pipe(tsLint.report());
});
gulp.task('tsc', () => {
del('build/');
return gulp.src(paths.ts)
.pipe(tsProject())
.once('error', function () {
this.once('finish', () => process.exit(1));
})
.pipe(gulp.dest('build/'));
});
gulp.task('vendor', () => {
let map = gulp.src('node_modules/reflect-metadata/Reflect.js.map')
.pipe(gulp.dest('dist/js/'));
let js = gulp.src([
'node_modules/core-js/client/shim.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/reflect-metadata/Reflect.js',
'node_modules/chartist/dist/chartist.js',
'node_modules/chartist-plugin-tooltip/dist/chartist-plugin-tooltip.js'
])
.pipe(concat('vendor.js'))
.pipe(gulp.dest('dist/js/'));
return merge(map, js);
});
gulp.task('system-build', ['tsc'], () => {
var builder = new SystemBuilder();
return builder.loadConfig('system.config.js')
.then(() => builder.buildStatic('app', 'dist/js/bundle.js', {
production: false,
rollup: false
}))
.then(() => del('build'));
});
gulp.task('minify-js', () => {
return gulp.src('dist/js/**/*.js')
.pipe(jsMinify())
.pipe(gulp.dest('dist/js/'));
});
gulp.task('minify-css', () => {
return gulp.src('dist/css/styles.css')
.pipe(cssMinify())
.pipe(gulp.dest('dist/css/'));
});
gulp.task('minify', ['minify-js', 'minify-css']);
gulp.task('composer', () => {
return composer({
'working-dir': 'src/api'
});
});
gulp.task('api', () => {
return gulp.src(paths.api)
.pipe(gulp.dest('dist/api/'));
});
gulp.task('app', ['html', 'json', 'system-build', 'ts-lint']);
gulp.task('styles', ['html', 'scss-lint', 'scss']);
gulp.task('test', ['coverage', 'test-api']);
gulp.task('test-app', ['tsc'], () => {
return gulp.src(paths.tests_app)
.pipe(mocha({
require: [
'./test/app/mocks.js'
]
}));
});
gulp.task('coverage-prep', ['tsc'], () => {
return gulp.src('build/**/*.js')
.pipe(coverage({
includeUntested: true
}))
.pipe(coverage.hookRequire());
});
gulp.task('coverage', ['coverage-prep'], () => {
return gulp.src(paths.tests_app)
.pipe(mocha({
require: [ './test/app/mocks.js' ]
}))
.pipe(coverage.writeReports({
dir: './coverage/app/',
reporters: [ 'html' ]
}));
});
gulp.task('api-test-db', () => {
del('tests.db');
touch('tests.db');
fs.chmod('tests.db', '0666');
del('tests.log');
});
gulp.task('test-api', ['api-test-db'], () => {
return gulp.src('test/api/phpunit.xml')
.pipe(phpunit('./src/api/vendor/phpunit/phpunit/phpunit'));
});
gulp.task('test-api-single', ['api-test-db'], () => {
return gulp.src('test/api/phpunit.xml')
.pipe(phpunit('./src/api/vendor/phpunit/phpunit/phpunit',
{ group: 'single' }));
});
gulp.task('watch', () => {
let watchTs = gulp.watch(paths.ts, ['system-build']),
watchScss = gulp.watch(paths.scss, ['scss-lint', 'scss']),
watchHtml = gulp.watch(paths.html, ['html']),
watchImages = gulp.watch(paths.images, ['images']),
watchApi = gulp.watch(paths.api, ['api']),
onChanged = (event) => {
console.log('File ' + event.path + ' was ' + event.type +
'. Running tasks...');
};
watchTs.on('change', onChanged);
watchScss.on('change', onChanged);
watchHtml.on('change', onChanged);
watchImages.on('change', onChanged);
watchApi.on('change', onChanged);
});
gulp.task('watchtests', () => {
let watchTests = gulp.watch(paths.tests_app, ['test-app']),
watchTs = gulp.watch(paths.ts, ['test-app']),
onChanged = (event) => {
console.log('File ' + event.path + ' was ' + event.type +
'. Running tasks...');
};
watchTests.on('change', onChanged);
watchTs.on('change', onChanged);
});
gulp.task('default', [
'vendor',
'ts-lint',
'system-build',
'html',
'json',
'images',
'scss-lint',
'fonts',
'scss',
'api'
], () => {
fs.chmod('dist/api', '0777');
});

34
karma.conf.js Normal file
View File

@ -0,0 +1,34 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-phantomjs-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['PhantomJS'], // ['Chrome'],
singleRun: false
});
};

16375
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,12 +2,7 @@
"name": "taskboard",
"version": "1.0.0",
"description": "A Kanban-inspired app for keeping track of things that need to get done.",
"main": "index.js",
"private": true,
"scripts": {
"test": "gulp test-api && gulp test-app",
"postinstall": "gulp composer"
},
"repository": {
"type": "git",
"url": "git+https://kiswa@github.com/kiswa/TaskBoard.git"
@ -21,64 +16,64 @@
"todo"
],
"author": "Matthew Ross <root@matthewross.me> (https://matthewross.me)",
"license": "MIT",
"bugs": {
"url": "https://github.com/kiswa/TaskBoard/issues"
},
"homepage": "https://github.com/kiswa/TaskBoard#readme",
"devDependencies": {
"@angular/common": "5.2.7",
"@angular/compiler": "5.2.7",
"@angular/core": "5.2.7",
"@angular/forms": "5.2.7",
"@angular/http": "5.2.7",
"@angular/platform-browser": "5.2.7",
"@angular/platform-browser-dynamic": "5.2.7",
"@angular/router": "5.2.7",
"@types/chartist": "^0.9.38",
"@types/core-js": "^0.9.46",
"@types/highlight.js": "^9.12.2",
"@types/marked": "0.3.0",
"bourbon": "4.3.4",
"bourbon-neat": "1.9.0",
"chai": "^4.1.2",
"license": "MIT",
"scripts": {
"start": "ng serve",
"build": "ng build --prod",
"test": "ng test",
"test-api": "./src/api/vendor/phpunit/phpunit/phpunit -c test/api/phpunit.xml",
"lint": "ng lint",
"e2e": "ng e2e",
"postinstall": "cd src/api/ && composer install && cd ../.."
},
"dependencies": {
"@angular/animations": "^5.2.0",
"@angular/common": "^5.2.0",
"@angular/compiler": "^5.2.0",
"@angular/core": "^5.2.0",
"@angular/forms": "^5.2.0",
"@angular/http": "^5.2.0",
"@angular/platform-browser": "^5.2.0",
"@angular/platform-browser-dynamic": "^5.2.0",
"@angular/router": "^5.2.0",
"chartist": "^0.11.0",
"chartist-plugin-tooltips": "^0.0.17",
"core-js": "^2.5.3",
"del": "^3.0.0",
"classlist.js": "^1.1.20150312",
"core-js": "^2.4.1",
"dragula": "^3.7.2",
"escape-string-regexp": "^1.0.5",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^5.0.0",
"gulp-chmod": "^2.0.0",
"gulp-composer": "^0.4.5",
"gulp-concat": "^2.6.1",
"gulp-cssimport": "^6.0.1",
"gulp-cssnano": "^2.1.2",
"gulp-imagemin": "^4.1.0",
"gulp-istanbul": "^1.1.3",
"gulp-mocha": "3.0.1",
"gulp-phpunit": "^0.25.0",
"gulp-sass": "^3.1.0",
"gulp-scss-lint": "^0.6.1",
"gulp-tslint": "^8.1.3",
"gulp-typescript": "^4.0.1",
"gulp-uglify": "^3.0.0",
"gulp-util": "^3.0.8",
"highlight.js": "^9.12.0",
"marked": "^0.3.17",
"merge-stream": "^1.0.1",
"mock-browser": "^0.92.14",
"ng2-dragula": "^1.5.0",
"node-normalize-scss": "^3.0.0",
"reflect-metadata": "^0.1.12",
"rxjs": "5.5.6",
"rxjs": "^5.5.6",
"scss-base": "^1.3.4",
"systemjs": "0.21.0",
"systemjs-builder": "0.16.12",
"touch": "^3.1.0",
"tslint": "^5.9.1",
"typescript": "2.7.2",
"zone.js": "^0.8.20"
"zone.js": "^0.8.19"
},
"devDependencies": {
"@angular/cli": "~1.7.3",
"@angular/compiler-cli": "^5.2.0",
"@angular/language-service": "^5.2.0",
"@types/jasmine": "~2.8.3",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~9.4.6",
"bourbon": "4.3.4",
"bourbon-neat": "1.9.0",
"codelyzer": "^4.0.1",
"jasmine-core": "~2.8.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~2.0.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-phantomjs-launcher": "^1.0.4",
"protractor": "~5.3.0",
"ts-node": "~5.0.1",
"tslint": "~5.9.1",
"typescript": "^2.6.2"
}
}

28
protractor.conf.js Normal file
View File

@ -0,0 +1,28 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

3463
src/api/composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -20,12 +20,17 @@ import { ApiResponse } from './shared/index';
export const API_HTTP_PROVIDERS = [
{
provide: Http,
useFactory: (xhrBackend: XHRBackend, requestOptions: RequestOptions,
router: Router) => new ApiHttp(xhrBackend, requestOptions, router),
useFactory: apiHttpFactory,
deps: [XHRBackend, RequestOptions, Router]
}
];
export function apiHttpFactory (xhrBackend: XHRBackend,
requestOptions: RequestOptions,
router: Router) {
return new ApiHttp(xhrBackend, requestOptions, router);
}
export class ApiHttp extends Http {
private JWT_KEY = 'taskboard.jwt';

View File

View File

@ -0,0 +1,27 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
}));
});

View File

@ -4,7 +4,7 @@ import { Notifications, StringsService } from './shared/index';
@Component({
selector: 'app-component',
templateUrl: 'app/app.component.html'
templateUrl: './app.component.html'
})
export class AppComponent {
constructor(strings: StringsService) {

View File

@ -21,24 +21,24 @@ import { BoardService } from './board.service';
@Component({
selector: 'tb-board',
templateUrl: 'app/board/board.component.html'
templateUrl: './board.component.html'
})
export class BoardDisplay implements OnInit {
private activeUser: User;
private activeBoard: Board;
private boards: Array<Board>;
private strings: any;
private boardNavId: number;
private userFilter: number;
private categoryFilter: number;
private noBoardsMessage: string;
private pageName: string;
private loading: boolean;
private hideFiltered: boolean;
public activeUser: User;
public activeBoard: Board;
public boards: Array<Board>;
public pageName: string;
public loading: boolean;
constructor(private title: Title,
private router: Router,
private active: ActivatedRoute,
@ -212,6 +212,16 @@ export class BoardDisplay implements OnInit {
});
}
noBoards(): boolean {
if (!this.loading) {
if (!this.boards || this.boards.length === 0) {
return true;
}
}
return false;
}
private updateBoardsList(boards: Array<any>): void {
let activeBoards: Array<Board> = [];
@ -272,15 +282,5 @@ export class BoardDisplay implements OnInit {
this.noBoardsMessage = this.strings.boards_noBoardsMessageAdmin;
}
}
private noBoards(): boolean {
if (!this.loading) {
if (!this.boards || this.boards.length === 0) {
return true;
}
}
return false;
}
}

View File

@ -34,31 +34,21 @@ import { BoardService } from '../board.service';
@Component({
selector: 'tb-column',
templateUrl: 'app/board/column/column.component.html'
templateUrl: './column.component.html'
})
export class ColumnDisplay implements OnInit {
private strings: any;
private templateElement: any;
private collapseTasks: boolean;
private saving: boolean;
private showLimitEditor: boolean;
private isOverdue: boolean;
private isNearlyDue: boolean;
private activeUser: User;
private activeBoard: Board;
private userOptions: UserOptions;
private tasks: Array<Task>;
private contextMenuItems: Array<ContextMenuItem>;
private sortOption: string;
private MODAL_ID: string;
private MODAL_VIEW_ID: string;
private MODAL_CONFIRM_ID: string;
private MODAL_CONFIRM_COMMENT_ID: string;
private quickAdd: Task;
private modalProps: Task;
private viewModalProps: Task;
private viewTaskActivities: Array<ActivitySimple>;
@ -71,6 +61,17 @@ export class ColumnDisplay implements OnInit {
private newComment: string;
private fileUpload: any;
public strings: any;
public collapseTasks: boolean;
public activeUser: User;
public activeBoard: Board;
public contextMenuItems: Array<ContextMenuItem>;
public sortOption: string;
public quickAdd: Task;
public MODAL_CONFIRM_ID: string;
public MODAL_CONFIRM_COMMENT_ID: string;
@Input('column') columnData: Column;
@Input('boards') boards: Array<Board>;
@ -79,7 +80,7 @@ export class ColumnDisplay implements OnInit {
constructor(private elRef: ElementRef,
private auth: AuthService,
private notes: NotificationsService,
private modal: ModalService,
public modal: ModalService,
private stringsService: StringsService,
private boardService: BoardService,
private sanitizer: DomSanitizer) {
@ -391,6 +392,20 @@ export class ColumnDisplay implements OnInit {
return yiq >= 140 ? '#333333' : '#efefef';
}
quickAddClicked(event: any) {
this.preventEnter(event);
if (this.quickAdd.title === '') {
this.showModal();
return;
}
this.quickAdd.column_id = this.columnData.id;
this.addTask(this.quickAdd);
this.quickAdd = new Task();
}
private convertToTask(updatedTask: any) {
let task = new Task(updatedTask.id,
updatedTask.title,
@ -539,20 +554,6 @@ export class ColumnDisplay implements OnInit {
return () => { this.showViewModal(taskId); };
}
private quickAddClicked(event: any) {
this.preventEnter(event);
if (this.quickAdd.title === '') {
this.showModal();
return;
}
this.quickAdd.column_id = this.columnData.id;
this.addTask(this.quickAdd);
this.quickAdd = new Task();
}
private showViewModal(taskId: number) {
let viewTask = this.columnData.tasks
.filter(task => task.id === taskId)[0];

View File

@ -28,23 +28,23 @@ import { BoardService } from '../board.service';
@Component({
selector: 'tb-task',
templateUrl: 'app/board/task/task.component.html'
templateUrl: './task.component.html'
})
export class TaskDisplay implements OnInit {
private strings: any;
private userOptions: UserOptions;
private contextMenuItems: Array<ContextMenuItem>;
private activeBoard: Board;
private boardsList: Array<Board>;
private totalTasks: number;
private completeTasks: number;
private percentComplete: number;
private isOverdue: boolean;
private isNearlyDue: boolean;
public strings: any;
public percentComplete: number;
public userOptions: UserOptions;
public contextMenuItems: Array<ContextMenuItem>;
@Input('task') taskData: Task;
@Input('add-task') addTask: Function;
@Input('edit-task') editTask: Function;

View File

@ -2,21 +2,22 @@ import { Component, Input } from '@angular/core';
@Component({
selector: 'tb-calendar',
templateUrl: 'app/dashboard/calendar/calendar.component.html'
templateUrl: './calendar.component.html'
})
export class Calendar {
private dayLabels = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];
private monthLabels = [
private today: Date;
private tasks: Array<any>; // TODO: Use Task model when created
public dayLabels = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];
public monthLabels = [
'January', 'February', 'March', 'April',
'May', 'June', 'July', 'August',
'September', 'October', 'November', 'December'
];
private today: Date;
private month: number;
private year: number;
private calendarDays: Array<Array<string>>;
private tasks: Array<any>; // TODO: Use Task model when created
public month: number;
public year: number;
public calendarDays: Array<Array<string>>;
@Input('board-id') boardId: number;

View File

@ -3,7 +3,7 @@ import * as Chartist from 'chartist';
@Component({
selector: 'tb-charts',
templateUrl: 'app/dashboard/charts/charts.component.html'
templateUrl: './charts.component.html'
})
export class Charts implements AfterViewInit {
private percentages: Array<number>;

View File

@ -7,7 +7,7 @@ import { Calendar } from './calendar/calendar.component';
@Component({
selector: 'tb-dashboard',
templateUrl: 'app/dashboard/dashboard.component.html'
templateUrl: './dashboard.component.html'
})
export class Dashboard {
constructor(private title: Title) {

View File

@ -11,7 +11,7 @@ import {
@Component({
selector: 'tb-login',
templateUrl: 'app/login/login.component.html'
templateUrl: './login.component.html'
})
export class Login implements OnInit {
version: string;

View File

@ -1,9 +0,0 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
// enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -20,15 +20,12 @@ import { AutoActionsService } from './auto-actions.service';
@Component({
selector: 'tb-auto-actions',
templateUrl: 'app/settings/auto-actions/auto-actions.component.html',
templateUrl: './auto-actions.component.html',
providers: [ AutoActionsService ]
})
export class AutoActions {
private noActionsMessage: string;
private MODAL_CONFIRM_ID: string;
private strings: any;
private activeUser: User;
private actionToRemove: AutoAction;
private newAction: AutoAction;
@ -41,14 +38,19 @@ export class AutoActions {
private typesList: Array<Array<any>>;
private actionSources: Array<Array<any>>;
private loading = true;
private firstRun = true;
private isAddDisabled = true;
private saving = false;
private hasInactiveBoards = false;
public MODAL_CONFIRM_ID: string;
public activeUser: User;
public strings: any;
public saving = false;
public loading = true;
public hasInactiveBoards = false;
constructor(private auth: AuthService,
private modal: ModalService,
public modal: ModalService,
private settings: SettingsService,
private actions: AutoActionsService,
private notes: NotificationsService,

View File

@ -181,7 +181,7 @@
[(ngModel)]="modalProps.newColumnName">
<button type="submit" class="flat"
title="{{ strings['settings_addColumn'] }}"
(click)="modalProps.addColumn($event)">
(click)="modalProps.addColumn()">
<i class="icon icon-plus"></i>
</button>
</form>
@ -215,7 +215,7 @@
[title]="strings['settings_defaultTaskColor']"
[(ngModel)]="modalProps.categoryDefaultColor">
<button type="submit" class="flat" [title]="strings['settings_addCategory']"
(click)="modalProps.addCategory($event)">
(click)="modalProps.addCategory()">
<i class="icon icon-plus"></i>
</button>
</form>
@ -260,7 +260,7 @@
(keyup.enter)="cancelEnterKey($event)"
[(ngModel)]="modalProps.issueTrackerBugId">
<button type="submit" class="flat" [title]="strings['settings_addIssueTracker']"
(click)="modalProps.addIssueTracker($event)">
(click)="modalProps.addIssueTracker()">
<i class="icon icon-plus"></i>
</button>
</form>

View File

@ -25,34 +25,36 @@ class SelectableUser extends User {
@Component({
selector: 'tb-board-admin',
templateUrl: 'app/settings/board-admin/board-admin.component.html',
templateUrl: './board-admin.component.html',
providers: [ BoardAdminService ],
viewProviders: [ DragulaService ]
})
export class BoardAdmin {
private users: Array<User>;
private boards: Array<Board>;
private displayBoards: Array<Board>;
private activeUser: User;
private modalProps: BoardData;
private noBoardsMessage: string;
private boardToRemove: Board;
private strings: any;
private userFilter: string;
private statusFilter: string;
private sortFilter: string;
private hasBAUsers = false;
private loading = true;
private firstRun = true;
private saving = false;
private MODAL_ID: string;
private MODAL_CONFIRM_ID: string;
public users: Array<User>;
public boards: Array<Board>;
public activeUser: User;
public modalProps: BoardData;
public strings: any;
public hasBAUsers = false;
public loading = true;
public saving = false;
public MODAL_ID: string;
public MODAL_CONFIRM_ID: string;
constructor(private auth: AuthService,
private modal: ModalService,
public modal: ModalService,
private settings: SettingsService,
private boardService: BoardAdminService,
private notes: NotificationsService,
@ -188,7 +190,7 @@ export class BoardAdmin {
this.sortBoards();
}
private cancelEnterKey(event: any): void {
cancelEnterKey(event: any): void {
if (event.stopPropagation) {
event.stopPropagation();
}

View File

@ -6,11 +6,11 @@ import { SettingsService } from './settings.service';
@Component({
selector: 'tb-settings',
templateUrl: 'app/settings/settings.component.html',
templateUrl: './settings.component.html',
providers: [ SettingsService ]
})
export class Settings {
private strings: any;
public strings: any;
constructor(private settings: SettingsService,
private stringsService: StringsService,

View File

@ -129,8 +129,8 @@
<button #defaultAction
(click)="addEditUser()" [disabled]="saving">
<i class="icon"
[ngClass]="{ 'icon-plus': modalProps.prefix === '',
'icon-floppy': modalProps.prefix !== '' }"></i>
[ngClass]="{ 'icon-plus': modalProps.prefix,
'icon-floppy': !modalProps.prefix }"></i>
{{ modalProps.prefix ? strings['settings_addUser']
: strings['settings_saveUser'] }}
</button>

View File

@ -21,28 +21,29 @@ import {
@Component({
selector: 'tb-user-admin',
templateUrl: 'app/settings/user-admin/user-admin.component.html',
templateUrl: './user-admin.component.html',
providers: [ UserAdminService ]
})
export class UserAdmin {
private users: Array<UserDisplay>;
private boards: Array<Board>;
private activeUser: User;
private modalProps: ModalProperties;
private userToRemove: UserDisplay;
private strings: any;
private loading = true;
private saving = false;
public boards: Array<Board>;
public activeUser: User;
public modalProps: ModalProperties;
public strings: any;
private MODAL_ID: string;
private MODAL_CONFIRM_ID: string;
public loading = true;
public saving = false;
public MODAL_ID: string;
public MODAL_CONFIRM_ID: string;
constructor(private userService: UserAdminService,
private notes: NotificationsService,
private auth: AuthService,
private settings: SettingsService,
private modal: ModalService,
public modal: ModalService,
private stringsService: StringsService) {
this.MODAL_ID = 'user-addEdit-form';
this.MODAL_CONFIRM_ID = 'user-remove-confirm';

View File

@ -16,17 +16,17 @@ import {
@Component({
selector: 'tb-user-settings',
templateUrl: 'app/settings/user-settings/user-settings.component.html',
templateUrl: './user-settings.component.html',
providers: [ UserSettingsService ]
})
export class UserSettings implements OnInit {
private boards: Array<Board>;
private user: User;
private userOptions: UserOptions;
private changePassword: PassForm;
private changeUsername: UsernameForm;
private changeEmail: EmailForm;
private strings: any;
public boards: Array<Board>;
public user: User;
public userOptions: UserOptions;
public changePassword: PassForm;
public changeUsername: UsernameForm;
public changeEmail: EmailForm;
public strings: any;
constructor(private auth: AuthService,
private notes: NotificationsService,

View File

@ -1,3 +0,0 @@
export * from './auth.guard';
export * from './auth.service';

View File

@ -10,7 +10,7 @@ import { ContextMenuService } from './context-menu.service';
@Component({
selector: 'tb-context-menu',
templateUrl: 'app/shared/context-menu/context-menu.component.html'
templateUrl: './context-menu.component.html'
})
export class ContextMenu {
@Input('menu-items') menuItems: Array<ContextMenuItem>;

View File

@ -1,3 +0,0 @@
export * from './context-menu.component';
export * from './context-menu-item.model';
export * from './context-menu.service';

View File

@ -1,11 +1,28 @@
export * from './auth/index';
export * from './auth/auth.guard';
export * from './auth/auth.service';
export * from './compile/compile.directive';
export * from './constants';
export * from './context-menu/index';
export * from './context-menu/context-menu.component';
export * from './context-menu/context-menu-item.model';
export * from './context-menu/context-menu.service';
export * from './inline-edit/inline-edit.component';
export * from './modal/index';
export * from './models/index';
export * from './notifications/index';
export * from './modal/modal.component';
export * from './modal/modal.service';
export * from './models/activity.model';
export * from './models/api-response.model';
export * from './models/attachment.model';
export * from './models/auto-actions.model';
export * from './models/board.model';
export * from './models/category.model';
export * from './models/column.model';
export * from './models/comment.model';
export * from './models/issue-tracker.model';
export * from './models/notification.model';
export * from './models/task.model';
export * from './models/user-options.model';
export * from './models/user.model';
export * from './notifications/notifications.component';
export * from './notifications/notifications.service';
export * from './strings/strings.service';
export * from './top-nav/top-nav.component';

View File

@ -7,10 +7,10 @@ import {
@Component({
selector: 'inline-edit',
templateUrl: 'app/shared/inline-edit/inline-edit.component.html'
templateUrl: './inline-edit.component.html'
})
export class InlineEdit {
private isDisplay = true;
public isDisplay = true;
@Input() text: string;
@Input() isTextarea: boolean;
@ -22,7 +22,7 @@ export class InlineEdit {
setTimeout(() => { el.focus(); }, 100);
}
editDone(newText: string, event: Event): void {
editDone(newText: string, event?: Event): void {
this.isDisplay = true;
this.text = newText;
this.edit.emit(this.text);

View File

@ -1,3 +0,0 @@
export * from './modal.component';
export * from './modal.service';

View File

@ -9,7 +9,7 @@ import { ModalService } from './modal.service';
@Component({
selector: 'tb-modal',
templateUrl: 'app/shared/modal/modal.component.html',
templateUrl: './modal.component.html',
host: {
'(document:keyup.enter)': 'keyup($event)',
'(document:keyup.escape)': 'keyup($event)'
@ -34,10 +34,19 @@ export class Modal implements OnInit {
this.modalService.registerModal(this);
}
private close(checkBlocking = false): void {
close(checkBlocking = false): void {
this.modalService.close(this.modalId, checkBlocking);
}
filterClick(event: Event): void {
event = event || window.event;
// Prevent click from propagating to modal container
if (event.stopPropagation) {
event.stopPropagation();
}
}
private keyup(event: KeyboardEvent): void {
if (event.keyCode === 27) {
this.modalService.close(this.modalId, true);
@ -48,15 +57,6 @@ export class Modal implements OnInit {
}
}
private filterClick(event: Event): void {
event = event || window.event;
// Prevent click from propagating to modal container
if (event.stopPropagation) {
event.stopPropagation();
}
}
private clickDefaultAction(): void {
if (this.defaultActionElement) {
this.defaultActionElement.nativeElement.click();

View File

@ -1,14 +0,0 @@
export * from './activity.model';
export * from './api-response.model';
export * from './attachment.model';
export * from './auto-actions.model';
export * from './board.model';
export * from './category.model';
export * from './column.model';
export * from './comment.model';
export * from './issue-tracker.model';
export * from './notification.model';
export * from './task.model';
export * from './user-options.model';
export * from './user.model';

View File

@ -1,3 +0,0 @@
export * from './notifications.component';
export * from './notifications.service';

View File

@ -5,10 +5,10 @@ import { NotificationsService } from './notifications.service';
@Component({
selector: 'tb-notifications',
templateUrl: 'app/shared/notifications/notifications.component.html'
templateUrl: './notifications.component.html'
})
export class Notifications {
private notes: Array<Notification>;
public notes: Array<Notification>;
constructor(private notifications: NotificationsService) {
this.notes = new Array<Notification>();

View File

@ -2,17 +2,19 @@ import { Component, Input } from '@angular/core';
import { Router } from '@angular/router';
import { Constants } from '../constants';
import { AuthService } from '../auth/index';
import { Notification } from '../models/index';
import { NotificationsService } from '../notifications/index';
import {
AuthService,
NotificationsService,
Notification
} from '../index';
import { StringsService } from '../strings/strings.service';
@Component({
selector: 'tb-top-nav',
templateUrl: 'app/shared/top-nav/top-nav.component.html'
templateUrl: './top-nav.component.html'
})
export class TopNav {
private strings: any;
public strings: any;
@Input('page-name') pageName: string = '';

View File

@ -0,0 +1,3 @@
export const environment = {
production: true
};

View File

@ -0,0 +1,8 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = {
production: false
};

View File

@ -1,25 +1,22 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<title>TaskBoard - Kanban App</title>
<base href="/dist/">
<head>
<meta charset="utf-8">
<title>TaskBoard - Kanban App</title>
<base href="/~kiswa/TaskBoard/dist/">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="cleartype" content="on">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="cleartype" content="on">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="Matthew Ross">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="Matthew Ross">
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<app-component>
<div class="loading">TaskBoard is Loading...</div>
</app-component>
<script src="js/vendor.js"></script>
<script src="js/bundle.js"></script>
</body>
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-component>
<div class="loading">TaskBoard is Loading...</div>
</app-component>
</body>
</html>

12
src/main.ts Normal file
View File

@ -0,0 +1,12 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));

79
src/polyfills.ts Normal file
View File

@ -0,0 +1,79 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/weak-map';
import 'core-js/es6/set';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
import 'core-js/es6/reflect';
/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import 'core-js/es7/reflect';
/**
* Required to support Web Animations `@angular/platform-browser/animations`.
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
*/
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
/*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*/
// (window as any).__Zone_enable_cross_context_check = true;
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/

View File

@ -1,9 +1,9 @@
@font-face {
font-family: 'fontello';
src: url('./fonts/fontello.eot');
src: url('./fonts/fontello.woff') format('woff'),
url('./fonts/fontello.ttf') format('truetype'),
url('./fonts/fontello.svg') format('svg');
src: url('../fonts/fontello.eot');
src: url('../fonts/fontello.woff') format('woff'),
url('../fonts/fontello.ttf') format('truetype'),
url('../fonts/fontello.svg') format('svg');
font-weight: normal;
font-style: normal;
}

View File

@ -1,5 +1,3 @@
@import 'neat-helpers';
//$visual-grid: true;
$visual-grid-color: #f00;
$visual-grid-index: front;

20
src/test.ts Normal file
View File

@ -0,0 +1,20 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

13
src/tsconfig.app.json Normal file
View File

@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "es2015",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}

19
src/tsconfig.spec.json Normal file
View File

@ -0,0 +1,19 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"baseUrl": "./",
"module": "commonjs",
"types": [
"jasmine",
"node"
]
},
"files": [
"test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

5
src/typings.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
/* SystemJS module definition */
declare var module: NodeModule;
interface NodeModule {
id: string;
}

View File

@ -1,48 +0,0 @@
(function(global) {
var map = {
'app': 'build',
'dragula': 'node_modules/dragula/dist/dragula.js',
'ng2-dragula': 'node_modules/ng2-dragula',
'rxjs': 'node_modules/rxjs',
'@angular': 'node_modules/@angular',
'chartist': 'node_modules/chartist/dist/chartist.js',
'marked': 'node_modules/marked/lib/marked.js',
'highlight.js': 'node_modules/highlight.js/lib'
};
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'ng2-dragula': { defaultExtension: 'js' },
'highlight.js': { main: 'index.js', defaultExtension: 'js' }
};
var angularPackages = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router'
];
angularPackages.forEach(function(pkgName) {
packages['@angular/' + pkgName] = {
main: 'bundles/' + pkgName + '.umd.js',
defaultExtension: 'js'
};
});
var config = {
map,
packages
};
System.config(config);
})(this);

BIN
tests.db Normal file

Binary file not shown.

View File

@ -1,22 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": true,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"lib": [ "es2015", "dom" ],
"typeRoots": [ "node_modules/@types" ],
"types": [
"chartist",
"core-js",
"marked",
"highlight.js"
]
}
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
]
}
}

View File

@ -1,73 +1,143 @@
{
"rules": {
"member-ordering": [ true, {
"order": [
"private-instance-field",
"public-instance-field",
"constructor",
"public-instance-method",
"private-instance-method"
]
}],
"no-reference": true,
"only-arrow-functions": true,
"curly": true,
"forin": true,
"label-position": true,
"no-conditional-assignment": true,
"no-console": [true, "log", "error"],
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-invalid-this": true,
"no-shadowed-variable": true,
"no-string-literal": true,
"no-switch-case-fall-through": true,
"no-unsafe-finally": true,
"no-unused-expression": true,
"no-var-keyword": true,
"radix": true,
"triple-equals": [ true,
"allow-null-check",
"allow-undefined-check"
],
"use-isnan": true,
"cyclomatic-complexity": true,
"eofline": true,
"indent": [ true, "spaces" ],
"linebreak-style": [ true, "LF" ],
"max-line-length": [ true, 120 ],
"trailing-comma": [ true, {
"multiline": "never",
"singleline": "never"
}],
"align": [ true,
"arguments",
"parameters",
"statements"
],
"array-type": [ true, "generic" ],
"arrow-parens": [ true, "ban-single-arg-parens" ],
"class-name": true,
"comment-format": [ true, "check-space" ],
"new-parens": true,
"no-consecutive-blank-lines": [ true, 2 ],
"object-literal-key-quotes": [ true, "as-needed" ],
"object-literal-shorthand": true,
"one-line": [ true, "check-catch", "check-finally", "check-else" ],
"quotemark": [ true, "single", "avoid-escape" ],
"semicolon": [ true, "always" ],
"variable-name": [ true, "check-format", "ban-keywords" ],
"whitespace": [ true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type",
"check-typecast"
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs",
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-output-on-prefix": true,
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true
}
}