Filtered sample data
This commit is contained in:
Родитель
67c2b5a190
Коммит
8f01541d80
|
@ -181,11 +181,11 @@ class SettingsStore extends AbstractStoreModel<ISettingsStoreState> implements I
|
|||
const forkedQueryComponents = dependencyProperty.split('-');
|
||||
const params = datasources[datasource].config.params;
|
||||
|
||||
const isForked = !params.query && !!params.table;
|
||||
const isForked = params && !params.query && !!params.table;
|
||||
|
||||
if (!isForked) {
|
||||
// unforked
|
||||
queryFn = params.query;
|
||||
queryFn = params && params.query || 'n/a';
|
||||
} else {
|
||||
// forked
|
||||
if (!params.queries[queryId] && forkedQueryComponents.length === 2) {
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import * as _ from 'lodash';
|
||||
import utils from '../../index';
|
||||
import { DataFormatTypes, IDataFormat, formatWarn, getPrefix } from '../common';
|
||||
import { IDataSourcePlugin } from '../../../data-sources/plugins/DataSourcePlugin';
|
||||
|
||||
/**
|
||||
* Applies selected filters to sample JSON data
|
||||
* Returns filtered data using a prefix.
|
||||
*
|
||||
* @param format {
|
||||
* type: 'filtered_samples',
|
||||
* args: {
|
||||
* prefix: string - a prefix string for the filtered sample data (defaults to 'filtered').
|
||||
* }
|
||||
* }
|
||||
* @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 filtered_samples (
|
||||
format: string | IDataFormat,
|
||||
state: any,
|
||||
dependencies: IDictionary,
|
||||
plugin: IDataSourcePlugin,
|
||||
prevState: any) {
|
||||
let result = {};
|
||||
|
||||
if (typeof format === 'string') {
|
||||
return formatWarn('format should be an object with args', 'bars', plugin);
|
||||
}
|
||||
|
||||
const args = format.args || {};
|
||||
const prefix = args['prefix'] || 'filtered';
|
||||
|
||||
const params = plugin.getParams();
|
||||
const filters = params.filters;
|
||||
|
||||
// Check for active filters selected
|
||||
const hasSelectedFilters = filters.some(filter => (
|
||||
dependencies[filter.dependency] && dependencies[filter.dependency].length > 0)
|
||||
);
|
||||
|
||||
// Apply filter to sample data
|
||||
Object.keys(dependencies).forEach(key => {
|
||||
// Skip filters
|
||||
if (filters.find(f => f.dependency === key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply filter data
|
||||
const values = dependencies[key];
|
||||
let filteredData = {};
|
||||
|
||||
// Return early if no active filters
|
||||
if (!hasSelectedFilters) {
|
||||
filteredData[prefix + '_' + key] = values;
|
||||
Object.assign(result, filteredData);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get active selected filters
|
||||
const activeFilters = filters.reduce((acc, filter) => {
|
||||
if (dependencies[filter.dependency].length > 0) {
|
||||
acc.push(filter);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Apply active selected filters to sample data
|
||||
const filteredValues = values.filter(value => {
|
||||
return activeFilters.every(filter => {
|
||||
const queryProperty = filter.queryProperty;
|
||||
const selectedFilters = dependencies[filter.dependency];
|
||||
return value[queryProperty] === selectedFilters.find(selectedFilter => selectedFilter === value[queryProperty]);
|
||||
});
|
||||
});
|
||||
|
||||
filteredData[prefix + '_' + key] = filteredValues;
|
||||
Object.assign(result, filteredData);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
|
@ -5,4 +5,5 @@ export * from './formats/flags';
|
|||
export * from './formats/retention';
|
||||
export * from './formats/scorecard';
|
||||
export * from './formats/timeline';
|
||||
export * from './formats/timespan';
|
||||
export * from './formats/timespan';
|
||||
export * from './formats/filtered-samples';
|
|
@ -28,62 +28,98 @@ export const config: IDashboardConfig = /*return*/ {
|
|||
}
|
||||
},
|
||||
dataSources: [
|
||||
{
|
||||
id: 'filter1',
|
||||
type: 'Sample',
|
||||
format: 'filter',
|
||||
params: {
|
||||
samples: {
|
||||
'values': [
|
||||
{value: 'en'},
|
||||
{value: 'fr'},
|
||||
{value: 'de'}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'filter2',
|
||||
type: 'Sample',
|
||||
format: 'filter',
|
||||
params: {
|
||||
samples: {
|
||||
'values': [
|
||||
{value: 'skype'},
|
||||
{value: 'messenger'},
|
||||
{value: 'slack'}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'samples',
|
||||
type: 'Sample',
|
||||
dependencies: {
|
||||
selectedFilter: 'filters:filter-selected',
|
||||
selectedFilter1: 'filter1:values-selected',
|
||||
selectedFilter2: 'filter2:values-selected',
|
||||
},
|
||||
params: {
|
||||
samples: {
|
||||
data_for_pie: [
|
||||
{ name: 'value1', value: 1, category: 'app' },
|
||||
{ name: 'value2', value: 2, category: 'bot' },
|
||||
{ name: 'value3', value: 3, category: 'bot' },
|
||||
{ name: 'value4', value: 4, category: 'web' },
|
||||
{ name: 'value5', value: 5, category: 'web' },
|
||||
{ name: 'value6', value: 6, category: 'web' },
|
||||
{ name: 'value6', value: 6, category: 'web' }
|
||||
{ name: 'skype-en', value: 9, locale: 'en', channel: 'skype' },
|
||||
{ name: 'skype-fr', value: 8, locale: 'fr', channel: 'skype' },
|
||||
{ name: 'skype-de', value: 7, locale: 'de', channel: 'skype' },
|
||||
{ name: 'messenger-en', value: 6, locale: 'en', channel: 'messenger' },
|
||||
{ name: 'messenger-fr', value: 5, locale: 'fr', channel: 'messenger' },
|
||||
{ name: 'messenger-de', value: 4, locale: 'de', channel: 'messenger' },
|
||||
{ name: 'slack-en', value: 3, locale: 'en', channel: 'slack' },
|
||||
{ name: 'slack-fr', value: 2, locale: 'fr', channel: 'slack' },
|
||||
{ name: 'slack-de', value: 1, locale: 'de', channel: 'slack' }
|
||||
]
|
||||
},
|
||||
filters: [{ dependency: 'selectedFilter', queryProperty: 'category' }],
|
||||
filters: [
|
||||
{ dependency: 'selectedFilter1', queryProperty: 'locale' },
|
||||
{ dependency: 'selectedFilter2', queryProperty: 'channel' }
|
||||
],
|
||||
},
|
||||
format: {
|
||||
type: 'filtered_samples'
|
||||
},
|
||||
calculated: (state, dependencies) => {
|
||||
const {data_for_pie} = state;
|
||||
const {selectedFilter} = dependencies;
|
||||
let {filtered_data_value, filtered_data_subvalue} = state;
|
||||
let filtered_data_for_pie = data_for_pie;
|
||||
if (selectedFilter && selectedFilter.length > 0) {
|
||||
filtered_data_for_pie = data_for_pie.filter(i => i.category === selectedFilter.find(f => f === i.category) );
|
||||
}
|
||||
filtered_data_value = filtered_data_for_pie.length;
|
||||
filtered_data_subvalue = filtered_data_for_pie.reduce((a,c) => a + c.value, 0);
|
||||
return {
|
||||
'filtered_data_value': filtered_data_value || 0,
|
||||
'filtered_data_subvalue': filtered_data_subvalue || 0,
|
||||
'filtered_data_for_pie': filtered_data_for_pie
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'filters',
|
||||
id: 'scorecard',
|
||||
type: 'Sample',
|
||||
params: {
|
||||
samples: {
|
||||
'filter-categories': ['web', 'app', 'bot'],
|
||||
'filter-selected': []
|
||||
}
|
||||
dependencies: {
|
||||
filteredData: 'samples:filtered_data_for_pie',
|
||||
},
|
||||
calculated: (state, dependencies) => {
|
||||
const {filteredData} = state;
|
||||
const filteredDataValue = filteredData && filteredData.reduce((a, c) => a + c.value, 0) || 0;
|
||||
const filteredDataSubvalue = filteredData && filteredData.length || 0;
|
||||
return {
|
||||
'filtered_data_value': filteredDataValue,
|
||||
'filtered_data_subvalue': filteredDataSubvalue,
|
||||
};
|
||||
}
|
||||
}
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
type: 'MenuFilter',
|
||||
title: 'Filter',
|
||||
subtitle: 'Select category',
|
||||
title: 'Locale',
|
||||
subtitle: 'Select locale',
|
||||
icon: 'forum',
|
||||
dependencies: { selectedValues: 'filters:filter-selected', values: 'filters:filter-categories' },
|
||||
actions: { onChange: 'filters:updateSelectedValues:filter-selected' },
|
||||
source: 'filter1',
|
||||
actions: { onChange: 'filter1:updateSelectedValues:values-selected' },
|
||||
first: true
|
||||
},
|
||||
{
|
||||
type: 'MenuFilter',
|
||||
title: 'Channel',
|
||||
subtitle: 'Select channel',
|
||||
icon: 'forum',
|
||||
source: 'filter2',
|
||||
actions: { onChange: 'filter2:updateSelectedValues:values-selected' },
|
||||
first: true
|
||||
},
|
||||
],
|
||||
|
@ -95,7 +131,7 @@ export const config: IDashboardConfig = /*return*/ {
|
|||
subtitle: 'Description of pie sample 1',
|
||||
size: { w: 5, h: 8 },
|
||||
dependencies: { values: 'samples:filtered_data_for_pie' },
|
||||
props: { showLegend: true }
|
||||
props: { entityType: 'Sessions', showLegend: true }
|
||||
},
|
||||
{
|
||||
id: 'pie_sample2',
|
||||
|
@ -104,34 +140,34 @@ export const config: IDashboardConfig = /*return*/ {
|
|||
subtitle: 'Hover on the values to see the difference from sample 1',
|
||||
size: { w: 5, h: 8 },
|
||||
dependencies: { values: 'samples:filtered_data_for_pie' },
|
||||
props: { showLegend: true, compact: true }
|
||||
props: { entityType: 'Sessions', showLegend: true, compact: true }
|
||||
},
|
||||
{
|
||||
id: 'scorecard_sample1',
|
||||
id: 'scorecard1',
|
||||
type: 'Scorecard',
|
||||
title: 'Value',
|
||||
size: { w: 1, h: 3 },
|
||||
dependencies: {
|
||||
value: 'samples:filtered_data_value',
|
||||
value: 'scorecard:filtered_data_value',
|
||||
color: '::#2196F3',
|
||||
icon: '::av_timer'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'scorecard_sample2',
|
||||
id: 'scorecard2',
|
||||
type: 'Scorecard',
|
||||
title: 'Same Value',
|
||||
size: { w: 1, h: 3 },
|
||||
dependencies: {
|
||||
value: 'samples:filtered_data_value',
|
||||
value: 'scorecard:filtered_data_value',
|
||||
color: '::#2196F3',
|
||||
icon: '::av_timer',
|
||||
subvalue: 'samples:filtered_data_subvalue'
|
||||
subvalue: 'scorecard:filtered_data_subvalue'
|
||||
},
|
||||
props: {
|
||||
subheading: 'Total value'
|
||||
subheading: 'segments'
|
||||
}
|
||||
}
|
||||
],
|
||||
dialogs: []
|
||||
}
|
||||
};
|
Загрузка…
Ссылка в новой задаче