Dev (#2316)
* refactor(chalice): upgraded dependencies * refactor(chalice): upgraded dependencies feat(chalice): support heatmaps * feat(chalice): support table-of-browsers showing user-count * feat(chalice): support table-of-devices showing user-count * feat(chalice): support table-of-URLs showing user-count * fix(chalice): fixed saved card's sessions-drilldown
This commit is contained in:
parent
2b9d38f858
commit
5fc087abd9
5 changed files with 206 additions and 91 deletions
|
|
@ -6,18 +6,18 @@ name = "pypi"
|
||||||
[packages]
|
[packages]
|
||||||
urllib3 = "==1.26.16"
|
urllib3 = "==1.26.16"
|
||||||
requests = "==2.32.3"
|
requests = "==2.32.3"
|
||||||
boto3 = "==1.34.134"
|
boto3 = "==1.34.125"
|
||||||
pyjwt = "==2.8.0"
|
pyjwt = "==2.8.0"
|
||||||
psycopg2-binary = "==2.9.9"
|
psycopg2-binary = "==2.9.9"
|
||||||
|
psycopg = {extras = ["binary", "pool"], version = "==3.1.19"}
|
||||||
elasticsearch = "==8.14.0"
|
elasticsearch = "==8.14.0"
|
||||||
jira = "==3.8.0"
|
jira = "==3.8.0"
|
||||||
fastapi = "==0.111.0"
|
fastapi = "==0.111.0"
|
||||||
|
uvicorn = {extras = ["standard"], version = "==0.30.1"}
|
||||||
python-decouple = "==3.8"
|
python-decouple = "==3.8"
|
||||||
|
pydantic = {extras = ["email"], version = "==2.3.0"}
|
||||||
apscheduler = "==3.10.4"
|
apscheduler = "==3.10.4"
|
||||||
redis = "==5.1.0b6"
|
redis = "==5.1.0b6"
|
||||||
psycopg = {extras = ["binary", "pool"], version = "==3.1.19"}
|
|
||||||
uvicorn = {extras = ["standard"], version = "==0.30.1"}
|
|
||||||
pydantic = {extras = ["email"], version = "==2.3.0"}
|
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -190,31 +190,34 @@ 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)
|
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,
|
# def __merge_metric_with_data(metric: schemas.CardSchema,
|
||||||
data: schemas.CardSessionsSchema) -> schemas.CardSchema:
|
# data: schemas.CardSessionsSchema) -> schemas.CardSchema:
|
||||||
metric.startTimestamp = data.startTimestamp
|
# metric.startTimestamp = data.startTimestamp
|
||||||
metric.endTimestamp = data.endTimestamp
|
# metric.endTimestamp = data.endTimestamp
|
||||||
metric.page = data.page
|
# metric.page = data.page
|
||||||
metric.limit = data.limit
|
# metric.limit = data.limit
|
||||||
metric.density = data.density
|
# metric.density = data.density
|
||||||
if data.series is not None and len(data.series) > 0:
|
# if data.series is not None and len(data.series) > 0:
|
||||||
metric.series = data.series
|
# metric.series = data.series
|
||||||
|
#
|
||||||
# if len(data.filters) > 0:
|
# # if len(data.filters) > 0:
|
||||||
# for s in metric.series:
|
# # for s in metric.series:
|
||||||
# s.filter.filters += data.filters
|
# # s.filter.filters += data.filters
|
||||||
# metric = schemas.CardSchema(**metric.model_dump(by_alias=True))
|
# # metric = schemas.CardSchema(**metric.model_dump(by_alias=True))
|
||||||
return metric
|
# return metric
|
||||||
|
|
||||||
|
|
||||||
def get_sessions_by_card_id(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
|
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)
|
# No need for this because UI is sending the full payload
|
||||||
if card is 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 not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
|
||||||
return None
|
return None
|
||||||
metric: schemas.CardSchema = schemas.CardSchema(**card)
|
|
||||||
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
|
|
||||||
results = []
|
results = []
|
||||||
for s in metric.series:
|
for s in data.series:
|
||||||
results.append({"seriesId": s.series_id, "seriesName": s.name,
|
results.append({"seriesId": s.series_id, "seriesName": s.name,
|
||||||
**sessions.search_sessions(data=s.filter, project_id=project_id, user_id=user_id)})
|
**sessions.search_sessions(data=s.filter, project_id=project_id, user_id=user_id)})
|
||||||
|
|
||||||
|
|
@ -222,27 +225,33 @@ def get_sessions_by_card_id(project_id, user_id, metric_id, data: schemas.CardSe
|
||||||
|
|
||||||
|
|
||||||
def get_funnel_issues(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
|
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)
|
# No need for this because UI is sending the full payload
|
||||||
if raw_metric is None:
|
# 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
|
return None
|
||||||
metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
|
for s in data.series:
|
||||||
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
|
|
||||||
if metric is None:
|
|
||||||
return None
|
|
||||||
for s in metric.series:
|
|
||||||
return {"seriesId": s.series_id, "seriesName": s.name,
|
return {"seriesId": s.series_id, "seriesName": s.name,
|
||||||
**funnels.get_issues_on_the_fly_widget(project_id=project_id, data=s.filter)}
|
**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):
|
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)
|
# No need for this because UI is sending the full payload
|
||||||
if raw_metric is None:
|
# 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
|
return None
|
||||||
metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
|
for s in data.series:
|
||||||
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
|
|
||||||
if metric is None:
|
|
||||||
return None
|
|
||||||
for s in metric.series:
|
|
||||||
return {"seriesId": s.series_id, "seriesName": s.name,
|
return {"seriesId": s.series_id, "seriesName": s.name,
|
||||||
**errors.search(data=s.filter, project_id=project_id, user_id=user_id)}
|
**errors.search(data=s.filter, project_id=project_id, user_id=user_id)}
|
||||||
|
|
||||||
|
|
@ -626,14 +635,17 @@ def get_funnel_sessions_by_issue(user_id, project_id, metric_id, issue_id,
|
||||||
data: schemas.CardSessionsSchema
|
data: schemas.CardSessionsSchema
|
||||||
# , range_value=None, start_date=None, end_date=None
|
# , 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)
|
# No need for this because UI is sending the full payload
|
||||||
if card is 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:
|
||||||
|
# return None
|
||||||
|
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
|
||||||
return None
|
return None
|
||||||
metric: schemas.CardSchema = schemas.CardSchema(**card)
|
for s in data.series:
|
||||||
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
|
|
||||||
if metric is None:
|
|
||||||
return None
|
|
||||||
for s in metric.series:
|
|
||||||
s.filter.startTimestamp = data.startTimestamp
|
s.filter.startTimestamp = data.startTimestamp
|
||||||
s.filter.endTimestamp = data.endTimestamp
|
s.filter.endTimestamp = data.endTimestamp
|
||||||
s.filter.limit = data.limit
|
s.filter.limit = data.limit
|
||||||
|
|
@ -693,3 +705,33 @@ def make_chart_from_card(project_id, user_id, metric_id, data: schemas.CardSessi
|
||||||
return raw_metric["data"]
|
return raw_metric["data"]
|
||||||
|
|
||||||
return get_chart(project_id=project_id, data=metric, user_id=user_id)
|
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
|
||||||
|
|
|
||||||
|
|
@ -1081,6 +1081,36 @@ class CardSessionsSchema(_TimedSchema, _PaginatedSchema):
|
||||||
|
|
||||||
return 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):
|
class CardConfigSchema(BaseModel):
|
||||||
col: Optional[int] = Field(default=None)
|
col: Optional[int] = Field(default=None)
|
||||||
|
|
|
||||||
|
|
@ -6,22 +6,22 @@ name = "pypi"
|
||||||
[packages]
|
[packages]
|
||||||
urllib3 = "==1.26.16"
|
urllib3 = "==1.26.16"
|
||||||
requests = "==2.32.3"
|
requests = "==2.32.3"
|
||||||
boto3 = "==1.34.134"
|
boto3 = "==1.34.125"
|
||||||
pyjwt = "==2.8.0"
|
pyjwt = "==2.8.0"
|
||||||
psycopg2-binary = "==2.9.9"
|
psycopg2-binary = "==2.9.9"
|
||||||
|
psycopg = {extras = ["binary", "pool"], version = "==3.1.19"}
|
||||||
elasticsearch = "==8.14.0"
|
elasticsearch = "==8.14.0"
|
||||||
jira = "==3.8.0"
|
jira = "==3.8.0"
|
||||||
fastapi = "==0.111.0"
|
fastapi = "==0.111.0"
|
||||||
|
uvicorn = {extras = ["standard"], version = "==0.30.1"}
|
||||||
gunicorn = "==22.0.0"
|
gunicorn = "==22.0.0"
|
||||||
python-decouple = "==3.8"
|
python-decouple = "==3.8"
|
||||||
|
pydantic = {extras = ["email"], version = "==2.3.0"}
|
||||||
apscheduler = "==3.10.4"
|
apscheduler = "==3.10.4"
|
||||||
|
clickhouse-driver = {extras = ["lz4"], version = "==0.2.8"}
|
||||||
python3-saml = "==1.16.0"
|
python3-saml = "==1.16.0"
|
||||||
redis = "==5.1.0b6"
|
redis = "==5.1.0b6"
|
||||||
azure-storage-blob = "==12.21.0b1"
|
azure-storage-blob = "==12.21.0b1"
|
||||||
psycopg = {extras = ["pool", "binary"], version = "==3.1.19"}
|
|
||||||
uvicorn = {extras = ["standard"], version = "==0.30.1"}
|
|
||||||
pydantic = {extras = ["email"], version = "==2.3.0"}
|
|
||||||
clickhouse-driver = {extras = ["lz4"], version = "==0.2.8"}
|
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ def __get_funnel_chart(project_id: int, data: schemas.CardFunnel, user_id: int =
|
||||||
"stages": [],
|
"stages": [],
|
||||||
"totalDropDueToIssues": 0
|
"totalDropDueToIssues": 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return funnels.get_top_insights_on_the_fly_widget(project_id=project_id,
|
return funnels.get_top_insights_on_the_fly_widget(project_id=project_id,
|
||||||
data=data.series[0].filter,
|
data=data.series[0].filter,
|
||||||
metric_of=data.metric_of)
|
metric_of=data.metric_of)
|
||||||
|
|
@ -209,31 +210,34 @@ 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)
|
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,
|
# def __merge_metric_with_data(metric: schemas.CardSchema,
|
||||||
data: schemas.CardSessionsSchema) -> schemas.CardSchema:
|
# data: schemas.CardSessionsSchema) -> schemas.CardSchema:
|
||||||
metric.startTimestamp = data.startTimestamp
|
# metric.startTimestamp = data.startTimestamp
|
||||||
metric.endTimestamp = data.endTimestamp
|
# metric.endTimestamp = data.endTimestamp
|
||||||
metric.page = data.page
|
# metric.page = data.page
|
||||||
metric.limit = data.limit
|
# metric.limit = data.limit
|
||||||
metric.density = data.density
|
# metric.density = data.density
|
||||||
if data.series is not None and len(data.series) > 0:
|
# if data.series is not None and len(data.series) > 0:
|
||||||
metric.series = data.series
|
# metric.series = data.series
|
||||||
|
#
|
||||||
# if len(data.filters) > 0:
|
# # if len(data.filters) > 0:
|
||||||
# for s in metric.series:
|
# # for s in metric.series:
|
||||||
# s.filter.filters += data.filters
|
# # s.filter.filters += data.filters
|
||||||
# metric = schemas.CardSchema(**metric.model_dump(by_alias=True))
|
# # metric = schemas.CardSchema(**metric.model_dump(by_alias=True))
|
||||||
return metric
|
# return metric
|
||||||
|
|
||||||
|
|
||||||
def get_sessions_by_card_id(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
|
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)
|
# No need for this because UI is sending the full payload
|
||||||
if card is 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 not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
|
||||||
return None
|
return None
|
||||||
metric: schemas.CardSchema = schemas.CardSchema(**card)
|
|
||||||
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
|
|
||||||
results = []
|
results = []
|
||||||
for s in metric.series:
|
for s in data.series:
|
||||||
results.append({"seriesId": s.series_id, "seriesName": s.name,
|
results.append({"seriesId": s.series_id, "seriesName": s.name,
|
||||||
**sessions.search_sessions(data=s.filter, project_id=project_id, user_id=user_id)})
|
**sessions.search_sessions(data=s.filter, project_id=project_id, user_id=user_id)})
|
||||||
|
|
||||||
|
|
@ -241,27 +245,33 @@ def get_sessions_by_card_id(project_id, user_id, metric_id, data: schemas.CardSe
|
||||||
|
|
||||||
|
|
||||||
def get_funnel_issues(project_id, user_id, metric_id, data: schemas.CardSessionsSchema):
|
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)
|
# No need for this because UI is sending the full payload
|
||||||
if raw_metric is None:
|
# 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
|
return None
|
||||||
metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
|
for s in data.series:
|
||||||
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
|
|
||||||
if metric is None:
|
|
||||||
return None
|
|
||||||
for s in metric.series:
|
|
||||||
return {"seriesId": s.series_id, "seriesName": s.name,
|
return {"seriesId": s.series_id, "seriesName": s.name,
|
||||||
**funnels.get_issues_on_the_fly_widget(project_id=project_id, data=s.filter)}
|
**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):
|
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)
|
# No need for this because UI is sending the full payload
|
||||||
if raw_metric is None:
|
# 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
|
return None
|
||||||
metric: schemas.CardSchema = schemas.CardSchema(**raw_metric)
|
for s in data.series:
|
||||||
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
|
|
||||||
if metric is None:
|
|
||||||
return None
|
|
||||||
for s in metric.series:
|
|
||||||
return {"seriesId": s.series_id, "seriesName": s.name,
|
return {"seriesId": s.series_id, "seriesName": s.name,
|
||||||
**errors.search(data=s.filter, project_id=project_id, user_id=user_id)}
|
**errors.search(data=s.filter, project_id=project_id, user_id=user_id)}
|
||||||
|
|
||||||
|
|
@ -672,14 +682,17 @@ def get_funnel_sessions_by_issue(user_id, project_id, metric_id, issue_id,
|
||||||
data: schemas.CardSessionsSchema
|
data: schemas.CardSessionsSchema
|
||||||
# , range_value=None, start_date=None, end_date=None
|
# , 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)
|
# No need for this because UI is sending the full payload
|
||||||
if card is 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:
|
||||||
|
# return None
|
||||||
|
if not card_exists(metric_id=metric_id, project_id=project_id, user_id=user_id):
|
||||||
return None
|
return None
|
||||||
metric: schemas.CardSchema = schemas.CardSchema(**card)
|
for s in data.series:
|
||||||
metric: schemas.CardSchema = __merge_metric_with_data(metric=metric, data=data)
|
|
||||||
if metric is None:
|
|
||||||
return None
|
|
||||||
for s in metric.series:
|
|
||||||
s.filter.startTimestamp = data.startTimestamp
|
s.filter.startTimestamp = data.startTimestamp
|
||||||
s.filter.endTimestamp = data.endTimestamp
|
s.filter.endTimestamp = data.endTimestamp
|
||||||
s.filter.limit = data.limit
|
s.filter.limit = data.limit
|
||||||
|
|
@ -739,3 +752,33 @@ def make_chart_from_card(project_id, user_id, metric_id, data: schemas.CardSessi
|
||||||
return raw_metric["data"]
|
return raw_metric["data"]
|
||||||
|
|
||||||
return get_chart(project_id=project_id, data=metric, user_id=user_id)
|
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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue