Add SQL insight dashboard widgets
This commit is contained in:
+64
-7
@@ -65,18 +65,75 @@ def _save_query(title, query):
|
||||
db.getDB().rollback()
|
||||
return error
|
||||
|
||||
def _list_saved_queries():
|
||||
"""Lists all saved queries."""
|
||||
return db.execute("SELECT id, title, query FROM saved_query ORDER BY title")
|
||||
def _list_saved_queries():
|
||||
"""Lists all saved queries."""
|
||||
person_id = getattr(current_user, 'id', None) or -1
|
||||
return db.execute("""
|
||||
SELECT
|
||||
q.id,
|
||||
q.title,
|
||||
q.query,
|
||||
EXISTS (
|
||||
SELECT 1 FROM dashboard_widget w
|
||||
WHERE w.saved_query_id = q.id
|
||||
AND w.person_id = %s
|
||||
AND w.visualization_type = 'table'
|
||||
AND w.is_visible = TRUE
|
||||
) AS table_pinned,
|
||||
EXISTS (
|
||||
SELECT 1 FROM dashboard_widget w
|
||||
WHERE w.saved_query_id = q.id
|
||||
AND w.person_id = %s
|
||||
AND w.visualization_type = 'graph'
|
||||
AND w.is_visible = TRUE
|
||||
) AS graph_pinned
|
||||
FROM saved_query q
|
||||
ORDER BY q.title
|
||||
""", [person_id, person_id])
|
||||
|
||||
def _get_saved_query(query_id):
|
||||
"""Fetches a specific saved query."""
|
||||
result = db.execute("SELECT title, query FROM saved_query WHERE id=%s", [query_id], one=True)
|
||||
return (result['title'], result['query']) if result else (None, None)
|
||||
|
||||
def _delete_saved_query(query_id):
|
||||
"""Deletes a saved query."""
|
||||
db.execute("DELETE FROM saved_query WHERE id=%s", [query_id], commit=True)
|
||||
def _delete_saved_query(query_id):
|
||||
"""Deletes a saved query."""
|
||||
db.execute("DELETE FROM saved_query WHERE id=%s", [query_id], commit=True)
|
||||
|
||||
|
||||
@sql_explorer_bp.route('/widget/<int:query_id>', methods=['POST', 'DELETE'])
|
||||
@login_required
|
||||
def dashboard_widget(query_id):
|
||||
"""Pin or unpin a saved query as a personal Home dashboard widget."""
|
||||
visualization_type = request.values.get('visualization_type', 'table')
|
||||
if visualization_type not in ('table', 'graph'):
|
||||
return "Unsupported visualization type", 400
|
||||
|
||||
query = db.execute("SELECT id FROM saved_query WHERE id=%s", [query_id], one=True)
|
||||
if not query:
|
||||
return "Query not found", 404
|
||||
|
||||
if request.method == 'POST':
|
||||
db.execute("""
|
||||
INSERT INTO dashboard_widget (person_id, saved_query_id, visualization_type)
|
||||
VALUES (%s, %s, %s)
|
||||
ON CONFLICT (person_id, saved_query_id, visualization_type)
|
||||
DO UPDATE SET is_visible = TRUE
|
||||
""", [current_user.id, query_id, visualization_type], commit=True)
|
||||
else:
|
||||
db.execute("""
|
||||
DELETE FROM dashboard_widget
|
||||
WHERE person_id=%s AND saved_query_id=%s AND visualization_type=%s
|
||||
""", [current_user.id, query_id, visualization_type], commit=True)
|
||||
|
||||
# Home widgets target themselves, while SQL Explorer refreshes its library.
|
||||
if request.headers.get('HX-Target', '').startswith('dashboard-widget-'):
|
||||
return ''
|
||||
|
||||
return render_template(
|
||||
'partials/sql_explorer/saved_queries.html',
|
||||
saved_queries=_list_saved_queries()
|
||||
)
|
||||
|
||||
def _generate_sql_from_natural_language(natural_query):
|
||||
"""Generates SQL query from natural language using Gemini REST API."""
|
||||
@@ -268,4 +325,4 @@ def generate_sql():
|
||||
# Return error message prepended, to be displayed in the textarea
|
||||
return f"-- Error generating SQL: {error}\n\n"
|
||||
|
||||
return generated_sql if generated_sql else "-- No SQL generated."
|
||||
return generated_sql if generated_sql else "-- No SQL generated."
|
||||
|
||||
Reference in New Issue
Block a user