/** * 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. */ var App = require('app'); App.AlertConfigProperty = Ember.Object.extend({ /** * label to be shown for config property * @type {String} */ label: '', /** * config property value * @type {*} */ value: null, /** * property value cache to realise undo function * @type {*} */ previousValue: null, /** * define either input is disabled or enabled * @type {Boolean} */ isDisabled: false, /** * options that Select list will have * @type {Array} */ options: [], /** * input displayType * one of 'textFields', 'textArea', 'select' or 'threshold' * @type {String} */ displayType: '', /** * unit to be shown with value * @type {String} */ unit: null, /** * space separated list of css class names to use * @type {String} */ classNames: '', /** * define whether row with property should be shifted right * @type {Boolean} */ isShifted: false, /** * name or names of properties related to config * may be either string for one property or array of strings for multiple properties * if this property is array, then apiFormattedValue should also be an array * example: apiProperty[0] relates to apiFormattedValue[0] * @type {String|Array} */ apiProperty: '', /** * for some metrics properties may be set true or false * depending on what property is related to (JMX or Ganglia) */ isJMXMetric: null, /** * define place to show label * if true - label is shown before input * if false - label is shown after input * @type {Boolean} */ isPreLabeled: function () { var afterLabeledTypes = ['radioButton']; return !afterLabeledTypes.contains(this.get('displayType')); }.property('displayType'), /** * value converted to appropriate format for sending to server * should be computed property * should be defined in child class * @type {*} */ apiFormattedValue: function () { return this.get('value'); }.property('value'), /** * define if property was changed by user * @type {Boolean} */ wasChanged: function () { return this.get('previousValue') !== null && this.get('value') !== this.get('previousValue'); }.property('value', 'previousValue'), /** * view class according to displayType * @type {Em.View} */ viewClass: function () { var displayType = this.get('displayType'); switch (displayType) { case 'textField': return App.AlertConfigTextFieldView; case 'textArea': return App.AlertConfigTextAreaView; case 'select': return App.AlertConfigSelectView; case 'threshold': return App.AlertConfigThresholdView; case 'radioButton': return App.AlertConfigRadioButtonView; default: console.error('Unable to find viewClass for displayType ', displayType); } }.property('displayType'), /** * Define whether property is valid * Computed property * Should be defined in child class * @type {Boolean} */ isValid: function () { return true; }.property(), /** * Array of a group of configs, that current config property relates to * Should be set in controller in rendering configs function * Used to get access to other configs properties of one group * @type {App.AlertConfigProperty[]} */ allConfigs: [] }); App.AlertConfigProperties = { AlertName: App.AlertConfigProperty.extend({ name: 'alert_name', label: 'Alert Name', displayType: 'textField', classNames: 'alert-text-input', apiProperty: 'name' }), AlertNameSelected: App.AlertConfigProperty.extend({ name: 'alert_name', label: 'Alert Name', displayType: 'select', apiProperty: 'name' }), ServiceAlertType: App.AlertConfigProperty.extend({ name: 'alert_type_service', label: 'Service Alert Definition', displayType: 'radioButton', group: 'alert_type' }), HostAlertType: App.AlertConfigProperty.extend({ name: 'alert_type_host', label: 'Host Alert Definition', displayType: 'radioButton', group: 'alert_type' }), Service: App.AlertConfigProperty.extend({ name: 'service', label: 'Service', displayType: 'select', apiProperty: 'service_name', apiFormattedValue: function () { return App.StackService.find().findProperty('displayName', this.get('value')).get('serviceName'); }.property('value') }), Component: App.AlertConfigProperty.extend({ name: 'component', label: 'Component', displayType: 'select', apiProperty: 'component_name', apiFormattedValue: function () { return App.StackServiceComponent.find().findProperty('displayName', this.get('value')).get('componentName'); }.property('value') }), Scope: App.AlertConfigProperty.extend({ name: 'scope', label: 'Scope', displayType: 'select', apiProperty: 'scope', apiFormattedValue: function () { return this.get('value').toUpperCase(); }.property('value') }), Description: App.AlertConfigProperty.extend({ name: 'description', label: 'Description', displayType: 'textArea', classNames: 'alert-config-text-area', // todo: check value after API will be provided apiProperty: 'description' }), Interval: App.AlertConfigProperty.extend({ name: 'interval', label: 'Interval', displayType: 'textField', unit: 'Minute', classNames: 'alert-interval-input', apiProperty: 'interval', isValid: function () { var value = this.get('value'); if (!value) return false; value = ('' + value).trim(); return !isNaN(value) && value >= 1; }.property('value') }), /** * Implements threshold * Main difference from other alertConfigProperties: * it has two editable parts - value and text * User may configure it to edit only one of them (use flags showInputForValue and showInputForText) * This flags also determines update value and text in the API-request or not (see App.AlertConfigProperties.Thresholds for more examples) * * @type {App.AlertConfigProperty.Threshold} */ Threshold: App.AlertConfigProperty.extend({ name: 'threshold', /** * Property text cache to realise undo function * @type {*} */ previousText: null, label: '', /** * OK|WARNING|CRITICAL * @type {string} */ badge: '', /** * threshold-value * @type {string} */ value: '', /** * Type of value. This will be a fixed set of types (like %). */ valueMetric: null, /** * Value actually displayed to the user. This value is transformed * based on the limited types of 'valueMetric's. Mappings from * 'value' to 'displayValue' is handled by observers. */ displayValue: '', /** * threshold-text * @type {string} */ text: '', displayType: 'threshold', classNames: 'alert-thresholds-input', apiProperty: [], init: function () { this.valueWasChanged(); this._super(); }, /** * @type {string[]} */ apiFormattedValue: function () { var ret = []; if (this.get('showInputForValue')) { ret.push(this.get('value')); } if (this.get('showInputForText')) { ret.push(this.get('text')); } return ret; }.property('value', 'text', 'showInputForValue', 'showInputForText'), /** * Determines if value should be visible and editable (if not - won't update API-value) * @type {bool} */ showInputForValue: true, /** * Determines if text should be visible and editable (if not - won't update API-text) * @type {bool} */ showInputForText: true, /** * Custom css-class for different badges * type {string} */ badgeCssClass: function () { return 'alert-state-' + this.get('badge'); }.property('badge'), /** * Determines if value or text were changed * @type {bool} */ wasChanged: function () { return (this.get('previousValue') !== null && this.get('value') !== this.get('previousValue')) || (this.get('previousText') !== null && this.get('text') !== this.get('previousText')); }.property('value', 'text', 'previousValue', 'previousText'), valueWasChanged: function () { var value = this.get('value'); var valueMetric = this.get('valueMetric'); var displayValue = this.get('displayValue'); var newDisplayValue = value; if (value && '%' == valueMetric && !isNaN(value)) { newDisplayValue = (Number(value) * 100) + ''; } if (newDisplayValue != displayValue) { this.set('displayValue', newDisplayValue); } }.observes('value', 'valueMetric'), displayValueWasChanged: function () { var value = this.get('value'); var valueMetric = this.get('valueMetric'); var displayValue = this.get('displayValue'); var newValue = displayValue; if (displayValue && '%' == valueMetric && !isNaN(displayValue)) { newValue = (Number(displayValue) / 100) + ''; } if (newValue != value) { this.set('value', newValue); } }.observes('displayValue', 'valueMetric') }), URI: App.AlertConfigProperty.extend({ name: 'uri', label: 'URI', displayType: 'textField', classNames: 'alert-text-input', apiProperty: 'source.uri' }), URIExtended: App.AlertConfigProperty.extend({ name: 'uri', label: 'URI', displayType: 'textArea', classNames: 'alert-config-text-area', apiProperty: 'source.uri', apiFormattedValue: function () { var result = {}; try { result = JSON.parse(this.get('value')); } catch (e) { console.error('Wrong format of URI'); } return result; }.property('value') }), DefaultPort: App.AlertConfigProperty.extend({ name: 'default_port', label: 'Default Port', displayType: 'textField', classNames: 'alert-port-input', apiProperty: 'source.default_port' }), Path: App.AlertConfigProperty.extend({ name: 'path', label: 'Path', displayType: 'textField', classNames: 'alert-text-input', apiProperty: 'source.path' }), Metrics: App.AlertConfigProperty.extend({ name: 'metrics', label: 'JMX/Ganglia Metrics', displayType: 'textArea', classNames: 'alert-config-text-area', apiProperty: function () { return this.get('isJMXMetric') ? 'source.jmx.property_list' : 'source.ganglia.property_list' }.property('isJMXMetric'), apiFormattedValue: function () { return this.get('value').split(',\n'); }.property('value') }), FormatString: App.AlertConfigProperty.extend({ name: 'metrics_string', label: 'Format String', displayType: 'textArea', classNames: 'alert-config-text-area', apiProperty: function () { return this.get('isJMXMetric') ? 'source.jmx.value' : 'source.ganglia.value' }.property('isJMXMetric') }) }; App.AlertConfigProperties.Thresholds = { OkThreshold: App.AlertConfigProperties.Threshold.extend({ badge: 'OK', name: 'ok_threshold', apiProperty: function () { var ret = []; if (this.get('showInputForValue')) { ret.push('source.reporting.ok.value'); } if (this.get('showInputForText')) { ret.push('source.reporting.ok.text'); } return ret; }.property('showInputForValue', 'showInputForText') }), WarningThreshold: App.AlertConfigProperties.Threshold.extend({ badge: 'WARNING', name: 'warning_threshold', apiProperty: function () { var ret = []; if (this.get('showInputForValue')) { ret.push('source.reporting.warning.value'); } if (this.get('showInputForText')) { ret.push('source.reporting.warning.text'); } return ret; }.property('showInputForValue', 'showInputForText'), isValid: function () { var value = this.get('value'); if (!value) return false; value = ('' + value).trim(); if (this.get('showInputForValue') && this.get('valueMetric') == '%') { return !isNaN(value) && value > 0 && value <= 1.0; } else if (this.get('showInputForValue')) { return !isNaN(value) && value > 0; } else { return true; } }.property('value', 'showInputForValue') }), CriticalThreshold: App.AlertConfigProperties.Threshold.extend({ badge: 'CRITICAL', name: 'critical_threshold', apiProperty: function () { var ret = []; if (this.get('showInputForValue')) { ret.push('source.reporting.critical.value'); } if (this.get('showInputForText')) { ret.push('source.reporting.critical.text'); } return ret; }.property('showInputForValue', 'showInputForText'), isValid: function () { var value = this.get('value'); if (!value) return false; value = ('' + value).trim(); if (this.get('showInputForValue') && this.get('valueMetric') == '%') { return !isNaN(value) && value > 0 && value <= 1.0; } else if (this.get('showInputForValue')) { return !isNaN(value) && value > 0; } else { return true; } }.property('value', 'showInputForValue') }) };