diff --git a/superset/assets/images/viz_thumbnails/event_flow.png b/superset/assets/images/viz_thumbnails/event_flow.png
new file mode 100644
index 000000000000..45765295be00
Binary files /dev/null and b/superset/assets/images/viz_thumbnails/event_flow.png differ
diff --git a/superset/assets/javascripts/explore/stores/controls.jsx b/superset/assets/javascripts/explore/stores/controls.jsx
index 794c9ee0cd9d..13306932ce01 100644
--- a/superset/assets/javascripts/explore/stores/controls.jsx
+++ b/superset/assets/javascripts/explore/stores/controls.jsx
@@ -659,7 +659,7 @@ export const controls = {
label: 'Entity',
default: null,
validators: [v.nonEmpty],
- description: 'This define the element to be plotted on the chart',
+ description: 'This defines the element to be plotted on the chart',
mapStateToProps: state => ({
choices: (state.datasource) ? state.datasource.gb_cols : [],
}),
@@ -1273,5 +1273,23 @@ export const controls = {
hidden: true,
description: 'The number of seconds before expiring the cache',
},
+
+ order_by_entity: {
+ type: 'CheckboxControl',
+ label: 'Order by entity id',
+ description: 'Important! Select this if the table is not already sorted by entity id, ' +
+ 'else there is no guarantee that all events for each entity are returned.',
+ default: true,
+ },
+
+ min_leaf_node_event_count: {
+ type: 'SelectControl',
+ freeForm: false,
+ label: 'Minimum leaf node event count',
+ default: 1,
+ choices: formatSelectOptionsForRange(1, 10),
+ description: 'Leaf nodes that represent fewer than this number of events will be initially ' +
+ 'hidden in the visualization',
+ },
};
export default controls;
diff --git a/superset/assets/javascripts/explore/stores/visTypes.js b/superset/assets/javascripts/explore/stores/visTypes.js
index 68991e35babf..bdebf076420a 100644
--- a/superset/assets/javascripts/explore/stores/visTypes.js
+++ b/superset/assets/javascripts/explore/stores/visTypes.js
@@ -1,5 +1,4 @@
import { D3_TIME_FORMAT_OPTIONS } from './controls';
-
import * as v from '../validators';
export const sections = {
@@ -890,6 +889,51 @@ const visTypes = {
},
},
},
+
+ event_flow: {
+ label: 'Event flow',
+ requiresTime: true,
+ controlPanelSections: [
+ {
+ label: 'Event definition',
+ controlSetRows: [
+ ['entity'],
+ ['all_columns_x'],
+ ['row_limit'],
+ ['order_by_entity'],
+ ['min_leaf_node_event_count'],
+ ],
+ },
+ {
+ label: 'Additional meta data',
+ controlSetRows: [
+ ['all_columns'],
+ ],
+ },
+ ],
+ controlOverrides: {
+ entity: {
+ label: 'Column containing entity ids',
+ description: 'e.g., a "user id" column',
+ },
+ all_columns_x: {
+ label: 'Column containing event names',
+ validators: [v.nonEmpty],
+ default: control => (
+ control.choices && control.choices.length > 0 ?
+ control.choices[0][0] : null
+ ),
+ },
+ row_limit: {
+ label: 'Event count limit',
+ description: 'The maximum number of events to return, equivalent to number of rows',
+ },
+ all_columns: {
+ label: 'Meta data',
+ description: 'Select any columns for meta data inspection',
+ },
+ },
+ },
};
export default visTypes;
diff --git a/superset/assets/package.json b/superset/assets/package.json
index 5d5022def10b..ff4c161ad6e1 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -38,6 +38,7 @@
},
"homepage": "https://github.com/airbnb/superset#readme",
"dependencies": {
+ "@data-ui/event-flow": "0.0.4",
"babel-register": "^6.24.1",
"bootstrap": "^3.3.6",
"brace": "^0.10.0",
diff --git a/superset/assets/visualizations/EventFlow.jsx b/superset/assets/visualizations/EventFlow.jsx
new file mode 100644
index 000000000000..110f4a76482c
--- /dev/null
+++ b/superset/assets/visualizations/EventFlow.jsx
@@ -0,0 +1,61 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+import {
+ App,
+ withParentSize,
+ cleanEvents,
+ TS,
+ EVENT_NAME,
+ ENTITY_ID,
+} from '@data-ui/event-flow';
+
+/*
+ * This function takes the slice object and json payload as input and renders a
+ * responsive