29 | import {MetricsPanelCtrl} from 'app/plugins/sdk';
30 | import TimeSeries from 'app/core/time_series2';
31 | import _ from 'lodash';
32 |
33 | import { dataProcessingDefaults } from "./dataProcessingDefaults.js";
34 | import { dataProcessingEditor } from "./dataProcessingEditor.js";
35 |
36 | /**
37 | * @alias dataProcessingFeature
38 | * @classdesc <h2>dataProcessingFeature feature</h2>
39 | * Implementation for a feature.<br>
40 | * Makes use of the mediator pattern in order to subscribe the feature to
41 | * the plugin's event, through the $scope reference which is passed to it.
42 | * <br>
43 | * <br><h3>Functionaliy<h3>
44 | * This feature is responsible for managing data from TimeSeries, process it, <br>
45 | * and applying the specified statistic.
46 | * <i>Subscribed events</i>
47 | * <ul>
48 | * <li>init-edit-mode</li>
49 | * <li>data-received</li>
50 | * <li>refresh</li>
51 | * </ul>
52 | */
53 | export default class Feature{
54 | /**
55 | * constructor - description <br>
56 | * Important the use of _.cloneDeep to ensure that no two instances of the same plugin
57 | * share references of the same variables.
58 | *
59 | * @param {type} $scope A reference to the plugin's scope for the subscription to events
60 | * @return {type} New instance of Feature
61 | */
62 | constructor( $scope){
63 | this.$scope = $scope;
64 | this.panelController = $scope.ctrl;
65 | this.panel = this.panelController.panel;
66 |
67 | const defaults = _.cloneDeep(dataProcessingDefaults);
68 | _.defaults( this.panelController.panel, defaults);
69 |
70 | this.panelController.events.on( 'init-edit-mode', this.onInitEditMode.bind(this));
71 | this.panelController.events.on( 'data-received', this.onDataReceived.bind(this));
72 | //this.panelController.events.on( 'panel-initialized', this.onPanelInitialized);
73 | this.panelController.events.on( 'refresh', this.onRefresh.bind(this));
74 | }
75 |
76 | /**
77 | * onInitEditMode - Handler for the event : init-edit-mode<br>
78 | *
79 | * @memberof dataProcessingFeature
80 | */
81 | onInitEditMode(){
82 | this.panelController.addEditorTab( 'DataProcessing', dataProcessingEditor( this.$scope), 2);
83 | }
84 |
85 | /**
86 | * onDataReceived - Handler for the event : data-received<br>
87 | * When new data is received, it is converted into a simpler data structure;<br>
88 | * then the selected statistic is applied to each of the metrics received.
89 | *
90 | * @param {type} dataList description
91 | * @memberof dataProcessingFeature
92 | */
93 | onDataReceived( dataList){
94 | if( dataList.length > 0){
95 | this.panel.rawData = dataList;
96 | let data = dataList.map( this.seriesHandler.bind( this));
97 | this.panel.data = [];
98 | this.panel.data = data.map( this.mapSeriesToValue.bind( this));
99 | }else{ return;}
100 | this.panelController.render();
101 | }
102 |
103 | /**
104 | * onRefresh - Handler for the event : refresh<br>
105 | * When configuration is modified, data is converted into a simpler data structure;<br>
106 | * then the selected statistic is applied to each of the metrics received.<br>
107 | * <i>Previous data received, stored in the rawData attribute, is used.</i>
108 | *
109 | * @memberof dataProcessingFeature
110 | */
111 | onRefresh(){
112 | if( this.panel.rawData.length > 0){
113 | let data = this.panel.rawData.map( this.seriesHandler.bind( this));
114 | this.panel.data = data.map( this.mapSeriesToValue.bind( this));
115 | }else{ return;}
116 | this.panelController.render();
117 | }
118 |
119 | /**
120 | * seriesHandler - Extracts a simpler data structure.<br>
121 | *
122 | * @param {type} dataList Original data structure
123 | * @return {TimeSeries} TimeSeries created from the original one
124 | * @memberof dataProcessingFeature
125 | */
126 | seriesHandler( dataList){
127 | //tratar nulos
128 | let series = new TimeSeries({
129 | datapoints: dataList.datapoints,
130 | alias: dataList.target
131 | });
132 | return( series);
133 | }
134 |
135 | /**
136 | * mapSeriesToValue - Applies statistics to obtain a [metric, value] pair from a TimeSeries.<br>
137 | *
138 | * @param {Timeseries} timeseries receives a timeseries object containing all values registered for
139 | * a metric.
140 | * @return {Object} Object containing both the name and value for a specific metric.
141 | * @memberof dataProcessingFeature
142 | */
143 | mapSeriesToValue( timeseries){
144 | let value = {};
145 | value['metric'] = timeseries.id;
146 | const elements = timeseries.datapoints.map(function(s){ return( s[0]);});
147 |
148 | switch( this.panel.dataProcessing.valueStat){
149 | case 'min':
150 | value['value'] = Math.min( ...elements);
151 | break;
152 | case 'max':
153 | value['value'] = Math.max( ...elements);
154 | break;
155 | case 'avg':
156 | value['value'] = elements.reduce( (a,b)=>a+b, 0) / timeseries.datapoints.length
157 | break;
158 | case 'current':
159 | value['value'] = elements[ timeseries.datapoints.length -1];
160 | break;
161 | case 'total':;
162 | value['value'] = elements.reduce( (a,b)=>a+b, 0);
163 | break;
164 | case 'first':
165 | value['value'] = elements[0];
166 | break;
167 | case 'diff':
168 | const pairs = _.map( elements, (a,b,c)=>{ return (b< c.length -1)?([a, c[b+1]]):([0,0]); });
169 | const differences = _.map( pairs, (a)=>{return Math.abs(a[0]-a[1]);});
170 | value['value'] =_.max( differences);
171 | break;
172 | case 'range':
173 | value['value'] = _.max(elements) - _.min(elements);
174 | break;
175 | case 'last_time':
176 | value['value'] = timeseries.datapoints[ timeseries.datapoints.length -1][1];
177 | break;
178 | }
179 | return( value);
180 | }
181 | }
182 |
183 |
184 |