mirror of
https://github.com/apache/superset.git
synced 2026-04-08 19:05:46 +00:00
773 lines
14 KiB
Markdown
773 lines
14 KiB
Markdown
---
|
|
title: Frontend API Reference
|
|
sidebar_position: 1
|
|
---
|
|
|
|
<!--
|
|
Licensed to the Apache Software Foundation (ASF) under one
|
|
or more contributor license agreements. See the NOTICE file
|
|
distributed with this work for additional information
|
|
regarding copyright ownership. The ASF licenses this file
|
|
to you under the Apache License, Version 2.0 (the
|
|
"License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing,
|
|
software distributed under the License is distributed on an
|
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
KIND, either express or implied. See the License for the
|
|
specific language governing permissions and limitations
|
|
under the License.
|
|
-->
|
|
|
|
# Frontend Extension API Reference
|
|
|
|
The `@apache-superset/core` package provides comprehensive APIs for frontend extensions to interact with Apache Superset. All APIs are versioned and follow semantic versioning principles.
|
|
|
|
## Core APIs
|
|
|
|
### Extension Context
|
|
|
|
Every extension receives a context object during activation that provides access to the extension system.
|
|
|
|
```typescript
|
|
interface ExtensionContext {
|
|
// Unique extension identifier
|
|
extensionId: string;
|
|
|
|
// Extension metadata
|
|
extensionPath: string;
|
|
extensionUri: Uri;
|
|
|
|
// Storage paths
|
|
globalStorageUri: Uri;
|
|
workspaceStorageUri: Uri;
|
|
|
|
// Subscription management
|
|
subscriptions: Disposable[];
|
|
|
|
// State management
|
|
globalState: Memento;
|
|
workspaceState: Memento;
|
|
|
|
// Extension-specific APIs
|
|
registerView(viewId: string, component: React.Component): Disposable;
|
|
registerCommand(commandId: string, handler: CommandHandler): Disposable;
|
|
}
|
|
```
|
|
|
|
### Lifecycle Methods
|
|
|
|
```typescript
|
|
// Required: Called when extension is activated
|
|
export function activate(context: ExtensionContext): void | Promise<void> {
|
|
console.log('Extension activated');
|
|
}
|
|
|
|
// Optional: Called when extension is deactivated
|
|
export function deactivate(): void | Promise<void> {
|
|
console.log('Extension deactivated');
|
|
}
|
|
```
|
|
|
|
## SQL Lab APIs
|
|
|
|
The `sqlLab` namespace provides APIs specific to SQL Lab functionality.
|
|
|
|
### Query Management
|
|
|
|
```typescript
|
|
// Get current query editor content
|
|
sqlLab.getCurrentQuery(): string | undefined
|
|
|
|
// Get active tab information
|
|
sqlLab.getCurrentTab(): Tab | undefined
|
|
|
|
// Get all open tabs
|
|
sqlLab.getTabs(): Tab[]
|
|
|
|
// Get available databases
|
|
sqlLab.getDatabases(): Database[]
|
|
|
|
// Get schemas for a database
|
|
sqlLab.getSchemas(databaseId: number): Promise<Schema[]>
|
|
|
|
// Get tables for a schema
|
|
sqlLab.getTables(databaseId: number, schema: string): Promise<Table[]>
|
|
|
|
// Insert text at cursor position
|
|
sqlLab.insertText(text: string): void
|
|
|
|
// Replace entire query
|
|
sqlLab.replaceQuery(query: string): void
|
|
|
|
// Execute current query
|
|
sqlLab.executeQuery(): Promise<QueryResult>
|
|
|
|
// Stop query execution
|
|
sqlLab.stopQuery(queryId: string): Promise<void>
|
|
```
|
|
|
|
### Event Subscriptions
|
|
|
|
```typescript
|
|
// Query execution events
|
|
sqlLab.onDidQueryRun(
|
|
listener: (event: QueryRunEvent) => void
|
|
): Disposable
|
|
|
|
sqlLab.onDidQueryComplete(
|
|
listener: (event: QueryCompleteEvent) => void
|
|
): Disposable
|
|
|
|
sqlLab.onDidQueryFail(
|
|
listener: (event: QueryFailEvent) => void
|
|
): Disposable
|
|
|
|
// Editor events
|
|
sqlLab.onDidChangeEditorContent(
|
|
listener: (content: string) => void
|
|
): Disposable
|
|
|
|
sqlLab.onDidChangeActiveTab(
|
|
listener: (tab: Tab) => void
|
|
): Disposable
|
|
|
|
// Panel events
|
|
sqlLab.onDidOpenPanel(
|
|
listener: (panel: Panel) => void
|
|
): Disposable
|
|
|
|
sqlLab.onDidClosePanel(
|
|
listener: (panel: Panel) => void
|
|
): Disposable
|
|
```
|
|
|
|
### Types
|
|
|
|
```typescript
|
|
interface Tab {
|
|
id: string;
|
|
title: string;
|
|
query: string;
|
|
database: Database;
|
|
schema?: string;
|
|
isActive: boolean;
|
|
queryId?: string;
|
|
status?: 'pending' | 'running' | 'success' | 'error';
|
|
}
|
|
|
|
interface Database {
|
|
id: number;
|
|
name: string;
|
|
backend: string;
|
|
allows_subquery: boolean;
|
|
allows_ctas: boolean;
|
|
allows_cvas: boolean;
|
|
}
|
|
|
|
interface QueryResult {
|
|
queryId: string;
|
|
status: 'success' | 'error';
|
|
data?: any[];
|
|
columns?: Column[];
|
|
error?: string;
|
|
startTime: number;
|
|
endTime: number;
|
|
rows: number;
|
|
}
|
|
```
|
|
|
|
## Commands API
|
|
|
|
Register and execute commands within Superset.
|
|
|
|
### Registration
|
|
|
|
```typescript
|
|
interface CommandHandler {
|
|
execute(...args: any[]): any | Promise<any>;
|
|
isEnabled?(): boolean;
|
|
isVisible?(): boolean;
|
|
}
|
|
|
|
// Register a command
|
|
commands.registerCommand(
|
|
commandId: string,
|
|
handler: CommandHandler
|
|
): Disposable
|
|
|
|
// Register with metadata
|
|
commands.registerCommand(
|
|
commandId: string,
|
|
metadata: CommandMetadata,
|
|
handler: (...args: any[]) => any
|
|
): Disposable
|
|
|
|
interface CommandMetadata {
|
|
title: string;
|
|
category?: string;
|
|
icon?: string;
|
|
enablement?: string;
|
|
when?: string;
|
|
}
|
|
```
|
|
|
|
### Execution
|
|
|
|
```typescript
|
|
// Execute a command
|
|
commands.executeCommand<T>(
|
|
commandId: string,
|
|
...args: any[]
|
|
): Promise<T>
|
|
|
|
// Get all registered commands
|
|
commands.getCommands(): Promise<string[]>
|
|
|
|
// Check if command exists
|
|
commands.hasCommand(commandId: string): boolean
|
|
```
|
|
|
|
### Built-in Commands
|
|
|
|
```typescript
|
|
// SQL Lab commands
|
|
'sqllab.executeQuery'
|
|
'sqllab.formatQuery'
|
|
'sqllab.saveQuery'
|
|
'sqllab.shareQuery'
|
|
'sqllab.downloadResults'
|
|
|
|
// Editor commands
|
|
'editor.action.formatDocument'
|
|
'editor.action.commentLine'
|
|
'editor.action.findReferences'
|
|
|
|
// Extension commands
|
|
'extensions.installExtension'
|
|
'extensions.uninstallExtension'
|
|
'extensions.enableExtension'
|
|
'extensions.disableExtension'
|
|
```
|
|
|
|
## UI Components
|
|
|
|
Pre-built components from `@apache-superset/core` for consistent UI.
|
|
|
|
### Basic Components
|
|
|
|
```typescript
|
|
import {
|
|
Button,
|
|
Input,
|
|
Select,
|
|
Checkbox,
|
|
Radio,
|
|
Switch,
|
|
Slider,
|
|
DatePicker,
|
|
TimePicker,
|
|
Tooltip,
|
|
Popover,
|
|
Modal,
|
|
Drawer,
|
|
Alert,
|
|
Message,
|
|
Notification,
|
|
Spin,
|
|
Progress
|
|
} from '@apache-superset/core';
|
|
```
|
|
|
|
### Data Display
|
|
|
|
```typescript
|
|
import {
|
|
Table,
|
|
List,
|
|
Card,
|
|
Collapse,
|
|
Tabs,
|
|
Tag,
|
|
Badge,
|
|
Statistic,
|
|
Timeline,
|
|
Tree,
|
|
Empty,
|
|
Result
|
|
} from '@apache-superset/core';
|
|
```
|
|
|
|
### Form Components
|
|
|
|
```typescript
|
|
import {
|
|
Form,
|
|
FormItem,
|
|
FormList,
|
|
InputNumber,
|
|
TextArea,
|
|
Upload,
|
|
Rate,
|
|
Cascader,
|
|
AutoComplete,
|
|
Mentions
|
|
} from '@apache-superset/core';
|
|
```
|
|
|
|
## Authentication API
|
|
|
|
Access authentication and user information.
|
|
|
|
```typescript
|
|
// Get current user
|
|
authentication.getCurrentUser(): User | undefined
|
|
|
|
interface User {
|
|
id: number;
|
|
username: string;
|
|
email: string;
|
|
firstName: string;
|
|
lastName: string;
|
|
roles: Role[];
|
|
isActive: boolean;
|
|
isAnonymous: boolean;
|
|
}
|
|
|
|
// Get CSRF token for API requests
|
|
authentication.getCSRFToken(): Promise<string>
|
|
|
|
// Check permissions
|
|
authentication.hasPermission(
|
|
permission: string,
|
|
resource?: string
|
|
): boolean
|
|
|
|
// Get user preferences
|
|
authentication.getPreferences(): UserPreferences
|
|
|
|
// Update preferences
|
|
authentication.setPreference(
|
|
key: string,
|
|
value: any
|
|
): Promise<void>
|
|
```
|
|
|
|
## Storage API
|
|
|
|
Persist data across sessions.
|
|
|
|
### Global Storage
|
|
|
|
```typescript
|
|
// Shared across all workspaces
|
|
const globalState = context.globalState;
|
|
|
|
// Get value
|
|
const value = globalState.get<T>(key: string): T | undefined
|
|
|
|
// Set value
|
|
await globalState.update(key: string, value: any): Promise<void>
|
|
|
|
// Get all keys
|
|
globalState.keys(): readonly string[]
|
|
```
|
|
|
|
### Workspace Storage
|
|
|
|
```typescript
|
|
// Specific to current workspace
|
|
const workspaceState = context.workspaceState;
|
|
|
|
// Same API as globalState
|
|
workspaceState.get<T>(key: string): T | undefined
|
|
workspaceState.update(key: string, value: any): Promise<void>
|
|
workspaceState.keys(): readonly string[]
|
|
```
|
|
|
|
### Secrets Storage
|
|
|
|
```typescript
|
|
// Secure storage for sensitive data
|
|
secrets.store(key: string, value: string): Promise<void>
|
|
secrets.get(key: string): Promise<string | undefined>
|
|
secrets.delete(key: string): Promise<void>
|
|
```
|
|
|
|
## Events API
|
|
|
|
Subscribe to and emit custom events.
|
|
|
|
```typescript
|
|
// Create an event emitter
|
|
const onDidChange = new EventEmitter<ChangeEvent>();
|
|
|
|
// Expose as event
|
|
export const onChange = onDidChange.event;
|
|
|
|
// Fire event
|
|
onDidChange.fire({
|
|
type: 'update',
|
|
data: newData
|
|
});
|
|
|
|
// Subscribe to event
|
|
const disposable = onChange((event) => {
|
|
console.log('Changed:', event);
|
|
});
|
|
|
|
// Cleanup
|
|
disposable.dispose();
|
|
```
|
|
|
|
## Window API
|
|
|
|
Interact with the UI window.
|
|
|
|
### Notifications
|
|
|
|
```typescript
|
|
// Show info message
|
|
window.showInformationMessage(
|
|
message: string,
|
|
...items: string[]
|
|
): Promise<string | undefined>
|
|
|
|
// Show warning
|
|
window.showWarningMessage(
|
|
message: string,
|
|
...items: string[]
|
|
): Promise<string | undefined>
|
|
|
|
// Show error
|
|
window.showErrorMessage(
|
|
message: string,
|
|
...items: string[]
|
|
): Promise<string | undefined>
|
|
|
|
// Show with options
|
|
window.showInformationMessage(
|
|
message: string,
|
|
options: MessageOptions,
|
|
...items: MessageItem[]
|
|
): Promise<MessageItem | undefined>
|
|
|
|
interface MessageOptions {
|
|
modal?: boolean;
|
|
detail?: string;
|
|
}
|
|
```
|
|
|
|
### Input Dialogs
|
|
|
|
```typescript
|
|
// Show input box
|
|
window.showInputBox(
|
|
options?: InputBoxOptions
|
|
): Promise<string | undefined>
|
|
|
|
interface InputBoxOptions {
|
|
title?: string;
|
|
prompt?: string;
|
|
placeHolder?: string;
|
|
value?: string;
|
|
password?: boolean;
|
|
validateInput?(value: string): string | null;
|
|
}
|
|
|
|
// Show quick pick
|
|
window.showQuickPick(
|
|
items: string[] | QuickPickItem[],
|
|
options?: QuickPickOptions
|
|
): Promise<string | QuickPickItem | undefined>
|
|
|
|
interface QuickPickOptions {
|
|
title?: string;
|
|
placeHolder?: string;
|
|
canPickMany?: boolean;
|
|
matchOnDescription?: boolean;
|
|
matchOnDetail?: boolean;
|
|
}
|
|
```
|
|
|
|
### Progress
|
|
|
|
```typescript
|
|
// Show progress
|
|
window.withProgress<T>(
|
|
options: ProgressOptions,
|
|
task: (progress: Progress<{message?: string}>) => Promise<T>
|
|
): Promise<T>
|
|
|
|
interface ProgressOptions {
|
|
location: ProgressLocation;
|
|
title?: string;
|
|
cancellable?: boolean;
|
|
}
|
|
|
|
// Example usage
|
|
await window.withProgress(
|
|
{
|
|
location: ProgressLocation.Notification,
|
|
title: "Processing",
|
|
cancellable: true
|
|
},
|
|
async (progress) => {
|
|
progress.report({ message: 'Step 1...' });
|
|
await step1();
|
|
progress.report({ message: 'Step 2...' });
|
|
await step2();
|
|
}
|
|
);
|
|
```
|
|
|
|
## Workspace API
|
|
|
|
Access workspace information and configuration.
|
|
|
|
```typescript
|
|
// Get workspace folders
|
|
workspace.workspaceFolders: readonly WorkspaceFolder[]
|
|
|
|
// Get configuration
|
|
workspace.getConfiguration(
|
|
section?: string
|
|
): WorkspaceConfiguration
|
|
|
|
// Update configuration
|
|
workspace.getConfiguration('myExtension')
|
|
.update('setting', value, ConfigurationTarget.Workspace)
|
|
|
|
// Watch for configuration changes
|
|
workspace.onDidChangeConfiguration(
|
|
listener: (e: ConfigurationChangeEvent) => void
|
|
): Disposable
|
|
|
|
// File system operations
|
|
workspace.fs.readFile(uri: Uri): Promise<Uint8Array>
|
|
workspace.fs.writeFile(uri: Uri, content: Uint8Array): Promise<void>
|
|
workspace.fs.delete(uri: Uri): Promise<void>
|
|
workspace.fs.rename(oldUri: Uri, newUri: Uri): Promise<void>
|
|
workspace.fs.copy(source: Uri, destination: Uri): Promise<void>
|
|
workspace.fs.createDirectory(uri: Uri): Promise<void>
|
|
workspace.fs.readDirectory(uri: Uri): Promise<[string, FileType][]>
|
|
workspace.fs.stat(uri: Uri): Promise<FileStat>
|
|
```
|
|
|
|
## HTTP Client API
|
|
|
|
Make HTTP requests from extensions.
|
|
|
|
```typescript
|
|
import { api } from '@apache-superset/core';
|
|
|
|
// GET request
|
|
const response = await api.get('/api/v1/chart/');
|
|
|
|
// POST request
|
|
const response = await api.post('/api/v1/chart/', {
|
|
data: chartData
|
|
});
|
|
|
|
// PUT request
|
|
const response = await api.put('/api/v1/chart/123', {
|
|
data: updatedData
|
|
});
|
|
|
|
// DELETE request
|
|
const response = await api.delete('/api/v1/chart/123');
|
|
|
|
// Custom headers
|
|
const response = await api.get('/api/v1/chart/', {
|
|
headers: {
|
|
'X-Custom-Header': 'value'
|
|
}
|
|
});
|
|
|
|
// Query parameters
|
|
const response = await api.get('/api/v1/chart/', {
|
|
params: {
|
|
page: 1,
|
|
page_size: 20
|
|
}
|
|
});
|
|
```
|
|
|
|
## Theming API
|
|
|
|
Access and customize theme settings.
|
|
|
|
```typescript
|
|
// Get current theme
|
|
theme.getActiveTheme(): Theme
|
|
|
|
interface Theme {
|
|
name: string;
|
|
isDark: boolean;
|
|
colors: ThemeColors;
|
|
typography: Typography;
|
|
spacing: Spacing;
|
|
}
|
|
|
|
// Listen for theme changes
|
|
theme.onDidChangeTheme(
|
|
listener: (theme: Theme) => void
|
|
): Disposable
|
|
|
|
// Get theme colors
|
|
const colors = theme.colors;
|
|
colors.primary
|
|
colors.success
|
|
colors.warning
|
|
colors.error
|
|
colors.info
|
|
colors.text
|
|
colors.background
|
|
colors.border
|
|
```
|
|
|
|
## Disposable Pattern
|
|
|
|
Manage resource cleanup consistently.
|
|
|
|
```typescript
|
|
interface Disposable {
|
|
dispose(): void;
|
|
}
|
|
|
|
// Create a disposable
|
|
class MyDisposable implements Disposable {
|
|
dispose() {
|
|
// Cleanup logic
|
|
}
|
|
}
|
|
|
|
// Combine disposables
|
|
const composite = Disposable.from(
|
|
disposable1,
|
|
disposable2,
|
|
disposable3
|
|
);
|
|
|
|
// Dispose all at once
|
|
composite.dispose();
|
|
|
|
// Use in extension
|
|
export function activate(context: ExtensionContext) {
|
|
// All disposables added here are cleaned up on deactivation
|
|
context.subscriptions.push(
|
|
registerCommand(...),
|
|
registerView(...),
|
|
onDidChange(...)
|
|
);
|
|
}
|
|
```
|
|
|
|
## Type Definitions
|
|
|
|
Complete TypeScript definitions are available:
|
|
|
|
```typescript
|
|
import type {
|
|
ExtensionContext,
|
|
Disposable,
|
|
Event,
|
|
EventEmitter,
|
|
Uri,
|
|
Command,
|
|
QuickPickItem,
|
|
InputBoxOptions,
|
|
Progress,
|
|
CancellationToken
|
|
} from '@apache-superset/core';
|
|
```
|
|
|
|
## Version Compatibility
|
|
|
|
The API follows semantic versioning:
|
|
|
|
```typescript
|
|
// Check API version
|
|
const version = superset.version;
|
|
|
|
// Version components
|
|
version.major // Breaking changes
|
|
version.minor // New features
|
|
version.patch // Bug fixes
|
|
|
|
// Check minimum version
|
|
if (version.major < 1) {
|
|
throw new Error('Requires Superset API v1.0.0 or higher');
|
|
}
|
|
```
|
|
|
|
## Migration Guide
|
|
|
|
### From v0.x to v1.0
|
|
|
|
```typescript
|
|
// Before (v0.x)
|
|
sqlLab.runQuery(query);
|
|
|
|
// After (v1.0)
|
|
sqlLab.executeQuery();
|
|
|
|
// Before (v0.x)
|
|
core.registerPanel(id, component);
|
|
|
|
// After (v1.0)
|
|
context.registerView(id, component);
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### Error Handling
|
|
|
|
```typescript
|
|
export async function activate(context: ExtensionContext) {
|
|
try {
|
|
await initializeExtension();
|
|
} catch (error) {
|
|
console.error('Failed to initialize:', error);
|
|
window.showErrorMessage(
|
|
`Extension failed to activate: ${error.message}`
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Resource Management
|
|
|
|
```typescript
|
|
// Always use disposables
|
|
const disposables: Disposable[] = [];
|
|
|
|
disposables.push(
|
|
commands.registerCommand(...),
|
|
sqlLab.onDidQueryRun(...),
|
|
workspace.onDidChangeConfiguration(...)
|
|
);
|
|
|
|
// Cleanup in deactivate
|
|
export function deactivate() {
|
|
disposables.forEach(d => d.dispose());
|
|
}
|
|
```
|
|
|
|
### Type Safety
|
|
|
|
```typescript
|
|
// Use type guards
|
|
function isDatabase(obj: any): obj is Database {
|
|
return obj && typeof obj.id === 'number' && typeof obj.name === 'string';
|
|
}
|
|
|
|
// Use generics
|
|
function getValue<T>(key: string, defaultValue: T): T {
|
|
return context.globalState.get(key) ?? defaultValue;
|
|
}
|
|
```
|