This commit is contained in:
morsh 2017-08-08 15:41:05 +03:00
Родитель 9fdc192f63
Коммит 04bf0ae8cd
17 изменённых файлов: 197 добавлений и 88 удалений

Просмотреть файл

@ -42,9 +42,9 @@ export default class Area extends GenericComponent<IAreaProps, IAreaState> {
static fromSource(source: string) {
return {
values: source + '-graphData',
lines: source + '-lines',
timeFormat: source + '-timeFormat'
values: GenericComponent.sourceFormat(source, 'graphData'),
lines: GenericComponent.sourceFormat(source, 'lines'),
timeFormat: GenericComponent.sourceFormat(source, 'timeFormat')
};
}

Просмотреть файл

@ -30,8 +30,8 @@ export default class BarData extends GenericComponent<IBarProps, IBarState> {
static editor = settings;
static fromSource(source: string) {
return {
values: source + '-values',
bars: source + '-bars'
values: GenericComponent.sourceFormat(source, 'values'),
bars: GenericComponent.sourceFormat(source, 'bars')
};
}

Просмотреть файл

@ -23,6 +23,15 @@ export abstract class GenericComponent<T1 extends IGenericProps, T2 extends IGen
private id: string = null;
static sourceFormat(source: string, variable: string) {
return source + ((source || '').indexOf(':') >= 0 ? '-' : ':') + variable;
}
static sourceAction(source: string, variable: string, action: string) {
let sourceFormat = GenericComponent.sourceFormat(source, variable).split(':');
return sourceFormat.join(`:${action}:`);
}
constructor(props: T1) {
super(props);

Просмотреть файл

@ -55,8 +55,8 @@ export default class MenuFilter extends GenericComponent<any, any> {
static fromSource(source: string) {
return {
selectedValue: source + '-selected',
values: source + '-values'
selectedValue: GenericComponent.sourceFormat(source, 'values-selected'),
values: GenericComponent.sourceFormat(source, 'values-all')
};
}

Просмотреть файл

@ -40,7 +40,7 @@ export default class PieData extends GenericComponent<IPieProps, IPieState> {
static fromSource(source: string) {
return {
values: source + '-pieData'
values: GenericComponent.sourceFormat(source, 'pieData')
};
}

Просмотреть файл

@ -45,12 +45,12 @@ export default class Scorecard extends GenericComponent<IScorecardProps, any> {
let mappings = {};
_.keys(source).forEach(key => {
mappings['card_' + key + '_value'] = source[key] + '-value';
mappings['card_' + key + '_heading'] = source[key] + '-heading';
mappings['card_' + key + '_color'] = source[key] + '-color';
mappings['card_' + key + '_icon'] = source[key] + '-icon';
mappings['card_' + key + '_subvalue'] = source[key] + '-subvalue';
mappings['card_' + key + '_subheading'] = source[key] + '-subheading';
mappings['card_' + key + '_value'] = GenericComponent.sourceFormat(source[key], 'value');
mappings['card_' + key + '_heading'] = GenericComponent.sourceFormat(source[key], 'heading');
mappings['card_' + key + '_color'] = GenericComponent.sourceFormat(source[key], 'color');
mappings['card_' + key + '_icon'] = GenericComponent.sourceFormat(source[key], 'icon');
mappings['card_' + key + '_subvalue'] = GenericComponent.sourceFormat(source[key], 'subvalue');
mappings['card_' + key + '_subheading'] = GenericComponent.sourceFormat(source[key], 'subheading');
});
return mappings;
}

Просмотреть файл

@ -10,8 +10,8 @@ export default class TextFilter extends GenericComponent<any, any> {
static fromSource(source: string) {
return {
selectedValue: source + '-selected',
values: source + '-values'
selectedValue: GenericComponent.sourceFormat(source, 'values-selected'),
values: GenericComponent.sourceFormat(source, 'values-all')
};
}

Просмотреть файл

@ -27,9 +27,9 @@ export default class Timeline extends GenericComponent<ITimelineProps, ITimeline
static editor = settings;
static fromSource(source: string) {
return {
values: source + '-graphData',
lines: source + '-lines',
timeFormat: source + '-timeFormat'
values: GenericComponent.sourceFormat(source, 'graphData'),
lines: GenericComponent.sourceFormat(source, 'lines'),
timeFormat: GenericComponent.sourceFormat(source, 'timeFormat')
};
}

Просмотреть файл

@ -147,14 +147,15 @@ export default class ApplicationInsightsQuery extends DataSourcePlugin<IQueryPar
// Extract data formats
let format = queries[aTable].format;
if (format && typeof format !== 'string') {
if (format) {
format = typeof format === 'string' ? { type: format } : format;
format = _.extend({ args: {} }, format);
format.args = _.extend({ prefix: aTable }, format.args);
}
let result = { values: returnedResults[aTable] };
let formatExtract = DataSourceConnector.handleDataFormat(format, this, result, dependencies);
if (formatExtract) {
Object.assign(returnedResults, formatExtract);
format.args = _.extend({ prefix: aTable + '-' }, format.args);
let result = { values: returnedResults[aTable] };
let formatExtract = DataSourceConnector.handleDataFormat(format, this, result, dependencies);
if (formatExtract) {
Object.assign(returnedResults, formatExtract);
}
}
// Extracting calculated values

Просмотреть файл

@ -1,3 +1,6 @@
import { ToastActions } from '../../components/Toast';
import { IDataSourcePlugin } from '../../data-sources/plugins/DataSourcePlugin';
export enum DataFormatTypes {
none,
timespan,
@ -9,4 +12,12 @@ export enum DataFormatTypes {
export interface IDataFormat {
type: string;
args: any;
}
export function formatWarn(text: string, format: string, plugin: IDataSourcePlugin) {
ToastActions.addToast({ text: `[format:${format}] text [data source:${plugin._props.id}]` });
}
export function getPrefix(format: string | IDataFormat) {
return (format && typeof format !== 'string' && format.args && format.args.prefix) || '';
}

Просмотреть файл

@ -1,6 +1,6 @@
import * as _ from 'lodash';
import utils from '../../index';
import { DataFormatTypes, IDataFormat } from '../common';
import { DataFormatTypes, IDataFormat, formatWarn, getPrefix } from '../common';
import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugin';
/**
@ -8,9 +8,10 @@ import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugi
*
* Receives a list of filtering values:
* values: [
* { field: 'value 1' },
* { field: 'value 2' },
* { field: 'value 3' },
* { count: 10, barField: 'bar 1', seriesField: 'series1Value' },
* { count: 15, barField: 'bar 2', seriesField: 'series1Value' },
* { count: 20, barField: 'bar 1', seriesField: 'series2Value' },
* { count: 44, barField: 'bar 3', seriesField: 'series2Value' },
* ]
*
* And outputs the result in a consumable filter way:
@ -18,8 +19,8 @@ import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugi
* "prefix-bars": [ 'bar 1', 'bar 2', 'bar 3' ],
* "prefix-values": [
* { value: 'bar 1', series1Value: 10, series2Value: 20 },
* { value: 'bar 2', series1Value: 15, series2Value: 5 },
* { value: 'bar 3', series1Value: 7, series2Value: 44 },
* { value: 'bar 2', series1Value: 15, series2Value: 0 },
* { value: 'bar 3', series1Value: 0, series2Value: 44 },
* ],
* }
*
@ -49,10 +50,12 @@ export function bars(
plugin: IDataSourcePlugin,
prevState: any) {
if (!format || typeof format === 'string') { return null; }
if (typeof format === 'string') {
return formatWarn('format should be an object with args', 'bars', plugin);
}
const args = format.args || {};
const prefix = args.prefix || 'prefix';
const prefix = getPrefix(format);
const valueField = args.valueField || 'count';
const barsField = args.barsField || null;
const seriesField = args.seriesField || null;
@ -94,12 +97,12 @@ export function bars(
}
});
result[prefix + '-bars'] = _.keys(series);
result[prefix + '-values'] = _.values(barValues);
result[prefix + 'bars'] = _.keys(series);
result[prefix + 'values'] = _.values(barValues);
} else {
result[prefix + '-bars'] = [ valueField ];
result[prefix + '-values'] = values;
result[prefix + 'bars'] = [ valueField ];
result[prefix + 'values'] = values;
}
return result;

Просмотреть файл

@ -1,6 +1,6 @@
import * as _ from 'lodash';
import utils from '../../index';
import { DataFormatTypes, IDataFormat } from '../common';
import { DataFormatTypes, IDataFormat, formatWarn, getPrefix } from '../common';
import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugin';
/**
@ -24,7 +24,7 @@ import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugi
* @param format {
* type: 'filter',
* args: {
* prefix: string - The prefix of the variable to be consumed,
* prefix: string - a prefix string for the exported variables (default to id).
* field: string - the field holding the filter values in the results
* }
* }
@ -42,25 +42,37 @@ export function filter (
const { values } = state;
let filterValues = values;
if (!filterValues || typeof format === 'string' || !format.args.prefix) { return {}; }
const { prefix, field } = format.args;
if (typeof format === 'string') {
return formatWarn('format should be an object with args', 'filter', plugin);
}
const args = format.args || {};
const field = args.field;
const prefix = getPrefix(format);
const unknown = format.args.unknown || 'unknown';
if (!field) {
return formatWarn('No value was supplied for "field" parameter', 'filter', plugin);
}
let filterValues = values;
if (!filterValues || !format.args.prefix) {
return null;
}
// This code is meant to fix the following scenario:
// When "Timespan" filter changes, to "channels-selected" variable
// is going to be reset into an empty set.
// For this reason, using previous state to copy filter
const filters = filterValues.map(x => x[field] || unknown);
let selectedValues = [];
if (prevState[prefix + '-selected'] !== undefined) {
selectedValues = prevState[prefix + '-selected'];
if (prevState[prefix + 'values-selected'] !== undefined) {
selectedValues = prevState[prefix + 'values-selected'];
}
let result = {};
result[prefix + '-values'] = filters;
result[prefix + '-selected'] = selectedValues;
result[prefix + 'values-all'] = filters;
result[prefix + 'values-selected'] = selectedValues;
return result;
}

Просмотреть файл

@ -1,8 +1,38 @@
import * as _ from 'lodash';
import utils from '../../index';
import { DataFormatTypes, IDataFormat } from '../common';
import { DataFormatTypes, IDataFormat, formatWarn, getPrefix } from '../common';
import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugin';
/**
* Turns a list of values into a list of flags
*
* Receives a list of filtering values (on the data source params variable):
* params: {
* values: [ 'value1', 'value2', 'value3' ]
* }
*
* And outputs the result in a consumable filter way:
* result: {
* "value1": false, (will be true if prefix-selected contains "value1")
* "value2": false,
* "value3": false,
* "prefix-filters": [ 'value 1', 'value 2', 'value 3' ],
* "prefix-selected": [ ],
* }
*
* "prefix-selected" will be able to hold the selected values from the filter component
*
* @param format 'filter' | {
* type: 'filter',
* args: {
* prefix: string - a prefix string for the exported variables (default to id).
* }
* }
* @param state Current received state from data source
* @param dependencies Dependencies for the plugin
* @param plugin The entire plugin (for id generation, params etc...)
* @param prevState The previous state to compare for changing filters
*/
export function flags(
format: string | IDataFormat,
state: any,
@ -10,16 +40,19 @@ export function flags(
plugin: IDataSourcePlugin,
prevState: any) {
const prefix = getPrefix(format);
const params = plugin.getParams();
if (!params || !Array.isArray(params.values)) {
return formatWarn('A paramerter "values" is expected as an array on "params" in the data source', 'filter', plugin);
}
if (!state || !params || !Array.isArray(params.values)) { return null; }
if (!state) { return null; }
let prefix = (typeof format !== 'string' && format.args && format.args.prefix) || plugin._props.id;
let flags = {};
params.values.forEach(key => { flags[key] = state.selectedValue === key; });
flags[prefix + '-values'] = params.values;
flags[prefix + '-selected'] = state.selectedValue;
flags[prefix + 'values-all'] = params.values;
flags[prefix + 'values-selected'] = state.selectedValue;
return flags;
}

Просмотреть файл

@ -1,6 +1,6 @@
import * as _ from 'lodash';
import utils from '../../index';
import { DataFormatTypes, IDataFormat } from '../common';
import { DataFormatTypes, IDataFormat, formatWarn, getPrefix } from '../common';
import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugin';
/**
@ -45,7 +45,8 @@ import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugi
*
* @param format Plugin format parameter
* @param state Current received state from data source
* @param dependencies Dependencies for the plugin
* @param dependencies Dependencies for the plugin
* should contain "selectedTimespan" equals to 'PT24H', 'P7D' etc...
* @param plugin The entire plugin (for id generation, params etc...)
*/
export function retention (
@ -57,6 +58,9 @@ export function retention (
const { values } = state;
const { selectedTimespan } = dependencies;
if (!values || !values.length) { return null; }
const prefix = getPrefix(format);
let result = {
totalUnique: 0,
totalUniqueUsersIn24hr: 0,
@ -70,10 +74,8 @@ export function retention (
returning: 0,
values: []
};
if (values && values.length) {
_.extend(result, values[0]);
}
_.extend(result, values[0]);
switch (selectedTimespan) {
case 'PT24H':
@ -97,7 +99,7 @@ export function retention (
break;
}
result.values = [
result[prefix + 'values'] = [
{
timespan: '24 hours',
retention: Math.round(100 * result.returning24hr / result.totalUniqueUsersIn24hr || 0) + '%',

Просмотреть файл

@ -1,29 +1,35 @@
import * as _ from 'lodash';
import utils from '../../index';
import { DataFormatTypes, IDataFormat } from '../common';
import { DataFormatTypes, IDataFormat, getPrefix } from '../common';
import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugin';
/**
* Formats a result to suite a timeline (time series) chart
* Formats a result to suite a scorecard
*
* Receives a list of filtering values:
* Receives a list of one value:
* values: [{ count: 99 }]
*
* And outputs the result in a consumable filter way:
* result: {
* "prefix-filters": [ 'value 1', 'value 2', 'value 3' ],
* "prefix-selected": [ ],
* "prefix-value": 99,
* "prefix-heading": "Heading",
* "prefix-color": "#fff",
* "prefix-icon": "chat",
* "prefix-subvalue": 44,
* "prefix-subheading": "Subheading"
* }
*
* "prefix-selected" will be able to hold the selected values from the filter component
*
* @param format {
* type: 'filter',
* @param format 'scorecard' | {
* type: 'scorecard',
* args: {
* prefix: string - a prefix string for the exported variables (default to id).
* timeField: 'timestamp' - The field containing timestamp
* lineField: 'channel' - A field to hold/group by different lines in the graph
* valueField: 'count' - holds the value/y value of the current point
* countField: 'count' - Field name with count value (default: 'count')
* postfix: '%' - String to add after the value (default: null)
* thresholds: [{ value: 0, heading: '', color: '#000', icon: 'done' }]
* subvalueField: 'other_count' - Other number field to check
* subvalueThresholds: [{ subvalue: 0, subheading: '' }]
* }
* }
* @param state Current received state from data source
@ -46,13 +52,13 @@ export function scorecard (
let createValue = (value: any, heading: string, color: string, icon: string, subvalue?: any, subheading?: string) => {
let item = {};
let prefix = args && args.prefix || plugin._props.id;
item[prefix + '-value'] = utils.kmNumber(value, postfix);
item[prefix + '-heading'] = heading;
item[prefix + '-color'] = color;
item[prefix + '-icon'] = icon;
item[prefix + '-subvalue'] = subvalue || '';
item[prefix + '-subheading'] = subheading || '';
const prefix = getPrefix(format);
item[prefix + 'value'] = utils.kmNumber(value, postfix);
item[prefix + 'heading'] = heading;
item[prefix + 'color'] = color;
item[prefix + 'icon'] = icon;
item[prefix + 'subvalue'] = subvalue || '';
item[prefix + 'subheading'] = subheading || '';
return item;
};

Просмотреть файл

@ -1,6 +1,6 @@
import * as _ from 'lodash';
import utils from '../../index';
import { DataFormatTypes, IDataFormat } from '../common';
import { DataFormatTypes, IDataFormat, formatWarn, getPrefix } from '../common';
import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugin';
/**
@ -42,13 +42,15 @@ export function timeline(
plugin: IDataSourcePlugin,
prevState: any) {
if (typeof format === 'string') { return {}; }
if (typeof format === 'string') {
return formatWarn('format should be an object with args', 'timeline', plugin);
}
const timeline = state.values;
const { timespan } = dependencies;
const args = format.args || {};
const { timeField, lineField, valueField } = args;
let prefix = args.prefix || 'timeline';
const prefix = getPrefix(format);
let _timeline = {};
let _lines = {};
@ -82,10 +84,10 @@ export function timeline(
});
let result = {};
result[prefix + '-graphData'] = timelineValues;
result[prefix + '-timeFormat'] = (timespan === '24 hours' ? 'hour' : 'date');
result[prefix + '-lines'] = lines;
result[prefix + '-pieData'] = usage;
result[prefix + 'graphData'] = timelineValues;
result[prefix + 'timeFormat'] = (timespan === '24 hours' ? 'hour' : 'date');
result[prefix + 'lines'] = lines;
result[prefix + 'pieData'] = usage;
return result;
}

Просмотреть файл

@ -1,8 +1,38 @@
import * as _ from 'lodash';
import utils from '../../index';
import { DataFormatTypes, IDataFormat } from '../common';
import { DataFormatTypes, IDataFormat, formatWarn, getPrefix } from '../common';
import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugin';
/**
* Receives a timespan data source and formats is accordingly
*
* Receives a list of filtering values (on the data source params variable):
* params: {
* values: ["24 hours","1 week","1 month","3 months"]
* selectedValue: "1 month",
* queryTimespan: "PT24H",
* granularity: "5m"
* }
*
* And outputs the result in a consumable filter way:
* result: {
* "prefix-values": ["24 hours","1 week","1 month","3 months"]
* "prefix-selected": "1 month",
* }
*
* "prefix-selected" will be able to hold the selected values from the filter component
*
* @param format 'timespan' | {
* type: 'timespan',
* args: {
* prefix: string - a prefix string for the exported variables (default to id).
* }
* }
* @param state Current received state from data source
* @param dependencies Dependencies for the plugin
* @param plugin The entire plugin (for id generation, params etc...)
* @param prevState The previous state to compare for changing filters
*/
export function timespan(
format: string | IDataFormat,
state: any,
@ -13,7 +43,7 @@ export function timespan(
if (!state) { return null; }
const params = plugin.getParams();
let prefix = (typeof format !== 'string' && format.args && format.args.prefix) || plugin._props.id;
const prefix = getPrefix(format);
let queryTimespan =
state.selectedValue === '24 hours' ? 'PT24H' :
state.selectedValue === '1 week' ? 'P7D' :
@ -28,8 +58,8 @@ export function timespan(
queryTimespan,
granularity
};
result[prefix + '-values'] = params.values;
result[prefix + '-selected'] = state.selectedValue;
result[prefix + 'values-all'] = params.values;
result[prefix + 'values-selected'] = state.selectedValue;
return result;
}