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';