Commit 62c4095b authored by Dhiraj Bodicherla's avatar Dhiraj Bodicherla

Add text variable parser for monitoring dashboard

This MR adds parsers for simple and
advanced type text variables. These variables
are defined in dashboard yml file
parent 8f803264
import { isString } from 'lodash';
import { VARIABLE_TYPES } from '../constants';
/**
* This file exclusively deals with parsing user-defined variables
* in dashboard yml file.
*
* As of 13.0, simple custom and advanced custom variables are supported.
* As of 13.0, simple text, advanced text, simple custom and
* advanced custom variables are supported.
*
* In the future iterations, text and query variables will be
* supported
......@@ -12,13 +14,30 @@ import { VARIABLE_TYPES } from '../constants';
*/
/**
* Utility method to determine if a custom variable is
* simple or not. If its not simple, it is advanced.
* Simple text variable is a string value only.
* This method parses such variables to a standard format.
*
* @param {Array|Object} customVar Array if simple, object if advanced
* @returns {Boolean} true if simple, false if advanced
* @param {String|Object} simpleTextVar
* @returns {Object}
*/
const isSimpleCustomVariable = customVar => Array.isArray(customVar);
const textSimpleVariableParser = simpleTextVar => ({
type: VARIABLE_TYPES.text,
label: null,
value: simpleTextVar,
});
/**
* Advanced text variable is an object.
* This method parses such variables to a standard format.
*
* @param {Object} advTextVar
* @returns {Object}
*/
const textAdvancedVariableParser = advTextVar => ({
type: VARIABLE_TYPES.text,
label: advTextVar.label,
value: advTextVar.options.default_value,
});
/**
* Normalize simple and advanced custom variable options to a standard
......@@ -26,20 +45,12 @@ const isSimpleCustomVariable = customVar => Array.isArray(customVar);
* @param {Object} custom variable option
* @returns {Object} normalized custom variable options
*/
const normalizeDropdownOptions = ({ default: defaultOpt = false, text, value }) => ({
const normalizeCustomVariableOptions = ({ default: defaultOpt = false, text, value }) => ({
default: defaultOpt,
text,
value,
});
/**
* Simple custom variables have an array of values.
* This method parses such variables options to a standard format.
*
* @param {String} opt option from simple custom variable
*/
const parseSimpleDropdownOptions = opt => ({ text: opt, value: opt });
/**
* Custom advanced variables are rendered as dropdown elements in the dashboard
* header. This method parses advanced custom variables.
......@@ -52,10 +63,19 @@ const customAdvancedVariableParser = advVariable => {
return {
type: VARIABLE_TYPES.custom,
label: advVariable.label,
options: options.map(normalizeDropdownOptions),
options: options.map(normalizeCustomVariableOptions),
};
};
/**
* Simple custom variables have an array of values.
* This method parses such variables options to a standard format.
*
* @param {String} opt option from simple custom variable
* @returns {Object}
*/
const parseSimpleCustomOptions = opt => ({ text: opt, value: opt });
/**
* Custom simple variables are rendered as dropdown elements in the dashboard
* header. This method parses simple custom variables.
......@@ -66,14 +86,23 @@ const customAdvancedVariableParser = advVariable => {
* @returns {Object}
*/
const customSimpleVariableParser = simpleVar => {
const options = (simpleVar || []).map(parseSimpleDropdownOptions);
const options = (simpleVar || []).map(parseSimpleCustomOptions);
return {
type: VARIABLE_TYPES.custom,
label: null,
options: options.map(normalizeDropdownOptions),
options: options.map(normalizeCustomVariableOptions),
};
};
/**
* Utility method to determine if a custom variable is
* simple or not. If its not simple, it is advanced.
*
* @param {Array|Object} customVar Array if simple, object if advanced
* @returns {Boolean} true if simple, false if advanced
*/
const isSimpleCustomVariable = customVar => Array.isArray(customVar);
/**
* This method returns a parser based on the type of the variable.
* Currently, the supported variables are simple custom and
......@@ -88,6 +117,10 @@ const getVariableParser = variable => {
return customSimpleVariableParser;
} else if (variable.type === VARIABLE_TYPES.custom) {
return customAdvancedVariableParser;
} else if (variable.type === VARIABLE_TYPES.text) {
return textAdvancedVariableParser;
} else if (isString(variable)) {
return textSimpleVariableParser;
}
return () => null;
};
......
......@@ -549,3 +549,214 @@ export const mockNamespacedData = {
export const mockLogsPath = '/mockLogsPath';
export const mockLogsHref = `${mockLogsPath}?duration_seconds=${mockTimeRange.duration.seconds}`;
const templatingVariableTypes = {
text: {
simple: 'Simple text',
advanced: {
label: 'Variable 4',
type: 'text',
options: {
default_value: 'default',
},
},
},
custom: {
simple: ['value1', 'value2', 'value3'],
advanced: {
normal: {
label: 'Advanced Var',
type: 'custom',
options: {
values: [
{ value: 'value1', text: 'Var 1 Option 1' },
{
value: 'value2',
text: 'Var 1 Option 2',
default: true,
},
],
},
},
withoutOpts: {
type: 'custom',
options: {},
},
withoutLabel: {
type: 'custom',
options: {
values: [
{ value: 'value1', text: 'Var 1 Option 1' },
{
value: 'value2',
text: 'Var 1 Option 2',
default: true,
},
],
},
},
withoutType: {
label: 'Variable 2',
options: {
values: [
{ value: 'value1', text: 'Var 1 Option 1' },
{
value: 'value2',
text: 'Var 1 Option 2',
default: true,
},
],
},
},
},
},
};
const generateMockTemplatingData = data => {
const vars = data
? {
variables: {
...data,
},
}
: {};
return {
dashboard: {
templating: vars,
},
};
};
const responseForSimpleTextVariable = {
simpleText: {
label: 'simpleText',
type: 'text',
value: 'Simple text',
},
};
const responseForAdvTextVariable = {
advText: {
label: 'Variable 4',
type: 'text',
value: 'default',
},
};
const responseForSimpleCustomVariable = {
simpleCustom: {
label: 'simpleCustom',
options: [
{
default: false,
text: 'value1',
value: 'value1',
},
{
default: false,
text: 'value2',
value: 'value2',
},
{
default: false,
text: 'value3',
value: 'value3',
},
],
type: 'custom',
},
};
const responseForAdvancedCustomVariableWithoutOptions = {
advCustomWithoutOpts: {
label: 'advCustomWithoutOpts',
options: [],
type: 'custom',
},
};
const responseForAdvancedCustomVariableWithoutLabel = {
advCustomWithoutLabel: {
label: 'advCustomWithoutLabel',
options: [
{
default: false,
text: 'Var 1 Option 1',
value: 'value1',
},
{
default: true,
text: 'Var 1 Option 2',
value: 'value2',
},
],
type: 'custom',
},
};
const responseForAdvancedCustomVariable = {
...responseForSimpleCustomVariable,
advCustomNormal: {
label: 'Advanced Var',
options: [
{
default: false,
text: 'Var 1 Option 1',
value: 'value1',
},
{
default: true,
text: 'Var 1 Option 2',
value: 'value2',
},
],
type: 'custom',
},
};
const responsesForAllVariableTypes = {
...responseForSimpleTextVariable,
...responseForAdvTextVariable,
...responseForSimpleCustomVariable,
...responseForAdvancedCustomVariable,
};
export const mockTemplatingData = {
emptyTemplatingProp: generateMockTemplatingData(),
emptyVariablesProp: generateMockTemplatingData({}),
simpleText: generateMockTemplatingData({ simpleText: templatingVariableTypes.text.simple }),
advText: generateMockTemplatingData({ advText: templatingVariableTypes.text.advanced }),
simpleCustom: generateMockTemplatingData({ simpleCustom: templatingVariableTypes.custom.simple }),
advCustomWithoutOpts: generateMockTemplatingData({
advCustomWithoutOpts: templatingVariableTypes.custom.advanced.withoutOpts,
}),
advCustomWithoutType: generateMockTemplatingData({
advCustomWithoutType: templatingVariableTypes.custom.advanced.withoutType,
}),
advCustomWithoutLabel: generateMockTemplatingData({
advCustomWithoutLabel: templatingVariableTypes.custom.advanced.withoutLabel,
}),
simpleAndAdv: generateMockTemplatingData({
simpleCustom: templatingVariableTypes.custom.simple,
advCustomNormal: templatingVariableTypes.custom.advanced.normal,
}),
allVariableTypes: generateMockTemplatingData({
simpleText: templatingVariableTypes.text.simple,
advText: templatingVariableTypes.text.advanced,
simpleCustom: templatingVariableTypes.custom.simple,
advCustomNormal: templatingVariableTypes.custom.advanced.normal,
}),
};
export const mockTemplatingDataResponses = {
emptyTemplatingProp: {},
emptyVariablesProp: {},
simpleText: responseForSimpleTextVariable,
advText: responseForAdvTextVariable,
simpleCustom: responseForSimpleCustomVariable,
advCustomWithoutOpts: responseForAdvancedCustomVariableWithoutOptions,
advCustomWithoutType: {},
advCustomWithoutLabel: responseForAdvancedCustomVariableWithoutLabel,
simpleAndAdv: responseForAdvancedCustomVariable,
allVariableTypes: responsesForAllVariableTypes,
};
import { parseTemplatingVariables } from '~/monitoring/stores/variable_mapping';
import { mockTemplatingData, mockTemplatingDataResponses } from '../mock_data';
describe('parseTemplatingVariables', () => {
const generateMockTemplatingData = data => {
const vars = data
? {
variables: {
...data,
},
}
: {};
return {
dashboard: {
templating: vars,
},
};
};
const simpleVar = ['value1', 'value2', 'value3'];
const advVar = {
label: 'Advanced Var',
type: 'custom',
options: {
values: [
{ value: 'value1', text: 'Var 1 Option 1' },
{
value: 'value2',
text: 'Var 1 Option 2',
default: true,
},
],
},
};
const advVarWithoutOptions = {
type: 'custom',
options: {},
};
const advVarWithoutLabel = {
type: 'custom',
options: {
values: [
{ value: 'value1', text: 'Var 1 Option 1' },
{
value: 'value2',
text: 'Var 1 Option 2',
default: true,
},
],
},
};
const advVarWithoutType = {
label: 'Variable 2',
options: {
values: [
{ value: 'value1', text: 'Var 1 Option 1' },
{
value: 'value2',
text: 'Var 1 Option 2',
default: true,
},
],
},
};
const responseForSimpleCustomVariable = {
simpleVar: {
label: 'simpleVar',
options: [
{
default: false,
text: 'value1',
value: 'value1',
},
{
default: false,
text: 'value2',
value: 'value2',
},
{
default: false,
text: 'value3',
value: 'value3',
},
],
type: 'custom',
},
};
const responseForAdvancedCustomVariableWithoutOptions = {
advVarWithoutOptions: {
label: 'advVarWithoutOptions',
options: [],
type: 'custom',
},
};
const responseForAdvancedCustomVariableWithoutLabel = {
advVarWithoutLabel: {
label: 'advVarWithoutLabel',
options: [
{
default: false,
text: 'Var 1 Option 1',
value: 'value1',
},
{
default: true,
text: 'Var 1 Option 2',
value: 'value2',
},
],
type: 'custom',
},
};
const responseForAdvancedCustomVariable = {
...responseForSimpleCustomVariable,
advVar: {
label: 'Advanced Var',
options: [
{
default: false,
text: 'Var 1 Option 1',
value: 'value1',
},
{
default: true,
text: 'Var 1 Option 2',
value: 'value2',
},
],
type: 'custom',
},
};
it.each`
case | input | expected
${'Returns empty object for no dashboard input'} | ${{}} | ${{}}
${'Returns empty object for empty dashboard input'} | ${{ dashboard: {} }} | ${{}}
${'Returns empty object for empty templating prop'} | ${generateMockTemplatingData()} | ${{}}
${'Returns empty object for empty variables prop'} | ${generateMockTemplatingData({})} | ${{}}
${'Returns parsed object for simple variable'} | ${generateMockTemplatingData({ simpleVar })} | ${responseForSimpleCustomVariable}
${'Returns parsed object for advanced variable without options'} | ${generateMockTemplatingData({ advVarWithoutOptions })} | ${responseForAdvancedCustomVariableWithoutOptions}
${'Returns parsed object for advanced variable without type'} | ${generateMockTemplatingData({ advVarWithoutType })} | ${{}}
${'Returns parsed object for advanced variable without label'} | ${generateMockTemplatingData({ advVarWithoutLabel })} | ${responseForAdvancedCustomVariableWithoutLabel}
${'Returns parsed object for simple and advanced variables'} | ${generateMockTemplatingData({ simpleVar, advVar })} | ${responseForAdvancedCustomVariable}
case | input | expected
${'Returns empty object for no dashboard input'} | ${{}} | ${{}}
${'Returns empty object for empty dashboard input'} | ${{ dashboard: {} }} | ${{}}
${'Returns empty object for empty templating prop'} | ${mockTemplatingData.emptyTemplatingProp} | ${{}}
${'Returns empty object for empty variables prop'} | ${mockTemplatingData.emptyVariablesProp} | ${{}}
${'Returns parsed object for simple text variable'} | ${mockTemplatingData.simpleText} | ${mockTemplatingDataResponses.simpleText}
${'Returns parsed object for advanced text variable'} | ${mockTemplatingData.advText} | ${mockTemplatingDataResponses.advText}
${'Returns parsed object for simple custom variable'} | ${mockTemplatingData.simpleCustom} | ${mockTemplatingDataResponses.simpleCustom}
${'Returns parsed object for advanced custom variable without options'} | ${mockTemplatingData.advCustomWithoutOpts} | ${mockTemplatingDataResponses.advCustomWithoutOpts}
${'Returns parsed object for advanced custom variable without type'} | ${mockTemplatingData.advCustomWithoutType} | ${{}}
${'Returns parsed object for advanced custom variable without label'} | ${mockTemplatingData.advCustomWithoutLabel} | ${mockTemplatingDataResponses.advCustomWithoutLabel}
${'Returns parsed object for simple and advanced custom variables'} | ${mockTemplatingData.simpleAndAdv} | ${mockTemplatingDataResponses.simpleAndAdv}
${'Returns parsed object for all variable types'} | ${mockTemplatingData.allVariableTypes} | ${mockTemplatingDataResponses.allVariableTypes}
`('$case', ({ input, expected }) => {
expect(parseTemplatingVariables(input?.dashboard?.templating)).toEqual(expected);
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment