mirror of https://github.com/apache/superset.git
Merge pull request #193 from airbnb/favstar
Adding favorites for Slices and Dashboards
This commit is contained in:
commit
3118d1b302
|
@ -17,6 +17,7 @@ var Dashboard = function (dashboardData) {
|
|||
filters: {},
|
||||
init: function () {
|
||||
this.initDashboardView();
|
||||
px.initFavStars();
|
||||
var sliceObjects = [],
|
||||
dash = this;
|
||||
dashboard.slices.forEach(function (data) {
|
||||
|
|
|
@ -117,6 +117,8 @@ function initExploreView() {
|
|||
$("#collapsed_fieldsets").val(collapsed_fieldsets.join("||"));
|
||||
}
|
||||
|
||||
px.initFavStars();
|
||||
|
||||
$('legend').click(function () {
|
||||
toggle_fieldset($(this), true);
|
||||
});
|
||||
|
|
|
@ -132,6 +132,46 @@ var px = (function () {
|
|||
};
|
||||
}
|
||||
|
||||
function initFavStars() {
|
||||
var baseUrl = '/dashed/favstar/';
|
||||
// Init star behavihor for favorite
|
||||
function show() {
|
||||
if ($(this).hasClass('selected')) {
|
||||
$(this).html('<i class="fa fa-star"></i>');
|
||||
} else {
|
||||
$(this).html('<i class="fa fa-star-o"></i>');
|
||||
}
|
||||
}
|
||||
$('.favstar')
|
||||
.attr('title', 'Click to favorite/unfavorite')
|
||||
.each(show)
|
||||
.each(function () {
|
||||
var url = baseUrl + $(this).attr("class_name");
|
||||
var star = this;
|
||||
url += '/' + $(this).attr("obj_id") + '/';
|
||||
$.getJSON(url + 'count/', function (data) {
|
||||
if (data.count > 0) {
|
||||
$(star)
|
||||
.addClass('selected')
|
||||
.each(show);
|
||||
}
|
||||
});
|
||||
})
|
||||
.click(function () {
|
||||
$(this).toggleClass('selected');
|
||||
var url = baseUrl + $(this).attr("class_name");
|
||||
url += '/' + $(this).attr("obj_id") + '/';
|
||||
if ($(this).hasClass('selected')) {
|
||||
url += 'select/';
|
||||
} else {
|
||||
url += 'unselect/';
|
||||
}
|
||||
$.get(url);
|
||||
$(this).each(show);
|
||||
})
|
||||
.tooltip();
|
||||
}
|
||||
|
||||
var Slice = function (data, dashboard) {
|
||||
var timer;
|
||||
var token = $('#' + data.token);
|
||||
|
@ -334,7 +374,8 @@ var px = (function () {
|
|||
formatDate: formatDate,
|
||||
timeFormatFactory: timeFormatFactory,
|
||||
color: color(),
|
||||
getParam: getParam
|
||||
getParam: getParam,
|
||||
initFavStars: initFavStars
|
||||
};
|
||||
})();
|
||||
|
||||
|
|
|
@ -26,6 +26,12 @@ input.form-control {
|
|||
margin-left: 365px;
|
||||
}
|
||||
|
||||
.favstar {
|
||||
margin-right: 10px;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.slice_description{
|
||||
padding: 8px;
|
||||
margin: 5px;
|
||||
|
@ -84,7 +90,10 @@ form div {
|
|||
|
||||
.notbtn {
|
||||
cursor: default;
|
||||
box-shadow: none;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
"""adding favstar model
|
||||
|
||||
Revision ID: a2d606a761d9
|
||||
Revises: 430039611635
|
||||
Create Date: 2016-03-13 09:56:58.329512
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'a2d606a761d9'
|
||||
down_revision = '18e88e1cc004'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table('favstar',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=True),
|
||||
sa.Column('class_name', sa.String(length=50), nullable=True),
|
||||
sa.Column('obj_id', sa.Integer(), nullable=True),
|
||||
sa.Column('dttm', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['ab_user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('favstar')
|
|
@ -0,0 +1,22 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: d2424a248d63
|
||||
Revises: ('a2d606a761d9', '836c0bf75904')
|
||||
Create Date: 2016-03-22 23:25:02.903273
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'd2424a248d63'
|
||||
down_revision = ('a2d606a761d9', '836c0bf75904')
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
pass
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
|
@ -1204,3 +1204,13 @@ class DruidColumn(Model):
|
|||
if not m:
|
||||
session.add(metric)
|
||||
session.commit()
|
||||
|
||||
|
||||
class FavStar(Model):
|
||||
__tablename__ = 'favstar'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey('ab_user.id'))
|
||||
class_name = Column(String(50))
|
||||
obj_id = Column(Integer)
|
||||
dttm = Column(DateTime, default=func.now())
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<div class="col-md-3"></div>
|
||||
<div class="col-md-6">
|
||||
<h2>
|
||||
<span class="favstar" class_name="Dashboard" obj_id="{{ dashboard.id }}"></span>
|
||||
{{ dashboard.dashboard_title }}
|
||||
</h2>
|
||||
</div>
|
||||
|
|
|
@ -29,21 +29,23 @@
|
|||
<div class="datasource container-fluid">
|
||||
<form id="query" method="GET" style="display: none;">
|
||||
<div class="header">
|
||||
<span class="btn btn-default notbtn">
|
||||
<strong>{{ datasource.full_name }}</strong>
|
||||
<span class="btn btn-default notbtn" title="datasource" data-toggle="tooltip">
|
||||
{{ datasource.full_name }}
|
||||
{% if datasource.description %}
|
||||
<a data-toggle="modal" data-target="#sourceinfo_modal">
|
||||
<i class="fa fa-info-circle" data-toggle="tooltip" data-placement="bottom" title="{{ datasource.description }}"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="" href="/{{ datasource.baselink }}/edit/{{ datasource.id }}" data-toggle="tooltip" title="Edit datasource">
|
||||
<a class="" href="/{{ datasource.baselink }}/edit/{{ datasource.id }}" data-toggle="tooltip" title="Edit">
|
||||
<i class="fa fa-edit"></i>
|
||||
</a>
|
||||
</span>
|
||||
<span>{{ form.get_field("viz_type")(class_="select2") }}</span>
|
||||
{% if slice %}
|
||||
<span class="alert alert-info" title="Slice" data-toggle="tooltip">{{ slice.slice_name }}
|
||||
<a class="" href="/slicemodelview/edit/{{ slice.id }}" data-toggle="tooltip" title="Edit Slice metadata">
|
||||
<span class="btn btn-default notbtn" title="Slice" data-toggle="tooltip" data-placement="bottom">
|
||||
<span class="favstar" class_name="Slice" obj_id="{{ slice.id }}"></span>
|
||||
{{ slice.slice_name }}
|
||||
<a class="" href="/slicemodelview/edit/{{ slice.id }}" data-toggle="tooltip" title="Edit">
|
||||
{% if slice.description %}
|
||||
<i class="fa fa-info-circle" data-toggle="tooltip" data-placement="bottom" title="{{ slice.description }}"></i>
|
||||
{% endif %}
|
||||
|
|
|
@ -6,7 +6,8 @@ import logging
|
|||
import re
|
||||
import traceback
|
||||
|
||||
from flask import request, redirect, flash, Response, render_template, Markup
|
||||
from flask import (
|
||||
g, request, redirect, flash, Response, render_template, Markup)
|
||||
from flask.ext.appbuilder import ModelView, CompactCRUDMixin, BaseView, expose
|
||||
from flask.ext.appbuilder.actions import action
|
||||
from flask.ext.appbuilder.models.sqla.interface import SQLAInterface
|
||||
|
@ -559,6 +560,30 @@ class Dashed(BaseView):
|
|||
status=500,
|
||||
mimetype="application/json")
|
||||
|
||||
@expose("/favstar/<class_name>/<obj_id>/<action>/")
|
||||
def favstar(self, class_name, obj_id, action):
|
||||
session = db.session()
|
||||
FavStar = models.FavStar
|
||||
count = 0
|
||||
favs = session.query(FavStar).filter_by(
|
||||
class_name=class_name, obj_id=obj_id, user_id=g.user.id).all()
|
||||
if action == 'select':
|
||||
if not favs:
|
||||
session.add(
|
||||
FavStar(
|
||||
class_name=class_name, obj_id=obj_id, user_id=g.user.id,
|
||||
dttm=datetime.now()))
|
||||
count = 1
|
||||
elif action == 'unselect':
|
||||
for fav in favs:
|
||||
session.delete(fav)
|
||||
else:
|
||||
count = len(favs)
|
||||
session.commit()
|
||||
return Response(
|
||||
json.dumps({'count': count}),
|
||||
mimetype="application/json")
|
||||
|
||||
@has_access
|
||||
@expose("/dashboard/<dashboard_id>/")
|
||||
def dashboard(self, dashboard_id):
|
||||
|
|
Loading…
Reference in New Issue