You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metron.apache.org by rm...@apache.org on 2017/04/11 13:51:22 UTC
[11/12] incubator-metron git commit: METRON-623 Management UI
[contributed by Raghu Mitra Kandikonda and Ryan Merriman] closes
apache/incubator-metron#489
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/e2e/sensor-list/sensor-list.po.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/e2e/sensor-list/sensor-list.po.ts b/metron-interface/metron-config/e2e/sensor-list/sensor-list.po.ts
new file mode 100644
index 0000000..b7f5167
--- /dev/null
+++ b/metron-interface/metron-config/e2e/sensor-list/sensor-list.po.ts
@@ -0,0 +1,240 @@
+/**
+ * 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 andx
+ * limitations under the License.
+ */
+
+import { browser, element, by, protractor } from 'protractor/globals';
+import { waitForElementPresence, waitForStalenessOf } from '../utils/e2e_util';
+var Promise = require('bluebird');
+
+export class SensorListPage {
+
+ clickOnActionsAndWait(parserNames: string[], clickOnClassName: string, waitOnClassName: string) {
+ let queueForClick = Promise.resolve();
+ parserNames.forEach((name) => {
+ queueForClick = queueForClick.then((result) => {
+ return this.getIconButton(name, clickOnClassName).click();
+ });
+ });
+
+ return queueForClick.then(() => {
+ let promiseArray = [];
+ parserNames.map(name => {
+ promiseArray.push(this.waitForElement(this.getIconButton(name, waitOnClassName)));
+ });
+
+ return protractor.promise.all(promiseArray).then(args => {
+ return args;
+ });
+ });
+ }
+
+ clickOnDropdownAndWait(parserNames: string[], dropDownLinkName: string, waitOnClassName: string) {
+ return protractor.promise.all([this.toggleSelectAll(), this.toggleDropdown()]).then(() => {
+
+ return element(by.css('span[data-action=\"'+ dropDownLinkName +'\"]')).click().then(() => {
+ let promiseArray = [];
+ parserNames.map(name => {
+ promiseArray.push(this.waitForElement(this.getIconButton(name, waitOnClassName)));
+ });
+
+ return protractor.promise.all(promiseArray).then(args => {
+ return this.toggleSelectAll().then(() => {
+ return args;
+ })
+ });
+ });
+ });
+ }
+
+ closePane(className: string ='.close-button') {
+ return this.waitForElement(element(by.css(className))).then(() => {
+ return element(by.css(className)).click();
+ });
+ }
+
+ disableParsers(names: string[]) {
+ return this.clickOnActionsAndWait(names, 'i.fa-ban', 'i.fa-check-circle-o');
+ }
+
+ disableParsersFromDropdown(names: string[]) {
+ return this.clickOnDropdownAndWait(names, 'Disable', 'i.fa-check-circle-o');
+ }
+
+ deleteParser(name: string) {
+ return this.getIconButton(name, '.fa-trash-o').click().then(() => {
+ browser.sleep(1000);
+ return element(by.css('.metron-dialog .btn-primary')).click().then(() => {
+ browser.sleep(1000);
+ return element(by.css('.alert .close')).click().then(() => {
+ return waitForStalenessOf(element(by.cssContainingText('td', name))).then(() =>{
+ return true;
+ });
+ })
+ });
+ });
+ }
+
+ enableParsers(names: string[]) {
+ return this.clickOnActionsAndWait(names, 'i.fa-check-circle-o', 'i.fa-ban');
+ }
+
+ enableParsersFromDropdown(names: string[]) {
+ return this.clickOnDropdownAndWait(names, 'Enable', 'i.fa-ban');
+ }
+
+ getActions(name: string) {
+ return element.all(by.css('table>tbody>tr')).filter(row => {
+ return row.all(by.tagName('td')).get(0).getText().then(pName => {
+ return pName === name;
+ })
+ }).get(0).all(by.tagName('i')).map(icon => {
+ return icon.getAttribute('class').then(classNames => {
+ let className = classNames.replace('fa ', '').replace('fa-lg', '').replace('fa-spin fa-fw', '').trim();
+ return {classNames: className, displayed: icon.isDisplayed()};
+ });
+ });
+ }
+
+ getAddButton() {
+ return element(by.css('.metron-add-button.hexa-button .fa-plus')).isPresent();
+ }
+
+ getColumnValues(colId: number) {
+ return element.all(by.css('table tbody tr')).map(function(elm) {
+ return elm.all(by.css('td')).get(colId).getText();
+ });
+ }
+
+ getDropdownActionState() {
+ return protractor.promise.all([
+ element.all(by.css('.dropdown.open .dropdown-menu span:not(.disabled)')).count(),
+ element.all(by.css('.dropdown.open .dropdown-menu span.disabled')).count(),
+ element.all(by.css('.dropdown-menu')).isDisplayed()
+ ]).then(args => {
+ return {
+ enabled: args[0],
+ disabled: args[1],
+ displayed: args[2][0],
+ }
+ });
+ }
+
+ getIconButton(name: string, className: string) {
+ return element.all(by.css('table>tbody>tr')).filter(row => {
+ return row.all(by.tagName('td')).get(0).getText().then(pName => {
+ return pName === name;
+ })
+ }).get(0).element(by.css(className));
+ }
+
+ getParserCount() {
+ browser.waitForAngular();
+ return element.all(by.css('table>tbody>tr')).count();
+ }
+
+ getRow(name: string) {
+ return element.all(by.css('table>tbody>tr')).filter(row => {
+ return row.all(by.tagName('td')).get(0).getText().then(pName => {
+ return pName === name;
+ })
+ }).get(0);
+ }
+
+ getSelectedRowCount() {
+ return element.all(by.css('tr.active')).count();
+ }
+
+ getSortOrder(name: string) {
+ return element(by.linkText(name)).element(by.tagName('i')).getAttribute('class');
+ }
+
+ getTableColumnNames() {
+ return element.all(by.css('table th a')).map(function(elm) {
+ return elm.getText();
+ });
+ }
+
+ getTitle() {
+ return element(by.css('.metron-title')).getText();
+ }
+
+ load() {
+ return browser.get('/sensors');
+ }
+
+ openDetailsPane(name: string) {
+ return this.getRow(name).click().then(() =>{
+ return browser.getCurrentUrl();
+ });
+ }
+
+ openEditPane(name: string) {
+ let row = element(by.cssContainingText('td', name));
+ return waitForElementPresence(row).then(() => {
+ return this.getIconButton(name, '.fa-pencil').click().then(() =>{
+ return browser.getCurrentUrl();
+ });
+ })
+ }
+
+ openEditPaneAndClose(name: string) {
+ return this.getIconButton(name, '.fa-pencil').click().then(() =>{
+ let url = browser.getCurrentUrl();
+ browser.sleep(500);
+ return this.closePane('.main.close-button').then(() => {
+ return url;
+ });
+ });
+ }
+
+ startParsers(names: string[]) {
+ return this.clickOnActionsAndWait(names, 'i.fa-play', 'i.fa-stop');
+ }
+
+ startParsersFromDropdown(names: string[]) {
+ return this.clickOnDropdownAndWait(names, 'Start', 'i.fa-stop');
+ }
+
+ stopParsers(names: string[]) {
+ return this.clickOnActionsAndWait(names, 'i.fa-stop', 'i.fa-play');
+ }
+
+ stopParsersFromDropdown(names: string[]) {
+ return this.clickOnDropdownAndWait(names, 'Stop', 'i.fa-play');
+ }
+
+ toggleDropdown() {
+ return element.all(by.id('dropdownMenu1')).click();
+ }
+
+ toggleRowSelect(name: string) {
+ element.all(by.css('label[for=\"'+name+'\"]')).click();
+ }
+
+ toggleSelectAll() {
+ return element.all(by.css('label[for="select-deselect-all"]')).click();
+ }
+
+ toggleSort(name: string) {
+ element.all(by.linkText(name)).click();
+ }
+
+ waitForElement ( _element ) {
+ var EC = protractor.ExpectedConditions;
+ return browser.wait(EC.visibilityOf(_element));
+ };
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/e2e/tsconfig.json
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/e2e/tsconfig.json b/metron-interface/metron-config/e2e/tsconfig.json
new file mode 100644
index 0000000..656bdb1
--- /dev/null
+++ b/metron-interface/metron-config/e2e/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "declaration": false,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "module": "commonjs",
+ "moduleResolution": "node",
+ "outDir": "../dist/out-tsc-e2e",
+ "sourceMap": true,
+ "target": "es5",
+ "typeRoots": [
+ "../node_modules/@types"
+ ]
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/e2e/use-cases/sensor-config-single-parser.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/e2e/use-cases/sensor-config-single-parser.e2e-spec.ts b/metron-interface/metron-config/e2e/use-cases/sensor-config-single-parser.e2e-spec.ts
new file mode 100644
index 0000000..dd1d71f
--- /dev/null
+++ b/metron-interface/metron-config/e2e/use-cases/sensor-config-single-parser.e2e-spec.ts
@@ -0,0 +1,159 @@
+/**
+ * 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 {LoginPage} from '../login/login.po';
+import {SensorConfigPage} from '../sensor-config/sensor-config.po';
+import {SensorListPage} from '../sensor-list/sensor-list.po';
+import {SensorDetailsPage} from '../sensor-config-readonly/sensor-config-readonly.po';
+
+describe('Sensor Config for parser e2e1', function() {
+ let page = new SensorConfigPage();
+ let sensorListPage = new SensorListPage();
+ let sensorDetailsPage = new SensorDetailsPage();
+ let loginPage = new LoginPage();
+
+ beforeAll(() => {
+ loginPage.login();
+ });
+
+ afterAll(() => {
+ loginPage.logout();
+ });
+
+ it('should add e2e parser', (done) => {
+ let expectedGrokResponse = [
+ 'action TCP_MISS',
+ 'bytes 337891',
+ 'code 200',
+ 'elapsed 415',
+ 'ip_dst_addr 207.109.73.154',
+ 'ip_src_addr 127.0.0.1',
+ 'method GET',
+ 'original_string 1467011157.401 415 127.0.0.1 TCP_MISS/200 337891 GET http://www.aliexpress.com/af/shoes.html? - DIRECT/207.109.73.154 text/html', 'timestamp 1467011157.401', 'url http://www.aliexpress.com/af/shoes.html?' ];
+ let grokStatement = '%{NUMBER:timestamp} %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}\/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}\/%{WORD:UNWANTED}';
+ let sampleMessage = '1467011157.401 415 127.0.0.1 TCP_MISS/200 337891 GET http://www.aliexpress.com/af/shoes.html? - DIRECT/207.109.73.154 text/html';
+ let expectedFieldSchemaResponse = [ 'elapsed', 'code', 'ip_dst_addr', 'original_string', 'method', 'bytes', 'action', 'ip_src_addr', 'url', 'timestamp' ];
+
+ page.clickAddButton();
+ page.setParserName('e2e1');
+ page.setParserType('Grok');
+
+ page.clickGrokStatement();
+ page.setSampleMessage('sensor-grok', sampleMessage);
+ page.setGrokStatement(grokStatement);
+ page.testGrokStatement();
+ expect(page.getGrokResponse()).toEqual(expectedGrokResponse);
+ page.saveGrokStatement();
+ expect(page.getGrokStatementFromMainPane()).toEqual([grokStatement]);
+ page.setAdvancedConfig('grokPath', 'target/patterns/e2e1');
+
+
+ page.clickSchema();
+ page.setSampleMessage('sensor-field-schema', '1467011157.401 415 127.0.0.1 TCP_MISS/200 337891 GET http://www.aliexpress.com/af/shoes.html? - DIRECT/207.109.73.154 text/html');
+ page.clickSchema();
+ expect(page.getFieldSchemaValues()).toEqual(expectedFieldSchemaResponse);
+ page.setSchemaConfig('elapsed', ['TRIM', 'TO_INTEGER'], ['geo', 'host'], ['malicious_ip']);
+ expect(page.getTransformText()).toEqual(['TO_INTEGER(TRIM(elapsed))']);
+ page.saveFieldSchemaConfig();
+ page.setSchemaConfig('ip_dst_addr', [], ['geo'], ['malicious_ip']);
+ page.saveFieldSchemaConfig();
+ page.closeSchemaPane();
+ expect(page.getFieldSchemaSummary()).toEqual( [ 'TRANSFORMATIONS 1', 'ENRICHMENTS 3', 'THREAT INTEL 2' ]);
+
+ page.clickThreatTriage();
+ page.clickAddThreatTriageRule();
+ page.setThreatTriageRule('IN_SUBNET(ip_dst_addr, \'192.168.0.0/24\')');
+ page.saveThreatTriageRule();
+ expect(page.getThreatTrigaeRule()).toEqual([ 'IN_SUBNET(ip_dst_addr, \'192.168.0.0/24\')']);
+ page.closeThreatTriagePane();
+ expect(page.getThreatTriageSummary()).toEqual([ 'RULES 1' ]);
+
+ page.saveParser();
+
+ done();
+
+ });
+
+ it('should have all the config for e2e parser', (done) => {
+ let grokStatement = '%{NUMBER:timestamp} %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}/%{WORD:UNWANTED}';
+ let expectedFormData = {
+ title: 'e2e1',
+ parserName: 'e2e1',
+ parserType: 'org.apache.metron.parsers.GrokParser',
+ grokStatement: grokStatement,
+ fieldSchemaSummary: [ 'TRANSFORMATIONS 1', 'ENRICHMENTS 3', 'THREAT INTEL 2' ],
+ threatTriageSummary: [ 'RULES 1' ],
+ indexName: 'e2e1',
+ batchSize: '1',
+ advancedConfig: [ 'patternLabel', 'E2E1', 'grokPath', 'target/patterns/e2e1', 'enter field', 'enter value' ]
+ };
+ expect(sensorListPage.openEditPane('e2e1')).toEqual('http://localhost:4200/sensors(dialog:sensors-config/e2e1)');
+ expect(page.getFormData()).toEqual(expectedFormData);
+
+ page.closeMainPane().then(() => {
+ done();
+ });
+ })
+
+ it('should have all the config details for e2e parser', () => {
+ let parserNotRunnigExpected = ['',
+ 'PARSERS\nGrok',
+ 'LAST UPDATED\n-',
+ 'LAST EDITOR\n-',
+ 'STATE\n-',
+ 'ORIGINATOR\n-',
+ 'CREATION DATE\n-',
+ ' ',
+ 'STORM\nStopped',
+ 'LATENCY\n-',
+ 'THROUGHPUT\n-',
+ 'EMITTED(10 MIN)\n-',
+ 'ACKED(10 MIN)\n-',
+ ' ',
+ 'KAFKA\nNo Kafka Topic',
+ 'PARTITONS\n-',
+ 'REPLICATION FACTOR\n-',
+ ''];
+ let grokStatement = '%{NUMBER:timestamp} %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}\/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}\/%{WORD:UNWANTED}';
+
+ expect(sensorDetailsPage.navigateTo('e2e1')).toEqual('http://localhost:4200/sensors(dialog:sensors-readonly/e2e1)');
+ expect(sensorDetailsPage.getTitle()).toEqual("e2e1");
+ expect(sensorDetailsPage.getParserConfig()).toEqual(parserNotRunnigExpected);
+ expect(sensorDetailsPage.getButtons()).toEqual([ 'EDIT', 'START', 'Delete' ]);
+ expect(sensorDetailsPage.getGrokStatement()).toEqual(grokStatement);
+ expect(sensorDetailsPage.getSchemaSummary()).toEqual(['Transforms\nelapsed']);
+ sensorDetailsPage.clickToggleShowMoreLess('show more', 1);
+ expect(sensorDetailsPage.getSchemaFullSummary()).toEqual([ 'Transforms\nelapsed\nTO_INTEGER(TRIM(elapsed))' ]);
+ sensorDetailsPage.clickToggleShowMoreLess('show less', 0);
+ expect(sensorDetailsPage.getThreatTriageSummary()).toEqual(['AGGREGATOR\nMAX\nIN_SUBNET(ip_dst_addr, \'192.168.0.0/24\')\nshow more']);
+ sensorDetailsPage.clickToggleShowMoreLess('show more', 2);
+ expect(sensorDetailsPage.getThreatTriageSummary()).toEqual(['AGGREGATOR\nMAX\nNAME\nSCORE\nIN_SUBNET(ip_dst_addr, \'192.168.0.0/24\')\n0\nshow less']);
+ sensorDetailsPage.clickToggleShowMoreLess('show less', 0);
+
+ sensorDetailsPage.closePane('e2e1');
+
+ })
+
+
+ it('should delete the e2e parser', (done) => {
+ expect(sensorListPage.getParserCount()).toEqual(8);
+ expect(sensorListPage.deleteParser('e2e1')).toEqual(true);
+ expect(sensorListPage.getParserCount()).toEqual(7);
+ done();
+ })
+
+});
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/e2e/utils/e2e_util.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/e2e/utils/e2e_util.ts b/metron-interface/metron-config/e2e/utils/e2e_util.ts
new file mode 100644
index 0000000..7ca9960
--- /dev/null
+++ b/metron-interface/metron-config/e2e/utils/e2e_util.ts
@@ -0,0 +1,30 @@
+import { browser, protractor } from 'protractor/globals';
+
+export function changeURL(url: string) {
+ return browser.get(url).then(() => {
+ return browser.getCurrentUrl().then((newURL) => {
+ return newURL;
+ })
+ })
+}
+
+export function waitForElementInVisibility (_element ) {
+ var EC = protractor.ExpectedConditions;
+ return browser.wait(EC.invisibilityOf(_element));
+}
+
+export function waitForElementPresence (_element ) {
+ var EC = protractor.ExpectedConditions;
+ return browser.wait(EC.presenceOf(_element));
+}
+
+export function waitForElementVisibility (_element ) {
+ var EC = protractor.ExpectedConditions;
+ return browser.wait(EC.visibilityOf(_element));
+}
+
+export function waitForStalenessOf (_element ) {
+ var EC = protractor.ExpectedConditions;
+ return browser.wait(EC.stalenessOf(_element));
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/karma.conf.js
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/karma.conf.js b/metron-interface/metron-config/karma.conf.js
new file mode 100644
index 0000000..6023550
--- /dev/null
+++ b/metron-interface/metron-config/karma.conf.js
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/0.13/config/configuration-file.html
+
+module.exports = function (config) {
+ config.set({
+ basePath: '',
+ frameworks: ['jasmine', 'angular-cli'],
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-chrome-launcher'),
+ require('karma-remap-istanbul'),
+ require('karma-phantomjs-launcher'),
+ require('angular-cli/plugins/karma')
+ ],
+ mime: {
+ 'text/x-typescript': ['ts','tsx']
+ },
+ files: [
+ { pattern: './src/test.ts', watched: false },
+ { pattern: './src/assets/**', watched: false, included: false, nocache: false, served: true }
+ ],
+ proxies: {
+ '/assets': '/base/src/assets/'
+ },
+ preprocessors: {
+ './src/test.ts': ['angular-cli']
+ },
+ remapIstanbulReporter: {
+ reports: {
+ html: 'coverage',
+ lcovonly: './coverage/coverage.lcov'
+ }
+ },
+ angularCli: {
+ config: './angular-cli.json',
+ environment: 'dev'
+ },
+ reporters: ['progress', 'karma-remap-istanbul'],
+ port: 9876,
+ colors: true,
+ logLevel: config.LOG_INFO,
+ autoWatch: true,
+ browsers: ['PhantomJS'],
+ singleRun: false
+ });
+};
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/package.json
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/package.json b/metron-interface/metron-config/package.json
new file mode 100644
index 0000000..924d916
--- /dev/null
+++ b/metron-interface/metron-config/package.json
@@ -0,0 +1,65 @@
+{
+ "name": "metron-management-ui",
+ "version": "0.3.1",
+ "license": "MIT",
+ "config": {
+ "node_ace": "node_modules/ace-builds/src-min-noconflict/"
+ },
+ "angular-cli": {},
+ "scripts": {
+ "build": "./node_modules/angular-cli/bin/ng build -prod",
+ "start": "ng serve",
+ "lint": "tslint \"src/**/*.ts\"",
+ "test": "./node_modules/angular-cli/bin/ng test --watch=false",
+ "pree2e": "webdriver-manager update",
+ "e2e": "./node_modules/.bin/protractor",
+ "e2e-all": "./node_modules/.bin/protractor --suite=all",
+ "copy-ace": "cp -f $npm_package_config_node_ace/ext-language_tools.js $npm_package_config_node_ace/mode-json.js $npm_package_config_node_ace/theme-monokai.js $npm_package_config_node_ace/worker-json.js src/assets/ace",
+ "copy-ace-snippets": "cp -f $npm_package_config_node_ace/snippets/text.js $npm_package_config_node_ace/snippets/json.js src/assets/ace/snippets",
+ "postinstall": "npm run copy-ace & npm run copy-ace-snippets"
+ },
+ "private": true,
+ "dependencies": {
+ "@types/ace": "0.0.32",
+ "@types/bootstrap": "^3.3.32",
+ "@types/jasmine": "2.2.30",
+ "@types/jquery": "^2.0.32",
+ "@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",
+ "font-awesome": "^4.6.3",
+ "jquery": "^2.2.4",
+ "rxjs": "5.0.0-beta.12",
+ "tether": "^1.3.4",
+ "ts-helpers": "^1.1.1",
+ "zone.js": "^0.6.23"
+ },
+ "devDependencies": {
+ "angular-cli": "1.0.0-beta.15",
+ "buffer-shims": "^1.0.0",
+ "codelyzer": "~0.0.26",
+ "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.2.1",
+ "phantomjs-prebuilt": "^2.1.14",
+ "protractor": "4.0.5",
+ "ts-node": "1.2.1",
+ "tslint": "3.13.0",
+ "typescript": "~2.0.3"
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/pom.xml
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/pom.xml b/metron-interface/metron-config/pom.xml
new file mode 100644
index 0000000..97a7404
--- /dev/null
+++ b/metron-interface/metron-config/pom.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.metron</groupId>
+ <artifactId>metron-interface</artifactId>
+ <version>0.3.1</version>
+ </parent>
+ <artifactId>metron-config</artifactId>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <node.version>v6.2.0</node.version>
+ <npm.version>3.8.9</npm.version>
+ </properties>
+ <dependencies>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.eirslett</groupId>
+ <artifactId>frontend-maven-plugin</artifactId>
+ <version>1.3</version>
+ <configuration>
+ <workingDirectory>./</workingDirectory>
+ <nodeVersion>${node.version}</nodeVersion>
+ <npmVersion>${npm.version}</npmVersion>
+ <npmInheritsProxyConfigFromMaven>false</npmInheritsProxyConfigFromMaven>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>generate-resources</phase>
+ <id>install node and npm</id>
+ <goals>
+ <goal>install-node-and-npm</goal>
+ </goals>
+ </execution>
+ <execution>
+ <phase>generate-resources</phase>
+ <id>npm install</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <configuration>
+ <arguments>install</arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <phase>generate-resources</phase>
+ <id>ng build</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <configuration>
+ <arguments>run build</arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>npm test</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <phase>test</phase>
+ <configuration>
+ <arguments>test</arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>3.0.0</version>
+ <configuration>
+ <filesets>
+ <fileset>
+ <directory>coverage</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <fileset>
+ <directory>dist</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <fileset>
+ <directory>node</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <fileset>
+ <directory>node_modules</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ </filesets>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <descriptor>assembly.xml</descriptor>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id> <!-- this is used for inheritance merges -->
+ <phase>package</phase> <!-- bind to the packaging phase -->
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.5.0</version>
+ <executions>
+ <execution>
+ <id>prepend-license-header</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>./scripts/prepend_license_header.sh</executable>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/protractor.conf.js
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/protractor.conf.js b/metron-interface/metron-config/protractor.conf.js
new file mode 100644
index 0000000..7289122
--- /dev/null
+++ b/metron-interface/metron-config/protractor.conf.js
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+
+// Protractor configuration file, see link for more information
+// https://github.com/angular/protractor/blob/master/docs/referenceConf.js
+
+/*global jasmine */
+var SpecReporter = require('jasmine-spec-reporter');
+
+exports.config = {
+ allScriptsTimeout: 11000,
+ suites: {
+ all: [
+ './e2e/login/login.e2e-spec.ts',
+ './e2e/app/app.e2e-spec.ts',
+ './e2e/sensor-list/sensor-list.e2e-spec.ts',
+ './e2e/sensor-list/sensor-list-parser-actions.e2e-spec.ts',
+ './e2e/use-cases/sensor-config-single-parser.e2e-spec.ts',
+ './e2e/sensor-config-readonly/sensor-config-readonly.e2e-spec.ts',
+ ]
+ },
+ specs: [
+ './e2e/login/login.e2e-spec.ts',
+ './e2e/app/app.e2e-spec.ts',
+ './e2e/sensor-list/sensor-list.e2e-spec.ts',
+ './e2e/use-cases/sensor-config-single-parser.e2e-spec.ts'
+ ],
+ capabilities: {
+ 'browserName': 'chrome'
+ },
+ directConnect: true,
+ baseUrl: 'http://localhost:4200',
+ framework: 'jasmine',
+ jasmineNodeOpts: {
+ showColors: true,
+ defaultTimeoutInterval: 30000,
+ print: function() {}
+ },
+ useAllAngular2AppRoots: true,
+ rootElement: 'metron-config-root',
+ beforeLaunch: function() {
+ require('ts-node').register({
+ project: 'e2e'
+ });
+ },
+ onPrepare: function() {
+ jasmine.getEnv().addReporter(new SpecReporter());
+ }
+};
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/proxy.conf.json
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/proxy.conf.json b/metron-interface/metron-config/proxy.conf.json
new file mode 100644
index 0000000..29466cc
--- /dev/null
+++ b/metron-interface/metron-config/proxy.conf.json
@@ -0,0 +1,10 @@
+{
+ "/api/v1": {
+ "target": "http://localhost:8080",
+ "secure": false
+ },
+ "/logout": {
+ "target": "http://localhost:8080",
+ "secure": false
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/scripts/package.json
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/scripts/package.json b/metron-interface/metron-config/scripts/package.json
new file mode 100644
index 0000000..28f9f3b
--- /dev/null
+++ b/metron-interface/metron-config/scripts/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "metron-management-ui-web-server",
+ "version": "0.3.1",
+ "description": "Metron management ui web server",
+ "main": "server.js",
+ "dependencies": {
+ "compression": "1.6.2",
+ "express": "4.15.2",
+ "http-proxy-middleware": "0.17.4",
+ "optimist": "0.6.1",
+ "serve-favicon": "2.4.2",
+ "serve-static": "1.12.1"
+ },
+ "devDependencies": {},
+ "scripts": {
+ "start": "node server.js"
+ },
+ "private": true,
+ "author": "",
+ "license": "MIT"
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/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
new file mode 100755
index 0000000..1957cd6
--- /dev/null
+++ b/metron-interface/metron-config/scripts/prepend_license_header.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+#
+# 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.
+#
+LICENSE_HEADER="/**
+ * 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.
+ */
+ "
+for file in ./dist/*.js
+do
+ if !(grep -Fxq "$LICENSE_HEADER" $file)
+ then
+ echo "$LICENSE_HEADER$(cat $file)" > $file
+ fi
+done
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/scripts/server.js
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/scripts/server.js b/metron-interface/metron-config/scripts/server.js
new file mode 100644
index 0000000..7fb1728
--- /dev/null
+++ b/metron-interface/metron-config/scripts/server.js
@@ -0,0 +1,82 @@
+#!/usr/bin/env node
+/**
+ * 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.
+ */
+
+'use strict';
+
+var os = require('os');
+var app = require('express')();
+var path = require('path');
+var compression = require('compression')
+var serveStatic = require('serve-static');
+var favicon = require('serve-favicon');
+var proxy = require('http-proxy-middleware');
+var argv = require('optimist')
+ .demand(['p', 'r'])
+ .alias('r', 'resturl')
+ .usage('Usage: server.js -p [port] -r [restUrl]')
+ .describe('p', 'Port to run metron management ui')
+ .describe('r', 'Url where metron rest application is available')
+ .argv;
+
+var port = argv.p;
+var metronUIAddress = '';
+var ifaces = os.networkInterfaces();
+var restUrl = argv.r || argv.resturl;
+var conf = {
+ "rest": {
+ "target": restUrl,
+ "secure": false
+ }
+};
+
+Object.keys(ifaces).forEach(function (dev) {
+ ifaces[dev].forEach(function (details) {
+ if (details.family === 'IPv4') {
+ metronUIAddress += '\n';
+ metronUIAddress += 'http://' + details.address + ':' + port;
+ }
+ });
+});
+
+function setCustomCacheControl (res, path) {
+ if (serveStatic.mime.lookup(path) === 'text/html') {
+ res.setHeader('Cache-Control', 'public, max-age=10')
+ }
+ res.setHeader("Expires", new Date(Date.now() + 2592000000).toUTCString());
+}
+
+app.use(compression());
+
+app.use('/api/v1', proxy(conf.rest));
+app.use('/logout', proxy(conf.rest));
+
+app.use(favicon(path.join(__dirname, '../management-ui/favicon.ico')));
+
+app.use(serveStatic(path.join(__dirname, '../management-ui'), {
+ maxAge: '1d',
+ setHeaders: setCustomCacheControl
+}));
+
+app.get('*', function(req, res){
+ res.sendFile(path.resolve('../management-ui/index.html'));
+});
+
+app.listen(port, function(){
+ console.log("Metron server listening on " + metronUIAddress);
+});
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/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
new file mode 100755
index 0000000..05ba601
--- /dev/null
+++ b/metron-interface/metron-config/scripts/start_dev.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+#
+SCRIPTS_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+$SCRIPTS_ROOT/../node_modules/angular-cli/bin/ng serve --proxy-config proxy.conf.json
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/scripts/start_management_ui.sh
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/scripts/start_management_ui.sh b/metron-interface/metron-config/scripts/start_management_ui.sh
new file mode 100755
index 0000000..cfd055b
--- /dev/null
+++ b/metron-interface/metron-config/scripts/start_management_ui.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# 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.
+#
+
+METRON_VERSION=${project.version}
+METRON_HOME=/usr/metron/$METRON_VERSION
+
+cd $METRON_HOME/web/expressjs
+npm install
+node $METRON_HOME/web/expressjs/server.js $*
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/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
new file mode 100644
index 0000000..f889c7a
--- /dev/null
+++ b/metron-interface/metron-config/src/app/_main.scss
@@ -0,0 +1,112 @@
+/**
+ * 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/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/_variables.scss
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/_variables.scss b/metron-interface/metron-config/src/app/_variables.scss
new file mode 100644
index 0000000..000a126
--- /dev/null
+++ b/metron-interface/metron-config/src/app/_variables.scss
@@ -0,0 +1,71 @@
+/**
+ * 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.
+ */
+$gray-dark: #232323;
+$gray-light: #333333;
+$gray-border: #4d4d4d;
+$tundora: #404040;
+$text-color-white: #999999;
+$nav-active-color: #32abe2;
+$nav-active-text-color: #ffffff;
+$table-cell-text-color: #a7a9ac;
+$form-label: #999999;
+$field-background: #2e2e2e;
+$form-field-text-color: #bdbdbd;
+$field-button-color: #27aae1;
+$edit-background: #0b4451;
+$edit-background-border: #17596d;
+$title-subscript-color: #666666;
+$form-field-separator-color: #404040;
+$form-button-border: #006ea0;
+$form-input-background: #2d2d2d;
+$warning-color: #C0661D;
+$black: #000000;
+$login-label: #606060;
+$silver-color: #BDBDBD;
+$dusty-grey: #9b9a9a;
+$ocean-green: #3AA570;
+$edit-child-background: #083b44;
+$edit-child-highlight: #07333a;
+$table-selection: $gray-light;
+$table-selection-lr-border: #2F2F2F;
+$table-selection-tb-border: #3E3E3E;
+
+$dialog-1x-width: 320px;
+$dialog-2x-width: 640px;
+$dialog-4x-width: 1380px;
+$slider-left-padding: 25px;
+
+$button-bar-height: 70px;
+
+@mixin transform($transforms) {
+ -moz-transform: $transforms;
+ -o-transform: $transforms;
+ -ms-transform: $transforms;
+ -webkit-transform: $transforms;
+ transform: $transforms;
+}
+
+@mixin place-holder-text
+{
+ font-family: Roboto;
+ font-size: 12px;
+ color:#bdbdbd !important;
+ font-weight: 300 !important;
+ text-align: center !important;
+ font-style: italic !important;
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/app.component.html
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/app.component.html b/metron-interface/metron-config/src/app/app.component.html
new file mode 100644
index 0000000..f2f5c46
--- /dev/null
+++ b/metron-interface/metron-config/src/app/app.component.html
@@ -0,0 +1,25 @@
+<!--
+ 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.
+ -->
+<div class="container-fluid header" *ngIf="loggedIn">
+ <metron-config-navbar></metron-config-navbar>
+</div>
+<div [ngClass]="{'container-fluid body-fill px-0': loggedIn, 'fill': !loggedIn}">
+ <div [ngClass]="{'card-group ': loggedIn}" class="fill">
+ <div *ngIf="loggedIn" class="card fill navigation" ><metron-config-vertical-navbar></metron-config-vertical-navbar></div>
+ <div [ngClass]="{'card fill content px-0 ' : loggedIn , 'fill': !loggedIn}"><router-outlet></router-outlet></div>
+ </div>
+</div>
+<router-outlet name="dialog" ></router-outlet>
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/app.component.scss
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/app.component.scss b/metron-interface/metron-config/src/app/app.component.scss
new file mode 100644
index 0000000..104b980
--- /dev/null
+++ b/metron-interface/metron-config/src/app/app.component.scss
@@ -0,0 +1,34 @@
+/**
+ * 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 "_variables.scss";
+
+.navigation{
+
+ background-color: $gray-light;
+ border-right: solid 1px #4d4d4d;
+ border-top: solid 1px #4d4d4d;
+ border-bottom: solid 1px #4d4d4d;
+ bottom: 0px;
+ padding-left: 0px;
+ width: 240px;
+}
+
+.content{
+ background: $gray-dark;
+ border: none;
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/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
new file mode 100644
index 0000000..6ae511f
--- /dev/null
+++ b/metron-interface/metron-config/src/app/app.component.spec.ts
@@ -0,0 +1,89 @@
+/**
+ * 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 {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';
+
+class MockAuthenticationService extends AuthenticationService {
+
+ constructor(private http2: Http, private router2: Router, @Inject(APP_CONFIG) private config2: IAppConfig) {
+ super(http2, router2, config2);
+ }
+
+ public checkAuthentication() {
+ }
+
+ public getCurrentUser(options: RequestOptions): Observable<Response> {
+ return Observable.create(observer => {
+ observer.next(new Response(new ResponseOptions({body: 'test'})));
+ observer.complete();
+ });
+ }
+}
+
+class MockRouter {
+ 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}
+ ]
+ }).compileComponents()
+ .then(() => {
+ fixture = TestBed.createComponent(AppComponent);
+ comp = fixture.componentInstance;
+ authenticationService = fixture.debugElement.injector.get(AuthenticationService);
+ });
+ }));
+
+ it('should create the app', () => {
+ expect(comp).toBeTruthy();
+ });
+
+ it('should return true/false from loginevent and loggedIn should be set', () => {
+
+ expect(comp.loggedIn).toEqual(false);
+ authenticationService.onLoginEvent.emit(true);
+ expect(comp.loggedIn).toEqual(true);
+ authenticationService.onLoginEvent.emit(false);
+ expect(comp.loggedIn).toEqual(false);
+
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/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
new file mode 100644
index 0000000..9bfe3d2
--- /dev/null
+++ b/metron-interface/metron-config/src/app/app.component.ts
@@ -0,0 +1,39 @@
+/**
+ * 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 {Component} from '@angular/core';
+import './rxjs-operators';
+import {AuthenticationService} from './service/authentication.service';
+
+
+@Component({
+ selector: 'metron-config-root',
+ templateUrl: 'app.component.html',
+ styleUrls: ['app.component.scss']
+})
+
+export class AppComponent {
+
+ loggedIn: boolean = false;
+
+ constructor(private authService: AuthenticationService) {
+ this.authService.onLoginEvent.subscribe(result => {
+ this.loggedIn = result;
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/app.config.interface.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/app.config.interface.ts b/metron-interface/metron-config/src/app/app.config.interface.ts
new file mode 100644
index 0000000..de9d7bd
--- /dev/null
+++ b/metron-interface/metron-config/src/app/app.config.interface.ts
@@ -0,0 +1,3 @@
+export interface IAppConfig {
+ apiEndpoint: string;
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/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
new file mode 100644
index 0000000..af4b360
--- /dev/null
+++ b/metron-interface/metron-config/src/app/app.config.ts
@@ -0,0 +1,8 @@
+import { OpaqueToken } from '@angular/core';
+import {IAppConfig} from './app.config.interface';
+
+export let APP_CONFIG = new OpaqueToken('app.config');
+
+export const METRON_REST_CONFIG: IAppConfig = {
+ apiEndpoint: '/api/v1'
+};
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/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
new file mode 100644
index 0000000..25e4acd
--- /dev/null
+++ b/metron-interface/metron-config/src/app/app.module.ts
@@ -0,0 +1,59 @@
+/**
+ * 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 {NgModule} from '@angular/core';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import {BrowserModule} from '@angular/platform-browser';
+import {HttpModule} from '@angular/http';
+import {AppComponent} from './app.component';
+import {SensorParserConfigService} from './service/sensor-parser-config.service';
+import {KafkaService} from './service/kafka.service';
+import {GrokValidationService} from './service/grok-validation.service';
+import {StellarService} from './service/stellar.service';
+import {MetronAlerts} from './shared/metron-alerts';
+import {LoginComponent} from './login/login.component';
+import {NavbarComponent} from './navbar/navbar.component';
+import {VerticalNavbarComponent} from './verticalnavbar/verticalnavbar.component';
+import {routing, appRoutingProviders} from './app.routes';
+import {AuthenticationService} from './service/authentication.service';
+import {AuthGuard} from './shared/auth-guard';
+import {LoginGuard} from './shared/login-guard';
+import {SensorParserConfigModule} from './sensors/sensor-parser-config/sensor-parser-config.module';
+import {SensorParserConfigReadonlyModule} from './sensors/sensor-parser-config-readonly/sensor-parser-config-readonly.module';
+import {SensorParserListModule} from './sensors/sensor-parser-list/sensor-parser-list.module';
+import {MetronDialogBox} from './shared/metron-dialog-box';
+import {GeneralSettingsModule} from './general-settings/general-settings.module';
+import {SensorEnrichmentConfigService} from './service/sensor-enrichment-config.service';
+import {GlobalConfigService} from './service/global-config.service';
+import {APP_CONFIG, METRON_REST_CONFIG} from './app.config';
+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';
+
+
+@NgModule({
+ imports: [ BrowserModule, routing, FormsModule, ReactiveFormsModule, HttpModule, SensorParserListModule,
+ SensorParserConfigModule, SensorParserConfigReadonlyModule, GeneralSettingsModule ],
+ declarations: [ AppComponent, LoginComponent, 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 }],
+ bootstrap: [ AppComponent ]
+})
+export class AppModule { }
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/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
new file mode 100644
index 0000000..73db2fd
--- /dev/null
+++ b/metron-interface/metron-config/src/app/app.routes.ts
@@ -0,0 +1,33 @@
+/**
+ * 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 {ModuleWithProviders} from '@angular/core';
+import {Routes, RouterModule} from '@angular/router';
+import {AuthGuard} from './shared/auth-guard';
+import {LoginGuard} from './shared/login-guard';
+
+export const routes: Routes = [
+ { path: '', redirectTo: 'sensors', canActivate: [AuthGuard], pathMatch: 'full'},
+ { path: 'login', loadChildren: 'app/login/login.module#LoginModule', canActivate: [LoginGuard] },
+ { path: 'sensors', loadChildren: 'app/sensors/sensor-parser-list/sensor-parser-list.module#SensorParserListModule',
+ canActivate: [AuthGuard] },
+];
+
+export const appRoutingProviders: any[] = [
+];
+
+export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/environment.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/environment.ts b/metron-interface/metron-config/src/app/environment.ts
new file mode 100644
index 0000000..1c4a54d
--- /dev/null
+++ b/metron-interface/metron-config/src/app/environment.ts
@@ -0,0 +1,24 @@
+/**
+ * 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.
+ */
+// The file for the current environment will overwrite this one during build
+// Different environments can be found in config/environment.{dev|prod}.ts
+// The build system defaults to the dev environment
+
+export const environment = {
+ production: false
+};
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/general-settings/general-settings.component.html
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/general-settings/general-settings.component.html b/metron-interface/metron-config/src/app/general-settings/general-settings.component.html
new file mode 100644
index 0000000..2c16f95
--- /dev/null
+++ b/metron-interface/metron-config/src/app/general-settings/general-settings.component.html
@@ -0,0 +1,57 @@
+<!--
+ 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.
+ -->
+<div >
+ <div class="container-fluid details-pane-padding">
+ <div class="row mb-1 mx-0">
+ <div class="metron-title"> General Settings </div>
+ </div>
+
+ <div class="row mx-0">
+ <form>
+ <div class="col-md-4 pl-0">
+ <div class="section px-1 py-1">
+ <label class="h6"> <strong> Elasticsearch </strong> </label>
+ <div class="form-group">
+ <label>INDEX DATE FORMAT</label>
+ <input type="text" class="form-control" name="es.date.format" [(ngModel)]="globalConfig['es.date.format']">
+ </div>
+
+ </div>
+
+ <div class="section px-1 py-1 mt-1">
+ <label class="h6"> <strong> Validation </strong> </label>
+
+ <div class="form-group">
+ <label>FIELD</label>
+ <metron-config-ace-editor [(ngModel)]="fieldValidations" [ngModelOptions]="{standalone: true}" [type]="'JSON'" [placeHolder]="'Enter Field Validations'"> </metron-config-ace-editor>
+ </div>
+
+ </div>
+
+ </div>
+ </form>
+ </div>
+
+ </div>
+
+ <div class="container-fluid metron-button-bar-settings details-pane-padding" >
+ <div class="row px-1 py-1">
+ <button type="submit" class="btn btn-primary" (click)="onSave()">SAVE</button>
+ <button class="btn form-enable-disable-button" (click)="onCancel()">CANCEL</button>
+ </div>
+ </div>
+
+</div>
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/general-settings/general-settings.component.scss
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/general-settings/general-settings.component.scss b/metron-interface/metron-config/src/app/general-settings/general-settings.component.scss
new file mode 100644
index 0000000..8bf6d89
--- /dev/null
+++ b/metron-interface/metron-config/src/app/general-settings/general-settings.component.scss
@@ -0,0 +1,41 @@
+/**
+ * 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 "../_variables.scss";
+
+.section
+{
+ border: solid 1px $gray-border;
+ background-color: $gray-light;
+}
+
+.metron-button-bar-settings
+{
+ bottom: 0;
+ z-index: 10;
+ width: 100%;
+ position: fixed;
+ border-right: solid 1px $gray-border;
+ border-bottom: solid 1px $gray-border;
+ border-top: solid 1px $gray-border;
+ background: $gray-dark;
+}
+
+textarea
+{
+ height: auto;
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/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
new file mode 100644
index 0000000..51fc709
--- /dev/null
+++ b/metron-interface/metron-config/src/app/general-settings/general-settings.component.spec.ts
@@ -0,0 +1,161 @@
+/**
+ * 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 {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';
+
+class MockGlobalConfigService extends GlobalConfigService {
+ _config: any = {};
+ _postSuccess: boolean = true;
+
+ constructor(private http2: Http, @Inject(APP_CONFIG) private config2: IAppConfig) {
+ super(http2, config2);
+ }
+
+ public post(globalConfig: {}): Observable<{}> {
+ if (this._postSuccess) {
+ return Observable.create(observer => {
+ observer.next(globalConfig);
+ observer.complete();
+ });
+ }
+
+ return Observable.throw('Error');
+ }
+
+ public get(): Observable<{}> {
+ return Observable.create(observer => {
+ observer.next(this._config);
+ observer.complete();
+ });
+ }
+}
+
+describe('GeneralSettingsComponent', () => {
+
+ let metronAlerts: MetronAlerts;
+ let metronDialogBox: MetronDialogBox;
+ let component: GeneralSettingsComponent;
+ let globalConfigService: MockGlobalConfigService;
+ let fixture: ComponentFixture<GeneralSettingsComponent>;
+ let config = {
+ 'solr.collection': 'metron',
+ 'storm.indexingWorkers': 1,
+ 'storm.indexingExecutors': 2,
+ 'hdfs.boltBatchSize': 5000,
+ 'hdfs.boltFieldDelimiter': '|',
+ 'hdfs.boltFileRotationSize': 5,
+ '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.requestRequiredAcks': 1,
+ 'solrWriter.indexName': 'alfaalfa',
+ 'solrWriter.shards': 1,
+ 'solrWriter.replicationFactor': 1,
+ 'solrWriter.batchSize': 50,
+ 'fieldValidations': {'field': 'validation'}
+ };
+
+ beforeEach(async(() => {
+
+ TestBed.configureTestingModule({
+ imports: [GeneralSettingsModule],
+ providers: [
+ {provide: Http},
+ MetronAlerts,
+ MetronDialogBox,
+ {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);
+ });
+
+ }));
+
+ it('can instantiate GeneralSettingsComponent', async(() => {
+ expect(component instanceof GeneralSettingsComponent).toBe(true);
+ }));
+
+ it('should load global config', async(() => {
+ globalConfigService._config = config;
+ component.ngOnInit();
+
+ expect(component.globalConfig).toEqual(globalConfigService._config);
+ }));
+
+ it('should save global config', async(() => {
+ globalConfigService._config = config;
+ component.ngOnInit();
+ fixture.detectChanges();
+ spyOn(metronAlerts, 'showSuccessMessage');
+ spyOn(metronAlerts, 'showErrorMessage');
+
+ component.onSave();
+ expect(metronAlerts.showSuccessMessage).toHaveBeenCalledWith('Saved Global Settings');
+
+ globalConfigService._postSuccess = false;
+
+ component.onSave();
+ 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 ?';
+
+ spyOn(component, 'ngOnInit');
+ spyOn(metronDialogBox, 'showConfirmationMessage').and.callFake(function() {
+ return Observable.create(observer => {
+ observer.next(dialogReturnTrue);
+ observer.complete();
+ });
+ });
+
+ component.onCancel();
+
+ expect(component.ngOnInit).toHaveBeenCalled();
+ expect(component.ngOnInit['calls'].count()).toEqual(1);
+ expect(metronDialogBox.showConfirmationMessage['calls'].count()).toEqual(1);
+ 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/incubator-metron/blob/1ef8cd8f/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
new file mode 100644
index 0000000..11d4cad
--- /dev/null
+++ b/metron-interface/metron-config/src/app/general-settings/general-settings.component.ts
@@ -0,0 +1,72 @@
+/**
+ * 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 { 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';
+
+@Component({
+ selector: 'metron-config-general-settings',
+ templateUrl: './general-settings.component.html',
+ styleUrls: ['./general-settings.component.scss']
+})
+export class GeneralSettingsComponent implements OnInit {
+
+ globalConfig: {} = {
+ 'es.date.format': '-'
+ };
+
+ private fieldValidations: string;
+
+ constructor(private globalConfigService: GlobalConfigService, private metronAlerts: MetronAlerts,
+ private metronDialog: MetronDialogBox) {}
+
+ ngOnInit() {
+ this.globalConfigService.get().subscribe((config: {}) => {
+ this.globalConfig = config;
+ if (!this.globalConfig['es.date.format']) {
+ this.globalConfig['es.date.format'] = '-';
+ }
+ if (this.globalConfig['fieldValidations']) {
+ this.fieldValidations = JSON.stringify(this.globalConfig['fieldValidations'], null, '\t');
+ }
+ });
+ }
+
+ onSave() {
+ if (this.fieldValidations && this.fieldValidations.length > 0) {
+ this.globalConfig['fieldValidations'] = JSON.parse(this.fieldValidations);
+ }
+ this.globalConfigService.post(this.globalConfig).subscribe(() => {
+ this.metronAlerts.showSuccessMessage('Saved 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();
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/general-settings/general-settings.module.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/general-settings/general-settings.module.ts b/metron-interface/metron-config/src/app/general-settings/general-settings.module.ts
new file mode 100644
index 0000000..83537b7
--- /dev/null
+++ b/metron-interface/metron-config/src/app/general-settings/general-settings.module.ts
@@ -0,0 +1,30 @@
+/**
+ * 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 {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import {routing} from './general-settings.routing';
+import {GeneralSettingsComponent} from './general-settings.component';
+import {AceEditorModule} from '../shared/ace-editor/ace-editor.module';
+
+
+@NgModule ({
+ imports: [ CommonModule, routing, FormsModule, ReactiveFormsModule, AceEditorModule ],
+ declarations: [ GeneralSettingsComponent ]
+})
+export class GeneralSettingsModule { }
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/general-settings/general-settings.routing.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/general-settings/general-settings.routing.ts b/metron-interface/metron-config/src/app/general-settings/general-settings.routing.ts
new file mode 100644
index 0000000..8aefa6b
--- /dev/null
+++ b/metron-interface/metron-config/src/app/general-settings/general-settings.routing.ts
@@ -0,0 +1,27 @@
+/**
+ * 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 { ModuleWithProviders } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+import {AuthGuard} from '../shared/auth-guard';
+import {GeneralSettingsComponent} from './general-settings.component';
+
+const routes: Routes = [
+ { path: 'general-settings', component: GeneralSettingsComponent, canActivate: [AuthGuard]}
+];
+
+export const routing: ModuleWithProviders = RouterModule.forChild(routes);
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/1ef8cd8f/metron-interface/metron-config/src/app/general-settings/index.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-config/src/app/general-settings/index.ts b/metron-interface/metron-config/src/app/general-settings/index.ts
new file mode 100644
index 0000000..6c04b7e
--- /dev/null
+++ b/metron-interface/metron-config/src/app/general-settings/index.ts
@@ -0,0 +1,18 @@
+/**
+ * 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.
+ */
+export * from './general-settings.component';