codeant-ai-for-open-source[bot] commented on code in PR #40450:
URL: https://github.com/apache/superset/pull/40450#discussion_r3306191416
##########
superset-frontend/src/extensions/ExtensionsList.tsx:
##########
@@ -50,6 +67,100 @@ const ExtensionsList:
FunctionComponent<ExtensionsListProps> = ({
addDangerToast,
);
+ // Load current active chatbot from settings on mount
+ useEffect(() => {
+ SupersetClient.get({ endpoint: '/api/v1/extensions/settings' })
+ .then(({ json }) => {
+ setActiveChatbotId(json?.result?.active_chatbot_id ?? null);
+ })
+ .catch(() => {
+ // non-fatal: leave activeChatbotId as null
+ });
+ }, []);
+
+ const handleUploadClick = () => {
+ fileInputRef.current?.click();
+ };
+
+ const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ const file = e.target.files?.[0];
+ if (!file) return;
+
+ if (!file.name.endsWith('.supx')) {
+ addDangerToast(t('File must have a .supx extension.'));
+ e.target.value = '';
+ return;
+ }
+
+ const formData = new FormData();
+ formData.append('bundle', file);
+
+ setUploading(true);
+ SupersetClient.post({
+ endpoint: '/api/v1/extensions/',
+ body: formData,
+ headers: { Accept: 'application/json' },
+ })
+ .then(() => {
+ addSuccessToast(t('Extension installed successfully.'));
+ refreshData();
+ })
+ .catch(
+ createErrorHandler(errMsg =>
+ addDangerToast(
+ t('There was an issue installing the extension: %s', errMsg),
+ ),
+ ),
+ )
+ .finally(() => {
+ setUploading(false);
+ e.target.value = '';
+ });
+ };
+
+ const handleDelete = (extension: Extension) => {
+ const { publisher, name } = extension;
+ SupersetClient.delete({
+ endpoint: `/api/v1/extensions/${publisher}/${name}`,
+ }).then(
Review Comment:
**Suggestion:** The delete URL is built from `extension.publisher`, but the
backend list payload is produced by `build_extension_data` and does not include
a `publisher` field, so this resolves to `/api/v1/extensions/undefined/<name>`
and deletion fails. Include `publisher` in the API response (or derive it from
`id` before calling delete). [api mismatch]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ Delete action on Extensions page always hits wrong URL.
- ❌ Uploaded .supx extensions cannot be removed via UI.
- ⚠️ Publisher column renders empty despite manifest having publisher.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Start the backend with the extensions API enabled so
`/api/v1/extensions/` is exposed
by `ExtensionsRestApi.get_list` in `superset/extensions/api.py:92-138`,
which builds each
extension object using `build_extension_data` in
`superset/extensions/utils.py:233-254`.
2. Observe that `build_extension_data` at
`superset/extensions/utils.py:233-241` only
populates fields `id`, `name`, `version`, `description`, `dependencies`, and
optionally
`remoteEntry` / `moduleFederationName`; it does not include a `publisher`
field, even
though `Manifest` defines `publisher` and `name` separately in
`superset-core/src/superset_core/extensions/types.py:38-75,133-144`.
3. On the frontend, the extensions list page uses
`useListViewResource<Extension>('extensions', ...)` in
`superset-frontend/src/extensions/ExtensionsList.tsx:60-68`, which relies on
`useListViewResource` at
`superset-frontend/src/views/CRUD/hooks.ts:11-24,46-56,149-56` to
fetch `/api/v1/extensions/?q=...` and assign `json.result` directly to
`resourceCollection` without adding or deriving a `publisher` field.
4. When a user clicks the delete icon in the Actions column rendered in
`superset-frontend/src/extensions/ExtensionsList.tsx:187-245`,
`ConfirmStatusChange` calls
`handleDelete(original)` at
`superset-frontend/src/extensions/ExtensionsList.tsx:121-136`;
inside `handleDelete`, the destructuring `const { publisher, name } =
extension;` at line
122 receives an `extension` object that has no `publisher` property, so
`publisher` is
`undefined`, and the DELETE request is sent to
`/api/v1/extensions/undefined/<name>` (line
124), which does not match any real extension and results in
`ExtensionsRestApi.delete` at
`superset/extensions/api.py:275-340` returning 404, causing the UI to show a
failure toast
instead of deleting the extension.
```
</details>
[Fix in
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=458f469b0c9e48cf8550f1a9cb880e21&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
| [Fix in VSCode
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=458f469b0c9e48cf8550f1a9cb880e21&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(Use Cmd/Ctrl + Click for best experience)*
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/extensions/ExtensionsList.tsx
**Line:** 122:125
**Comment:**
*Api Mismatch: The delete URL is built from `extension.publisher`, but
the backend list payload is produced by `build_extension_data` and does not
include a `publisher` field, so this resolves to
`/api/v1/extensions/undefined/<name>` and deletion fails. Include `publisher`
in the API response (or derive it from `id` before calling delete).
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.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40450&comment_hash=550ffee53b5ff4187a5d221bd62a6c0960ba4882ee7de28f5cefc283e3d47611&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40450&comment_hash=550ffee53b5ff4187a5d221bd62a6c0960ba4882ee7de28f5cefc283e3d47611&reaction=dislike'>👎</a>
##########
superset/extensions/api.py:
##########
@@ -16,21 +16,43 @@
# under the License.
import mimetypes
from io import BytesIO
+from pathlib import Path
from typing import Any
+from zipfile import is_zipfile, ZipFile
-from flask import send_file
+from flask import current_app, request, send_file
from flask.wrappers import Response
from flask_appbuilder.api import BaseApi, expose, protect, safe
+from superset.extensions import security_manager
+from superset.extensions.settings import (
+ get_extension_settings,
+ update_extension_settings,
+)
Review Comment:
**Suggestion:** This import references a module that does not exist in the
current codebase (`superset/extensions/settings.py`), so importing
`superset.extensions.api` will fail at runtime with `ModuleNotFoundError` and
break the extensions API endpoints. Add the missing module in this PR or change
the import to the correct existing path. [import error]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ Enabling extensions feature crashes during app initialization.
- ❌ /api/v1/extensions endpoints unavailable when feature flag enabled.
- ⚠️ Frontend ExtensionsList cannot load or update extension settings.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Enable the `ENABLE_EXTENSIONS` feature flag so that the initialization
routine in
`superset/initialization/__init__.py:16-24` executes the block that imports
and registers
the extensions API: `from superset.extensions.api import ExtensionsRestApi`
followed by
`appbuilder.add_api(ExtensionsRestApi)`.
2. When Python imports `superset.extensions.api`, it executes the top-level
imports shown
in `superset/extensions/api.py:17-37`, including `from
superset.extensions.settings import
(get_extension_settings, update_extension_settings)`.
3. The `superset.extensions` package directory at `superset/extensions`
(listed via `ls`
output in `superset/extensions`) only contains `__init__.py`, `api.py`,
`cache_middleware.py`, `context.py`, `contributions.py`, `discovery.py`,
`exceptions.py`,
`local_extensions_watcher.py`, `metadb.py`, `metastore_cache.py`,
`pylint.py`, `ssh.py`,
`stats_logger.py`, `types.py`, and `utils.py`; there is no `settings.py`
file in this
package, and an attempt to read
`/workspace/superset/superset/extensions/settings.py`
fails, confirming the module does not exist.
4. Because `superset.extensions.settings` cannot be found, the import at
`superset/extensions/api.py:28-31` raises `ModuleNotFoundError: No module
named
'superset.extensions.settings'`, which prevents `ExtensionsRestApi` from
being imported
and causes the initialization block in
`superset/initialization/__init__.py:16-24` to
fail, so the `/api/v1/extensions` endpoints (including list, post, delete,
and settings)
are never registered and any code depending on them (such as the
ExtensionsList frontend
using `/api/v1/extensions/settings` and `/api/v1/extensions/`) cannot
function when the
feature flag is enabled.
```
</details>
[Fix in
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=e0447a741b35419f924c43ed1fa01968&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
| [Fix in VSCode
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=e0447a741b35419f924c43ed1fa01968&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(Use Cmd/Ctrl + Click for best experience)*
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/extensions/api.py
**Line:** 28:31
**Comment:**
*Import Error: This import references a module that does not exist in
the current codebase (`superset/extensions/settings.py`), so importing
`superset.extensions.api` will fail at runtime with `ModuleNotFoundError` and
break the extensions API endpoints. Add the missing module in this PR or change
the import to the correct existing path.
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.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40450&comment_hash=f3e9a4d1cfa7f96f027e2fbd73a066d88fa13c62024eb9baa6fd228213a01cc3&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40450&comment_hash=f3e9a4d1cfa7f96f027e2fbd73a066d88fa13c62024eb9baa6fd228213a01cc3&reaction=dislike'>👎</a>
--
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]