diff --git a/superset/assets/javascripts/profile/components/CreatedContent.jsx b/superset/assets/javascripts/profile/components/CreatedContent.jsx
index d779e19892178..96978756d3fa2 100644
--- a/superset/assets/javascripts/profile/components/CreatedContent.jsx
+++ b/superset/assets/javascripts/profile/components/CreatedContent.jsx
@@ -19,6 +19,7 @@ class CreatedContent extends React.PureComponent {
renderSliceTable() {
const mutator = (data) => data.map(slice => ({
slice: {slice.title},
+ views: slice.views,
favorited: moment.utc(slice.dttm).fromNow(),
_favorited: slice.dttm,
}));
@@ -26,7 +27,7 @@ class CreatedContent extends React.PureComponent {
data.map(dash => ({
dashboard: {dash.title},
+ views: dash.views,
favorited: moment.utc(dash.dttm).fromNow(),
_favorited: dash.dttm,
}));
@@ -45,7 +47,7 @@ class CreatedContent extends React.PureComponent {
mutator={mutator}
dataEndpoint={`/superset/created_dashboards/${this.props.user.userId}/`}
noDataText="No dashboards"
- columns={['dashboard', 'favorited']}
+ columns={['dashboard', 'favorited', 'views']}
sortable
/>
);
diff --git a/superset/migrations/versions/1b2c3f7c96f9_.py b/superset/migrations/versions/1b2c3f7c96f9_.py
new file mode 100644
index 0000000000000..0e1a1379de0e4
--- /dev/null
+++ b/superset/migrations/versions/1b2c3f7c96f9_.py
@@ -0,0 +1,64 @@
+"""Add number of views as column to dashboards and slices
+
+Revision ID: 1b2c3f7c96f9
+Revises: 6414e83d82b7
+Create Date: 2016-12-15 16:32:31.909331
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '1b2c3f7c96f9'
+down_revision = '6414e83d82b7'
+
+from alembic import op
+import sqlalchemy as sa
+from superset import db, models
+
+def upgrade():
+ op.add_column('dashboards', sa.Column('views', sa.Integer, server_default='1', nullable=True))
+ op.add_column('slices', sa.Column('views', sa.Integer, server_default='1', nullable=True))
+
+ if db.engine.name != 'postgresql':
+ Dash = models.Dashboard
+ Log = models.Log
+ qry = (
+ db.session.query(
+ Dash,
+ sa.func.count(),
+ )
+ .outerjoin(Log)
+ .filter(
+ sa.and_(
+ Log.dashboard_id == Dash.id,
+ )
+ )
+ .group_by(Dash)
+ )
+ for dash_obj in qry.all():
+ dash_obj[0].views = dash_obj[1]
+ db.session.commit()
+
+ Slice = models.Slice
+ qry = (
+ db.session.query(
+ Slice,
+ sa.func.count(),
+ )
+ .outerjoin(Log)
+ .filter(
+ sa.and_(
+ Log.slice_id == Slice.id,
+ )
+ )
+ .group_by(Slice)
+ )
+ for slice_obj in qry.all():
+ slice_obj[0].views = slice_obj[1]
+ db.session.commit()
+ db.session.close()
+
+
+
+def downgrade():
+ op.drop_column('dashboards', 'views')
+ op.drop_column('slices', 'views')
diff --git a/superset/models.py b/superset/models.py
index 84701a17db2b2..cef46a4c57a8b 100644
--- a/superset/models.py
+++ b/superset/models.py
@@ -232,6 +232,7 @@ class Slice(Model, AuditMixinNullable, ImportMixin):
cache_timeout = Column(Integer)
perm = Column(String(1000))
owners = relationship("User", secondary=slice_user)
+ views = Column(Integer, default=1)
export_fields = ('slice_name', 'datasource_type', 'datasource_name',
'viz_type', 'params', 'cache_timeout')
@@ -437,9 +438,9 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin):
slices = relationship(
'Slice', secondary=dashboard_slices, backref='dashboards')
owners = relationship("User", secondary=dashboard_user)
-
export_fields = ('dashboard_title', 'position_json', 'json_metadata',
'description', 'css', 'slug')
+ views = Column(Integer, default=1)
def __repr__(self):
return self.dashboard_title
@@ -2366,8 +2367,8 @@ class Log(Model):
id = Column(Integer, primary_key=True)
action = Column(String(512))
user_id = Column(Integer, ForeignKey('ab_user.id'))
- dashboard_id = Column(Integer)
- slice_id = Column(Integer)
+ dashboard_id = Column(Integer, ForeignKey('dashboards.id'))
+ slice_id = Column(Integer, ForeignKey('slices.id'))
json = Column(Text)
user = relationship('User', backref='logs', foreign_keys=[user_id])
dttm = Column(DateTime, default=datetime.utcnow)
diff --git a/superset/views.py b/superset/views.py
index fb8d6faa628a2..6cb206bfff7f2 100755
--- a/superset/views.py
+++ b/superset/views.py
@@ -1438,6 +1438,8 @@ def explore(self, datasource_type, datasource_id):
if slice_id:
slc = db.session.query(models.Slice).filter_by(id=slice_id).first()
+ slc.views = slc.views + 1
+ db.session.commit()
error_redirect = '/slicemodelview/list/'
datasource_class = SourceRegistry.sources[datasource_type]
@@ -1955,10 +1957,7 @@ def created_dashboards(self, user_id):
Dash,
)
.filter(
- sqla.or_(
- Dash.created_by_fk == user_id,
- Dash.changed_by_fk == user_id,
- )
+ Dash.created_by_fk == user_id,
)
.order_by(
Dash.changed_on.desc()
@@ -1970,6 +1969,7 @@ def created_dashboards(self, user_id):
'title': o.dashboard_title,
'url': o.url,
'dttm': o.changed_on,
+ 'views': o.views,
} for o in qry.all()]
return Response(
json.dumps(payload, default=utils.json_int_dttm_ser),
@@ -1984,10 +1984,7 @@ def created_slices(self, user_id):
qry = (
db.session.query(Slice)
.filter(
- sqla.or_(
- Slice.created_by_fk == user_id,
- Slice.changed_by_fk == user_id,
- )
+ Slice.created_by_fk == user_id,
)
.order_by(Slice.changed_on.desc())
)
@@ -1996,6 +1993,7 @@ def created_slices(self, user_id):
'title': o.slice_name,
'url': o.slice_url,
'dttm': o.changed_on,
+ 'views': o.views,
} for o in qry.all()]
return Response(
json.dumps(payload, default=utils.json_int_dttm_ser),
@@ -2132,6 +2130,8 @@ def dashboard(self, dashboard_id):
qry = qry.filter_by(slug=dashboard_id)
dash = qry.one()
+ dash.views = dash.views + 1
+ db.session.commit()
datasources = {slc.datasource for slc in dash.slices}
for datasource in datasources:
if not self.datasource_access(datasource):