codeant-ai-for-open-source[bot] commented on code in PR #36740:
URL: https://github.com/apache/superset/pull/36740#discussion_r2631635722
##########
superset-frontend/src/dashboard/types.ts:
##########
@@ -130,6 +130,21 @@ export type DashboardState = {
};
chartStates?: Record<string, any>;
};
+/**
+ * Template metadata fields that can be stored either:
+ * 1. Nested under "template_info" key (new format after import)
+ * 2. At the top level of metadata (legacy format)
+ */
+export interface TemplateInfo {
+ is_template?: boolean;
+ is_featured_template?: boolean;
+ template_category?: string;
+ template_thumbnail_url?: string;
Review Comment:
**Suggestion:** The `TemplateInfo` interface types `template_category` and
`template_thumbnail_url` as `string`, but backend responses and related
frontend types (e.g. `DashboardTemplate`) allow these fields to be `null`, so
this mismatch can lead to unsafe assumptions and runtime errors when code uses
these fields as always-strings while receiving `null` from the API. [type error]
**Severity Level:** Minor ⚠️
```suggestion
template_category?: string | null;
template_thumbnail_url?: string | null;
```
<details>
<summary><b>Why it matters? ⭐ </b></summary>
The PR added TemplateInfo with optional string fields for template_category
and template_thumbnail_url.
If the backend can return null for these keys (common for optional
metadata), typing them as only 'string' is inaccurate and can lead to unsafe
assumptions or the need for non-null assertions elsewhere.
Widening the types to 'string | null' aligns the TypeScript model with
nullable API responses and forces callers to handle the null case explicitly,
preventing runtime surprises.
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/dashboard/types.ts
**Line:** 141:142
**Comment:**
*Type Error: The `TemplateInfo` interface types `template_category` and
`template_thumbnail_url` as `string`, but backend responses and related
frontend types (e.g. `DashboardTemplate`) allow these fields to be `null`, so
this mismatch can lead to unsafe assumptions and runtime errors when code uses
these fields as always-strings while receiving `null` from the API.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
##########
superset-frontend/src/dashboard/selectors.ts:
##########
@@ -21,6 +21,9 @@ import { RootState } from 'src/dashboard/types';
/**
* Selector to check if the current dashboard is a template.
* Template dashboards are read-only and cannot be edited.
+ *
+ * Template metadata is stored in the nested "template_info" structure
+ * within the dashboard's metadata.
*/
export const selectIsTemplateDashboard = (state: RootState): boolean =>
- !!state.dashboardInfo?.metadata?.is_template;
+ !!state.dashboardInfo?.metadata?.template_info?.is_template;
Review Comment:
**Suggestion:** The selector only checks the nested
`template_info.is_template` flag and ignores the documented legacy case where
template metadata may still be stored at the top level as
`metadata.is_template`, leading to inconsistent behavior (some parts of the UI
will treat a dashboard as a template while this selector returns false), so the
selector should fall back to the top-level flag when `template_info` is not
present. [logic error]
**Severity Level:** Minor ⚠️
```suggestion
!!(
state.dashboardInfo?.metadata?.template_info?.is_template ??
(state.dashboardInfo?.metadata as any)?.is_template
);
```
<details>
<summary><b>Why it matters? ⭐ </b></summary>
The current selector only inspects metadata.template_info.is_template and
will miss dashboards that still set metadata.is_template (legacy format). That
can produce real inconsistent UI behavior (some code paths might treat the
dashboard as a template while this selector does not). The proposed fallback is
a small, targeted compatibility fix that resolves a real logic gap rather than
a cosmetic change.
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/dashboard/selectors.ts
**Line:** 29:29
**Comment:**
*Logic Error: The selector only checks the nested
`template_info.is_template` flag and ignores the documented legacy case where
template metadata may still be stored at the top level as
`metadata.is_template`, leading to inconsistent behavior (some parts of the UI
will treat a dashboard as a template while this selector returns false), so the
selector should fall back to the top-level flag when `template_info` is not
present.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
##########
superset/daos/dashboard.py:
##########
@@ -145,9 +145,11 @@ def get_templates() -> list[Dashboard]:
templates = []
for dashboard in dashboards:
metadata = json.loads(dashboard.json_metadata or "{}")
- if metadata.get("is_template", False):
+ # Template metadata is stored in the nested template_info structure
+ template_info = metadata.get("template_info", {})
+ if template_info.get("is_template", False):
Review Comment:
**Suggestion:** The new template metadata handling assumes `template_info`
is always a dict, but `DashboardJSONMetadataSchema` explicitly allows
`template_info` to be `null`; if any dashboard has `"template_info": null` in
its `json_metadata`, `template_info.get(...)` will raise an AttributeError at
runtime when iterating templates. Guarding for non-dict values prevents this
crash while keeping the intended behavior. [type error]
**Severity Level:** Minor ⚠️
```suggestion
template_info = metadata.get("template_info") or {}
if isinstance(template_info, dict) and
template_info.get("is_template", False):
```
<details>
<summary><b>Why it matters? ⭐ </b></summary>
The current code uses metadata.get("template_info", {}) which only provides
the {} default when the key is missing.
If the key exists but is explicitly null (template_info: null),
metadata.get(...) returns None and template_info.get(...) will raise
AttributeError.
The suggested change (use metadata.get("template_info") or {} and guard with
isinstance(..., dict)) prevents that runtime crash while preserving intended
behavior.
This fixes a real runtime bug and is minimal and safe.
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/daos/dashboard.py
**Line:** 149:150
**Comment:**
*Type Error: The new template metadata handling assumes `template_info`
is always a dict, but `DashboardJSONMetadataSchema` explicitly allows
`template_info` to be `null`; if any dashboard has `"template_info": null` in
its `json_metadata`, `template_info.get(...)` will raise an AttributeError at
runtime when iterating templates. Guarding for non-dict values prevents this
crash while keeping the intended behavior.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
##########
superset/commands/dashboard_generator/template_analyzer.py:
##########
@@ -133,6 +134,12 @@ def analyze(self, dashboard: Dashboard) ->
TemplateRequirements:
self._extract_dataset_info(dashboard)
)
+ # Extract template context if present
+ metadata = json.loads(dashboard.json_metadata or "{}")
+ template_info = metadata.get("template_info", {}) if
isinstance(metadata, dict) else {}
+ if isinstance(template_info, dict) and "template_context" in
template_info:
+ requirements.template_context =
template_info.get("template_context")
Review Comment:
**Suggestion:** The value stored in `requirements.template_context` is taken
directly from `template_info["template_context"]`, which elsewhere in the
codebase is treated as a JSON string, while
`TemplateRequirements.template_context` and downstream consumers (like the LLM
prompt builder) expect a structured dict; this causes the context to be
double-encoded with `json.dumps` and breaks the intended contract of providing
a structured context object to the reasoning loop. [logic error]
**Severity Level:** Minor ⚠️
```suggestion
template_info = (
metadata.get("template_info", {}) if isinstance(metadata, dict)
else {}
)
if isinstance(template_info, dict) and "template_context" in
template_info:
raw_context = template_info.get("template_context")
# Normalize to a dict so downstream consumers see structured
context
if isinstance(raw_context, str):
try:
requirements.template_context = json.loads(raw_context)
except Exception:
logger.warning(
"Failed to parse template_context JSON for dashboard
%s",
dashboard.id,
)
requirements.template_context = None
elif isinstance(raw_context, dict):
requirements.template_context = raw_context
```
<details>
<summary><b>Why it matters? ⭐ </b></summary>
The LLM prompt builders and other consumers in this PR expect
template_context to be a structured dict (see
llm_service._build_dataset_generation_prompt which json.dumps(template_context)
and LLM function signatures typed as dict[str, Any]). However the dashboard
API/schema/store often keeps template_context as a JSON string (frontend and
marshmallow schemas show template_context as String). Leaving the raw string
through leads to double-encoding when later json.dumps is applied and can break
prompt formatting or downstream logic. The suggested normalization (attempt to
json.loads if the stored value is a str) fixes a real logic mismatch between
storage (string) and runtime expectation (dict) and is therefore a valid,
non-cosmetic bug fix.
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/commands/dashboard_generator/template_analyzer.py
**Line:** 139:141
**Comment:**
*Logic Error: The value stored in `requirements.template_context` is
taken directly from `template_info["template_context"]`, which elsewhere in the
codebase is treated as a JSON string, while
`TemplateRequirements.template_context` and downstream consumers (like the LLM
prompt builder) expect a structured dict; this causes the context to be
double-encoded with `json.dumps` and breaks the intended contract of providing
a structured context object to the reasoning loop.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
##########
superset/security/manager.py:
##########
@@ -2926,7 +2926,8 @@ def _is_template_dashboard(dashboard: "Dashboard") ->
bool:
return False
try:
metadata = json.loads(dashboard.json_metadata)
- return metadata.get("is_template", False)
+ template_info = metadata.get("template_info", {})
+ return template_info.get("is_template", False)
Review Comment:
**Suggestion:** The updated template detection assumes that
`json.loads(dashboard.json_metadata)` always returns a dict, but if the stored
JSON is valid yet non-dict (for example `"null"`, a list, or a string), then
`metadata.get(...)` and `template_info.get(...)` will raise AttributeError,
causing `_is_template_dashboard` to crash instead of safely treating the
dashboard as non-template. Adding type checks around `metadata` and
`template_info` (and defaulting to `{}` when appropriate) prevents these
runtime errors and keeps access checks robust against unexpected JSON shapes.
[type error]
**Severity Level:** Minor ⚠️
```suggestion
metadata = json.loads(dashboard.json_metadata or "{}")
if not isinstance(metadata, dict):
return False
template_info = metadata.get("template_info", {})
if not isinstance(template_info, dict):
return False
return bool(template_info.get("is_template", False))
```
<details>
<summary><b>Why it matters? ⭐ </b></summary>
The current code calls .get() on metadata and template_info without
verifying their types. json.loads(...) can legally return non-dict values
(None, list, string, etc.), which would make metadata.get raise AttributeError
and crash the access check. The proposed change defensively handles non-dict
JSON shapes and returns False for unexpected metadata, preserving behavior and
avoiding runtime errors. This fixes a real robustness bug introduced by the PR
change.
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/security/manager.py
**Line:** 2928:2930
**Comment:**
*Type Error: The updated template detection assumes that
`json.loads(dashboard.json_metadata)` always returns a dict, but if the stored
JSON is valid yet non-dict (for example `"null"`, a list, or a string), then
`metadata.get(...)` and `template_info.get(...)` will raise AttributeError,
causing `_is_template_dashboard` to crash instead of safely treating the
dashboard as non-template. Adding type checks around `metadata` and
`template_info` (and defaulting to `{}` when appropriate) prevents these
runtime errors and keeps access checks robust against unexpected JSON shapes.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
##########
superset/dashboards/api.py:
##########
@@ -702,20 +702,26 @@ def templates(self) -> Response:
return self.response_500(message=str(ex))
def _enrich_template_with_metadata(self, dashboard: Dashboard) ->
dict[str, Any]:
- """Extract template metadata from json_metadata into top-level
fields."""
+ """Extract template metadata from json_metadata into top-level fields.
+
+ Template metadata is stored in the nested "template_info" structure
+ within the dashboard's json_metadata.
+ """
metadata = json.loads(dashboard.json_metadata or "{}")
+ template_info = metadata.get("template_info", {})
Review Comment:
**Suggestion:** The new code assumes that `dashboard.json_metadata` always
deserializes into a dictionary; if it is valid JSON but not an object (for
example a list or string), `template_info = metadata.get("template_info", {})`
will raise an `AttributeError` and cause the `/templates` endpoint to fail for
that dashboard instead of gracefully treating it as having no template
metadata. [logic error]
**Severity Level:** Minor ⚠️
```suggestion
template_info = metadata.get("template_info", {}) if
isinstance(metadata, dict) else {}
```
<details>
<summary><b>Why it matters? ⭐ </b></summary>
The code calls json.loads on dashboard.json_metadata and immediately uses
.get on the result.
If the stored JSON is valid but not an object (e.g. "[]" or "\"string\""),
metadata will be a list or str
and metadata.get(...) raises AttributeError at runtime. That would make the
/templates endpoint fail
for dashboards with non-object json_metadata. The proposed guard (use {}
when metadata is not a dict)
fixes a real runtime bug and is a minimal, safe change localized to this
function.
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/dashboards/api.py
**Line:** 711:711
**Comment:**
*Logic Error: The new code assumes that `dashboard.json_metadata`
always deserializes into a dictionary; if it is valid JSON but not an object
(for example a list or string), `template_info = metadata.get("template_info",
{})` will raise an `AttributeError` and cause the `/templates` endpoint to fail
for that dashboard instead of gracefully treating it as having no template
metadata.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]