From 449441fed5097b30eb9600a6a0225647423c8801 Mon Sep 17 00:00:00 2001 From: Maxime Beauchemin Date: Tue, 22 Sep 2015 16:34:11 -0700 Subject: [PATCH] Adding support for markup (html/markdown) widgets --- TODO.md | 1 + panoramix/bin/panoramix | 43 +++++++++++++++++++++++++++++++++-------- panoramix/forms.py | 9 ++++++++- panoramix/views.py | 10 +++++++--- panoramix/viz.py | 18 +++++++++++++++-- requirements.txt | 1 + 6 files changed, 68 insertions(+), 14 deletions(-) diff --git a/TODO.md b/TODO.md index 336510e995012..842dc2b772530 100644 --- a/TODO.md +++ b/TODO.md @@ -8,3 +8,4 @@ * Add a per-datasource permission * Reintroduce query and stopwatch * Sort tooltip +* Add a "Test Connection" button in Add Connection menu diff --git a/panoramix/bin/panoramix b/panoramix/bin/panoramix index eed9b6073bd6c..b80dcb25b5743 100755 --- a/panoramix/bin/panoramix +++ b/panoramix/bin/panoramix @@ -107,7 +107,7 @@ def load_examples(): def get_slice_json( slice_name, filter_value, viz_type="table", group_by=None, granularity="all", filter_operator='in', - row_limit=config.ROW_LIMIT, flt_col_1="gender"): + row_limit=config.ROW_LIMIT, flt_col_1="gender", code=""): group_by = group_by if group_by is not None else ["name"] default_json = { "compare_lag": "10", @@ -130,7 +130,9 @@ def load_examples(): "slice_name": slice_name, "until": "now", "viz_type": viz_type, - "where": "" + "where": "", + "code": code, + "markup_type": "markdown", } return json.dumps(default_json, indent=4, sort_keys=True) Slice = models.Slice @@ -210,6 +212,24 @@ def load_examples(): session.add(slc) slices.append(slc) + slice_name = "Title" + slc = session.query(Slice).filter_by(slice_name=slice_name).first() + code = """ +### Birth Names Dashboard +The source dataset came from [here](https://github.com/hadley/babynames) + +![img](http://monblog.system-linux.net/image/tux/baby-tux_overlord59-tux.png) + """ + if not slc: + slc = Slice( + slice_name=slice_name, + viz_type='markup', + datasource_type='table', + table=tbl, + params=get_slice_json( + slice_name, "", "markup", ['name'], code=code)) + session.add(slc) + slices.append(slc) print("Creating a dashboard") Dash = models.Dashboard @@ -222,44 +242,51 @@ def load_examples(): { "size_y": 5, "size_x": 2, - "col": 5, + "col": 10, "slice_id": "1", "row": 1 }, { "size_y": 5, "size_x": 2, - "col": 7, + "col": 8, "slice_id": "2", "row": 1 }, { "size_y": 2, "size_x": 2, - "col": 1, + "col": 6, "slice_id": "3", "row": 1 }, { "size_y": 2, "size_x": 2, - "col": 3, + "col": 4, "slice_id": "4", "row": 1 }, { "size_y": 3, "size_x": 4, - "col": 1, + "col": 4, "slice_id": "5", "row": 3 }, { "size_y": 6, - "size_x": 8, + "size_x": 11, "col": 1, "slice_id": "6", "row": 6 + }, + { + "size_y": 5, + "size_x": 3, + "col": 1, + "slice_id": "9", + "row": 1 } ] """ diff --git a/panoramix/forms.py b/panoramix/forms.py index 29b5b22d76fd8..69d001927559c 100644 --- a/panoramix/forms.py +++ b/panoramix/forms.py @@ -1,4 +1,5 @@ -from wtforms import Field, Form, SelectMultipleField, SelectField, TextField +from wtforms import ( + Field, Form, SelectMultipleField, SelectField, TextField, TextAreaField) from copy import copy @@ -84,6 +85,12 @@ def form_factory(viz): description="Based on granularity, number of time periods to compare against"), 'compare_suffix': TextField('Comparison suffix', description="Suffix to apply after the percentage display"), + 'markup_type': SelectField( + "Markup Type", + choices=[(s, s) for s in ['markdown', 'html']], + default="markdown", + description="Pick your favorite markup language"), + 'code': TextAreaField("Code", description="Put your code here"), } field_css_classes = {k: ['form-control'] for k in px_form_fields.keys()} select2 = [ diff --git a/panoramix/views.py b/panoramix/views.py index c5148fbe25bcb..a295a63232a65 100644 --- a/panoramix/views.py +++ b/panoramix/views.py @@ -10,7 +10,7 @@ from wtforms.validators import ValidationError from flask.ext.appbuilder.actions import action -from panoramix import appbuilder, db, models, viz, utils, app +from panoramix import appbuilder, db, models, viz, utils, app, config def validate_json(form, field): @@ -288,13 +288,17 @@ def datasource(self, datasource_type, datasource_id): status=status, mimetype="application/json") else: - try: - resp = self.render_template("panoramix/viz.html", viz=obj) + #try: + resp = self.render_template("panoramix/viz.html", viz=obj) + ''' except Exception as e: + if config.DEBUG: + raise(e) return Response( str(e), status=500, mimetype="application/json") + ''' return resp @has_access diff --git a/panoramix/viz.py b/panoramix/viz.py index 2d80bb04ce184..457a2d315d853 100644 --- a/panoramix/viz.py +++ b/panoramix/viz.py @@ -4,6 +4,7 @@ import uuid from flask import flash +from markdown import markdown from werkzeug.datastructures import MultiDict from werkzeug.urls import Href import numpy as np @@ -21,7 +22,6 @@ class BaseViz(object): verbose_name = "Base Viz" template = None - hidden_fields = [] form_fields = [ 'viz_type', 'metrics', 'groupby', 'granularity', ('since', 'until')] @@ -161,6 +161,20 @@ def get_df(self): return df +class MarkupViz(BaseViz): + verbose_name = "Markup Widget" + template = 'panoramix/viz_markup.html' + form_fields = ['viz_type', 'markup_type', 'code'] + + def rendered(self): + markup_type = self.form_data.get("markup_type") + code = self.form_data.get("code", '') + if markup_type == "markdown": + return markdown(code) + elif markup_type == "html": + return code + + class HighchartsViz(BaseViz): verbose_name = "Base Highcharts Viz" template = 'panoramix/viz_highcharts.html' @@ -174,7 +188,6 @@ class HighchartsViz(BaseViz): class BubbleViz(HighchartsViz): verbose_name = "Bubble Chart" chart_type = 'bubble' - hidden_fields = ['granularity', 'metrics', 'groupby'] form_fields = [ 'viz_type', 'since', 'until', 'series', 'entity', 'x', 'y', 'size', 'limit'] @@ -376,4 +389,5 @@ class DistributionBarViz(DistributionPieViz): ['dist_bar', DistributionBarViz], ['pie', DistributionPieViz], ['bubble', BubbleViz], + ['markup', MarkupViz], ]) diff --git a/requirements.txt b/requirements.txt index eb06eeb912c9f..1dcd911eb5cb2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,7 @@ flask flask-migrate flask-appbuilder gunicorn +markdown mysql-python pandas parsedatetime