http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/package.json ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/package.json b/metron-interface/metron-config/package.json index 6e196d5..ffc92ff 100644 --- a/metron-interface/metron-config/package.json +++ b/metron-interface/metron-config/package.json @@ -7,10 +7,11 @@ }, "angular-cli": {}, "scripts": { - "build": "./node_modules/angular-cli/bin/ng build -prod", + "build": "ng build --prod", "start": "ng serve", "lint": "tslint \"src/**/*.ts\"", - "test": "./node_modules/angular-cli/bin/ng test --watch=false", + "test": "ng test --browsers=Chrome", + "testCI": "ng test --watch=false --browsers=ChromeHeadless", "pree2e": "webdriver-manager update", "e2e": "./node_modules/.bin/protractor", "e2e-all": "./node_modules/.bin/protractor --suite=all", @@ -20,47 +21,54 @@ }, "private": true, "dependencies": { + "@angular-devkit/schematics": "^0.7.5", + "@angular/cli": "^6.2.3", + "@angular/common": "^6.1.8", + "@angular/compiler": "^6.1.8", + "@angular/core": "^6.1.8", + "@angular/forms": "^6.1.8", + "@angular/http": "^6.1.8", + "@angular/platform-browser": "^6.1.8", + "@angular/platform-browser-dynamic": "^6.1.8", + "@angular/platform-server": "^6.1.8", + "@angular/router": "^6.1.8", "@types/ace": "0.0.32", - "@types/bootstrap": "^3.3.32", - "@types/jasmine": "2.2.30", - "@types/jquery": "^2.0.32", + "@types/bootstrap": "^4.1.2", + "@types/jasmine": "~2.8.6", + "@types/jasminewd2": "~2.0.3", + "@types/jquery": "^3.3.6", + "@types/node": "^10.9.4", "@types/tether": "^1.1.27", - "@angular/common": "2.0.0", - "@angular/compiler": "2.0.0", - "@angular/core": "2.0.0", - "@angular/forms": "2.0.0", - "@angular/http": "2.0.0", - "@angular/platform-browser": "2.0.0", - "@angular/platform-browser-dynamic": "2.0.0", - "@angular/router": "3.0.0", "ace-builds": "^1.2.5", "bootstrap": "4.0.0-alpha.5", - "core-js": "^2.4.1", + "core-js": "^2.5.7", "font-awesome": "^4.6.3", "jquery": "^3.3.1", - "rxjs": "5.0.0-beta.12", + "karma-phantomjs-launcher": "^1.0.4", + "puppeteer": "^1.8.0", + "rxjs": "6.2.2", "tether": "^1.3.4", "ts-helpers": "^1.1.1", - "zone.js": "^0.6.23" + "zone.js": "^0.8.26" }, "devDependencies": { - "angular-cli": "1.0.0-beta.15", + "@angular-devkit/build-angular": "^0.8.3", + "@angular/compiler-cli": "^6.1.8", + "@types/request": "2.0.3", "buffer-shims": "^1.0.0", - "codelyzer": "~0.0.26", + "codelyzer": "~4.2.1", "copy": "^0.3.0", - "jasmine-core": "2.4.1", - "jasmine-spec-reporter": "2.5.0", - "karma": "1.2.0", - "karma-chrome-launcher": "^2.0.0", - "karma-cli": "^1.0.1", - "karma-jasmine": "^1.0.2", - "karma-phantomjs-launcher": "^1.0.4", - "karma-remap-istanbul": "0.6.0", + "jasmine-core": "~2.99.1", + "jasmine-spec-reporter": "~4.2.1", + "karma": "^3.0.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.0", + "karma-jasmine": "^1.1.2", + "karma-jasmine-html-reporter": "^0.2.2", "phantomjs-prebuilt": "^2.1.14", - "protractor": "4.0.5", - "ts-node": "1.2.1", - "tslint": "3.13.0", - "typescript": "~2.0.3", - "@types/request": "2.0.3" + "protractor": "^5.4.1", + "ts-node": "~5.0.1", + "tslint": "^5.11.0", + "typescript": "~2.7.2" } }
http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/pom.xml ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/pom.xml b/metron-interface/metron-config/pom.xml index fd76447..c6ef5b5 100644 --- a/metron-interface/metron-config/pom.xml +++ b/metron-interface/metron-config/pom.xml @@ -63,7 +63,7 @@ </execution> <execution> <phase>generate-resources</phase> - <id>ng build</id> + <id>npm run build</id> <goals> <goal>npm</goal> </goals> @@ -72,13 +72,13 @@ </configuration> </execution> <execution> - <id>npm test</id> + <phase>test</phase> + <id>npm testCI</id> <goals> - <goal>npm</goal> + <goal>npm</goal> </goals> - <phase>test</phase> <configuration> - <arguments>test</arguments> + <arguments>run testCI</arguments> </configuration> </execution> </executions> http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/scripts/prepend_license_header.sh ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/scripts/prepend_license_header.sh b/metron-interface/metron-config/scripts/prepend_license_header.sh index 1957cd6..6bf004f 100755 --- a/metron-interface/metron-config/scripts/prepend_license_header.sh +++ b/metron-interface/metron-config/scripts/prepend_license_header.sh @@ -33,7 +33,7 @@ LICENSE_HEADER="/** * limitations under the License. */ " -for file in ./dist/*.js +for file in ./dist/*.{js,css} do if !(grep -Fxq "$LICENSE_HEADER" $file) then http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/scripts/start_dev.sh ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/scripts/start_dev.sh b/metron-interface/metron-config/scripts/start_dev.sh index 05ba601..830c543 100755 --- a/metron-interface/metron-config/scripts/start_dev.sh +++ b/metron-interface/metron-config/scripts/start_dev.sh @@ -16,4 +16,4 @@ # limitations under the License. # SCRIPTS_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -$SCRIPTS_ROOT/../node_modules/angular-cli/bin/ng serve --proxy-config proxy.conf.json +$SCRIPTS_ROOT/../node_modules/@angular/cli/bin/ng serve --proxy-config proxy.conf.json --aot http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/_fonts.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/_fonts.scss b/metron-interface/metron-config/src/app/_fonts.scss new file mode 100644 index 0000000..fdcb87e --- /dev/null +++ b/metron-interface/metron-config/src/app/_fonts.scss @@ -0,0 +1,101 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 100; + src: local('Roboto Thin'), local('Roboto-Thin'), url("/assets/fonts/Roboto/Roboto-Thin.ttf"); +} + +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + src: local('Roboto Light'), local('Roboto-Light'), url("/assets/fonts/Roboto/Roboto-Light.ttf"); +} + +@font-face { + font-family: 'Roboto-Regular'; + font-style: normal; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), url("/assets/fonts/Roboto/Roboto-Regular.ttf"); +} + +@font-face { + font-family: 'Roboto-Medium'; + font-style: normal; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), url("/assets/fonts/Roboto/Roboto-Medium.ttf"); +} + +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + src: local('Roboto Bold'), local('Roboto-Bold'), url("/assets/fonts/Roboto/Roboto-Bold.ttf"); +} + +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 900; + src: local('Roboto Black'), local('Roboto-Black'), url("/assets/fonts/Roboto/Roboto-Black.ttf"); +} + +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 100; + src: local('Roboto Thin Italic'), local('Roboto-ThinItalic'), url("/assets/fonts/Roboto/Roboto-ThinItalic.ttf"); +} + +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + src: local('Roboto Light Italic'), local('Roboto-LightItalic'), url("/assets/fonts/Roboto/Roboto-LightItalic.ttf"); +} + +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + src: local('Roboto Italic'), local('Roboto-Italic'), url("/assets/fonts/Roboto/Roboto-Italic.ttf"); +} + +@font-face { + font-family: 'Roboto-MediumItalic'; + font-style: italic; + font-weight: 500; + src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), url("/assets/fonts/Roboto/Roboto-MediumItalic.ttf"); +} + +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + src: local('Roboto Bold Italic'), local('Roboto-BoldItalic'), url("/assets/fonts/Roboto/Roboto-BoldItalic.ttf"); +} + +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 900; + src: local('Roboto Black Italic'), local('Roboto-BlackItalic'), url("/assets/fonts/Roboto/Roboto-BlackItalic.ttf"); +} + http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/_main.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/_main.scss b/metron-interface/metron-config/src/app/_main.scss deleted file mode 100644 index f889c7a..0000000 --- a/metron-interface/metron-config/src/app/_main.scss +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url("assets/fonts/Roboto/Roboto-Thin.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url("assets/fonts/Roboto/Roboto-Light.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto-Regular'; - font-style: normal; - font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url("assets/fonts/Roboto/Roboto-Regular.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto-Medium'; - font-style: normal; - font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url("assets/fonts/Roboto/Roboto-Medium.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url("assets/fonts/Roboto/Roboto-Bold.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url("assets/fonts/Roboto/Roboto-Black.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: italic; - font-weight: 100; - src: local('Roboto Thin Italic'), local('Roboto-ThinItalic'), url("assets/fonts/Roboto/Roboto-ThinItalic.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: italic; - font-weight: 300; - src: local('Roboto Light Italic'), local('Roboto-LightItalic'), url("assets/fonts/Roboto/Roboto-LightItalic.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: italic; - font-weight: 400; - src: local('Roboto Italic'), local('Roboto-Italic'), url("assets/fonts/Roboto/Roboto-Italic.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto-MediumItalic'; - font-style: italic; - font-weight: 500; - src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), url("assets/fonts/Roboto/Roboto-MediumItalic.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: italic; - font-weight: 700; - src: local('Roboto Bold Italic'), local('Roboto-BoldItalic'), url("assets/fonts/Roboto/Roboto-BoldItalic.ttf"); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Roboto'; - font-style: italic; - font-weight: 900; - src: local('Roboto Black Italic'), local('Roboto-BlackItalic'), url("assets/fonts/Roboto/Roboto-BlackItalic.ttf"); -} - http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/app.component.spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/app.component.spec.ts b/metron-interface/metron-config/src/app/app.component.spec.ts index 6ae511f..4ca1bfa 100644 --- a/metron-interface/metron-config/src/app/app.component.spec.ts +++ b/metron-interface/metron-config/src/app/app.component.spec.ts @@ -15,61 +15,58 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {Inject} from '@angular/core'; -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import {ResponseOptions, RequestOptions, Response, Http} from '@angular/http'; -import {Router} from '@angular/router'; -import {Observable} from 'rxjs/Observable'; -import {AppComponent} from './app.component'; -import {AuthenticationService} from './service/authentication.service'; -import {AppModule} from './app.module'; -import {APP_CONFIG, METRON_REST_CONFIG} from './app.config'; -import {IAppConfig} from './app.config.interface'; +import { Inject } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { Observable } from 'rxjs'; +import { AppComponent } from './app.component'; +import { AuthenticationService } from './service/authentication.service'; +import { AppModule } from './app.module'; +import { APP_CONFIG, METRON_REST_CONFIG } from './app.config'; +import { IAppConfig } from './app.config.interface'; +import { HttpResponse, HttpClient } from '@angular/common/http'; class MockAuthenticationService extends AuthenticationService { - - constructor(private http2: Http, private router2: Router, @Inject(APP_CONFIG) private config2: IAppConfig) { + constructor( + private http2: HttpClient, + private router2: Router, + @Inject(APP_CONFIG) private config2: IAppConfig + ) { super(http2, router2, config2); + this.onLoginEvent.next(false); } - public checkAuthentication() { - } + public checkAuthentication() {} - public getCurrentUser(options: RequestOptions): Observable<Response> { + public getCurrentUser(options): Observable<HttpResponse<{}>> { return Observable.create(observer => { - observer.next(new Response(new ResponseOptions({body: 'test'}))); + observer.next(new HttpResponse({ body: 'test' })); observer.complete(); }); } } class MockRouter { - navigateByUrl(url: string) { - } + navigateByUrl(url: string) {} } describe('App: Static', () => { - let comp: AppComponent; let fixture: ComponentFixture<AppComponent>; let authenticationService: AuthenticationService; beforeEach(async(() => { - TestBed.configureTestingModule({ imports: [AppModule], providers: [ - {provide: Http}, - {provide: AuthenticationService, useClass: MockAuthenticationService}, - {provide: Router, useClass: MockRouter}, - {provide: APP_CONFIG, useValue: METRON_REST_CONFIG} + { provide: AuthenticationService, useClass: MockAuthenticationService }, + { provide: Router, useClass: MockRouter }, + { provide: APP_CONFIG, useValue: METRON_REST_CONFIG } ] - }).compileComponents() - .then(() => { - fixture = TestBed.createComponent(AppComponent); - comp = fixture.componentInstance; - authenticationService = fixture.debugElement.injector.get(AuthenticationService); - }); + }); + fixture = TestBed.createComponent(AppComponent); + comp = fixture.componentInstance; + authenticationService = TestBed.get(AuthenticationService); })); it('should create the app', () => { @@ -77,13 +74,10 @@ describe('App: Static', () => { }); it('should return true/false from loginevent and loggedIn should be set', () => { - expect(comp.loggedIn).toEqual(false); - authenticationService.onLoginEvent.emit(true); + authenticationService.onLoginEvent.next(true); expect(comp.loggedIn).toEqual(true); - authenticationService.onLoginEvent.emit(false); + authenticationService.onLoginEvent.next(false); expect(comp.loggedIn).toEqual(false); - }); - }); http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/app.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/app.component.ts b/metron-interface/metron-config/src/app/app.component.ts index 9bfe3d2..591f0b0 100644 --- a/metron-interface/metron-config/src/app/app.component.ts +++ b/metron-interface/metron-config/src/app/app.component.ts @@ -16,7 +16,6 @@ * limitations under the License. */ import {Component} from '@angular/core'; -import './rxjs-operators'; import {AuthenticationService} from './service/authentication.service'; @@ -28,7 +27,7 @@ import {AuthenticationService} from './service/authentication.service'; export class AppComponent { - loggedIn: boolean = false; + loggedIn = false; constructor(private authService: AuthenticationService) { this.authService.onLoginEvent.subscribe(result => { http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/app.config.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/app.config.ts b/metron-interface/metron-config/src/app/app.config.ts index 27f24c4..abd378c 100644 --- a/metron-interface/metron-config/src/app/app.config.ts +++ b/metron-interface/metron-config/src/app/app.config.ts @@ -16,10 +16,10 @@ * limitations under the License. */ -import { OpaqueToken } from '@angular/core'; +import { InjectionToken } from '@angular/core'; import {IAppConfig} from './app.config.interface'; -export let APP_CONFIG = new OpaqueToken('app.config'); +export let APP_CONFIG = new InjectionToken('app.config'); export const METRON_REST_CONFIG: IAppConfig = { apiEndpoint: '/api/v1' http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/app.module.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/app.module.ts b/metron-interface/metron-config/src/app/app.module.ts index 4ac82a2..8df5293 100644 --- a/metron-interface/metron-config/src/app/app.module.ts +++ b/metron-interface/metron-config/src/app/app.module.ts @@ -18,7 +18,8 @@ import {NgModule} from '@angular/core'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {BrowserModule} from '@angular/platform-browser'; -import {HttpModule} from '@angular/http'; +import {HttpClientModule, HTTP_INTERCEPTORS} from '@angular/common/http'; +import { Router } from '@angular/router'; import {AppComponent} from './app.component'; import {SensorParserConfigService} from './service/sensor-parser-config.service'; import {KafkaService} from './service/kafka.service'; @@ -27,7 +28,7 @@ import {StellarService} from './service/stellar.service'; import {MetronAlerts} from './shared/metron-alerts'; import {NavbarComponent} from './navbar/navbar.component'; import {VerticalNavbarComponent} from './verticalnavbar/verticalnavbar.component'; -import {routing, appRoutingProviders} from './app.routes'; +import {MetronConfigRoutingModule} from './app.routes'; import {AuthenticationService} from './service/authentication.service'; import {AuthGuard} from './shared/auth-guard'; import {LoginGuard} from './shared/login-guard'; @@ -43,16 +44,20 @@ import {StormService} from './service/storm.service'; import {SensorParserConfigHistoryService} from './service/sensor-parser-config-history.service'; import {SensorIndexingConfigService} from './service/sensor-indexing-config.service'; import {HdfsService} from './service/hdfs.service'; +import { DefaultHeadersInterceptor } from './http-interceptors/default-headers.interceptor'; @NgModule({ - imports: [ BrowserModule, routing, FormsModule, ReactiveFormsModule, HttpModule, SensorParserListModule, - SensorParserConfigModule, SensorParserConfigReadonlyModule, GeneralSettingsModule ], + imports: [ BrowserModule, FormsModule, ReactiveFormsModule, HttpClientModule, SensorParserListModule, + SensorParserConfigModule, SensorParserConfigReadonlyModule, GeneralSettingsModule, MetronConfigRoutingModule ], declarations: [ AppComponent, NavbarComponent, VerticalNavbarComponent ], providers: [ AuthenticationService, AuthGuard, LoginGuard, SensorParserConfigService, SensorParserConfigHistoryService, SensorEnrichmentConfigService, SensorIndexingConfigService, StormService, KafkaService, GrokValidationService, StellarService, HdfsService, - GlobalConfigService, MetronAlerts, MetronDialogBox, appRoutingProviders, { provide: APP_CONFIG, useValue: METRON_REST_CONFIG }], + GlobalConfigService, MetronAlerts, MetronDialogBox, { provide: APP_CONFIG, useValue: METRON_REST_CONFIG }, + { provide: HTTP_INTERCEPTORS, useClass: DefaultHeadersInterceptor, multi: true }], bootstrap: [ AppComponent ] }) -export class AppModule { } +export class AppModule { + constructor(router: Router) {} +} http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/app.routes.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/app.routes.ts b/metron-interface/metron-config/src/app/app.routes.ts index 73db2fd..fd3655d 100644 --- a/metron-interface/metron-config/src/app/app.routes.ts +++ b/metron-interface/metron-config/src/app/app.routes.ts @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {ModuleWithProviders} from '@angular/core'; +import { NgModule } from '@angular/core'; import {Routes, RouterModule} from '@angular/router'; import {AuthGuard} from './shared/auth-guard'; import {LoginGuard} from './shared/login-guard'; @@ -30,4 +30,10 @@ export const routes: Routes = [ export const appRoutingProviders: any[] = [ ]; -export const routing: ModuleWithProviders = RouterModule.forRoot(routes); +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule], + providers: [] +}) + +export class MetronConfigRoutingModule { } http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/general-settings/general-settings.component.spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/general-settings/general-settings.component.spec.ts b/metron-interface/metron-config/src/app/general-settings/general-settings.component.spec.ts index 51fc709..b1c5ede 100644 --- a/metron-interface/metron-config/src/app/general-settings/general-settings.component.spec.ts +++ b/metron-interface/metron-config/src/app/general-settings/general-settings.component.spec.ts @@ -15,23 +15,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {Inject} from '@angular/core'; -import {async, TestBed, ComponentFixture} from '@angular/core/testing'; -import {Http} from '@angular/http'; -import {GeneralSettingsComponent} from './general-settings.component'; -import {MetronAlerts} from '../shared/metron-alerts'; -import {MetronDialogBox} from '../shared/metron-dialog-box'; -import {GlobalConfigService} from '../service/global-config.service'; -import {GeneralSettingsModule} from './general-settings.module'; -import {Observable} from 'rxjs/Observable'; -import {APP_CONFIG, METRON_REST_CONFIG} from '../app.config'; -import {IAppConfig} from '../app.config.interface'; +import { Inject } from '@angular/core'; +import { async, TestBed, ComponentFixture } from '@angular/core/testing'; +import { HttpClient } from '@angular/common/http'; +import { GeneralSettingsComponent } from './general-settings.component'; +import { MetronAlerts } from '../shared/metron-alerts'; +import { MetronDialogBox } from '../shared/metron-dialog-box'; +import { GlobalConfigService } from '../service/global-config.service'; +import { GeneralSettingsModule } from './general-settings.module'; +import { Observable, throwError } from 'rxjs'; +import { APP_CONFIG, METRON_REST_CONFIG } from '../app.config'; +import { IAppConfig } from '../app.config.interface'; class MockGlobalConfigService extends GlobalConfigService { _config: any = {}; - _postSuccess: boolean = true; + _postSuccess = true; - constructor(private http2: Http, @Inject(APP_CONFIG) private config2: IAppConfig) { + constructor( + private http2: HttpClient, + @Inject(APP_CONFIG) private config2: IAppConfig + ) { super(http2, config2); } @@ -43,7 +46,7 @@ class MockGlobalConfigService extends GlobalConfigService { }); } - return Observable.throw('Error'); + return throwError('Error'); } public get(): Observable<{}> { @@ -55,7 +58,6 @@ class MockGlobalConfigService extends GlobalConfigService { } describe('GeneralSettingsComponent', () => { - let metronAlerts: MetronAlerts; let metronDialogBox: MetronDialogBox; let component: GeneralSettingsComponent; @@ -68,39 +70,38 @@ describe('GeneralSettingsComponent', () => { 'hdfs.boltBatchSize': 5000, 'hdfs.boltFieldDelimiter': '|', 'hdfs.boltFileRotationSize': 5, - 'hdfs.boltCompressionCodecClass': 'org.apache.hadoop.io.compress.SnappyCodec', + 'hdfs.boltCompressionCodecClass': + 'org.apache.hadoop.io.compress.SnappyCodec', 'hdfs.indexOutput': '/tmp/metron/enriched', 'kafkaWriter.topic': 'outputTopic', - 'kafkaWriter.keySerializer': 'org.apache.kafka.common.serialization.StringSerializer', - 'kafkaWriter.valueSerializer': 'org.apache.kafka.common.serialization.StringSerializer', + 'kafkaWriter.keySerializer': + 'org.apache.kafka.common.serialization.StringSerializer', + 'kafkaWriter.valueSerializer': + 'org.apache.kafka.common.serialization.StringSerializer', 'kafkaWriter.requestRequiredAcks': 1, 'solrWriter.indexName': 'alfaalfa', 'solrWriter.shards': 1, 'solrWriter.replicationFactor': 1, 'solrWriter.batchSize': 50, - 'fieldValidations': {'field': 'validation'} + fieldValidations: { field: 'validation' } }; beforeEach(async(() => { - TestBed.configureTestingModule({ imports: [GeneralSettingsModule], providers: [ - {provide: Http}, + { provide: HttpClient }, MetronAlerts, MetronDialogBox, - {provide: GlobalConfigService, useClass: MockGlobalConfigService}, - {provide: APP_CONFIG, useValue: METRON_REST_CONFIG} + { provide: GlobalConfigService, useClass: MockGlobalConfigService }, + { provide: APP_CONFIG, useValue: METRON_REST_CONFIG } ] - }).compileComponents() - .then(() => { - fixture = TestBed.createComponent(GeneralSettingsComponent); - component = fixture.componentInstance; - globalConfigService = fixture.debugElement.injector.get(GlobalConfigService); - metronAlerts = fixture.debugElement.injector.get(MetronAlerts); - metronDialogBox = fixture.debugElement.injector.get(MetronDialogBox); - }); - + }); + fixture = TestBed.createComponent(GeneralSettingsComponent); + component = fixture.componentInstance; + globalConfigService = TestBed.get(GlobalConfigService); + metronAlerts = TestBed.get(MetronAlerts); + metronDialogBox = TestBed.get(MetronDialogBox); })); it('can instantiate GeneralSettingsComponent', async(() => { @@ -111,7 +112,7 @@ describe('GeneralSettingsComponent', () => { globalConfigService._config = config; component.ngOnInit(); - expect(component.globalConfig).toEqual(globalConfigService._config); + expect(component.globalConfig).toEqual(config); })); it('should save global config', async(() => { @@ -122,18 +123,22 @@ describe('GeneralSettingsComponent', () => { spyOn(metronAlerts, 'showErrorMessage'); component.onSave(); - expect(metronAlerts.showSuccessMessage).toHaveBeenCalledWith('Saved Global Settings'); + expect(metronAlerts.showSuccessMessage).toHaveBeenCalledWith( + 'Saved Global Settings' + ); globalConfigService._postSuccess = false; component.onSave(); - expect(metronAlerts.showErrorMessage).toHaveBeenCalledWith('Unable to save Global Settings: Error'); - + expect(metronAlerts.showErrorMessage).toHaveBeenCalledWith( + 'Unable to save Global Settings: Error' + ); })); it('should handle onCancel', async(() => { let dialogReturnTrue = true; - let confirmationMsg = 'Cancelling will revert all the changes made to the form. Do you wish to continue ?'; + let confirmationMsg = + 'Cancelling will revert all the changes made to the form. Do you wish to continue ?'; spyOn(component, 'ngOnInit'); spyOn(metronDialogBox, 'showConfirmationMessage').and.callFake(function() { @@ -148,14 +153,14 @@ describe('GeneralSettingsComponent', () => { expect(component.ngOnInit).toHaveBeenCalled(); expect(component.ngOnInit['calls'].count()).toEqual(1); expect(metronDialogBox.showConfirmationMessage['calls'].count()).toEqual(1); - expect(metronDialogBox.showConfirmationMessage).toHaveBeenCalledWith(confirmationMsg); + expect(metronDialogBox.showConfirmationMessage).toHaveBeenCalledWith( + confirmationMsg + ); dialogReturnTrue = false; component.onCancel(); expect(metronDialogBox.showConfirmationMessage['calls'].count()).toEqual(2); expect(component.ngOnInit['calls'].count()).toEqual(1); - })); - }); http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/general-settings/general-settings.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/general-settings/general-settings.component.ts b/metron-interface/metron-config/src/app/general-settings/general-settings.component.ts index 11d4cad..494c83c 100644 --- a/metron-interface/metron-config/src/app/general-settings/general-settings.component.ts +++ b/metron-interface/metron-config/src/app/general-settings/general-settings.component.ts @@ -16,9 +16,9 @@ * limitations under the License. */ import { Component, OnInit } from '@angular/core'; -import {GlobalConfigService} from '../service/global-config.service'; -import {MetronAlerts} from '../shared/metron-alerts'; -import {MetronDialogBox} from '../shared/metron-dialog-box'; +import { GlobalConfigService } from '../service/global-config.service'; +import { MetronAlerts } from '../shared/metron-alerts'; +import { MetronDialogBox } from '../shared/metron-dialog-box'; @Component({ selector: 'metron-config-general-settings', @@ -26,15 +26,17 @@ import {MetronDialogBox} from '../shared/metron-dialog-box'; styleUrls: ['./general-settings.component.scss'] }) export class GeneralSettingsComponent implements OnInit { - globalConfig: {} = { 'es.date.format': '-' }; - private fieldValidations: string; + fieldValidations: string; - constructor(private globalConfigService: GlobalConfigService, private metronAlerts: MetronAlerts, - private metronDialog: MetronDialogBox) {} + constructor( + private globalConfigService: GlobalConfigService, + private metronAlerts: MetronAlerts, + private metronDialog: MetronDialogBox + ) {} ngOnInit() { this.globalConfigService.get().subscribe((config: {}) => { @@ -43,7 +45,11 @@ export class GeneralSettingsComponent implements OnInit { this.globalConfig['es.date.format'] = '-'; } if (this.globalConfig['fieldValidations']) { - this.fieldValidations = JSON.stringify(this.globalConfig['fieldValidations'], null, '\t'); + this.fieldValidations = JSON.stringify( + this.globalConfig['fieldValidations'], + null, + '\t' + ); } }); } @@ -52,21 +58,27 @@ export class GeneralSettingsComponent implements OnInit { if (this.fieldValidations && this.fieldValidations.length > 0) { this.globalConfig['fieldValidations'] = JSON.parse(this.fieldValidations); } - this.globalConfigService.post(this.globalConfig).subscribe(() => { + this.globalConfigService.post(this.globalConfig).subscribe( + () => { this.metronAlerts.showSuccessMessage('Saved Global Settings'); }, error => { - this.metronAlerts.showErrorMessage('Unable to save Global Settings: ' + error); - }); + this.metronAlerts.showErrorMessage( + 'Unable to save Global Settings: ' + error + ); + } + ); } onCancel() { - let confirmationMsg = 'Cancelling will revert all the changes made to the form. Do you wish to continue ?'; - this.metronDialog.showConfirmationMessage(confirmationMsg).subscribe((result: boolean) => { - if (result) { - this.ngOnInit(); - } - }); + let confirmationMsg = + 'Cancelling will revert all the changes made to the form. Do you wish to continue ?'; + this.metronDialog + .showConfirmationMessage(confirmationMsg) + .subscribe((result: boolean) => { + if (result) { + this.ngOnInit(); + } + }); } - } http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/global.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/global.scss b/metron-interface/metron-config/src/app/global.scss index 8b64cab..bcce900 100644 --- a/metron-interface/metron-config/src/app/global.scss +++ b/metron-interface/metron-config/src/app/global.scss @@ -16,7 +16,7 @@ * limitations under the License. */ @import "_variables.scss"; -@import "_main.scss"; +@import "_fonts.scss"; $height: 60px; http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/http-interceptors/default-headers.interceptor.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/http-interceptors/default-headers.interceptor.ts b/metron-interface/metron-config/src/app/http-interceptors/default-headers.interceptor.ts new file mode 100644 index 0000000..1df12ad --- /dev/null +++ b/metron-interface/metron-config/src/app/http-interceptors/default-headers.interceptor.ts @@ -0,0 +1,32 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Injectable } from '@angular/core'; +import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http'; +import { Observable } from 'rxjs'; + +@Injectable() +export class DefaultHeadersInterceptor implements HttpInterceptor { + intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { + // Clone the request and replace the original headers with + // cloned headers, updated with the authorization. + const authReq = req.clone({ + setHeaders: {'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest'} + }); + return next.handle(authReq); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/login/login.component.spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/login/login.component.spec.ts b/metron-interface/metron-config/src/app/login/login.component.spec.ts index 5ad285a..eac383c 100644 --- a/metron-interface/metron-config/src/app/login/login.component.spec.ts +++ b/metron-interface/metron-config/src/app/login/login.component.spec.ts @@ -15,23 +15,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import {AuthenticationService} from '../service/authentication.service'; -import {LoginComponent} from './login.component'; -import {Observable} from 'rxjs/Observable'; -import {ActivatedRoute, Params} from '@angular/router'; -import {LoginModule} from './login.module'; -import {APP_CONFIG, METRON_REST_CONFIG} from '../app.config'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AuthenticationService } from '../service/authentication.service'; +import { LoginComponent } from './login.component'; +import { Observable } from 'rxjs'; +import { ActivatedRoute, Params } from '@angular/router'; +import { LoginModule } from './login.module'; +import { APP_CONFIG, METRON_REST_CONFIG } from '../app.config'; class MockAuthenticationService { - public login(username: string, password: string, onError): void { if (username === 'success') { - onError({status: 200}); + onError({ status: 200 }); } if (username === 'failure') { - onError({status: 401}); + onError({ status: 401 }); } } } @@ -43,14 +42,13 @@ class MockActivatedRoute { setSessionExpired() { this.queryParams = Observable.create(observer => { - observer.next({'sessionExpired': 'true'}); + observer.next({ sessionExpired: 'true' }); observer.complete(); }); } } describe('LoginComponent', () => { - let component: LoginComponent; let fixture: ComponentFixture<LoginComponent>; let activatedRoute: MockActivatedRoute; @@ -59,17 +57,14 @@ describe('LoginComponent', () => { TestBed.configureTestingModule({ imports: [LoginModule], providers: [ - {provide: ActivatedRoute, useClass: MockActivatedRoute}, - {provide: AuthenticationService, useClass: MockAuthenticationService}, - {provide: APP_CONFIG, useValue: METRON_REST_CONFIG} + { provide: ActivatedRoute, useClass: MockActivatedRoute }, + { provide: AuthenticationService, useClass: MockAuthenticationService }, + { provide: APP_CONFIG, useValue: METRON_REST_CONFIG } ] - }).compileComponents() - .then(() => { - fixture = TestBed.createComponent(LoginComponent); - component = fixture.componentInstance; - activatedRoute = fixture.debugElement.injector.get(ActivatedRoute); }); - + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + activatedRoute = TestBed.get(ActivatedRoute); })); it('should create an instance', async(() => { @@ -86,14 +81,13 @@ describe('LoginComponent', () => { component.password = 'failure'; component.login(); expect(component.loginFailure).toEqual('Login failed for failure'); - })); it('can handle sessionExpired', async(() => { activatedRoute.setSessionExpired(); - let sessionExpiredComponent = TestBed.createComponent(LoginComponent).componentInstance; + let sessionExpiredComponent = TestBed.createComponent(LoginComponent) + .componentInstance; expect(sessionExpiredComponent.loginFailure).toEqual('Session has expired'); })); - }); http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/model/rest-error.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/model/rest-error.ts b/metron-interface/metron-config/src/app/model/rest-error.ts index 5daee25..f000c1f 100644 --- a/metron-interface/metron-config/src/app/model/rest-error.ts +++ b/metron-interface/metron-config/src/app/model/rest-error.ts @@ -16,7 +16,7 @@ * limitations under the License. */ export class RestError { - responseCode: number; + status: number; message: string; - fullMessage: string; + error: string; } http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/navbar/navbar.component.spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/navbar/navbar.component.spec.ts b/metron-interface/metron-config/src/app/navbar/navbar.component.spec.ts index d0bd4e0..db7574e 100644 --- a/metron-interface/metron-config/src/app/navbar/navbar.component.spec.ts +++ b/metron-interface/metron-config/src/app/navbar/navbar.component.spec.ts @@ -15,11 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {async, TestBed, ComponentFixture} from '@angular/core/testing'; -import {NavbarComponent} from './navbar.component'; -import {AuthenticationService} from '../service/authentication.service'; +import { async, TestBed, ComponentFixture } from '@angular/core/testing'; +import { NavbarComponent } from './navbar.component'; +import { AuthenticationService } from '../service/authentication.service'; +import { of } from 'rxjs'; class MockAuthenticationService { + getCurrentUser() { + return of('user'); + } } describe('NavbarComponent', () => { @@ -28,21 +32,18 @@ describe('NavbarComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ NavbarComponent], + declarations: [NavbarComponent], providers: [ NavbarComponent, - {provide: AuthenticationService, useClass: MockAuthenticationService} + { provide: AuthenticationService, useClass: MockAuthenticationService } ] }); - fixture = TestBed.createComponent(NavbarComponent); navbarComponent = fixture.componentInstance; - })); it('can instantiate SampleDataComponent', async(() => { expect(navbarComponent instanceof NavbarComponent).toBe(true); - fixture.destroy(); + fixture.detectChanges(); })); - }); http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/navbar/navbar.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/navbar/navbar.component.ts b/metron-interface/metron-config/src/app/navbar/navbar.component.ts index 45c15ef..7861423 100644 --- a/metron-interface/metron-config/src/app/navbar/navbar.component.ts +++ b/metron-interface/metron-config/src/app/navbar/navbar.component.ts @@ -15,17 +15,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {Component} from '@angular/core'; -import {AuthenticationService} from '../service/authentication.service'; +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { AuthenticationService } from '../service/authentication.service'; +import { Subscription } from 'rxjs'; @Component({ - selector: 'metron-config-navbar', - templateUrl: 'navbar.html', - styleUrls: ['navbar.component.scss'] + selector: 'metron-config-navbar', + templateUrl: 'navbar.html', + styleUrls: ['navbar.component.scss'] }) +export class NavbarComponent implements OnInit, OnDestroy { + currentUser; + authService: Subscription; -export class NavbarComponent { + constructor(private authenticationService: AuthenticationService) {} - constructor(private authenticationService: AuthenticationService) { + ngOnInit() { + this.authService = this.authenticationService + .getCurrentUser({ responseType: 'text' }) + .subscribe(r => { + this.currentUser = r; + }); + } + + logout() { + this.authenticationService.logout(); + } + + ngOnDestroy() { + this.authService.unsubscribe(); } } http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/navbar/navbar.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/navbar/navbar.html b/metron-interface/metron-config/src/app/navbar/navbar.html index 3af1c7c..0e373e1 100644 --- a/metron-interface/metron-config/src/app/navbar/navbar.html +++ b/metron-interface/metron-config/src/app/navbar/navbar.html @@ -23,7 +23,7 @@ <div class="form-inline pull-right"> <i class="fa fa-user " style="padding-left: 11px" aria-hidden="true"></i> - <div *ngIf="authenticationService.currentUser != null" class="fa logout">Logged in as {{authenticationService.currentUser}} - <span class="logout-link" (click)="authenticationService.logout()">Logout</span></div> + <div *ngIf="currentUser != null" class="fa logout">Logged in as {{currentUser}} - <span class="logout-link" (click)="logout()">Logout</span></div> </div> </nav> http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/rxjs-operators.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/rxjs-operators.ts b/metron-interface/metron-config/src/app/rxjs-operators.ts deleted file mode 100644 index 11c86fb..0000000 --- a/metron-interface/metron-config/src/app/rxjs-operators.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// import 'rxjs/Rx'; // adds ALL RxJS statics & operators to Observable - -// See node_module/rxjs/Rxjs.js -// Import just the rxjs statics and operators we need for THIS app. - -// Statics -import 'rxjs/add/observable/throw'; - -// Operators -import 'rxjs/add/operator/catch'; -import 'rxjs/add/operator/debounceTime'; -import 'rxjs/add/operator/distinctUntilChanged'; -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/switchMap'; -import 'rxjs/add/operator/toPromise'; http://git-wip-us.apache.org/repos/asf/metron/blob/0c4c622b/metron-interface/metron-config/src/app/sensors/sensor-field-schema/sensor-field-schema.component.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-config/src/app/sensors/sensor-field-schema/sensor-field-schema.component.html b/metron-interface/metron-config/src/app/sensors/sensor-field-schema/sensor-field-schema.component.html index 18b4b82..1dcc9f1 100644 --- a/metron-interface/metron-config/src/app/sensors/sensor-field-schema/sensor-field-schema.component.html +++ b/metron-interface/metron-config/src/app/sensors/sensor-field-schema/sensor-field-schema.component.html @@ -20,7 +20,7 @@ <form role="form" class="fieldschema-form"> - <metron-config-sample-data [topic]="sensorParserConfig.sensorTopic" (onSampleDataChanged)="onSampleDataChanged($event)" (onSampleDataNotAvailable)="onSampleDataNotAvailable($event)"></metron-config-sample-data> + <metron-config-sample-data [topic]="sensorParserConfig.sensorTopic" (onSampleDataChanged)="onSampleDataChanged($event)" (onSampleDataNotAvailable)="onSampleDataNotAvailable()"></metron-config-sample-data> <br><br>