Skip to content

Commit

Permalink
fix(chalice): fixed saved card's sessions-drilldown
Browse files Browse the repository at this point in the history
  • Loading branch information
tahayk committed Jun 27, 2024
1 parent ad34258 commit a8433ed
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 82 deletions.
124 changes: 83 additions & 41 deletions api/chalicelib/core/custom_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,59 +190,68 @@ def get_chart(project_id: int, data: schemas.CardSchema, user_id: int):
return supported.get(data.metric_type, not_supported)(project_id=project_id, data=data, user_id=user_id)


def __merge_metric_with_data(metric: schemas.CardSchema,
data: schemas.CardSessionsSchema) -> schemas.CardSchema:
metric.startTimestamp = data.startTimestamp
metric.endTimestamp = data.endTimestamp
metric.page = data.page
metric.limit = data.limit
metric.density = data.density
if data.series is not None and len(data.series) > 0:
metric.series = data.series

# if len(data.filters) > 0:
# for s in metric.series:
# s.filter.filters += data.filters
# metric = schemas.CardSchema(**metric.model_dump(by_alias=True))
return metric
# def __merge_metric_with_data(metric: schemas.CardSchema,
# data: schemas.CardSessionsSchema) -> schemas.CardSchema:
# metric.startTimestamp = data.startTimestamp
# metric.endTimestamp = data.endTimestamp
# metric.page = data.page
# metric.limit = data.limit
# metric.density = data.density
# if data.series is not None and len(data.series) > 0:
# metric.series = data.series
#
# # if len(data.filters) > 0:
# # for s in metric.series:
# # s.filter.filters += data.filters
# # metric = schemas.CardSchema(**metric.model_dump(by_alias=True))
# return metric


def get_sessions_by_card_id(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
card: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
if card is None:
# No need for this because UI is sending the full payload
# card: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
# if card is None:
# return None
# metric: schemas.CardSchema = schemas.CardSchema(**card)
# metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
return None
metric: schemas.CardSchema = schemas.CardSchema(**card)
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
results = []
for s in metric.series:
for s in data.series:
results.append({"seriesId": s.series_id, "seriesName": s.name,
**sessions.search_sessions(data=s.filter, project_id=project_id, user_id=user_id)})

return results


def get_funnel_issues(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
raw_metric: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
if raw_metric is None:
return None
metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
if metric is None:
# No need for this because UI is sending the full payload
# raw_metric: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
# if raw_metric is None:
# return None
# metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
# metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
# if metric is None:
# return None
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
return None
for s in metric.series:
for s in data.series:
return {"seriesId": s.series_id, "seriesName": s.name,
**funnels.get_issues_on_the_fly_widget(project_id=project_id, data=s.filter)}


def get_errors_list(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
raw_metric: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
if raw_metric is None:
# No need for this because UI is sending the full payload
# raw_metric: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
# if raw_metric is None:
# return None
# metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
# metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
# if metric is None:
# return None
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
return None
metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
if metric is None:
return None
for s in metric.series:
for s in data.series:
return {"seriesId": s.series_id, "seriesName": s.name,
**errors.search(data=s.filter, project_id=project_id, user_id=user_id)}

Expand Down Expand Up @@ -626,14 +635,17 @@ def get_funnel_sessions_by_issue(user_id, project_id, metric_id, issue_id,
data: schemas.CardSessionsSchema
# , range_value=None, start_date=None, end_date=None
):
card: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
if card is None:
# No need for this because UI is sending the full payload
# card: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
# if card is None:
# return None
# metric: schemas.CardSchema = schemas.CardSchema(**card)
# metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
# if metric is None:
# return None
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
return None
metric: schemas.CardSchema = schemas.CardSchema(**card)
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
if metric is None:
return None
for s in metric.series:
for s in data.series:
s.filter.startTimestamp = data.startTimestamp
s.filter.endTimestamp = data.endTimestamp
s.filter.limit = data.limit
Expand Down Expand Up @@ -693,3 +705,33 @@ def make_chart_from_card(project_id, user_id, metric_id, data: schemas.CardSessi
return raw_metric["data"]

return get_chart(project_id=project_id, data=metric, user_id=user_id)


def card_exists(metric_id, project_id, user_id) -> bool:
with pg_client.PostgresClient() as cur:
query = cur.mogrify(
f"""SELECT 1
FROM metrics
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 INNER JOIN dashboard_widgets USING (dashboard_id)
WHERE deleted_at ISNULL
AND project_id = %(project_id)s
AND ((dashboards.user_id = %(user_id)s OR is_public))
AND metric_id = %(metric_id)s) AS connected_dashboards
) AS connected_dashboards ON (TRUE)
LEFT JOIN LATERAL (SELECT email AS owner_email
FROM users
WHERE deleted_at ISNULL
AND users.user_id = metrics.user_id
) AS owner ON (TRUE)
WHERE metrics.project_id = %(project_id)s
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}
)
cur.execute(query)
row = cur.fetchone()
return row is not None
30 changes: 30 additions & 0 deletions api/schemas/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,36 @@ def __enforce_default_after(cls, values):

return values

@model_validator(mode="after")
def __merge_out_filters_with_series(cls, values):
if len(values.filters) > 0:
for f in values.filters:
for s in values.series:
found = False

if f.is_event:
sub = s.filter.events
else:
sub = s.filter.filters

for e in sub:
if f.type == e.type and f.operator == e.operator:
found = True
if f.is_event:
# If extra event: append value
for v in f.value:
if v not in e.value:
e.value.append(v)
else:
# If extra filter: override value
e.value = f.value
if not found:
sub.append(f)

values.filters = []

return values


class CardConfigSchema(BaseModel):
col: Optional[int] = Field(default=None)
Expand Down
125 changes: 84 additions & 41 deletions ee/api/chalicelib/core/custom_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def __get_funnel_chart(project_id: int, data: schemas.CardFunnel, user_id: int =
"stages": [],
"totalDropDueToIssues": 0
}

return funnels.get_top_insights_on_the_fly_widget(project_id=project_id,
data=data.series[0].filter,
metric_of=data.metric_of)
Expand Down Expand Up @@ -209,59 +210,68 @@ def get_chart(project_id: int, data: schemas.CardSchema, user_id: int):
return supported.get(data.metric_type, not_supported)(project_id=project_id, data=data, user_id=user_id)


def __merge_metric_with_data(metric: schemas.CardSchema,
data: schemas.CardSessionsSchema) -> schemas.CardSchema:
metric.startTimestamp = data.startTimestamp
metric.endTimestamp = data.endTimestamp
metric.page = data.page
metric.limit = data.limit
metric.density = data.density
if data.series is not None and len(data.series) > 0:
metric.series = data.series

# if len(data.filters) > 0:
# for s in metric.series:
# s.filter.filters += data.filters
# metric = schemas.CardSchema(**metric.model_dump(by_alias=True))
return metric
# def __merge_metric_with_data(metric: schemas.CardSchema,
# data: schemas.CardSessionsSchema) -> schemas.CardSchema:
# metric.startTimestamp = data.startTimestamp
# metric.endTimestamp = data.endTimestamp
# metric.page = data.page
# metric.limit = data.limit
# metric.density = data.density
# if data.series is not None and len(data.series) > 0:
# metric.series = data.series
#
# # if len(data.filters) > 0:
# # for s in metric.series:
# # s.filter.filters += data.filters
# # metric = schemas.CardSchema(**metric.model_dump(by_alias=True))
# return metric


def get_sessions_by_card_id(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
card: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
if card is None:
# No need for this because UI is sending the full payload
# card: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
# if card is None:
# return None
# metric: schemas.CardSchema = schemas.CardSchema(**card)
# metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
return None
metric: schemas.CardSchema = schemas.CardSchema(**card)
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
results = []
for s in metric.series:
for s in data.series:
results.append({"seriesId": s.series_id, "seriesName": s.name,
**sessions.search_sessions(data=s.filter, project_id=project_id, user_id=user_id)})

return results


def get_funnel_issues(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
raw_metric: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
if raw_metric is None:
# No need for this because UI is sending the full payload
# raw_metric: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
# if raw_metric is None:
# return None
# metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
# metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
# if metric is None:
# return None
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
return None
metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
if metric is None:
return None
for s in metric.series:
for s in data.series:
return {"seriesId": s.series_id, "seriesName": s.name,
**funnels.get_issues_on_the_fly_widget(project_id=project_id, data=s.filter)}


def get_errors_list(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
raw_metric: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
if raw_metric is None:
return None
metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
if metric is None:
# No need for this because UI is sending the full payload
# raw_metric: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
# if raw_metric is None:
# return None
# metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
# metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
# if metric is None:
# return None
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
return None
for s in metric.series:
for s in data.series:
return {"seriesId": s.series_id, "seriesName": s.name,
**errors.search(data=s.filter, project_id=project_id, user_id=user_id)}

Expand Down Expand Up @@ -672,14 +682,17 @@ def get_funnel_sessions_by_issue(user_id, project_id, metric_id, issue_id,
data: schemas.CardSessionsSchema
# , range_value=None, start_date=None, end_date=None
):
card: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
if card is None:
return None
metric: schemas.CardSchema = schemas.CardSchema(**card)
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
if metric is None:
# No need for this because UI is sending the full payload
# card: dict = get_card(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False)
# if card is None:
# return None
# metric: schemas.CardSchema = schemas.CardSchema(**card)
# metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
# if metric is None:
# return None
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
return None
for s in metric.series:
for s in data.series:
s.filter.startTimestamp = data.startTimestamp
s.filter.endTimestamp = data.endTimestamp
s.filter.limit = data.limit
Expand Down Expand Up @@ -739,3 +752,33 @@ def make_chart_from_card(project_id, user_id, metric_id, data: schemas.CardSessi
return raw_metric["data"]

return get_chart(project_id=project_id, data=metric, user_id=user_id)


def card_exists(metric_id, project_id, user_id) -> bool:
with pg_client.PostgresClient() as cur:
query = cur.mogrify(
f"""SELECT 1
FROM metrics
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 INNER JOIN dashboard_widgets USING (dashboard_id)
WHERE deleted_at ISNULL
AND project_id = %(project_id)s
AND ((dashboards.user_id = %(user_id)s OR is_public))
AND metric_id = %(metric_id)s) AS connected_dashboards
) AS connected_dashboards ON (TRUE)
LEFT JOIN LATERAL (SELECT email AS owner_email
FROM users
WHERE deleted_at ISNULL
AND users.user_id = metrics.user_id
) AS owner ON (TRUE)
WHERE metrics.project_id = %(project_id)s
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}
)
cur.execute(query)
row = cur.fetchone()
return row is not None

0 comments on commit a8433ed

Please sign in to comment.