OpenSearch-Dashboards
OpenSearch-Dashboards copied to clipboard
[Proposal] Introduce extension points management module
Terms
- Core plugins: plugins that reside under src/plugins of the OpenSearch Dashboards repo.
- 2nd party plugins: plugins that reside under github.com/opensearch-project.
- External plugins: plugins developed by the community.
Background
OpenSearch Dashboards uses a plugin architecture to manage all its features, which has proven to be powerful and extensible. However, this structure can introduce potential dependency loops or even require Core plugins to depend on 2nd party plugins, creating architectural challenges.
Problem Statement
Currently, OpenSearch Dashboards plugins often need to directly depend on each other to extend functionality, creating tight coupling that leads to:
- Difficulty in maintaining and updating plugins independently
- Challenges in testing plugins in isolation
- Potential circular dependencies
- Reduced flexibility for third-party plugin developers
We have observed several use cases that demonstrate the need for a decoupling mechanism:
Example 1: Copy Button in Saved Objects Management Page
The copy button is a feature introduced by the workspace plugin and should be maintained within that plugin. This would allow the button to be hidden or removed when the workspace plugin is disabled.
Example 2: Alerting/AD Quick Setup in Visualizations
Alerting and Anomaly Detection plugins need to provide setup options within visualizations. This required introducing a new registry in the visualization plugin to support registration of additional options from other plugins.
Example 3: Query Editor Extensions
AI-enhanced components registered from the dashboards-assistant plugin required introducing a new plugin (query_enhancement) specifically to expose extension points.
Additional use cases include adding notebook trigger points in Discover, Alert, and Anomaly Detection plugins.
Proposed Solution
We propose creating an Extension Point Core Module or reuse Content management plugin that will:
- Provide a centralized registry for extension points defined by core modules
- Allow plugins to implement these extension points without direct dependencies
- Support React-based extensions initially, with the architecture allowing for vanilla JavaScript functions in the future
- Enable type-safe extension registration and consumption
Extension Point Registry Module
interface SectionMappings {}
class ExtensionPointRegistry {
getAll<T extends keyof SectionMappings>(sectionId: T): SectionMappings[T][];
registerExtensionPoint(extensionPointId: string): () => void;
registerImplementation<T extends keyof SectionMappings>(sectionId: T, extension: SectionMappings[T]): () => void;
}
Consuming Extensions (Core Module Side)
interface RenderProps {
onCreateVisualization: (visualizationId: string) => void;
}
// Declare module to ensure type safety
declare module 'opensearch-dashboards/public/extension_point' {
interface SectionMappings {
'dashboard:panels'?: Array<(renderProps: RenderProps) => ReactNode>;
}
}
// For plugin setup
setup(core) {
this.unregisterFunc = core.extensionPointRegistry.registerExtensionPoint('dashboard:panels');
}
stop() {
this.unregisterFunc();
}
// For React components
const DashboardPanels = ({ coreStart, onCreateVisualization }) => {
const extensions = coreStart.extensionPointRegistry.getAll('dashboard:panels') || [];
const renderProps = { onCreateVisualization };
return (
<div className="dashboard-panels">
{extensions.map((extension, index) => (
<React.Fragment key={index}>
{extension(renderProps)}
</React.Fragment>
))}
</div>
);
};
Implementing Extensions (Plugin Side)
// In plugin's setup or start method
setup(core) {
this.unregisterFunc = core.extensionPointRegistry.registerImplementation('dashboard:panels', (renderProps) => {
return (
<button
onClick={() => renderProps.onCreateVisualization('my-viz-type')}
className="extension-button"
>
Add to notebook
</button>
);
});
}
// Clean up in plugin's stop method
stop() {
this.unregisterFunc();
}
Advantages Over Existing Solutions
Comparison with UIActions
While UIActions provides an effective event subscription/broadcast mechanism, it cannot handle rendering components or UI elements. The Extension Point Framework specifically addresses this gap by allowing plugins to inject UI components into designated areas.
Comparison with Embeddable Framework
The Embeddable framework focuses on making components embeddable into OSD documents, regardless of the underlying rendering technology. However, it doesn't solve the extension point challenge where plugins need to register components or functions to extend specific areas of the UI.
Comparison with Expressions
The Expressions module is designed for function composition using a pipeline pattern (a | b | c | d). It's optimized for data transformation rather than UI extension. Our proposed framework addresses the specific need for plugins to register UI extensions at predefined points.
Comparison with Content Management framework
The content management framework/plugin enables dynamic placeholders, allowing content management hosted pages to append sections/cards from other plugins. While serving a similar purpose to the extension point framework, it has the following limitations:
- Primarily addresses React component extensions, but doesn't support non-React component function registration
- Lacks type-safe mechanisms for ensuring integration security
- Currently doesn't support dynamic input parameters
Implementation Considerations
-
Performance: The framework should minimize performance impact by lazy-loading extensions when possible.
-
Type Safety: Leveraging TypeScript's declaration merging to ensure type safety when registering and consuming extensions.
-
Lifecycle Management: Extensions should be properly registered and unregistered during plugin lifecycle events.
-
Documentation: Clear documentation of available extension points will be crucial for plugin developers, but they can get extension points from typescript suggestion as well as long as they installed the required plugins.
-
Testing: The framework should facilitate testing of both extension points and extensions.
This Extension Point Framework will significantly improve OpenSearch Dashboards' plugin architecture by reducing tight coupling between plugins while maintaining the flexibility and extensibility that makes the platform powerful.