Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add registrable DiscoverActions to discover page #7793

Closed
2 changes: 2 additions & 0 deletions changelogs/fragments/7793.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Add registrable DiscoverActions to discover page ([#7793](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7793))
1 change: 1 addition & 0 deletions src/plugins/data_explorer/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export {
setIndexPattern,
setDataSet,
} from './utils/state_management';
export { DiscoverAction, DiscoverActionContext } from './types';
8 changes: 7 additions & 1 deletion src/plugins/data_explorer/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
DataExplorerPluginStart,
DataExplorerPluginStartDependencies,
DataExplorerServices,
DiscoverAction,
} from './types';
import { PLUGIN_ID, PLUGIN_NAME } from '../common';
import { ViewService } from './services/view_service';
Expand All @@ -43,6 +44,7 @@ export class DataExplorerPlugin
private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
private stopUrlTracking?: () => void;
private currentHistory?: ScopedHistory;
private discoverActions: DiscoverAction[] = [];

public setup(
core: CoreSetup<DataExplorerPluginStartDependencies, DataExplorerPluginStart>,
Expand Down Expand Up @@ -105,6 +107,7 @@ export class DataExplorerPlugin
...withNotifyOnErrors(coreStart.notifications.toasts),
}),
viewRegistry: viewService.start(),
actions: this.discoverActions,
};

// Get start services as specified in opensearch_dashboards.json
Expand All @@ -124,7 +127,10 @@ export class DataExplorerPlugin
});

return {
...this.viewService.setup(),
registerView: this.viewService.setup().registerView,
registerDiscoverAction: (discoverAction: DiscoverAction) => {
this.discoverActions.push(discoverAction);
},
};
}

Expand Down
18 changes: 16 additions & 2 deletions src/plugins/data_explorer/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import { EmbeddableStart } from '../../embeddable/public';
import { ExpressionsStart } from '../../expressions/public';
import { ViewServiceStart, ViewServiceSetup } from './services/view_service';
import { IOsdUrlStateStorage } from '../../opensearch_dashboards_utils/public';
import { DataPublicPluginSetup, DataPublicPluginStart } from '../../data/public';
import { DataPublicPluginSetup, DataPublicPluginStart, IndexPattern } from '../../data/public';
import { Store } from './utils/state_management';

export type DataExplorerPluginSetup = ViewServiceSetup;
export type DataExplorerPluginSetup = ViewServiceSetup & {
registerDiscoverAction: (discoverAction: DiscoverAction) => void;
};

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DataExplorerPluginStart {}
Expand All @@ -34,4 +36,16 @@ export interface DataExplorerServices extends CoreStart {
data: DataPublicPluginStart;
scopedHistory: ScopedHistory;
osdUrlStateStorage: IOsdUrlStateStorage;
actions?: DiscoverAction[];
}

export interface DiscoverActionContext {
indexPattern: IndexPattern | undefined;
}

export interface DiscoverAction {
order: number;
name: string;
iconType: string;
onClick: (context: DiscoverActionContext) => void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { DiscoverActions } from './discover_actions';
import {
DiscoverAction,
DiscoverActionContext,
} from '../../../../../../plugins/data_explorer/public';

jest.mock('@elastic/eui', () => ({
EuiButtonEmpty: jest.requireActual('@elastic/eui').EuiButtonEmpty,
}));

const mockActions: DiscoverAction[] = [
{ order: 2, iconType: 'icon1', name: 'Action 2', onClick: jest.fn() },
{ order: 1, iconType: 'icon2', name: 'Action 1', onClick: jest.fn() },
{ order: 3, iconType: 'icon3', name: 'Action 3', onClick: jest.fn() },
];

const mockContext: DiscoverActionContext = {
indexPattern: undefined,
};

describe('DiscoverActions Component', () => {
it('renders all actions in the correct order', () => {
render(<DiscoverActions actions={mockActions} context={mockContext} />);

const buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveTextContent('Action 1');
expect(buttons[1]).toHaveTextContent('Action 2');
expect(buttons[2]).toHaveTextContent('Action 3');
});

it('calls the action onClick function with the correct context', () => {
render(<DiscoverActions actions={mockActions} context={mockContext} />);

const buttons = screen.getAllByRole('button');
fireEvent.click(buttons[0]);
expect(mockActions[0].onClick).toHaveBeenCalledWith(mockContext);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { EuiButtonEmpty } from '@elastic/eui';
import {
DiscoverAction,
DiscoverActionContext,
} from '../../../../../../plugins/data_explorer/public';

interface DiscoverActionsProps {
actions: DiscoverAction[];
context: DiscoverActionContext;
}

const DiscoverActions: React.FC<DiscoverActionsProps> = ({ actions, context }) => {
actions.sort((a, b) => {
return a.order - b.order;
});

return (
<div className="dscCanvas_actions">
{actions.map((action) => (
<EuiButtonEmpty
key={action.order}
size="s"
iconType={action.iconType}
onClick={() => {
action.onClick(context);
}}
>
{action.name}
</EuiButtonEmpty>
))}
</div>
);
};

export { DiscoverActions };
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
position: relative;
}

&_actions {
position: absolute;
top: 0;
right: 30px;
gaobinlong marked this conversation as resolved.
Show resolved Hide resolved
}

&_options {
position: absolute;
top: 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import {
EuiCompressedSwitch,
} from '@elastic/eui';
import { TopNav } from './top_nav';
import { ViewProps } from '../../../../../data_explorer/public';
import {
DataExplorerServices,
DiscoverAction,
ViewProps,
} from '../../../../../data_explorer/public';
import { DiscoverTable } from './discover_table';
import { DiscoverChartContainer } from './discover_chart_container';
import { useDiscoverContext } from '../context';
Expand All @@ -35,6 +39,7 @@ import { buildColumns } from '../../utils/columns';
import './discover_canvas.scss';
import { getNewDiscoverSetting, setNewDiscoverSetting } from '../../components/utils/local_storage';
import { HeaderVariant } from '../../../../../../core/public';
import { DiscoverActions } from './discover_actions';

// eslint-disable-next-line import/no-default-export
export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalRef }: ViewProps) {
Expand All @@ -47,6 +52,10 @@ export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalR
chrome: { setHeaderVariant },
},
} = useOpenSearchDashboards<DiscoverViewServices>();
const {
services: { actions },
} = useOpenSearchDashboards<DataExplorerServices>();

const { columns } = useSelector((state) => {
const stateColumns = state.discover.columns;

Expand Down Expand Up @@ -166,6 +175,7 @@ export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalR
<EuiPanel hasShadow={false} paddingSize="none" className="dscCanvas_results">
<MemoizedDiscoverChartContainer {...fetchState} />
<MemoizedDiscoverTable rows={rows} scrollToTop={scrollToTop} />
<DiscoverActions actions={actions as DiscoverAction[]} context={{ indexPattern }} />
</EuiPanel>
)}
</EuiPanel>
Expand Down
Loading