http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/app/public/feature/common/controller.js ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/common/controller.js b/eagle-webservice/src/main/webapp/app/public/feature/common/controller.js deleted file mode 100644 index 207c8df..0000000 --- a/eagle-webservice/src/main/webapp/app/public/feature/common/controller.js +++ /dev/null @@ -1,1224 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -(function() { - 'use strict'; - - var featureControllers = angular.module("featureControllers"); - var feature = featureControllers.register("common"); - - // ============================================================== - // = Function = - // ============================================================== - feature.service("Policy", function(Entities) { - var Policy = function () {}; - - Policy.updatePolicyStatus = function(policy, status) { - $.dialog({ - title: "Confirm", - content: "Do you want to " + (status ? "enable" : "disable") + " policy[" + policy.tags.policyId + "]?", - confirm: true - }, function(ret) { - if(ret) { - policy.enabled = status; - Entities.updateEntity("AlertDefinitionService", policy); - } - }); - }; - Policy.deletePolicy = function(policy, callback) { - $.dialog({ - title: "Confirm", - content: "Do you want to delete policy[" + policy.tags.policyId + "]?", - confirm: true - }, function(ret) { - if(ret) { - policy.enabled = status; - Entities.deleteEntity("AlertDefinitionService", policy)._promise.finally(function() { - if(callback) { - callback(policy); - } - }); - } - }); - }; - return Policy; - }); - - feature.service("Notification", function(Entities) { - var Notification = function () {}; - Notification.map = {}; - - Notification.list = Entities.queryEntities("AlertNotificationService"); - Notification.list._promise.then(function () { - $.each(Notification.list, function (i, notification) { - // Parse fields - notification.fieldList = common.parseJSON(notification.fields, []); - - // Fill map - Notification.map[notification.tags.notificationType] = notification; - }); - }); - - Notification.promise = Notification.list._promise; - - return Notification; - }); - - // ============================================================== - // = Policies = - // ============================================================== - - // ========================= Policy List ======================== - feature.navItem("policyList", "Policies", "list"); - feature.controller('policyList', function(PageConfig, Site, $scope, Application, Entities, Policy) { - PageConfig.pageTitle = "Policy List"; - PageConfig.pageSubTitle = Site.current().tags.site; - - // Initial load - $scope.policyList = []; - $scope.application = Application.current(); - - // List policies - var _policyList = Entities.queryEntities("AlertDefinitionService", {site: Site.current().tags.site, application: $scope.application.tags.application}); - _policyList._promise.then(function() { - $.each(_policyList, function(i, policy) { - policy.__expression = common.parseJSON(policy.policyDef, {}).expression; - - $scope.policyList.push(policy); - }); - }); - $scope.policyList._promise = _policyList._promise; - - // Function - $scope.searchFunc = function(item) { - var key = $scope.search; - if(!key) return true; - - var _key = key.toLowerCase(); - function _hasKey(item, path) { - var _value = common.getValueByPath(item, path, "").toLowerCase(); - return _value.indexOf(_key) !== -1; - } - return _hasKey(item, "tags.policyId") || _hasKey(item, "__expression") || _hasKey(item, "description") || _hasKey(item, "owner"); - }; - - $scope.updatePolicyStatus = Policy.updatePolicyStatus; - $scope.deletePolicy = function(policy) { - Policy.deletePolicy(policy, function(policy) { - var _index = $scope.policyList.indexOf(policy); - $scope.policyList.splice(_index, 1); - }); - }; - }); - - // ======================= Policy Detail ======================== - feature.controller('policyDetail', function(PageConfig, Site, $scope, $wrapState, $interval, Entities, Policy, nvd3) { - var MAX_PAGESIZE = 10000; - var seriesRefreshInterval; - - PageConfig.pageTitle = "Policy Detail"; - PageConfig.lockSite = true; - PageConfig - .addNavPath("Policy List", "/common/policyList") - .addNavPath("Policy Detail"); - - $scope.chartConfig = { - chart: "line", - xType: "time" - }; - - // Query policy - if($wrapState.param.filter) { - $scope.policyList = Entities.queryEntity("AlertDefinitionService", $wrapState.param.filter); - } else { - $scope.policyList = Entities.queryEntities("AlertDefinitionService", { - policyId: $wrapState.param.policy, - site: $wrapState.param.site, - alertExecutorId: $wrapState.param.executor - }); - } - - $scope.policyList._promise.then(function() { - var policy = null; - - if($scope.policyList.length === 0) { - $.dialog({ - title: "OPS!", - content: "Policy not found!" - }, function() { - location.href = "#/common/policyList"; - }); - return; - } else { - policy = $scope.policyList[0]; - - policy.__notificationList = common.parseJSON(policy.notificationDef, []); - - policy.__expression = common.parseJSON(policy.policyDef, {}).expression; - - $scope.policy = policy; - Site.current(Site.find($scope.policy.tags.site)); - console.log($scope.policy); - } - - // Visualization - var _intervalType = 0; - var _intervalList = [ - ["Daily", 1440, function() { - var _endTime = app.time.now().hour(23).minute(59).second(59).millisecond(0); - var _startTime = _endTime.clone().subtract(1, "month").hour(0).minute(0).second(0).millisecond(0); - return [_startTime, _endTime]; - }], - ["Hourly", 60, function() { - var _endTime = app.time.now().minute(59).second(59).millisecond(0); - var _startTime = _endTime.clone().subtract(48, "hour").minute(0).second(0).millisecond(0); - return [_startTime, _endTime]; - }], - ["Every 5 minutes", 5, function() { - var _endTime = app.time.now().second(59).millisecond(0); - var _minute = Math.floor(_endTime.minute() / 5) * 5; - var _startTime = _endTime.clone().minute(_minute).subtract(5 * 30, "minute").second(0).millisecond(0); - _endTime.minute(_minute + 4); - return [_startTime, _endTime]; - }] - ]; - - function _loadSeries(seriesName, metricName, condition) { - var list = Entities.querySeries("GenericMetricService", $.extend({_metricName: metricName}, condition), "@site", "sum(value)", _intervalList[_intervalType][1]); - var seriesList = nvd3.convert.eagle([list]); - if(!$scope[seriesName]) $scope[seriesName] = seriesList; - list._promise.then(function() { - $scope[seriesName] = seriesList; - }); - } - - function refreshSeries() { - var _timeRange = _intervalList[_intervalType][2](); - var _startTime = _timeRange[0]; - var _endTime = _timeRange[1]; - var _cond = { - application: policy.tags.application, - policyId: policy.tags.policyId, - _startTime: _startTime, - _endTime: _endTime - }; - console.log("Range:", common.format.date(_startTime, "datetime"), common.format.date(_endTime, "datetime")); - - // > eagle.policy.eval.count - _loadSeries("policyEvalSeries", "eagle.policy.eval.count", _cond); - - // > eagle.policy.eval.fail.count - _loadSeries("policyEvalFailSeries", "eagle.policy.eval.fail.count", _cond); - - // > eagle.alert.count - _loadSeries("alertSeries", "eagle.alert.count", _cond); - - // > eagle.alert.fail.count - _loadSeries("alertFailSeries", "eagle.alert.fail.count", _cond); - } - - // Alert list - $scope.alertList = Entities.queryEntities("AlertService", { - site: Site.current().tags.site, - application: policy.tags.application, - policyId: policy.tags.policyId, - _pageSize: MAX_PAGESIZE, - _duration: 1000 * 60 * 60 * 24 * 30, - __ETD: 1000 * 60 * 60 * 24 - }); - - refreshSeries(); - seriesRefreshInterval = $interval(refreshSeries, 60000); - - // Menu - $scope.visualizationMenu = [ - {icon: "clock-o", title: "Interval", list: - $.map(_intervalList, function(item, index) { - var _item = {icon: "clock-o", title: item[0], func: function() { - _intervalType = index; - refreshSeries(); - }}; - Object.defineProperty(_item, 'strong', { - get: function() {return _intervalType === index;} - }); - return _item; - }) - } - ]; - }); - - // Function - $scope.updatePolicyStatus = Policy.updatePolicyStatus; - $scope.deletePolicy = function(policy) { - Policy.deletePolicy(policy, function() { - location.href = "#/common/policyList"; - }); - }; - - // Clean up - $scope.$on('$destroy', function() { - $interval.cancel(seriesRefreshInterval); - }); - }); - - // ======================== Policy Edit ========================= - function policyCtrl(create, PageConfig, Site, Policy, $scope, $wrapState, $q, UI, Entities, Application, Authorization, Notification) { - PageConfig.pageTitle = create ? "Policy Create" : "Policy Edit"; - PageConfig.pageSubTitle = Site.current().tags.site; - PageConfig - .addNavPath("Policy List", "/common/policyList") - .addNavPath("Policy Edit"); - - var _winTimeDesc = "Number unit[millisecond, sec, min, hour, day, month, year]. e.g. 23 sec"; - var _winTimeRegex = /^\d+\s+(millisecond|milliseconds|second|seconds|sec|minute|minutes|min|hour|hours|day|days|week|weeks|month|months|year|years)$/; - var _winTimeDefaultValue = '10 min'; - $scope.config = { - window: [ - // Display name, window type, required columns[Title, Description || "LONG_FIELD", Regex check, default value] - { - title: "Message Time Slide", - description: "Using timestamp filed from input is used as event's timestamp", - type: "externalTime", - fields:[ - {title: "Field", defaultValue: "timestamp", hide: true}, - {title: "Time", description: _winTimeDesc, regex: _winTimeRegex, defaultValue: _winTimeDefaultValue} - ] - }, - { - title: "System Time Slide", - description: "Using System time is used as timestamp for event's timestamp", - type: "time", - fields:[ - {title: "Time", description: _winTimeDesc, regex: _winTimeRegex, defaultValue: _winTimeDefaultValue} - ] - }, - { - title: "System Time Batch", - description: "Same as System Time Window except the policy is evaluated at fixed duration", - type: "timeBatch", - fields:[ - {title: "Time", description: _winTimeDesc, regex: _winTimeRegex, defaultValue: _winTimeDefaultValue} - ] - }, - { - title: "Length Slide", - description: "The slide window has a fixed length", - type: "length", - fields:[ - {title: "Number", description: "Number only. e.g. 1023", regex: /^\d+$/} - ] - }, - { - title: "Length Batch", - description: "Same as Length window except the policy is evaluated in batch mode when fixed event count reached", - type: "lengthBatch", - fields:[ - {title: "Number", description: "Number only. e.g. 1023", regex: /^\d+$/} - ] - } - ] - }; - - $scope.Notification = Notification; - - $scope.create = create; - $scope.encodedRowkey = $wrapState.param.filter; - - $scope.step = 0; - $scope.applications = {}; - $scope.policy = {}; - - // ========================================== - // = Notification = - // ========================================== - $scope.notificationTabHolder = null; - - $scope.newNotification = function (notificationType) { - var __notification = { - notificationType: notificationType - }; - - $.each(Notification.map[notificationType].fieldList, function (i, field) { - __notification[field.name] = field.value || ""; - }); - - $scope.policy.__.notification.push(__notification); - }; - - Notification.promise.then(function () { - $scope.menu = Authorization.isRole('ROLE_ADMIN') ? [ - {icon: "cog", title: "Configuration", list: [ - {icon: "trash", title: "Delete", danger: true, func: function () { - var notification = $scope.notificationTabHolder.selectedPane.data; - UI.deleteConfirm(notification.notificationType).then(null, null, function(holder) { - common.array.remove(notification, $scope.policy.__.notification); - holder.closeFunc(); - }); - }} - ]}, - {icon: "plus", title: "New", list: $.map(Notification.list, function(notification) { - return { - icon: "plus", - title: notification.tags.notificationType, - func: function () { - $scope.newNotification(notification.tags.notificationType); - setTimeout(function() { - $scope.notificationTabHolder.setSelect(-1); - $scope.$apply(); - }, 0); - } - }; - })} - ] : []; - }); - - // ========================================== - // = Data Preparation = - // ========================================== - // Steam list - var _streamList = Entities.queryEntities("AlertStreamService", {application: Application.current().tags.application}); - var _executorList = Entities.queryEntities("AlertExecutorService", {application: Application.current().tags.application}); - $scope.streamList = _streamList; - $scope.executorList = _executorList; - $scope.streamReady = false; - - $q.all([_streamList._promise, _executorList._promise]).then(function() { - // Map executor with stream - $.each(_executorList, function(i, executor) { - $.each(_streamList, function(j, stream) { - if(stream.tags.application === executor.tags.application && stream.tags.streamName === executor.tags.streamName) { - stream.alertExecutor = executor; - return false; - } - }); - }); - - // Fill stream list - $.each(_streamList, function(i, unit) { - var _srcStreamList = $scope.applications[unit.tags.application] = $scope.applications[unit.tags.application] || []; - _srcStreamList.push(unit); - }); - - $scope.streamReady = true; - - // ========================================== - // = Function = - // ========================================== - function _findStream(application, streamName) { - var _streamList = $scope.applications[application]; - if(!_streamList) return null; - - for(var i = 0 ; i < _streamList.length ; i += 1) { - if(_streamList[i].tags.streamName === streamName) { - return _streamList[i]; - } - } - return null; - } - - // ========================================== - // = Step control = - // ========================================== - $scope.steps = [ - // >> Select stream - { - title: "Select Stream", - ready: function() { - return $scope.streamReady; - }, - init: function() { - $scope.policy.__.streamName = $scope.policy.__.streamName || - common.array.find($scope.policy.tags.application, _streamList, "tags.application").tags.streamName; - }, - nextable: function() { - var _streamName = common.getValueByPath($scope.policy, "__.streamName"); - if(!_streamName) return false; - - // Detect stream in current data source list - return !!common.array.find(_streamName, $scope.applications[$scope.policy.tags.application], "tags.streamName"); - } - }, - - // >> Define Alert Policy - { - title: "Define Alert Policy", - init: function() { - // Normal mode will fetch meta list - if(!$scope.policy.__.advanced) { - var _stream = _findStream($scope.policy.tags.application, $scope.policy.__.streamName); - $scope._stream = _stream; - - if(!_stream) { - $.dialog({ - title: "OPS", - content: "Stream not found! Current application don't match any stream." - }); - return; - } - - if(!_stream.metas) { - _stream.metas = Entities.queryEntities("AlertStreamSchemaService", {application: $scope.policy.tags.application, streamName: $scope.policy.__.streamName}); - _stream.metas._promise.then(function() { - _stream.metas.sort(function(a, b) { - if(a.tags.attrName < b.tags.attrName) { - return -1; - } else if(a.tags.attrName > b.tags.attrName) { - return 1; - } - return 0; - }); - }); - } - } - }, - ready: function() { - if(!$scope.policy.__.advanced) { - return $scope._stream.metas._promise.$$state.status === 1; - } - return true; - }, - nextable: function() { - if($scope.policy.__.advanced) { - // Check stream source - $scope._stream = null; - $.each($scope.applications[$scope.policy.tags.application], function(i, stream) { - if(($scope.policy.__._expression || "").indexOf(stream.tags.streamName) !== -1) { - $scope._stream = stream; - return false; - } - }); - return $scope._stream; - } else { - // Window - if($scope.policy.__.windowConfig) { - var _winMatch = true; - var _winConds = $scope.getWindow().fields; - $.each(_winConds, function(i, cond) { - if(!(cond.val || "").match(cond.regex)) { - _winMatch = false; - return false; - } - }); - if(!_winMatch) return false; - - // Aggregation - if($scope.policy.__.groupAgg) { - if(!$scope.policy.__.groupAggPath || - !$scope.policy.__.groupCondOp || - !$scope.policy.__.groupCondVal) { - return false; - } - } - } - } - return true; - } - }, - - // >> Configuration & Notification - { - title: "Configuration & Notification", - nextable: function() { - return !!$scope.policy.tags.policyId; - } - } - ]; - - // ========================================== - // = Policy Logic = - // ========================================== - _streamList._promise.then(function() { - // Initial policy entity - if(create) { - $scope.policy = { - __: { - toJSON: jQuery.noop, - conditions: {}, - notification: [], - dedupe: { - alertDedupIntervalMin: 10, - fields: [] - }, - _dedupTags: {}, - policy: {}, - window: "externalTime", - group: "", - groupAgg: "count", - groupAggPath: "timestamp", - groupCondOp: ">=", - groupCondVal: "2" - }, - description: "", - enabled: true, - prefix: "alertdef", - remediationDef: "", - tags: { - application: Application.current().tags.application, - policyType: "siddhiCEPEngine" - } - }; - - // If configured data source - if($wrapState.param.app) { - $scope.policy.tags.application = $wrapState.param.app; - if(common.array.find($wrapState.param.app, Site.current().applicationList, "tags.application")) { - setTimeout(function() { - $scope.changeStep(0, 2, false); - $scope.$apply(); - }, 1); - } - } - - // Start step - $scope.changeStep(0, 1, false); - console.log($scope.policy); - } else { - var _policy = Entities.queryEntity("AlertDefinitionService", $scope.encodedRowkey); - _policy._promise.then(function() { - if(_policy.length) { - $scope.policy = _policy[0]; - $scope.policy.__ = { - toJSON: jQuery.noop - }; - - Site.current(Site.find($scope.policy.tags.site)); - } else { - $.dialog({ - title: "OPS", - content: "Policy not found!" - }, function() { - $wrapState.path("/common/policyList"); - $scope.$apply(); - }); - return; - } - - var _application = Application.current(); - if(_application.tags.application !== $scope.policy.tags.application) { - _application = Application.find($scope.policy.tags.application); - if(_application) { - Application.current(_application, false); - console.log("Application not match. Do reload..."); - $wrapState.reload(); - } else { - $.dialog({ - title: "OPS", - content: "Application not found! Current policy don't match any application." - }, function() { - $location.path("/common/policyList"); - $scope.$apply(); - }); - } - return; - } - - // === Revert inner data === - // >> De-dupe - $scope.policy.__._dedupTags = {}; - $scope.policy.__.dedupe = common.parseJSON($scope.policy.dedupeDef, {}); - $.each($scope.policy.__.dedupe.fields || [], function (i, field) { - $scope.policy.__._dedupTags[field] = true; - }); - - // >> Notification - $scope.policy.__.notification = common.parseJSON($scope.policy.notificationDef, []); - - // >> Policy - var _policyUnit = $scope.policy.__.policy = common.parseJSON($scope.policy.policyDef); - - // >> Parse expression - $scope.policy.__.conditions = {}; - var _condition = _policyUnit.expression.match(/from\s+(\w+)(\[(.*)])?(#window[^\)]*\))?\s+(select (\w+, )?(\w+)\((\w+)\) as [\w\d_]+ (group by (\w+) )?having ([\w\d_]+) ([<>=]+) ([^\s]+))?/); - var _cond_stream = _condition[1]; - var _cond_query = _condition[3] || ""; - var _cond_window = _condition[4]; - var _cond_group = _condition[5]; - var _cond_groupUnit = _condition.slice(7,14); - - if(!_condition) { - $scope.policy.__.advanced = true; - } else { - // > StreamName - var _streamName = _cond_stream; - var _cond = _cond_query; - - $scope.policy.__.streamName = _streamName; - - // > Conditions - // Loop condition groups - if(_cond.trim() !== "" && /^\(.*\)$/.test(_cond)) { - var _condGrps = _cond.substring(1, _cond.length - 1).split(/\)\s+and\s+\(/); - $.each(_condGrps, function(i, line) { - // Loop condition cells - var _condCells = line.split(/\s+or\s+/); - $.each(_condCells, function(i, cell) { - var _opMatch = cell.match(/(\S*)\s*(==|!=|>|<|>=|<=|contains)\s*('(?:[^'\\]|\\.)*'|[\w\d]+)/); - if(!common.isEmpty(_opMatch)) { - var _key = _opMatch[1]; - var _op = _opMatch[2]; - var _val = _opMatch[3]; - var _conds = $scope.policy.__.conditions[_key] = $scope.policy.__.conditions[_key] || []; - var _type = ""; - if(_val.match(/'.*'/)) { - _val = _val.slice(1, -1); - _type = "string"; - } else if(_val === "true" || _val === "false") { - var _regexMatch = _key.match(/^str:regexp\((\w+),'(.*)'\)/); - var _containsMatch = _key.match(/^str:contains\((\w+),'(.*)'\)/); - var _mathes = _regexMatch || _containsMatch; - if(_mathes) { - _key = _mathes[1]; - _val = _mathes[2]; - _type = "string"; - _op = _regexMatch ? "regex" : "contains"; - _conds = $scope.policy.__.conditions[_key] = $scope.policy.__.conditions[_key] || []; - } else { - _type = "bool"; - } - } else { - _type = "number"; - } - _conds.push($scope._CondUnit(_key, _op, _val, _type)); - } - }); - }); - } else if(_cond_query !== "") { - $scope.policy.__.advanced = true; - } - } - - if($scope.policy.__.advanced) { - $scope.policy.__._expression = _policyUnit.expression; - } else { - // > window - if(!_cond_window) { - $scope.policy.__.window = "externalTime"; - $scope.policy.__.group = ""; - $scope.policy.__.groupAgg = "count"; - $scope.policy.__.groupAggPath = "timestamp"; - $scope.policy.__.groupCondOp = ">="; - $scope.policy.__.groupCondVal = "2"; - } else { - try { - $scope.policy.__.windowConfig = true; - - var _winCells = _cond_window.match(/\.(\w+)\((.*)\)/); - $scope.policy.__.window = _winCells[1]; - var _winConds = $scope.getWindow().fields; - $.each(_winCells[2].split(","), function(i, val) { - _winConds[i].val = val; - }); - - // Group - if(_cond_group) { - $scope.policy.__.group = _cond_groupUnit[3]; - $scope.policy.__.groupAgg = _cond_groupUnit[0]; - $scope.policy.__.groupAggPath = _cond_groupUnit[1]; - $scope.policy.__.groupAggAlias = _cond_groupUnit[4] === "aggValue" ? "" : _cond_groupUnit[4]; - $scope.policy.__.groupCondOp = _cond_groupUnit[5]; - $scope.policy.__.groupCondVal = _cond_groupUnit[6]; - } else { - $scope.policy.__.group = ""; - $scope.policy.__.groupAgg = "count"; - $scope.policy.__.groupAggPath = "timestamp"; - $scope.policy.__.groupCondOp = ">="; - $scope.policy.__.groupCondVal = "2"; - } - } catch(err) { - $scope.policy.__.window = "externalTime"; - } - } - } - - $scope.changeStep(0, 2, false); - console.log($scope.policy); - }); - } - }); - - // ========================================== - // = Function = - // ========================================== - // UI: Highlight select step - $scope.stepSelect = function(step) { - return step === $scope.step ? "active" : ""; - }; - - // UI: Collapse all - $scope.collapse = function(cntr) { - var _list = $(cntr).find(".collapse").css("height", "auto"); - if(_list.hasClass("in")) { - _list.removeClass("in"); - } else { - _list.addClass("in"); - } - }; - - // Step process. Will fetch target step attribute and return boolean - function _check(key, step) { - var _step = $scope.steps[step - 1]; - if(!_step) return; - - var _value = _step[key]; - if(typeof _value === "function") { - return _value(); - } else if(typeof _value === "boolean") { - return _value; - } - return true; - } - // Check step is ready. Otherwise will display load animation - $scope.stepReady = function(step) { - return _check("ready", step); - }; - // Check whether process next step. Otherwise will disable next button - $scope.checkNextable = function(step) { - return !_check("nextable", step); - }; - // Switch step - $scope.changeStep = function(step, targetStep, check) { - if(check === false || _check("checkStep", step)) { - $scope.step = targetStep; - - _check("init", targetStep); - } - }; - - // Window - $scope.getWindow = function() { - if(!$scope.policy || !$scope.policy.__) return null; - return common.array.find($scope.policy.__.window, $scope.config.window, "type"); - }; - - // Aggregation - $scope.groupAggPathList = function() { - return $.grep(common.getValueByPath($scope, "_stream.metas", []), function(meta) { - return $.inArray(meta.attrType, ['long','integer','number', 'double', 'float']) !== -1; - }); - }; - - $scope.updateGroupAgg = function() { - $scope.policy.__.groupAggPath = $scope.policy.__.groupAggPath || common.getValueByPath($scope.groupAggPathList()[0], "tags.attrName"); - - if($scope.policy.__.groupAgg === 'count') { - $scope.policy.__.groupAggPath = 'timestamp'; - } - }; - - // Resolver - $scope.resolverTypeahead = function(value, resolver) { - var _resolverList = Entities.query("stream/attributeresolve", { - site: Site.current().tags.site, - resolver: resolver, - query: value - }); - return _resolverList._promise.then(function() { - return _resolverList; - }); - }; - - // Used for input box when pressing enter - $scope.conditionPress = function(event) { - if(event.which == 13) { - setTimeout(function() { - $(event.currentTarget).closest(".input-group").find("button").click(); - }, 1); - } - }; - // Check whether has condition - $scope.hasCondition = function(key, type) { - var _list = common.getValueByPath($scope.policy.__.conditions, key, []); - if(_list.length === 0) return false; - - if(type === "bool") { - return !_list[0].ignored(); - } - return true; - }; - // Condition unit definition - $scope._CondUnit = function(key, op, value, type) { - return { - key: key, - op: op, - val: value, - type: type, - ignored: function() { - return this.type === "bool" && this.val === "none"; - }, - getVal: function() { - return this.type === "string" ? "'" + this.val + "'" : this.val; - }, - toString: function() { - return this.op + " " + this.getVal(); - }, - toCondString: function() { - var _op = this.op === "=" ? "==" : this.op; - if(_op === "regex") { - return "str:regexp(" + this.key + "," + this.getVal() + ")==true"; - } else if(_op === "contains") { - return "str:contains(" + this.key + "," + this.getVal() + ")==true"; - } else { - return this.key + " " + _op + " " + this.getVal(); - } - } - }; - }; - - //for maprfs, if key is status or volume or src/dst, convert these names to id. - $scope.convertToID = function(_condList, key, op, name, type, site){ - if(key == "dst" || key == "src") { - Entities.maprfsNameToID("fNameResolver", name, site)._promise.then( - function(response){ - console.log("success"); - console.log(response); - _condList.push($scope._CondUnit(key, op, response.data, type)); - }, - function(error, status){ - console.log("error: " + status); - } - ); - } - else if (key == "status"){ - Entities.maprfsNameToID("sNameResolver", name, site)._promise.then( - function(response){ - console.log("success"); - console.log(response); - _condList.push($scope._CondUnit(key, op, response.data, type)); - }, - function(error, status){ - console.log("error: " + status); - } - ); - } - else if (key == "volume") { - Entities.maprfsNameToID("vNameResolver", name, site)._promise.then( - function(response){ - console.log("success"); - console.log(response); - _condList.push($scope._CondUnit(key, op, response.data, type)); - }, - function(error, status){ - console.log("error: " + status); - } - ); - } - }; - - // Add condition for policy - $scope.addCondition = function(key, op, value, type) { - if(value === "" || value === undefined) return false; - - var _condList = $scope.policy.__.conditions[key] = $scope.policy.__.conditions[key] || []; - _condList.push($scope._CondUnit(key, op, value, type)); - - //if it is mapr application, covert human readable name to ids - if(Application.current().tags.application == "maprFSAuditLog") { - if ( key == "dst" || key == "src" || key == "volume" || key == "status") { - $scope.convertToID(_condList, key, op, value , type, Site.current().tags.site); - } - } - - return true; - }; - // Convert condition list to description string - $scope.parseConditionDesc = function(key) { - return $.map($scope.policy.__.conditions[key] || [], function(cond) { - if(!cond.ignored()) return "[" + cond.toString() + "]"; - }).join(" or "); - }; - - // To query - $scope.toQuery = function() { - if(!$scope.policy.__) return ""; - - if($scope.policy.__.advanced) return $scope.policy.__._expression; - - // > Query - var _query = $.map(common.getValueByPath($scope.policy, "__.conditions", {}), function(list) { - var _conds = $.map(list, function(cond) { - if(!cond.ignored()) return cond.toCondString(); - }); - if(_conds.length) { - return "(" + _conds.join(" or ") + ")"; - } - }).join(" and "); - if(_query) { - _query = "[" + _query + "]"; - } - - // > Window - var _window = $scope.getWindow(); - var _windowStr = ""; - if($scope.policy.__.windowConfig) { - _windowStr = $.map(_window.fields, function(field) { - return field.val; - }).join(","); - _windowStr = "#window." + _window.type + "(" + _windowStr + ")"; - - // > Group - if($scope.policy.__.group) { - _windowStr += common.template(" select ${group}, ${groupAgg}(${groupAggPath}) as ${groupAggAlias} group by ${group} having ${groupAggAlias} ${groupCondOp} ${groupCondVal}", { - group: $scope.policy.__.group, - groupAgg: $scope.policy.__.groupAgg, - groupAggPath: $scope.policy.__.groupAggPath, - groupCondOp: $scope.policy.__.groupCondOp, - groupCondVal: $scope.policy.__.groupCondVal, - groupAggAlias: $scope.policy.__.groupAggAlias || "aggValue" - }); - } else { - _windowStr += common.template(" select ${groupAgg}(${groupAggPath}) as ${groupAggAlias} having ${groupAggAlias} ${groupCondOp} ${groupCondVal}", { - groupAgg: $scope.policy.__.groupAgg, - groupAggPath: $scope.policy.__.groupAggPath, - groupCondOp: $scope.policy.__.groupCondOp, - groupCondVal: $scope.policy.__.groupCondVal, - groupAggAlias: $scope.policy.__.groupAggAlias || "aggValue" - }); - } - } else { - _windowStr = " select *"; - } - - return common.template("from ${stream}${query}${window} insert into outputStream;", { - stream: $scope.policy.__.streamName, - query: _query, - window: _windowStr - }); - }; - - // ========================================== - // = Update Policy = - // ========================================== - // dedupeDef notificationDef policyDef - $scope.finishPolicy = function() { - $scope.lock = true; - - // dedupeDef - $scope.policy.__.dedupe.fields = $.map($scope.policy.__._dedupTags, function (value, key) { - if(value) return key; - }); - $scope.policy.dedupeDef = JSON.stringify($scope.policy.__.dedupe); - - // notificationDef - $scope.policy.__.notification = $scope.policy.__.notification || []; - - $scope.policy.notificationDef = JSON.stringify($scope.policy.__.notification); - - // policyDef - $scope.policy.__.policy = { - expression: $scope.toQuery(), - type: "siddhiCEPEngine" - }; - $scope.policy.policyDef = JSON.stringify($scope.policy.__.policy); - - // alertExecutorId - if($scope._stream.alertExecutor) { - $scope.policy.tags.alertExecutorId = $scope._stream.alertExecutor.tags.alertExecutorId; - } else { - $scope.lock = false; - $.dialog({ - title: "OPS!", - content: "Alert Executor not defined! Please check 'AlertExecutorService'!" - }); - return; - } - - // site - $scope.policy.tags.site = $scope.policy.tags.site || Site.current().tags.site; - - // owner - $scope.policy.owner = Authorization.userProfile.username; - - // Update function - function _updatePolicy() { - Entities.updateEntity("AlertDefinitionService", $scope.policy)._promise.success(function(data) { - $.dialog({ - title: "Success", - content: (create ? "Create" : "Update") + " success!" - }, function() { - if(data.success) { - location.href = "#/common/policyList"; - } else { - $.dialog({ - title: "OPS", - content: (create ? "Create" : "Update") + "failed!" + JSON.stringify(data) - }); - } - }); - - $scope.create = create = false; - $scope.encodedRowkey = data.obj[0]; - }).error(function(data) { - $.dialog({ - title: "OPS", - content: (create ? "Create" : "Update") + "failed!" + JSON.stringify(data) - }); - }).then(function() { - $scope.lock = false; - }); - } - - // Check if already exist - if($scope.create) { - var _checkList = Entities.queryEntities("AlertDefinitionService", { - alertExecutorId: $scope.policy.tags.alertExecutorId, - policyId: $scope.policy.tags.policyId, - policyType: "siddhiCEPEngine", - application: $scope.policy.tags.application - }); - _checkList._promise.then(function() { - if(_checkList.length) { - $.dialog({ - title: "Override Confirm", - content: "Already exists PolicyID '" + $scope.policy.tags.policyId + "'. Do you want to override?", - confirm: true - }, function(ret) { - if(ret) { - _updatePolicy(); - } else { - $scope.lock = false; - $scope.$apply(); - } - }); - } else { - _updatePolicy(); - } - }); - } else { - _updatePolicy(); - } - }; - }); - } - - feature.controller('policyCreate', function(PageConfig, Site, Policy, $scope, $wrapState, $q, UI, Entities, Application, Authorization, Notification) { - var _args = [true]; - _args.push.apply(_args, arguments); - policyCtrl.apply(this, _args); - }, "policyEdit"); - feature.controller('policyEdit', function(PageConfig, Site, Policy, $scope, $wrapState, $q, UI, Entities, Application, Authorization, Notification) { - PageConfig.lockSite = true; - var _args = [false]; - _args.push.apply(_args, arguments); - policyCtrl.apply(this, _args); - }); - - // ============================================================== - // = Alerts = - // ============================================================== - - // ========================= Alert List ========================= - feature.navItem("alertList", "Alerts", "exclamation-triangle"); - feature.controller('alertList', function(PageConfig, Site, $scope, $wrapState, $interval, $timeout, Entities, Application) { - PageConfig.pageSubTitle = Site.current().tags.site; - - var MAX_PAGESIZE = 10000; - - // Initial load - $scope.application = Application.current(); - - $scope.alertList = []; - $scope.alertList.ready = false; - - // Load data - function _loadAlerts() { - if($scope.alertList._promise) { - $scope.alertList._promise.abort(); - } - - var _list = Entities.queryEntities("AlertService", { - site: Site.current().tags.site, - application: $scope.application.tags.application, - _pageSize: MAX_PAGESIZE, - _duration: 1000 * 60 * 60 * 24 * 30, - __ETD: 1000 * 60 * 60 * 24 - }); - $scope.alertList._promise = _list._promise; - _list._promise.then(function() { - var index; - - if($scope.alertList[0]) { - // List new alerts - for(index = 0 ; index < _list.length ; index += 1) { - var _alert = _list[index]; - _alert.__new = true; - if(_alert.encodedRowkey === $scope.alertList[0].encodedRowkey) { - break; - } - } - - if(index > 0) { - $scope.alertList.unshift.apply($scope.alertList, _list.slice(0, index)); - - // Clean up UI highlight - $timeout(function() { - $.each(_list, function(i, alert) { - delete alert.__new; - }); - }, 100); - } - } else { - // List all alerts - $scope.alertList.push.apply($scope.alertList, _list); - } - - $scope.alertList.ready = true; - }); - } - - _loadAlerts(); - var _loadInterval = $interval(_loadAlerts, app.time.refreshInterval); - $scope.$on('$destroy',function(){ - $interval.cancel(_loadInterval); - }); - }); - - // ======================== Alert Detail ======================== - feature.controller('alertDetail', function(PageConfig, Site, $scope, $wrapState, Entities) { - PageConfig.pageTitle = "Alert Detail"; - PageConfig.lockSite = true; - PageConfig - .addNavPath("Alert List", "/common/alertList") - .addNavPath("Alert Detail"); - - $scope.common = common; - - // Query policy - $scope.alertList = Entities.queryEntity("AlertService", $wrapState.param.filter); - $scope.alertList._promise.then(function() { - if($scope.alertList.length === 0) { - $.dialog({ - title: "OPS!", - content: "Alert not found!" - }, function() { - location.href = "#/common/alertList"; - }); - } else { - $scope.alert = $scope.alertList[0]; - $scope.alert.rawAlertContext = JSON.stringify($scope.alert.alertContext, null, "\t"); - Site.current(Site.find($scope.alert.tags.site)); - console.log($scope.alert); - } - }); - - // UI - $scope.getMessageTime = function(alert) { - var _time = common.getValueByPath(alert, "alertContext.timestamp"); - return Number(_time); - }; - }); -})(); \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/app/public/feature/common/page/alertDetail.html ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/common/page/alertDetail.html b/eagle-webservice/src/main/webapp/app/public/feature/common/page/alertDetail.html deleted file mode 100644 index 309fac3..0000000 --- a/eagle-webservice/src/main/webapp/app/public/feature/common/page/alertDetail.html +++ /dev/null @@ -1,67 +0,0 @@ -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> -<div class="box box-info"> - <div class="box-header with-border"> - <h3 class="box-title" id="policyId"> - {{alert.tags.policyId}} - <small>{{common.format.date(alert.timestamp)}}</small> - </h3> - </div><!-- /.box-header --> - - <div class="box-body"> - <a class="btn btn-primary pull-right" href="#/common/policyDetail/?policy={{alert.tags.policyId}}&site={{alert.tags.site}}&executor={{alert.tags.alertExecutorId}}">View Policy</a> - - <div class="inline-group"> - <dl><dt>Site</dt><dd>{{alert.tags.site}}</dd></dl> - <dl><dt>Data Source</dt><dd>{{alert.tags.application}}</dd></dl> - </div> - <div class="inline-group"> - <dl><dt>Alert Time</dt><dd>{{common.format.date(alert.timestamp)}}</dd></dl> - <dl><dt>Message Time</dt><dd>{{common.format.date(alert.alertContext.properties.timestamp)}}</dd></dl> - </div> - <div class="inline-group"> - <dl><dt>Stream Name</dt><dd>{{alert.tags.sourceStreams}}</dd></dl> - </div> - <div class="inline-group"> - <dl><dt>Alert Source</dt><dd>{{alert.tags.alertSource}}</dd></dl> - </div> - <div class="inline-group"> - <dl><dt>User</dt><dd>{{alert.alertContext.properties.user}}</dd></dl> - <dl><dt>Host</dt><dd>{{alert.alertContext.properties.host}}</dd></dl> - </div> - <div class="inline-group"> - <dl><dt>Event</dt><dd>{{alert.alertContext.properties.alertEvent}}</dd></dl> - </div> - <div class="inline-group"> - <dl><dt>Message</dt><dd>{{alert.alertContext.properties.alertMessage}}</dd></dl> - </div> - </div><!-- /.box-body --> - - <div class="overlay" ng-hide="alertList._promise.$$state.status === 1;"> - <i class="fa fa-refresh fa-spin"></i> - </div> - - <div class="box-footer clearfix"> - <a data-toggle="collapse" href="[data-id='rawAlertContext']"> - Raw Alert Context - </a> - <div data-id="rawAlertContext" class="collapse"> - <pre>{{alert.rawAlertContext}}</pre> - </div> - </div> -</div> http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/app/public/feature/common/page/alertList.html ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/common/page/alertList.html b/eagle-webservice/src/main/webapp/app/public/feature/common/page/alertList.html deleted file mode 100644 index 0415cc0..0000000 --- a/eagle-webservice/src/main/webapp/app/public/feature/common/page/alertList.html +++ /dev/null @@ -1,67 +0,0 @@ -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> -<div class="box box-primary"> - <div class="box-header with-border"> - <i class="fa fa-list-alt"> </i> - <h3 class="box-title"> - {{application.displayName}} - </h3> - </div> - <div class="box-body"> - <p ng-show="!alertList.ready"> - <span class="fa fa-refresh fa-spin"> </span> - Loading... - </p> - - <div sorttable source="alertList" sort="-timestamp"> - <table class="table table-bordered" ng-non-bindable> - <thead> - <tr> - <th width="170" sortpath="timestamp">Alert Time</th> - <th width="170" sortpath="alertContext.properties.timestamp">Message Time</th> - <th width="105" sortpath="tags.application">Application</th> - <th width="150" sortpath="tags.policyId">Policy Name</th> - <th width="60" sortpath="alertContext.properties.user">User</th> - <th width="150" sortpath="tags.alertSource">Source</th> - <th sortpath="alertContext.properties.emailMessage">Description</th> - <th width="50"> </th> - </tr> - </thead> - <tbody> - <tr ng-class="{info : item.__new}"> - <td>{{common.format.date(item.timestamp)}}</td> - <td>{{common.format.date(item.alertContext.properties.timestamp)}}</td> - <td>{{item.tags.application}}</td> - <td class="text-nowrap"> - <a class="fa fa-share-square-o" ng-show="item.tags.policyId" - href="#/common/policyDetail/?policy={{item.tags.policyId}}&site={{item.tags.site}}&executor={{item.tags.alertExecutorId}}"> </a> - {{item.tags.policyId}} - </td> - <td>{{item.alertContext.properties.user}}</td> - <td>{{item.tags.alertSource}}</td> - <td>{{item.alertContext.properties.alertMessage}}</td> - <td><a href="#/common/alertDetail/{{item.encodedRowkey}}">Detail</a></td> - </tr> - </tbody> - </table> - </div> - - </div> - <!--div class="box-footer clearfix"> - </div--> -</div> http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyDetail.html ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyDetail.html b/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyDetail.html deleted file mode 100644 index cdddc43..0000000 --- a/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyDetail.html +++ /dev/null @@ -1,173 +0,0 @@ -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> - -<div class="box box-info"> - <div class="box-header with-border"> - <h3 class="box-title"> - {{policy.tags.policyId}} - <small>{{policy.tags.site}}</small> - </h3> - </div> - - <div class="box-body"> - <div class="row"> - <div class="col-xs-8"> - <div class="inline-group"> - <dl><dt>Data Source</dt><dd>{{policy.tags.application}}</dd></dl> - <dl><dt>Status</dt><dd> - <span ng-show="policy.enabled" class="text-muted"><i class="fa fa-square text-green"></i> Enabled</span> - <span ng-show="!policy.enabled" class="text-muted"><i class="fa fa-square text-muted"></i> Disabled</span> - </dd></dl> - </div> - <div class="inline-group"> - <dl><dt>Description</dt><dd>{{policy.description}}</dd></dl> - </div> - <!--div class="inline-group"> - <dl><dt>Alert</dt><dd> - <a href="mailto:{{mail}}" ng-repeat="mail in policy.__mailList track by $index" style="margin-right: 10px;">{{mail}}</a> - <div tabs> - <pane ng-repeat="notification in policy.__notificationList track by $index" data-title="{{notification.notificationType}}"> - </pane> - </div> - </dd></dl> - </div--> - <label>Notification</label> - <div tabs> - <pane ng-repeat="notification in policy.__notificationList track by $index" data-title="{{notification.notificationType}}"> - <table class="table table-bordered"> - <tbody> - <tr ng-repeat="(key, value) in notification track by $index"> - <th width="30%">{{key}}</th> - <td>{{value}}</td> - </tr> - </tbody> - </table> - </pane> - </div> - </div> - <div class="col-xs-4 text-right" ng-show="Auth.isRole('ROLE_ADMIN')"> - <a class="btn btn-primary" href="#/common/policyEdit/{{policy.encodedRowkey}}">Edit</a> - <button class="btn btn-warning" ng-show="!policy.enabled" ng-click="updatePolicyStatus(policy, true)">Enable</button> - <button class="btn btn-warning" ng-show="policy.enabled" ng-click="updatePolicyStatus(policy, false)">Disable</button> - <button class="btn btn-danger" ng-click="deletePolicy(policy)">Delete</button> - </div> - </div> - </div> - - <div class="overlay" ng-hide="policyList._promise.$$state.status === 1;"> - <i class="fa fa-refresh fa-spin"></i> - </div> - - <div class="box-footer clearfix"> - <a data-toggle="collapse" href="[data-id='query']"> - View Query - </a> - <div data-id="query" class="collapse in"> - <pre>{{policy.__expression}}</pre> - </div> - </div> -</div> - -<div tabs> - <pane data-title="Visualization" menu="visualizationMenu"> - <div class="row"> - <div class="col-xs-6"> - <div nvd3="policyEvalSeries" data-title="Policy Eval Count" data-config="chartConfig" class="nvd3-chart-cntr"></div> - </div> - <div class="col-xs-6"> - <div nvd3="policyEvalFailSeries" data-title="Policy Eval Fail Count" data-config="chartConfig" class="nvd3-chart-cntr"></div> - </div> - <div class="col-xs-6"> - <div nvd3="alertSeries" data-title="Alert Count" data-config="chartConfig" class="nvd3-chart-cntr"></div> - </div> - <div class="col-xs-6"> - <div nvd3="alertFailSeries" data-title="Alert Fail Count" data-config="chartConfig" class="nvd3-chart-cntr"></div> - </div> - </div> - </pane> - <pane data-title="Statistics"> - <div class="row"> - <div class="col-xs-3"> - <div class="info-box bg-aqua"> - <span class="info-box-icon"><i class="fa fa-bookmark-o"></i></span> - <div class="info-box-content"> - <span class="info-box-text">Policy Eval Count</span> - <span class="info-box-number">{{common.array.sum(policyEvalSeries, "1")}} <small>(Monthly)</small></span> - <span class="info-box-number">{{policyEvalSeries[policyEvalSeries.length - 1][1]}} <small>(Daily)</small></span> - </div> - </div> - </div> - <div class="col-xs-3"> - <div class="info-box bg-red"> - <span class="info-box-icon"><i class="fa fa-bookmark-o"></i></span> - <div class="info-box-content"> - <span class="info-box-text">Policy Eval Fail Count</span> - <span class="info-box-number">{{common.array.sum(policyEvalFailSeries, "1")}} <small>(Monthly)</small></span> - <span class="info-box-number">{{policyEvalFailSeries[policyEvalFailSeries.length - 1][1]}} <small>(Daily)</small></span> - </div> - </div> - </div> - <div class="col-xs-3"> - <div class="info-box bg-aqua"> - <span class="info-box-icon"><i class="fa fa-bookmark-o"></i></span> - <div class="info-box-content"> - <span class="info-box-text">Alert Count</span> - <span class="info-box-number">{{common.array.sum(alertSeries, "1")}} <small>(Monthly)</small></span> - <span class="info-box-number">{{alertSeries[alertSeries.length - 1][1]}} <small>(Daily)</small></span> - </div> - </div> - </div> - <div class="col-xs-3"> - <div class="info-box bg-red"> - <span class="info-box-icon"><i class="fa fa-bookmark-o"></i></span> - <div class="info-box-content"> - <span class="info-box-text">Alert Fail Count</span> - <span class="info-box-number">{{common.array.sum(alertFailSeries, "1")}} <small>(Monthly)</small></span> - <span class="info-box-number">{{alertFailSeries[alertFailSeries.length - 1][1]}} <small>(Daily)</small></span> - </div> - </div> - </div> - </div> - </pane> - <pane data-title="Alerts"> - <div sorttable source="alertList" sort="-timestamp"> - <table class="table table-bordered" ng-non-bindable> - <thead> - <tr> - <th width="170" sortpath="timestamp">Alert Time</th> - <th width="170" sortpath="alertContext.properties.timestamp">Message Time</th> - <th width="60" sortpath="alertContext.properties.user">User</th> - <th width="150" sortpath="alertContext.properties.host">Host</th> - <th sortpath="alertContext.properties.emailMessage">Description</th> - <th width="50"> </th> - </tr> - </thead> - <tbody> - <tr ng-class="{info : item.__new}"> - <td>{{common.format.date(item.timestamp)}}</td> - <td>{{common.format.date(item.alertContext.properties.timestamp)}}</td> - <td>{{item.alertContext.properties.user}}</td> - <td>{{item.alertContext.properties.host}}</td> - <td>{{item.alertContext.properties.alertMessage}}</td> - <td><a href="#/common/alertDetail/{{item.encodedRowkey}}">Detail</a></td> - </tr> - </tbody> - </table> - </div> - </pane> -</div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyEdit.html ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyEdit.html b/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyEdit.html deleted file mode 100644 index 33d4cde..0000000 --- a/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyEdit.html +++ /dev/null @@ -1,346 +0,0 @@ -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> -<div class="progress active" ng-show="!streamReady"> - <div class="progress-bar progress-bar-primary progress-bar-striped" style="width: 100%"> - </div> -</div> - -<!-- Step navigation --> -<div ng-show="streamReady"> - <div class="row step-cntr"> - <div class="col-sm-4" ng-repeat="step in steps"> - <div class="step" ng-class="stepSelect($index + 1)"> - <h1>{{$index + 1}}</h1> - <h2>Step {{$index + 1}}</h2> - <p title="{{step.title}}">{{step.title}}</p> - </div> - </div> - </div> - - <!-- Step container --> - <div class="box box-info"> - <div class="box-header with-border"> - <h3 class="box-title">Step {{step}} - {{steps[step - 1].title}}</h3> - </div><!-- /.box-header --> - - <div class="box-body"> - <!-- ---------------------- Step Body Start ---------------------- --> - - <!-- Step 1: Stream --> - <div ng-show="step === 1"> - <div class="pull-right" ng-show="policy.__.advanced === undefined"> - <span class="text-muted">or</span> - <a ng-click="policy.__.advanced = true;">Advanced</a> - </div> - - <div class="form-group"> - <label>Select Stream</label> - <select class="form-control" ng-model="policy.__.streamName" ng-show="!policy.__.advanced"> - <option ng-repeat="stream in applications[policy.tags.application]">{{stream.tags.streamName}}</option> - </select> - <select class="form-control" ng-show="policy.__.advanced" disabled="disabled"> - <option>[Advanced Mode]</option> - </select> - </div> - - <div class="checkbox" ng-show="policy.__.advanced !== undefined"> - <label> - <input type="checkbox" ng-model="policy.__.advanced"> - Advanced Mode - </label> - </div> - </div> - - <!-- Step 2: Define Alert Policy --> - <div ng-show="step === 2 && !policy.__.advanced"> - <!-- Criteria --> - <div> - <label>Match Criteria</label> - <a ng-click="collapse('.panel-group')">expand / collapse all</a> - - <div class="panel-group panel-group-sm" role="tablist"> - <div class="panel panel-default" - ng-repeat="meta in _stream.metas" - ng-init="op = '=='; val = null; type = (meta.attrType || '').toLowerCase();"> - <div class="panel-heading" role="tab"> - <h4 class="panel-title"> - <span class="bg-navy disabled color-palette pull-right"> - {{parseConditionDesc(meta.tags.attrName)}} - </span> - - <a role="button" data-toggle="collapse" href="[data-name='{{meta.tags.attrName}}']" class="collapsed"> - <span class="fa fa-square" ng-class="hasCondition(meta.tags.attrName, type) ? 'text-green' : 'text-muted'"> </span> - {{meta.attrDisplayName || meta.tags.attrName}} - <span class="fa fa-question-circle" ng-show="meta.attrDescription" - uib-tooltip="{{meta.attrDescription}}" tooltip-placement="right" tooltip-animation="false"> </span> - </a> - </h4> - </div> - <div data-name="{{meta.tags.attrName}}" data-type="{{meta.attrType}}" role="tabpanel" class="collapse"> - <div class="panel-body"> - <ul ng-show="type !== 'bool'"> - <li ng-repeat="cond in policy.__.conditions[meta.tags.attrName]"> - [<a ng-click="policy.__.conditions[meta.tags.attrName].splice($index, 1)">X</a>] - {{cond.toString()}} - </li> - </ul> - - <!-- String --> - <div ng-if="type == 'string'"> - <div class="input-group" style="max-width: 450px;"> - <div class="input-group-btn"> - <select class="form-control" ng-model="op"> - <option ng-repeat="mark in ['==','!=','contains','regex']">{{mark}}</option> - </select> - </div> - - <!-- With resolver --> - <input type="text" class="form-control" autocomplete="off" ng-model="val" ng-show="meta.attrValueResolver" - ng-keypress="conditionPress($event, meta.tags.attrName, op, val, type)" - uib-typeahead="item for item in resolverTypeahead($viewValue, meta.attrValueResolver)"> - <!-- Without resolver --> - <input type="text" class="form-control" autocomplete="off" ng-model="val" ng-show="!meta.attrValueResolver" - ng-keypress="conditionPress($event, meta.tags.attrName, op, val, type)"> - - <span class="input-group-btn"> - <button class="btn btn-info btn-flat" type="button" ng-click="addCondition(meta.tags.attrName, op, val, type);val=null;">Add</button> - </span> - </div> - </div> - - <!-- Number --> - <div ng-if="type == 'long' || type == 'integer' || type == 'number' || type == 'double' || type == 'float'"> - <div class="input-group" style="max-width: 450px;"> - <div class="input-group-btn"> - <select class="form-control" ng-model="op"> - <option ng-repeat="mark in ['==','!=','>','>=','<','<=']">{{mark}}</option> - </select> - </div> - - <input type="number" class="form-control" autocomplete="off" placeholder="Number Only..." ng-model="val" ng-keypress="conditionPress($event, meta.tags.attrName, op, val, type)"> - <span class="input-group-btn"> - <button class="btn btn-info btn-flat" type="button" ng-click="addCondition(meta.tags.attrName, op, val, type) ? val=null : void(0);">Add</button> - </span> - </div> - </div> - - <!-- Boolean --> - <div ng-if="type == 'bool'" ng-init="policy.__.conditions[meta.tags.attrName] = policy.__.conditions[meta.tags.attrName] || [_CondUnit(meta.tags.attrName, '==', 'none', 'bool')]"> - <select class="form-control" ng-model="policy.__.conditions[meta.tags.attrName][0].val" style="max-width: 100px;"> - <option ng-repeat="bool in ['none','true','false']">{{bool}}</option> - </select> - </div> - </div> - </div> - </div> - </div> - </div> - - <!-- Window --> - <div class="checkbox"> - <label> - <input type="checkbox" ng-checked="policy.__.windowConfig" ng-click="policy.__.windowConfig = !policy.__.windowConfig"> Slide Window - </label> - </div> - <div ng-show="policy.__.windowConfig"> - <div class="row"> - <div class="col-md-4"> - <div class="form-group"> - <label>Window</label> - <select class="form-control" ng-model="policy.__.window" - uib-tooltip="{{getWindow().description}}" tooltip-animation="false"> - <option ng-repeat="item in config.window" value="{{item.type}}">{{item.title}}</option> - </select> - </div> - </div> - - <!-- fields --> - <div class="col-md-4" ng-repeat="field in getWindow().fields" ng-init="field.val = field.val || (field.defaultValue || '');" ng-hide="field.hide"> - <div class="form-group" ng-class="{'has-warning' : !field.val || !field.val.match(field.regex)}"> - <label>Window - {{field.title}}</label> - <input type="text" class="form-control" autocomplete="off" placeholder="{{field.description}}" ng-model="field.val" title="{{field.description}}"> - </div> - </div> - </div> - - <!-- Aggregation --> - <div class="row"> - <div class="col-md-4"> - <div class="form-group" ng-class="{'text-yellow' : (policy.__.groupAgg && !policy.__.groupAggPath)}"> - <label>Aggregation</label> - <div class="input-group"> - <div class="input-group-btn"> - <select class="form-control" ng-model="policy.__.groupAgg" ng-change="updateGroupAgg()"> - <option ng-repeat="op in ['max','min','avg','count', 'sum']">{{op}}</option> - </select> - </div> - <select class="form-control" ng-model="policy.__.groupAggPath" ng-class="{'has-warning' : !policy.__.groupAggPath}" id="groupAggPath" - ng-show="policy.__.groupAgg" ng-disabled="policy.__.groupAgg === 'count'"> - <option ng-repeat="meta in groupAggPathList()">{{meta.tags.attrName}}</option> - </select> - </div> - </div> - </div> - - <div class="col-md-4"> - <div class="form-group" ng-class="{'text-yellow' : (!policy.__.groupCondOp || !policy.__.groupCondVal)}"> - <label>Condition</label> - <div class="input-group"> - <div class="input-group-btn"> - <select class="form-control" ng-model="policy.__.groupCondOp" ng-class="{'has-warning' : !policy.__.groupCondOp}"> - <option ng-repeat="op in ['>','<','>=','<=','==']">{{op}}</option> - </select> - </div> - <input type="text" class="form-control" ng-model="policy.__.groupCondVal" ng-class="{'has-warning' : !policy.__.groupCondVal}" /> - </div> - </div> - </div> - - <div class="col-md-4"> - <div class="form-group"> - <label>Alias (Optional)</label> - <input type="text" class="form-control" ng-model="policy.__.groupAggAlias" placeholder="Default: aggValue" /> - </div> - </div> - </div> - - <!-- Group --> - <div class="row"> - <div class="col-md-4"> - <div class="form-group"> - <label>Group By</label> - <select class="form-control" ng-model="policy.__.group"> - <option value="">None</option> - <option ng-repeat="meta in _stream.metas">{{meta.tags.attrName}}</option> - </select> - </div> - </div> - </div> - </div> - </div> - - <!-- Step 2: Define Alert Policy --> - <div ng-show="step === 2 && policy.__.advanced"> - <div class="form-group"> - <label>Query Expression</label> - <textarea class="form-control" ng-model="policy.__._expression" - placeholder="Query expression. e.g. from hdfsAuditLogEventStream[(cmd=='open') and (host=='localhost' or host=='127.0.0.1')]#window.time(2 sec) select * insert into outputStream;" rows="5"></textarea> - </div> - </div> - - <!-- Step 3: Email Notification --> - <div ng-show="step === 3"> - <div class="row"> - <div class="col-xs-4"> - <div class="form-group" ng-class="{'has-warning' : !policy.tags.policyId}"> - <label>Policy Name</label> - <input type="text" class="form-control" placeholder="" ng-model="policy.tags.policyId" ng-disabled="!create"> - </div> - </div> - <div class="col-xs-3"> - <div class="form-group"> - <label> - Alert De-Dup Interval(min) - <span class="fa fa-question-circle" uib-tooltip="Same type alert will be De-dup in configured interval"> </span> - </label> - <input type="number" class="form-control" ng-model="policy.__.dedupe.alertDedupIntervalMin" placeholder="[Minute] Number only. Suggestion: 720"> - </div> - </div> - <div class="col-xs-2"> - <div class="form-group"> - <label> - Enabled - </label> - <p> - <input type="checkbox" checked="checked" ng-model="policy.enabled"> - </p> - </div> - </div> - </div> - - <div> - <a data-toggle="collapse" href="[data-id='advancedDeDup']">Advanced De-Dup</a> - <div data-id='advancedDeDup' class="collapse"> - <label> - De-Dup Key - <span class="fa fa-question-circle" uib-tooltip="Type of grouping alerts. If you don't know how to config, leave it default."> </span> - </label> - <div class="form-group"> - <div class="checkbox" ng-repeat="meta in _stream.metas" ng-init="create ? policy.__._dedupTags[meta.tags.attrName] = !!meta.usedAsTag : void(0);"> - <label> - <input type="checkbox" ng-model="policy.__._dedupTags[meta.tags.attrName]"> - {{meta.tags.attrName}} - </label> - </div> - </div> - </div> - </div> - - <hr/> - - <label>Notification</label> - <div tabs menu="menu" holder="notificationTabHolder" ng-show="policy.__.notification.length"> - <pane ng-repeat="notification in policy.__.notification track by $index" data-data="notification" data-title="{{notification.notificationType}}"> - <div class="form-group" ng-repeat="field in Notification.map[notification.notificationType].fieldList track by $index"> - <label>{{field.name}}</label> - <input type="text" class="form-control" ng-model="notification[field.name]"> - </div> - <p class="text-muted" ng-if="Notification.map[notification.notificationType].fieldList.length === 0">No configuration required</p> - </pane> - </div> - <ul ng-show="policy.__.notification.length === 0"> - <li ng-repeat="notification in Notification.list track by $index"> - <a ng-click="newNotification(notification.tags.notificationType)">+ New {{notification.tags.notificationType}} Notification</a> - </li> - </ul> - - <hr/> - - <div class="form-group"> - <label>Description</label> - <textarea class="form-control" placeholder="Policy description" ng-model="policy.description"></textarea> - </div> - - <a data-toggle="collapse" href="[data-id='policyQuery']"> - View Query - </a> - <div class="collapse in" data-id="policyQuery"> - <pre>{{toQuery()}}</pre> - </div> - </div> - - <!-- ----------------------- Step Body End ----------------------- --> - </div><!-- /.box-body --> - - <div class="overlay" ng-hide="stepReady(step)"> - <span class="fa fa-refresh fa-spin"> </span> - </div> - - <div class="box-footer text-right"> - <button class="btn btn-info" ng-show="step > 1" ng-click="changeStep(step, step - 1, false)" ng-disabled="lock"> - Prev <span class="fa fa-arrow-circle-o-left"> </span> - </button> - <button class="btn btn-info" ng-show="step < steps.length" ng-click="changeStep(step, step + 1)" ng-disabled="checkNextable(step) || lock"> - Next <span class="fa fa-arrow-circle-o-right"> </span> - </button> - <button class="btn btn-info" ng-show="step === steps.length" ng-click="finishPolicy()" ng-disabled="checkNextable(step) || lock"> - Done <span class="fa fa-check-circle-o"> </span> - </button> - </div> - </div> -</div> http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyList.html ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyList.html b/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyList.html deleted file mode 100644 index 20a38dd..0000000 --- a/eagle-webservice/src/main/webapp/app/public/feature/common/page/policyList.html +++ /dev/null @@ -1,84 +0,0 @@ -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> -<div class="box box-primary"> - <div class="box-header with-border"> - <i class="fa fa-list-alt"> </i> - <h3 class="box-title"> - {{application.displayName}} - </h3> - </div> - <div class="box-body"> - <div class="row"> - <div class="col-xs-3"> - <div class="search-box"> - <input type="search" class="form-control input-sm" placeholder="Search" ng-model="search" /> - <span class="fa fa-search"> </span> - </div> - </div> - <div class="col-xs-6"> - <div class="inline-group form-inline text-muted"> - <dl><dt><i class="fa fa-square text-green"> </i></dt><dd>Enabled</dd></dl> - <dl><dt><i class="fa fa-square text-muted"> </i></dt><dd>Disabled</dd></dl> - </div> - </div> - <div class="col-xs-3 text-right"> - <a class="btn btn-primary" href="#/common/policyCreate/{{!application ? '' : '?app=' + application.tags.application}}" ng-show="Auth.isRole('ROLE_ADMIN')"> - New Policy - <i class="fa fa-plus-circle"> </i> - </a> - </div> - </div> - - <p ng-show="policyList._promise.$$state.status !== 1"> - <span class="fa fa-refresh fa-spin"> </span> - Loading... - </p> - - <div sorttable source="policyList" ng-show="policyList._promise.$$state.status === 1" search="false" searchfunc="searchFunc"> - <table class="table table-bordered" ng-non-bindable> - <thead> - <tr> - <th width="30" sortpath="enabled"> </th> - <th width="200" sortpath="tags.policyId">Policy Name</th> - <th sortpath="description">Description</th> - <th width="150" sortpath="owner">Owner</th> - <th width="170" sortpath="lastModifiedDate">Last Modified</th> - <th width="95" ng-show="_parent.Auth.isRole('ROLE_ADMIN')">Action</th> - </tr> - </thead> - <tbody> - <tr> - <td><span class='fa fa-square' ng-class="item.enabled ? 'text-green' : 'text-muted'"> </span></td> - <td><a href="#/common/policyDetail/{{item.encodedRowkey}}" style="width: 200px;" class="text-breakall">{{item.tags.policyId}}</a></td> - <td>{{item.description}}</td> - <td>{{item.owner}}</td> - <td>{{common.format.date(item.lastModifiedDate) || "-"}}</td> - <td ng-show="_parent.Auth.isRole('ROLE_ADMIN')"> - <a class="fa fa-pencil btn btn-default btn-xs" uib-tooltip="Edit" tooltip-animation="false" href="#/common/policyEdit/{{item.encodedRowkey}}"> </a> - <button class="fa fa-play sm btn btn-default btn-xs" uib-tooltip="Enable" tooltip-animation="false" ng-show="!item.enabled" ng-click="_parent.updatePolicyStatus(item, true)"> </button> - <button class="fa fa-pause sm btn btn-default btn-xs" uib-tooltip="Disable" tooltip-animation="false" ng-show="item.enabled" ng-click="_parent.updatePolicyStatus(item, false)"> </button> - <button class="rm fa fa-trash-o btn btn-danger btn-xs" uib-tooltip="Delete" tooltip-animation="false" ng-click="_parent.deletePolicy(item)"> </button> - </td> - </tr> - </tbody> - </table> - </div> - </div> - <!--div class="box-footer clearfix"> - </div--> -</div> http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/app/public/feature/metadata/controller.js ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/metadata/controller.js b/eagle-webservice/src/main/webapp/app/public/feature/metadata/controller.js deleted file mode 100644 index c17d612..0000000 --- a/eagle-webservice/src/main/webapp/app/public/feature/metadata/controller.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -(function() { - 'use strict'; - - var featureControllers = angular.module('featureControllers'); - var feature = featureControllers.register("metadata"); - - // ============================================================== - // = Function = - // ============================================================== - - // ============================================================== - // = Metadata = - // ============================================================== - - // ======================= Metadata List ======================== - feature.navItem("streamList", "Metadata", "bullseye"); - feature.controller('streamList', function(PageConfig, Site, $scope, $q, Application, Entities) { - PageConfig.hideSite = true; - - $scope.streams = {}; - $scope._streamEntity = null; - $scope._streamEntityLock = false; - - // =========================================== List =========================================== - var _streamList = Entities.queryEntities("AlertStreamService", {application: Application.current().tags.application}); - var _streamSchemaList = Entities.queryEntities("AlertStreamSchemaService", {application: Application.current().tags.application}); - $scope.streamList = _streamList; - $scope.streamSchemaList = _streamSchemaList; - - _streamList._promise.then(function() { - $.each(_streamList, function(i, stream) { - stream.metaList = []; - $scope.streams[stream.tags.application + "_" + stream.tags.streamName] = stream; - }); - }); - - $q.all([_streamList._promise, _streamSchemaList._promise]).then(function() { - $.each(_streamSchemaList, function(i, meta) { - var _stream = $scope.streams[meta.tags.application + "_" + meta.tags.streamName]; - if(_stream) { - _stream.metaList.push(meta); - } else { - console.warn("[Meta] Stream not match:", meta.tags.application + "_" + meta.tags.streamName); - } - }); - }); - }); -})(); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/app/public/feature/metadata/page/streamList.html ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/metadata/page/streamList.html b/eagle-webservice/src/main/webapp/app/public/feature/metadata/page/streamList.html deleted file mode 100644 index 2b73300..0000000 --- a/eagle-webservice/src/main/webapp/app/public/feature/metadata/page/streamList.html +++ /dev/null @@ -1,84 +0,0 @@ -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> -<p ng-show="streamList._promise.$$state.status !== 1"> - <span class="fa fa-refresh fa-spin"> </span> - Loading... -</p> - -<div class="box box-primary" ng-repeat="stream in streams"> - <div class="box-header with-border"> - <h3 class="box-title">{{stream.tags.streamName}}</h3> - </div> - <div class="box-body"> - <div class="inline-group"> - <dl> - <dt> - Data Source - </dt> - <dd> - {{stream.tags.application}} - </dd> - </dl> - <dl> - <dt> - Stream Name - </dt> - <dd> - {{stream.tags.streamName}} - </dd> - </dl> - </div> - <div> - <dl> - <dt> - Description - </dt> - <dd> - {{stream.description}} - </dd> - </dl> - </div> - - <p ng-show="streamSchemaList._promise.$$state.status !== 1"> - <span class="fa fa-refresh fa-spin"> </span> - Loading... - </p> - - <div class="list" ng-show="streamSchemaList._promise.$$state.status === 1"> - <table class="table table-bordered"> - <thead> - <tr> - <th width="10%">Attribute Name</th> - <th width="12%">Display Name</th> - <th width="8%">Type</th> - <th>Description</th> - </tr> - </thead> - <tbody> - <tr ng-repeat="meta in stream.metaList"> - <td>{{meta.tags.attrName}}</td> - <td>{{meta.attrDisplayName}}</td> - <td><span class="label label-warning">{{meta.attrType}}</span></td> - <td>{{meta.attrDescription}}</td> - </tr> - </tbody> - </table> - </div> - </div><!-- /.box-body --> - <!-- Loading (remove the following to stop the loading)--> -</div> \ No newline at end of file