#!/usr/bin/env python3 """Apply Palantir styling and enrich ATC Lakehouse Superset dashboard.""" import json import os import requests BASE = "http://127.0.0.1:8088" DASH_ID = 1 CSS_PATH = "/tmp/palantir_dashboard.css" NEW_CHARTS = [ ( "Trino · PostgreSQL Sales", "public", "sales_orders", "PostgreSQL · Orders by Channel", "pie", { "metric": {"expressionType": "SQL", "sqlExpression": "COUNT(*)", "label": "COUNT(*)"}, "groupby": ["sales_channel"], "row_limit": 10, }, ), ( "Trino · PostgreSQL Sales", "public", "sales_orders", "PostgreSQL · Avg Order by Region", "echarts_timeseries_bar", { "metrics": [ {"expressionType": "SQL", "sqlExpression": "AVG(amount)", "label": "Avg Amount"} ], "groupby": ["region"], "row_limit": 15, }, ), ( "Trino · PostgreSQL Sales", "public", "sales_orders", "PostgreSQL · Status Breakdown", "pie", { "metric": {"expressionType": "SQL", "sqlExpression": "COUNT(*)", "label": "COUNT(*)"}, "groupby": ["order_status"], "row_limit": 10, }, ), ( "Trino · MySQL HR", "hr", "employee_events", "MySQL HR · By Event Type", "pie", { "metric": {"expressionType": "SQL", "sqlExpression": "COUNT(*)", "label": "COUNT(*)"}, "groupby": ["event_type"], "row_limit": 12, }, ), ( "Trino · MySQL HR", "hr", "employee_events", "MySQL HR · Events per Month", "echarts_timeseries_line", { "metrics": [ {"expressionType": "SQL", "sqlExpression": "COUNT(*)", "label": "Events"} ], "groupby": [ { "expressionType": "SQL", "sqlExpression": "date_trunc('month', event_ts)", "label": "Month", } ], "row_limit": 24, }, ), ( "Trino · MongoDB Supply Chain", "supplychain", "events", "MongoDB · Amount by Source", "echarts_timeseries_bar", { "metrics": [ {"expressionType": "SQL", "sqlExpression": "SUM(amount)", "label": "Total Amount"} ], "groupby": ["source"], "row_limit": 10, }, ), ( "Trino · MongoDB Supply Chain", "supplychain", "events", "MongoDB · Events per Month", "echarts_timeseries_line", { "metrics": [ {"expressionType": "SQL", "sqlExpression": "COUNT(*)", "label": "Events"} ], "groupby": [ { "expressionType": "SQL", "sqlExpression": "date_trunc('month', ts)", "label": "Month", } ], "row_limit": 24, }, ), ( "Trino · Cassandra Telemetry", "telemetry", "device_metrics", "Cassandra · Avg Metric Over Time", "echarts_timeseries_line", { "metrics": [ { "expressionType": "SQL", "sqlExpression": "AVG(metric_value)", "label": "Avg Value", } ], "groupby": [ { "expressionType": "SQL", "sqlExpression": "date_trunc('day', metric_ts)", "label": "Day", } ], "row_limit": 30, }, ), ] SECTIONS = [ ("HEADER", "ATC Lakehouse · Federated Data Platform", "Trino · PostgreSQL · MySQL · MongoDB · Cassandra · Dell Technologies FDE"), ("PostgreSQL Sales", "30M orders · postgres_sales.public.sales_orders"), ("MySQL HR", "569K events · mysql_hr.hr.employee_events"), ("MongoDB Supply Chain", "3M events · mongodb_supplychain.supplychain.events"), ("Cassandra Telemetry", "Device metrics · cassandra_telemetry.telemetry.device_metrics"), ] def session(): s = requests.Session() r = s.post( f"{BASE}/api/v1/security/login", json={"username": "admin", "password": "admin", "provider": "db", "refresh": True}, ) r.raise_for_status() h = { "Authorization": "Bearer " + r.json()["access_token"], "Content-Type": "application/json", } h["X-CSRFToken"] = s.get(f"{BASE}/api/v1/security/csrf_token/", headers=h).json()["result"] h["Referer"] = BASE return s, h def get_db_map(s, h): r = s.get(f"{BASE}/api/v1/database/", headers=h) r.raise_for_status() return {d["database_name"]: d["id"] for d in r.json().get("result", [])} def get_or_create_dataset(s, h, db_id, schema, table): r = s.get(f"{BASE}/api/v1/dataset/", headers=h) for d in r.json().get("result", []): if ( d.get("table_name") == table and d.get("schema") == schema and d.get("database", {}).get("id") == db_id ): return d["id"] r = s.post( f"{BASE}/api/v1/dataset/", headers=h, json={"database": db_id, "schema": schema, "table_name": table}, ) r.raise_for_status() return r.json()["id"] def create_chart(s, h, name, ds_id, viz_type, params): r = s.get(f"{BASE}/api/v1/chart/", headers=h) for c in r.json().get("result", []): if c.get("slice_name") == name: return c["id"] full = {"datasource": f"{ds_id}__table", "viz_type": viz_type, "row_limit": 1000, **params} r = s.post( f"{BASE}/api/v1/chart/", headers=h, json={ "slice_name": name, "viz_type": viz_type, "datasource_id": ds_id, "datasource_type": "table", "params": json.dumps(full), "owners": [1, 2, 3], }, ) if r.status_code not in (200, 201): raise RuntimeError(f"chart {name}: {r.text[:300]}") return r.json()["id"] def build_layout(chart_items): """chart_items: list of (chart_id, name, section) or ('md', title, subtitle).""" layout = { "DASHBOARD_VERSION": "v2", "ROOT_ID": {"type": "ROOT", "id": "ROOT_ID", "children": ["GRID_ID"]}, "GRID_ID": {"type": "GRID", "id": "GRID_ID", "children": [], "parents": ["ROOT_ID"]}, } row_idx = 0 def add_row(): nonlocal row_idx row_idx += 1 rid = f"ROW-{row_idx}" layout["GRID_ID"]["children"].append(rid) layout[rid] = { "type": "ROW", "id": rid, "children": [], "parents": ["ROOT_ID", "GRID_ID"], "meta": {"background": "BACKGROUND_TRANSPARENT"}, } return rid for item in chart_items: if item[0] == "md": _, title, subtitle = item rid = add_row() mid = f"MARKDOWN-{row_idx}" layout[rid]["children"].append(mid) layout[mid] = { "type": "MARKDOWN", "id": mid, "children": [], "parents": ["ROOT_ID", "GRID_ID", rid], "meta": { "width": 12, "height": 12, "code": f"## {title}\n\n{subtitle}", }, } else: cid, name, _section = item rid = add_row() # up to 3 charts per row existing = [ k for k in layout[rid]["children"] if k.startswith("CHART-") ] if len(existing) >= 3: rid = add_row() chart_key = f"CHART-explore-{cid}" layout[rid]["children"].append(chart_key) col = len([k for k in layout[rid]["children"] if k.startswith("CHART-")]) - 1 layout[chart_key] = { "type": "CHART", "id": chart_key, "children": [], "parents": ["ROOT_ID", "GRID_ID", rid], "meta": { "width": 4, "height": 55 if "Total" in name or "Records" in name else 65, "chartId": cid, "sliceName": name, }, } return layout def save_query_contexts(): app = __import__("superset.app", fromlist=["create_app"]).create_app() with app.app_context(): from flask import g from superset.extensions import db from superset.models.slice import Slice from superset.charts.schemas import ChartDataQueryContextSchema from superset import security_manager g.user = security_manager.find_user(username="admin") for sl in db.session.query(Slice).all(): try: fd = sl.form_data metric = fd.get("metric") metrics = fd.get("metrics") or ([metric] if metric else []) if not metrics: metrics = [ { "expressionType": "SQL", "sqlExpression": "COUNT(*)", "label": "COUNT(*)", } ] groupby = fd.get("groupby") or [] payload = { "datasource": {"id": sl.datasource_id, "type": sl.datasource_type}, "force": False, "queries": [ { "filters": [], "extras": {"having": "", "where": ""}, "applied_time_extras": {}, "columns": groupby if isinstance(groupby, list) else [], "metrics": metrics, "orderby": [], "annotation_layers": [], "row_limit": int(fd.get("row_limit") or 1000), "series_limit": 0, "order_desc": True, "url_params": {}, "custom_params": {}, "custom_form_data": {}, } ], "form_data": fd, "result_format": "json", "result_type": "full", } ChartDataQueryContextSchema().load(payload) sl.query_context = json.dumps(payload) sl.query_context_generation = True db.session.add(sl) except Exception as e: print("qc err", sl.id, e) db.session.commit() def main(): s, h = session() db_map = get_db_map(s, h) # Create new charts new_ids = [] for db_name, schema, table, name, viz, params in NEW_CHARTS: db_id = db_map.get(db_name) if not db_id: print("skip, no db:", db_name) continue ds_id = get_or_create_dataset(s, h, db_id, schema, table) cid = create_chart(s, h, name, ds_id, viz, params) new_ids.append((cid, name, db_name.split("·")[-1].strip())) print("new chart", cid, name) # All charts for dashboard r = s.get(f"{BASE}/api/v1/chart/?q=(page:0,page_size:200)", headers=h) all_charts = r.json().get("result", []) def sort_key(c): n = c.get("slice_name") or "" if "Lakehouse" in n or "Records per Source" in n: return (0, n) if "PostgreSQL" in n: return (1, n) if "MySQL" in n: return (2, n) if "MongoDB" in n: return (3, n) if "Cassandra" in n: return (4, n) return (5, n) all_charts.sort(key=sort_key) chart_items = [ ("md", "ATC Lakehouse · Federated Data Platform", "Real-time analytics across all Trino catalogs · Dell Technologies"), ] current_section = None for c in all_charts: name = c.get("slice_name") or "" if "PostgreSQL" in name and current_section != "pg": chart_items.append(("md", "PostgreSQL Sales", "30M orders · CDC-enabled · atc-db02")) current_section = "pg" elif "MySQL" in name and current_section != "mysql": chart_items.append(("md", "MySQL HR", "569K employee events · HR domain")) current_section = "mysql" elif "MongoDB" in name and current_section != "mongo": chart_items.append(("md", "MongoDB Supply Chain", "3M supply chain events")) current_section = "mongo" elif "Cassandra" in name and current_section != "cass": chart_items.append(("md", "Cassandra Telemetry", "IoT device metrics")) current_section = "cass" chart_items.append((c["id"], name, current_section)) chart_ids = [x[0] for x in chart_items if x[0] != "md"] position = build_layout(chart_items) css = "" if os.path.exists(CSS_PATH): css = open(CSS_PATH, encoding="utf-8").read() chart_configuration = { str(cid): {"id": cid, "crossFilters": {"scope": "global", "chartsInScope": chart_ids}} for cid in chart_ids } payload = { "dashboard_title": "ATC Lakehouse · Trino Federated", "published": True, "position_json": json.dumps(position), "css": css, "json_metadata": json.dumps( { "color_scheme": "palantir_ops", "label_colors": {}, "refresh_frequency": 120, "timed_refresh_immune_slices": [], "expanded_slices": {}, "chart_configuration": chart_configuration, "global_chart_configuration": { "scope": {"rootPath": ["ROOT_ID"], "excluded": []}, "chartsInScope": chart_ids, }, "native_filter_configuration": [], "color_scheme_domain": [], "shared_label_colors": {}, } ), "owners": [1, 2, 3], } r = s.put(f"{BASE}/api/v1/dashboard/{DASH_ID}", headers=h, json=payload) print("dashboard update", r.status_code) if r.status_code >= 400: print(r.text[:500]) return for cid in chart_ids: s.put( f"{BASE}/api/v1/chart/{cid}", headers=h, json={"dashboards": [DASH_ID], "owners": [1, 2, 3]}, ) print("Saving query contexts...") save_query_contexts() print(f"Done — {len(chart_ids)} charts, Palantir theme applied to dashboard.") if __name__ == "__main__": main()