Updated angular version and switched hosting to docker
All checks were successful
Build Website / Build NPM Project (push) Successful in 17s
Build Website / Tag Version (push) Successful in 3s
Build Website / Build & Push Dockerfile (push) Successful in 44s

This commit is contained in:
Zakary Timson 2023-12-06 22:37:53 -05:00
parent 858f741ac8
commit 156825d473
30 changed files with 9667 additions and 13374 deletions

View File

@ -1,5 +0,0 @@
{
"projects": {
"default": "etfdemo"
}
}

View File

@ -42,4 +42,13 @@ jobs:
- name: Tag Version - name: Tag Version
uses: ztimson/actions/tag@develop uses: ztimson/actions/tag@develop
with: with:
tag: ${{env.VERSION}} tag: ${{env.VERSION}}
publish:
name: Build & Push Dockerfile
needs: build
uses: ztimson/actions/.github/workflows/docker.yaml@develop
with:
name: ztimson/etf
repository: ${{github.server_url}}/${{github.repository}}.git
pass: ${{secrets.DEPLOY_TOKEN}}

26
.gitignore vendored
View File

@ -1,19 +1,4 @@
# See http://help.github.com/ignore-files/ for more about ignoring files. .idea
# compiled output
/dist
/tmp
/out-tsc
# dependencies
/node_modules
# profiling files
chrome-profiler-events.json
speed-measure-plugin.json
# IDEs and editors
/.idea
.project .project
.classpath .classpath
.c9/ .c9/
@ -28,6 +13,15 @@ speed-measure-plugin.json
!.vscode/launch.json !.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
# compiled output
.angular
dist
tmp
out-tsc
# dependencies
node_modules
# misc # misc
/.sass-cache /.sass-cache
/connect.lock /connect.lock

22
Dockerfile Normal file
View File

@ -0,0 +1,22 @@
FROM node as build
# Variables
ARG NODE_ENV=prod
ARG NODE_OPTIONS="--max_old_space_size=4096"
ENV NG_CLI_ANALYTICS=ci \
NODE_ENV=${NODE_ENV} \
NODE_OPTIONS=${NODE_OPTIONS}
# Setup
WORKDIR /app
COPY . .
# Install & build
RUN if [ ! -d "dist" ]; then npm ci && npm run build; fi
# Use Nginx to serve
FROM nginx:1.20-alpine
COPY --from=build /app/dist/browser /usr/share/nginx/html
COPY docker/robots.txt /usr/share/nginx/html/robots.txt
COPY docker/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80

View File

@ -9,7 +9,7 @@
### ETF Demo ### ETF Demo
<!-- Description --> <!-- Description -->
Recruitement project for Enjine Recruitment project for Enjine
<!-- Repo badges --> <!-- Repo badges -->
[![Version](https://img.shields.io/badge/dynamic/json.svg?label=Version&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/etf-demo/tags&query=$[0].name)](https://git.zakscode.com/ztimson/etf-demo/tags) [![Version](https://img.shields.io/badge/dynamic/json.svg?label=Version&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/etf-demo/tags&query=$[0].name)](https://git.zakscode.com/ztimson/etf-demo/tags)
@ -46,7 +46,7 @@ This project was deployed using Firebase.
### Demo ### Demo
Website: TBD Website: https://etf.zakscode.com
Demo CSV Files: Demo CSV Files:
- [data/Holding_details_FTSE_Canada_All_Cap_Index_ETF_(VCN).csv](./data/Holding_details_FTSE_Canada_All_Cap_Index_ETF_(VCN).csv) - [data/Holding_details_FTSE_Canada_All_Cap_Index_ETF_(VCN).csv](./data/Holding_details_FTSE_Canada_All_Cap_Index_ETF_(VCN).csv)

View File

@ -1,137 +1,73 @@
{ {
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"ETFDemo": { "proj": {
"root": "", "projectType": "application",
"sourceRoot": "src", "schematics": {
"projectType": "application", "@schematics/angular:component": {
"prefix": "app", "style": "scss"
"schematics": {
"@schematics/angular:component": {
"styleext": "scss"
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/ETFDemo",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
} }
], },
"optimization": true, "root": "",
"outputHashing": "all", "sourceRoot": "src",
"sourceMap": false, "prefix": "app",
"extractCss": true, "architect": {
"namedChunks": false, "build": {
"aot": true, "builder": "@angular-devkit/build-angular:application",
"extractLicenses": true, "options": {
"vendorChunk": false, "outputPath": "dist",
"buildOptimizer": true, "index": "src/index.html",
"budgets": [ "browser": "src/main.ts",
{ "polyfills": ["zone.js"],
"type": "initial", "tsConfig": "tsconfig.json",
"maximumWarning": "2mb", "inlineStyleLanguage": "scss",
"maximumError": "5mb" "assets": [
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "proj:build:production"
},
"development": {
"buildTarget": "proj:build:development"
}
},
"defaultConfiguration": "development"
} }
]
} }
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "ETFDemo:build"
},
"configurations": {
"production": {
"browserTarget": "ETFDemo:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "ETFDemo: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.scss"
],
"scripts": [],
"assets": [
"src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
} }
}
},
"ETFDemo-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "ETFDemo:serve"
},
"configurations": {
"production": {
"devServerTarget": "ETFDemo:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
} }
},
"defaultProject": "ETFDemo"
} }

31
docker/nginx.conf Normal file
View File

@ -0,0 +1,31 @@
worker_processes auto;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
gzip on;
gzip_proxied any;
gzip_types text/plain text/css application/xml application/xhtml+xml application/rss+xml application/javascript application/x-javascript application/json application/x-font-woff;
gzip_vary on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
sendfile off;
keepalive_timeout 65;
server {
listen 80;
index index.html;
root /usr/share/nginx/html;
autoindex off;
location / {
try_files $uri$args $uri$args/ /index.html;
}
}
}

2
docker/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-Agent: *
Allow: /

View File

@ -1,16 +0,0 @@
{
"hosting": {
"public": "dist/ETFDemo",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}

22247
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +1,36 @@
{ {
"name": "etfdemo", "name": "etf-demo",
"version": "0.0.0", "version": "2.0.0",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
"build": "ng build", "build": "ng build",
"test": "ng test", "watch": "ng build --watch --configuration development"
"lint": "ng lint",
"e2e": "ng e2e",
"deploy": "firebase deploy --token \"${FIREBASE_TOKEN}\""
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "~7.1.0", "@angular/cdk": "^17.0.0",
"@angular/cdk": "^7.1.0", "@angular/animations": "^17.0.0",
"@angular/common": "~7.1.0", "@angular/common": "^17.0.0",
"@angular/compiler": "~7.1.0", "@angular/compiler": "^17.0.0",
"@angular/core": "~7.1.0", "@angular/core": "^17.0.0",
"@angular/forms": "~7.1.0", "@angular/forms": "^17.0.0",
"@angular/material": "^7.1.0", "@angular/material": "^17.0.0",
"@angular/platform-browser": "~7.1.0", "@angular/platform-browser": "^17.0.0",
"@angular/platform-browser-dynamic": "~7.1.0", "@angular/platform-browser-dynamic": "^17.0.0",
"@angular/router": "~7.1.0", "@angular/router": "^17.0.0",
"@swimlane/ngx-charts": "^10.0.0", "@swimlane/ngx-charts": "^20.5.0",
"core-js": "^2.5.4",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
"rxjs": "~6.3.3", "rxjs": "~7.8.0",
"tslib": "^1.9.0", "tslib": "^2.3.0",
"zone.js": "~0.8.26" "zone.js": "~0.14.2"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.11.0", "@angular-devkit/build-angular": "^17.0.6",
"@angular/cli": "~7.1.0", "@angular/cli": "^17.0.6",
"@angular/compiler-cli": "~7.1.0", "@angular/compiler-cli": "^17.0.0",
"@angular/language-service": "~7.1.0", "@types/jasmine": "~5.1.0",
"@types/jasmine": "~2.8.8", "typescript": "~5.2.2"
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "~4.5.0",
"firebase-tools": "^6.1.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.1.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.1.6"
} }
} }

View File

@ -1,17 +1,17 @@
<!-- Toolbar --> <!-- Toolbar -->
<mat-toolbar> <mat-toolbar>
<img class="mr-3" src="assets/logo.png" height="36px" width="auto"> <img class="mr-3" src="assets/enjine.png" height="32px" width="auto">
<span class="mr-3">ETF Demo</span> <span class="mr-3">ETF Demo</span>
<small *ngIf="timer" class="text-muted">{{timer}} microseconds to upload</small> <small *ngIf="timer" class="text-muted">{{timer}} microseconds to upload</small>
<span class="mx-auto"><!-- Spacer --></span> <span class="mx-auto"><!-- Spacer --></span>
<mat-chip-list class="mr-2"> <mat-chip-listbox class="mr-2">
<mat-chip *ngFor="let file of fileNames; let i = index" class="text-white" <mat-chip *ngFor="let file of fileNames; let i = index" class="text-white"
[style.backgroundColor]="colorScheme.domain[i]" [style.backgroundColor]="colorScheme.domain[i]"
[removable]="true" (removed)="remove($event.chip.value)" [value]="file"> [removable]="true" (removed)="remove($event.chip.value)" [value]="file">
{{file}} {{file}}
<mat-icon matChipRemove>cancel</mat-icon> <mat-icon matChipRemove>cancel</mat-icon>
</mat-chip> </mat-chip>
</mat-chip-list> </mat-chip-listbox>
<button mat-button (click)="fileUploader.click()"> <button mat-button (click)="fileUploader.click()">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
Upload Upload
@ -28,7 +28,7 @@
<div class="p-3"> <div class="p-3">
<mat-form-field class="w-50" appearance="fill"> <mat-form-field class="w-50" appearance="fill">
<mat-label>Add Holding</mat-label> <mat-label>Add Holding</mat-label>
<mat-chip-list #chipList> <mat-chip-grid #chipList>
<mat-chip *ngFor="let holding of graphHoldings; let i = index" [removable]="true" (removed)="graphHoldings.splice(i, 1); updateGraph();"> <mat-chip *ngFor="let holding of graphHoldings; let i = index" [removable]="true" (removed)="graphHoldings.splice(i, 1); updateGraph();">
{{holding}} {{holding}}
<mat-icon matChipRemove>cancel</mat-icon> <mat-icon matChipRemove>cancel</mat-icon>
@ -37,8 +37,8 @@
placeholder="Search" placeholder="Search"
[matAutocomplete]="auto" [matAutocomplete]="auto"
[matChipInputFor]="chipList" [matChipInputFor]="chipList"
(keyup)="search($event.target.value)"> (keyup)="search($event?.target)">
</mat-chip-list> </mat-chip-grid>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="updateGraph($event.option.value); holdingInput.blur();"> <mat-autocomplete #auto="matAutocomplete" (optionSelected)="updateGraph($event.option.value); holdingInput.blur();">
<mat-option *ngFor="let holding of autoCompleteList | async" [value]="holding"> <mat-option *ngFor="let holding of autoCompleteList | async" [value]="holding">
{{holding}} {{holding}}
@ -48,11 +48,12 @@
</div> </div>
<!-- Chart --> <!-- Chart -->
<ngx-charts-bar-vertical-2d #chart <div style="max-height: calc(100% - 80px)">
[scheme]="colorScheme" <ngx-charts-bar-vertical-2d class="h-100"
[results]="chartResults" [results]="chartResults"
[xAxis]="true" [xAxis]="true"
[yAxis]="true" [yAxis]="true"
[yAxisTickFormatting]="format"> [yAxisTickFormatting]="format">
</ngx-charts-bar-vertical-2d> </ngx-charts-bar-vertical-2d>
</div>
</div> </div>

View File

@ -1,36 +1,63 @@
import {CommonModule} from '@angular/common';
import {Component, ElementRef, NgZone, ViewChild} from '@angular/core'; import {Component, ElementRef, NgZone, ViewChild} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MatAutocompleteModule} from '@angular/material/autocomplete';
import {MatButtonModule} from '@angular/material/button';
import {MatChipsModule} from '@angular/material/chips';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatIconModule} from '@angular/material/icon';
import {MatInputModule} from '@angular/material/input';
import {MatSelectModule} from '@angular/material/select';
import {MatToolbarModule} from '@angular/material/toolbar';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
import {NgxChartsModule} from '@swimlane/ngx-charts';
import {timer} from './timer'; import {timer} from './timer';
import {colorScheme} from './colorScheme'; import {colorScheme} from './colorScheme';
import {BehaviorSubject} from 'rxjs'; import {BehaviorSubject} from 'rxjs';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
standalone: true,
imports: [
CommonModule,
FormsModule,
MatAutocompleteModule,
MatButtonModule,
MatChipsModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatSelectModule,
MatToolbarModule,
NgxChartsModule,
],
templateUrl: './app.component.html' templateUrl: './app.component.html'
}) })
export class AppComponent { export class AppComponent {
@ViewChild('fileUploader') fileUploader: ElementRef; @ViewChild('fileUploader') fileUploader!: ElementRef;
@ViewChild('holdingInput') holdingInput: ElementRef; @ViewChild('holdingInput') holdingInput!: ElementRef;
autoCompleteList = new BehaviorSubject<string[]>([]); // Async pipe to provide autocomplete list after being filtered by the text input autoCompleteList = new BehaviorSubject<string[]>([]); // Async pipe to provide autocomplete list after being filtered by the text input
colorScheme = colorScheme; // colors colorScheme = colorScheme; // colors
chartResults = []; // This is where the chart reads the data from chartResults: any[] = []; // This is where the chart reads the data from
holdings: string[] = []; // All the merged holdings holdings: string[] = []; // All the merged holdings
fileNames: string[] = []; // All the filenames fileNames: string[] = []; // All the filenames
mergedData = {}; // All the holdings merged together mergedData: any = {}; // All the holdings merged together
timer = window['timer']; // Async pipe to display the timed data timer = (<any>window)['timer']; // Async pipe to display the timed data
graphHoldings: string[] = []; // Holdings we are graphing graphHoldings: string[] = []; // Holdings we are graphing
// ngx-charts requires a different data structure than the hash map we built so I will use a setter to handle converting it when we go to save the processed data. // ngx-charts requires a different data structure than the hash map we built so I will use a setter to handle converting it when we go to save the processed data.
private _data = {}; private _data: any = {};
get data() { return this._data; } get data() { return this._data; }
set data(data) { set data(data) {
this._data = data; this._data = data;
// merge the files together // merge the files together
this.mergedData = Object.values(data).reduce((acc, file) => { this.mergedData = Object.values(data).reduce((acc: any, file: any) => {
Object.keys(file).forEach(key => { Object.keys(file).forEach(key => {
if(!acc[key]) acc[key] = []; if(!acc[key]) acc[key] = [];
file[key].forEach(val => acc[key].push(val)); file[key].forEach((val: any) => acc[key].push(val));
}); });
return acc; return acc;
}, {}); }, {});
@ -46,24 +73,24 @@ export class AppComponent {
constructor(private ngZone: NgZone) { constructor(private ngZone: NgZone) {
// Hack to connect angular context to the native one // Hack to connect angular context to the native one
setInterval(() => this.timer = Math.round(window['timer'] * 10) / 10, 250); setInterval(() => this.timer = Math.round((<any>window)['timer'] * 10) / 10, 250);
} }
remove(fileName) { remove(fileName: string) {
// Remove the file // Remove the file
delete this.data[fileName]; delete this.data[fileName];
this.data = Object.assign({}, this.data); this.data = Object.assign({}, this.data);
this.updateGraph(); this.updateGraph();
} }
search(text?: string) { search(target?: any) {
// Filter the holdings list by the text and push it through the async pipe // Filter the holdings list by the text and push it through the async pipe
if(!text) this.autoCompleteList.next(this.holdings); if(!target || !target?.value) this.autoCompleteList.next(this.holdings);
this.autoCompleteList.next(this.holdings.filter(holding => holding.toLowerCase().indexOf(text) != -1)); this.autoCompleteList.next(this.holdings.filter(holding => holding.toLowerCase().indexOf(target.value) != -1));
} }
@timer @timer
upload(fileList: FileList) { upload(fileList?: FileList | null) {
if(!fileList || !fileList.length) return; if(!fileList || !fileList.length) return;
// Because we enabled uploading multiple fileNames at once we need to process each one individually // Because we enabled uploading multiple fileNames at once we need to process each one individually
@ -76,10 +103,10 @@ export class AppComponent {
const lines = ((<FileReader>e.target).result as string).split('\n'); const lines = ((<FileReader>e.target).result as string).split('\n');
// Use regex to grab the holding name and its % market value // Use regex to grab the holding name and its % market value
this.data = Object.assign(this.data, {[file.name]: lines.map(text => { this.data = Object.assign(this.data, {[file.name]: lines.map((text: any) => {
const parse = /^(.+),.+?(\d+\.\d+)%/gm.exec(text); const parse = /^(.+),.+?(\d+\.\d+)%/gm.exec(text);
if(parse) return parse.slice(1); return parse ? parse.slice(1) : 'Unknown';
}).reduce((acc, line) => { }).reduce((acc: any, line) => {
// The regex will turn lines that don't match into null values so lets filter those out here // The regex will turn lines that don't match into null values so lets filter those out here
if(!line) return acc; if(!line) return acc;
@ -108,9 +135,9 @@ export class AppComponent {
.filter(key => this.graphHoldings.indexOf(key) != -1) .filter(key => this.graphHoldings.indexOf(key) != -1)
.map(key => ({ .map(key => ({
name: key, name: key,
series: this.mergedData[key].map((val, i) => ({name: i, value: val})) series: this.mergedData[key].map((val: any, i: number) => ({name: i, value: val}))
})); }));
} }
format(text) { return `${text} %`} format(text: string) { return `${text} %`}
} }

View File

@ -1,38 +0,0 @@
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AppComponent} from './app.component';
import {
MatAutocompleteModule,
MatButtonModule,
MatChipsModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatSelectModule,
MatToolbarModule
} from '@angular/material';
import {NgxChartsModule} from '@swimlane/ngx-charts';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {FormsModule} from '@angular/forms';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserAnimationsModule,
BrowserModule,
FormsModule,
MatAutocompleteModule,
MatButtonModule,
MatChipsModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatSelectModule,
MatToolbarModule,
NgxChartsModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}

View File

@ -9,7 +9,7 @@ export function timer(target: any, key: string, descriptor: PropertyDescriptor)
const end = window.performance.now() - start; const end = window.performance.now() - start;
// Log it // Log it
window['timer'] = end; (<any>window)['timer'] = end;
console.log(`${end} microseconds`); console.log(`${end} microseconds`);
// Return it // Return it

View File

BIN
src/assets/enjine.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1,11 +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 remove 'not' from the last line of the file and adjust as needed
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11

View File

@ -1,16 +1,3 @@
// 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 = { export const environment = {
production: false production: false
}; };
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.

View File

@ -1,13 +1,13 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ETF Demo</title> <title>ETF Demo</title>
<base href="/"> <base href="/">
<link rel="icon" type="image/x-icon" href="assets/logo.png"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="assets/enjine.png">
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
</head> </head>
<body> <body>

View File

@ -1,31 +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('@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', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

View File

@ -1,14 +1,10 @@
import { enableProdMode } from '@angular/core'; import {importProvidersFrom} from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { bootstrapApplication } from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import { AppModule } from './app/app.module'; import {AppComponent} from './app/app.component';
import { environment } from './environments/environment';
import 'hammerjs'; import 'hammerjs';
if (environment.production) { bootstrapApplication(AppComponent, {
enableProdMode(); providers:[importProvidersFrom([BrowserAnimationsModule])]
} }).catch((err: any) => console.error(err));
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));

View File

@ -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/guide/browser-support
*/
/***************************************************************************************************
* 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';
/**
* If the application will be indexed by Google Search, the following is required.
* Googlebot uses a renderer based on Chrome 41.
* https://developers.google.com/search/docs/guides/rendering
**/
// import 'core-js/es6/array';
/** 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';
/**
* 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
*/

View File

@ -1,5 +1,5 @@
@import url('https://fonts.googleapis.com/css?family=Archivo|Material+Icons'); @import url('https://fonts.googleapis.com/css?family=Archivo|Material+Icons');
@import "~@angular/material/prebuilt-themes/indigo-pink.css"; @import "@angular/material/prebuilt-themes/indigo-pink.css";
html, body { html, body {
padding: 0; padding: 0;
@ -11,14 +11,13 @@ html, body {
} }
.content-height { .content-height {
height: calc(100vh - 64px); height: calc(100% - 64px);
} }
.w-50 { .w-50 {
width: 50%; width: 50%;
} }
// Bootstrap overrides
.text-muted { .text-muted {
color: #bbbbbb !important; color: #bbbbbb !important;
} }

View File

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

View File

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

View File

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

View File

@ -1,17 +0,0 @@
{
"extends": "../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
]
}
}

View File

@ -1,22 +1,39 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"compileOnSave": false, "compileOnSave": false,
"compilerOptions": { "compilerOptions": {
"baseUrl": "./", "outDir": "./out-tsc/app",
"outDir": "./dist/out-tsc", "forceConsistentCasingInFileNames": true,
"sourceMap": true, "strict": true,
"declaration": false, "noImplicitOverride": true,
"module": "es2015", "noPropertyAccessFromIndexSignature": true,
"moduleResolution": "node", "noImplicitReturns": true,
"emitDecoratorMetadata": true, "noFallthroughCasesInSwitch": true,
"experimentalDecorators": true, "skipLibCheck": true,
"importHelpers": true, "esModuleInterop": true,
"target": "es5", "sourceMap": true,
"typeRoots": [ "declaration": false,
"node_modules/@types" "experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": [
"ES2022",
"dom"
]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
},
"files": [
"src/main.ts"
], ],
"lib": [ "include": [
"es2018", "src/**/*.d.ts"
"dom"
] ]
}
} }