Skip to content

Commit

Permalink
Persistent Dashboard refresh settings.
Browse files Browse the repository at this point in the history
  • Loading branch information
alanmcruickshank committed Aug 2, 2016
1 parent aaef338 commit c912643
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 28 deletions.
18 changes: 10 additions & 8 deletions caravel/assets/javascripts/dashboard/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ function dashboardContainer(dashboardData) {
filters: {},
init() {
this.initDashboardView();
this.firstLoad = true;
px.initFavStars();
const sliceObjects = [];
const dash = this;
Expand All @@ -64,7 +63,7 @@ function dashboardContainer(dashboardData) {
this.slices = sliceObjects;
this.refreshTimer = null;
this.loadPreSelectFilters();
this.startPeriodicRender(0);
this.startPeriodicRender();
this.bindResizeToWindowResize();
},
loadPreSelectFilters() {
Expand Down Expand Up @@ -131,14 +130,12 @@ function dashboardContainer(dashboardData) {
const maxRandomDelay = Math.min(interval * 0.2, 5000);
const refreshAll = function () {
dash.slices.forEach(function (slice) {
const force = !dash.firstLoad;
setTimeout(function () {
slice.render(force);
},
// Randomize to prevent all widgets refreshing at the same time
maxRandomDelay * Math.random());
});
dash.firstLoad = false;
};

const fetchAndRender = function () {
Expand All @@ -149,7 +146,9 @@ function dashboardContainer(dashboardData) {
}, interval);
}
};
fetchAndRender();
if (interval > 0){
fetchAndRender();
}
},
refreshExcept(sliceId) {
const immune = this.metadata.filter_immune_slices || [];
Expand Down Expand Up @@ -244,6 +243,8 @@ function dashboardContainer(dashboardData) {
positions,
css: this.editor.getValue(),
expanded_slices: expandedSlices,
autorefresh_seconds: dashboard.autorefresh_seconds,
autorefresh_from_cache: dashboard.autorefresh_from_cache
};
$.ajax({
type: 'POST',
Expand Down Expand Up @@ -323,9 +324,10 @@ function dashboardContainer(dashboardData) {
dashboard.readFilters(),
});
});
$('#refresh_dash_interval').on('change', function () {
const interval = $(this).find('option:selected').val() * 1000;
dashboard.startPeriodicRender(interval);
$("#refresh_dash_apply").click(function () {
dashboard.autorefresh_seconds = $("#refresh_dash_interval").val();
dashboard.autorefresh_from_cache = $("#refresh_dach_from_cache").is(':checked');
dashboard.startPeriodicRender();
});
$('#refresh_dash').click(() => {
dashboard.slices.forEach((slice) => {
Expand Down
59 changes: 54 additions & 5 deletions caravel/migrations/versions/27ae655e4247_make_creator_owners.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,67 @@
down_revision = 'd8bc074f7aad'

from alembic import op
from caravel import db, models
from caravel import db

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import (
Column, Integer, ForeignKey, Table)

Base = declarative_base()

slice_user = Table(
'slice_user', Base.metadata,
Column('id', Integer, primary_key=True),
Column('user_id', Integer, ForeignKey('ab_user.id')),
Column('slice_id', Integer, ForeignKey('slices.id'))
)

dashboard_user = Table(
'dashboard_user', Base.metadata,
Column('id', Integer, primary_key=True),
Column('user_id', Integer, ForeignKey('ab_user.id')),
Column('dashboard_id', Integer, ForeignKey('dashboards.id'))
)


class User(Base):

"""Declarative class to do query in upgrade"""

__tablename__ = 'ab_user'
id = Column(Integer, primary_key=True)


class Slice(Base):

"""Declarative class to do query in upgrade"""

__tablename__ = 'slices'
id = Column(Integer, primary_key=True)
owners = relationship("User", secondary=slice_user)
created_by_fk = Column(Integer)


class Dashboard(Base):

"""Declarative class to do query in upgrade"""

__tablename__ = 'dashboards'
id = Column(Integer, primary_key=True)
owners = relationship("User", secondary=dashboard_user)
created_by_fk = Column(Integer)


def upgrade():
bind = op.get_bind()
session = db.Session(bind=bind)

objects = session.query(models.Slice).all()
objects += session.query(models.Dashboard).all()
objects = session.query(Slice).all()
objects += session.query(Dashboard).all()
for obj in objects:
if obj.created_by and obj.created_by not in obj.owners:
obj.owners.append(obj.created_by)
if obj.created_by_fk and obj.created_by_fk not in obj.owners:
obj.owners.append(obj.created_by_fk)
session.commit()
session.close()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Adding Columns for Dashboard Refresh Properties
Revision ID: 79aef3baedae
Revises: f162a1dea4c4
Create Date: 2016-07-02 14:51:00.106192
"""

# revision identifiers, used by Alembic.
revision = '79aef3baedae'
down_revision = 'f162a1dea4c4'

from alembic import op
import sqlalchemy as sa


def upgrade():
try:
op.add_column('dashboards', sa.Column('autorefresh_from_cache', sa.Boolean(), nullable=False, server_default='True'))
except:
# To pick up databases (like some MySQL variants) without a true Boolean value
op.add_column('dashboards', sa.Column('autorefresh_from_cache', sa.Boolean(), nullable=False, server_default='1'))

op.add_column('dashboards', sa.Column('autorefresh_seconds', sa.Integer(), nullable=False, server_default='0'))


def downgrade():
op.drop_column('dashboards', 'autorefresh_seconds')
op.drop_column('dashboards', 'autorefresh_from_cache')
6 changes: 6 additions & 0 deletions caravel/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,9 @@ class Dashboard(Model, AuditMixinNullable):
slices = relationship(
'Slice', secondary=dashboard_slices, backref='dashboards')
owners = relationship("User", secondary=dashboard_user)
# A zero for autorefresh seconds implies no autorefresh
autorefresh_seconds = Column(Integer, default=0, nullable=False)
autorefresh_from_cache = Column(Boolean, default=True, nullable=False)

def __repr__(self):
return self.dashboard_title
Expand All @@ -315,13 +318,16 @@ def dashboard_link(self):

@property
def json_data(self):
"""Returns the configuration data for the dashboard as json"""
d = {
'id': self.id,
'metadata': self.metadata_dejson,
'dashboard_title': self.dashboard_title,
'slug': self.slug,
'slices': [slc.data for slc in self.slices],
'position_json': json.loads(self.position_json) if self.position_json else [],
'autorefresh_seconds': self.autorefresh_seconds,
'autorefresh_from_cache': self.autorefresh_from_cache,
}
return json.dumps(d)

Expand Down
27 changes: 14 additions & 13 deletions caravel/templates/caravel/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,22 @@ <h6><strong>Styling applies to this dashboard only</strong></h6>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">Refresh Interval</h4>
<h6><strong>Choose how frequent should the dashboard refresh</strong></h6>
<h4 class="modal-title" id="myModalLabel">Autorefresh Interval and Settings</h4>
<h6><strong>Choose if and how frequently the dashboard should refresh</strong></h6>
</div>
<div class="modal-body">
<select id="refresh_dash_interval" class="select2" style="margin-bottom: 5px;">
<option value="0">Don't refresh</option>
<option value="10">10 seconds</option>
<option value="30">30 seconds</option>
<option value="60">1 minute</option>
<option value="300">5 minutes</option>
</select><br>
<label for="refresh_dash_interval">Dashboard Refresh Interval</label>
<input id="refresh_dash_interval" value="{{ dashboard.autorefresh_seconds }}" />
<p class="help-block">Number of seconds between refreshes. Set to 0 for no auto-refresh</p>
<br>
<label for="refresh_dash_from_cache">Refresh from Cache</label>
<input type="checkbox" id="refresh_dash_force" {{ "checked" if dashboard.autorefresh_from_cache }}/>
<p class="help-block">If unchecked the dashboard will force fresh values from the database. While checked the dashboard will allow values from the cache resulting in better performance for multiple users.</p>
<br>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Close
<button type="button" class="btn btn-default" data-dismiss="modal" id="refresh_dash_apply">
Apply and Close
</button>
</div>
</div>
Expand All @@ -84,7 +85,7 @@ <h2>
<i class="fa fa-plus" data-toggle="tooltip" title="Add a new slice to the dashboard"></i>
</button>
<button type="button" id="refresh_dash_periodic" class="btn btn-default" data-toggle="modal" data-target="#refresh_modal">
<i class="fa fa-clock-o" data-toggle="tooltip" title="Decide how frequent should the dashboard refresh"></i>
<i class="fa fa-clock-o" data-toggle="tooltip" title="Decide if and how frequently should the dashboard refresh"></i>
</button>
<button type="button" id="filters" class="btn btn-default" data-toggle="tooltip" title="View the list of active filters">
<i class="fa fa-filter"></i>
Expand All @@ -95,7 +96,7 @@ <h2>
<a id="editdash" class="btn btn-default {{ "disabled disabledButton" if not dash_edit_perm }} " href="/dashboardmodelview/edit/{{ dashboard.id }}" title="Edit this dashboard's property" data-toggle="tooltip" >
<i class="fa fa-edit"></i>
</a>
<button type="button" id="savedash" class="btn btn-default {{ "disabled disabledButton" if not dash_save_perm }}" data-toggle="tooltip" title="Save the current positioning and CSS">
<button type="button" id="savedash" class="btn btn-default {{ "disabled disabledButton" if not dash_save_perm }}" data-toggle="tooltip" title="Save the current refresh settings, positioning and CSS">
<i class="fa fa-save"></i>
</button>
</div>
Expand Down
18 changes: 16 additions & 2 deletions caravel/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,12 +628,22 @@ class DashboardModelView(CaravelModelView, DeleteMixin): # noqa
datamodel = SQLAInterface(models.Dashboard)
list_columns = ['dashboard_link', 'creator', 'modified']
edit_columns = [
'dashboard_title', 'slug', 'slices', 'owners', 'position_json', 'css',
'json_metadata']
'dashboard_title', 'slug', 'slices', 'owners',
'autorefresh_seconds', 'autorefresh_from_cache',
'position_json', 'css', 'json_metadata']
show_columns = edit_columns + ['table_names']
add_columns = edit_columns
base_order = ('changed_on', 'desc')
description_columns = {
'autorefresh_seconds': _(
"The number of seconds between automatic refreshes "
"of the dashboard. The default value of 0 means the "
"dashboard will not automatically refresh."),
'autorefresh_from_cache': _(
"If checked the dashboard will use cached values when "
"refreshing. To force the dashboard to always use fresh "
"values then uncheck this option. Performance with many "
"users will be lower if unchecked."),
'position_json': _(
"This json object describes the positioning of the widgets in "
"the dashboard. It is dynamically generated when adjusting "
Expand All @@ -660,6 +670,8 @@ class DashboardModelView(CaravelModelView, DeleteMixin): # noqa
'owners': _("Owners"),
'creator': _("Creator"),
'modified': _("Modified"),
'autorefresh_seconds': _("Dashboard Refresh Frequency"),
'autorefresh_from_cache': _("Refresh From Cache"),
'position_json': _("Position JSON"),
'css': _("CSS"),
'json_metadata': _("JSON Metadata"),
Expand Down Expand Up @@ -1066,6 +1078,8 @@ def save_dash(self, dashboard_id):
md['expanded_slices'] = data['expanded_slices']
dash.json_metadata = json.dumps(md, indent=4)
dash.css = data['css']
dash.autorefresh_seconds = data['autorefresh_seconds']
dash.autorefresh_from_cache = data['autorefresh_from_cache']
session.merge(dash)
session.commit()
session.close()
Expand Down
2 changes: 2 additions & 0 deletions tests/core_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ def test_save_dash(self, username='admin'):
'css': '',
'expanded_slices': {},
'positions': positions,
'autorefresh_seconds': 60,
'autorefresh_from_cache': True,
}
url = '/caravel/save_dash/{}/'.format(dash.id)
resp = self.client.post(url, data=dict(data=json.dumps(data)))
Expand Down

0 comments on commit c912643

Please sign in to comment.