mirror of
https://github.com/apache/superset.git
synced 2026-08-03 20:42:30 +00:00
feat(build): migrate from Prettier to Oxfmt for docs
Signed-off-by: hainenber <dotronghai96@gmail.com>
This commit is contained in:
@@ -177,14 +177,14 @@ plugins: [
|
||||
'@apache-superset/core': { singleton: true, import: false },
|
||||
},
|
||||
}),
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
This configuration does several important things:
|
||||
|
||||
**`exposes`** - Declares which modules are available to the host application. Superset always loads extensions by requesting the `./index` module from the remote container — this is a fixed convention, not a configurable value. Extensions must expose exactly `'./index': './src/index.tsx'` and place all API registrations (views, commands, menus, editors, event listeners) in that file. The module is executed as a side effect when the extension loads, so any call to `views.registerView`, `commands.registerCommand`, etc. made at the top level of `index.tsx` will run automatically.
|
||||
|
||||
**`shared`** - Prevents duplication of common libraries like React and Ant Design, and, for `@apache-superset/core`, is the mechanism that gives each extension an isolated context (see below). The `singleton: true` setting ensures only one *logical* instance of each library exists — for `react`/`react-dom`/`antd` that means the host's actual instance is reused; for `@apache-superset/core` it means the extension's container defers to whatever module the host's loader supplies for it at init time, which is not the same object for every extension (see [Runtime Resolution](#runtime-resolution)).
|
||||
**`shared`** - Prevents duplication of common libraries like React and Ant Design, and, for `@apache-superset/core`, is the mechanism that gives each extension an isolated context (see below). The `singleton: true` setting ensures only one _logical_ instance of each library exists — for `react`/`react-dom`/`antd` that means the host's actual instance is reused; for `@apache-superset/core` it means the extension's container defers to whatever module the host's loader supplies for it at init time, which is not the same object for every extension (see [Runtime Resolution](#runtime-resolution)).
|
||||
|
||||
### Runtime Resolution
|
||||
|
||||
|
||||
@@ -34,45 +34,40 @@ Alert component for displaying important messages to users. Wraps Ant Design Ale
|
||||
<StoryWithControls
|
||||
component={Alert}
|
||||
props={{
|
||||
closable: true,
|
||||
type: 'info',
|
||||
message: 'This is a sample alert message.',
|
||||
description: 'Sample description for additional context.',
|
||||
showIcon: true
|
||||
}}
|
||||
closable: true,
|
||||
type: 'info',
|
||||
message: 'This is a sample alert message.',
|
||||
description: 'Sample description for additional context.',
|
||||
showIcon: true,
|
||||
}}
|
||||
controls={[
|
||||
{
|
||||
name: 'type',
|
||||
label: 'Type',
|
||||
type: 'select',
|
||||
options: [
|
||||
'info',
|
||||
'error',
|
||||
'warning',
|
||||
'success'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'closable',
|
||||
label: 'Closable',
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
name: 'showIcon',
|
||||
label: 'Show Icon',
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
label: 'Message',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
label: 'Description',
|
||||
type: 'text'
|
||||
}
|
||||
]}
|
||||
{
|
||||
name: 'type',
|
||||
label: 'Type',
|
||||
type: 'select',
|
||||
options: ['info', 'error', 'warning', 'success'],
|
||||
},
|
||||
{
|
||||
name: 'closable',
|
||||
label: 'Closable',
|
||||
type: 'boolean',
|
||||
},
|
||||
{
|
||||
name: 'showIcon',
|
||||
label: 'Show Icon',
|
||||
type: 'boolean',
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
label: 'Message',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
## Try It
|
||||
@@ -95,13 +90,13 @@ function Demo() {
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `closable` | `boolean` | `true` | Whether the Alert can be closed with a close button. |
|
||||
| `type` | `string` | `"info"` | Type of the alert (e.g., info, error, warning, success). |
|
||||
| `message` | `string` | `"This is a sample alert message."` | Message |
|
||||
| `description` | `string` | `"Sample description for additional context."` | Description |
|
||||
| `showIcon` | `boolean` | `true` | Whether to display an icon in the Alert. |
|
||||
| Prop | Type | Default | Description |
|
||||
| ------------- | --------- | ---------------------------------------------- | -------------------------------------------------------- |
|
||||
| `closable` | `boolean` | `true` | Whether the Alert can be closed with a close button. |
|
||||
| `type` | `string` | `"info"` | Type of the alert (e.g., info, error, warning, success). |
|
||||
| `message` | `string` | `"This is a sample alert message."` | Message |
|
||||
| `description` | `string` | `"Sample description for additional context."` | Description |
|
||||
| `showIcon` | `boolean` | `true` | Whether to display an icon in the Alert. |
|
||||
|
||||
## Usage in Extensions
|
||||
|
||||
@@ -112,11 +107,7 @@ import { Alert } from '@apache-superset/core/components';
|
||||
|
||||
function MyExtension() {
|
||||
return (
|
||||
<Alert
|
||||
closable
|
||||
type="info"
|
||||
message="This is a sample alert message."
|
||||
/>
|
||||
<Alert closable type="info" message="This is a sample alert message." />
|
||||
);
|
||||
}
|
||||
```
|
||||
@@ -128,4 +119,4 @@ function MyExtension() {
|
||||
|
||||
---
|
||||
|
||||
*This page was auto-generated from the component's Storybook story.*
|
||||
_This page was auto-generated from the component's Storybook story._
|
||||
|
||||
@@ -39,11 +39,7 @@ All components are exported from the `@apache-superset/core/components` package:
|
||||
import { Alert } from '@apache-superset/core/components';
|
||||
|
||||
export function MyExtensionPanel() {
|
||||
return (
|
||||
<Alert type="info">
|
||||
Welcome to my extension!
|
||||
</Alert>
|
||||
);
|
||||
return <Alert type="info">Welcome to my extension!</Alert>;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -68,7 +64,7 @@ export default {
|
||||
},
|
||||
};
|
||||
|
||||
export const InteractiveMyComponent = (args) => <MyComponent {...args} />;
|
||||
export const InteractiveMyComponent = args => <MyComponent {...args} />;
|
||||
|
||||
InteractiveMyComponent.args = {
|
||||
variant: 'primary',
|
||||
|
||||
@@ -169,6 +169,7 @@ from .api import MyExtensionAPI
|
||||
- **Host context**: `/api/v1/` with original ID
|
||||
|
||||
For an extension with publisher `my-org` and name `dataset-tools`, the endpoint above would be accessible at:
|
||||
|
||||
```
|
||||
/extensions/my-org/dataset-tools/hello
|
||||
```
|
||||
|
||||
@@ -34,10 +34,10 @@ Extensions run in the same context as Superset during runtime. This means extens
|
||||
|
||||
The core packages follow [semantic versioning](https://semver.org/) and provide stable, documented APIs:
|
||||
|
||||
| Package | Language | Description |
|
||||
|---------|----------|-------------|
|
||||
| Package | Language | Description |
|
||||
| ----------------------- | --------------------- | -------------------------------------------------- |
|
||||
| `@apache-superset/core` | JavaScript/TypeScript | Frontend APIs, UI components, hooks, and utilities |
|
||||
| `apache-superset-core` | Python | Backend APIs, models, DAOs, and utilities |
|
||||
| `apache-superset-core` | Python | Backend APIs, models, DAOs, and utilities |
|
||||
|
||||
**Benefits of using core packages:**
|
||||
|
||||
@@ -116,12 +116,14 @@ Abstracting libraries like React or SQLAlchemy would:
|
||||
Extension developers should depend on and use core libraries directly:
|
||||
|
||||
**Frontend (examples):**
|
||||
|
||||
- [React](https://react.dev/) - UI framework
|
||||
- [Ant Design](https://ant.design/) - UI component library (prefer Superset components from `@apache-superset/core/components` when available to preserve visual consistency)
|
||||
- [Emotion](https://emotion.sh/) - CSS-in-JS styling
|
||||
- ...
|
||||
|
||||
**Backend (examples):**
|
||||
|
||||
- [SQLAlchemy](https://www.sqlalchemy.org/) - Database toolkit
|
||||
- [Flask](https://flask.palletsprojects.com/) - Web framework
|
||||
- [Flask-AppBuilder](https://flask-appbuilder.readthedocs.io/) - Application framework
|
||||
|
||||
@@ -35,7 +35,7 @@ Packaging is handled by the `superset-extensions bundle` command, which:
|
||||
|
||||
To deploy an extension, place the `.supx` file in the extensions directory configured via `EXTENSIONS_PATH` in your `superset_config.py`:
|
||||
|
||||
``` python
|
||||
```python
|
||||
EXTENSIONS_PATH = "/path/to/extensions"
|
||||
```
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ dataset-references/
|
||||
```
|
||||
|
||||
**Note**: With publisher `my-org` and name `dataset-references`, the technical names are:
|
||||
|
||||
- Directory name: `dataset-references` (kebab-case)
|
||||
- Backend Python namespace: `my_org.dataset_references`
|
||||
- Backend distribution package: `my_org-dataset_references`
|
||||
|
||||
@@ -30,19 +30,19 @@ Extensions can add a chat interface to Superset by registering a trigger and a p
|
||||
|
||||
A chat registration consists of two React components:
|
||||
|
||||
| Component | Role |
|
||||
|-----------|------|
|
||||
| Component | Role |
|
||||
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Trigger** | Always-visible entry point (e.g., a floating button). Rendered in the bottom-right corner in floating mode, or as a fixed overlay in panel mode. |
|
||||
| **Panel** | The chat UI itself (message list, input, etc.). Mounted by the host in the active display mode. |
|
||||
| **Panel** | The chat UI itself (message list, input, etc.). Mounted by the host in the active display mode. |
|
||||
|
||||
## Display Modes
|
||||
|
||||
The host supports two display modes, switchable by the user or the extension at runtime:
|
||||
|
||||
| Mode | Behavior |
|
||||
|------|----------|
|
||||
| `floating` | Panel floats above page content, anchored to the bottom-right corner. |
|
||||
| `panel` | Panel is docked to the right side of the application as a resizable sidebar, sitting beside the page content. |
|
||||
| Mode | Behavior |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| `floating` | Panel floats above page content, anchored to the bottom-right corner. |
|
||||
| `panel` | Panel is docked to the right side of the application as a resizable sidebar, sitting beside the page content. |
|
||||
|
||||
The user's last selected mode and open/closed state are persisted across page reloads.
|
||||
|
||||
@@ -107,7 +107,11 @@ export default function ChatPanel() {
|
||||
|
||||
return (
|
||||
<div style={{ height: mode === 'panel' ? '100%' : '80vh' }}>
|
||||
<button onClick={() => chat.setDisplayMode(mode === 'panel' ? 'floating' : 'panel')}>
|
||||
<button
|
||||
onClick={() =>
|
||||
chat.setDisplayMode(mode === 'panel' ? 'floating' : 'panel')
|
||||
}
|
||||
>
|
||||
{mode === 'panel' ? 'Float' : 'Dock'}
|
||||
</button>
|
||||
{/* message list and input */}
|
||||
@@ -120,20 +124,20 @@ export default function ChatPanel() {
|
||||
|
||||
All methods are available on the `chat` namespace from `@apache-superset/core`:
|
||||
|
||||
| Method / Event | Description |
|
||||
|----------------|-------------|
|
||||
| `registerChat(descriptor, trigger, panel)` | Register a chat extension. Returns a `Disposable` to unregister. |
|
||||
| `open()` | Open the chat panel. No-op if already open or no registration. |
|
||||
| `close()` | Close the chat panel. |
|
||||
| `isOpen()` | Returns `true` if the panel is currently open. |
|
||||
| `getDisplayMode()` | Returns the current display mode (`'floating'` or `'panel'`). |
|
||||
| `setDisplayMode(mode)` | Switch between `'floating'` and `'panel'` mode. |
|
||||
| `onDidOpen(listener)` | Subscribe to panel open events. Returns a `Disposable`. |
|
||||
| `onDidClose(listener)` | Subscribe to panel close events. Returns a `Disposable`. |
|
||||
| `onDidChangeDisplayMode(listener)` | Subscribe to display mode changes. Returns a `Disposable`. |
|
||||
| `onDidRegisterChat(listener)` | Subscribe to registration events. |
|
||||
| `onDidUnregisterChat(listener)` | Subscribe to unregistration events. |
|
||||
| `onDidResizePanel(listener)` | Subscribe to panel resize events (panel mode only). Not all hosts provide a resizer — do not rely on this firing. Returns a `Disposable`. |
|
||||
| Method / Event | Description |
|
||||
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `registerChat(descriptor, trigger, panel)` | Register a chat extension. Returns a `Disposable` to unregister. |
|
||||
| `open()` | Open the chat panel. No-op if already open or no registration. |
|
||||
| `close()` | Close the chat panel. |
|
||||
| `isOpen()` | Returns `true` if the panel is currently open. |
|
||||
| `getDisplayMode()` | Returns the current display mode (`'floating'` or `'panel'`). |
|
||||
| `setDisplayMode(mode)` | Switch between `'floating'` and `'panel'` mode. |
|
||||
| `onDidOpen(listener)` | Subscribe to panel open events. Returns a `Disposable`. |
|
||||
| `onDidClose(listener)` | Subscribe to panel close events. Returns a `Disposable`. |
|
||||
| `onDidChangeDisplayMode(listener)` | Subscribe to display mode changes. Returns a `Disposable`. |
|
||||
| `onDidRegisterChat(listener)` | Subscribe to registration events. |
|
||||
| `onDidUnregisterChat(listener)` | Subscribe to unregistration events. |
|
||||
| `onDidResizePanel(listener)` | Subscribe to panel resize events (panel mode only). Not all hosts provide a resizer — do not rely on this firing. Returns a `Disposable`. |
|
||||
|
||||
## Next Steps
|
||||
|
||||
|
||||
@@ -30,16 +30,16 @@ Extensions can replace Superset's default text editors with custom implementatio
|
||||
|
||||
Superset uses text editors in various places throughout the application:
|
||||
|
||||
| Language | Locations |
|
||||
|----------|-----------|
|
||||
| `sql` | SQL Lab, Metric/Filter Popovers |
|
||||
| `json` | Dashboard Properties, Annotation Modal, Theme Modal |
|
||||
| `css` | Dashboard Properties, CSS Template Modal |
|
||||
| `markdown` | Dashboard Markdown component |
|
||||
| `yaml` | Template Params Editor |
|
||||
| `javascript` | Custom JavaScript editor contexts |
|
||||
| `python` | Custom Python editor contexts |
|
||||
| `text` | Plain text editor contexts |
|
||||
| Language | Locations |
|
||||
| ------------ | --------------------------------------------------- |
|
||||
| `sql` | SQL Lab, Metric/Filter Popovers |
|
||||
| `json` | Dashboard Properties, Annotation Modal, Theme Modal |
|
||||
| `css` | Dashboard Properties, CSS Template Modal |
|
||||
| `markdown` | Dashboard Markdown component |
|
||||
| `yaml` | Template Params Editor |
|
||||
| `javascript` | Custom JavaScript editor contexts |
|
||||
| `python` | Custom Python editor contexts |
|
||||
| `text` | Plain text editor contexts |
|
||||
|
||||
By registering an editor for a language, your extension replaces the default Ace editor in **all** locations that use that language.
|
||||
|
||||
@@ -170,7 +170,7 @@ Superset passes keyboard shortcuts via the `hotkeys` prop. Each hotkey includes
|
||||
```typescript
|
||||
interface EditorHotkey {
|
||||
name: string;
|
||||
key: string; // e.g., "Ctrl-Enter", "Alt-Shift-F"
|
||||
key: string; // e.g., "Ctrl-Enter", "Alt-Shift-F"
|
||||
description?: string;
|
||||
exec: (handle: EditorHandle) => void;
|
||||
}
|
||||
@@ -185,9 +185,9 @@ Superset passes static autocomplete suggestions via the `keywords` prop. These i
|
||||
```typescript
|
||||
interface EditorKeyword {
|
||||
name: string;
|
||||
value?: string; // Text to insert (defaults to name)
|
||||
meta?: string; // Category like "table", "column", "function"
|
||||
score?: number; // Sorting priority
|
||||
value?: string; // Text to insert (defaults to name)
|
||||
meta?: string; // Category like "table", "column", "function"
|
||||
score?: number; // Sorting priority
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -106,7 +106,11 @@ This example adds primary, secondary, and context actions to the editor:
|
||||
import { commands, menus, sqlLab } from '@apache-superset/core';
|
||||
|
||||
commands.registerCommand(
|
||||
{ id: 'my-extension.format', title: 'Format Query', icon: 'FormatPainterOutlined' },
|
||||
{
|
||||
id: 'my-extension.format',
|
||||
title: 'Format Query',
|
||||
icon: 'FormatPainterOutlined',
|
||||
},
|
||||
async () => {
|
||||
const tab = sqlLab.getCurrentTab();
|
||||
if (tab) {
|
||||
|
||||
@@ -33,9 +33,11 @@ Model Context Protocol (MCP) integration allows extensions to register custom AI
|
||||
MCP enables extensions to extend Superset's AI capabilities in two ways:
|
||||
|
||||
### MCP Tools
|
||||
|
||||
Tools are Python functions that AI agents can call to perform specific tasks. They provide executable functionality that extends Superset's capabilities.
|
||||
|
||||
**Examples of MCP tools:**
|
||||
|
||||
- Data processing and transformation functions
|
||||
- Custom analytics calculations
|
||||
- Integration with external APIs
|
||||
@@ -43,9 +45,11 @@ Tools are Python functions that AI agents can call to perform specific tasks. Th
|
||||
- Business-specific operations
|
||||
|
||||
### MCP Prompts
|
||||
|
||||
Prompts provide interactive guidance and context to AI agents. They help agents understand how to better assist users with specific workflows or domain knowledge.
|
||||
|
||||
**Examples of MCP prompts:**
|
||||
|
||||
- Step-by-step workflow guidance
|
||||
- Domain-specific context and knowledge
|
||||
- Interactive troubleshooting assistance
|
||||
@@ -76,6 +80,7 @@ This creates a tool that AI agents can call by name. The tool name defaults to t
|
||||
The `@tool` decorator accepts several optional parameters:
|
||||
|
||||
**Parameter details:**
|
||||
|
||||
- **`name`**: Tool identifier (AI agents use this to call your tool)
|
||||
- **`description`**: Explains what the tool does (helps AI agents decide when to use it)
|
||||
- **`tags`**: Categories for organization and discovery
|
||||
@@ -213,6 +218,7 @@ Agent: I generated the number 42 for you.
|
||||
```
|
||||
|
||||
The AI agent sees your tool's:
|
||||
|
||||
- **Name**: How to call it
|
||||
- **Description**: What it does and when to use it
|
||||
- **Parameters**: What inputs it expects (from Pydantic schema)
|
||||
@@ -377,18 +383,21 @@ async def troubleshoot_charts(ctx: Context) -> str:
|
||||
### Prompt Best Practices
|
||||
|
||||
#### Content Structure
|
||||
|
||||
- **Use clear headings** and sections for easy navigation
|
||||
- **Provide actionable steps** rather than just theory
|
||||
- **Include examples** relevant to the user's domain
|
||||
- **Offer next steps** to continue the workflow
|
||||
|
||||
#### Interactive Design
|
||||
|
||||
- **Ask questions** to engage the user
|
||||
- **Provide options** for different scenarios
|
||||
- **Reference specific Superset features** by name
|
||||
- **Link to related tools** when appropriate
|
||||
|
||||
#### Context Awareness
|
||||
|
||||
```python
|
||||
@prompt("analytics_extension.context_aware_guide")
|
||||
async def context_aware_guide(ctx: Context) -> str:
|
||||
|
||||
@@ -36,9 +36,9 @@ This page serves as a registry of community-created Superset extensions. These e
|
||||
| [SQL Lab Export to Parquet](https://github.com/rusackas/superset-extensions/tree/main/sqllab_parquet) | Export SQL Lab query results directly to Apache Parquet format with Snappy compression. | Evan Rusackas | <a href="/img/extensions/parquet-export.png" target="_blank"><img src="/img/extensions/parquet-export.png" alt="SQL Lab Export to Parquet" width="120" /></a> |
|
||||
| [SQL Lab Query Comparison](https://github.com/michael-s-molina/superset-extensions/tree/main/query-comparison) | A SQL Lab extension that enables side-by-side comparison of query results across different tabs, with GitHub-style diff visualization showing added/removed rows and columns. | Michael S. Molina | <a href="/img/extensions/query-comparison.png" target="_blank"><img src="/img/extensions/query-comparison.png" alt="Query Comparison" width="120" /></a> |
|
||||
| [SQL Lab Result Stats](https://github.com/michael-s-molina/superset-extensions/tree/main/result-stats) | A SQL Lab extension that automatically computes statistics for query results, providing type-aware analysis including numeric metrics (min, max, mean, median, std dev), string analysis (length, empty counts), and date range information. | Michael S. Molina | <a href="/img/extensions/result-stats.png" target="_blank"><img src="/img/extensions/result-stats.png" alt="Result Stats" width="120" /></a> |
|
||||
| [Editor Snippets](https://github.com/michael-s-molina/superset-extensions/tree/main/editor-snippets) | A SQL Lab extension for managing and inserting reusable code snippets into the editor, with server-side persistence per user. | Michael S. Molina | <a href="/img/extensions/editor-snippets.png" target="_blank"><img src="/img/extensions/editor-snippets.png" alt="Editor Snippets" width="120" /></a> |
|
||||
| [Editor Snippets](https://github.com/michael-s-molina/superset-extensions/tree/main/editor-snippets) | A SQL Lab extension for managing and inserting reusable code snippets into the editor, with server-side persistence per user. | Michael S. Molina | <a href="/img/extensions/editor-snippets.png" target="_blank"><img src="/img/extensions/editor-snippets.png" alt="Editor Snippets" width="120" /></a> |
|
||||
| [SQL Lab Query Estimator](https://github.com/michael-s-molina/superset-extensions/tree/main/query-estimator) | A SQL Lab panel that analyzes query execution plans to estimate resource impact, detect performance issues like Cartesian products and high-cost operations, and visualize the query plan tree. | Michael S. Molina | <a href="/img/extensions/query-estimator.png" target="_blank"><img src="/img/extensions/query-estimator.png" alt="Query Estimator" width="120" /></a> |
|
||||
| [Editors Bundle](https://github.com/michael-s-molina/superset-extensions/tree/main/editors-bundle) | A Superset extension that demonstrates how to provide custom code editors for different languages. This extension showcases the editor contribution system by registering alternative editors that can replace Superset's default Ace editor. | Michael S. Molina | <a href="/img/extensions/editors-bundle.png" target="_blank"><img src="/img/extensions/editors-bundle.png" alt="Editors Bundle" width="120" /></a> |
|
||||
| [Editors Bundle](https://github.com/michael-s-molina/superset-extensions/tree/main/editors-bundle) | A Superset extension that demonstrates how to provide custom code editors for different languages. This extension showcases the editor contribution system by registering alternative editors that can replace Superset's default Ace editor. | Michael S. Molina | <a href="/img/extensions/editors-bundle.png" target="_blank"><img src="/img/extensions/editors-bundle.png" alt="Editors Bundle" width="120" /></a> |
|
||||
|
||||
## How to Add Your Extension
|
||||
|
||||
|
||||
@@ -117,7 +117,11 @@ import { extensions } from '@apache-superset/core';
|
||||
const ctx = extensions.getContext();
|
||||
|
||||
// Store with a 5-minute TTL
|
||||
await ctx.storage.ephemeral.set('job_progress', { pct: 42, status: 'running' }, { ttl: 300 });
|
||||
await ctx.storage.ephemeral.set(
|
||||
'job_progress',
|
||||
{ pct: 42, status: 'running' },
|
||||
{ ttl: 300 },
|
||||
);
|
||||
|
||||
// Retrieve
|
||||
const progress = await ctx.storage.ephemeral.get('job_progress');
|
||||
@@ -155,7 +159,11 @@ import { extensions } from '@apache-superset/core';
|
||||
|
||||
const ctx = extensions.getContext();
|
||||
|
||||
await ctx.storage.ephemeral.shared.set('shared_result', { data: [1, 2, 3] }, { ttl: 3600 });
|
||||
await ctx.storage.ephemeral.shared.set(
|
||||
'shared_result',
|
||||
{ data: [1, 2, 3] },
|
||||
{ ttl: 3600 },
|
||||
);
|
||||
const result = await ctx.storage.ephemeral.shared.get('shared_result');
|
||||
```
|
||||
|
||||
@@ -198,7 +206,9 @@ import { extensions } from '@apache-superset/core';
|
||||
const ctx = extensions.getContext();
|
||||
|
||||
// Store a saved SQL snippet
|
||||
await ctx.storage.persistent.set('snippet:top_customers', { sql: 'SELECT ...' });
|
||||
await ctx.storage.persistent.set('snippet:top_customers', {
|
||||
sql: 'SELECT ...',
|
||||
});
|
||||
|
||||
// Retrieve
|
||||
const snippet = await ctx.storage.persistent.get('snippet:top_customers');
|
||||
@@ -268,7 +278,10 @@ result.entries.forEach(entry => {
|
||||
console.log(result.count); // total matching entries across all pages
|
||||
|
||||
// Shared (global) scope
|
||||
const shared = await ctx.storage.persistent.shared.list({ page: 0, pageSize: 10 });
|
||||
const shared = await ctx.storage.persistent.shared.list({
|
||||
page: 0,
|
||||
pageSize: 10,
|
||||
});
|
||||
```
|
||||
|
||||
```python
|
||||
|
||||
@@ -37,6 +37,7 @@ FEATURE_FLAGS = {
|
||||
```
|
||||
|
||||
When GTF is disabled:
|
||||
|
||||
- The Task List UI menu item is hidden
|
||||
- The `/api/v1/task/*` endpoints return 404
|
||||
- Calling or scheduling a `@task`-decorated function raises `GlobalTaskFrameworkDisabledError`
|
||||
@@ -79,10 +80,10 @@ print(task.status) # "success"
|
||||
|
||||
### Async vs Sync Execution
|
||||
|
||||
| Method | When to Use |
|
||||
|--------|-------------|
|
||||
| `.schedule()` | Long-running operations, background processing, when you need to return immediately |
|
||||
| Direct call | Short operations, when deduplication matters, when you need the result before responding |
|
||||
| Method | When to Use |
|
||||
| ------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `.schedule()` | Long-running operations, background processing, when you need to return immediately |
|
||||
| Direct call | Short operations, when deduplication matters, when you need the result before responding |
|
||||
|
||||
Both execution modes provide the same task features: deduplication, progress tracking, cancellation, and visibility in the Task List UI. The difference is whether execution happens in a Celery worker (async) or inline (sync).
|
||||
|
||||
@@ -100,15 +101,15 @@ PENDING ──→ IN_PROGRESS ────→ SUCCESS
|
||||
└─────────────┴──────────→ ABORTED (user cancel)
|
||||
```
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| `PENDING` | Queued, awaiting execution |
|
||||
| `IN_PROGRESS` | Executing |
|
||||
| `ABORTING` | Abort/timeout triggered, abort handlers running |
|
||||
| `SUCCESS` | Completed successfully |
|
||||
| `FAILURE` | Failed with error or abort/cleanup handler exception |
|
||||
| `ABORTED` | Cancelled by user/admin |
|
||||
| `TIMED_OUT` | Exceeded configured timeout |
|
||||
| Status | Description |
|
||||
| ------------- | ---------------------------------------------------- |
|
||||
| `PENDING` | Queued, awaiting execution |
|
||||
| `IN_PROGRESS` | Executing |
|
||||
| `ABORTING` | Abort/timeout triggered, abort handlers running |
|
||||
| `SUCCESS` | Completed successfully |
|
||||
| `FAILURE` | Failed with error or abort/cleanup handler exception |
|
||||
| `ABORTED` | Cancelled by user/admin |
|
||||
| `TIMED_OUT` | Exceeded configured timeout |
|
||||
|
||||
## Context API
|
||||
|
||||
@@ -139,11 +140,11 @@ Call `update_task()` once per iteration for best performance. Frequent DB writes
|
||||
|
||||
The `progress` parameter accepts three formats:
|
||||
|
||||
| Format | Example | Display |
|
||||
|--------|---------|---------|
|
||||
| Format | Example | Display |
|
||||
| ----------------- | ------------------- | ---------------------- |
|
||||
| `tuple[int, int]` | `progress=(3, 100)` | 3 of 100 (3%) with ETA |
|
||||
| `float` (0.0-1.0) | `progress=0.5` | 50% with ETA |
|
||||
| `int` | `progress=42` | 42 processed |
|
||||
| `float` (0.0-1.0) | `progress=0.5` | 50% with ETA |
|
||||
| `int` | `progress=42` | 42 processed |
|
||||
|
||||
:::tip
|
||||
Use the tuple format `(current, total)` whenever possible. It provides the richest information to users: showing both the count and percentage, while still computing ETA automatically.
|
||||
@@ -159,10 +160,10 @@ In the Task List UI, when a payload is defined, an info icon appears in the **De
|
||||
|
||||
Register handlers to run cleanup logic or respond to abort requests:
|
||||
|
||||
| Handler | When it runs | Use case |
|
||||
|---------|--------------|----------|
|
||||
| `on_cleanup` | Always (success, failure, abort) | Release resources, close connections |
|
||||
| `on_abort` | When task is aborted | Set stop flag, cancel external operations |
|
||||
| Handler | When it runs | Use case |
|
||||
| ------------ | -------------------------------- | ----------------------------------------- |
|
||||
| `on_cleanup` | Always (success, failure, abort) | Release resources, close connections |
|
||||
| `on_abort` | When task is aborted | Set stop flag, cancel external operations |
|
||||
|
||||
```python
|
||||
@task
|
||||
@@ -187,6 +188,7 @@ Multiple handlers of the same type execute in LIFO order (last registered runs f
|
||||
**All registered handlers will always be attempted, even if one fails.** This ensures that a failure in one handler doesn't prevent other handlers from running their cleanup logic.
|
||||
|
||||
For example, if you have three cleanup handlers and the second one throws an exception:
|
||||
|
||||
1. Handler 3 runs ✓
|
||||
2. Handler 2 throws an exception ✗ (logged, but execution continues)
|
||||
3. Handler 1 runs ✓
|
||||
@@ -200,6 +202,7 @@ Write handlers to be independent and self-contained. Don't assume previous handl
|
||||
## Making Tasks Abortable
|
||||
|
||||
When users click **Cancel** in the Task List, the system decides whether to **abort** (stop) the task or **unsubscribe** (remove the user from a shared task). Abort occurs when:
|
||||
|
||||
- It's a private or system task
|
||||
- It's a shared task and the user is the last subscriber
|
||||
- An admin checks **Force abort** to stop the task for all subscribers
|
||||
@@ -229,6 +232,7 @@ def abortable_task(items: list[str]) -> None:
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
|
||||
- Registering `on_abort` marks the task as abortable and starts the abort listener
|
||||
- The abort handler fires automatically when abort is triggered
|
||||
- Use a flag pattern to gracefully stop processing at safe points
|
||||
@@ -283,11 +287,11 @@ The timeout timer starts when the task begins executing (status changes to `IN_P
|
||||
|
||||
### Timeout Precedence
|
||||
|
||||
| Source | Priority | Example |
|
||||
|--------|----------|---------|
|
||||
| `TaskOptions.timeout` | Highest | `options=TaskOptions(timeout=600)` |
|
||||
| `@task(timeout=...)` | Default | `@task(timeout=300)` |
|
||||
| Not set | No timeout | Task runs indefinitely |
|
||||
| Source | Priority | Example |
|
||||
| --------------------- | ---------- | ---------------------------------- |
|
||||
| `TaskOptions.timeout` | Highest | `options=TaskOptions(timeout=600)` |
|
||||
| `@task(timeout=...)` | Default | `@task(timeout=300)` |
|
||||
| Not set | No timeout | Task runs indefinitely |
|
||||
|
||||
Call-time options always override decorator defaults, allowing tasks to have sensible defaults while permitting callers to extend or shorten the timeout for specific use cases.
|
||||
|
||||
@@ -345,11 +349,11 @@ def shared_task(): ...
|
||||
def system_task(): ...
|
||||
```
|
||||
|
||||
| Scope | Visibility | Cancel Behavior |
|
||||
|-------|------------|-----------------|
|
||||
| `PRIVATE` | Creator only | Cancels immediately |
|
||||
| `SHARED` | All subscribers | Last subscriber cancels; others unsubscribe |
|
||||
| `SYSTEM` | Admins only | Admin cancels |
|
||||
| Scope | Visibility | Cancel Behavior |
|
||||
| --------- | --------------- | ------------------------------------------- |
|
||||
| `PRIVATE` | Creator only | Cancels immediately |
|
||||
| `SHARED` | All subscribers | Last subscriber cancels; others unsubscribe |
|
||||
| `SYSTEM` | Admins only | Admin cancels |
|
||||
|
||||
## Task Cleanup
|
||||
|
||||
@@ -393,11 +397,11 @@ By default, abort detection and sync join-and-wait use database polling. Configu
|
||||
|
||||
### TaskContext Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `update_task(progress, payload)` | Update progress and/or custom payload |
|
||||
| `on_cleanup(handler)` | Register cleanup handler |
|
||||
| `on_abort(handler)` | Register abort handler (makes task abortable) |
|
||||
| Method | Description |
|
||||
| -------------------------------- | --------------------------------------------- |
|
||||
| `update_task(progress, payload)` | Update progress and/or custom payload |
|
||||
| `on_cleanup(handler)` | Register cleanup handler |
|
||||
| `on_abort(handler)` | Register abort handler (makes task abortable) |
|
||||
|
||||
### TaskOptions
|
||||
|
||||
@@ -429,6 +433,7 @@ def risky_task() -> None:
|
||||
```
|
||||
|
||||
On failure, the framework records:
|
||||
|
||||
- `error_message`: Exception message
|
||||
- `exception_type`: Exception class name
|
||||
- `stack_trace`: Full traceback (visible when `SHOW_STACKTRACE=True`)
|
||||
|
||||
Reference in New Issue
Block a user