Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ const TopNav = ({
const [isFullScreenMode, setIsFullScreenMode] = useState<any>();

const { services } = useOpenSearchDashboards<DashboardServices>();
console.log('TopNav: Services:', services);
console.log('TopNav: Navigation service:', services.navigation);
console.log('TopNav: Navigation UI:', services.navigation?.ui);
console.log('TopNav: enum:', TopNavMenuItemRenderType);
const { TopNavMenu, HeaderControl } = services.navigation.ui;
const { dashboardConfig, setHeaderActionMenu } = services;
const { setAppRightControls } = services.application;
Expand Down Expand Up @@ -151,7 +155,8 @@ const TopNav = ({
defaultMessage: 'New dashboard',
})
}
showSearchBar={showSearchBar && TopNavMenuItemRenderType.IN_PORTAL}
// showSearchBar={showSearchBar && TopNavMenuItemRenderType.IN_PORTAL}
showSearchBar={showSearchBar}
showQueryBar={showQueryBar}
showQueryInput={showQueryInput}
showDatePicker={showDatePicker}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ export interface DashboardContainerOptions {
SavedObjectFinder: React.ComponentType<any>;
ExitFullScreenButton: React.ComponentType<any>;
uiActions: UiActionsStart;
savedObjectsClient: CoreStart['savedObjects']['client'];
http: CoreStart['http'];
}

export type DashboardReactContextValue = OpenSearchDashboardsReactContextValue<
Expand Down Expand Up @@ -244,6 +246,9 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard
logos={this.logos}
container={this}
PanelComponent={this.embeddablePanel}
savedObjectsClient={this.options.savedObjectsClient}
http={this.options.http}
notifications={this.options.notifications}
/>
</OpenSearchDashboardsContextProvider>
</I18nProvider>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,38 @@

import React from 'react';
import { Subscription } from 'rxjs';
import { Logos } from 'opensearch-dashboards/public';
import { PanelState, EmbeddableStart } from '../../../../../embeddable/public';
import {
Logos,
SavedObjectsClientContract,
HttpStart,
NotificationsStart,
} from 'opensearch-dashboards/public';
import { EmbeddableStart } from '../../../../../embeddable/public';
import { DashboardContainer, DashboardReactContextValue } from '../dashboard_container';
import { DashboardGrid } from '../grid';
import { context } from '../../../../../opensearch_dashboards_react/public';
import {
DashboardExtensions,
getDashboardExtensions,
} from '../../../ui/dashboard_extensions/dashboard_extensions';
import { DashboardPanelState } from '../types';

export interface DashboardViewportProps {
container: DashboardContainer;
PanelComponent: EmbeddableStart['EmbeddablePanel'];
renderEmpty?: () => React.ReactNode;
logos: Logos;
savedObjectsClient: SavedObjectsClientContract;
http: HttpStart;
notifications: NotificationsStart;
}

interface State {
isFullScreenMode: boolean;
useMargins: boolean;
title: string;
description?: string;
panels: { [key: string]: PanelState };
panels: { [key: string]: DashboardPanelState };
isEmbeddedExternally?: boolean;
isEmptyState?: boolean;
}
Expand Down Expand Up @@ -88,13 +101,15 @@ export class DashboardViewport extends React.Component<DashboardViewportProps, S
useMargins,
title,
description,
panels,
isEmbeddedExternally,
isEmptyState,
} = this.props.container.getInput();
if (this.mounted) {
this.setState({
isFullScreenMode,
description,
panels,
useMargins,
title,
isEmbeddedExternally,
Expand Down Expand Up @@ -135,7 +150,7 @@ export class DashboardViewport extends React.Component<DashboardViewportProps, S
}

private renderContainerScreen() {
const { container, PanelComponent } = this.props;
const { container, PanelComponent, http, notifications, savedObjectsClient } = this.props;
const {
isEmbeddedExternally,
isFullScreenMode,
Expand All @@ -144,6 +159,15 @@ export class DashboardViewport extends React.Component<DashboardViewportProps, S
description,
useMargins,
} = this.state;

// Dependencies for dashboard extensions
const extensionDependencies = {
http,
notifications,
savedObjectsClient,
panels,
};

return (
<div
data-shared-items-count={Object.values(panels).length}
Expand All @@ -159,6 +183,11 @@ export class DashboardViewport extends React.Component<DashboardViewportProps, S
logos={this.props.logos}
/>
)}
{/* Render dashboard extensions above the grid */}
<DashboardExtensions
configs={getDashboardExtensions()}
dependencies={extensionDependencies}
/>
<DashboardGrid container={container} PanelComponent={PanelComponent} />
</div>
);
Expand Down
9 changes: 9 additions & 0 deletions src/plugins/dashboard/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ export { SavedObjectDashboard } from './saved_dashboards';
export { SavedDashboardPanel } from './types';
export { AttributeService, ATTRIBUTE_SERVICE_KEY } from './attribute_service';

// Re-export dashboard extensions for use by other plugins
export {
DashboardExtensionConfig,
DashboardExtensionDependencies,
DashboardExtensions,
registerDashboardExtension,
getDashboardExtensions,
} from './ui/dashboard_extensions/dashboard_extensions';

export function plugin(initializerContext: PluginInitializerContext) {
return new DashboardPlugin(initializerContext);
}
2 changes: 2 additions & 0 deletions src/plugins/dashboard/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ export class DashboardPlugin
SavedObjectFinder: getSavedObjectFinder(coreStart.savedObjects, coreStart.uiSettings),
ExitFullScreenButton,
uiActions: deps.uiActions,
savedObjectsClient: coreStart.savedObjects.client,
http: coreStart.http,
};
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { EuiErrorBoundary } from '@elastic/eui';
import React, { useMemo } from 'react';
import {
HttpStart,
NotificationsStart,
SavedObjectsClientContract,
} from 'opensearch-dashboards/public';
import { DashboardPanelState } from '../../application/embeddable/types';

// Dependencies provided to dashboard extensions
export interface DashboardExtensionDependencies {
http: HttpStart;
notifications: NotificationsStart;
savedObjectsClient: SavedObjectsClientContract;
panels: { [key: string]: DashboardPanelState };
}

// Configuration for a dashboard extension
export interface DashboardExtensionConfig {
id: string; // Unique identifier for the extension
order: number; // Lower order means higher position in the UI
isEnabled: () => Promise<boolean>; // Determines if the extension should be rendered
getComponent: (dependencies: DashboardExtensionDependencies) => React.ReactElement; // Returns the component to render
}

// Registry to store dashboard extensions
const dashboardExtensions: DashboardExtensionConfig[] = [];

// Public method to register a dashboard extension
export function registerDashboardExtension(config: DashboardExtensionConfig) {
dashboardExtensions.push(config);
}

// Getter to access the registered extensions (used internally by DashboardViewport)
export function getDashboardExtensions(): DashboardExtensionConfig[] {
return dashboardExtensions;
}

interface DashboardExtensionProps {
config: DashboardExtensionConfig;
dependencies: DashboardExtensionDependencies;
}

// Component to render a single dashboard extension
const DashboardExtension: React.FC<DashboardExtensionProps> = (props) => {
const [isEnabled, setIsEnabled] = React.useState(false);

const component = useMemo(() => props.config.getComponent(props.dependencies), [
props.config,
props.dependencies,
]);

React.useEffect(() => {
props.config.isEnabled().then(setIsEnabled);
}, [props.config]);

if (!isEnabled) return null;

return <EuiErrorBoundary>{component}</EuiErrorBoundary>;
};

interface DashboardExtensionsProps {
configs?: DashboardExtensionConfig[];
dependencies: DashboardExtensionDependencies;
}

// Component to render all registered dashboard extensions
export const DashboardExtensions: React.FC<DashboardExtensionsProps> = (props) => {
const configs = useMemo(() => {
if (!props.configs) return [];

const seenIds = new Set();
props.configs.forEach((config) => {
if (seenIds.has(config.id)) {
throw new Error(`Duplicate dashboard extension id '${config.id}' found.`);
}
seenIds.add(config.id);
});

return [...props.configs].sort((a, b) => a.order - b.order);
}, [props.configs]);

return (
<>
{configs.map((config) => (
<DashboardExtension key={config.id} config={config} dependencies={props.dependencies} />
))}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "opensearchDashboards",
"server": true,
"ui": true,
"requiredPlugins": ["navigation", "management", "indexPatternManagement"],
"requiredPlugins": ["navigation", "management", "indexPatternManagement", "dashboard"],
"optionalPlugins": ["dataSource"],
"requiredBundles": ["opensearchDashboardsReact", "dataSource", "opensearchDashboardsUtils"],
"extraPublicDirs": ["public/components/utils"],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { DashboardExtensionDependencies } from 'src/plugins/dashboard/public';

interface TestDashboardExtensionProps {
dependencies: DashboardExtensionDependencies;
}

export const TestDashboardExtension: React.FC<TestDashboardExtensionProps> = ({ dependencies }) => {
// Log the dependencies for debugging
console.log('TestDashboardExtension: Dependencies:', {
hasHttp: !!dependencies.http,
hasNotifications: !!dependencies.notifications,
hasSavedObjectsClient: !!dependencies.savedObjectsClient,
panelCount: Object.keys(dependencies.panels).length,
});

return (
<div style={{ padding: '10px', backgroundColor: '#f0f0f0', border: '1px solid #ddd' }}>
<h3>Test Dashboard Extension</h3>
<p>Hello World from Data Source Management Plugin!</p>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { DashboardExtensionDependencies } from 'src/plugins/dashboard/public';

interface TestDashboardExtensionProps {
dependencies: DashboardExtensionDependencies;
}

export const TestDashboardExtension: React.FC<TestDashboardExtensionProps> = ({ dependencies }) => {
// Log the dependencies for debugging
console.log('TestDashboardExtension: Dependencies:', {
hasHttp: !!dependencies.http,
hasNotifications: !!dependencies.notifications,
hasSavedObjectsClient: !!dependencies.savedObjectsClient,
panelCount: Object.keys(dependencies.panels).length,
});

return (
<div style={{ padding: '10px', backgroundColor: '#f0f0f0', border: '1px solid #ddd' }}>
<h3>Test Dashboard Extension</h3>
<p>Hello World from Data Source Management Plugin!</p>
</div>
);
};
18 changes: 18 additions & 0 deletions src/plugins/data_source_management/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { useObservable } from 'react-use';

import React from 'react';
import { i18n } from '@osd/i18n';
import { DataSourcePluginSetup } from 'src/plugins/data_source/public';
Expand All @@ -15,6 +17,8 @@ import {
MountPoint,
Plugin,
} from '../../../core/public';
import { registerDashboardExtension, DashboardExtensionDependencies } from '../../dashboard/public';
import { TestDashboardExtension } from './components/direct_query_data_sources_components/direct_query_sync/test_dashboard_extension';

import { PLUGIN_NAME } from '../common';
import { createDataSourceSelector } from './components/data_source_selector/create_data_source_selector';
Expand Down Expand Up @@ -110,6 +114,11 @@ export class DataSourceManagementPlugin
private authMethodsRegistry = new AuthenticationMethodRegistry();
private dataSourceSelection = new DataSourceSelectionService();
private featureFlagStatus: boolean = false;

private getTestComponent(dependencies: DashboardExtensionDependencies): React.ReactElement {
return React.createElement(TestDashboardExtension, { dependencies });
}

public setup(
core: CoreSetup<DataSourceManagementPluginStart>,
{ management, indexPatternManagement, dataSource }: DataSourceManagementSetupDependencies
Expand Down Expand Up @@ -211,6 +220,15 @@ export class DataSourceManagementPlugin
// This instance will be got in each data source selector component.
setDataSourceSelection(this.dataSourceSelection);

// Register the test dashboard extension
console.log('DataSourceManagementPlugin: Registering test dashboard extension');
registerDashboardExtension({
id: 'test-dashboard-extension',
order: 1,
isEnabled: async () => Promise.resolve(true), // Always enabled for testing
getComponent: (dependencies) => this.getTestComponent(dependencies),
});

return {
registerAuthenticationMethod,
// Other plugins can get this instance from setupDeps and use to get selected data sources.
Expand Down
Loading