An airpal like interface

This commit is contained in:
Maxime Beauchemin 2016-01-29 10:29:23 -08:00
parent 354ef9b4bb
commit e8ae49d181
3 changed files with 139 additions and 2 deletions

View File

@ -11,11 +11,11 @@ List of TODO items for Panoramix
the same way that you can groupby for series, you could chart by. The form fieldset would be common and use
a single field to "grid by", a limit number of chart as an N * N grid size.
* **Free form SQL editor:** Having an Airpal-like easy SQL editor
* **Advanced dashboard configuration:** define which slices are immune to which filters, how often widgets should refresh,
* **Advanced dashboard configuration:** define which slices are immune to which filters, how often widgets should refresh,
maybe this should start as a json blob...
* **Getting proper JS testing:** unit tests on the Python side are pretty solid, but now we need a test
suite for the JS part of the site, testing all the ajax-type calls
* **Annotations layers:** allow for people to maintain data annotations,
* **Annotations layers:** allow for people to maintain data annotations,
attached to a layer and time range. These layers can be added on top of some visualizations as annotations.
An example of a layer might be "holidays" or "site outages", ...
* **Worth doing? User defined groups:** People could define mappings in the UI of say "Countries I follow" and apply it to different datasets. For now, this is done by writing CASE-WHEN-type expression which is probably good enough.

View File

@ -0,0 +1,105 @@
{% extends "panoramix/base.html" %}
{% block head_css %}
{{super()}}
<link rel="stylesheet" type="text/css" href="/static/lib/dataTables/jquery.dataTables.min.css" />
<link rel="stylesheet" type="text/css" href="/static/lib/dataTables/dataTables.bootstrap.css" />
<style type="text/css">
.topsql {
height: 250px;
}
.bordered {
padding: 5px 10px;
border: 1px solid grey;
border-radius: 5px;
background-color: #EEE;
}
.metadata {
overflow: auto;
width: 300px;
height: 100px;
}
.fillup {
width: 100%;
height: 100%;
}
.fillheight {
height: 100%;
}
#interactive {
padding-top: 10px;
}
#results {
overflow: auto;
font-size: 12px;
}
#results table tbody tr td{
padding: 2px 4px;
}
</style>
{% endblock %}
{% block content %}
<h2>db: [{{ db }}]</h2>
<div class="topsql row">
<div class="col-xs-7 fillheight">
<textarea id="sql" class="fillup">SELECT * FROM information_schema.tables;
</textarea>
</div>
<div class="col-xs-5 fillheight">
<div class="metadata fillup bordered">
Tables
</div>
</div>
</div>
<div id="interactive">
<input type="hidden" id="database_id" value="{{ database_id }}">
<button class="btn btn-primary" id="run">Run!</button>
<button class="btn btn-default" id="view">Create View</button>
</div>
<div id="results_section">
<hr/>
<img id="loading" width="25" style="display: none;" src="/static/img/loading.gif">
</div>
<div>
<div id="results" class="bordered"></div>
</div>
{% endblock %}
{% block tail_js %}
{{ super() }}
<script src="/static/lib/bootstrap-toggle.min.js"></script>
<script src="/static/lib/dataTables/jquery.dataTables.min.js"></script>
<script src="/static/lib/dataTables/dataTables.bootstrap.js"></script>
<script>
$(document).ready(function() {
$("#run").click(function() {
$('#results').hide(0);
$('#loading').show(0);
$.ajax({
type: "POST",
url: '/panoramix/runsql/',
data: {
'data': JSON.stringify({
'database_id': $('#database_id').val(),
'sql': $('#sql').val(),
})},
success: function(data) {
$('#loading').hide(0);
$('#results').show(0);
$('#results').html(data);
var datatable = $('table').DataTable({
paging: false,
searching: true,
});
},
error: function() {
$('#loading').hide(0);
},
});
});
});
</script>
{% endblock %}

View File

@ -552,6 +552,38 @@ class Panoramix(BaseView):
templates=templates,
pos_dict=pos_dict)
@has_access
@expose("/sql/<database_id>/")
@utils.log_this
def sql(self, database_id):
mydb = db.session.query(models.Database).filter_by(id=database_id).first()
return self.render_template(
"panoramix/sql.html",
database_id=database_id,
db=mydb)
@has_access
@expose("/runsql/", methods=['POST', 'GET'])
@utils.log_this
def runsql(self):
session = db.session()
data = json.loads(request.form.get('data'))
sql = data.get('sql')
database_id = data.get('database_id')
mydb = session.query(models.Database).filter_by(id=database_id).first()
content = ""
if mydb:
print("SUPER!")
from pandas import read_sql_query
eng = mydb.get_sqla_engine()
df = read_sql_query(sql=sql, con=eng)
content = df.to_html(
classes="dataframe table table-striped table-bordered table-condensed")
else:
print("ELSE")
session.commit()
return content
@has_access
@expose("/refresh_datasources/")
def refresh_datasources(self):