http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/package.json ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/package.json b/metron-interface/metron-alerts/package.json new file mode 100644 index 0000000..dd249cc --- /dev/null +++ b/metron-interface/metron-alerts/package.json @@ -0,0 +1,60 @@ +{ + "name": "metron-alerts", + "version": "0.4.0", + "license": "Apache-2.0", + "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": "protractor" + }, + "private": true, + "dependencies": { + "@angular/common": "^4.0.0", + "@angular/compiler": "^4.0.0", + "@angular/core": "^4.0.0", + "@angular/forms": "^4.0.0", + "@angular/http": "^4.0.0", + "@angular/platform-browser": "^4.0.0", + "@angular/platform-browser-dynamic": "^4.0.0", + "@angular/router": "^4.0.0", + "ace-builds": "^1.2.6", + "bootstrap": "^4.0.0-alpha.6", + "core-js": "^2.4.1", + "font-awesome": "^4.7.0", + "rxjs": "^5.1.0", + "web-animations-js": "^2.2.2", + "zone.js": "^0.8.4" + }, + "devDependencies": { + "@angular/cli": "1.2.4", + "@angular/compiler-cli": "^4.0.0", + "@types/ace": "0.0.32", + "@types/jasmine": "2.5.38", + "@types/node": "~6.0.60", + "codelyzer": "~2.0.0", + "compression": "1.6.2", + "elementor": "^2.1.0", + "express": "4.15.2", + "http-proxy-middleware": "0.17.4", + "jasmine-core": "~2.5.2", + "jasmine-spec-reporter": "~3.2.0", + "karma": "~1.4.1", + "karma-chrome-launcher": "~2.0.0", + "karma-cli": "~1.0.1", + "karma-coverage-istanbul-reporter": "^0.2.0", + "karma-jasmine": "~1.1.0", + "karma-jasmine-html-reporter": "^0.2.2", + "node-sass": "^4.5.0", + "optimist": "0.6.1", + "protractor": "~5.1.0", + "serve-favicon": "2.4.2", + "serve-static": "1.12.1", + "ts-node": "~2.0.0", + "tslint": "~4.5.0", + "typescript": "~2.2.0" + } +}
http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/pom.xml ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/pom.xml b/metron-interface/metron-alerts/pom.xml new file mode 100644 index 0000000..fe06a3e --- /dev/null +++ b/metron-interface/metron-alerts/pom.xml @@ -0,0 +1,133 @@ +<?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.4.1</version> + </parent> + <artifactId>metron-alerts</artifactId> + <url>https://metron.apache.org/</url> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <node.version>v7.10.0</node.version> + <npm.version>4.2.0</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> + </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/metron/blob/7d554444/metron-interface/metron-alerts/protractor.conf.js ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/protractor.conf.js b/metron-interface/metron-alerts/protractor.conf.js new file mode 100644 index 0000000..082f1bf --- /dev/null +++ b/metron-interface/metron-alerts/protractor.conf.js @@ -0,0 +1,61 @@ +/** + * 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').SpecReporter; + +exports.config = { + allScriptsTimeout: 25000, + specs: [ + './e2e/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 50000, + print: function() {} + }, + useAllAngular2AppRoots: true, + rootElement: 'metron-alerts-root', + beforeLaunch: function() { + require('ts-node').register({ + project: 'e2e' + }); + }, + onPrepare: function() { + jasmine.getEnv().addReporter(new SpecReporter()); + setTimeout(function() { + browser.driver.executeScript(function() { + return { + width: window.screen.availWidth, + height: window.screen.availHeight + }; + }).then(function(result) { + browser.driver.manage().window().setSize(result.width, result.height); + }); + }); + } +}; http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/proxy.conf.json ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/proxy.conf.json b/metron-interface/metron-alerts/proxy.conf.json new file mode 100644 index 0000000..38f3e90 --- /dev/null +++ b/metron-interface/metron-alerts/proxy.conf.json @@ -0,0 +1,19 @@ +{ + "/api/v1": { + "target": "http://localhost:8080", + "secure": false + }, + "/logout": { + "target": "http://localhost:8080", + "secure": false + }, + "/search": { + "target": "http://node1:9200", + "pathRewrite": {"^/search" : ""}, + "secure": false + }, + "/_cluster": { + "target": "http://node1:9200", + "secure": false + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/scripts/alerts-server.js ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/scripts/alerts-server.js b/metron-interface/metron-alerts/scripts/alerts-server.js new file mode 100644 index 0000000..84504cc --- /dev/null +++ b/metron-interface/metron-alerts/scripts/alerts-server.js @@ -0,0 +1,90 @@ +#!/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 = { + "elastic": { + "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()); +} + +var rewriteSearchProxy = proxy({ + target: restUrl, + ws: true, + pathRewrite: { + '^/search' : '' + } +}); + +app.use(compression()); + +app.use('/search', rewriteSearchProxy); +app.use('/_cluster', proxy(conf.elastic)); + +app.use(favicon(path.join(__dirname, '../alerts-ui/favicon.ico'))); + +app.use(serveStatic(path.join(__dirname, '../alerts-ui'), { + maxAge: '1d', + setHeaders: setCustomCacheControl +})); + +app.get('*', function(req, res){ + res.sendFile(path.resolve('../alerts-ui/index.html')); +}); + +app.listen(port, function(){ + console.log("Metron alerts ui is listening on " + metronUIAddress); +}); http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/scripts/package.json ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/scripts/package.json b/metron-interface/metron-alerts/scripts/package.json new file mode 100644 index 0000000..d41da81 --- /dev/null +++ b/metron-interface/metron-alerts/scripts/package.json @@ -0,0 +1,21 @@ +{ + "name": "metron-alerts-ui-web-server", + "version": "0.4.0", + "description": "Metron alerts 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": "Apache 2.0" +} http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/scripts/prepend_license_header.sh ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/scripts/prepend_license_header.sh b/metron-interface/metron-alerts/scripts/prepend_license_header.sh new file mode 100755 index 0000000..b44d388 --- /dev/null +++ b/metron-interface/metron-alerts/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 http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/scripts/start-dev.sh ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/scripts/start-dev.sh b/metron-interface/metron-alerts/scripts/start-dev.sh new file mode 100755 index 0000000..5f6941a --- /dev/null +++ b/metron-interface/metron-alerts/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/metron/blob/7d554444/metron-interface/metron-alerts/scripts/start-server-for-e2e.sh ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/scripts/start-server-for-e2e.sh b/metron-interface/metron-alerts/scripts/start-server-for-e2e.sh new file mode 100755 index 0000000..0c97f88 --- /dev/null +++ b/metron-interface/metron-alerts/scripts/start-server-for-e2e.sh @@ -0,0 +1,20 @@ +#!/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 )" +cd $SCRIPTS_ROOT/.. && npm run build +node $SCRIPTS_ROOT/../alerts-server-e2e.js -p 4200 http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/scripts/start_alerts_ui.sh ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/scripts/start_alerts_ui.sh b/metron-interface/metron-alerts/scripts/start_alerts_ui.sh new file mode 100755 index 0000000..732ea08 --- /dev/null +++ b/metron-interface/metron-alerts/scripts/start_alerts_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/alerts-ui +npm install +node $METRON_HOME/web/alerts-ui/alerts-server.js $* http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/_variables.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/_variables.scss b/metron-interface/metron-alerts/src/_variables.scss new file mode 100644 index 0000000..8bb37b2 --- /dev/null +++ b/metron-interface/metron-alerts/src/_variables.scss @@ -0,0 +1,99 @@ +/** + * 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. + */ +//Bootstrap overrides +$body-bg: #232323; +$body-color: #999999; +$btn-primary-bg: #006EA0; +$btn-primary-border: #006EA0; +$dropdown-bg: #262626; +$dropdown-border-color: #4D4D4D; +$dropdown-link-color: #999999; +$dropdown-min-width: 8rem; +$dropdown-link-hover-color: #999999; +$dropdown-link-hover-bg: #333333; +$table-border-color: #404040; +$list-group-bg: #262626; +$list-group-border-color: #404040; +$list-group-active-bg: #28A9E2; +$list-group-item-padding-y: 4px; +$list-group-item-padding-x: 10px; + +//Metron variables +$mine-shaft: #2E2E2E; +$mine-shaft-1: #2D2D2D; +$mine-shaft-2: #333333; +$mine-shaft-3: #262626; +$mine-shaft-4: #383838; +$mine-shaft-5: #3D3D3D; +$dove-grey: #737373; +$tundora: #4D4D4D; +$tundora-1: #404040; +$curious-blue: #27AAE1; +$blue-chill: #0F6F9E; +$piction-blue: #32ABDF; +$dove-grey: #6B6B6B; +$dove-grey-1: #676767; +$checkbox-checked-color: #32abe2; +$edit-panel-background: #083b44; +$errors-red: #D60A15; +$warning-yellow: #D6711D; +$info-yellow: #AC9B5A; +$eden: #0C3B43; +$all-ports: #006EA0; +$blue-mine: #1B596C; +$gothic: #689AA9; +$tiber: #0B363E; +$silver: #BDBDBD; +$silver-1: #B8B8B8; +$breaker-bay: #669AAA; +$gray: #909090; +$silver-chalice: #B2B2B2; +$silver-chalice-2: #A2A2A2; +$dusty-grey: #999999; +$dusty-grey-1: #9B9A9A; +$outer-space: #2D3A3F; +$eastern-blue: #1F91BE; +$mantis: #80BF4D; +$sky-blue: #75D2ED; +$outer-space: #2E3A3F; + +$eastern-blue-1: #1190C0; +$matisse: #1E7490; +$downy: #77BBD0; +$trout: #515760; +$oslo-gray: #808792; +$gray-chateau: #9BA1AA; + +$nav-bar-bg: $mine-shaft; +$input-background: $mine-shaft-1; +$input-border-color: $tundora; +$icon-button-background: $mine-shaft-2; +$placeholder-color: $dove-grey; + +$nav-content-nav-width: 200px; + +@mixin place-holder-text +{ + font-family: Roboto; + font-size: 11px; + font-style: italic !important; +} + +.list-group-item { + font-size: 14px; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html new file mode 100644 index 0000000..afc93eb --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html @@ -0,0 +1,47 @@ +<!-- + 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="metron-slider-pane-details load-right-to-left dialog1x"> + <div class="container-fluid"> + <div class="row mb-3"> + <div class="col-md-10"> + <div class="form-title" appAlertSeverity [severity]="alert['threat:triage:score']"> {{ alert['threat:triage:score'] }} {{ alert._id }}</div> + </div> + <div class="col-md-2"><i class="fa fa-times pull-right close-button" aria-hidden="true" (click)="goBack()"></i></div> + </div> + <div class="row justify-content-center py-4 actions"> + <table> + <tr> + <td class="title"> Status</td> + <td class="secondary" [ngClass]="{'primary': selectedAlertState === alertState.ESCALATE, 'secondary': selectedAlertState !== alertState.ESCALATE}" (click)="processEscalate()">ESCALATE</td> + <td></td> + </tr> + <tr> + <td class="secondary" [ngClass]="{'primary': selectedAlertState === alertState.NEW, 'secondary': selectedAlertState !== alertState.NEW}" (click)="processNew()">NEW</td> + <td class="primary" [ngClass]="{'primary': selectedAlertState === alertState.OPEN, 'secondary': selectedAlertState !== alertState.OPEN}" (click)="processOpen()">OPEN</td> + <td class="secondary" [ngClass]="{'primary': selectedAlertState === alertState.DISMISS, 'secondary': selectedAlertState !== alertState.DISMISS}" (click)="processDismiss()">DISMISS</td> + </tr> + <tr> + <td></td> + <td class="secondary" [ngClass]="{'primary': selectedAlertState === alertState.RESOLVE, 'secondary': selectedAlertState !== alertState.RESOLVE}" (click)="processResolve()">RESOLVE</td> + <td></td> + </tr> + </table> + </div> + <div class="ml-1 my-4 form"> + <div *ngFor="let field of alertFields" class="row"> + <div class="col-6 mb-1 key">{{ field }}</div> <div class="col-6"> {{ alert._source[field] }} </div> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.scss b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.scss new file mode 100644 index 0000000..8407bba --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.scss @@ -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 "../../../slider"; +@import "../../../variables"; + +.container-fluid { + padding-top: 15px; +} + +.form-title { + font-size: 18px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.actions { + background: $mine-shaft-2; + + table { + text-align: center; + + td { + height: 35px; + } + + .primary { + min-width: 95px; + font-size: 12px; + color: #fff; + background: $piction-blue; + cursor: pointer; + } + + .secondary { + min-width: 95px; + font-size: 12px; + font-weight: bold; + background: $mine-shaft-3; + border: 1px solid $tundora; + cursor: pointer; + } + + .title { + text-align: start; + vertical-align: top; + } + } +} + +.form { + font-size: 14px; + + .key { + color: $dove-grey; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts new file mode 100644 index 0000000..218ceff --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts @@ -0,0 +1,108 @@ +/** + * 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 {Router, ActivatedRoute} from '@angular/router'; +import {AlertService} from '../../service/alert.service'; +import {Alert} from '../../model/alert'; +import {WorkflowService} from '../../service/workflow.service'; + +export enum AlertState { + NEW, OPEN, ESCALATE, DISMISS, RESOLVE +} + +@Component({ + selector: 'app-alert-details', + templateUrl: './alert-details.component.html', + styleUrls: ['./alert-details.component.scss'] +}) +export class AlertDetailsComponent implements OnInit { + + alertId = ''; + alertIndex = ''; + alertType = ''; + alertState = AlertState; + selectedAlertState: AlertState = AlertState.NEW; + alert: Alert = new Alert(); + alertFields: string[] = []; + + constructor(private router: Router, + private activatedRoute: ActivatedRoute, + private alertsService: AlertService, + private workflowService: WorkflowService) { } + + goBack() { + this.router.navigateByUrl('/alerts-list'); + return false; + } + + getData() { + this.alertsService.getAlert(this.alertIndex, this.alertType, this.alertId).subscribe(alert => { + this.alert = alert; + this.alertFields = Object.keys(alert._source).filter(field => !field.includes(':ts') && field !== 'original_string').sort(); + }); + } + + ngOnInit() { + this.activatedRoute.params.subscribe(params => { + this.alertId = params['id']; + this.alertIndex = params['index']; + this.alertType = params['type']; + this.getData(); + }); + } + + processOpen() { + this.selectedAlertState = AlertState.OPEN; + this.alertsService.updateAlertState([this.alert], 'OPEN', '').subscribe(results => { + this.getData(); + }); + } + + processNew() { + this.selectedAlertState = AlertState.NEW; + this.alertsService.updateAlertState([this.alert], 'NEW', '').subscribe(results => { + this.getData(); + }); + } + + processEscalate() { + this.selectedAlertState = AlertState.ESCALATE; + this.workflowService.start([this.alert]).subscribe(workflowId => { + this.alertsService.updateAlertState([this.alert], 'ESCALATE', workflowId).subscribe(results => { + this.getData(); + }); + }); + } + + processDismiss() { + this.selectedAlertState = AlertState.DISMISS; + this.alertsService.updateAlertState([this.alert], 'DISMISS', '').subscribe(results => { + this.getData(); + }); + } + + processResolve() { + this.selectedAlertState = AlertState.RESOLVE; + this.alertsService.updateAlertState([this.alert], 'RESOLVE', '').subscribe(results => { + this.getData(); + }); + } + +} + + http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.module.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.module.ts b/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.module.ts new file mode 100644 index 0000000..e7dd735 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.module.ts @@ -0,0 +1,29 @@ +/** + * 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 {routing} from './alerts-details.routing'; +import {SharedModule} from '../../shared/shared.module'; +import {AlertDetailsComponent} from './alert-details.component'; +import {WorkflowService} from '../../service/workflow.service'; + +@NgModule ({ + imports: [ routing, SharedModule], + declarations: [ AlertDetailsComponent ], + providers: [ WorkflowService ], +}) +export class AlertDetailsModule { } http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.routing.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.routing.ts b/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.routing.ts new file mode 100644 index 0000000..11cf61c --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.routing.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. + */ +import { ModuleWithProviders } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import {AlertDetailsComponent} from './alert-details.component'; + +export const routing: ModuleWithProviders = RouterModule.forChild([ + { path: 'details/:index/:type/:id', component: AlertDetailsComponent, outlet: 'dialog'} +]); http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html new file mode 100644 index 0000000..1fb01bf --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html @@ -0,0 +1,100 @@ +<!-- + 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 px-0"> + <div class="mrow"> + <div class="col-md-12 px-0"> + <div class="col-padding-50"> + <div class="input-group search"> + <span class="input-group-btn"> + <button class="btn btn-secondary btn-saved-searches" type="button" (click)="showSavedSearches()">Searches</button> + </span> + <div appAceEditor style="width:100%;" placeholder="Search Alerts" [text]="queryBuilder.displayQuery" (textChanged)="onSearch($event)"> </div> + <span class="input-group-btn"> + <button class="btn btn-secondary btn-search-clear" type="button" (click)="onClear()"></button> + </span> + <span class="input-group-btn"> + <button class="btn btn-secondary btn-search" type="button" (click)="onSearch(alertSearchDirective.getSeacrhText())"></button> + </span> + </div> + </div> + </div> + <div class="col-fixed-50"> + <span class="save-button" (click)="showSaveSearch()"> + </span> + </div> + </div> + <div class="mrow"> + <div class="col-md-9 px-0"> + <span class="col-form-label-lg"> Alerts ({{alerts.length}} of {{pagingData.total}}) </span> + </div> + <div class="col-md-3 px-0"> + <div class="pull-right" style="position: relative; display: block;"> + <div class="btn settings"> + <i #settingsIcon class="fa fa-sliders" aria-hidden="true"></i> + </div> + <app-configure-rows [srcElement]="settingsIcon" [tableMetaData]="tableMetaData" [(interval)]="refreshInterval" [(size)]="pagingData.size" (configRowsChange)="onConfigRowsChange()" > </app-configure-rows> + <div class="btn pause-play" (click)="onPausePlay()"> + <i *ngIf="!pauseRefresh" class="fa fa-pause" aria-hidden="true"></i> + <i *ngIf="pauseRefresh" class="fa fa-play" aria-hidden="true"></i> + </div> + <div class="dropdown d-inline-block"> + <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">ACTIONS</button> + <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton"> + <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processOpen()">Open</span> + <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processDismiss()">Dismiss</span> + <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processEscalate()">Escalate</span> + <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processResolve()">Resolve</span> + </div> + </div> + </div> + </div> + </div> +</div> + +<div class="container-fluid nav-content"> + <div class="row"> + <div class="col-sm-12 pl-0"> + <div class="table-wrapper"> + <table class="table table-sm" metron-config-table [data]="alerts" [cellSelectable]="true" (onSort)="onSort($event)" style="white-space: nowrap;" (window:resize)="onResize()" #table> + <thead> + <tr> + <th style="width:55px"> <metron-config-sorter [type]="'number'" [sortBy]="threatScoreFieldName"> Score </metron-config-sorter> </th> + <th *ngFor="let column of alertsColumnsToDisplay" [id]="column.name"> <metron-config-sorter [type]="column.type" [sortBy]="column.name" title="{{column.name}}"> {{ column.name | columnNameTranslate | centerEllipses:15 }}</metron-config-sorter> </th> + <th style="width:25px"><i class="fa fa-cog configure-table-icon" (click)="showConfigureTable()"></i></th> + <th style="width:25px"><input id="select-deselect-all" class="fontawesome-checkbox" type="checkbox" (click)="selectAllRows($event)"><label for="select-deselect-all"></label></th> + </tr> + </thead> + <tbody> + <tr *ngFor="let alert of alerts" (click)="showDetails($event, alert)" [ngClass]="{'selected' : selectedAlerts.indexOf(alert) != -1}"> + <td (click)="onAddFilter(threatScoreFieldName, alert._source[threatScoreFieldName])"> + <div appAlertSeverity [severity]="alert._source[threatScoreFieldName]"> <a> {{ alert._source[threatScoreFieldName] ? alert._source[threatScoreFieldName] : '-' }} </a> </div> + </td> + <td *ngFor="let column of alertsColumnsToDisplay" #cell> + <a (click)="onAddFilter(column.name, getValue(alert, column, false))" title="{{getValue(alert, column, true)}}" style="color:#689AA9">{{ getValue(alert, column, true) | centerEllipses:20:cell }}</a> + </td> + <td></td> + <td><input id="{{ alert._id }}" class="fontawesome-checkbox" type="checkbox" name="{{alert._id}}" (click)="selectRow($event, alert)" [checked]="selectedAlerts.indexOf(alert) != -1"><label attr.for="{{ alert._id }}"></label></td> + </tr> + </tbody> + </table> + </div> + <div clas="row"> + <div class="col-md-3 push-md-5"> + <metron-table-pagination [(pagingData)]="pagingData" (pageChange)="onPageChange()"> </metron-table-pagination> + </div> + </div> + </div> + </div> +</div> + http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.scss b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.scss new file mode 100644 index 0000000..dd1bb99 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.scss @@ -0,0 +1,311 @@ +/** + * 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 "../../../vendor.scss"; +@import "../../../styles.scss"; +@import "../../../variables.scss"; + +$searchbox-height: 42px; + +.mrow { + @extend .my-4; +} + +.search { + div { + height: auto; + } + + .form-control { + @extend .input; + min-height: $searchbox-height; + border-right: none; + } + + .input-group-btn { + &:focus { + outline: none; + } + } + + button { + background: $icon-button-background; + cursor: pointer; + } + + .btn-search { + min-width: $searchbox-height; + padding-left: 0px; + padding-right: 0px; + border: 1px solid $blue-chill !important; + + &:focus { + box-shadow: none; + } + + &::before { + font-family: "FontAwesome"; + content: '\f002'; + color: $piction-blue; + } + } + + .btn-saved-searches { + font-size: 15px; + + background: $mine-shaft-5; + border: 1px solid $tundora; + color: $silver-chalice; + + &:focus { + box-shadow: none; + } + + &::after { + font-family: "FontAwesome"; + content: '\f0da'; + color: $gray; + padding-left: 5px; + } + } + + .btn-search-clear { + border-top: 1px solid $tundora; + border-bottom: 1px solid $tundora; + border-right: 1px solid $blue-chill; + background: $mine-shaft-1; + border-left: none; + padding: 0px 5px 0px 0px; + width: 30px; + cursor: pointer; + + &:focus { + box-shadow: none; + } + + &::before { + font-family: "FontAwesome"; + content: '\f057'; + color: $gray; + padding-left: 5px; + } + } +} + +.col-padding-50 { + padding-right: 50px; +} + +.col-fixed-50 { + top: 0px; + right: 0; + z-index: 1; + position: absolute; +} + +.save-button { + width: $searchbox-height; + height: $searchbox-height; + display: block; + margin-left: 10px; + background: $mine-shaft-5; + border: 1px solid $tundora; + color: $silver-chalice; + border-radius: 4px; + cursor: pointer; + + &::before { + font-family: "FontAwesome"; + content: '\f0c7'; + color: $dusty-grey; + position: absolute; + padding-left: 10px; + padding-top: 3px; + font-size: 22px; + } +} + +.btn.severity { + padding: 0.25rem 1rem; + border-radius: 0rem; + background: $mine-shaft-2; + border: 1px solid $list-group-border-color; + + &::before { + font-family: "FontAwesome"; + content: '\f111'; + padding-right: 15px; + } +} + +.btn.severity.error::before { + color: $errors-red; +} + +.btn.severity.warning::before { + color: $warning-yellow; +} + +.btn.severity.info::before { + color: $info-yellow; +} + +.btn-group-severity { + padding: 10px; + background: $mine-shaft-4; +} + +.selected { + background: $mine-shaft-2; +} + + +.cell-value { + padding: 5px; +} + +.filter-button { + margin-left: 5px; + margin-right: 5px; + cursor: pointer; +} + +.configure-table-icon { + font-size: 16px; + cursor: pointer; +} + +.pause-play { + height: 38px; + padding: 0px; + border: 1px solid #0F6F9E; + width: 38px; + line-height: 39px; + border-radius: 12px; + margin-left: 15px; + background: $mine-shaft-2; + cursor: pointer; + + i { + font-size: 17px; + color: $piction-blue; + } + + .fa-play { + padding-left: 3px; + } +} + +.settings { + height: 38px; + padding: 0px; + line-height: 40px; + margin-left: 15px; + color: $dove-grey-1; + cursor: pointer; + + i { + font-size: 20px; + } +} + +.dropdown { + margin-left: 15px; + + .btn { + font-size: 0.8em; + min-height: 38px; + } +} + +.table-wrapper { + min-height: calc(100vh - 250px); +} + +.ace_editor { + background: $mine-shaft-1; + border: 1px solid $tundora; +} + +:host /deep/ .ace-monokai { + .ace_keyword { + color: $mantis; + } + + .ace_line { + color: $sky-blue; + } + + .ace_operator { + color: $silver; + } + + .ace_constant.ace_character { + color: $mantis; + } + + .ace_value { + height: 100%; + cursor: pointer; + pointer-events: auto; + display: inline-block; + + &.active { + border : 1px solid $outer-space; + border-left : none; + height: 18px; + display: inline-block; + background: $outer-space; + cursor: pointer; + padding-right: 3px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + } + } + + .ace_keyword { + height: 100%; + cursor: pointer; + pointer-events: auto; + display: inline-block; + + &.active { + border : 1px solid $outer-space; + border-right : none; + height: 18px; + display: inline-block; + background: $outer-space; + cursor: pointer; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + } + } + + .ace_content { + margin-left: 10px; + margin-right: 10px; + } + + .fa-times { + padding-left: 4px; + color: $silver-1; + } + + .ace_hidden-cursors .ace_cursor { + opacity: 0; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts new file mode 100644 index 0000000..e014ede --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts @@ -0,0 +1,399 @@ +/** + * 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, ViewChild, ElementRef} from '@angular/core'; +import {Router, NavigationStart} from '@angular/router'; +import {Observable, Subscription} from 'rxjs/Rx'; + +import {Alert} from '../../model/alert'; +import {AlertService} from '../../service/alert.service'; +import {QueryBuilder} from './query-builder'; +import {ConfigureTableService} from '../../service/configure-table.service'; +import {WorkflowService} from '../../service/workflow.service'; +import {ClusterMetaDataService} from '../../service/cluster-metadata.service'; +import {ColumnMetadata} from '../../model/column-metadata'; +import {SortEvent} from '../../shared/metron-table/metron-table.directive'; +import {Sort} from '../../utils/enums'; +import {Pagination} from '../../model/pagination'; +import {SaveSearchService} from '../../service/save-search.service'; +import {RefreshInterval} from '../configure-rows/configure-rows-enums'; +import {SaveSearch} from '../../model/save-search'; +import {TableMetadata} from '../../model/table-metadata'; +import {MetronDialogBox, DialogType} from '../../shared/metron-dialog-box'; +import {AlertSearchDirective} from '../../shared/directives/alert-search.directive'; +import {AlertsSearchResponse} from '../../model/alerts-search-response'; +import {ElasticsearchUtils} from '../../utils/elasticsearch-utils'; + +@Component({ + selector: 'app-alerts-list', + templateUrl: './alerts-list.component.html', + styleUrls: ['./alerts-list.component.scss'] +}) + +export class AlertsListComponent implements OnInit { + + alertsColumns: ColumnMetadata[] = []; + alertsColumnsToDisplay: ColumnMetadata[] = []; + selectedAlerts: Alert[] = []; + alerts: any[] = []; + colNumberTimerId: number; + refreshInterval = RefreshInterval.ONE_MIN; + refreshTimer: Subscription; + pauseRefresh = false; + lastPauseRefreshValue = false; + threatScoreFieldName = 'threat:triage:score'; + + @ViewChild('table') table: ElementRef; + @ViewChild(AlertSearchDirective) alertSearchDirective: AlertSearchDirective; + + pagingData = new Pagination(); + tableMetaData = new TableMetadata(); + queryBuilder: QueryBuilder = new QueryBuilder(); + + constructor(private router: Router, + private alertsService: AlertService, + private configureTableService: ConfigureTableService, + private workflowService: WorkflowService, + private clusterMetaDataService: ClusterMetaDataService, + private saveSearchService: SaveSearchService, + private metronDialogBox: MetronDialogBox) { + router.events.subscribe(event => { + if (event instanceof NavigationStart && event.url === '/alerts-list') { + this.selectedAlerts = []; + this.restoreRefreshState(); + } + }); + } + + addAlertColChangedListner() { + this.configureTableService.tableChanged$.subscribe(colChanged => { + if (colChanged) { + this.getAlertColumnNames(false); + } + }); + } + + addLoadSavedSearchListner() { + this.saveSearchService.loadSavedSearch$.subscribe((savedSearch: SaveSearch) => { + let queryBuilder = new QueryBuilder(); + queryBuilder.searchRequest = savedSearch.searchRequest; + this.queryBuilder = queryBuilder; + this.prepareColumnData(savedSearch.tableColumns, []); + this.search(true, savedSearch); + }); + } + + calcColumnsToDisplay() { + let availableWidth = document.documentElement.clientWidth - (200 + (15 * 3)); /* screenwidth - (navPaneWidth + (paddings))*/ + availableWidth = availableWidth - (55 + 25 + 25); /* availableWidth - (score + colunSelectIcon +selectCheckbox )*/ + let tWidth = 0; + this.alertsColumnsToDisplay = this.alertsColumns.filter(colMetaData => { + if (colMetaData.type.toUpperCase() === 'DATE') { + tWidth += 140; + } else if (colMetaData.type.toUpperCase() === 'IP') { + tWidth += 120; + } else if (colMetaData.type.toUpperCase() === 'BOOLEAN') { + tWidth += 50; + } else { + tWidth += 130; + } + + return tWidth < availableWidth; + }); + } + + formatValue(column: ColumnMetadata, returnValue: string) { + try { + if (column.name.endsWith(':ts') || column.name.endsWith('timestamp')) { + returnValue = new Date(parseInt(returnValue, 10)).toISOString().replace('T', ' ').slice(0, 19); + } + } catch (e) {} + + return returnValue; + } + + getAlertColumnNames(resetPaginationForSearch: boolean) { + Observable.forkJoin( + this.configureTableService.getTableMetadata(), + this.clusterMetaDataService.getDefaultColumns() + ).subscribe((response: any) => { + this.prepareData(response[0], response[1], resetPaginationForSearch); + }); + } + + getCollapseComponentData(data: any) { + return { + getName: () => { + return Object.keys(data.aggregations)[0]; + }, + getData: () => { + return data.aggregations[Object.keys(data.aggregations)[0]].buckets; + }, + }; + } + + getColumnNamesForQuery() { + let fieldNames = this.alertsColumns.map(columnMetadata => columnMetadata.name); + fieldNames = fieldNames.filter(name => !(name === '_id' || name === 'alert_status')); + fieldNames.push(this.threatScoreFieldName); + return fieldNames; + } + + getDataType(name: string): string { + if (name === this.threatScoreFieldName || name === '_id') { + return 'number'; + } + + return this.alertsColumns.filter(colMetaData => colMetaData.name === name)[0].type; + } + + getValue(alert: any, column: ColumnMetadata, formatData: boolean) { + let returnValue = ''; + try { + switch (column.name) { + case '_id': + returnValue = alert[column.name]; + break; + case 'alert_status': + returnValue = 'NEW'; + break; + default: + returnValue = alert['_source'][column.name]; + break; + } + } catch (e) {} + + if (formatData) { + returnValue = this.formatValue(column, returnValue); + } + + return returnValue; + } + + ngOnInit() { + this.getAlertColumnNames(true); + this.addAlertColChangedListner(); + this.addLoadSavedSearchListner(); + } + + onClear() { + this.queryBuilder.displayQuery = ''; + this.search(); + } + + onSearch($event) { + this.queryBuilder.displayQuery = $event; + this.search(); + + return false; + } + + onAddFilter(field: string, value: string) { + this.queryBuilder.addOrUpdateFilter(field, value); + this.search(); + } + + onConfigRowsChange() { + this.alertsService.interval = this.refreshInterval; + this.search(); + } + + onPageChange() { + this.queryBuilder.setFromAndSize(this.pagingData.from, this.pagingData.size); + this.search(false); + } + + onPausePlay() { + this.pauseRefresh = !this.pauseRefresh; + if (this.pauseRefresh) { + this.tryStopPolling(); + } else { + this.search(false); + } + } + + onResize() { + clearTimeout(this.colNumberTimerId); + this.colNumberTimerId = setTimeout(() => { this.calcColumnsToDisplay(); }, 500); + } + + onSort(sortEvent: SortEvent) { + let sortOrder = (sortEvent.sortOrder === Sort.ASC ? 'asc' : 'desc'); + let sortBy = sortEvent.sortBy === '_id' ? '_uid' : sortEvent.sortBy; + this.queryBuilder.setSort(sortBy, sortOrder, this.getDataType(sortEvent.sortBy)); + this.search(); + } + + prepareColumnData(configuredColumns: ColumnMetadata[], defaultColumns: ColumnMetadata[]) { + this.alertsColumns = (configuredColumns && configuredColumns.length > 0) ? configuredColumns : defaultColumns; + this.queryBuilder.setFields(this.getColumnNamesForQuery()); + this.calcColumnsToDisplay(); + } + + prepareData(tableMetaData: TableMetadata, defaultColumns: ColumnMetadata[], resetPagination: boolean) { + this.tableMetaData = tableMetaData; + this.pagingData.size = this.tableMetaData.size; + this.refreshInterval = this.tableMetaData.refreshInterval; + + this.updateConfigRowsSettings(); + this.prepareColumnData(tableMetaData.tableColumns, defaultColumns); + + this.search(resetPagination); + } + + processEscalate() { + this.workflowService.start(this.selectedAlerts).subscribe(workflowId => { + this.alertsService.updateAlertState(this.selectedAlerts, 'ESCALATE', workflowId).subscribe(results => { + this.updateSelectedAlertStatus('ESCALATE'); + }); + }); + } + + processDismiss() { + this.alertsService.updateAlertState(this.selectedAlerts, 'DISMISS', '').subscribe(results => { + this.updateSelectedAlertStatus('DISMISS'); + }); + } + + processOpen() { + this.alertsService.updateAlertState(this.selectedAlerts, 'OPEN', '').subscribe(results => { + this.updateSelectedAlertStatus('OPEN'); + }); + } + + processResolve() { + this.alertsService.updateAlertState(this.selectedAlerts, 'RESOLVE', '').subscribe(results => { + this.updateSelectedAlertStatus('RESOLVE'); + }); + } + + removeFilter(field: string) { + this.queryBuilder.removeFilter(field); + this.search(); + } + + restoreRefreshState() { + this.pauseRefresh = this.lastPauseRefreshValue; + this.tryStartPolling(); + } + + selectAllRows($event) { + this.selectedAlerts = []; + if ($event.target.checked) { + this.selectedAlerts = this.alerts; + } + } + + search(resetPaginationParams = true, savedSearch?: SaveSearch) { + this.selectedAlerts = []; + + if (resetPaginationParams) { + this.pagingData.from = 0; + this.queryBuilder.setFromAndSize(this.pagingData.from, this.pagingData.size); + } + + if (this.queryBuilder.query !== '*') { + if (!savedSearch) { + savedSearch = new SaveSearch(); + savedSearch.searchRequest = this.queryBuilder.searchRequest; + savedSearch.tableColumns = this.alertsColumns; + savedSearch.name = savedSearch.getDisplayString(); + } + + this.saveSearchService.saveAsRecentSearches(savedSearch).subscribe(() => {}); + } + + this.alertsService.search(this.queryBuilder.searchRequest).subscribe(results => { + this.setData(results); + }, error => { + this.setData(new AlertsSearchResponse()); + this.metronDialogBox.showConfirmationMessage(ElasticsearchUtils.extractESErrorMessage(error), DialogType.Error); + }); + + this.tryStartPolling(); + } + + selectRow($event, alert: Alert) { + if ($event.target.checked) { + this.selectedAlerts.push(alert); + } else { + this.selectedAlerts.splice(this.selectedAlerts.indexOf(alert), 1); + } + } + + setData(results: AlertsSearchResponse) { + this.alerts = results.results; + this.pagingData.total = results.total; + } + + showConfigureTable() { + this.saveRefreshState(); + this.router.navigateByUrl('/alerts-list(dialog:configure-table)'); + } + + showDetails($event, alert: any) { + if ($event.target.type !== 'checkbox' && $event.target.parentElement.firstChild.type !== 'checkbox' && $event.target.nodeName !== 'A') { + this.selectedAlerts = []; + this.selectedAlerts = [alert]; + this.saveRefreshState(); + this.router.navigateByUrl('/alerts-list(dialog:details/' + alert._index + '/' + alert._type + '/' + alert._id + ')'); + } + } + + saveRefreshState() { + this.lastPauseRefreshValue = this.pauseRefresh; + this.tryStopPolling(); + } + + + showSavedSearches() { + this.saveRefreshState(); + this.router.navigateByUrl('/alerts-list(dialog:saved-searches)'); + } + + showSaveSearch() { + this.saveRefreshState(); + this.saveSearchService.setCurrentQueryBuilderAndTableColumns(this.queryBuilder, this.alertsColumns); + this.router.navigateByUrl('/alerts-list(dialog:save-search)'); + } + + tryStartPolling() { + if (!this.pauseRefresh) { + this.tryStopPolling(); + this.refreshTimer = this.alertsService.pollSearch(this.queryBuilder.searchRequest).subscribe(results => { + this.setData(results); + }); + } + } + + tryStopPolling() { + if (this.refreshTimer && !this.refreshTimer.closed) { + this.refreshTimer.unsubscribe(); + } + } + + updateConfigRowsSettings() { + this.alertsService.interval = this.refreshInterval; + this.queryBuilder.setFromAndSize(this.pagingData.from, this.pagingData.size); + } + + updateSelectedAlertStatus(status: string) { + for (let alert of this.selectedAlerts) { + alert.status = status; + } + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.module.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.module.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.module.ts new file mode 100644 index 0000000..1a39e51 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.module.ts @@ -0,0 +1,38 @@ +/** + * 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 {AlertsListComponent} from './alerts-list.component'; +import {routing} from './alerts-list.routing'; +import {SharedModule} from '../../shared/shared.module'; +import {AlertService} from '../../service/alert.service'; +import {MetronSorterModule} from '../../shared/metron-table/metron-sorter/metron-sorter.module'; +import {ListGroupModule} from '../../shared/list-group/list-grup.module'; +import {CollapseModule} from '../../shared/collapse/collapse.module'; +import {MetronTablePaginationModule} from '../../shared/metron-table/metron-table-pagination/metron-table-pagination.module'; +import {ConfigureRowsModule} from '../configure-rows/configure-rows.module'; + +@NgModule({ + imports: [routing, SharedModule, ConfigureRowsModule, MetronSorterModule, MetronTablePaginationModule, + ListGroupModule, CollapseModule], + exports: [], + declarations: [AlertsListComponent], + providers: [AlertService], +}) +export class AlertsListModule { +} http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.routing.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.routing.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.routing.ts new file mode 100644 index 0000000..37534f1 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.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 {Routes, RouterModule} from '@angular/router'; +import {ModuleWithProviders} from '@angular/core'; + +import {AlertsListComponent} from './alerts-list.component'; + +export const routes: Routes = [ + {path: '', component: AlertsListComponent}, +]; + +export const routing: ModuleWithProviders = RouterModule.forChild(routes); http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/alerts-list/query-builder.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/query-builder.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/query-builder.ts new file mode 100644 index 0000000..b651d26 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/query-builder.ts @@ -0,0 +1,139 @@ +/** + * 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 {Filter} from '../../model/filter'; +import {ColumnNamesService} from '../../service/column-names.service'; +import {SearchRequest} from '../../model/search-request'; + +export class QueryBuilder { + private _searchRequest = new SearchRequest(); + private _query = '*'; + private _displayQuery = this._query; + private _filters: Filter[] = []; + + set query(value: string) { + value = value.replace(/\\:/g, ':'); + this._query = value; + this.updateFilters(this._query, false); + this.onSearchChange(); + } + + get query(): string { + return this._query; + } + + set displayQuery(value: string) { + this._displayQuery = value; + this.updateFilters(this._displayQuery, true); + this.onSearchChange(); + } + + get displayQuery(): string { + return this._displayQuery; + } + + get filters(): Filter[] { + return this._filters; + } + + + get searchRequest(): SearchRequest { + this._searchRequest.query = this.generateSelect(); + return this._searchRequest; + } + + set searchRequest(value: SearchRequest) { + this._searchRequest = value; + this.query = this._searchRequest.query; + } + + addOrUpdateFilter(field: string, value: string) { + let filter = this._filters.find(tFilter => tFilter.field === field); + if (filter) { + filter.value = value; + } else { + this._filters.push(new Filter(field, value)); + } + + this.onSearchChange(); + } + + generateSelect() { + let select = this._filters.map(filter => { + return filter.field.replace(/:/g, '\\:') + + ':' + + String(filter.value) + .replace(/[\*\+\-=~><\"\?^\${}\(\)\:\!\/[\]\\\s]/g, '\\$&') // replace single special characters + .replace(/\|\|/g, '\\||') // replace || + .replace(/\&\&/g, '\\&&'); // replace && + }).join(' AND '); + return (select.length === 0) ? '*' : select; + } + + generateSelectForDisplay() { + let select = this._filters.map(filter => ColumnNamesService.getColumnDisplayValue(filter.field) + ':' + filter.value).join(' AND '); + return (select.length === 0) ? '*' : select; + } + + onSearchChange() { + this._query = this.generateSelect(); + this._displayQuery = this.generateSelectForDisplay(); + } + + removeFilter(field: string) { + let filter = this._filters.find(tFilter => tFilter.field === field); + this._filters.splice(this._filters.indexOf(filter), 1); + + this.onSearchChange(); + } + + setFields(fieldNames: string[]) { + this.searchRequest._source = fieldNames; + } + + setFromAndSize(from: number, size: number) { + this.searchRequest.from = from; + this.searchRequest.size = size; + } + + setSort(sortBy: string, order: string, dataType: string) { + let sortQuery = {}; + sortQuery[sortBy] = { + order: order, + ignore_unmapped: true, + unmapped_type: dataType, + missing: '_last' + }; + this.searchRequest.sort = [sortQuery]; + } + + private updateFilters(tQuery: string, updateNameTransform = false) { + let query = tQuery; + this._filters = []; + + if (query && query !== '' && query !== '*') { + let terms = query.split(' AND '); + for (let term of terms) { + let separatorPos = term.lastIndexOf(':'); + let field = term.substring(0, separatorPos).replace('\\', ''); + field = updateNameTransform ? ColumnNamesService.getColumnDisplayKey(field) : field; + let value = term.substring(separatorPos + 1, term.length); + this.addOrUpdateFilter(field, value); + } + } + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows-enums.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows-enums.ts b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows-enums.ts new file mode 100644 index 0000000..facd597 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows-enums.ts @@ -0,0 +1,37 @@ +/** + * 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 enum PageSize { + TEN = 10, + TWENTY_FIVE = 25, + FIFTY = 50, + HUNDRED = 100, + TOW_HUNDRED_FIFTY = 250, + FIVE_HUNDRED = 500, + THOUSAND = 1000 +} + +export enum RefreshInterval { + FIVE_SEC = 5, + TEN_SEC = 10, + FIFTEEN_SEC = 15, + THIRTY_SEC = 30, + ONE_MIN = 60, + TEN_MIN = 600, + ONE_HOUR = 3600 + +} http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.html b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.html new file mode 100644 index 0000000..d765d5e --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.html @@ -0,0 +1,45 @@ +<!-- + 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. + --> +<i class="fa fa-sort-asc" aria-hidden="true" *ngIf="showView"></i> +<div class="card" *ngIf="showView"> + <div class="card-block"> + <h6 class="card-title">Settings</h6> + <form> + <label> REFRESH RATE </label> + <div #refreshInterval class="preset-row refresh-interval" (click)="onRefreshIntervalChange($event, refreshInterval)"> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.refreshInterval===5}" [attr.value]="5"> 5s </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.refreshInterval===10}" [attr.value]="10"> 10s </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.refreshInterval===15}" [attr.value]="15"> 15s </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.refreshInterval===30}" [attr.value]="30"> 30s </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.refreshInterval===60}" [attr.value]="60"> 1m </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.refreshInterval===600}" [attr.value]="600"> 10m </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.refreshInterval===3600}" [attr.value]="3600"> 1h </div> + </div> + <label> ROWS PER PAGE </label> + <div #pageSize class="preset-row page-size" (click)="onPageSizeChange($event, pageSize)"> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.size===10}"> 10 </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.size===25}"> 25 </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.size===50}"> 50 </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.size===100}"> 100 </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.size===250}"> 250 </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.size===500}"> 500 </div> + <div class="preset-cell" [ngClass]="{'is-active': tableMetadata.size===1000}"> 1000 </div> + </div> + + <app-switch [text]="'HIDE Resolved Alerts'"> </app-switch> + <app-switch [text]="'HIDE Dismissed Alerts'"> </app-switch> + + </form> + </div> +</div> http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.scss b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.scss new file mode 100644 index 0000000..4c29e28 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.scss @@ -0,0 +1,85 @@ +/** + * 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 "../../../vendor.scss"; +@import "../../../variables.scss"; + +label { + margin-bottom: 2px; +} + +.card { + width: 349px; + position: absolute; + left: -140px; + z-index: 1; + top: 50px; + border-radius: 0; + background: $mine-shaft-2; +} + +.card-block { + padding: 1rem; +} + +.card-title { + color: $silver; +} + +.preset-row { + color: $silver; + text-align: center; + width: 100%; + height: 45px; + + .preset-cell { + @extend .d-inline-block; + + width : 45px; + height: 35px; + float: left; + cursor: pointer; + line-height: 35px; + font-size:13px; + border-right: 1px solid $tundora; + border-top: 1px solid $tundora; + border-bottom: 1px solid $tundora; + } + + .preset-cell:first-child { + border-left: 1px solid $tundora; + border-radius: 4px 0px 0px 4px; + } + + .preset-cell:last-child { + border-radius: 0px 4px 4px 0px; + } + + .preset-cell.is-active { + color: #ffffff; + background: $eastern-blue; + } +} + +.fa-sort-asc { + position: absolute; + bottom: -50px; + left: 10px; + font-size: 62px; + color: #333333; + z-index: 2; +} http://git-wip-us.apache.org/repos/asf/metron/blob/7d554444/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.spec.ts b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.spec.ts new file mode 100644 index 0000000..65b704a --- /dev/null +++ b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.spec.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 { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConfigureRowsComponent } from './configure-rows.component'; + +describe('ConfigureRowsComponent', () => { + let component: ConfigureRowsComponent; + let fixture: ComponentFixture<ConfigureRowsComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ConfigureRowsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfigureRowsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + +});