123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- /**
- * 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.WidgetWizardStep2Controller = Em.Controller.extend({
- name: "widgetWizardStep2Controller",
- EXPRESSION_PREFIX: 'Expression',
- /**
- * @type {RegExp}
- * @const
- */
- EXPRESSION_REGEX: /\$\{([\w\s\.\,\+\-\*\/\(\)\:\=\[\]]*)\}/g,
- /**
- * list of operators that can be used in expression
- * @type {Array}
- * @constant
- */
- OPERATORS: ["+", "-", "*", "/", "(", ")"],
- /**
- * actual values of properties in API format
- * @type {object}
- */
- widgetProperties: {},
- /**
- * @type {Array}
- */
- widgetValues: [],
- /**
- * @type {Array}
- */
- widgetMetrics: [],
- /**
- * @type {Array}
- */
- expressions: [],
- /**
- * used only for GRAPH widget
- * @type {Array}
- */
- dataSets: [],
- /**
- * content of template of Template widget
- * @type {string}
- */
- templateValue: '',
- /**
- * views of properties
- * @type {Array}
- */
- widgetPropertiesViews: [],
- /**
- * @type {boolean}
- */
- isEditWidget: function () {
- return this.get('content.controllerName') === 'widgetEditController';
- }.property('content.controllerName'),
- /**
- * metrics filtered by type
- * @type {Array}
- */
- filteredMetrics: function () {
- var type = this.get('content.widgetType');
- return this.get('content.allMetrics').filter(function (metric) {
- if (type === 'GRAPH') {
- return metric.temporal;
- } else {
- return metric.point_in_time;
- }
- }, this);
- }.property('content.allMetrics'),
- /**
- * @type {boolean}
- */
- isSubmitDisabled: function() {
- if (this.get('widgetPropertiesViews').someProperty('isValid', false)) {
- return true;
- }
- switch (this.get('content.widgetType')) {
- case "NUMBER":
- case "GAUGE":
- return !this.isExpressionComplete(this.get('expressions')[0]);
- case "GRAPH":
- return !this.isGraphDataComplete(this.get('dataSets'));
- case "TEMPLATE":
- return !this.isTemplateDataComplete(this.get('expressions'), this.get('templateValue'));
- }
- return false;
- }.property(
- 'widgetPropertiesViews.@each.isValid',
- 'dataSets.@each.label',
- 'templateValue'
- ),
- /**
- * check whether data of expression is complete
- * @param {Em.Object} expression
- * @returns {boolean}
- */
- isExpressionComplete: function (expression) {
- return Boolean(expression && !expression.get('isInvalid') && !expression.get('isEmpty'));
- },
- /**
- * check whether data of graph widget is complete
- * @param dataSets
- * @returns {boolean} isComplete
- */
- isGraphDataComplete: function (dataSets) {
- var isComplete = Boolean(dataSets.length);
- for (var i = 0; i < dataSets.length; i++) {
- if (dataSets[i].get('label').trim() === '' || !this.isExpressionComplete(dataSets[i].get('expression'))) {
- isComplete = false;
- break;
- }
- }
- return isComplete;
- },
- /**
- * check whether data of template widget is complete
- * @param {Array} expressions
- * @param {string} templateValue
- * @returns {boolean} isComplete
- */
- isTemplateDataComplete: function (expressions, templateValue) {
- var isComplete = Boolean(expressions.length > 0 && templateValue.trim() !== '');
- if (isComplete) {
- for (var i = 0; i < expressions.length; i++) {
- if (!this.isExpressionComplete(expressions[i])) {
- isComplete = false;
- break;
- }
- }
- }
- return isComplete;
- },
- /**
- * Add data set
- * @param {object|null} event
- * @param {boolean} isDefault
- * @returns {number} id
- */
- addDataSet: function(event, isDefault) {
- var id = (isDefault) ? 1 :(Math.max.apply(this, this.get('dataSets').mapProperty('id')) + 1);
- this.get('dataSets').pushObject(Em.Object.create({
- id: id,
- label: Em.I18n.t('dashboard.widgets.wizard.step2.dataSeries').format(id),
- isRemovable: !isDefault,
- expression: Em.Object.create({
- data: [],
- isInvalid: false,
- isEmpty: function () {
- return (this.get('data.length') === 0);
- }.property('data.length')
- })
- }));
- return id;
- },
- /**
- * Remove data set
- * @param {object} event
- */
- removeDataSet: function(event) {
- this.get('dataSets').removeObject(event.context);
- },
- /**
- * Add expression
- * @param {object|null} event
- * @param {boolean} isDefault
- * @returns {number} id
- */
- addExpression: function(event, isDefault) {
- var id = (isDefault) ? 1 :(Math.max.apply(this, this.get('expressions').mapProperty('id')) + 1);
- this.get('expressions').pushObject(Em.Object.create({
- id: id,
- isRemovable: !isDefault,
- data: [],
- alias: '{{' + this.get('EXPRESSION_PREFIX') + id + '}}',
- isInvalid: false,
- isEmpty: function () {
- return (this.get('data.length') === 0);
- }.property('data.length')
- }));
- return id;
- },
- /**
- * Remove expression
- * @param {object} event
- */
- removeExpression: function(event) {
- this.get('expressions').removeObject(event.context);
- },
- /**
- * initialize data
- * widget should have at least one expression or dataSet
- */
- initWidgetData: function() {
- this.set('widgetProperties', this.get('content.widgetProperties'));
- this.set('widgetValues', this.get('content.widgetValues'));
- this.set('widgetMetrics', this.get('content.widgetMetrics'));
- if (this.get('expressions.length') === 0) {
- this.addExpression(null, true);
- }
- if (this.get('dataSets.length') === 0) {
- this.addDataSet(null, true);
- }
- },
- /**
- * update preview widget with latest expression data
- * Note: in order to draw widget it should be converted to API format of widget
- */
- updateExpressions: function () {
- var widgetType = this.get('content.widgetType');
- var expressionData = {
- values: [],
- metrics: []
- };
- if (this.get('expressions').length > 0 && this.get('dataSets').length > 0) {
- switch (widgetType) {
- case 'GAUGE':
- case 'NUMBER':
- expressionData = this.parseExpression(this.get('expressions')[0]);
- expressionData.values = [
- {
- name: "",
- value: expressionData.value
- }
- ];
- break;
- case 'TEMPLATE':
- expressionData = this.parseTemplateExpression(this.get('templateValue'), this.get('expressions'));
- break;
- case 'GRAPH':
- expressionData = this.parseGraphDataset(this.get('dataSets'));
- break;
- }
- }
- this.set('widgetValues', expressionData.values);
- this.set('widgetMetrics', expressionData.metrics);
- }.observes('templateValue', 'dataSets.@each.label'),
- /**
- * parse Graph data set
- * @param {Array} dataSets
- * @returns {{metrics: Array, values: Array}}
- */
- parseGraphDataset: function (dataSets) {
- var metrics = [];
- var values = [];
- dataSets.forEach(function (dataSet) {
- var result = this.parseExpression(dataSet.get('expression'));
- metrics.pushObjects(result.metrics);
- values.push({
- name: dataSet.get('label'),
- value: result.value
- });
- }, this);
- return {
- metrics: metrics,
- values: values
- };
- },
- /**
- * parse expression from template
- * @param {string} templateValue
- * @param {Array} expressions
- * @returns {{metrics: Array, values: {value: *}[]}}
- */
- parseTemplateExpression: function (templateValue, expressions) {
- var metrics = [];
- var self = this;
- var expression = templateValue.replace(/\{\{Expression[\d]\}\}/g, function (exp) {
- var result;
- if (expressions.someProperty('alias', exp)) {
- result = self.parseExpression(expressions.findProperty('alias', exp));
- metrics.pushObjects(result.metrics);
- return result.value;
- }
- return exp;
- });
- return {
- metrics: metrics,
- values: [
- {
- value: expression
- }
- ]
- };
- },
- /**
- *
- * @param {object} expression
- * @returns {{metrics: Array, value: string}}
- */
- parseExpression: function (expression) {
- var value = '';
- var metrics = [];
- if (expression.data.length > 0) {
- value = '${';
- expression.data.forEach(function (element) {
- if (element.isMetric) {
- var metricObj = {
- "name": element.name,
- "service_name": element.serviceName,
- "component_name": element.componentName,
- "metric_path": element.metricPath
- };
- if (element.hostComponentCriteria) {
- metricObj.host_component_criteria = element.hostComponentCriteria;
- }
- metrics.push(metricObj);
- }
- value += element.name;
- }, this);
- value += '}';
- }
- return {
- metrics: metrics,
- value: value
- };
- },
- /**
- * update properties of preview widget
- */
- updateProperties: function () {
- var result = {};
- this.get('widgetPropertiesViews').forEach(function (property) {
- for (var key in property.valueMap) {
- result[property.valueMap[key]] = property.get(key);
- }
- });
- this.set('widgetProperties', result);
- }.observes('widgetPropertiesViews.@each.value', 'widgetPropertiesViews.@each.bigValue', 'widgetPropertiesViews.@each.smallValue'),
- /*
- * Generate the thresholds, unit, time range.etc object based on the widget type selected in previous step.
- */
- renderProperties: function () {
- var widgetProperties = App.WidgetType.find(this.get('content.widgetType')).get('properties');
- var propertiesData = this.get('widgetProperties');
- var result = [];
- widgetProperties.forEach(function (property) {
- var definition = App.WidgetPropertyTypes.findProperty('name', property.name);
- property = $.extend({}, property);
- //restore previous values
- for (var key in definition.valueMap) {
- if (propertiesData[definition.valueMap[key]]) {
- property[key] = propertiesData[definition.valueMap[key]];
- }
- }
- result.pushObject(App.WidgetProperty.create($.extend(definition, property)));
- });
- this.set('widgetPropertiesViews', result);
- },
- /**
- * convert data with model format to editable format
- * Note: in order to edit widget expression it should be converted to editable format
- */
- convertData: function() {
- var self = this;
- var expressionId = 0;
- var widgetValues = this.get('content.widgetValues');
- var widgetMetrics = this.get('content.widgetMetrics');
- this.get('expressions').clear();
- this.get('dataSets').clear();
- if (widgetValues.length > 0) {
- switch (this.get('content.widgetType')) {
- case 'NUMBER':
- case 'GAUGE':
- var id = this.addExpression(null, true);
- this.get('expressions').findProperty('id', id).set('data', this.parseValue(widgetValues[0].value, widgetMetrics)[0]);
- break;
- case 'TEMPLATE':
- this.parseValue(widgetValues[0].value, widgetMetrics).forEach(function (item, index) {
- var id = this.addExpression(null, (index === 0));
- this.get('expressions').findProperty('id', id).set('data', item);
- }, this);
- this.set('templateValue', widgetValues[0].value.replace(this.get('EXPRESSION_REGEX'), function () {
- return '{{' + self.get('EXPRESSION_PREFIX') + ++expressionId + '}}';
- }));
- break;
- case 'GRAPH':
- widgetValues.forEach(function (value, index) {
- var id = this.addDataSet(null, (index === 0));
- var dataSet = this.get('dataSets').findProperty('id', id);
- dataSet.set('label', value.name);
- dataSet.set('expression.data', this.parseValue(value.value, widgetMetrics)[0]);
- }, this);
- break;
- }
- }
- },
- /**
- * parse value
- * @param value
- * @param metrics
- * @returns {Array}
- */
- parseValue: function(value, metrics) {
- var pattern = this.get('EXPRESSION_REGEX'),
- expressions = [],
- match;
- while (match = pattern.exec(value)) {
- expressions.push(this.getExpressionData(match[1], metrics));
- }
- return expressions;
- },
- /**
- * format values into expression data objects
- * @param {string} expression
- * @param {Array} metrics
- * @returns {Array}
- */
- getExpressionData: function(expression, metrics) {
- var str = '';
- var data = [];
- var id = 0;
- for (var i = 0, l = expression.length; i < l; i++) {
- if (this.get('OPERATORS').contains(expression[i])) {
- if (str.trim().length > 0) {
- data.pushObject(this.getExpressionVariable(str.trim(), ++id, metrics));
- str = '';
- }
- data.pushObject(Em.Object.create({
- id: ++id,
- name: expression[i],
- isOperator: true
- }));
- } else {
- str += expression[i];
- }
- }
- if (str.trim().length > 0) {
- data.pushObject(this.getExpressionVariable(str.trim(), ++id, metrics));
- }
- return data;
- },
- /**
- * get variable of expression
- * could be name of metric "m1" or constant number "1"
- * @param {string} name
- * @param {Array} metrics
- * @param {number} id
- * @returns {Em.Object}
- */
- getExpressionVariable: function (name, id, metrics) {
- var metric;
- if (isNaN(Number(name))) {
- metric = metrics.findProperty('name', name);
- return Em.Object.create({
- id: id,
- name: metric.name,
- isMetric: true,
- componentName: metric.component_name,
- serviceName: metric.service_name,
- metricPath: metric.metric_path,
- hostComponentCriteria: metric.host_component_criteria
- });
- } else {
- return Em.Object.create({
- id: id,
- name: name,
- isNumber: true
- });
- }
- },
- next: function () {
- App.router.send('next');
- }
- });
|