feat: upgrade to Angular 9 and Nebular 5 (#5628)

BREAKING CHANGE:
Angular updated to version 9.
Nebular updated to version 5.
`@agm/core` replaced with `@angular/google-maps`.
`ng2-completer` replaced with `@akveo/ng2-completer`, read details [here](https://github.com/akveo/ng2-smart-table/pull/1140#issue-392285957).
This commit is contained in:
Evgeny Lupanov 2020-03-30 12:06:51 +03:00 committed by Maksim Karatkevich
parent b48f502f37
commit aa4ae169d9
21 changed files with 6191 additions and 3175 deletions

View file

@ -11,6 +11,7 @@
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"aot": true,
"preserveSymlinks": true, "preserveSymlinks": true,
"rebaseRootRelativeCssUrls": true, "rebaseRootRelativeCssUrls": true,
"outputPath": "dist", "outputPath": "dist",
@ -21,24 +22,45 @@
"assets": [ "assets": [
"src/assets", "src/assets",
"src/favicon.ico", "src/favicon.ico",
"src/favicon.png" "src/favicon.png",
{
"glob": "**/*",
"input": "node_modules/leaflet/dist/images",
"output": "/assets/img/markers"
}
], ],
"styles": [ "styles": [
"node_modules/bootstrap/dist/css/bootstrap.css", "node_modules/bootstrap/dist/css/bootstrap.css",
"node_modules/typeface-exo/index.css", "node_modules/typeface-exo/index.css",
"node_modules/roboto-fontface/css/roboto/roboto-fontface.css", "node_modules/roboto-fontface/css/roboto/roboto-fontface.css",
"node_modules/ionicons/scss/ionicons.scss", "node_modules/ionicons/scss/ionicons.scss",
"node_modules/@fortawesome/fontawesome-free/css/all.css",
"node_modules/socicon/css/socicon.css", "node_modules/socicon/css/socicon.css",
"node_modules/nebular-icons/scss/nebular-icons.scss", "node_modules/nebular-icons/scss/nebular-icons.scss",
"node_modules/pace-js/templates/pace-theme-flash.tmpl.css", "node_modules/pace-js/templates/pace-theme-flash.tmpl.css",
"node_modules/leaflet/dist/leaflet.css",
"src/app/@theme/styles/styles.scss" "src/app/@theme/styles/styles.scss"
], ],
"scripts": [ "scripts": [
"node_modules/pace-js/pace.min.js" "node_modules/pace-js/pace.min.js",
"node_modules/tinymce/tinymce.min.js",
"node_modules/tinymce/themes/modern/theme.min.js",
"node_modules/tinymce/plugins/link/plugin.min.js",
"node_modules/tinymce/plugins/paste/plugin.min.js",
"node_modules/tinymce/plugins/table/plugin.min.js",
"node_modules/echarts/dist/echarts.min.js",
"node_modules/echarts/dist/extension/bmap.min.js",
"node_modules/chart.js/dist/Chart.min.js"
] ]
}, },
"configurations": { "configurations": {
"production": { "production": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"optimization": true, "optimization": true,
"outputHashing": "all", "outputHashing": "all",
"sourceMap": false, "sourceMap": false,
@ -82,13 +104,22 @@
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json", "tsConfig": "src/tsconfig.spec.json",
"scripts": [ "scripts": [
"node_modules/pace-js/pace.min.js" "node_modules/pace-js/pace.min.js",
"node_modules/tinymce/tinymce.min.js",
"node_modules/tinymce/themes/modern/theme.min.js",
"node_modules/tinymce/plugins/link/plugin.min.js",
"node_modules/tinymce/plugins/paste/plugin.min.js",
"node_modules/tinymce/plugins/table/plugin.min.js",
"node_modules/echarts/dist/echarts.min.js",
"node_modules/echarts/dist/extension/bmap.min.js",
"node_modules/chart.js/dist/Chart.min.js"
], ],
"styles": [ "styles": [
"node_modules/bootstrap/dist/css/bootstrap.css", "node_modules/bootstrap/dist/css/bootstrap.css",
"node_modules/typeface-exo/index.css", "node_modules/typeface-exo/index.css",
"node_modules/roboto-fontface/css/roboto/roboto-fontface.css", "node_modules/roboto-fontface/css/roboto/roboto-fontface.css",
"node_modules/ionicons/scss/ionicons.scss", "node_modules/ionicons/scss/ionicons.scss",
"node_modules/font-awesome/scss/font-awesome.scss",
"node_modules/socicon/css/socicon.css", "node_modules/socicon/css/socicon.css",
"node_modules/nebular-icons/scss/nebular-icons.scss", "node_modules/nebular-icons/scss/nebular-icons.scss",
"node_modules/pace-js/templates/pace-theme-flash.tmpl.css", "node_modules/pace-js/templates/pace-theme-flash.tmpl.css",
@ -97,7 +128,12 @@
"assets": [ "assets": [
"src/assets", "src/assets",
"src/favicon.ico", "src/favicon.ico",
"src/favicon.png" "src/favicon.png",
{
"glob": "**/*",
"input": "node_modules/leaflet/dist/images",
"output": "/assets/img/markers"
}
] ]
} }
}, },
@ -141,8 +177,11 @@
"defaultProject": "ngx-admin-demo", "defaultProject": "ngx-admin-demo",
"schematics": { "schematics": {
"@schematics/angular:component": { "@schematics/angular:component": {
"styleext": "scss" "prefix": "ngx",
"style": "scss"
}, },
"@schematics/angular:directive": {} "@schematics/angular:directive": {
"prefix": "ngx"
}
} }
} }

8919
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -26,70 +26,70 @@
"docs": "compodoc -p src/tsconfig.app.json -d docs", "docs": "compodoc -p src/tsconfig.app.json -d docs",
"docs:serve": "compodoc -p src/tsconfig.app.json -d docs -s", "docs:serve": "compodoc -p src/tsconfig.app.json -d docs -s",
"prepush": "npm run lint:ci", "prepush": "npm run lint:ci",
"release:changelog": "npm run conventional-changelog -- -p angular -i CHANGELOG.md -s" "release:changelog": "npm run conventional-changelog -- -p angular -i CHANGELOG.md -s",
"postinstall": "ngcc --properties es2015 es5 browser module main --first-only --create-ivy-entry-points"
}, },
"dependencies": { "dependencies": {
"@agm/core": "^1.0.0-beta.5", "@akveo/ng2-completer": "^9.0.1",
"@angular/animations": "^8.0.0", "@angular/animations": "^9.0.4",
"@angular/cdk": "^8.0.0", "@angular/cdk": "^9.1.2",
"@angular/common": "^8.0.0", "@angular/common": "^9.0.4",
"@angular/compiler": "^8.0.0", "@angular/compiler": "^9.0.4",
"@angular/core": "^8.0.0", "@angular/core": "^9.0.4",
"@angular/forms": "^8.0.0", "@angular/forms": "^9.0.4",
"@angular/platform-browser": "^8.0.0", "@angular/google-maps": "^9.1.0",
"@angular/platform-browser-dynamic": "^8.0.0", "@angular/platform-browser": "^9.0.4",
"@angular/router": "^8.0.0", "@angular/platform-browser-dynamic": "^9.0.4",
"@angular/router": "^9.0.4",
"@asymmetrik/ngx-leaflet": "3.0.1", "@asymmetrik/ngx-leaflet": "3.0.1",
"@nebular/auth": "4.4.0", "@nebular/auth": "5.0.0",
"@nebular/eva-icons": "4.4.0", "@nebular/eva-icons": "5.0.0",
"@nebular/security": "4.4.0", "@nebular/security": "5.0.0",
"@nebular/theme": "4.4.0", "@nebular/theme": "5.0.0",
"@swimlane/ngx-charts": "^10.0.0", "@swimlane/ngx-charts": "^13.0.2",
"angular-tree-component": "7.2.0",
"angular2-chartjs": "0.4.1", "angular2-chartjs": "0.4.1",
"angular2-toaster": "^7.0.0",
"bootstrap": "4.3.1", "bootstrap": "4.3.1",
"chart.js": "2.7.1", "chart.js": "2.7.1",
"ckeditor": "4.7.3", "ckeditor": "4.7.3",
"classlist.js": "1.1.20150312", "classlist.js": "1.1.20150312",
"core-js": "2.5.1", "core-js": "2.5.1",
"echarts": "^4.0.2", "echarts": "^4.0.2",
"eva-icons": "^1.1.0", "eva-icons": "^1.1.3",
"intl": "1.2.5", "intl": "1.2.5",
"ionicons": "2.0.1", "ionicons": "2.0.1",
"leaflet": "1.2.0", "leaflet": "1.2.0",
"nebular-icons": "1.1.0", "nebular-icons": "1.1.0",
"ng2-ckeditor": "^1.2.2", "ng2-ckeditor": "^1.2.2",
"ng2-completer": "2.0.8", "ng2-smart-table": "^1.6.0",
"ng2-smart-table": "1.3.5", "ngx-echarts": "^4.2.2",
"ngx-echarts": "^4.0.1",
"node-sass": "^4.12.0", "node-sass": "^4.12.0",
"normalize.css": "6.0.0", "normalize.css": "6.0.0",
"pace-js": "1.0.2", "pace-js": "1.0.2",
"roboto-fontface": "0.8.0", "roboto-fontface": "0.8.0",
"rxjs": "6.5.2", "rxjs": "6.5.4",
"rxjs-compat": "6.3.0", "rxjs-compat": "6.3.0",
"socicon": "3.0.5", "socicon": "3.0.5",
"style-loader": "^1.1.3",
"tinymce": "4.5.7", "tinymce": "4.5.7",
"tslib": "^1.9.0", "tslib": "^1.10.0",
"typeface-exo": "0.0.22", "typeface-exo": "0.0.22",
"web-animations-js": "github:angular/web-animations-js#release_pr208", "web-animations-js": "^2.3.2",
"zone.js": "~0.9.1" "zone.js": "~0.10.2"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.800.2", "@angular-devkit/build-angular": "~0.900.4",
"@angular/cli": "^8.0.2", "@angular/cli": "^9.0.4",
"@angular/compiler-cli": "^8.0.0", "@angular/compiler-cli": "^9.0.4",
"@angular/language-service": "8.0.0", "@angular/language-service": "9.0.4",
"@compodoc/compodoc": "1.0.1", "@compodoc/compodoc": "1.0.1",
"@fortawesome/fontawesome-free": "^5.2.0", "@fortawesome/fontawesome-free": "^5.2.0",
"@types/d3-color": "1.0.5", "@types/d3-color": "1.0.5",
"@types/googlemaps": "^3.30.4", "@types/googlemaps": "^3.39.3",
"@types/jasmine": "2.5.54", "@types/jasmine": "2.5.54",
"@types/jasminewd2": "2.0.3", "@types/jasminewd2": "2.0.3",
"@types/leaflet": "1.2.3", "@types/leaflet": "1.2.3",
"@types/node": "6.0.90", "@types/node": "^12.11.1",
"codelyzer": "^5.0.1", "codelyzer": "^5.1.2",
"conventional-changelog-cli": "1.3.4", "conventional-changelog-cli": "1.3.4",
"husky": "0.13.3", "husky": "0.13.3",
"jasmine-core": "2.6.4", "jasmine-core": "2.6.4",
@ -107,6 +107,6 @@
"ts-node": "3.2.2", "ts-node": "3.2.2",
"tslint": "^5.7.0", "tslint": "^5.7.0",
"tslint-language-service": "^0.9.9", "tslint-language-service": "^0.9.9",
"typescript": "3.4.5" "typescript": "3.7.5"
} }
} }

View file

@ -159,8 +159,8 @@ export class CoreModule {
throwIfAlreadyLoaded(parentModule, 'CoreModule'); throwIfAlreadyLoaded(parentModule, 'CoreModule');
} }
static forRoot(): ModuleWithProviders { static forRoot(): ModuleWithProviders<CoreModule> {
return <ModuleWithProviders>{ return {
ngModule: CoreModule, ngModule: CoreModule,
providers: [ providers: [
...NB_CORE_PROVIDERS, ...NB_CORE_PROVIDERS,

View file

@ -16,8 +16,8 @@ const SERVICES = [
], ],
}) })
export class MockDataModule { export class MockDataModule {
static forRoot(): ModuleWithProviders { static forRoot(): ModuleWithProviders<MockDataModule> {
return <ModuleWithProviders>{ return {
ngModule: MockDataModule, ngModule: MockDataModule,
providers: [ providers: [
...SERVICES, ...SERVICES,

View file

@ -78,8 +78,8 @@ const PIPES = [
declarations: [...COMPONENTS, ...PIPES], declarations: [...COMPONENTS, ...PIPES],
}) })
export class ThemeModule { export class ThemeModule {
static forRoot(): ModuleWithProviders { static forRoot(): ModuleWithProviders<ThemeModule> {
return <ModuleWithProviders>{ return {
ngModule: ThemeModule, ngModule: ThemeModule,
providers: [ providers: [
...NbThemeModule.forRoot( ...NbThemeModule.forRoot(

View file

@ -9,10 +9,10 @@ import {
NbResetPasswordComponent, NbResetPasswordComponent,
} from '@nebular/auth'; } from '@nebular/auth';
const routes: Routes = [ export const routes: Routes = [
{ {
path: 'pages', path: 'pages',
loadChildren: () => import('app/pages/pages.module') loadChildren: () => import('./pages/pages.module')
.then(m => m.PagesModule), .then(m => m.PagesModule),
}, },
{ {

View file

@ -28,9 +28,6 @@ import {
BrowserAnimationsModule, BrowserAnimationsModule,
HttpClientModule, HttpClientModule,
AppRoutingModule, AppRoutingModule,
ThemeModule.forRoot(),
NbSidebarModule.forRoot(), NbSidebarModule.forRoot(),
NbMenuModule.forRoot(), NbMenuModule.forRoot(),
NbDatepickerModule.forRoot(), NbDatepickerModule.forRoot(),
@ -41,6 +38,7 @@ import {
messageGoogleMapKey: 'AIzaSyA_wNuCzia92MAmdLRzmqitRGvCF7wCZPY', messageGoogleMapKey: 'AIzaSyA_wNuCzia92MAmdLRzmqitRGvCF7wCZPY',
}), }),
CoreModule.forRoot(), CoreModule.forRoot(),
ThemeModule.forRoot(),
], ],
bootstrap: [AppComponent], bootstrap: [AppComponent],
}) })

View file

@ -0,0 +1,67 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { NbMediaBreakpoint, NbMediaBreakpointsService, NbThemeService } from '@nebular/theme';
import { takeWhile } from 'rxjs/operators';
import { CountryOrderData } from '../../../@core/data/country-order';
@Component({
selector: 'ngx-country-orders',
styleUrls: ['./country-orders.component.scss'],
template: `
<nb-card [size]="breakpoint.width >= breakpoints.md ? 'medium' : 'giant'">
<nb-card-header>Country Orders Statistics</nb-card-header>
<nb-card-body>
<ngx-country-orders-map (select)="selectCountryById($event)"
countryId="USA">
</ngx-country-orders-map>
<ngx-country-orders-chart [countryName]="countryName"
[data]="countryData"
[labels]="countriesCategories"
maxValue="20">
</ngx-country-orders-chart>
</nb-card-body>
</nb-card>
`,
})
export class CountryOrdersComponent implements OnInit, OnDestroy {
private alive = true;
countryName = '';
countryData: number[] = [];
countriesCategories: string[];
breakpoint: NbMediaBreakpoint = { name: '', width: 0 };
breakpoints: any;
constructor(private themeService: NbThemeService,
private breakpointService: NbMediaBreakpointsService,
private countryOrderService: CountryOrderData) {
this.breakpoints = this.breakpointService.getBreakpointsMap();
}
ngOnInit() {
this.themeService.onMediaQueryChange()
.pipe(takeWhile(() => this.alive))
.subscribe(([oldValue, newValue]) => {
this.breakpoint = newValue;
});
this.countryOrderService.getCountriesCategories()
.pipe(takeWhile(() => this.alive))
.subscribe((countriesCategories) => {
this.countriesCategories = countriesCategories;
});
}
selectCountryById(countryName: string) {
this.countryName = countryName;
this.countryOrderService.getCountriesCategoriesData(countryName)
.pipe(takeWhile(() => this.alive))
.subscribe((countryData) => {
this.countryData = countryData;
});
}
ngOnDestroy() {
this.alive = false;
}
}

View file

@ -0,0 +1,8 @@
<nb-card>
<nb-card-header>Google Maps</nb-card-header>
<nb-card-body>
<google-map [center]="position" [zoom]="8" width="100%" height="36.5625rem">
<map-marker [position]="position"></map-marker>
</google-map>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,10 @@
import { Component } from '@angular/core';
@Component({
selector: 'ngx-gmaps',
styleUrls: ['./gmaps.component.scss'],
templateUrl: './gmaps.component.html',
})
export class GmapsComponent {
readonly position = { lat: 51.678418, lng: 7.809007 };
}

View file

@ -0,0 +1,24 @@
import { NgModule } from '@angular/core';
import { GoogleMapsModule } from '@angular/google-maps';
import { LeafletModule } from '@asymmetrik/ngx-leaflet';
import { NgxEchartsModule } from 'ngx-echarts';
import { NbCardModule } from '@nebular/theme';
import { ThemeModule } from '../../@theme/theme.module';
import { MapsRoutingModule, routedComponents } from './maps-routing.module';
@NgModule({
imports: [
ThemeModule,
GoogleMapsModule,
LeafletModule.forRoot(),
MapsRoutingModule,
NgxEchartsModule,
NbCardModule,
],
exports: [],
declarations: [
...routedComponents,
],
})
export class MapsModule { }

View file

@ -0,0 +1,6 @@
export class PositionModel {
constructor(
public lat = 53.9,
public lng = 27.5667,
) {}
}

View file

@ -0,0 +1,3 @@
<google-map [center]="position" [zoom]="zoom" width="100%" height="36.5625rem">
<map-marker [position]="position"></map-marker>
</google-map>

View file

@ -0,0 +1,32 @@
import { Component, Input, OnInit } from '@angular/core';
import { PositionModel } from '../entity/position.model';
@Component({
selector: 'ngx-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.scss'],
})
export class MapComponent implements OnInit {
position: PositionModel = null;
zoom: number = 1;
@Input()
public set searchedPosition(position: PositionModel) {
if (position) {
this.position = position;
this.zoom = 12;
}
}
ngOnInit() {
// set up current location
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
this.searchedPosition = new PositionModel(
position.coords.latitude,
position.coords.longitude,
);
});
}
}
}

View file

@ -0,0 +1,7 @@
<nb-card>
<nb-card-header>Google Maps with search</nb-card-header>
<nb-card-body>
<ngx-search (positionChanged)="setPosition($event)"></ngx-search>
<ngx-map [searchedPosition]="searchedPosition"></ngx-map>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import { PositionModel } from './entity/position.model';
@Component({
selector: 'ngx-search-map',
templateUrl: './search-map.component.html',
})
export class SearchMapComponent {
searchedPosition: PositionModel = new PositionModel();
setPosition(position: PositionModel) {
this.searchedPosition = position;
}
}

View file

@ -0,0 +1,40 @@
import { Component, ElementRef, EventEmitter, NgZone, OnInit, Output, ViewChild } from '@angular/core';
import { PositionModel } from '../entity/position.model';
@Component({
selector: 'ngx-search',
templateUrl: './search.component.html',
})
export class SearchComponent implements OnInit {
@Output()
positionChanged: EventEmitter<PositionModel> = new EventEmitter<PositionModel>();
@ViewChild('search', { static: true })
searchElementRef: ElementRef;
constructor(private ngZone: NgZone) {}
ngOnInit() {
const autocomplete = new google.maps.places.Autocomplete(
this.searchElementRef.nativeElement, { types: ['address'] },
);
autocomplete.addListener('place_changed', () => {
this.ngZone.run(() => {
// get the place result
const place: google.maps.places.PlaceResult = autocomplete.getPlace();
// verify result
if (place.geometry === undefined || place.geometry === null) {
return;
}
this.positionChanged.emit(new PositionModel(
place.geometry.location.lat(),
place.geometry.location.lng(),
));
});
});
}
}

View file

@ -0,0 +1,86 @@
import { Component } from '@angular/core';
import {
NbComponentStatus,
NbGlobalLogicalPosition,
NbGlobalPhysicalPosition,
NbGlobalPosition,
NbToastrService,
NbToastrConfig,
} from '@nebular/theme';
@Component({
selector: 'ngx-toastr',
styleUrls: ['./toastr.component.scss'],
templateUrl: './toastr.component.html',
})
export class ToastrComponent {
constructor(private toastrService: NbToastrService) {}
config: NbToastrConfig;
index = 1;
destroyByClick = true;
duration = 2000;
hasIcon = true;
position: NbGlobalPosition = NbGlobalPhysicalPosition.TOP_RIGHT;
preventDuplicates = false;
status: NbComponentStatus = 'primary';
title = 'HI there!';
content = `I'm cool toaster!`;
types: NbComponentStatus[] = [
'primary',
'success',
'info',
'warning',
'danger',
];
positions: string[] = [
NbGlobalPhysicalPosition.TOP_RIGHT,
NbGlobalPhysicalPosition.TOP_LEFT,
NbGlobalPhysicalPosition.BOTTOM_LEFT,
NbGlobalPhysicalPosition.BOTTOM_RIGHT,
NbGlobalLogicalPosition.TOP_END,
NbGlobalLogicalPosition.TOP_START,
NbGlobalLogicalPosition.BOTTOM_END,
NbGlobalLogicalPosition.BOTTOM_START,
];
quotes = [
{ title: null, body: 'We rock at Angular' },
{ title: null, body: 'Titles are not always needed' },
{ title: null, body: 'Toastr rock!' },
];
makeToast() {
this.showToast(this.status, this.title, this.content);
}
openRandomToast () {
const typeIndex = Math.floor(Math.random() * this.types.length);
const quoteIndex = Math.floor(Math.random() * this.quotes.length);
const type = this.types[typeIndex];
const quote = this.quotes[quoteIndex];
this.showToast(type, quote.title, quote.body);
}
private showToast(type: NbComponentStatus, title: string, body: string) {
const config = {
status: type,
destroyByClick: this.destroyByClick,
duration: this.duration,
hasIcon: this.hasIcon,
position: this.position,
preventDuplicates: this.preventDuplicates,
};
const titleContent = title ? `. ${title}` : '';
this.index += 1;
this.toastrService.show(
body,
`Toast ${this.index}${titleContent}`,
config);
}
}

View file

@ -9,6 +9,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="favicon.png"> <link rel="icon" type="image/png" href="favicon.png">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<script defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCpVhQiwAllg1RAFaxMWSpQruuGARy0Y1k&libraries=places"></script>
</head> </head>
<body> <body>
<ngx-app>Loading...</ngx-app> <ngx-app>Loading...</ngx-app>

View file

@ -2,15 +2,7 @@
"extends": "../tsconfig.json", "extends": "../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "../out-tsc/app", "outDir": "../out-tsc/app",
"baseUrl": "./", "baseUrl": "./"
"paths": {
"@angular/*": [
"../node_modules/@angular/*"
],
"@nebular/*": [
"../node_modules/@nebular/*"
]
}
}, },
"exclude": [ "exclude": [
"test.ts", "test.ts",