Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions superset/assets/src/explore/components/controls/VizTypeControl.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export default class VizTypeControl extends React.PureComponent {
this.state = {
showModal: false,
filter: '',
vizTypeStats: '',
};
this.toggleModal = this.toggleModal.bind(this);
this.changeSearch = this.changeSearch.bind(this);
Expand All @@ -69,6 +70,12 @@ export default class VizTypeControl extends React.PureComponent {
this.searchRef.focus();
}
}
componentDidMount() {
$.get("/superset/viz_type_stats", (data) => {
Comment thread
thomaswang-shift marked this conversation as resolved.
Outdated
this.setState({ vizTypeStats: data.this_user.concat(data.overall) });
this.forceUpdate();
Comment thread
thomaswang-shift marked this conversation as resolved.
Outdated
});
}
renderItem(entry) {
const { value } = this.props;
const { key, value: type } = entry;
Expand All @@ -89,13 +96,42 @@ export default class VizTypeControl extends React.PureComponent {
</div>
</div>);
}
getVizTypeByKey(types, key) {
Comment thread
thomaswang-shift marked this conversation as resolved.
Outdated
for (var i = 0; i < types.length; i++) {
if (types[i].key == key) return types[i];
}
}
sortVizTypes(types) {
var sorted = [];
Comment thread
thomaswang-shift marked this conversation as resolved.
Outdated
var loaded_keys = new Set();
Comment thread
thomaswang-shift marked this conversation as resolved.
Outdated
// Sort based on existing visualization type usages statistics
for (var i = 0; i < this.state.vizTypeStats.length; i++) {
var key = this.state.vizTypeStats[i].viz_type;
if (loaded_keys.has(key)) continue;
var t = this.getVizTypeByKey(types, key);
if (typeof t !== 'undefined') {
sorted.push(t);
loaded_keys.add(key);
}
}
// For visualization types that do not have any statistics, apply the
// original order
for (var i = 0; i < types.length; i++) {
var t = types[i];
var key = t['key'];
if (! loaded_keys.has(key)) {
sorted.push(t);
loaded_keys.add(key);
}
}
return sorted;
}
render() {
const { filter, showModal } = this.state;
const { value } = this.props;

const registry = getChartMetadataRegistry();

const types = registry.entries();
const types = this.sortVizTypes(registry.entries());
const filteredTypes = filter.length > 0
? types.filter(type => type.value.name.toLowerCase().includes(filter))
: types;
Expand Down
50 changes: 49 additions & 1 deletion superset/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import pandas as pd
import simplejson as json
import sqlalchemy as sqla
from sqlalchemy import and_, create_engine, MetaData, or_, update
from sqlalchemy import and_, create_engine, MetaData, or_, update, func, desc
from sqlalchemy.engine.url import make_url
from sqlalchemy.exc import IntegrityError
from werkzeug.routing import BaseConverter
Expand Down Expand Up @@ -2825,6 +2825,54 @@ def sqllab(self):
bootstrap_data=json.dumps(d, default=utils.json_iso_dttm_ser),
)

@has_access
@expose('/viz_type_stats', methods=['GET'])
@expose('/viz_type_stats/<user_id>/', methods=['GET'])
def viz_type_stats(self, user_id=None):
"""
This endpoint provides the statistics of the visualization type usage.
"""
if not user_id:
user_id = g.user.id

key = self._get_viz_type_stats_cache_key(user_id)
payload = cache.get(key)
if payload is not None:
payload['served_from'] = 'cache'
else:
payload = {
'served_from': 'live',
'this_user': self._get_viz_type_stats(user_id=user_id),
'overall': self._get_viz_type_stats(),
}
cache.set(key, payload, 7 * 24 * 60 * 60) # cache for 7 days
return json_success(
json.dumps(payload, default=utils.json_int_dttm_ser)
)

def _get_viz_type_stats_cache_key(self, user_id):
"""
This function returns the key for caching the result of visualization
type usage statistics of this user.
"""
return f"viz_type_stats_{user_id}"

def _get_viz_type_stats(self, user_id=None):
"""
This function returns the statistics of the visualization type usage of
the `user_id`. If `user_id` is not provided, this function returns the
same statistics across all users.
"""
query = db.session.query(
models.Slice.viz_type,
func.count().label("cnt"),
)
if user_id is not None:
query = query.filter(models.Slice.created_by_fk == user_id)
query = query.group_by(models.Slice.viz_type)
query = query.order_by(desc("cnt"))
return query.all()

@api
@handle_api_exception
@has_access_api
Expand Down