feat: implement plugin architecture and application settings with Svelte UI
- Added plugin base and loader for backend extensibility - Implemented application settings management with config persistence - Created Svelte-based frontend with Dashboard and Settings pages - Added API routes for plugins, tasks, and settings - Updated documentation and specifications - Improved project structure and developer tools
This commit is contained in:
172
docs/plugin_dev.md
Normal file → Executable file
172
docs/plugin_dev.md
Normal file → Executable file
@@ -1,87 +1,87 @@
|
||||
# Plugin Development Guide
|
||||
|
||||
This guide explains how to create new plugins for the Superset Tools application.
|
||||
|
||||
## 1. Plugin Structure
|
||||
|
||||
A plugin is a single Python file located in the `backend/src/plugins/` directory. Each plugin file must contain a class that inherits from `PluginBase`.
|
||||
|
||||
## 2. Implementing `PluginBase`
|
||||
|
||||
The `PluginBase` class is an abstract base class that defines the interface for all plugins. You must implement the following properties and methods:
|
||||
|
||||
- **`id`**: A unique string identifier for your plugin (e.g., `"my-cool-plugin"`).
|
||||
- **`name`**: A human-readable name for your plugin (e.g., `"My Cool Plugin"`).
|
||||
- **`description`**: A brief description of what your plugin does.
|
||||
- **`version`**: The version of your plugin (e.g., `"1.0.0"`).
|
||||
- **`get_schema()`**: A method that returns a JSON schema dictionary defining the input parameters for your plugin. This schema is used to automatically generate a form in the frontend.
|
||||
- **`execute(params: Dict[str, Any])`**: An `async` method that contains the main logic of your plugin. The `params` argument is a dictionary containing the input data from the user, validated against the schema you defined.
|
||||
|
||||
## 3. Example Plugin
|
||||
|
||||
Here is an example of a simple "Hello World" plugin:
|
||||
|
||||
```python
|
||||
# backend/src/plugins/hello.py
|
||||
# [DEF:HelloWorldPlugin:Plugin]
|
||||
# @SEMANTICS: hello, world, example, plugin
|
||||
# @PURPOSE: A simple "Hello World" plugin example.
|
||||
# @LAYER: Domain (Plugin)
|
||||
# @RELATION: Inherits from PluginBase
|
||||
# @PUBLIC_API: execute
|
||||
|
||||
from typing import Dict, Any
|
||||
from ..core.plugin_base import PluginBase
|
||||
|
||||
class HelloWorldPlugin(PluginBase):
|
||||
@property
|
||||
def id(self) -> str:
|
||||
return "hello-world"
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "Hello World"
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return "A simple plugin that prints a greeting."
|
||||
|
||||
@property
|
||||
def version(self) -> str:
|
||||
return "1.0.0"
|
||||
|
||||
def get_schema(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name",
|
||||
"description": "The name to greet.",
|
||||
"default": "World",
|
||||
}
|
||||
},
|
||||
"required": ["name"],
|
||||
}
|
||||
|
||||
async def execute(self, params: Dict[str, Any]):
|
||||
name = params["name"]
|
||||
print(f"Hello, {name}!")
|
||||
```
|
||||
|
||||
## 4. Logging
|
||||
|
||||
You can use the global logger instance to log messages from your plugin. The logger is available in the `superset_tool.utils.logger` module.
|
||||
|
||||
```python
|
||||
from superset_tool.utils.logger import SupersetLogger
|
||||
|
||||
logger = SupersetLogger()
|
||||
|
||||
async def execute(self, params: Dict[str, Any]):
|
||||
logger.info("My plugin is running!")
|
||||
```
|
||||
|
||||
## 5. Testing
|
||||
|
||||
# Plugin Development Guide
|
||||
|
||||
This guide explains how to create new plugins for the Superset Tools application.
|
||||
|
||||
## 1. Plugin Structure
|
||||
|
||||
A plugin is a single Python file located in the `backend/src/plugins/` directory. Each plugin file must contain a class that inherits from `PluginBase`.
|
||||
|
||||
## 2. Implementing `PluginBase`
|
||||
|
||||
The `PluginBase` class is an abstract base class that defines the interface for all plugins. You must implement the following properties and methods:
|
||||
|
||||
- **`id`**: A unique string identifier for your plugin (e.g., `"my-cool-plugin"`).
|
||||
- **`name`**: A human-readable name for your plugin (e.g., `"My Cool Plugin"`).
|
||||
- **`description`**: A brief description of what your plugin does.
|
||||
- **`version`**: The version of your plugin (e.g., `"1.0.0"`).
|
||||
- **`get_schema()`**: A method that returns a JSON schema dictionary defining the input parameters for your plugin. This schema is used to automatically generate a form in the frontend.
|
||||
- **`execute(params: Dict[str, Any])`**: An `async` method that contains the main logic of your plugin. The `params` argument is a dictionary containing the input data from the user, validated against the schema you defined.
|
||||
|
||||
## 3. Example Plugin
|
||||
|
||||
Here is an example of a simple "Hello World" plugin:
|
||||
|
||||
```python
|
||||
# backend/src/plugins/hello.py
|
||||
# [DEF:HelloWorldPlugin:Plugin]
|
||||
# @SEMANTICS: hello, world, example, plugin
|
||||
# @PURPOSE: A simple "Hello World" plugin example.
|
||||
# @LAYER: Domain (Plugin)
|
||||
# @RELATION: Inherits from PluginBase
|
||||
# @PUBLIC_API: execute
|
||||
|
||||
from typing import Dict, Any
|
||||
from ..core.plugin_base import PluginBase
|
||||
|
||||
class HelloWorldPlugin(PluginBase):
|
||||
@property
|
||||
def id(self) -> str:
|
||||
return "hello-world"
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "Hello World"
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return "A simple plugin that prints a greeting."
|
||||
|
||||
@property
|
||||
def version(self) -> str:
|
||||
return "1.0.0"
|
||||
|
||||
def get_schema(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name",
|
||||
"description": "The name to greet.",
|
||||
"default": "World",
|
||||
}
|
||||
},
|
||||
"required": ["name"],
|
||||
}
|
||||
|
||||
async def execute(self, params: Dict[str, Any]):
|
||||
name = params["name"]
|
||||
print(f"Hello, {name}!")
|
||||
```
|
||||
|
||||
## 4. Logging
|
||||
|
||||
You can use the global logger instance to log messages from your plugin. The logger is available in the `superset_tool.utils.logger` module.
|
||||
|
||||
```python
|
||||
from superset_tool.utils.logger import SupersetLogger
|
||||
|
||||
logger = SupersetLogger()
|
||||
|
||||
async def execute(self, params: Dict[str, Any]):
|
||||
logger.info("My plugin is running!")
|
||||
```
|
||||
|
||||
## 5. Testing
|
||||
|
||||
To test your plugin, simply run the application and navigate to the web UI. Your plugin should appear in the list of available tools.
|
||||
46
docs/settings.md
Normal file
46
docs/settings.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Web Application Settings Mechanism
|
||||
|
||||
This document describes the settings management system for the Superset Tools application.
|
||||
|
||||
## Overview
|
||||
|
||||
The settings mechanism allows users to configure multiple Superset environments and global application settings (like backup storage) via the web UI.
|
||||
|
||||
## Backend Architecture
|
||||
|
||||
### Data Models
|
||||
|
||||
Configuration is structured using Pydantic models in `backend/src/core/config_models.py`:
|
||||
|
||||
- `Environment`: Represents a Superset instance (URL, credentials).
|
||||
- `GlobalSettings`: Global application parameters (e.g., `backup_path`).
|
||||
- `AppConfig`: The root configuration object.
|
||||
|
||||
### Configuration Manager
|
||||
|
||||
The `ConfigManager` (`backend/src/core/config_manager.py`) handles:
|
||||
- Persistence to `config.json`.
|
||||
- CRUD operations for environments.
|
||||
- Validation and logging.
|
||||
|
||||
### API Endpoints
|
||||
|
||||
The settings API is available at `/settings`:
|
||||
|
||||
- `GET /settings`: Retrieve all settings (passwords are masked).
|
||||
- `PATCH /settings/global`: Update global settings.
|
||||
- `GET /settings/environments`: List environments.
|
||||
- `POST /settings/environments`: Add environment.
|
||||
- `PUT /settings/environments/{id}`: Update environment.
|
||||
- `DELETE /settings/environments/{id}`: Remove environment.
|
||||
- `POST /settings/environments/{id}/test`: Test connection.
|
||||
|
||||
## Frontend Implementation
|
||||
|
||||
The settings page is located at `frontend/src/pages/Settings.svelte`. It provides forms for managing global settings and Superset environments.
|
||||
|
||||
## Integration
|
||||
|
||||
Existing plugins and utilities use the `ConfigManager` to fetch configuration:
|
||||
- `superset_tool/utils/init_clients.py`: Dynamically initializes Superset clients from the configured environments.
|
||||
- `BackupPlugin`: Uses the configured `backup_path` as the default storage location.
|
||||
Reference in New Issue
Block a user