feat(dashboards): show owners and improve grid actions UI
This commit is contained in:
@@ -61,6 +61,7 @@ class LastTask(BaseModel):
|
||||
None,
|
||||
pattern="^PENDING|RUNNING|SUCCESS|FAILED|ERROR|AWAITING_INPUT|WAITING_INPUT|AWAITING_MAPPING$",
|
||||
)
|
||||
validation_status: Optional[str] = Field(None, pattern="^PASS|FAIL|WARN|UNKNOWN$")
|
||||
# [/DEF:LastTask:DataClass]
|
||||
|
||||
# [DEF:DashboardItem:DataClass]
|
||||
@@ -70,6 +71,9 @@ class DashboardItem(BaseModel):
|
||||
slug: Optional[str] = None
|
||||
url: Optional[str] = None
|
||||
last_modified: Optional[str] = None
|
||||
created_by: Optional[str] = None
|
||||
modified_by: Optional[str] = None
|
||||
owners: Optional[List[str]] = None
|
||||
git_status: Optional[GitStatus] = None
|
||||
last_task: Optional[LastTask] = None
|
||||
# [/DEF:DashboardItem:DataClass]
|
||||
|
||||
@@ -106,7 +106,17 @@ class SupersetClient:
|
||||
def get_dashboards_summary(self) -> List[Dict]:
|
||||
with belief_scope("SupersetClient.get_dashboards_summary"):
|
||||
query = {
|
||||
"columns": ["id", "dashboard_title", "changed_on_utc", "published"]
|
||||
"columns": [
|
||||
"id",
|
||||
"dashboard_title",
|
||||
"changed_on_utc",
|
||||
"published",
|
||||
"created_by",
|
||||
"created_by_name",
|
||||
"changed_by",
|
||||
"changed_by_name",
|
||||
"owners",
|
||||
]
|
||||
}
|
||||
_, dashboards = self.get_dashboards(query=query)
|
||||
|
||||
@@ -117,11 +127,83 @@ class SupersetClient:
|
||||
"id": dash.get("id"),
|
||||
"title": dash.get("dashboard_title"),
|
||||
"last_modified": dash.get("changed_on_utc"),
|
||||
"status": "published" if dash.get("published") else "draft"
|
||||
"status": "published" if dash.get("published") else "draft",
|
||||
"created_by": self._extract_user_display(
|
||||
dash.get("created_by_name"),
|
||||
dash.get("created_by"),
|
||||
),
|
||||
"modified_by": self._extract_user_display(
|
||||
dash.get("changed_by_name"),
|
||||
dash.get("changed_by"),
|
||||
),
|
||||
"owners": self._extract_owner_labels(dash.get("owners")),
|
||||
})
|
||||
return result
|
||||
# [/DEF:get_dashboards_summary:Function]
|
||||
|
||||
# [DEF:_extract_owner_labels:Function]
|
||||
# @PURPOSE: Normalize dashboard owners payload to stable display labels.
|
||||
# @PRE: owners payload can be None, list of dicts or list of strings.
|
||||
# @POST: Returns deduplicated non-empty owner labels preserving order.
|
||||
# @RETURN: List[str]
|
||||
def _extract_owner_labels(self, owners_payload: Optional[List[Union[Dict, str]]]) -> List[str]:
|
||||
if not isinstance(owners_payload, list):
|
||||
return []
|
||||
|
||||
normalized: List[str] = []
|
||||
for owner in owners_payload:
|
||||
label: Optional[str] = None
|
||||
if isinstance(owner, dict):
|
||||
label = self._extract_user_display(None, owner)
|
||||
else:
|
||||
label = self._sanitize_user_text(owner)
|
||||
if label and label not in normalized:
|
||||
normalized.append(label)
|
||||
return normalized
|
||||
# [/DEF:_extract_owner_labels:Function]
|
||||
|
||||
# [DEF:_extract_user_display:Function]
|
||||
# @PURPOSE: Normalize user payload to a stable display name.
|
||||
# @PRE: user payload can be string, dict or None.
|
||||
# @POST: Returns compact non-empty display value or None.
|
||||
# @RETURN: Optional[str]
|
||||
def _extract_user_display(self, preferred_value: Optional[str], user_payload: Optional[Dict]) -> Optional[str]:
|
||||
preferred = self._sanitize_user_text(preferred_value)
|
||||
if preferred:
|
||||
return preferred
|
||||
|
||||
if isinstance(user_payload, dict):
|
||||
full_name = self._sanitize_user_text(user_payload.get("full_name"))
|
||||
if full_name:
|
||||
return full_name
|
||||
first_name = self._sanitize_user_text(user_payload.get("first_name")) or ""
|
||||
last_name = self._sanitize_user_text(user_payload.get("last_name")) or ""
|
||||
combined = " ".join(part for part in [first_name, last_name] if part).strip()
|
||||
if combined:
|
||||
return combined
|
||||
username = self._sanitize_user_text(user_payload.get("username"))
|
||||
if username:
|
||||
return username
|
||||
email = self._sanitize_user_text(user_payload.get("email"))
|
||||
if email:
|
||||
return email
|
||||
return None
|
||||
# [/DEF:_extract_user_display:Function]
|
||||
|
||||
# [DEF:_sanitize_user_text:Function]
|
||||
# @PURPOSE: Convert scalar value to non-empty user-facing text.
|
||||
# @PRE: value can be any scalar type.
|
||||
# @POST: Returns trimmed string or None.
|
||||
# @RETURN: Optional[str]
|
||||
def _sanitize_user_text(self, value: Optional[Union[str, int]]) -> Optional[str]:
|
||||
if value is None:
|
||||
return None
|
||||
normalized = str(value).strip()
|
||||
if not normalized:
|
||||
return None
|
||||
return normalized
|
||||
# [/DEF:_sanitize_user_text:Function]
|
||||
|
||||
# [DEF:get_dashboard:Function]
|
||||
# @PURPOSE: Fetches a single dashboard by ID.
|
||||
# @PRE: Client is authenticated and dashboard_id exists.
|
||||
|
||||
Reference in New Issue
Block a user