[Summary Widget] support enum fields (#2406)

* Display a drop down menu if the selected key is of type enum.

* Create normalized dataum when persisting telemerty datum using  metadatum source as key.:

* * Clear config values before creating new inputs.
* Emit ‘change' event with the value of the first option after creating the select element.
* If a value is a number, pass it as a number when emitting ‘change’. Similarly, if the cashed telemetry value is a number, convert it to number before applying the operation and validation.

* Update description.

* Update description in operations.js also.
This commit is contained in:
Pegah Sarram 2019-05-24 09:18:46 -07:00 committed by Andrew Henry
parent 35d0c02bc5
commit 72ea7b80fd
5 changed files with 114 additions and 30 deletions

View File

@ -70,16 +70,14 @@ define([
*/
function onValueInput(event) {
var elem = event.target,
value = (isNaN(elem.valueAsNumber) ? elem.value : elem.valueAsNumber),
value = isNaN(Number(elem.value)) ? elem.value : Number(elem.value),
inputIndex = self.valueInputs.indexOf(elem);
if (elem.tagName.toUpperCase() === 'INPUT') {
self.eventEmitter.emit('change', {
value: value,
property: 'values[' + inputIndex + ']',
index: self.index
});
}
self.eventEmitter.emit('change', {
value: value,
property: 'values[' + inputIndex + ']',
index: self.index
});
}
this.listenTo(this.deleteButton, 'click', this.remove, this);
@ -108,8 +106,7 @@ define([
Object.values(this.selects).forEach(function (select) {
$('.t-configuration', self.domElement).append(select.getDOM());
});
this.listenTo($(this.domElement), 'input', onValueInput);
this.listenTo($('.t-value-inputs', this.domElement), 'input', onValueInput);
}
Condition.prototype.getDOM = function (container) {
@ -167,7 +164,9 @@ define([
/**
* When an operation is selected, create the appropriate value inputs
* and add them to the view
* and add them to the view. If an operation is of type enum, create
* a drop-down menu instead.
*
* @param {string} operation The key of currently selected operation
*/
Condition.prototype.generateValueInputs = function (operation) {
@ -176,25 +175,49 @@ define([
inputCount,
inputType,
newInput,
index = 0;
index = 0,
emitChange = false;
inputArea.html('');
this.valueInputs = [];
this.config.values = [];
if (evaluator.getInputCount(operation)) {
inputCount = evaluator.getInputCount(operation);
inputType = evaluator.getInputType(operation);
while (index < inputCount) {
if (!this.config.values[index]) {
this.config.values[index] = (inputType === 'number' ? 0 : '');
if (inputType === 'select') {
newInput = $('<select>' + this.generateSelectOptions() + '</select>');
emitChange = true;
} else {
this.config.values[index] = inputType === 'number' ? 0 : '';
newInput = $('<input type = "' + inputType + '" value = "' + this.config.values[index] + '"> </input>');
}
newInput = $('<input type = "' + inputType + '" value = "' + this.config.values[index] + '"> </input>');
this.valueInputs.push(newInput.get(0));
inputArea.append(newInput);
index += 1;
}
if (emitChange) {
this.eventEmitter.emit('change', {
value: Number(newInput[0].options[0].value),
property: 'values[0]',
index: this.index
});
}
}
};
Condition.prototype.generateSelectOptions = function () {
let telemetryMetadata = this.conditionManager.getTelemetryMetadata(this.config.object);
let options = '';
telemetryMetadata[this.config.key].enumerations.forEach(enumeration => {
options += '<option value="' + enumeration.value + '">'+ enumeration.string + '</option>';
});
return options;
};
return Condition;
});

View File

@ -24,7 +24,8 @@ define([], function () {
*/
this.inputTypes = {
number: 'number',
string: 'text'
string: 'text',
enum: 'select'
};
/**
@ -34,7 +35,8 @@ define([], function () {
*/
this.inputValidators = {
number: this.validateNumberInput,
string: this.validateStringInput
string: this.validateStringInput,
enum: this.validateNumberInput
};
/**
@ -201,7 +203,7 @@ define([], function () {
return typeof input[0] === 'undefined';
},
text: 'is undefined',
appliesTo: ['string', 'number'],
appliesTo: ['string', 'number', 'enum'],
inputCount: 0,
getDescription: function () {
return ' is undefined';
@ -212,11 +214,33 @@ define([], function () {
return typeof input[0] !== 'undefined';
},
text: 'is defined',
appliesTo: ['string', 'number'],
appliesTo: ['string', 'number', 'enum'],
inputCount: 0,
getDescription: function () {
return ' is defined';
}
},
enumValueIs: {
operation: function (input) {
return input[0] === input[1];
},
text: 'is',
appliesTo: ['enum'],
inputCount: 1,
getDescription: function (values) {
return ' == ' + values[0];
}
},
enumValueIsNot: {
operation: function (input) {
return input[0] !== input[1];
},
text: 'is not',
appliesTo: ['enum'],
inputCount: 1,
getDescription: function (values) {
return ' != ' + values[0];
}
}
};
}
@ -310,13 +334,16 @@ define([], function () {
validator;
if (cache[object] && typeof cache[object][key] !== 'undefined') {
telemetryValue = [cache[object][key]];
let value = cache[object][key];
telemetryValue = [isNaN(Number(value)) ? value : Number(value)];
}
op = this.operations[operation] && this.operations[operation].operation;
input = telemetryValue && telemetryValue.concat(values);
validator = op && this.inputValidators[this.operations[operation].appliesTo[0]];
if (op && input && validator) {
if (this.operations[operation].appliesTo.length === 2) {
if (this.operations[operation].appliesTo.length > 1) {
return (this.validateNumberInput(input) || this.validateStringInput(input)) && op(input);
} else {
return validator(input) && op(input);
@ -372,7 +399,7 @@ define([], function () {
};
/**
* Returns true only of the given operation applies to a given type
* Returns true only if the given operation applies to a given type
* @param {string} key The key of the operation
* @param {string} type The value type to query
* @returns {boolean} True if the condition applies, false otherwise

View File

@ -130,7 +130,9 @@ define ([
this.telemetryTypesById[objectId] = {};
Object.values(this.telemetryMetadataById[objectId]).forEach(function (valueMetadata) {
var type;
if (valueMetadata.hints.hasOwnProperty('range')) {
if (valueMetadata.enumerations !== undefined) {
type = 'enum';
} else if (valueMetadata.hints.hasOwnProperty('range')) {
type = 'number';
} else if (valueMetadata.hints.hasOwnProperty('domain')) {
type = 'number';
@ -163,11 +165,18 @@ define ([
* @param {datum} datum The new data from the telemetry source
* @private
*/
ConditionManager.prototype.handleSubscriptionCallback = function (objId, datum) {
this.subscriptionCache[objId] = datum;
ConditionManager.prototype.handleSubscriptionCallback = function (objId, telemetryDatum) {
this.subscriptionCache[objId] = this.createNormalizedDatum(objId, telemetryDatum);
this.eventEmitter.emit('receiveTelemetry');
};
ConditionManager.prototype.createNormalizedDatum = function (objId, telemetryDatum) {
return Object.values(this.telemetryMetadataById[objId]).reduce((normalizedDatum, metadatum) => {
normalizedDatum[metadatum.key] = telemetryDatum[metadatum.source];
return normalizedDatum;
}, {});
};
/**
* Event handler for an add event in this Summary Widget's composition.
* Sets up subscription handlers and parses its property types.
@ -236,6 +245,7 @@ define ([
id.namespace === identifier.namespace;
});
delete this.compositionObjs[objectId];
delete this.subscriptionCache[objectId];
this.subscriptions[objectId](); //unsubscribe from telemetry source
delete this.subscriptions[objectId];
this.eventEmitter.emit('remove', identifier);

View File

@ -110,9 +110,11 @@ define([
type = self.manager.getTelemetryPropertyType(self.config.object, key);
self.operationKeys = operations.filter(function (operation) {
return self.evaluator.operationAppliesTo(operation, type);
});
if (type !== undefined) {
self.operationKeys = operations.filter(function (operation) {
return self.evaluator.operationAppliesTo(operation, type);
});
}
};
OperationSelect.prototype.destroy = function () {

View File

@ -174,7 +174,7 @@ define([
return typeof input[0] === 'undefined';
},
text: 'is undefined',
appliesTo: ['string', 'number'],
appliesTo: ['string', 'number', 'enum'],
inputCount: 0,
getDescription: function () {
return ' is undefined';
@ -185,11 +185,33 @@ define([
return typeof input[0] !== 'undefined';
},
text: 'is defined',
appliesTo: ['string', 'number'],
appliesTo: ['string', 'number', 'enum'],
inputCount: 0,
getDescription: function () {
return ' is defined';
}
},
enumValueIs: {
operation: function (input) {
return input[0] === input[1];
},
text: 'is',
appliesTo: ['enum'],
inputCount: 1,
getDescription: function (values) {
return ' == ' + values[0];
}
},
enumValueIsNot: {
operation: function (input) {
return input[0] !== input[1];
},
text: 'is not',
appliesTo: ['enum'],
inputCount: 1,
getDescription: function (values) {
return ' != ' + values[0];
}
}
};