Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
5e7224c
GMI-353: get widget data from dashboard
yashdattsawant Apr 26, 2024
5e97ebb
GMI-353: black format
yashdattsawant Apr 26, 2024
f1098a4
GMI-353: rename file
yashdattsawant Apr 26, 2024
ba88888
GMI-353: rename fields
yashdattsawant Apr 26, 2024
0a44f64
GMI-353: Add compare by field to create share link
yashdattsawant May 7, 2024
371a3b9
GMI-353: Black format files
yashdattsawant May 7, 2024
028473f
GMI-353: Black format files
yashdattsawant May 7, 2024
5eb6435
GMI-353: Black format files
yashdattsawant May 7, 2024
0ee1247
GMI-353: Add in use flag in share link
yashdattsawant May 7, 2024
2b422a1
GMIM-353: Add dashboard code
yashdattsawant May 15, 2024
5666bea
GMIM-353: Add black code format
yashdattsawant May 15, 2024
54a66ef
GMIM-353: Add dashboard code
yashdattsawant May 15, 2024
75b05cf
GMIM-353: black format
yashdattsawant May 15, 2024
71a5176
GMIM-353: Add support for line model and share link for lines model
yashdattsawant May 24, 2024
d2af978
GMIM-353: Black format code
yashdattsawant May 24, 2024
40b9590
GMIM-353: Add support to analytics SingleValue, Event Timeline analytics
yashdattsawant May 27, 2024
c3eb788
GMIM-353: Black format the code
yashdattsawant May 27, 2024
76c1161
GMIM-353: Add sharelink support to data viz analytics like Single Val…
yashdattsawant Jun 5, 2024
795f995
GMIM-439: add UDF support in smsdk
yashdattsawant Aug 19, 2024
a1d9b5d
GMIM-439: add UDF support in smsdk
yashdattsawant Aug 19, 2024
5dfe926
GMIM-439: Sightmachine SDK add method to call UDF
yashdattsawant Aug 19, 2024
dd42657
GMIM-439: Sightmachine SDK add method to call UDF
yashdattsawant Aug 19, 2024
32da602
GMIM-439: Sightmachine SDK add method to call UDF
yashdattsawant Aug 19, 2024
0345fa1
GMIM-439: Add utility method to list UDFs
yashdattsawant Aug 21, 2024
16d35cc
GMIM-439: Add utility method to list UDFs
yashdattsawant Aug 21, 2024
cd44067
Clean up commits
yashdattsawant Dec 13, 2024
c18e4c9
Merge branch 'master' into GMI-353-async
yashdattsawant Dec 13, 2024
dd2b6a6
Black format files
yashdattsawant Dec 13, 2024
58245f5
MyPy refactor code
yashdattsawant Dec 13, 2024
6d1b31d
MyPy formating
yashdattsawant Dec 13, 2024
bc57208
MyPy formatting
yashdattsawant Dec 13, 2024
cda912c
Test case fixture
yashdattsawant Dec 19, 2024
64c1f96
black format
yashdattsawant Dec 19, 2024
6cb2b77
Mypy formatting
yashdattsawant Dec 19, 2024
696da53
Mypy formatting
yashdattsawant Dec 19, 2024
25d8cdf
Mypy formatting
yashdattsawant Dec 19, 2024
a5d9da6
Mypy formating for dev_udf
yashdattsawant Dec 19, 2024
8011182
Mypy formating for dev_udf
yashdattsawant Dec 19, 2024
f5e949c
Mypy formating for dev_udf
yashdattsawant Dec 19, 2024
15c7f5f
Mypy formating for dev_udf
yashdattsawant Dec 19, 2024
2fe8cea
Mypy workspace.py
yashdattsawant Dec 19, 2024
7b9af38
Mypy workspace.py
yashdattsawant Dec 19, 2024
bc7434e
Code cleanup
yashdattsawant Dec 19, 2024
9615f73
GMIM-353: changes in code per comments
yashdattsawant Mar 7, 2025
dc4950e
GMIM-353: update code as per comments
yashdattsawant Mar 11, 2025
fa7807c
GMIM: resolve time sleep code into loop
yashdattsawant Mar 13, 2025
e819479
GMIM: resolve time sleep code into loop
yashdattsawant Mar 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ mock>=4.0.2
importlib-resources>=3.0.0
pathos>=0.2.7
plotly==5.18.0
beautifulsoup4>=4.12.3
98 changes: 83 additions & 15 deletions smsdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,15 @@ def get_kpi_data_viz(
] = self.get_machine_source_from_clean_name(kwargs)
return kpi_entity(self.session, base_url).get_kpi_data_viz(**kwargs)

def get_widget_data(self, model, url_params):
widget_entity = smsdkentities.get("dataViz")
base_url = get_url(
self.config["protocol"], self.tenant, self.config["site.domain"]
)
return widget_entity(self.session, base_url).get_dashboard_widget_data(
model, **url_params
)

@version_check_decorator
def get_type_from_machine(self, machine_source=None, **kwargs):
machine = smsdkentities.get("machine")
Expand Down Expand Up @@ -698,6 +707,7 @@ def create_share_link(
xAxis=X_AXIS_TIME,
model="cycle",
time_selection=ONE_WEEK_RELATIVE,
are_line_params_available=False,
*args,
**kwargs,
):
Expand Down Expand Up @@ -726,21 +736,31 @@ def create_share_link(

if model == "kpi" and not isinstance(yAxis, list):
yAxis = [yAxis]

if model == "line" and isinstance(yAxis, list):
newYAxis = []
for y in yAxis:
if y.get("machineType"):
newYAxis.append(y)
else:
y["machineType"] = self.get_type_from_machine(y["machineName"])
newYAxis.append(y)
yAxis = newYAxis
elif model == "line":
if not yAxis.get("machineType"):
yAxis["machineType"] = self.get_type_from_machine(yAxis["machineName"])
if not are_line_params_available:
if model == "line" and isinstance(yAxis, list):
newYAxis = []
for y in yAxis:
if y.get("machineType"):
newYAxis.append(y)
else:
y["machineType"] = self.get_type_from_machine(y["machineName"])
newYAxis.append(y)
yAxis = newYAxis
elif model == "line":
if not yAxis.get("machineType"):
yAxis["machineType"] = self.get_type_from_machine(
yAxis["machineName"]
)
return dataViz(self.session, base_url).create_share_link(
*args, assets, chartType, yAxis, xAxis, model, time_selection, **kwargs
asset=assets,
chartType=chartType,
yAxis=yAxis,
xAxis=xAxis,
model=model,
time_selection=time_selection,
are_line_params_available=are_line_params_available,
*args,
**kwargs,
)

@version_check_decorator
Expand Down Expand Up @@ -828,7 +848,6 @@ def get_machine_type_names(self, clean_strings_out=True):
machine_types = self.get_data_v1(
"machine_type_v1", "get_machine_types", True, **query_params
)

if clean_strings_out:
return machine_types["source_type_clean"].unique().tolist()
else:
Expand Down Expand Up @@ -861,3 +880,52 @@ def get_raw_data(
kwargs["offset"] = offset

return self.get_data_v1("raw_data", "get_raw_data", True, *args, **kwargs)

@version_check_decorator
def get_dashboard_data(self, dashboard_id=""):
base_url = get_url(
self.config["protocol"], self.tenant, self.config["site.domain"]
)
# load the entity class and initialize it
cls = smsdkentities.get("dashboard")(self.session, base_url)
panels = getattr(cls, "get_dashboards")(dashboard_id)
return panels

@version_check_decorator
def create_widget_share_link(self, context="/analysis/datavis", **kwargs):
dataViz = smsdkentities.get("dataViz")
base_url = get_url(
self.config["protocol"], self.tenant, self.config["site.domain"]
)
return dataViz(self.session, base_url).create_widget_share_link(
context, **kwargs
)

@version_check_decorator
def fetch_list_of_udf(self):
base_url = get_url(
self.config["protocol"], self.tenant, self.config["site.domain"]
)
# load the entity class and initialize it
cls = smsdkentities.get("dev_udf")(self.session, base_url)
udf_list = getattr(cls, "get_list_of_udf")()
return udf_list

@version_check_decorator
def get_udf_data(self, udf_name, **params):
if udf_name:
existing_udf_list = self.fetch_list_of_udf()
if udf_name in existing_udf_list:
base_url = get_url(
self.config["protocol"], self.tenant, self.config["site.domain"]
)
# load the entity class and initialize it
cls = smsdkentities.get("dev_udf")(self.session, base_url)
udf_data = getattr(cls, "get_udf_data")(udf_name, params)
return udf_data
else:
log.error(
f'UDF named "{udf_name}" does not exist. Please check the name again'
)
else:
log.error("Name of user defined function is required")
8 changes: 7 additions & 1 deletion smsdk/config/api_endpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
"estimate_cycle": "/v1/selector/datavis/estimate/cycle",
"estimate_part": "/v1/selector/datavis/estimate/part",
"task": "/v1/datavis/task/async",
"analytics_task": "/v1/analytics/task/async",
"line_task": "/v1/linevis/task/async",
"share_link": "/v1/obj/ui_share_state"
},
"KPI": {
"availible_kpis_for_asset": "/v1/selector/datavis/kpi/y_axis"
},
"Assets": {
"Assets": {
"url":"/v1/selector/assets"
},
"Cookbook": {
Expand All @@ -52,5 +54,9 @@
},
"RawData": {
"url": "/v1/datatab/raw_data"
},
"UDF_dev": {
"url": "/v1/udf/task/async",
"list_url":"/dev/udf/notebooks"
}
}
21 changes: 18 additions & 3 deletions smsdk/ma_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,11 @@ def _complete_async_task(
db_mode: str = "sql",
**url_params: t_.Any,
) -> t_.Any:
if url_params.get("db_mode") == None:
is_analytics = url_params.get("is_analytics")
if url_params.get("db_mode") == None and not is_analytics:
url_params["db_mode"] = db_mode
try:
url_params.pop("is_analytics", None)
response = getattr(self.session, method.lower())(endpoint, json=url_params)
if response.status_code not in [200, 201]:
raise ValueError("Error - {}".format(response.text))
Expand All @@ -261,15 +263,28 @@ def _complete_async_task(
data = response.json()
state = data["response"]["state"]
if state == "SUCCESS":
return data["response"]["meta"]["results"]

if not is_analytics:
return data["response"]["meta"]["results"]
else:
response = data["response"]["data"]
return response
if state == "FAILURE" or state == "REVOKED":
raise ValueError("Error - {}".format(response.text))
except Exception as e:
raise e
except Exception as e:
raise e

def _get_dashboard_panels(self, endpoint: str, method: str = "get") -> t_.Any:
try:
response = getattr(self.session, method.lower())(endpoint)
if response.status_code not in [200, 201]:
raise ValueError(f"Error - {response.text}")
data = response.json().get("panels", [])
except Exception as e:
raise ValueError("Failed to fetch dashboard panels") from e
return data

def get_json_headers(self) -> CaseInsensitiveDict:
"""
Headers for json requests
Expand Down
Empty file.
41 changes: 41 additions & 0 deletions smsdk/smsdk_entities/dashboard/dashboard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from typing import List, Any, Dict, Tuple
import json

import importlib.resources as pkg_resources
from smsdk.tool_register import SmsdkEntities, smsdkentities
from smsdk.utils import module_utility
from smsdk import config
from smsdk.ma_session import MaSession
import logging

log = logging.getLogger(__name__)

ENDPOINTS = json.loads(pkg_resources.read_text(config, "api_endpoints.json"))


@smsdkentities.register("dashboard")
class DashboardData(SmsdkEntities, MaSession):
# Decorator to register a function as utility
# Only the registered utilites would be accessible
# to outside world via client.get_data()
mod_util = module_utility()
log = log

def __init__(self, session: Any, base_url: str) -> None:
self.session = session
self.base_url = base_url

@mod_util
def get_utilities(
self, *args: Tuple[Any, ...], **kwargs: Dict[str, Any]
) -> List[Any]:
return [*self.mod_util.all]

@mod_util
def get_dashboards(self, dashboard_id: str) -> List[Any]:
"""
Utility function to get the panels data for dashboard
"""
url = "{}{}{}".format(self.base_url, "/v1/obj/dashboard/", dashboard_id)
panels: List[Any] = self._get_dashboard_panels(url, method="get")
return panels
70 changes: 66 additions & 4 deletions smsdk/smsdk_entities/data_viz/data_viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from datetime import datetime, timedelta
from typing import List
import uuid
from smsdk.Auth.auth import X_SM_WORKSPACE_ID

import numpy as np

Expand Down Expand Up @@ -43,7 +44,16 @@ def get_utilities(self, *args, **kwargs) -> List:

@mod_util
def create_share_link(
self, asset, chartType, yAxis, xAxis, model, time_selection, *args, **kwargs
self,
asset,
chartType,
yAxis,
xAxis,
model,
time_selection,
are_line_params_available=False,
*args,
**kwargs
):
"""
Creates a share link
Expand All @@ -52,6 +62,13 @@ def create_share_link(
url_params = {}
url_params["state_hash"] = str(uuid.uuid4())[:8]
url_params["context"] = "/analysis/datavis"
try:
url_params["in_use_workspace"] = self.session.headers[X_SM_WORKSPACE_ID]
except:
print(
"Creating dashboard over prod since we didn't get WORKSPACE_ID from headers"
)
pass
if time_selection["time_type"] == "relative":
dateRange = {
"mode": "relative",
Expand All @@ -67,6 +84,8 @@ def create_share_link(
"endDate": time_selection["end_time"],
"selectedTimeZone": time_selection["time_zone"],
}
else:
dateRange = {}
url_params["state"] = {
"dataModel": model,
"asset": asset,
Expand All @@ -75,7 +94,7 @@ def create_share_link(
"dateRange": dateRange,
}
url_params["state"].update(kwargs)
if model == "line":
if model == "line" and not are_line_params_available:
del url_params["state"]["asset"]
url_params["state"]["lineProcess"] = {}
if not isinstance(asset, List) and asset.get("assetOffsets"):
Expand Down Expand Up @@ -138,6 +157,49 @@ def create_share_link(
else:
url_params["state"]["yAxis"] = yAxis
response = getattr(self.session, "post")(url, json=url_params)
return "{}/#/analysis/datavis/s/{}".format(
self.base_url, response.json()["state_hash"]
return "{}/#{}/s/{}".format(
self.base_url, url_params["context"], response.json()["state_hash"]
)

@mod_util
def get_dashboard_widget_data(self, model, *args, **kwargs):
"""
Takes a query params from the widget in dashboard
Returns Data info for that query
"""
is_analytics = False
if model == "line":
endpoint = ENDPOINTS["DataViz"]["line_task"]
elif model == "cycle":
endpoint = ENDPOINTS["DataViz"]["task"]
kwargs["model"] = model

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is model only set if it's cycle? it's just information and should probably be set to whatever the model arg is

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only Async api for cycle need the "model" as part of payload and not rest. so added it only for cycle model.
Screenshot from 2025-03-11 15-35-51
Screenshot from 2025-03-11 15-35-40

else:
endpoint = ENDPOINTS["DataViz"]["analytics_task"]
is_analytics = True
kwargs["is_analytics"] = is_analytics
url = "{}{}".format(self.base_url, endpoint)
records = self._complete_async_task(url, **kwargs)

if not isinstance(records, List) and not is_analytics:
raise ValueError("Error - {}".format(records))

return records

@mod_util
def create_widget_share_link(self, context, **kwargs):
url = "{}{}".format(self.base_url, ENDPOINTS["DataViz"]["share_link"])
url_params = {}
url_params["state_hash"] = str(uuid.uuid4())[:8]
url_params["context"] = context
try:
url_params["in_use_workspace"] = self.session.headers[X_SM_WORKSPACE_ID]
except:
print(
"Creating dashboard over prod since we didn't get WORKSPACE_ID from headers"
)
pass
url_params["state"] = kwargs
response = getattr(self.session, "post")(url, json=url_params)
return "{}/#{}/s/{}".format(
self.base_url, url_params["context"], response.json()["state_hash"]
)
Empty file.
Loading