Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 15 additions & 5 deletions caravel/assets/javascripts/dashboard/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var Dashboard = function (dashboardData) {
this.slices = sliceObjects;
this.refreshTimer = null;
this.loadPreSelectFilters();
this.startPeriodicRender(0);
this.startPeriodicRender();
this.bindResizeToWindowResize();
},
loadPreSelectFilters: function () {
Expand Down Expand Up @@ -103,13 +103,14 @@ var Dashboard = function (dashboardData) {
this.refreshTimer = null;
}
},
startPeriodicRender: function (interval) {
startPeriodicRender: function () {
this.stopPeriodicRender();
var dash = this;
var interval = dash.autorefresh_seconds * 1000;
var force = !(dash.autorefresh_from_cache);
var maxRandomDelay = Math.min(interval * 0.2, 5000);
var refreshAll = function () {
dash.slices.forEach(function (slice) {
var force = !dash.firstLoad;
setTimeout(function () {
slice.render(force);
},
Expand All @@ -127,7 +128,9 @@ var Dashboard = function (dashboardData) {
}, interval);
}
};
fetchAndRender();
if (interval > 0) {
fetchAndRender();
};
},
refreshExcept: function (slice_id) {
var immune = this.metadata.filter_immune_slices || [];
Expand Down Expand Up @@ -213,7 +216,9 @@ var Dashboard = function (dashboardData) {
var data = {
positions: this.reactGridLayout.serialize(),
css: this.editor.getValue(),
expanded_slices: expandedSlices
expanded_slices: expandedSlices,
autorefresh_seconds: dashboard.autorefresh_seconds,
autorefresh_from_cache: dashboard.autorefresh_from_cache
};
$.ajax({
type: "POST",
Expand Down Expand Up @@ -297,6 +302,11 @@ var Dashboard = function (dashboardData) {
var interval = $(this).find('option:selected').val() * 1000;
dashboard.startPeriodicRender(interval);
});
$("#refresh_dash_apply").click(function () {
dashboard.autorefresh_seconds = $("refresh_dash_interval").val() * 1000;
dashboard.autorefresh_from_cache = $("refresh_dash_from_cache").is(':checked');
dashboard.startPeriodicRender(dashboard.autorefresh_seconds, dashboard.autorefresh_from_cache);
});
$('#refresh_dash').click(function () {
dashboard.slices.forEach(function (slice) {
slice.render(true);
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: 960c69cb1f5b
Create Date: 2016-07-02 14:51:00.106192

"""

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

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 frequent 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
17 changes: 16 additions & 1 deletion caravel/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,12 +607,23 @@ 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',
'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 used 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 @@ -639,6 +650,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 @@ -1045,6 +1058,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