diff options
author | crupest <crupest@outlook.com> | 2019-04-13 13:03:18 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-04-13 13:03:18 +0800 |
commit | 72890735ced2edc8ccecfed811393e951de5c091 (patch) | |
tree | 39cf181a18a3dc443dbab5669a04d0a23cdefd00 /Timeline/ClientApp | |
parent | 19cae15eba2bcede41b818e1b8ab7fd5ac92eb05 (diff) | |
download | timeline-72890735ced2edc8ccecfed811393e951de5c091.tar.gz timeline-72890735ced2edc8ccecfed811393e951de5c091.tar.bz2 timeline-72890735ced2edc8ccecfed811393e951de5c091.zip |
Init separate.
Diffstat (limited to 'Timeline/ClientApp')
88 files changed, 0 insertions, 2766 deletions
diff --git a/Timeline/ClientApp/.editorconfig b/Timeline/ClientApp/.editorconfig deleted file mode 100644 index 6e87a003..00000000 --- a/Timeline/ClientApp/.editorconfig +++ /dev/null @@ -1,13 +0,0 @@ -# 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 diff --git a/Timeline/ClientApp/.gitignore b/Timeline/ClientApp/.gitignore deleted file mode 100644 index e1f679be..00000000 --- a/Timeline/ClientApp/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -# 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 - -# System Files -.DS_Store -Thumbs.db diff --git a/Timeline/ClientApp/.prettierrc.json b/Timeline/ClientApp/.prettierrc.json deleted file mode 100644 index 6c70cb20..00000000 --- a/Timeline/ClientApp/.prettierrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "printWidth": 140, - "singleQuote": true -} diff --git a/Timeline/ClientApp/.vscode/launch.json b/Timeline/ClientApp/.vscode/launch.json deleted file mode 100644 index 73e17a72..00000000 --- a/Timeline/ClientApp/.vscode/launch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "chrome", - "request": "launch", - "name": "Launch app", - "url": "https://localhost:5001", - "webRoot": "${workspaceFolder}" - } - ] -} diff --git a/Timeline/ClientApp/README.md b/Timeline/ClientApp/README.md deleted file mode 100644 index 9f66fc75..00000000 --- a/Timeline/ClientApp/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Timeline - -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.0. - -## Development server - -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. - -## Code scaffolding - -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. - -## Build - -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Running end-to-end tests - -Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/Timeline/ClientApp/angular.json b/Timeline/ClientApp/angular.json deleted file mode 100644 index 9a696714..00000000 --- a/Timeline/ClientApp/angular.json +++ /dev/null @@ -1,151 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "cli": { - "packageManager": "yarn" - }, - "newProjectRoot": "projects", - "projects": { - "Timeline": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": {}, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "progress": true, - "extractCss": true, - "outputPath": "dist", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.app.json", - "assets": [ - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "extractCss": true, - "namedChunks": false, - "aot": true, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "Timeline:build" - }, - "configurations": { - "production": { - "browserTarget": "Timeline:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "Timeline:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.spec.json", - "karmaConfig": "src/karma.conf.js", - "styles": [ - "src/styles.css" - ], - "scripts": [], - "assets": [ - "src/assets" - ] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "src/tsconfig.app.json", - "src/tsconfig.spec.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - }, - "server": { - "builder": "@angular-devkit/build-angular:server", - "options": { - "outputPath": "dist-server", - "main": "src/main.ts", - "tsConfig": "src/tsconfig.server.json" - }, - "configurations": { - "dev": { - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": true - }, - "production": { - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false - } - } - } - } - }, - "Timeline-e2e": { - "root": "e2e/", - "projectType": "application", - "architect": { - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "Timeline:serve" - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": "e2e/tsconfig.e2e.json", - "exclude": [ - "**/node_modules/**" - ] - } - } - } - } - }, - "defaultProject": "Timeline" -} diff --git a/Timeline/ClientApp/e2e/protractor.conf.js b/Timeline/ClientApp/e2e/protractor.conf.js deleted file mode 100644 index 86776a39..00000000 --- a/Timeline/ClientApp/e2e/protractor.conf.js +++ /dev/null @@ -1,28 +0,0 @@ -// 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: [ - './src/**/*.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: require('path').join(__dirname, './tsconfig.e2e.json') - }); - jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); - } -};
\ No newline at end of file diff --git a/Timeline/ClientApp/e2e/src/app.e2e-spec.ts b/Timeline/ClientApp/e2e/src/app.e2e-spec.ts deleted file mode 100644 index 5b3b4b27..00000000 --- a/Timeline/ClientApp/e2e/src/app.e2e-spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { AppPage } from './app.po'; - -describe('App', () => { - let page: AppPage; - - beforeEach(() => { - page = new AppPage(); - }); - - it('should display welcome message', () => { - page.navigateTo(); - expect(page.getMainHeading()).toEqual('Hello, world!'); - }); -}); diff --git a/Timeline/ClientApp/e2e/src/app.po.ts b/Timeline/ClientApp/e2e/src/app.po.ts deleted file mode 100644 index 24bc8b3c..00000000 --- a/Timeline/ClientApp/e2e/src/app.po.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { browser, by, element } from 'protractor'; - -export class AppPage { - navigateTo() { - return browser.get('/'); - } - - getMainHeading() { - return element(by.css('app-root h1')).getText(); - } -} diff --git a/Timeline/ClientApp/e2e/tsconfig.e2e.json b/Timeline/ClientApp/e2e/tsconfig.e2e.json deleted file mode 100644 index a6dd6220..00000000 --- a/Timeline/ClientApp/e2e/tsconfig.e2e.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "outDir": "../out-tsc/app", - "module": "commonjs", - "target": "es5", - "types": [ - "jasmine", - "jasminewd2", - "node" - ] - } -}
\ No newline at end of file diff --git a/Timeline/ClientApp/package.json b/Timeline/ClientApp/package.json deleted file mode 100644 index 7c6d28f0..00000000 --- a/Timeline/ClientApp/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "timeline", - "version": "0.0.0", - "scripts": { - "ng": "ng", - "start": "ng serve", - "start-dotnet": "dotnet run --project ../Timeline.csproj", - "build": "ng build", - "build:ssr": "ng run Timeline:server:dev", - "test": "ng test", - "lint": "ng lint", - "e2e": "ng e2e" - }, - "private": true, - "dependencies": { - "@angular/animations": "^7.2.4", - "@angular/cdk": "^7.3.2", - "@angular/common": "^7.2.4", - "@angular/compiler": "^7.2.4", - "@angular/core": "^7.2.4", - "@angular/forms": "^7.2.4", - "@angular/http": "^7.2.4", - "@angular/material": "^7.3.2", - "@angular/platform-browser": "^7.2.4", - "@angular/platform-browser-dynamic": "^7.2.4", - "@angular/platform-server": "^7.2.4", - "@angular/router": "^7.2.4", - "@nguniversal/module-map-ngfactory-loader": "^7.1.0", - "aspnet-prerendering": "^3.0.1", - "core-js": "^2.6.3", - "rxjs": "^6.3.3", - "zone.js": "^0.8.29" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^0.12.3", - "@angular/cli": "^7.3.1", - "@angular/compiler-cli": "^7.2.4", - "@angular/language-service": "^7.2.4", - "@types/jasmine": "^3.3.8", - "@types/jasminewd2": "^2.0.6", - "@types/node": "^10.12.19", - "codelyzer": "^4.5.0", - "jasmine-core": "^3.3.0", - "jasmine-spec-reporter": "^4.2.1", - "karma": "^4.0.0", - "karma-chrome-launcher": "^2.2.0", - "karma-coverage-istanbul-reporter": "^2.0.4", - "karma-jasmine": "^2.0.1", - "karma-jasmine-html-reporter": "^1.4.0", - "karma-junit-reporter": "^1.2.0", - "tslint": "^5.12.1", - "typescript": "~3.2.4" - }, - "optionalDependencies": { - "node-sass": "^4.9.3", - "protractor": "^5.4.0", - "ts-node": "^5.0.1" - } -} diff --git a/Timeline/ClientApp/src/app/app.component.css b/Timeline/ClientApp/src/app/app.component.css deleted file mode 100644 index 13a44248..00000000 --- a/Timeline/ClientApp/src/app/app.component.css +++ /dev/null @@ -1,10 +0,0 @@ -a.icp-record { - color: grey; - text-decoration: none; - font-size: 0.8rem; - margin: 0 5vw; -} - -footer { - display: flex; -} diff --git a/Timeline/ClientApp/src/app/app.component.html b/Timeline/ClientApp/src/app/app.component.html deleted file mode 100644 index 92c88625..00000000 --- a/Timeline/ClientApp/src/app/app.component.html +++ /dev/null @@ -1,20 +0,0 @@ -<body> - <mat-toolbar color="primary" class="mat-elevation-z4"> - <a mat-button routerLink="/"> - <img width="30" height="30" src="assets/icon.svg">Timeline</a> - <a mat-button routerLink="/todo">TodoList</a> - <span class="fill-remaining-space"></span> - <a mat-icon-button [routerLink]="[{outlets: {user: ['login']}}]"> - <mat-icon>account_circle</mat-icon> - </a> - </mat-toolbar> - - <div> - <router-outlet></router-outlet> - </div> - - <footer> - <span class="fill-remaining-space"></span> - <a class="icp-record" href="http://www.miitbeian.gov.cn/state/outPortal/loginPortal.action" target=”_blank”>鄂ICP备18030913号-1</a> - </footer> -</body> diff --git a/Timeline/ClientApp/src/app/app.component.ts b/Timeline/ClientApp/src/app/app.component.ts deleted file mode 100644 index 33f33048..00000000 --- a/Timeline/ClientApp/src/app/app.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component } from '@angular/core'; - -import { UserService } from './user/user.service'; - -@Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] -}) -export class AppComponent { - // never remove userService because we need it explicit constructing. - constructor(userService: UserService) { } -} diff --git a/Timeline/ClientApp/src/app/app.module.ts b/Timeline/ClientApp/src/app/app.module.ts deleted file mode 100644 index b75e10e2..00000000 --- a/Timeline/ClientApp/src/app/app.module.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { MatIconModule, MatButtonModule, MatToolbarModule, MatDialogModule } from '@angular/material'; - -import { AppComponent } from './app.component'; - -import { TodoModule } from './todo/todo.module'; -import { HomeModule } from './home/home.module'; -import { UserModule } from './user/user.module'; -import { UserService } from './user/user.service'; - - -@NgModule({ - declarations: [AppComponent], - imports: [ - BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), - BrowserAnimationsModule, - MatIconModule, MatButtonModule, MatToolbarModule, MatDialogModule, - HomeModule, TodoModule, UserModule, - RouterModule.forRoot([ - { path: '', redirectTo: '/home', pathMatch: 'full' }, - ]) - ], - providers: [UserService], - bootstrap: [AppComponent] -}) -export class AppModule { } diff --git a/Timeline/ClientApp/src/app/app.server.module.ts b/Timeline/ClientApp/src/app/app.server.module.ts deleted file mode 100644 index cfb0e021..00000000 --- a/Timeline/ClientApp/src/app/app.server.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NgModule } from '@angular/core'; -import { ServerModule } from '@angular/platform-server'; -import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader'; -import { AppComponent } from './app.component'; -import { AppModule } from './app.module'; - -@NgModule({ - imports: [AppModule, ServerModule, ModuleMapLoaderModule], - bootstrap: [AppComponent] -}) -export class AppServerModule { } diff --git a/Timeline/ClientApp/src/app/home/home.component.css b/Timeline/ClientApp/src/app/home/home.component.css deleted file mode 100644 index 76297a9e..00000000 --- a/Timeline/ClientApp/src/app/home/home.component.css +++ /dev/null @@ -1,49 +0,0 @@ -p { - font-size: 2rem; - margin: 0; -} - -.bold { - font-weight: 600; -} - -#loginBox { - display: inline-grid; - grid-template: "username-label username-input" auto - "password-label password-input" auto - "login-button login-button" auto - "message message" auto - / max-content max-content; - align-items: center; - padding: 10px; - border: solid black 1px; -} - -#usernameLabel { - grid-area: username-label; -} - -#usernameInput { - grid-area: username-input; - margin: 2px; -} - -#passwordLabel { - grid-area: password-label; -} - -#passwordInput { - grid-area: password-input; - margin: 2px; -} - -#loginButton { - grid-area: login-button; - justify-self: end; -} - -#loginMessage { - grid-area: message; - justify-self: end; - color: red; -} diff --git a/Timeline/ClientApp/src/app/home/home.component.html b/Timeline/ClientApp/src/app/home/home.component.html deleted file mode 100644 index 28ab3039..00000000 --- a/Timeline/ClientApp/src/app/home/home.component.html +++ /dev/null @@ -1,3 +0,0 @@ -<h2 class="mat-h2"> - This page is under <span class="bold">construction</span>! -</h2> diff --git a/Timeline/ClientApp/src/app/home/home.component.spec.ts b/Timeline/ClientApp/src/app/home/home.component.spec.ts deleted file mode 100644 index 74bedd08..00000000 --- a/Timeline/ClientApp/src/app/home/home.component.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HomeComponent } from './home.component'; - - -describe('HomeComponent', () => { - let component: HomeComponent; - let fixture: ComponentFixture<HomeComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [HomeComponent], - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HomeComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/Timeline/ClientApp/src/app/home/home.component.ts b/Timeline/ClientApp/src/app/home/home.component.ts deleted file mode 100644 index 0cb0d0f5..00000000 --- a/Timeline/ClientApp/src/app/home/home.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-home', - templateUrl: './home.component.html', - styleUrls: ['./home.component.css'] -}) -export class HomeComponent { - -} diff --git a/Timeline/ClientApp/src/app/home/home.module.ts b/Timeline/ClientApp/src/app/home/home.module.ts deleted file mode 100644 index 98456238..00000000 --- a/Timeline/ClientApp/src/app/home/home.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RouterModule } from '@angular/router'; - -import { HomeComponent } from './home.component'; - -@NgModule({ - declarations: [HomeComponent], - imports: [ - CommonModule, - RouterModule.forChild([ - { path: 'home', component: HomeComponent } - ]) - ], - exports: [RouterModule] -}) -export class HomeModule { } diff --git a/Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts b/Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts deleted file mode 100644 index 40484387..00000000 --- a/Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { ParamMap, ActivatedRouteSnapshot, ActivatedRoute } from '@angular/router'; - -import { Observable, BehaviorSubject } from 'rxjs'; -import { map } from 'rxjs/operators'; - -import { PartialMock } from './mock'; - -export interface ParamMapCreator { [name: string]: string | string[]; } - -export class MockActivatedRouteSnapshot implements PartialMock<ActivatedRouteSnapshot> { - - private paramMapInternal: ParamMap; - - constructor({ mockParamMap }: { mockParamMap: ParamMapCreator } = { mockParamMap: {} }) { - this.paramMapInternal = { - keys: Object.keys(mockParamMap), - get(name: string): string | null { - const param = mockParamMap[name]; - if (typeof param === 'string') { - return param; - } else if (param instanceof Array) { - if (param.length === 0) { - return null; - } - return param[0]; - } - return null; - }, - getAll(name: string): string[] { - const param = mockParamMap[name]; - if (typeof param === 'string') { - return [param]; - } else if (param instanceof Array) { - return param; - } - return []; - }, - has(name: string): boolean { - return mockParamMap.hasOwnProperty(name); - } - }; - } - - get paramMap(): ParamMap { - return this.paramMapInternal; - } -} - -export class MockActivatedRoute implements PartialMock<ActivatedRoute> { - - snapshot$ = new BehaviorSubject<MockActivatedRouteSnapshot>(new MockActivatedRouteSnapshot()); - - get paramMap(): Observable<ParamMap> { - return this.snapshot$.pipe(map(snapshot => snapshot.paramMap)); - } - - get snapshot(): MockActivatedRouteSnapshot { - return this.snapshot$.value; - } - - pushSnapshot(snapshot: MockActivatedRouteSnapshot) { - this.snapshot$.next(snapshot); - } - - pushSnapshotWithParamMap(mockParamMap: ParamMapCreator) { - this.pushSnapshot(new MockActivatedRouteSnapshot({mockParamMap})); - } -} diff --git a/Timeline/ClientApp/src/app/test-utilities/mock.ts b/Timeline/ClientApp/src/app/test-utilities/mock.ts deleted file mode 100644 index c3e368f0..00000000 --- a/Timeline/ClientApp/src/app/test-utilities/mock.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type Mock<T> = { - [P in keyof T]: T[P] extends Function ? T[P] : T[P] | Mock<T[P]>; -}; - -export type PartialMock<T> = { - [P in keyof T]?: T[P] extends Function ? T[P] : T[P] | PartialMock<T[P]> | Mock<T[P]>; -}; diff --git a/Timeline/ClientApp/src/app/test-utilities/router-link.mock.ts b/Timeline/ClientApp/src/app/test-utilities/router-link.mock.ts deleted file mode 100644 index 7f4cde4d..00000000 --- a/Timeline/ClientApp/src/app/test-utilities/router-link.mock.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Directive, Input } from '@angular/core'; - -@Directive({ - /* tslint:disable-next-line:directive-selector*/ - selector: '[routerLink]' -}) -export class RouterLinkStubDirective { - @Input('routerLink') linkParams: any; -} diff --git a/Timeline/ClientApp/src/app/test-utilities/storage.mock.ts b/Timeline/ClientApp/src/app/test-utilities/storage.mock.ts deleted file mode 100644 index 0ba5aa35..00000000 --- a/Timeline/ClientApp/src/app/test-utilities/storage.mock.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Mock } from './mock'; -import { nullIfUndefined } from '../utilities/language-untilities'; - -export function createMockStorage(): Mock<Storage> { - const map: { [key: string]: string } = {}; - return { - get length(): number { - return Object.keys(map).length; - }, - key(index: number): string | null { - const keys = Object.keys(map); - if (index >= keys.length) { return null; } - return keys[index]; - }, - clear() { - Object.keys(map).forEach(key => delete map.key); - }, - getItem(key: string): string | null { - return nullIfUndefined(map[key]); - }, - setItem(key: string, value: string) { - map[key] = value; - }, - removeItem(key: string) { - delete map[key]; - } - }; -} diff --git a/Timeline/ClientApp/src/app/todo/todo-item.ts b/Timeline/ClientApp/src/app/todo/todo-item.ts deleted file mode 100644 index b19d8335..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-item.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface TodoItem { - number: number; - title: string; - isClosed: boolean; - detailUrl: string; -} diff --git a/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.css b/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.css deleted file mode 100644 index dcf25fd8..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.css +++ /dev/null @@ -1,25 +0,0 @@ -.item-card { - padding: 0; - display: flex; - overflow: hidden; -} - -.item-body-box { - margin: 5px!important -} - -.item-color-block { - width: 15px; - align-self: stretch; - flex: 0 0 auto; -} - -.item-title { - vertical-align: middle; -} - -.item-detail-button { - width: unset; - height: unset; - line-height: unset; -} diff --git a/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.html b/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.html deleted file mode 100644 index 6f76e73b..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.html +++ /dev/null @@ -1,9 +0,0 @@ -<mat-card class="mat-elevation-z2 item-card"> - <span class="item-color-block" [class.color-block-closed]="item.isClosed" [class.color-block-open]="!item.isClosed"></span> - <div class="mat-h3 item-body-box"> - <span class="item-title">{{ item.number }}. {{ item.title }}</span> - <a mat-icon-button class="item-detail-button" [href]="item.detailUrl"> - <mat-icon>arrow_forward</mat-icon> - </a> - </div> -</mat-card> diff --git a/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.spec.ts b/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.spec.ts deleted file mode 100644 index 239ffc42..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; - -import { TodoItem } from '../todo-item'; -import { TodoItemComponent } from '../todo-item/todo-item.component'; - -describe('TodoItemComponent', () => { - let component: TodoItemComponent; - let fixture: ComponentFixture<TodoItemComponent>; - - const mockTodoItem: TodoItem = { - number: 1, - title: 'Title', - isClosed: true, - detailUrl: '/detail', - }; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [TodoItemComponent], - schemas: [NO_ERRORS_SCHEMA] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(TodoItemComponent); - component = fixture.componentInstance; - component.item = mockTodoItem; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should set title', () => { - expect((fixture.debugElement.query(By.css('span.item-title')).nativeElement as HTMLSpanElement).textContent).toBe( - mockTodoItem.number + '. ' + mockTodoItem.title - ); - }); - - it('should set detail link', () => { - expect(fixture.debugElement.query(By.css('a.item-detail-button')).properties['href']).toBe(mockTodoItem.detailUrl); - }); -}); diff --git a/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.ts b/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.ts deleted file mode 100644 index b5c51229..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-item/todo-item.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import { TodoItem } from '../todo-item'; - -@Component({ - selector: 'app-todo-item', - templateUrl: './todo-item.component.html', - styleUrls: ['./todo-item.component.css', '../todo-list-color-block.css'] -}) -export class TodoItemComponent { - @Input() item!: TodoItem; -} diff --git a/Timeline/ClientApp/src/app/todo/todo-list-color-block.css b/Timeline/ClientApp/src/app/todo/todo-list-color-block.css deleted file mode 100644 index 5e0d4ba9..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-list-color-block.css +++ /dev/null @@ -1,7 +0,0 @@ -.color-block-open { - background: red; -} - -.color-block-closed { - background: green; -} diff --git a/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.css b/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.css deleted file mode 100644 index 754b786e..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.css +++ /dev/null @@ -1,39 +0,0 @@ -.align-self-bottom { - align-self: flex-end; -} - -.item-box { - display: flex; - width: 100%; - box-sizing: border-box; -} - -.first-item-box { - justify-content: space-between; - padding: 0 0 5px 5px; -} - -.non-first-item-box { - padding: 5px; -} - -.space { - flex: 1 4 20px; -} - -.sample-box { - box-sizing: border-box; - align-self: flex-start; -} - -.sample-item { - display: flex; - align-items: center; -} - -.sample-color-block { - border-radius: 0.2em; - width: 1em; - height: 1em; - margin-right: 2px; -} diff --git a/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.html b/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.html deleted file mode 100644 index 50180fe8..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.html +++ /dev/null @@ -1,21 +0,0 @@ -<mat-progress-bar *ngIf="!isLoadCompleted" mode="indeterminate"></mat-progress-bar> - -<mat-list> - <mat-list-item *ngFor="let item of items; let i = index" style="height:unset;"> - <div class="item-box" [class.first-item-box]="i === 0" [class.non-first-item-box]="i !== 0"> - <app-todo-item @itemEnter [class.align-self-bottom]="i === 0" [item]="item"></app-todo-item> - <div class="space"></div> - <div class="sample-box" *ngIf="i === 0"> - <div class="mat-caption sample-item"> - <span class="sample-color-block color-block-open"></span> - <span> means working now.</span> - </div> - <div class="mat-caption sample-item"> - <span class="sample-color-block color-block-closed"></span> - <span> means completed.</span> - </div> - <div class="mat-caption">click on item to see details.</div> - </div> - </div> - </mat-list-item> -</mat-list> diff --git a/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.spec.ts b/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.spec.ts deleted file mode 100644 index 16c77376..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; - -import { Observable, from } from 'rxjs'; -import { delay } from 'rxjs/operators'; - -import { TodoItem } from '../todo-item'; -import { TodoPageComponent } from './todo-page.component'; -import { TodoService } from '../todo-service/todo.service'; - - -@Component({ - /* tslint:disable-next-line:component-selector*/ - selector: 'mat-progress-bar', - template: '' -}) -class MatProgressBarStubComponent { } - -function asyncArray<T>(data: T[]): Observable<T> { - return from(data).pipe(delay(0)); -} - -describe('TodoListPageComponent', () => { - let component: TodoPageComponent; - let fixture: ComponentFixture<TodoPageComponent>; - - const mockTodoItems: TodoItem[] = [ - { - number: 0, - title: 'Test title 1', - isClosed: true, - detailUrl: 'test_url1' - }, - { - number: 1, - title: 'Test title 2', - isClosed: false, - detailUrl: 'test_url2' - } - ]; - - beforeEach(async(() => { - const mockTodoService: jasmine.SpyObj<TodoService> = jasmine.createSpyObj('TodoService', ['getWorkItemList']); - - mockTodoService.getWorkItemList.and.returnValue(asyncArray(mockTodoItems)); - - TestBed.configureTestingModule({ - declarations: [TodoPageComponent, MatProgressBarStubComponent], - imports: [NoopAnimationsModule], - providers: [{ provide: TodoService, useValue: mockTodoService }], - schemas: [NO_ERRORS_SCHEMA] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(TodoPageComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - fixture.detectChanges(); - expect(component).toBeTruthy(); - }); - - it('should show progress bar during loading', () => { - fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('mat-progress-bar'))).toBeTruthy(); - }); - - it('should hide progress bar after loading', fakeAsync(() => { - fixture.detectChanges(); - tick(); - fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('mat-progress-bar'))).toBeFalsy(); - })); -}); diff --git a/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.ts b/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.ts deleted file mode 100644 index 7b658228..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-page/todo-page.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { trigger, transition, style, animate } from '@angular/animations'; - - -import { TodoItem } from '../todo-item'; -import { TodoService } from '../todo-service/todo.service'; - -@Component({ - selector: 'app-todo-page', - templateUrl: './todo-page.component.html', - styleUrls: ['./todo-page.component.css', '../todo-list-color-block.css'], - animations: [ - trigger('itemEnter', [ - transition(':enter', [ - style({ - transform: 'translateX(-100%) translateX(-20px)' - }), - animate('400ms ease-out', style({ - transform: 'none' - })) - ]) - ]) - ] -}) -export class TodoPageComponent implements OnInit { - - items: TodoItem[] = []; - isLoadCompleted = false; - - constructor(private todoService: TodoService) { - } - - ngOnInit() { - this.todoService.getWorkItemList().subscribe({ - next: result => this.items.push(result), - complete: () => { this.isLoadCompleted = true; } - }); - } -} diff --git a/Timeline/ClientApp/src/app/todo/todo-service/http-entities.ts b/Timeline/ClientApp/src/app/todo/todo-service/http-entities.ts deleted file mode 100644 index 3971617c..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-service/http-entities.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const githubBaseUrl = 'https://api.github.com/repos/crupest/Timeline'; - -export interface IssueResponseItem { - number: number; - title: string; - state: string; - html_url: string; - pull_request?: any; -} - -export type IssueResponse = IssueResponseItem[]; diff --git a/Timeline/ClientApp/src/app/todo/todo-service/todo.service.spec.ts b/Timeline/ClientApp/src/app/todo/todo-service/todo.service.spec.ts deleted file mode 100644 index 679dc8b7..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-service/todo.service.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { toArray } from 'rxjs/operators'; - -import { TodoItem } from '../todo-item'; -import { TodoService } from './todo.service'; -import { IssueResponse, githubBaseUrl } from './http-entities'; - - -describe('TodoService', () => { - beforeEach(() => TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] - })); - - it('should be created', () => { - const service: TodoService = TestBed.get(TodoService); - expect(service).toBeTruthy(); - }); - - it('should work well', () => { - const service: TodoService = TestBed.get(TodoService); - - const mockIssueList: IssueResponse = [{ - number: 1, - title: 'Issue title 1', - state: 'open', - html_url: 'test_url1' - }, { - number: 2, - title: 'Issue title 2', - state: 'closed', - html_url: 'test_url2', - pull_request: {} - }]; - - const mockTodoItemList: TodoItem[] = [{ - number: 1, - title: 'Issue title 1', - isClosed: false, - detailUrl: 'test_url1' - }]; - - service.getWorkItemList().pipe(toArray()).subscribe(data => { - expect(data).toEqual(mockTodoItemList); - }); - - const httpController: HttpTestingController = TestBed.get(HttpTestingController); - - httpController.expectOne(request => request.url === githubBaseUrl + '/issues' && - request.params.get('state') === 'all').flush(mockIssueList); - - httpController.verify(); - }); -}); diff --git a/Timeline/ClientApp/src/app/todo/todo-service/todo.service.ts b/Timeline/ClientApp/src/app/todo/todo-service/todo.service.ts deleted file mode 100644 index df63636d..00000000 --- a/Timeline/ClientApp/src/app/todo/todo-service/todo.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable, from } from 'rxjs'; -import { switchMap, map, filter } from 'rxjs/operators'; - -import { IssueResponse, githubBaseUrl } from './http-entities'; -import { TodoItem } from '../todo-item'; - - -@Injectable({ - providedIn: 'root' -}) -export class TodoService { - - constructor(private client: HttpClient) { } - - getWorkItemList(): Observable<TodoItem> { - return this.client.get<IssueResponse>(`${githubBaseUrl}/issues`, { - params: { - state: 'all' - } - }).pipe( - switchMap(result => from(result)), - filter(result => result.pull_request === undefined), // filter out pull requests. - map(result => <TodoItem>{ - number: result.number, - title: result.title, - isClosed: result.state === 'closed', - detailUrl: result.html_url - }) - ); - } -} diff --git a/Timeline/ClientApp/src/app/todo/todo.module.ts b/Timeline/ClientApp/src/app/todo/todo.module.ts deleted file mode 100644 index 5bcfefbd..00000000 --- a/Timeline/ClientApp/src/app/todo/todo.module.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RouterModule } from '@angular/router'; -import { MatListModule, MatIconModule, MatCardModule, MatProgressBarModule, MatButtonModule } from '@angular/material'; -import { HttpClientModule } from '@angular/common/http'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; - -import { TodoItemComponent } from './todo-item/todo-item.component'; -import { TodoPageComponent } from './todo-page/todo-page.component'; - -@NgModule({ - declarations: [ - TodoItemComponent, - TodoPageComponent - ], - imports: [ - CommonModule, HttpClientModule, BrowserAnimationsModule, - MatListModule, MatCardModule, MatIconModule, MatProgressBarModule, MatButtonModule, - RouterModule.forChild([ - { path: 'todo', component: TodoPageComponent } - ]) - ], - exports: [ - RouterModule - ] -}) -export class TodoModule { } diff --git a/Timeline/ClientApp/src/app/user/auth.guard.spec.ts b/Timeline/ClientApp/src/app/user/auth.guard.spec.ts deleted file mode 100644 index 6a36fea6..00000000 --- a/Timeline/ClientApp/src/app/user/auth.guard.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Observable, of } from 'rxjs'; - -import { AuthGuard, AuthStrategy } from './auth.guard'; -import { UserInfo } from './entities'; - -describe('AuthGuard', () => { - class ConfiurableAuthGuard extends AuthGuard { - constructor(mockInternalUserService: any) { - super(mockInternalUserService); - } - - authStrategy: AuthStrategy = 'all'; - } - - let mockUserService: { userInfo$: Observable<UserInfo | null> }; - let guard: ConfiurableAuthGuard; - let onAuthFialedSpy: jasmine.Spy; - - const mockRoles = ['role1', 'role2']; - - interface ActivateResultMap { - nologin: boolean; - loginWithNoRole: boolean; - loginWithMockRoles: boolean; - } - - - function createTest(authStrategy: AuthStrategy, result: ActivateResultMap): () => void { - return () => { - guard.authStrategy = authStrategy; - - function testWith(userInfo: UserInfo | null, r: boolean) { - mockUserService.userInfo$ = of(userInfo); - - const rawResult = guard.canActivate(<any>null, <any>null); - if (typeof rawResult === 'boolean') { - expect(rawResult).toBe(r); - } else if (rawResult instanceof Observable) { - rawResult.subscribe(next => expect(next).toBe(r)); - } else { - throw new Error('Unsupported return type.'); - } - } - - testWith(null, result.nologin); - testWith({ username: 'user', roles: [] }, result.loginWithNoRole); - testWith({ username: 'user', roles: mockRoles }, result.loginWithMockRoles); - }; - } - - beforeEach(() => { - mockUserService = { userInfo$: of(null) }; - guard = new ConfiurableAuthGuard(mockUserService); - onAuthFialedSpy = spyOn(guard, 'onAuthFailed'); - }); - - - it('all should work', createTest('all', { nologin: true, loginWithNoRole: true, loginWithMockRoles: true })); - it('require login should work', createTest('requirelogin', { nologin: false, loginWithNoRole: true, loginWithMockRoles: true })); - it('require no login should work', createTest('requirenologin', { nologin: true, loginWithNoRole: false, loginWithMockRoles: false })); - it('good roles should work', createTest(mockRoles, { nologin: false, loginWithNoRole: false, loginWithMockRoles: true })); - it('bad roles should work', createTest(['role3'], { nologin: false, loginWithNoRole: false, loginWithMockRoles: false })); - - it('auth failed callback should be called', () => { - guard.authStrategy = 'requirelogin'; - (<Observable<boolean>>guard.canActivate(<any>null, <any>null)).subscribe(); - expect(onAuthFialedSpy).toHaveBeenCalled(); - }); -}); diff --git a/Timeline/ClientApp/src/app/user/auth.guard.ts b/Timeline/ClientApp/src/app/user/auth.guard.ts deleted file mode 100644 index 1fc7a7c0..00000000 --- a/Timeline/ClientApp/src/app/user/auth.guard.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Injectable } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; -import { Observable } from 'rxjs'; -import { take, map } from 'rxjs/operators'; - -import { InternalUserService } from './internal-user-service/internal-user.service'; - -export type AuthStrategy = 'all' | 'requirelogin' | 'requirenologin' | string[]; - -export abstract class AuthGuard implements CanActivate { - - constructor(protected internalUserService: InternalUserService) { } - - onAuthFailed() { } - - abstract get authStrategy(): AuthStrategy; - - canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): - Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { - - const { authStrategy } = this; - - if (authStrategy === 'all') { - return true; - } - - return this.internalUserService.userInfo$.pipe(take(1), map(userInfo => { - if (userInfo === null) { - if (authStrategy === 'requirenologin') { - return true; - } - } else { - if (authStrategy === 'requirelogin') { - return true; - } else if (authStrategy instanceof Array) { - const { roles } = userInfo; - if (authStrategy.every(value => roles.includes(value))) { - return true; - } - } - } - - // reach here means auth fails - this.onAuthFailed(); - return false; - })); - } -} - -@Injectable({ - providedIn: 'root' -}) -export class RequireLoginGuard extends AuthGuard { - readonly authStrategy: AuthStrategy = 'requirelogin'; - - // never remove this constructor or you will get an injection error. - constructor(internalUserService: InternalUserService) { - super(internalUserService); - } - - onAuthFailed() { - this.internalUserService.userRouteNavigate(['login']); - } -} - -@Injectable({ - providedIn: 'root' -}) -export class RequireNoLoginGuard extends AuthGuard { - readonly authStrategy: AuthStrategy = 'requirenologin'; - - // never remove this constructor or you will get an injection error. - constructor(internalUserService: InternalUserService) { - super(internalUserService); - } - - onAuthFailed() { - this.internalUserService.userRouteNavigate(['success']); - } -} diff --git a/Timeline/ClientApp/src/app/user/entities.ts b/Timeline/ClientApp/src/app/user/entities.ts deleted file mode 100644 index 6d432ec6..00000000 --- a/Timeline/ClientApp/src/app/user/entities.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface UserCredentials { - username: string; - password: string; -} - -export interface UserInfo { - username: string; - roles: string[]; -} diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/errors.ts b/Timeline/ClientApp/src/app/user/internal-user-service/errors.ts deleted file mode 100644 index 3358a9d9..00000000 --- a/Timeline/ClientApp/src/app/user/internal-user-service/errors.ts +++ /dev/null @@ -1,29 +0,0 @@ -export class BadNetworkError extends Error { - constructor() { - super('Network is bad.'); - } -} - -export class AlreadyLoginError extends Error { - constructor() { - super('Internal logical error. There is already a token saved. Please call validateUserLoginState first.'); - } -} - -export class BadCredentialsError extends Error { - constructor() { - super('Username or password is wrong.'); - } -} - -export class UnknownError extends Error { - constructor(public internalError?: any) { - super('Sorry, unknown error occured!'); - } -} - -export class ServerInternalError extends Error { - constructor(message?: string) { - super('Wrong server response. ' + message); - } -} diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/http-entities.ts b/Timeline/ClientApp/src/app/user/internal-user-service/http-entities.ts deleted file mode 100644 index f52233c9..00000000 --- a/Timeline/ClientApp/src/app/user/internal-user-service/http-entities.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { UserCredentials, UserInfo } from '../entities'; - -export const createTokenUrl = '/api/User/CreateToken'; -export const validateTokenUrl = '/api/User/ValidateToken'; - -export type CreateTokenRequest = UserCredentials; - -export interface CreateTokenResponse { - success: boolean; - token?: string; - userInfo?: UserInfo; -} - -export interface ValidateTokenRequest { - token: string; -} - -export interface ValidateTokenResponse { - isValid: boolean; - userInfo?: UserInfo; -} diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts deleted file mode 100644 index f4a85262..00000000 --- a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { InternalUserService } from './internal-user.service'; - -export function createMockInternalUserService(): jasmine.SpyObj<InternalUserService> { - return jasmine.createSpyObj('InternalUserService', ['userRouteNavigate', 'refreshAndGetUserState', 'tryLogin']); -} diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts deleted file mode 100644 index 15755382..00000000 --- a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { TestBed, fakeAsync, tick } from '@angular/core/testing'; -import { HttpRequest } from '@angular/common/http'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { Router } from '@angular/router'; -import { MatSnackBar } from '@angular/material'; - -import { Mock } from 'src/app/test-utilities/mock'; -import { createMockStorage } from 'src/app/test-utilities/storage.mock'; -import { WINDOW } from '../window-inject-token'; - -import { UserInfo, UserCredentials } from '../entities'; -import { - createTokenUrl, validateTokenUrl, CreateTokenRequest, - CreateTokenResponse, ValidateTokenRequest, ValidateTokenResponse -} from './http-entities'; -import { InternalUserService, SnackBarTextKey, snackBarText, TOKEN_STORAGE_KEY } from './internal-user.service'; -import { repeat } from 'src/app/utilities/language-untilities'; - - -describe('InternalUserService', () => { - let mockLocalStorage: Mock<Storage>; - let mockSnackBar: jasmine.SpyObj<MatSnackBar>; - - beforeEach(() => { - mockLocalStorage = createMockStorage(); - mockSnackBar = jasmine.createSpyObj('MatSnackBar', ['open']); - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { provide: WINDOW, useValue: { localStorage: mockLocalStorage } }, - { provide: Router, useValue: null }, - { provide: MatSnackBar, useValue: mockSnackBar } - ] - }); - }); - - it('should be created', () => { - const service: InternalUserService = TestBed.get(InternalUserService); - expect(service).toBeTruthy(); - }); - - const mockUserInfo: UserInfo = { - username: 'user', - roles: ['user', 'other'] - }; - - const mockToken = 'mock-token'; - - describe('validate token', () => { - const validateTokenRequestMatcher = (req: HttpRequest<ValidateTokenRequest>): boolean => - req.url === validateTokenUrl && req.body !== null && req.body.token === mockToken; - - function createTest( - expectSnackBarTextKey: SnackBarTextKey, - setStorageToken: boolean, - setHttpController?: (controller: HttpTestingController) => void - ): () => void { - return fakeAsync(() => { - if (setStorageToken) { - mockLocalStorage.setItem(TOKEN_STORAGE_KEY, mockToken); - } - TestBed.get(InternalUserService); - const controller = TestBed.get(HttpTestingController) as HttpTestingController; - if (setHttpController) { - setHttpController(controller); - } - controller.verify(); - tick(); - expect(mockSnackBar.open).toHaveBeenCalledWith(snackBarText[expectSnackBarTextKey], jasmine.anything(), jasmine.anything()); - }); - } - - it('no login should work well', createTest('noLogin', false)); - it('already login should work well', createTest('alreadyLogin', true, - controller => controller.expectOne(validateTokenRequestMatcher).flush( - <ValidateTokenResponse>{ isValid: true, userInfo: mockUserInfo }))); - it('invalid login should work well', createTest('invalidLogin', true, - controller => controller.expectOne(validateTokenRequestMatcher).flush(<ValidateTokenResponse>{ isValid: false }))); - it('check fail should work well', createTest('checkFail', true, - controller => repeat(4, () => { - controller.expectOne(validateTokenRequestMatcher).error(new ErrorEvent('Network error', { message: 'simulated network error' })); - }))); - }); - - describe('login should work well', () => { - const mockUserCredentials: UserCredentials = { - username: 'user', - password: 'user' - }; - - function createTest(rememberMe: boolean) { - return () => { - const service: InternalUserService = TestBed.get(InternalUserService); - - service.tryLogin({ ...mockUserCredentials, rememberMe: rememberMe }).subscribe(result => { - expect(result).toEqual(mockUserInfo); - }); - - const httpController = TestBed.get(HttpTestingController) as HttpTestingController; - - httpController.expectOne((request: HttpRequest<CreateTokenRequest>) => - request.url === createTokenUrl && request.body !== null && - request.body.username === mockUserCredentials.username && - request.body.password === mockUserCredentials.password).flush(<CreateTokenResponse>{ - success: true, - token: mockToken, - userInfo: mockUserInfo - }); - - expect(service.currentUserInfo).toEqual(mockUserInfo); - - httpController.verify(); - - expect(mockLocalStorage.getItem(TOKEN_STORAGE_KEY)).toBe(rememberMe ? mockToken : null); - }; - } - - it('remember me should work well', createTest(true)); - it('not remember me should work well', createTest(false)); - }); - - // TODO: test on error situations. -}); diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts deleted file mode 100644 index 66eafde9..00000000 --- a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { Injectable, Inject } from '@angular/core'; -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Router } from '@angular/router'; - -import { Observable, throwError, BehaviorSubject, of } from 'rxjs'; -import { map, catchError, retry, switchMap, tap, filter } from 'rxjs/operators'; - -import { AlreadyLoginError, BadCredentialsError, BadNetworkError, UnknownError, ServerInternalError } from './errors'; -import { - createTokenUrl, validateTokenUrl, CreateTokenRequest, - CreateTokenResponse, ValidateTokenRequest, ValidateTokenResponse -} from './http-entities'; -import { UserCredentials, UserInfo } from '../entities'; -import { MatSnackBar } from '@angular/material'; -import { WINDOW } from '../window-inject-token'; - -export const snackBarText = { - checkFail: 'Failed to check last login', - noLogin: 'No login before!', - alreadyLogin: 'You have login already!', - invalidLogin: 'Last login is no longer invalid!', - ok: 'ok' -}; - -export type SnackBarTextKey = Exclude<keyof typeof snackBarText, 'ok'>; - -export const TOKEN_STORAGE_KEY = 'token'; - -export interface LoginInfo extends UserCredentials { - rememberMe: boolean; -} - -/** - * This service is only used internal in user module. - */ -@Injectable({ - providedIn: 'root' -}) -export class InternalUserService { - - private token: string | null = null; - private userInfoSubject = new BehaviorSubject<UserInfo | null | undefined>(undefined); - - readonly userInfo$: Observable<UserInfo | null> = - <Observable<UserInfo | null>>this.userInfoSubject.pipe(filter(value => value !== undefined)); - - get currentUserInfo(): UserInfo | null | undefined { - return this.userInfoSubject.value; - } - - private openSnackBar(snackBar: MatSnackBar, textKey: SnackBarTextKey) { - setTimeout(() => snackBar.open(snackBarText[textKey], snackBarText.ok, { duration: 2000 }), 0); - } - - constructor(@Inject(WINDOW) private window: Window, private httpClient: HttpClient, private router: Router, snackBar: MatSnackBar) { - const savedToken = this.window.localStorage.getItem(TOKEN_STORAGE_KEY); - if (savedToken === null) { - this.openSnackBar(snackBar, 'noLogin'); - this.userInfoSubject.next(null); - } else { - this.validateToken(savedToken).subscribe(result => { - if (result === null) { - this.window.localStorage.removeItem(TOKEN_STORAGE_KEY); - this.openSnackBar(snackBar, 'invalidLogin'); - this.userInfoSubject.next(null); - } else { - this.token = savedToken; - this.userInfoSubject.next(result); - this.openSnackBar(snackBar, 'alreadyLogin'); - } - }, _ => { - this.openSnackBar(snackBar, 'checkFail'); - this.userInfoSubject.next(null); - }); - } - } - - private validateToken(token: string): Observable<UserInfo | null> { - return this.httpClient.post<ValidateTokenResponse>(validateTokenUrl, <ValidateTokenRequest>{ token: token }).pipe( - retry(3), - switchMap(result => { - if (result.isValid) { - const { userInfo } = result; - if (userInfo) { - return of(userInfo); - } else { - return throwError(new ServerInternalError('IsValid is true but UserInfo is null.')); - } - } else { - return of(null); - } - }), - tap({ - error: error => { - console.error('Failed to validate token.'); - console.error(error); - } - }), - ); - } - - userRouteNavigate(commands: any[] | null) { - this.router.navigate([{ - outlets: { - user: commands - } - }]); - } - - tryLogin(info: LoginInfo): Observable<UserInfo> { - if (this.token) { - return throwError(new AlreadyLoginError()); - } - - return this.httpClient.post<CreateTokenResponse>(createTokenUrl, <CreateTokenRequest>info).pipe( - catchError((error: HttpErrorResponse) => { - if (error.error instanceof ErrorEvent) { - console.error('An error occurred when login: ' + error.error.message); - return throwError(new BadNetworkError()); - } else { - console.error('An unknown error occurred when login: ' + error); - return throwError(new UnknownError(error)); - } - }), - switchMap(result => { - if (result.success) { - if (result.token && result.userInfo) { - this.token = result.token; - if (info.rememberMe) { - this.window.localStorage.setItem(TOKEN_STORAGE_KEY, result.token); - } - this.userInfoSubject.next(result.userInfo); - return of(result.userInfo); - } else { - console.error('An error occurred when login: server return wrong data.'); - return throwError(new ServerInternalError('Token or userInfo is null.')); - } - } else { - console.error('An error occurred when login: wrong credentials.'); - return throwError(new BadCredentialsError()); - } - }) - ); - } - - logout() { - if (this.currentUserInfo === null) { - throw new Error('No login now. You can\'t logout.'); - } - - this.window.localStorage.removeItem(TOKEN_STORAGE_KEY); - this.token = null; - this.userInfoSubject.next(null); - } -} diff --git a/Timeline/ClientApp/src/app/user/redirect.component.ts b/Timeline/ClientApp/src/app/user/redirect.component.ts deleted file mode 100644 index 438b38b9..00000000 --- a/Timeline/ClientApp/src/app/user/redirect.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { InternalUserService } from './internal-user-service/internal-user.service'; - -@Component({ - selector: 'app-redirect', - template: '' -}) -export class RedirectComponent implements OnInit { - - constructor(private userService: InternalUserService) { } - - ngOnInit() { - this.userService.userRouteNavigate(['login']); - } -} diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.css b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.css deleted file mode 100644 index e69de29b..00000000 --- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.css +++ /dev/null diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html deleted file mode 100644 index e8dbb003..00000000 --- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html +++ /dev/null @@ -1 +0,0 @@ -<router-outlet name="user"></router-outlet> diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts deleted file mode 100644 index 47860eee..00000000 --- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Component } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { Router, Event } from '@angular/router'; - -import { Observable } from 'rxjs'; - -import { UserDialogComponent } from './user-dialog.component'; - -@Component({ - /* tslint:disable-next-line:component-selector*/ - selector: 'router-outlet', - template: '' -}) -class RouterOutletStubComponent { } - - -describe('UserDialogComponent', () => { - let component: UserDialogComponent; - let fixture: ComponentFixture<UserDialogComponent>; - - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [UserDialogComponent, RouterOutletStubComponent], - providers: [{ // for the workaround - provide: Router, useValue: { - events: new Observable<Event>() - } - }] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UserDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts deleted file mode 100644 index 2887f0a6..00000000 --- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; -import { RouterOutlet, Router, ActivationStart } from '@angular/router'; - -@Component({ - selector: 'app-user-dialog', - templateUrl: './user-dialog.component.html', - styleUrls: ['./user-dialog.component.css'] -}) -export class UserDialogComponent implements OnInit { - - constructor(private router: Router) { } - - @ViewChild(RouterOutlet) outlet!: RouterOutlet; - - ngOnInit() { - // this is a workaround for a bug. see https://github.com/angular/angular/issues/20694 - const subscription = this.router.events.subscribe(e => { - if (e instanceof ActivationStart && e.snapshot.outlet === 'user') { - this.outlet.deactivate(); - subscription.unsubscribe(); - } - }); - } -} diff --git a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.css b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.css deleted file mode 100644 index b1101e2a..00000000 --- a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.css +++ /dev/null @@ -1,22 +0,0 @@ -.login-success-message { - color: green; -} - -.username { - color: blue; -} - -:host { - display: flex; - flex-wrap: wrap; -} - -:host p { - margin-top: 0.3em; - margin-bottom: 0.3em; - width: 100%; -} - -.logout-button { - margin-left: auto; -} diff --git a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html deleted file mode 100644 index 685f6299..00000000 --- a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html +++ /dev/null @@ -1,6 +0,0 @@ -<p *ngIf="displayLoginSuccessMessage" class="mat-body login-success-message"> - Login succeeds! -</p> -<p class="mat-body">You have been login as <span class="username">{{ userInfo.username }}</span>.</p> -<p class="mat-body">Your roles are <span class="roles">{{ userInfo.roles.join(', ') }}</span>.</p> -<a mat-flat-button class="logout-button" [routerLink]="['..','logout']">Logout</a> diff --git a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts deleted file mode 100644 index 3eba2696..00000000 --- a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { ActivatedRoute } from '@angular/router'; - -import { RouterLinkStubDirective } from '../../test-utilities/router-link.mock'; -import { MockActivatedRoute } from '../../test-utilities/activated-route.mock'; -import { createMockInternalUserService } from '../internal-user-service/internal-user.service.mock'; - -import { UserLoginSuccessComponent } from './user-login-success.component'; -import { InternalUserService } from '../internal-user-service/internal-user.service'; - - -describe('UserLoginSuccessComponent', () => { - let component: UserLoginSuccessComponent; - let fixture: ComponentFixture<UserLoginSuccessComponent>; - - let mockInternalUserService: jasmine.SpyObj<InternalUserService>; - let mockActivatedRoute: MockActivatedRoute; - - const mockUserInfo = { - username: 'crupest', - roles: ['superman', 'coder'] - }; - - beforeEach(async(() => { - mockInternalUserService = createMockInternalUserService(); - mockActivatedRoute = new MockActivatedRoute(); - - // mock currentUserInfo property. because it only has a getter so cast it to any first. - (<any>mockInternalUserService).currentUserInfo = mockUserInfo; - - TestBed.configureTestingModule({ - declarations: [UserLoginSuccessComponent, RouterLinkStubDirective], - providers: [ - { provide: InternalUserService, useValue: mockInternalUserService }, - { provide: ActivatedRoute, useValue: mockActivatedRoute } - ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UserLoginSuccessComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - fixture.detectChanges(); - expect(component).toBeTruthy(); - }); - - it('user info should work well', () => { - fixture.detectChanges(); - - expect((fixture.debugElement.query(By.css('p.login-success-message')))).toBeFalsy(); - - expect((fixture.debugElement.query(By.css('span.username')).nativeElement as HTMLSpanElement).textContent) - .toBe(mockUserInfo.username); - expect((fixture.debugElement.query(By.css('span.roles')).nativeElement as HTMLSpanElement).textContent) - .toBe(mockUserInfo.roles.join(', ')); - }); - - it('login success message should display well', () => { - mockActivatedRoute.pushSnapshotWithParamMap({ fromlogin: 'true' }); - fixture.detectChanges(); - expect((fixture.debugElement.query(By.css('p.login-success-message')))).toBeTruthy(); - }); - - it('logout button should be set well', () => { - fixture.detectChanges(); - const routerLinkDirective: RouterLinkStubDirective = - fixture.debugElement.query(By.css('a')).injector.get(RouterLinkStubDirective); - expect(routerLinkDirective.linkParams).toEqual(['..', 'logout']); - }); -}); diff --git a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.ts b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.ts deleted file mode 100644 index 2ae584d6..00000000 --- a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; - -import { UserInfo } from '../entities'; -import { InternalUserService } from '../internal-user-service/internal-user.service'; -import { throwIfNullOrUndefined } from 'src/app/utilities/language-untilities'; - -@Component({ - selector: 'app-user-login-success', - templateUrl: './user-login-success.component.html', - styleUrls: ['./user-login-success.component.css'] -}) -export class UserLoginSuccessComponent implements OnInit { - - displayLoginSuccessMessage = false; - - userInfo!: UserInfo; - - constructor(private route: ActivatedRoute, private userService: InternalUserService) { } - - ngOnInit() { - this.userInfo = throwIfNullOrUndefined(this.userService.currentUserInfo, () => 'Route error. No login now!'); - this.displayLoginSuccessMessage = this.route.snapshot.paramMap.get('fromlogin') === 'true'; - } -} diff --git a/Timeline/ClientApp/src/app/user/user-login/user-login.component.css b/Timeline/ClientApp/src/app/user/user-login/user-login.component.css deleted file mode 100644 index 8bf6b408..00000000 --- a/Timeline/ClientApp/src/app/user/user-login/user-login.component.css +++ /dev/null @@ -1,24 +0,0 @@ -form { - display: flex; - flex-wrap: wrap; -} - -div.w-100 { - width: 100%; -} - -.login-button { - margin-left: auto; -} - -.no-login-message { - color: blue; -} - -.invalid-login-message { - color: red; -} - -.error-message { - color: red; -} diff --git a/Timeline/ClientApp/src/app/user/user-login/user-login.component.html b/Timeline/ClientApp/src/app/user/user-login/user-login.component.html deleted file mode 100644 index 7398ece7..00000000 --- a/Timeline/ClientApp/src/app/user/user-login/user-login.component.html +++ /dev/null @@ -1,19 +0,0 @@ -<form [formGroup]="form"> - <ng-container *ngIf="message" [ngSwitch]="message"> - <p *ngSwitchCase="'nologin'" class="mat-h3 no-login-message">You haven't login.</p> - <p *ngSwitchCase="'invalidlogin'" class="mat-h3 invalid-login-message">Your login is no longer valid.</p> - <p *ngSwitchDefault class="mat-h3 error-message">{{ message }}</p> - </ng-container> - <mat-form-field> - <mat-label>Username</mat-label> - <input formControlName="username" matInput type="text" /> - </mat-form-field> - <div class="w-100"></div> - <mat-form-field> - <mat-label>Password</mat-label> - <input formControlName="password" matInput type="password" /> - </mat-form-field> - <mat-checkbox formControlName="rememberMe">Remember me!</mat-checkbox> - <div class="w-100"></div> - <button mat-flat-button class="login-button" (appDebounceClick)="onLoginButtonClick()">Login</button> -</form> diff --git a/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts b/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts deleted file mode 100644 index f010e4b7..00000000 --- a/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { By } from '@angular/platform-browser'; - -import { of, throwError } from 'rxjs'; - -import { createMockInternalUserService } from '../internal-user-service/internal-user.service.mock'; -import { UserLoginComponent } from './user-login.component'; -import { InternalUserService } from '../internal-user-service/internal-user.service'; -import { UserInfo } from '../entities'; -import { MatCheckboxModule } from '@angular/material'; - -describe('UserLoginComponent', () => { - let component: UserLoginComponent; - let fixture: ComponentFixture<UserLoginComponent>; - let mockInternalUserService: jasmine.SpyObj<InternalUserService>; - - beforeEach(async(() => { - mockInternalUserService = createMockInternalUserService(); - - // mock property - (<any>mockInternalUserService).currentUserInfo = null; - - TestBed.configureTestingModule({ - declarations: [UserLoginComponent], - providers: [ - { provide: InternalUserService, useValue: mockInternalUserService } - ], - imports: [ReactiveFormsModule, MatCheckboxModule], - schemas: [NO_ERRORS_SCHEMA] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UserLoginComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - fixture.detectChanges(); - expect(component).toBeTruthy(); - }); - - it('reactive form should work well', () => { - fixture.detectChanges(); - - const usernameInput = fixture.debugElement.query(By.css('input[type=text]')).nativeElement as HTMLInputElement; - const passwordInput = fixture.debugElement.query(By.css('input[type=password]')).nativeElement as HTMLInputElement; - const rememberMeCheckbox = fixture.debugElement.query(By.css('input[type=checkbox]')).nativeElement as HTMLInputElement; - - usernameInput.value = 'user'; - usernameInput.dispatchEvent(new Event('input')); - passwordInput.value = 'user'; - passwordInput.dispatchEvent(new Event('input')); - rememberMeCheckbox.dispatchEvent(new MouseEvent('click')); - - fixture.detectChanges(); - - expect(component.form.value).toEqual({ - username: 'user', - password: 'user', - rememberMe: true - }); - }); - - it('login should work well', () => { - fixture.detectChanges(); - - const mockValue = { - username: 'user', - password: 'user', - rememberMe: true - }; - - mockInternalUserService.tryLogin.withArgs(mockValue).and.returnValue(of(<UserInfo>{ username: 'user', roles: ['user'] })); - - component.form.setValue(mockValue); - component.onLoginButtonClick(); - - expect(mockInternalUserService.tryLogin).toHaveBeenCalledWith(mockValue); - expect(mockInternalUserService.userRouteNavigate).toHaveBeenCalledWith(['success', { fromlogin: 'true' }]); - }); - - describe('message display', () => { - it('nologin reason should display', () => { - fixture.detectChanges(); - component.message = 'nologin'; - fixture.detectChanges(); - expect((fixture.debugElement.query(By.css('p')).nativeElement as - HTMLParagraphElement).textContent).toBe('You haven\'t login.'); - }); - - it('invalid login reason should display', () => { - fixture.detectChanges(); - component.message = 'invalidlogin'; - fixture.detectChanges(); - expect((fixture.debugElement.query(By.css('p')).nativeElement as - HTMLParagraphElement).textContent).toBe('Your login is no longer valid.'); - }); - - it('custom error message should display', () => { - const customMessage = 'custom message'; - - fixture.detectChanges(); - - const mockValue = { - username: 'user', - password: 'user', - rememberMe: false - }; - mockInternalUserService.tryLogin.withArgs(mockValue).and.returnValue(throwError(new Error(customMessage))); - component.form.setValue(mockValue); - component.onLoginButtonClick(); - - fixture.detectChanges(); - expect(component.message).toBe(customMessage); - expect((fixture.debugElement.query(By.css('p')).nativeElement as - HTMLParagraphElement).textContent).toBe(customMessage); - }); - }); -}); diff --git a/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts b/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts deleted file mode 100644 index 4395c5cf..00000000 --- a/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FormGroup, FormControl } from '@angular/forms'; - -import { InternalUserService } from '../internal-user-service/internal-user.service'; - - -export type LoginMessage = 'nologin' | 'invalidlogin' | string | null | undefined; - -@Component({ - selector: 'app-user-login', - templateUrl: './user-login.component.html', - styleUrls: ['./user-login.component.css'] -}) -export class UserLoginComponent implements OnInit { - - constructor(private userService: InternalUserService) { } - - message: LoginMessage; - - form = new FormGroup({ - username: new FormControl(''), - password: new FormControl(''), - rememberMe: new FormControl(false) - }); - - ngOnInit() { - if (this.userService.currentUserInfo) { - throw new Error('Route error! Already login!'); - } - this.message = 'nologin'; - } - - onLoginButtonClick() { - this.userService.tryLogin(this.form.value).subscribe(_ => { - this.userService.userRouteNavigate(['success', { fromlogin: 'true' }]); - }, (error: Error) => this.message = error.message); - } -} diff --git a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.css b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.css deleted file mode 100644 index e69de29b..00000000 --- a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.css +++ /dev/null diff --git a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.html b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.html deleted file mode 100644 index 309e5c83..00000000 --- a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.html +++ /dev/null @@ -1 +0,0 @@ -<p class="mat-body">Logout successfully!</p> diff --git a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.spec.ts b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.spec.ts deleted file mode 100644 index 855ea4a1..00000000 --- a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { UserLogoutComponent } from './user-logout.component'; -import { InternalUserService } from '../internal-user-service/internal-user.service'; - -describe('UserLogoutComponent', () => { - let component: UserLogoutComponent; - let fixture: ComponentFixture<UserLogoutComponent>; - - let mockInternalUserService: jasmine.SpyObj<InternalUserService>; - - beforeEach(async(() => { - mockInternalUserService = jasmine.createSpyObj('InternalUserService', ['logout']); - - TestBed.configureTestingModule({ - declarations: [UserLogoutComponent], - providers: [{ provide: InternalUserService, useValue: mockInternalUserService }] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UserLogoutComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should logout on init', () => { - fixture.detectChanges(); - expect(mockInternalUserService.logout).toHaveBeenCalled(); - }); -}); diff --git a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.ts b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.ts deleted file mode 100644 index e004196f..00000000 --- a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { InternalUserService } from '../internal-user-service/internal-user.service'; - -@Component({ - selector: 'app-user-logout', - templateUrl: './user-logout.component.html', - styleUrls: ['./user-logout.component.css'] -}) -export class UserLogoutComponent implements OnInit { - constructor(private userService: InternalUserService) { } - - ngOnInit() { - this.userService.logout(); - } -} diff --git a/Timeline/ClientApp/src/app/user/user.module.ts b/Timeline/ClientApp/src/app/user/user.module.ts deleted file mode 100644 index 59193380..00000000 --- a/Timeline/ClientApp/src/app/user/user.module.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ReactiveFormsModule } from '@angular/forms'; -import { HttpClientModule } from '@angular/common/http'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterModule } from '@angular/router'; -import { - MatFormFieldModule, MatProgressSpinnerModule, - MatDialogModule, MatInputModule, MatButtonModule, MatSnackBarModule, MatCheckboxModule -} from '@angular/material'; - -import { RequireNoLoginGuard, RequireLoginGuard } from './auth.guard'; -import { UserDialogComponent } from './user-dialog/user-dialog.component'; -import { UserLoginComponent } from './user-login/user-login.component'; -import { UserLoginSuccessComponent } from './user-login-success/user-login-success.component'; -import { RedirectComponent } from './redirect.component'; -import { UtilityModule } from '../utilities/utility.module'; -import { WINDOW } from './window-inject-token'; -import { UserLogoutComponent } from './user-logout/user-logout.component'; - -@NgModule({ - declarations: [UserDialogComponent, UserLoginComponent, UserLoginSuccessComponent, RedirectComponent, UserLogoutComponent], - imports: [ - RouterModule.forChild([ - { path: 'login', canActivate: [RequireNoLoginGuard], component: UserLoginComponent, outlet: 'user' }, - { path: 'success', canActivate: [RequireLoginGuard], component: UserLoginSuccessComponent, outlet: 'user' }, - { path: 'logout', canActivate: [RequireLoginGuard], component: UserLogoutComponent, outlet: 'user' }, - { path: '**', component: RedirectComponent, outlet: 'user' } - ]), - CommonModule, HttpClientModule, ReactiveFormsModule, BrowserAnimationsModule, - MatFormFieldModule, MatProgressSpinnerModule, MatDialogModule, MatInputModule, MatButtonModule, MatCheckboxModule, MatSnackBarModule, - UtilityModule - ], - providers: [{ provide: WINDOW, useValue: window }], - exports: [RouterModule], - entryComponents: [UserDialogComponent] -}) -export class UserModule { } diff --git a/Timeline/ClientApp/src/app/user/user.service.ts b/Timeline/ClientApp/src/app/user/user.service.ts deleted file mode 100644 index 6cae2d31..00000000 --- a/Timeline/ClientApp/src/app/user/user.service.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Injectable } from '@angular/core'; -import { MatDialog, MatDialogRef } from '@angular/material'; -import { Router, ActivationStart } from '@angular/router'; - -import { Observable } from 'rxjs'; - -import { UserInfo } from './entities'; -import { InternalUserService } from './internal-user-service/internal-user.service'; -import { UserDialogComponent } from './user-dialog/user-dialog.component'; - - -/** - * This service provides public api of user module. - */ -@Injectable({ - providedIn: 'root' -}) -export class UserService { - - private dialogRef: MatDialogRef<UserDialogComponent> | null = null; - - constructor(router: Router, private dialog: MatDialog, private internalService: InternalUserService) { - router.events.subscribe(event => { - if (event instanceof ActivationStart && event.snapshot.outlet === 'user') { - if (!this.dialogRef) { - setTimeout(() => this.openUserDialog(), 0); - } - } - }); - } - - get currentUserInfo(): UserInfo | null | undefined { - return this.internalService.currentUserInfo; - } - - get userInfo$(): Observable<UserInfo | null> { - return this.internalService.userInfo$; - } - - private openUserDialog() { - if (this.dialogRef) { - return; - } - - this.dialogRef = this.dialog.open(UserDialogComponent, { - width: '300px' - }); - - const subscription = this.dialogRef.afterClosed().subscribe(_ => { - this.internalService.userRouteNavigate(null); - this.dialogRef = null; - subscription.unsubscribe(); - }); - } -} diff --git a/Timeline/ClientApp/src/app/user/window-inject-token.ts b/Timeline/ClientApp/src/app/user/window-inject-token.ts deleted file mode 100644 index 9f8723f6..00000000 --- a/Timeline/ClientApp/src/app/user/window-inject-token.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { InjectionToken } from '@angular/core'; - -export const WINDOW = new InjectionToken<Window>('global window'); diff --git a/Timeline/ClientApp/src/app/utilities/debounce-click.directive.spec.ts b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.spec.ts deleted file mode 100644 index 89f66b99..00000000 --- a/Timeline/ClientApp/src/app/utilities/debounce-click.directive.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { Component, ViewChild } from '@angular/core'; -import { async, TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; - -import { DebounceClickDirective } from './debounce-click.directive'; - -interface TestComponent { - clickHandler: () => void; -} - -@Component({ - selector: 'app-default-test', - template: '<button (appDebounceClick)="clickHandler()"></button>' -}) -class DefaultDebounceTimeTestComponent { - - @ViewChild(DebounceClickDirective) directive!: DebounceClickDirective; - - clickHandler: () => void = () => { }; -} - -@Component({ - selector: 'app-default-test', - template: '<button (appDebounceClick)="clickHandler()" [appDebounceClickTime]="debounceTime"></button>' -}) -class CustomDebounceTimeTestComponent { - debounceTime: number | undefined; - - @ViewChild(DebounceClickDirective) directive!: DebounceClickDirective; - - clickHandler: () => void = () => { }; -} - - -describe('DebounceClickDirective', () => { - let counter: number; - - function initComponent(component: TestComponent) { - component.clickHandler = () => counter++; - } - - beforeEach(() => { - counter = 0; - }); - - describe('default debounce time', () => { - let component: DefaultDebounceTimeTestComponent; - let componentFixture: ComponentFixture<DefaultDebounceTimeTestComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [DebounceClickDirective, DefaultDebounceTimeTestComponent] - }).compileComponents(); - })); - - beforeEach(() => { - componentFixture = TestBed.createComponent(DefaultDebounceTimeTestComponent); - component = componentFixture.componentInstance; - initComponent(component); - }); - - it('should create an instance', () => { - componentFixture.detectChanges(); - expect(component.directive).toBeTruthy(); - }); - - it('should work well', fakeAsync(() => { - function click() { - (<HTMLButtonElement>componentFixture.debugElement.query(By.css('button')).nativeElement).dispatchEvent(new MouseEvent('click')); - } - componentFixture.detectChanges(); - expect(counter).toBe(0); - click(); - tick(300); - expect(counter).toBe(0); - click(); - tick(); - expect(counter).toBe(0); - tick(500); - expect(counter).toBe(1); - })); - }); - - - describe('custom debounce time', () => { - let component: CustomDebounceTimeTestComponent; - let componentFixture: ComponentFixture<CustomDebounceTimeTestComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [DebounceClickDirective, CustomDebounceTimeTestComponent] - }).compileComponents(); - })); - - beforeEach(() => { - componentFixture = TestBed.createComponent(CustomDebounceTimeTestComponent); - component = componentFixture.componentInstance; - initComponent(component); - component.debounceTime = 600; - }); - - it('should create an instance', () => { - componentFixture.detectChanges(); - expect(component.directive).toBeTruthy(); - }); - - it('should work well', fakeAsync(() => { - function click() { - (<HTMLButtonElement>componentFixture.debugElement.query(By.css('button')).nativeElement).dispatchEvent(new MouseEvent('click')); - } - componentFixture.detectChanges(); - expect(counter).toBe(0); - click(); - tick(300); - expect(counter).toBe(0); - click(); - tick(); - expect(counter).toBe(0); - tick(600); - expect(counter).toBe(1); - })); - }); -}); diff --git a/Timeline/ClientApp/src/app/utilities/debounce-click.directive.ts b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.ts deleted file mode 100644 index 1d01b671..00000000 --- a/Timeline/ClientApp/src/app/utilities/debounce-click.directive.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Directive, Output, Input, EventEmitter, ElementRef, OnInit, OnDestroy } from '@angular/core'; -import { fromEvent, Subscription } from 'rxjs'; -import { debounceTime } from 'rxjs/operators'; - -@Directive({ - selector: '[appDebounceClick]' -}) -export class DebounceClickDirective implements OnInit, OnDestroy { - - private subscription: Subscription | undefined; - - @Output('appDebounceClick') clickEvent = new EventEmitter<any>(); - - // tslint:disable-next-line:no-input-rename - @Input('appDebounceClickTime') - set debounceTime(value: number) { - if (this.subscription) { - this.subscription.unsubscribe(); - } - this.subscription = fromEvent(<HTMLElement>this.element.nativeElement, 'click').pipe( - debounceTime(value) - ).subscribe(o => this.clickEvent.emit(o)); - } - - constructor(private element: ElementRef) { - } - - ngOnInit() { - if (!this.subscription) { - this.subscription = fromEvent(<HTMLElement>this.element.nativeElement, 'click').pipe( - debounceTime(500) - ).subscribe(o => this.clickEvent.emit(o)); - } - } - - ngOnDestroy() { - if (this.subscription) { - this.subscription.unsubscribe(); - } - } -} diff --git a/Timeline/ClientApp/src/app/utilities/language-untilities.ts b/Timeline/ClientApp/src/app/utilities/language-untilities.ts deleted file mode 100644 index 94434665..00000000 --- a/Timeline/ClientApp/src/app/utilities/language-untilities.ts +++ /dev/null @@ -1,18 +0,0 @@ -export function nullIfUndefined<T>(value: T | undefined): T | null { - return value === undefined ? null : value; -} - -export function throwIfNullOrUndefined<T>(value: T | null | undefined, - message: string | (() => string) = 'Value mustn\'t be null or undefined'): T | never { - if (value === null || value === undefined) { - throw new Error(typeof message === 'string' ? message : message()); - } else { - return value; - } -} - -export function repeat(time: number, action: (index?: number) => void) { - for (let i = 0; i < time; i++) { - action(i); - } -} diff --git a/Timeline/ClientApp/src/app/utilities/utility.module.ts b/Timeline/ClientApp/src/app/utilities/utility.module.ts deleted file mode 100644 index dd686bf7..00000000 --- a/Timeline/ClientApp/src/app/utilities/utility.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; - -import { DebounceClickDirective } from './debounce-click.directive'; - -@NgModule({ - declarations: [DebounceClickDirective], - imports: [CommonModule], - exports: [DebounceClickDirective] -}) -export class UtilityModule { } diff --git a/Timeline/ClientApp/src/assets/.gitkeep b/Timeline/ClientApp/src/assets/.gitkeep deleted file mode 100644 index e69de29b..00000000 --- a/Timeline/ClientApp/src/assets/.gitkeep +++ /dev/null diff --git a/Timeline/ClientApp/src/assets/icon.svg b/Timeline/ClientApp/src/assets/icon.svg deleted file mode 100644 index a04bddac..00000000 --- a/Timeline/ClientApp/src/assets/icon.svg +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 1000"> -<line fill="none" stroke="#ffffff" stroke-width="200" x1="500" y1="0" x2="500" y2="250"/> -<circle fill="none" stroke="#ffffff" stroke-width="120" cx="500" cy="500" r="250"/> -<line fill="none" stroke="#ffffff" stroke-width="200" x1="500" y1="750" x2="500" y2="1000"/> -</svg> diff --git a/Timeline/ClientApp/src/browserslist b/Timeline/ClientApp/src/browserslist deleted file mode 100644 index 8e09ab49..00000000 --- a/Timeline/ClientApp/src/browserslist +++ /dev/null @@ -1,9 +0,0 @@ -# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers -# For additional information regarding the format and rule options, please see: -# https://github.com/browserslist/browserslist#queries -# For IE 9-11 support, please uncomment the last line of the file and adjust as needed -> 0.5% -last 2 versions -Firefox ESR -not dead -# IE 9-11
\ No newline at end of file diff --git a/Timeline/ClientApp/src/environments/environment.prod.ts b/Timeline/ClientApp/src/environments/environment.prod.ts deleted file mode 100644 index 3612073b..00000000 --- a/Timeline/ClientApp/src/environments/environment.prod.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const environment = { - production: true -}; diff --git a/Timeline/ClientApp/src/environments/environment.ts b/Timeline/ClientApp/src/environments/environment.ts deleted file mode 100644 index 012182ef..00000000 --- a/Timeline/ClientApp/src/environments/environment.ts +++ /dev/null @@ -1,15 +0,0 @@ -// This file can be replaced during build by using the `fileReplacements` array. -// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`. -// The list of file replacements can be found in `angular.json`. - -export const environment = { - production: false -}; - -/* - * In development mode, to ignore zone related error stack frames such as - * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can - * import the following file, but please comment it out in production mode - * because it will have performance impact when throw error - */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/Timeline/ClientApp/src/index.html b/Timeline/ClientApp/src/index.html deleted file mode 100644 index 58959f75..00000000 --- a/Timeline/ClientApp/src/index.html +++ /dev/null @@ -1,17 +0,0 @@ -<!doctype html> -<html lang="en"> -<head> - <meta charset="utf-8"> - <title>Timeline</title> - <base href="/"> - - <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel="icon" type="image/x-icon" href="favicon.ico"> - - <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> - <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet"> -</head> -<body> - <app-root>Loading...</app-root> -</body> -</html> diff --git a/Timeline/ClientApp/src/karma.conf.js b/Timeline/ClientApp/src/karma.conf.js deleted file mode 100644 index 775e624c..00000000 --- a/Timeline/ClientApp/src/karma.conf.js +++ /dev/null @@ -1,32 +0,0 @@ -// 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-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), - require('karma-junit-reporter'), - require('@angular-devkit/build-angular/plugins/karma') - ], - client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser - }, - coverageIstanbulReporter: { - dir: require('path').join(__dirname, '../coverage'), - reports: ['html', 'lcovonly'], - fixWebpackSourcePaths: true - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false - }); -}; diff --git a/Timeline/ClientApp/src/main.ts b/Timeline/ClientApp/src/main.ts deleted file mode 100644 index a2f708cb..00000000 --- a/Timeline/ClientApp/src/main.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; - -export function getBaseUrl() { - return document.getElementsByTagName('base')[0].href; -} - -const providers = [ - { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] } -]; - -if (environment.production) { - enableProdMode(); -} - -platformBrowserDynamic(providers).bootstrapModule(AppModule) - .catch(err => console.log(err)); diff --git a/Timeline/ClientApp/src/polyfills.ts b/Timeline/ClientApp/src/polyfills.ts deleted file mode 100644 index d310405a..00000000 --- a/Timeline/ClientApp/src/polyfills.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * 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'; - - -/** - * Web Animations `@angular/platform-browser/animations` - * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. - * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). - **/ -// 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 - */ diff --git a/Timeline/ClientApp/src/styles.css b/Timeline/ClientApp/src/styles.css deleted file mode 100644 index f60c9204..00000000 --- a/Timeline/ClientApp/src/styles.css +++ /dev/null @@ -1,14 +0,0 @@ -/* You can add global styles to this file, and also import other style files */ -@import "~@angular/material/prebuilt-themes/indigo-pink.css"; - -html { - overflow: unset!important; /* why cdk-global-scrollblock add overflow-y: scroll ??????????? */ -} - -body { - margin: 0; -} - -.fill-remaining-space { - flex: 1 1 auto; -} diff --git a/Timeline/ClientApp/src/test.ts b/Timeline/ClientApp/src/test.ts deleted file mode 100644 index 688add40..00000000 --- a/Timeline/ClientApp/src/test.ts +++ /dev/null @@ -1,22 +0,0 @@ -// This file is required by karma.conf.js and loads recursively all the .spec and framework files - -import 'zone.js/dist/zone-testing'; -import 'zone.js/dist/zone-patch-rxjs-fake-async'; - -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); diff --git a/Timeline/ClientApp/src/tsconfig.app.json b/Timeline/ClientApp/src/tsconfig.app.json deleted file mode 100644 index 0d3b876e..00000000 --- a/Timeline/ClientApp/src/tsconfig.app.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "outDir": "../out-tsc/app", - "module": "es2015", - "types": [] - }, - "exclude": [ - "src/test.ts", - "test-utilities/**/*", - "**/*.spec.ts", - "**/*.mock.ts", - "**/*.test.ts" - ] -} diff --git a/Timeline/ClientApp/src/tsconfig.server.json b/Timeline/ClientApp/src/tsconfig.server.json deleted file mode 100644 index 8019d415..00000000 --- a/Timeline/ClientApp/src/tsconfig.server.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "module": "commonjs" - }, - "angularCompilerOptions": { - "entryModule": "app/app.server.module#AppServerModule" - } -}
\ No newline at end of file diff --git a/Timeline/ClientApp/src/tsconfig.spec.json b/Timeline/ClientApp/src/tsconfig.spec.json deleted file mode 100644 index 3bcc8926..00000000 --- a/Timeline/ClientApp/src/tsconfig.spec.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "outDir": "../out-tsc/spec", - "module": "commonjs", - "types": [ - "jasmine", - "node" - ] - }, - "files": [ - "test.ts", - "polyfills.ts" - ], - "include": [ - "test-utilities/**/*", - "**/*.spec.ts", - "**/*.d.ts", - "**/*.mock.ts", - "**/*.test.ts" - ] -} diff --git a/Timeline/ClientApp/src/tslint.json b/Timeline/ClientApp/src/tslint.json deleted file mode 100644 index 52e2c1a5..00000000 --- a/Timeline/ClientApp/src/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "app", - "camelCase" - ], - "component-selector": [ - true, - "element", - "app", - "kebab-case" - ] - } -} diff --git a/Timeline/ClientApp/tsconfig.json b/Timeline/ClientApp/tsconfig.json deleted file mode 100644 index 86c42495..00000000 --- a/Timeline/ClientApp/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compileOnSave": false, - "compilerOptions": { - "baseUrl": "./", - "outDir": "./dist/out-tsc", - "sourceMap": true, - "declaration": false, - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "target": "es5", - "typeRoots": [ - "node_modules/@types" - ], - "lib": [ - "es2017", - "dom" - ], - "strict": true - }, - "angularCompilerOptions": { - "fullTemplateTypeCheck": true, - "strictInjectionParameters": true - } -} diff --git a/Timeline/ClientApp/tslint.json b/Timeline/ClientApp/tslint.json deleted file mode 100644 index dcc5f765..00000000 --- a/Timeline/ClientApp/tslint.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "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/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": false, - "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" - ], - "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 - } -} |