{
+ const mockedProps = {
+ slice,
+ removeSlice: () => {},
+ expandedSlices: () => {},
+ };
+ it('is valid', () => {
+ expect(
+ React.isValidElement(
)
+ ).to.equal(true);
+ });
+ it('renders five links', () => {
+ const wrapper = mount(
);
+ expect(wrapper.find('a')).to.have.length(5);
+ });
+});
diff --git a/caravel/assets/spec/javascripts/dashboard/fixtures.jsx b/caravel/assets/spec/javascripts/dashboard/fixtures.jsx
new file mode 100644
index 0000000000000..7ac259e9416bb
--- /dev/null
+++ b/caravel/assets/spec/javascripts/dashboard/fixtures.jsx
@@ -0,0 +1,69 @@
+export const slice = {
+ token: 'token_089ec8c1',
+ csv_endpoint: '',
+ edit_url: '/slicemodelview/edit/39',
+ viz_name: 'filter_box',
+ json_endpoint: '',
+ slice_id: 39,
+ standalone_endpoint: '',
+ description_markeddown: '',
+ form_data: {
+ collapsed_fieldsets: null,
+ time_grain_sqla: 'Time Column',
+ granularity_sqla: 'year',
+ standalone: null,
+ date_filter: false,
+ until: '2014-01-02',
+ extra_filters: null,
+ force: null,
+ where: '',
+ since: '2014-01-01',
+ async: null,
+ slice_id: null,
+ json: null,
+ having: '',
+ flt_op_2: 'in',
+ previous_viz_type: 'filter_box',
+ groupby: [
+ 'region',
+ 'country_name',
+ ],
+ flt_col_7: '',
+ slice_name: null,
+ viz_type: 'filter_box',
+ metric: 'sum__SP_POP_TOTL',
+ flt_col_8: '',
+ },
+ slice_url: '',
+ slice_name: 'Region Filter',
+ description: null,
+ column_formats: {},
+};
+export const dashboardData = {
+ css: '',
+ metadata: {
+ filter_immune_slices: [],
+ filter_immune_slice_fields: {},
+ expanded_slices: {},
+ },
+ slug: 'births',
+ position_json: [
+ {
+ size_x: 2,
+ slice_id: '52',
+ row: 0,
+ size_y: 2,
+ col: 1,
+ },
+ ],
+ id: 2,
+ slices: [slice],
+ dashboard_title: 'Births',
+};
+
+export const contextData = {
+ dash_save_perm: true,
+ standalone_mode: false,
+ dash_edit_perm: true,
+ user_id: '1',
+};
diff --git a/caravel/assets/stylesheets/caravel.css b/caravel/assets/stylesheets/caravel.css
index 94e7018137b1c..37863fce1a804 100644
--- a/caravel/assets/stylesheets/caravel.css
+++ b/caravel/assets/stylesheets/caravel.css
@@ -156,7 +156,6 @@ li.widget:hover {
div.widget .chart-header {
padding-top: 8px;
- background-color: #fff;
color: #333;
border-bottom: 1px solid #aaa;
margin: 0 10px;
diff --git a/caravel/assets/stylesheets/dashboard.css b/caravel/assets/stylesheets/dashboard.css
index b09d9444a21fe..b140e77808fb5 100644
--- a/caravel/assets/stylesheets/dashboard.css
+++ b/caravel/assets/stylesheets/dashboard.css
@@ -118,3 +118,12 @@ div.widget .chart-controls {
.chart-header .header {
font-size: 16px;
}
+.ace_gutter {
+ z-index: 0;
+}
+.ace_content {
+ z-index: 0;
+}
+.ace_scrollbar {
+ z-index: 0;
+}
diff --git a/caravel/assets/visualizations/big_number.js b/caravel/assets/visualizations/big_number.js
index d8c2a6a8f9b92..2a5c68161c813 100644
--- a/caravel/assets/visualizations/big_number.js
+++ b/caravel/assets/visualizations/big_number.js
@@ -4,9 +4,8 @@ import { formatDate } from '../javascripts/modules/dates';
require('./big_number.css');
function bigNumberVis(slice) {
- const div = d3.select(slice.selector);
-
function render() {
+ const div = d3.select(slice.selector);
d3.json(slice.jsonEndpoint(), function (error, payload) {
// Define the percentage bounds that define color from red to green
if (error !== null) {
diff --git a/caravel/models.py b/caravel/models.py
index 8494d4716a81b..00440cb3809a6 100644
--- a/caravel/models.py
+++ b/caravel/models.py
@@ -251,6 +251,7 @@ def data(self):
d = self.viz.data
self.token = d.get('token')
except Exception as e:
+ logging.exception(e)
d['error'] = str(e)
d['slice_id'] = self.id
d['slice_name'] = self.slice_name
@@ -433,13 +434,17 @@ def dashboard_link(self):
@property
def json_data(self):
+ positions = self.position_json
+ if positions:
+ positions = json.loads(positions)
d = {
'id': self.id,
'metadata': self.params_dict,
+ 'css': self.css,
'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 [],
+ 'position_json': positions,
}
return json.dumps(d)
@@ -714,8 +719,6 @@ def select_star(
self, table_name, schema=None, limit=100, show_cols=False,
indent=True):
"""Generates a ``select *`` statement in the proper dialect"""
- for i in range(10):
- print(schema)
quote = self.get_quoter()
fields = '*'
table = self.get_table(table_name, schema=schema)
diff --git a/caravel/templates/caravel/dashboard.html b/caravel/templates/caravel/dashboard.html
index f6c65fcd21be3..2e141ce6b7471 100644
--- a/caravel/templates/caravel/dashboard.html
+++ b/caravel/templates/caravel/dashboard.html
@@ -12,108 +12,11 @@
{% include 'caravel/flash_wrapper.html' %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% if not standalone_mode %}
-
- {% endif %}
-
-
-
-
-
-
- {{ dashboard.dashboard_title }}
-
-
-
-
- {% if not standalone_mode %}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% endif %}
-
-
+
diff --git a/caravel/utils.py b/caravel/utils.py
index 0fbe27687b5dc..af4fdfce27359 100644
--- a/caravel/utils.py
+++ b/caravel/utils.py
@@ -16,16 +16,17 @@
import uuid
from sqlalchemy import event, exc
-from sqlalchemy.pool import Pool
import parsedatetime
import sqlalchemy as sa
from dateutil.parser import parse
from flask import flash, Markup
from flask_appbuilder.security.sqla import models as ab_models
-from markdown import markdown as md
+import markdown as md
from sqlalchemy.types import TypeDecorator, TEXT
from pydruid.utils.having import Having
+logging.getLogger('MARKDOWN').setLevel(logging.INFO)
+
EPOCH = datetime(1970, 1, 1)
@@ -426,8 +427,7 @@ def error_msg_from_exception(e):
def markdown(s, markup_wrap=False):
- s = s or ''
- s = md(s, [
+ s = md.markdown(s or '', [
'markdown.extensions.tables',
'markdown.extensions.fenced_code',
'markdown.extensions.codehilite',
diff --git a/caravel/views.py b/caravel/views.py
index 92ffea518b0c3..b0f58d03bb963 100755
--- a/caravel/views.py
+++ b/caravel/views.py
@@ -832,13 +832,8 @@ class SliceAsync(SliceModelView): # noqa
class SliceAddView(SliceModelView): # noqa
list_columns = [
- 'slice_link', 'viz_type',
- 'owners', 'modified', 'data', 'changed_on']
- label_columns = {
- 'icons': ' ',
- 'slice_link': _('Slice'),
- 'viz_type': _('Visualization Type'),
- }
+ 'id', 'slice_name', 'slice_link', 'viz_type',
+ 'owners', 'modified', 'changed_on']
appbuilder.add_view_no_menu(SliceAddView)
@@ -1705,7 +1700,6 @@ def dashboard(self, dashboard_id):
else:
qry = qry.filter_by(slug=dashboard_id)
- templates = session.query(models.CssTemplate).all()
dash = qry.one()
datasources = {slc.datasource for slc in dash.slices}
for datasource in datasources:
@@ -1727,13 +1721,17 @@ def dashboard(**kwargs): # noqa
dash_save_perm = \
dash_edit_perm and self.can_access('can_save_dash', 'Caravel')
standalone = request.args.get("standalone") == "true"
- return self.render_template(
- "caravel/dashboard.html", dashboard=dash,
+ context = dict(
user_id=g.user.get_id(),
- templates=templates,
dash_save_perm=dash_save_perm,
dash_edit_perm=dash_edit_perm,
- standalone_mode=standalone)
+ standalone_mode=standalone,
+ )
+ return self.render_template(
+ "caravel/dashboard.html",
+ dashboard=dash,
+ context=json.dumps(context),
+ )
@has_access
@expose("/sync_druid/", methods=['POST'])
@@ -2293,6 +2291,10 @@ class CssTemplateModelView(CaravelModelView, DeleteMixin):
edit_columns = ['template_name', 'css']
add_columns = edit_columns
+
+class CssTemplateAsyncModelView(CssTemplateModelView):
+ list_columns = ['template_name', 'css']
+
appbuilder.add_separator("Sources")
appbuilder.add_view(
CssTemplateModelView,
@@ -2303,6 +2305,8 @@ class CssTemplateModelView(CaravelModelView, DeleteMixin):
category_label=__("Manage"),
category_icon='')
+appbuilder.add_view_no_menu(CssTemplateAsyncModelView)
+
appbuilder.add_link(
'SQL Editor',
href='/caravel/sqllab',
@@ -2337,9 +2341,4 @@ def __init__(self, url_map, *items):
@app.route('/
')
def panoramix(url): # noqa
return redirect(request.full_path.replace('panoramix', 'caravel'))
-
-
-@app.route('/')
-def dashed(url): # noqa
- return redirect(request.full_path.replace('dashed', 'caravel'))
# ---------------------------------------------------------------------