Add SQL insight dashboard widgets

This commit is contained in:
Peter Stockings
2026-09-06 13:37:46 +10:00
parent ff6a921550
commit d1100ece80
11 changed files with 273 additions and 28 deletions
+64 -7
View File
@@ -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."