feat(api): dashboard get predefined metrics charts
feat(api): support root_path for Uvicorn server
This commit is contained in:
parent
cfcff0293a
commit
1807174b8b
5 changed files with 144 additions and 18 deletions
|
|
@ -13,7 +13,7 @@ from routers.crons import core_crons
|
|||
from routers.crons import core_dynamic_crons
|
||||
from routers.subs import dashboard, insights, metrics, v1_api
|
||||
|
||||
app = FastAPI()
|
||||
app = FastAPI(root_path="/api")
|
||||
|
||||
|
||||
@app.middleware('http')
|
||||
|
|
|
|||
|
|
@ -54,13 +54,9 @@ def merged_live(project_id, data: schemas.CreateCustomMetricsSchema):
|
|||
return results
|
||||
|
||||
|
||||
def __get_merged_metric(project_id, user_id, metric_id,
|
||||
data: Union[schemas.CustomMetricChartPayloadSchema,
|
||||
schemas.CustomMetricSessionsPayloadSchema]) \
|
||||
def __merge_metric_with_data(metric, data: Union[schemas.CustomMetricChartPayloadSchema,
|
||||
schemas.CustomMetricSessionsPayloadSchema]) \
|
||||
-> Union[schemas.CreateCustomMetricsSchema, None]:
|
||||
metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
|
||||
if metric is None:
|
||||
return None
|
||||
metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj({**data.dict(), **metric})
|
||||
if len(data.filters) > 0 or len(data.events) > 0:
|
||||
for s in metric.series:
|
||||
|
|
@ -71,11 +67,12 @@ def __get_merged_metric(project_id, user_id, metric_id,
|
|||
return metric
|
||||
|
||||
|
||||
def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPayloadSchema):
|
||||
metric: schemas.CreateCustomMetricsSchema = __get_merged_metric(project_id=project_id, user_id=user_id,
|
||||
metric_id=metric_id, data=data)
|
||||
def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPayloadSchema, metric=None):
|
||||
if metric is None:
|
||||
metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
|
||||
if metric is None:
|
||||
return None
|
||||
metric: schemas.CreateCustomMetricsSchema = __merge_metric_with_data(metric=metric, data=data)
|
||||
series_charts = __try_live(project_id=project_id, data=metric)
|
||||
if metric.view_type == schemas.MetricTimeseriesViewType.progress or metric.metric_type == schemas.MetricType.table:
|
||||
return series_charts
|
||||
|
|
@ -88,8 +85,10 @@ def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPa
|
|||
|
||||
|
||||
def get_sessions(project_id, user_id, metric_id, data: schemas.CustomMetricSessionsPayloadSchema):
|
||||
metric: schemas.CreateCustomMetricsSchema = __get_merged_metric(project_id=project_id, user_id=user_id,
|
||||
metric_id=metric_id, data=data)
|
||||
metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
|
||||
if metric is None:
|
||||
return None
|
||||
metric: schemas.CreateCustomMetricsSchema = __merge_metric_with_data(metric=metric, data=data)
|
||||
if metric is None:
|
||||
return None
|
||||
results = []
|
||||
|
|
@ -294,6 +293,36 @@ def get(metric_id, project_id, user_id, flatten=True):
|
|||
return helper.dict_to_camel_case(row)
|
||||
|
||||
|
||||
def get_with_template(metric_id, project_id, user_id):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
cur.mogrify(
|
||||
"""SELECT *
|
||||
FROM metrics
|
||||
LEFT JOIN LATERAL (SELECT COALESCE(jsonb_agg(metric_series.* ORDER BY index),'[]'::jsonb) AS series
|
||||
FROM metric_series
|
||||
WHERE metric_series.metric_id = metrics.metric_id
|
||||
AND metric_series.deleted_at ISNULL
|
||||
) AS metric_series ON (TRUE)
|
||||
LEFT JOIN LATERAL (SELECT COALESCE(jsonb_agg(connected_dashboards.* ORDER BY is_public,name),'[]'::jsonb) AS dashboards
|
||||
FROM (SELECT dashboard_id, name, is_public
|
||||
FROM dashboards
|
||||
WHERE deleted_at ISNULL
|
||||
AND project_id = %(project_id)s
|
||||
AND ((user_id = %(user_id)s OR is_public))) AS connected_dashboards
|
||||
) AS connected_dashboards ON (TRUE)
|
||||
WHERE (metrics.project_id = %(project_id)s OR metrics.project_id ISNULL)
|
||||
AND metrics.deleted_at ISNULL
|
||||
AND (metrics.user_id = %(user_id)s OR metrics.is_public)
|
||||
AND metrics.metric_id = %(metric_id)s
|
||||
ORDER BY created_at;""",
|
||||
{"metric_id": metric_id, "project_id": project_id, "user_id": user_id}
|
||||
)
|
||||
)
|
||||
row = cur.fetchone()
|
||||
return helper.dict_to_camel_case(row)
|
||||
|
||||
|
||||
def get_series_for_alert(project_id, user_id):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import json
|
||||
|
||||
import schemas
|
||||
from chalicelib.core import custom_metrics
|
||||
from chalicelib.core import custom_metrics, dashboard
|
||||
from chalicelib.utils import helper
|
||||
from chalicelib.utils import pg_client
|
||||
|
||||
|
|
@ -79,7 +79,6 @@ def get_dashboard(project_id, user_id, dashboard_id):
|
|||
AND dashboard_id = %(dashboard_id)s
|
||||
AND (dashboards.user_id = %(userId)s OR is_public);"""
|
||||
params = {"userId": user_id, "projectId": project_id, "dashboard_id": dashboard_id}
|
||||
print(cur.mogrify(pg_query, params))
|
||||
cur.execute(cur.mogrify(pg_query, params))
|
||||
row = cur.fetchone()
|
||||
return helper.dict_to_camel_case(row)
|
||||
|
|
@ -111,6 +110,30 @@ def update_dashboard(project_id, user_id, dashboard_id, data: schemas.EditDashbo
|
|||
return helper.dict_to_camel_case(row)
|
||||
|
||||
|
||||
def get_widget(project_id, user_id, dashboard_id, widget_id):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
pg_query = """SELECT metrics.*, metric_series.series
|
||||
FROM dashboard_widgets
|
||||
INNER JOIN dashboards USING (dashboard_id)
|
||||
INNER JOIN metrics USING (metric_id)
|
||||
LEFT JOIN LATERAL (SELECT COALESCE(jsonb_agg(metric_series.* ORDER BY index), '[]'::jsonb) AS series
|
||||
FROM metric_series
|
||||
WHERE metric_series.metric_id = metrics.metric_id
|
||||
AND metric_series.deleted_at ISNULL
|
||||
) AS metric_series ON (TRUE)
|
||||
WHERE dashboard_id = %(dashboard_id)s
|
||||
AND widget_id = %(widget_id)s
|
||||
AND (dashboards.is_public OR dashboards.user_id = %(userId)s)
|
||||
AND dashboards.deleted_at IS NULL
|
||||
AND metrics.deleted_at ISNULL
|
||||
AND (metrics.project_id = %(projectId)s OR metrics.project_id ISNULL)
|
||||
AND (metrics.is_public OR metrics.user_id = %(userId)s);"""
|
||||
params = {"userId": user_id, "projectId": project_id, "dashboard_id": dashboard_id, "widget_id": widget_id}
|
||||
cur.execute(cur.mogrify(pg_query, params))
|
||||
row = cur.fetchone()
|
||||
return helper.dict_to_camel_case(row)
|
||||
|
||||
|
||||
def add_widget(project_id, user_id, dashboard_id, data: schemas.AddWidgetToDashboardPayloadSchema):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
pg_query = """INSERT INTO dashboard_widgets(dashboard_id, metric_id, user_id, config, name)
|
||||
|
|
@ -154,7 +177,7 @@ def pin_dashboard(project_id, user_id, dashboard_id):
|
|||
with pg_client.PostgresClient() as cur:
|
||||
pg_query = """UPDATE dashboards
|
||||
SET is_pinned = FALSE
|
||||
WHERE dashboard_id=%(dashboard_id)s AND project_id=%(project_id)s;
|
||||
WHERE project_id=%(project_id)s;
|
||||
UPDATE dashboards
|
||||
SET is_pinned = True
|
||||
WHERE dashboard_id=%(dashboard_id)s AND project_id=%(project_id)s AND deleted_at ISNULL
|
||||
|
|
@ -169,3 +192,53 @@ def create_metric_add_widget(project_id, user_id, dashboard_id, data: schemas.Cr
|
|||
metric_id = custom_metrics.create(project_id=project_id, user_id=user_id, data=data, dashboard=True)
|
||||
return add_widget(project_id=project_id, user_id=user_id, dashboard_id=dashboard_id,
|
||||
data=schemas.AddWidgetToDashboardPayloadSchema(metric_id=metric_id))
|
||||
|
||||
|
||||
PREDEFINED = {schemas.TemplateKeys.count_sessions: dashboard.get_processed_sessions,
|
||||
schemas.TemplateKeys.avg_image_load_time: dashboard.get_application_activity_avg_image_load_time,
|
||||
schemas.TemplateKeys.avg_page_load_time: dashboard.get_application_activity_avg_page_load_time,
|
||||
schemas.TemplateKeys.avg_request_load_time: dashboard.get_application_activity_avg_request_load_time,
|
||||
schemas.TemplateKeys.avg_dom_content_load_start: dashboard.get_page_metrics_avg_dom_content_load_start,
|
||||
schemas.TemplateKeys.avg_first_contentful_pixel: dashboard.get_page_metrics_avg_first_contentful_pixel,
|
||||
schemas.TemplateKeys.avg_visited_pages: dashboard.get_user_activity_avg_visited_pages,
|
||||
schemas.TemplateKeys.avg_session_duration: dashboard.get_user_activity_avg_session_duration,
|
||||
schemas.TemplateKeys.avg_pages_dom_buildtime: dashboard.get_pages_dom_build_time,
|
||||
schemas.TemplateKeys.avg_pages_response_time: dashboard.get_pages_response_time,
|
||||
schemas.TemplateKeys.avg_response_time: dashboard.get_top_metrics_avg_response_time,
|
||||
schemas.TemplateKeys.avg_first_paint: dashboard.get_top_metrics_avg_first_paint,
|
||||
schemas.TemplateKeys.avg_dom_content_loaded: dashboard.get_top_metrics_avg_dom_content_loaded,
|
||||
schemas.TemplateKeys.avg_till_first_bit: dashboard.get_top_metrics_avg_till_first_bit,
|
||||
schemas.TemplateKeys.avg_time_to_interactive: dashboard.get_top_metrics_avg_time_to_interactive,
|
||||
schemas.TemplateKeys.count_requests: dashboard.get_top_metrics_count_requests,
|
||||
schemas.TemplateKeys.avg_time_to_render: dashboard.get_time_to_render,
|
||||
schemas.TemplateKeys.avg_used_js_heap_size: dashboard.get_memory_consumption,
|
||||
schemas.TemplateKeys.avg_cpu: dashboard.get_avg_cpu,
|
||||
schemas.TemplateKeys.avg_fps: dashboard.get_avg_fps}
|
||||
|
||||
|
||||
def get_predefined_metric(key: schemas.TemplateKeys, project_id: int, data: dict):
|
||||
return PREDEFINED.get(key, lambda *args: None)(project_id=project_id, **data)
|
||||
|
||||
|
||||
def make_chart_metrics(project_id, user_id, metric_id, data: schemas.CustomMetricChartPayloadSchema):
|
||||
raw_metric = custom_metrics.get_with_template(metric_id=metric_id, project_id=project_id, user_id=user_id)
|
||||
if raw_metric is None:
|
||||
return None
|
||||
metric = schemas.CustomMetricAndTemplate = schemas.CustomMetricAndTemplate.parse_obj(raw_metric)
|
||||
if metric.is_template:
|
||||
return get_predefined_metric(key=metric.key, project_id=project_id, data=data.dict())
|
||||
else:
|
||||
return custom_metrics.make_chart(project_id=project_id, user_id=user_id, metric_id=metric_id, data=data,
|
||||
metric=raw_metric)
|
||||
|
||||
|
||||
def make_chart_widget(dashboard_id, project_id, user_id, widget_id, data: schemas.CustomMetricChartPayloadSchema):
|
||||
raw_metric = get_widget(widget_id=widget_id, project_id=project_id, user_id=user_id, dashboard_id=dashboard_id)
|
||||
if raw_metric is None:
|
||||
return None
|
||||
metric = schemas.CustomMetricAndTemplate = schemas.CustomMetricAndTemplate.parse_obj(raw_metric)
|
||||
if metric.is_template:
|
||||
return get_predefined_metric(key=metric.key, project_id=project_id, data=data.dict())
|
||||
else:
|
||||
return custom_metrics.make_chart(project_id=project_id, user_id=user_id, metric_id=raw_metric["metricId"],
|
||||
data=data, metric=raw_metric)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@ def get_dashboards(projectId: int, context: schemas.CurrentContext = Depends(OR_
|
|||
|
||||
@app.get('/{projectId}/dashboards/{dashboardId}', tags=["dashboard"])
|
||||
def get_dashboard(projectId: int, dashboardId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
return {"data": dashboards2.get_dashboard(project_id=projectId, user_id=context.user_id, dashboard_id=dashboardId)}
|
||||
data = dashboards2.get_dashboard(project_id=projectId, user_id=context.user_id, dashboard_id=dashboardId)
|
||||
if data is None:
|
||||
return {"errors": ["dashboard not found"]}
|
||||
return {"data": data}
|
||||
|
||||
|
||||
@app.post('/{projectId}/dashboards/{dashboardId}', tags=["dashboard"])
|
||||
|
|
@ -78,6 +81,17 @@ def remove_widget_from_dashboard(projectId: int, dashboardId: int, widgetId: int
|
|||
widget_id=widgetId)
|
||||
|
||||
|
||||
@app.post('/{projectId}/dashboards/{dashboardId}/widgets/{widgetId}/chart', tags=["dashboard"])
|
||||
def get_widget_chart(projectId: int, dashboardId: int, widgetId: int,
|
||||
data: schemas.CustomMetricChartPayloadSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = dashboards2.make_chart_widget(project_id=projectId, user_id=context.user_id, dashboard_id=dashboardId,
|
||||
widget_id=widgetId, data=data)
|
||||
if data is None:
|
||||
return {"errors": ["widget not found"]}
|
||||
return {"data": data}
|
||||
|
||||
|
||||
@app.get('/{projectId}/metrics/templates', tags=["dashboard"])
|
||||
def get_templates(projectId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
return {"data": dashboards2.get_templates(project_id=projectId, user_id=context.user_id)}
|
||||
|
|
@ -131,8 +145,8 @@ def get_custom_metric_sessions(projectId: int, metric_id: int,
|
|||
@app.post('/{projectId}/custom_metrics/{metric_id}/chart', tags=["customMetrics"])
|
||||
def get_custom_metric_chart(projectId: int, metric_id: int, data: schemas.CustomMetricChartPayloadSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = custom_metrics.make_chart(project_id=projectId, user_id=context.user_id, metric_id=metric_id,
|
||||
data=data)
|
||||
data = dashboards2.make_chart_metrics(project_id=projectId, user_id=context.user_id, metric_id=metric_id,
|
||||
data=data)
|
||||
if data is None:
|
||||
return {"errors": ["custom metric not found"]}
|
||||
return {"data": data}
|
||||
|
|
|
|||
|
|
@ -926,3 +926,13 @@ class TemplateKeys(str, Enum):
|
|||
avg_used_js_heap_size = "avg_used_js_heap_size"
|
||||
avg_cpu = "avg_cpu"
|
||||
avg_fps = "avg_fps"
|
||||
|
||||
|
||||
# class CustomMetricAndTemplate(CreateCustomMetricsSchema):
|
||||
class CustomMetricAndTemplate(BaseModel):
|
||||
is_template: bool = Field(...)
|
||||
project_id: Optional[int] = Field(...)
|
||||
key: Optional[TemplateKeys] = Field(...)
|
||||
|
||||
class Config:
|
||||
alias_generator = attribute_to_camel_case
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue