Skip to content

Commit 2db22a4

Browse files
Merge branch 'master' of https://github.com/apache/superset into alexandrusoare/fix/world-map
2 parents 2f74e7b + 2b6c745 commit 2db22a4

File tree

143 files changed

+10886
-2167
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+10886
-2167
lines changed

.github/dependabot.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ updates:
1616
update-types: ["version-update:semver-major", "version-update:semver-minor"]
1717
- dependency-name: "eslint-plugin-storybook"
1818
- dependency-name: "react-error-boundary"
19+
- dependency-name: "@rjsf/*"
1920
# remark-gfm v4+ requires react-markdown v9+, which needs React 18
2021
- dependency-name: "remark-gfm"
2122
- dependency-name: "react-markdown"

.github/workflows/superset-docs-verify.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
- uses: actions/checkout@v6
2828
# Do not bump this linkinator-action version without opening
2929
# an ASF Infra ticket to allow the new version first!
30-
- uses: JustinBeckwith/linkinator-action@f62ba0c110a76effb2ee6022cc6ce4ab161085e3 # v2.4
30+
- uses: JustinBeckwith/linkinator-action@af984b9f30f63e796ae2ea5be5e07cb587f1bbd9 # v2.3
3131
continue-on-error: true # This will make the job advisory (non-blocking, no red X)
3232
with:
3333
paths: "**/*.md, **/*.mdx"

.github/workflows/superset-frontend.yml

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ jobs:
8787
-v ${{ github.workspace }}/superset-frontend/coverage:/app/superset-frontend/coverage \
8888
--rm $TAG \
8989
bash -c \
90-
"npm run test -- --coverage --shard=${{ matrix.shard }}/8 --coverageReporters=json-summary"
90+
"npm run test -- --coverage --shard=${{ matrix.shard }}/8 --coverageReporters=json"
9191
9292
- name: Upload Coverage Artifact
9393
uses: actions/upload-artifact@v6
@@ -99,15 +99,29 @@ jobs:
9999
needs: [sharded-jest-tests]
100100
if: needs.frontend-build.outputs.should-run == 'true'
101101
runs-on: ubuntu-24.04
102+
permissions:
103+
id-token: write
102104
steps:
105+
- name: Checkout Code
106+
uses: actions/checkout@v6
107+
with:
108+
persist-credentials: false
109+
fetch-depth: 0
110+
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
111+
103112
- name: Download Coverage Artifacts
104113
uses: actions/download-artifact@v7
105114
with:
106115
pattern: coverage-artifacts-*
107116
path: coverage/
108117

109-
- name: Show Files
110-
run: find coverage/
118+
- name: Reorganize test result reports
119+
run: |
120+
find coverage/
121+
for i in {1..8}; do
122+
mv coverage/coverage-artifacts-${i}/coverage-final.json coverage/coverage-shard-${i}.json
123+
done
124+
shell: bash
111125

112126
- name: Merge Code Coverage
113127
run: npx nyc merge coverage/ merged-output/coverage-summary.json
@@ -116,8 +130,9 @@ jobs:
116130
uses: codecov/codecov-action@v5
117131
with:
118132
flags: javascript
119-
token: ${{ secrets.CODECOV_TOKEN }}
133+
use_oidc: true
120134
verbose: true
135+
disable_search: true
121136
files: merged-output/coverage-summary.json
122137
slug: apache/superset
123138

docs/developer_portal/extensions/quick-start.md

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -51,36 +51,39 @@ Use the CLI to scaffold a new extension project. Extensions can include frontend
5151
superset-extensions init
5252
```
5353

54-
The CLI will prompt you for information:
54+
The CLI will prompt you for information using a three-step publisher workflow:
5555

5656
```
57-
Extension name (e.g. Hello World): Hello World
58-
Extension ID [hello-world]: hello-world
57+
Extension display name: Hello World
58+
Extension name (hello-world): hello-world
59+
Publisher (e.g., my-org): my-org
5960
Initial version [0.1.0]: 0.1.0
6061
License [Apache-2.0]: Apache-2.0
6162
Include frontend? [Y/n]: Y
6263
Include backend? [Y/n]: Y
6364
```
6465

65-
**Important**: The extension ID must be **globally unique** across all Superset extensions and serves as the basis for all technical identifiers:
66-
- **Frontend package name**: `hello-world` (same as ID, used in package.json)
67-
- **Webpack Module Federation name**: `helloWorld` (camelCase from ID)
68-
- **Backend package name**: `hello_world` (snake_case from ID, used in project.toml)
69-
- **Python namespace**: `superset_extensions.hello_world`
66+
**Publisher Namespaces**: Extensions use organizational namespaces similar to VS Code extensions, providing collision-safe naming across organizations:
67+
- **NPM package**: `@my-org/hello-world` (scoped package for frontend distribution)
68+
- **Module Federation name**: `myOrg_helloWorld` (collision-safe JavaScript identifier)
69+
- **Backend package**: `my_org-hello_world` (collision-safe Python distribution name)
70+
- **Python namespace**: `superset_extensions.my_org.hello_world`
7071

71-
This ensures consistent naming across all technical components, even when the display name differs significantly from the ID. Since all technical names derive from the extension ID, choosing a unique ID automatically ensures all generated names are also unique, preventing conflicts between extensions.
72+
This approach ensures that extensions from different organizations cannot conflict, even if they use the same technical name (e.g., both `acme.dashboard-widgets` and `corp.dashboard-widgets` can coexist).
7273

7374
This creates a complete project structure:
7475

7576
```
76-
hello-world/
77+
my-org.hello-world/
7778
├── extension.json # Extension metadata and configuration
7879
├── backend/ # Backend Python code
7980
│ ├── src/
8081
│ │ └── superset_extensions/
81-
│ │ └── hello_world/
82+
│ │ └── my_org/
8283
│ │ ├── __init__.py
83-
│ │ └── entrypoint.py # Backend registration
84+
│ │ └── hello_world/
85+
│ │ ├── __init__.py
86+
│ │ └── entrypoint.py # Backend registration
8487
│ └── pyproject.toml
8588
└── frontend/ # Frontend TypeScript/React code
8689
├── src/
@@ -96,8 +99,9 @@ The generated `extension.json` contains basic metadata. Update it to register yo
9699

97100
```json
98101
{
99-
"id": "hello-world",
100-
"name": "Hello World",
102+
"publisher": "my-org",
103+
"name": "hello-world",
104+
"displayName": "Hello World",
101105
"version": "0.1.0",
102106
"license": "Apache-2.0",
103107
"frontend": {
@@ -106,7 +110,7 @@ The generated `extension.json` contains basic metadata. Update it to register yo
106110
"sqllab": {
107111
"panels": [
108112
{
109-
"id": "hello-world.main",
113+
"id": "my-org.hello-world.main",
110114
"name": "Hello World"
111115
}
112116
]
@@ -115,29 +119,32 @@ The generated `extension.json` contains basic metadata. Update it to register yo
115119
},
116120
"moduleFederation": {
117121
"exposes": ["./index"],
118-
"name": "helloWorld"
122+
"name": "myOrg_helloWorld"
119123
}
120124
},
121125
"backend": {
122-
"entryPoints": ["superset_extensions.hello_world.entrypoint"],
123-
"files": ["backend/src/superset_extensions/hello_world/**/*.py"]
126+
"entryPoints": ["superset_extensions.my_org.hello_world.entrypoint"],
127+
"files": ["backend/src/superset_extensions/my_org/hello_world/**/*.py"]
124128
},
125129
"permissions": ["can_read"]
126130
}
127131
```
128132

129-
**Note**: The `moduleFederation.name` is automatically derived from the extension ID (`hello-world``helloWorld`), and backend entry points use the full Python namespace (`superset_extensions.hello_world`).
133+
**Note**: The `moduleFederation.name` uses collision-safe naming (`myOrg_helloWorld`), and backend entry points use the full nested Python namespace (`superset_extensions.my_org.hello_world`).
130134

131135
**Key fields:**
132136

137+
- `publisher`: Organizational namespace for the extension
138+
- `name`: Technical identifier (kebab-case)
139+
- `displayName`: Human-readable name shown to users
133140
- `frontend.contributions.views.sqllab.panels`: Registers your panel in SQL Lab
134141
- `backend.entryPoints`: Python modules to load eagerly when extension starts
135142

136143
## Step 4: Create Backend API
137144

138-
The CLI generated a basic `backend/src/superset_extensions/hello_world/entrypoint.py`. We'll create an API endpoint.
145+
The CLI generated a basic `backend/src/superset_extensions/my_org/hello_world/entrypoint.py`. We'll create an API endpoint.
139146

140-
**Create `backend/src/superset_extensions/hello_world/api.py`**
147+
**Create `backend/src/superset_extensions/my_org/hello_world/api.py`**
141148

142149
```python
143150
from flask import Response
@@ -186,10 +193,10 @@ class HelloWorldAPI(RestApi):
186193
- Extends `RestApi` from `superset_core.api.types.rest_api`
187194
- Uses Flask-AppBuilder decorators (`@expose`, `@protect`, `@safe`)
188195
- Returns responses using `self.response(status_code, result=data)`
189-
- The endpoint will be accessible at `/extensions/hello-world/message`
196+
- The endpoint will be accessible at `/extensions/my-org/hello-world/message`
190197
- OpenAPI docstrings are crucial - Flask-AppBuilder uses them to automatically generate interactive API documentation at `/swagger/v1`, allowing developers to explore endpoints, understand schemas, and test the API directly from the browser
191198

192-
**Update `backend/src/superset_extensions/hello_world/entrypoint.py`**
199+
**Update `backend/src/superset_extensions/my_org/hello_world/entrypoint.py`**
193200

194201
Replace the generated print statement with API registration:
195202

@@ -213,7 +220,7 @@ The `@apache-superset/core` package must be listed in both `peerDependencies` (t
213220

214221
```json
215222
{
216-
"name": "hello-world",
223+
"name": "@my-org/hello-world",
217224
"version": "0.1.0",
218225
"private": true,
219226
"license": "Apache-2.0",
@@ -264,7 +271,7 @@ module.exports = (env, argv) => {
264271
chunkFilename: "[name].[contenthash].js",
265272
clean: true,
266273
path: path.resolve(__dirname, "dist"),
267-
publicPath: `/api/v1/extensions/${packageConfig.name}/`,
274+
publicPath: `/api/v1/extensions/my-org/hello-world/`,
268275
},
269276
resolve: {
270277
extensions: [".ts", ".tsx", ".js", ".jsx"],
@@ -285,7 +292,7 @@ module.exports = (env, argv) => {
285292
},
286293
plugins: [
287294
new ModuleFederationPlugin({
288-
name: packageConfig.name,
295+
name: "myOrg_helloWorld",
289296
filename: "remoteEntry.[contenthash].js",
290297
exposes: {
291298
"./index": "./src/index.tsx",
@@ -342,7 +349,7 @@ const HelloWorldPanel: React.FC = () => {
342349
const fetchMessage = async () => {
343350
try {
344351
const csrfToken = await authentication.getCSRFToken();
345-
const response = await fetch('/extensions/hello-world/message', {
352+
const response = await fetch('/extensions/my-org/hello-world/message', {
346353
method: 'GET',
347354
headers: {
348355
'Content-Type': 'application/json',
@@ -415,7 +422,7 @@ import HelloWorldPanel from './HelloWorldPanel';
415422

416423
export const activate = (context: core.ExtensionContext) => {
417424
context.disposables.push(
418-
core.registerViewProvider('hello-world.main', () => <HelloWorldPanel />),
425+
core.registerViewProvider('my-org.hello-world.main', () => <HelloWorldPanel />),
419426
);
420427
};
421428

@@ -425,9 +432,9 @@ export const deactivate = () => {};
425432
**Key patterns:**
426433

427434
- `activate` function is called when the extension loads
428-
- `core.registerViewProvider` registers the component with ID `hello-world.main` (matching `extension.json`)
435+
- `core.registerViewProvider` registers the component with ID `my-org.hello-world.main` (matching `extension.json`)
429436
- `authentication.getCSRFToken()` retrieves the CSRF token for API calls
430-
- Fetch calls to `/extensions/{extension_id}/{endpoint}` reach your backend API
437+
- Fetch calls to `/extensions/{publisher}/{name}/{endpoint}` reach your backend API
431438
- `context.disposables.push()` ensures proper cleanup
432439

433440
## Step 6: Install Dependencies
@@ -456,7 +463,7 @@ This command automatically:
456463
- `manifest.json` - Build metadata and asset references
457464
- `frontend/dist/` - Built frontend assets (remoteEntry.js, chunks)
458465
- `backend/` - Python source files
459-
- Packages everything into `hello-world-0.1.0.supx` - a zip archive with the specific structure required by Superset
466+
- Packages everything into `my-org.hello-world-0.1.0.supx` - a zip archive with the specific structure required by Superset
460467

461468
## Step 8: Deploy to Superset
462469

@@ -481,7 +488,7 @@ EXTENSIONS_PATH = "/path/to/extensions/folder"
481488
Copy your `.supx` file to the configured extensions path:
482489

483490
```bash
484-
cp hello-world-0.1.0.supx /path/to/extensions/folder/
491+
cp my-org.hello-world-0.1.0.supx /path/to/extensions/folder/
485492
```
486493

487494
**Restart Superset**
@@ -512,7 +519,7 @@ Here's what happens when your extension loads:
512519
4. **Module Federation**: Webpack loads your extension code and resolves `@apache-superset/core` to `window.superset`
513520
5. **Activation**: `activate()` is called, registering your view provider
514521
6. **Rendering**: When the user opens your panel, React renders `<HelloWorldPanel />`
515-
7. **API call**: Component fetches data from `/extensions/hello-world/message`
522+
7. **API call**: Component fetches data from `/extensions/my-org/hello-world/message`
516523
8. **Backend response**: Your Flask API returns the hello world message
517524
9. **Display**: Component shows the message to the user
518525

docs/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@
6464
"@storybook/preview-api": "^8.6.17",
6565
"@storybook/theming": "^8.6.15",
6666
"@superset-ui/core": "^0.20.4",
67-
"@swc/core": "^1.15.11",
68-
"antd": "^6.3.0",
67+
"@swc/core": "^1.15.13",
68+
"antd": "^6.3.1",
6969
"baseline-browser-mapping": "^2.10.0",
7070
"caniuse-lite": "^1.0.30001770",
7171
"docusaurus-plugin-openapi-docs": "^4.6.0",
@@ -95,15 +95,15 @@
9595
"@types/js-yaml": "^4.0.9",
9696
"@types/react": "^19.1.8",
9797
"@typescript-eslint/eslint-plugin": "^8.52.0",
98-
"@typescript-eslint/parser": "^8.55.0",
98+
"@typescript-eslint/parser": "^8.56.1",
9999
"eslint": "^9.39.2",
100100
"eslint-config-prettier": "^10.1.8",
101101
"eslint-plugin-prettier": "^5.5.5",
102102
"eslint-plugin-react": "^7.37.5",
103103
"globals": "^17.3.0",
104104
"prettier": "^3.8.1",
105105
"typescript": "~5.9.3",
106-
"typescript-eslint": "^8.56.0",
106+
"typescript-eslint": "^8.56.1",
107107
"webpack": "^5.105.2"
108108
},
109109
"browserslist": {

0 commit comments

Comments
 (0)