aminghadersohi commented on code in PR #44126:
URL: https://github.com/apache/superset/pull/44126#discussion_r4270433227
##########
docs/admin_docs/configuration/configuring-superset.mdx:
##########
@@ -606,6 +606,52 @@ def FLASK_APP_MUTATOR(app: Flask) -> None:
app.before_request_funcs.setdefault(None,
[]).append(make_session_permanent)
```
+## Reacting to chart and dashboard creation
+
+`AFTER_ASSET_CREATE` is an optional hook that runs after a chart or dashboard
+is created, letting deployments react to new assets without forking the
+creation commands or views — for example to auto-categorize the asset, write
+an audit log entry, or fire a notification.
+
+The hook receives the model instance and the asset type string (`"chart"` or
+`"dashboard"`):
+
+```python
+# superset_config.py
+from superset import db
+
+
+def _after_asset_create(model, asset_type):
+ # The model is pending in the session but may not be flushed yet, so
+ # flush first if you need database-assigned fields like ``id``.
+ db.session.flush()
+ audit_log.write(f"{asset_type} {model.id} created by {model.created_by}")
+
+
+AFTER_ASSET_CREATE = _after_asset_create
+```
+
+It defaults to `None`, which is a no-op: with nothing configured, chart and
+dashboard creation behaves exactly as it did before this hook existed.
+
+The hook runs before the surrounding database transaction commits, so an
+exception raised inside it aborts the chart or dashboard creation. Keep it
+fast and side-effect-light, and avoid raising unless you intend to cancel
+the creation. On the REST API path the model has been added to the session
+but not flushed when the hook is called, so `id`, `created_by`, and other
+database-assigned fields are still `None` unless the hook flushes the
+session itself, as in the example above.
Review Comment:
On master `CreateDashboardCommand.run` flushes before the hook
(`commands/dashboard/create.py:58`), so "not flushed" is wrong for dashboards
once this merges; only the chart path is unflushed. Writes outside the session
also survive a later rollback, which this never says.
```suggestion
The hook runs before the surrounding database transaction commits, so an
exception raised inside it aborts the chart or dashboard creation, while work
it does outside the session (an external audit write, a notification) is not
undone if the transaction later rolls back. Keep it fast and
side-effect-light, and avoid raising unless you intend to cancel the
creation. The model may not be flushed when the hook is called (the chart
create command never flushes first), so `id`, `created_by`, and other
database-assigned fields can still be `None` unless the hook flushes the
session itself, as in the example above.
```
##########
docs/admin_docs/configuration/configuring-superset.mdx:
##########
@@ -606,6 +606,52 @@ def FLASK_APP_MUTATOR(app: Flask) -> None:
app.before_request_funcs.setdefault(None,
[]).append(make_session_permanent)
```
+## Reacting to chart and dashboard creation
+
+`AFTER_ASSET_CREATE` is an optional hook that runs after a chart or dashboard
+is created, letting deployments react to new assets without forking the
+creation commands or views — for example to auto-categorize the asset, write
+an audit log entry, or fire a notification.
+
+The hook receives the model instance and the asset type string (`"chart"` or
+`"dashboard"`):
+
+```python
+# superset_config.py
+from superset import db
+
+
+def _after_asset_create(model, asset_type):
+ # The model is pending in the session but may not be flushed yet, so
+ # flush first if you need database-assigned fields like ``id``.
+ db.session.flush()
+ audit_log.write(f"{asset_type} {model.id} created by {model.created_by}")
+
+
+AFTER_ASSET_CREATE = _after_asset_create
+```
+
+It defaults to `None`, which is a no-op: with nothing configured, chart and
+dashboard creation behaves exactly as it did before this hook existed.
+
+The hook runs before the surrounding database transaction commits, so an
+exception raised inside it aborts the chart or dashboard creation. Keep it
+fast and side-effect-light, and avoid raising unless you intend to cancel
+the creation. On the REST API path the model has been added to the session
+but not flushed when the hook is called, so `id`, `created_by`, and other
+database-assigned fields are still `None` unless the hook flushes the
+session itself, as in the example above.
+
+The hook fires for any chart or dashboard created through the REST API
+(including Explore's Save As) and for blank dashboards created from the UI's
+"+ New dashboard" button. MCP-generated charts go through the same path, but
+MCP-generated dashboards currently build the dashboard directly and skip the
+hook. The dashboard copy endpoint (`POST /api/v1/dashboard/<id>/copy/`) also
+bypasses it, since it clones the dashboard directly rather than going through
+the create command. The chart and dashboard import endpoints
+(`POST /api/v1/chart/import/` and `POST /api/v1/dashboard/import/`) create
+assets via `import_from_dict` and skip the hook as well.
Review Comment:
`POST /api/v1/assets/import/` (`importexport/api.py:92`) also creates charts
and dashboards via `import_charts`/`import_dashboard` and `import_from_dict`
with no hook call, so line 645's "any ... through the REST API" is still too
broad.
```suggestion
the create command. The chart, dashboard, and bulk asset import endpoints
(`POST /api/v1/chart/import/`, `POST /api/v1/dashboard/import/`, and
`POST /api/v1/assets/import/`) create assets via `import_from_dict` and skip
the hook as well.
```
--
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]