Plugin extensions: Make sure core features use new hooks (#92723)

* use new extensions APIs across grafana core

* setup setPluginLinksHook

* fix tests

* fix mock

* fix more broken tests

* use plugin components hook

* remove unused func

* fix tests

* remove unused import
This commit is contained in:
Erik Sundell 2024-09-13 09:23:18 +02:00 committed by GitHub
parent 01a4e6b9af
commit 8c702d4a6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 115 additions and 111 deletions

View File

@ -16,7 +16,7 @@ import { AppChrome } from './AppChrome';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
const searchData: DataFrame = {

View File

@ -3,7 +3,7 @@ import { byTestId, byText } from 'testing-library-selector';
import { DataSourceApi } from '@grafana/data';
import { PromOptions, PrometheusDatasource } from '@grafana/prometheus';
import { setDataSourceSrv, setPluginExtensionsHook } from '@grafana/runtime';
import { setDataSourceSrv, setPluginLinksHook } from '@grafana/runtime';
import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
@ -191,8 +191,8 @@ describe('PanelAlertTabContent', () => {
AccessControlAction.AlertingRuleExternalWrite,
]);
setPluginExtensionsHook(() => ({
extensions: [],
setPluginLinksHook(() => ({
links: [],
isLoading: false,
}));

View File

@ -13,7 +13,7 @@ import {
locationService,
setAppEvents,
setDataSourceSrv,
usePluginLinkExtensions,
usePluginLinks,
} from '@grafana/runtime';
import appEvents from 'app/core/app_events';
import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons';
@ -52,7 +52,7 @@ import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
getPluginLinkExtensions: jest.fn(),
usePluginLinkExtensions: jest.fn(),
usePluginLinks: jest.fn(),
useReturnToPrevious: jest.fn(),
}));
jest.mock('./api/buildInfo');
@ -72,7 +72,7 @@ setupPluginsExtensionsHook();
const mocks = {
getAllDataSourcesMock: jest.mocked(config.getAllDataSources),
getPluginLinkExtensionsMock: jest.mocked(getPluginLinkExtensions),
usePluginLinkExtensionsMock: jest.mocked(usePluginLinkExtensions),
usePluginLinksMock: jest.mocked(usePluginLinks),
rulesInSameGroupHaveInvalidForMock: jest.mocked(actions.rulesInSameGroupHaveInvalidFor),
api: {
@ -168,8 +168,8 @@ describe('RuleList', () => {
AccessControlAction.AlertingRuleExternalWrite,
]);
mocks.rulesInSameGroupHaveInvalidForMock.mockReturnValue([]);
mocks.usePluginLinkExtensionsMock.mockReturnValue({
extensions: [
mocks.usePluginLinksMock.mockReturnValue({
links: [
{
pluginId: 'grafana-ml-app',
id: '1',

View File

@ -1,7 +1,7 @@
import { ReactElement, useMemo, useState } from 'react';
import { PluginExtensionLink, PluginExtensionPoints } from '@grafana/data';
import { usePluginLinkExtensions } from '@grafana/runtime';
import { usePluginLinks } from '@grafana/runtime';
import { Dropdown, IconButton } from '@grafana/ui';
import { ConfirmNavigationModal } from 'app/features/explore/extensions/ConfirmNavigationModal';
import { Alert, CombinedRule } from 'app/types/unified-alerting';
@ -21,13 +21,13 @@ export const AlertInstanceExtensionPoint = ({
}: AlertInstanceExtensionPointProps): ReactElement | null => {
const [selectedExtension, setSelectedExtension] = useState<PluginExtensionLink | undefined>();
const context = useMemo(() => ({ instance, rule }), [instance, rule]);
const { extensions } = usePluginLinkExtensions({ context, extensionPointId, limitPerPlugin: 3 });
const { links } = usePluginLinks({ context, extensionPointId, limitPerPlugin: 3 });
if (extensions.length === 0) {
if (links.length === 0) {
return null;
}
const menu = <AlertExtensionPointMenu extensions={extensions} onSelect={setSelectedExtension} />;
const menu = <AlertExtensionPointMenu extensions={links} onSelect={setSelectedExtension} />;
return (
<>
<Dropdown placement="bottom-start" overlay={menu}>

View File

@ -2,7 +2,7 @@ import { within } from '@testing-library/react';
import { render, waitFor, screen, userEvent } from 'test/test-utils';
import { byText, byRole } from 'testing-library-selector';
import { setPluginExtensionsHook } from '@grafana/runtime';
import { setPluginLinksHook } from '@grafana/runtime';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
import { setFolderAccessControl } from 'app/features/alerting/unified/mocks/server/configure';
import { AlertManagerDataSourceJsonData } from 'app/plugins/datasource/alertmanager/types';
@ -66,8 +66,8 @@ const ELEMENTS = {
setupMswServer();
setupDataSources(mockDataSource({ type: DataSourceType.Prometheus, name: 'mimir-1' }));
setPluginExtensionsHook(() => ({
extensions: [
setPluginLinksHook(() => ({
links: [
mockPluginLinkExtension({ pluginId: 'grafana-slo-app', title: 'SLO dashboard', path: '/a/grafana-slo-app' }),
mockPluginLinkExtension({
pluginId: 'grafana-asserts-app',

View File

@ -404,8 +404,8 @@ const helpStyles = (theme: GrafanaTheme2) => ({
});
function usePluginsFilterStatus() {
const { extensions } = useAlertingHomePageExtensions();
return { pluginsFilterEnabled: extensions.length > 0 };
const { components } = useAlertingHomePageExtensions();
return { pluginsFilterEnabled: components.length > 0 };
}
export default RulesFilter;

View File

@ -2,7 +2,7 @@ import { produce } from 'immer';
import { render, screen, userEvent } from 'test/test-utils';
import { byLabelText, byRole } from 'testing-library-selector';
import { config, setPluginExtensionsHook } from '@grafana/runtime';
import { config, setPluginLinksHook } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
import { RuleActionsButtons } from 'app/features/alerting/unified/components/rules/RuleActionsButtons';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
@ -53,8 +53,8 @@ const getMenuContents = async () => {
return [...allMenuItems, ...allLinkItems];
};
setPluginExtensionsHook(() => ({
extensions: [],
setPluginLinksHook(() => ({
links: [],
isLoading: false,
}));

View File

@ -2,7 +2,7 @@ import { render } from 'test/test-utils';
import { byRole } from 'testing-library-selector';
import { PluginExtensionTypes } from '@grafana/data';
import { usePluginLinkExtensions } from '@grafana/runtime';
import { usePluginLinks } from '@grafana/runtime';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
import { useIsRuleEditable } from '../../hooks/useIsRuleEditable';
@ -12,14 +12,14 @@ import { RuleDetails } from './RuleDetails';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
usePluginLinkExtensions: jest.fn(),
usePluginLinks: jest.fn(),
useReturnToPrevious: jest.fn(),
}));
jest.mock('../../hooks/useIsRuleEditable');
const mocks = {
usePluginLinkExtensionsMock: jest.mocked(usePluginLinkExtensions),
usePluginLinksMock: jest.mocked(usePluginLinks),
useIsRuleEditable: jest.mocked(useIsRuleEditable),
};
@ -37,8 +37,8 @@ beforeAll(() => {
});
beforeEach(() => {
mocks.usePluginLinkExtensionsMock.mockReturnValue({
extensions: [
mocks.usePluginLinksMock.mockReturnValue({
links: [
{
pluginId: 'grafana-ml-app',
id: '1',

View File

@ -4,7 +4,7 @@ import { times } from 'lodash';
import { byLabelText, byRole, byTestId } from 'testing-library-selector';
import { PluginExtensionTypes } from '@grafana/data';
import { usePluginLinkExtensions } from '@grafana/runtime';
import { usePluginLinks } from '@grafana/runtime';
import { CombinedRuleNamespace } from '../../../../../types/unified-alerting';
import { GrafanaAlertState, PromAlertingRuleState } from '../../../../../types/unified-alerting-dto';
@ -16,11 +16,11 @@ import { RuleDetailsMatchingInstances } from './RuleDetailsMatchingInstances';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
getPluginLinkExtensions: jest.fn(),
usePluginLinkExtensions: jest.fn(),
usePluginLinks: jest.fn(),
}));
const mocks = {
usePluginLinkExtensionsMock: jest.mocked(usePluginLinkExtensions),
usePluginLinksMock: jest.mocked(usePluginLinks),
};
const ui = {
@ -43,8 +43,8 @@ const ui = {
describe('RuleDetailsMatchingInstances', () => {
beforeEach(() => {
mocks.usePluginLinkExtensionsMock.mockReturnValue({
extensions: [
mocks.usePluginLinksMock.mockReturnValue({
links: [
{
pluginId: 'grafana-ml-app',
id: '1',

View File

@ -2,7 +2,7 @@ import { waitFor } from '@testing-library/react';
import { render } from 'test/test-utils';
import { byRole } from 'testing-library-selector';
import { setPluginExtensionsHook } from '@grafana/runtime';
import { setPluginLinksHook } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
import { AccessControlAction } from 'app/types';
import { CombinedRuleNamespace } from 'app/types/unified-alerting';
@ -20,8 +20,8 @@ const ui = {
cloudRulesHeading: byRole('heading', { name: 'Data source-managed' }),
};
setPluginExtensionsHook(() => ({
extensions: [],
setPluginLinksHook(() => ({
links: [],
isLoading: false,
}));

View File

@ -1,6 +1,6 @@
import { render, screen } from 'test/test-utils';
import { setPluginExtensionsHook } from '@grafana/runtime';
import { setPluginLinksHook } from '@grafana/runtime';
import { RuleListStateView } from 'app/features/alerting/unified/components/rules/RuleListStateView';
import {
mockCombinedRule,
@ -10,8 +10,8 @@ import {
} from 'app/features/alerting/unified/mocks';
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
setPluginExtensionsHook(() => ({
extensions: [],
setPluginLinksHook(() => ({
links: [],
isLoading: false,
}));

View File

@ -1,7 +1,7 @@
import { render, userEvent, screen } from 'test/test-utils';
import { byRole } from 'testing-library-selector';
import { setPluginExtensionsHook } from '@grafana/runtime';
import { setPluginLinksHook } from '@grafana/runtime';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
import { AlertRuleAction, useAlertRuleAbility } from '../../hooks/useAbilities';
@ -15,8 +15,8 @@ const mocks = {
useAlertRuleAbility: jest.mocked(useAlertRuleAbility),
};
setPluginExtensionsHook(() => ({
extensions: [],
setPluginLinksHook(() => ({
links: [],
isLoading: false,
}));

View File

@ -9,9 +9,9 @@ import { useAlertingHomePageExtensions } from '../plugins/useAlertingHomePageExt
export function PluginIntegrations() {
const styles = useStyles2(getStyles);
const { extensions } = useAlertingHomePageExtensions();
const { components } = useAlertingHomePageExtensions();
if (extensions.length === 0) {
if (components.length === 0) {
return null;
}
@ -21,9 +21,9 @@ export function PluginIntegrations() {
Speed up your alerts creation now by using one of our tailored apps
</Text>
<Stack gap={2} wrap="wrap" direction="row">
{extensions.map((extension) => (
<div key={extension.id} className={styles.box}>
<extension.component />
{components.map((Component, i) => (
<div key={i} className={styles.box}>
<Component />
</div>
))}
</Stack>

View File

@ -1,8 +1,8 @@
import { PluginExtensionPoints } from '@grafana/data';
import { usePluginComponentExtensions } from '@grafana/runtime';
import { usePluginComponents } from '@grafana/runtime';
export function useAlertingHomePageExtensions() {
return usePluginComponentExtensions({
return usePluginComponents({
extensionPointId: PluginExtensionPoints.AlertingHomePage,
limitPerPlugin: 1,
});

View File

@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { PluginExtensionPoints } from '@grafana/data';
import { usePluginLinkExtensions } from '@grafana/runtime';
import { usePluginLinks } from '@grafana/runtime';
import { CombinedRule } from 'app/types/unified-alerting';
import { PromRuleType } from 'app/types/unified-alerting-dto';
@ -23,7 +23,7 @@ export interface RecordingRuleExtensionContext extends BaseRuleExtensionContext
export function useRulePluginLinkExtension(rule: CombinedRule) {
const ruleExtensionPoint = useRuleExtensionPoint(rule);
const { extensions } = usePluginLinkExtensions(ruleExtensionPoint);
const { links } = usePluginLinks(ruleExtensionPoint);
const ruleOrigin = getRulePluginOrigin(rule);
const ruleType = rule.promRule?.type;
@ -33,7 +33,7 @@ export function useRulePluginLinkExtension(rule: CombinedRule) {
const { pluginId } = ruleOrigin;
return extensions.filter((extension) => extension.pluginId === pluginId);
return links.filter((link) => link.pluginId === pluginId);
}
export interface PluginRuleExtensionParam {

View File

@ -1,5 +1,5 @@
import { PluginMeta, PluginType } from '@grafana/data';
import { setPluginExtensionsHook } from '@grafana/runtime';
import { setPluginComponentsHook, setPluginExtensionsHook } from '@grafana/runtime';
import { SupportedPlugin } from 'app/features/alerting/unified/types/pluginBridges';
import { mockPluginLinkExtension } from '../mocks';
@ -15,6 +15,10 @@ export function setupPluginsExtensionsHook() {
),
isLoading: false,
}));
setPluginComponentsHook(() => ({
components: [],
isLoading: false,
}));
}
export const plugins: PluginMeta[] = [

View File

@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { PluginExtensionCommandPaletteContext, PluginExtensionPoints } from '@grafana/data';
import { usePluginLinkExtensions } from '@grafana/runtime';
import { usePluginLinks } from '@grafana/runtime';
import { CommandPaletteAction } from '../types';
import { EXTENSIONS_PRIORITY } from '../values';
@ -10,20 +10,20 @@ import { EXTENSIONS_PRIORITY } from '../values';
const context: PluginExtensionCommandPaletteContext = {};
export default function useExtensionActions(): CommandPaletteAction[] {
const { extensions } = usePluginLinkExtensions({
const { links } = usePluginLinks({
extensionPointId: PluginExtensionPoints.CommandPalette,
context,
limitPerPlugin: 3,
});
return useMemo(() => {
return extensions.map((extension) => ({
section: extension.category ?? 'Extensions',
return links.map((link) => ({
section: link.category ?? 'Extensions',
priority: EXTENSIONS_PRIORITY,
id: extension.id,
name: extension.title,
target: extension.path,
perform: () => extension.onClick && extension.onClick(),
id: link.id,
name: link.title,
target: link.path,
perform: () => link.onClick && link.onClick(),
}));
}, [extensions]);
}, [links]);
}

View File

@ -5,7 +5,7 @@ import { byTestId } from 'testing-library-selector';
import { DataSourceApi } from '@grafana/data';
import { PromOptions, PrometheusDatasource } from '@grafana/prometheus';
import { locationService, setDataSourceSrv, setPluginExtensionsHook } from '@grafana/runtime';
import { locationService, setDataSourceSrv, setPluginLinksHook } from '@grafana/runtime';
import { backendSrv } from 'app/core/services/backend_srv';
import * as ruler from 'app/features/alerting/unified/api/ruler';
import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons';
@ -50,8 +50,8 @@ jest.spyOn(ruleActionButtons, 'matchesWidth').mockReturnValue(false);
jest.spyOn(ruler, 'rulerUrlBuilder');
jest.spyOn(alertingAbilities, 'useAlertRuleAbility');
setPluginExtensionsHook(() => ({
extensions: [],
setPluginLinksHook(() => ({
links: [],
isLoading: false,
}));

View File

@ -63,7 +63,7 @@ jest.mock('app/core/core', () => ({
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
getPluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
function getTestDashboard(overrides?: Partial<Dashboard>, metaOverrides?: Partial<DashboardMeta>): DashboardModel {

View File

@ -7,7 +7,7 @@ import {
PluginExtensionPoints,
getTimeZone,
} from '@grafana/data';
import { usePluginLinkExtensions } from '@grafana/runtime';
import { usePluginLinks } from '@grafana/runtime';
import { getPanelStateForModel } from 'app/features/panel/state/selectors';
import { useSelector } from 'app/types';
@ -29,15 +29,15 @@ export function PanelHeaderMenuProvider({ panel, dashboard, loadingState, childr
const [items, setItems] = useState<PanelMenuItem[]>([]);
const angularComponent = useSelector((state) => getPanelStateForModel(state, panel)?.angularComponent);
const context = useMemo(() => createExtensionContext(panel, dashboard), [panel, dashboard]);
const { extensions } = usePluginLinkExtensions({
const { links } = usePluginLinks({
extensionPointId: PluginExtensionPoints.DashboardPanelMenu,
context,
limitPerPlugin: 3,
});
useEffect(() => {
setItems(getPanelMenu(dashboard, panel, extensions, angularComponent));
}, [dashboard, panel, angularComponent, loadingState, setItems, extensions]);
setItems(getPanelMenu(dashboard, panel, links, angularComponent));
}, [dashboard, panel, angularComponent, loadingState, setItems, links]);
return children({ items });
}

View File

@ -1,7 +1,7 @@
import { Store } from 'redux';
import { PanelMenuItem, PluginExtensionLink, PluginExtensionTypes } from '@grafana/data';
import { AngularComponent, usePluginLinkExtensions } from '@grafana/runtime';
import { AngularComponent, usePluginLinks } from '@grafana/runtime';
import config from 'app/core/config';
import { grantUserPermissions } from 'app/features/alerting/unified/mocks';
import * as actions from 'app/features/explore/state/main';
@ -22,16 +22,16 @@ jest.mock('app/core/services/context_srv', () => ({
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
setPluginExtensionsHook: jest.fn(),
usePluginLinkExtensions: jest.fn(),
setPluginLinksHook: jest.fn(),
usePluginLinks: jest.fn(),
}));
const usePluginLinkExtensionsMock = jest.mocked(usePluginLinkExtensions);
const usePluginLinksMock = jest.mocked(usePluginLinks);
describe('getPanelMenu()', () => {
beforeEach(() => {
usePluginLinkExtensionsMock.mockRestore();
usePluginLinkExtensionsMock.mockReturnValue({ extensions: [], isLoading: false });
usePluginLinksMock.mockRestore();
usePluginLinksMock.mockReturnValue({ links: [], isLoading: false });
grantUserPermissions([AccessControlAction.AlertingRuleRead, AccessControlAction.AlertingRuleUpdate]);
config.unifiedAlertingEnabled = false;
});

View File

@ -12,7 +12,7 @@ import {
store,
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { usePluginLinkExtensions } from '@grafana/runtime';
import { usePluginLinks } from '@grafana/runtime';
import { configureStore } from 'app/store/configureStore';
import { ContentOutlineContextProvider } from './ContentOutline/ContentOutlineContext';
@ -124,7 +124,7 @@ jest.mock('app/core/core', () => ({
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
usePluginLinkExtensions: jest.fn(() => ({ extensions: [] })),
usePluginLinks: jest.fn(() => ({ links: [] })),
}));
// for the AutoSizer component to have a width
@ -138,7 +138,7 @@ jest.mock('react-virtualized-auto-sizer', () => {
});
});
const usePluginLinkExtensionsMock = jest.mocked(usePluginLinkExtensions);
const usePluginLinksMock = jest.mocked(usePluginLinks);
const setup = (overrideProps?: Partial<Props>) => {
const store = configureStore({
@ -180,8 +180,8 @@ describe('Explore', () => {
});
it('should render toolbar extension point if extensions is available', async () => {
usePluginLinkExtensionsMock.mockReturnValueOnce({
extensions: [
usePluginLinksMock.mockReturnValueOnce({
links: [
{
id: '1',
pluginId: 'grafana',

View File

@ -4,7 +4,7 @@ import { ReactNode } from 'react';
import { Provider } from 'react-redux';
import { PluginExtensionPoints, PluginExtensionTypes } from '@grafana/data';
import { usePluginLinkExtensions } from '@grafana/runtime';
import { usePluginLinks } from '@grafana/runtime';
import { DataQuery } from '@grafana/schema';
import { contextSrv } from 'app/core/services/context_srv';
import { configureStore } from 'app/store/configureStore';
@ -16,13 +16,13 @@ import { ToolbarExtensionPoint } from './ToolbarExtensionPoint';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
usePluginLinkExtensions: jest.fn(),
usePluginLinks: jest.fn(),
}));
jest.mock('app/core/services/context_srv');
const contextSrvMock = jest.mocked(contextSrv);
const usePluginLinkExtensionsMock = jest.mocked(usePluginLinkExtensions);
const usePluginLinksMock = jest.mocked(usePluginLinks);
type storeOptions = {
targets: DataQuery[];
@ -54,8 +54,8 @@ function renderWithExploreStore(
describe('ToolbarExtensionPoint', () => {
describe('with extension points', () => {
beforeAll(() => {
usePluginLinkExtensionsMock.mockReturnValue({
extensions: [
usePluginLinksMock.mockReturnValue({
links: [
{
pluginId: 'grafana',
id: '1',
@ -100,10 +100,10 @@ describe('ToolbarExtensionPoint', () => {
await userEvent.click(screen.getByRole('button', { name: 'Add' }));
await userEvent.click(screen.getByRole('menuitem', { name: 'Add to dashboard' }));
const { extensions } = usePluginLinkExtensionsMock({
const { links } = usePluginLinksMock({
extensionPointId: PluginExtensionPoints.ExploreToolbarAction,
});
const [extension] = extensions;
const [extension] = links;
expect(jest.mocked(extension.onClick)).toBeCalledTimes(1);
});
@ -128,7 +128,7 @@ describe('ToolbarExtensionPoint', () => {
data,
});
const [options] = usePluginLinkExtensionsMock.mock.calls[0];
const [options] = usePluginLinksMock.mock.calls[0];
const { context } = options;
expect(context).toEqual({
@ -153,7 +153,7 @@ describe('ToolbarExtensionPoint', () => {
data,
});
const [options] = usePluginLinkExtensionsMock.mock.calls[0];
const [options] = usePluginLinksMock.mock.calls[0];
const { context } = options;
expect(context).toHaveProperty('timeZone', 'browser');
@ -162,7 +162,7 @@ describe('ToolbarExtensionPoint', () => {
it('should correct extension point id when fetching extensions', async () => {
renderWithExploreStore(<ToolbarExtensionPoint exploreId="left" timeZone="browser" />);
const [options] = usePluginLinkExtensionsMock.mock.calls[0];
const [options] = usePluginLinksMock.mock.calls[0];
const { extensionPointId } = options;
expect(extensionPointId).toBe(PluginExtensionPoints.ExploreToolbarAction);
@ -171,8 +171,8 @@ describe('ToolbarExtensionPoint', () => {
describe('with extension points without categories', () => {
beforeAll(() => {
usePluginLinkExtensionsMock.mockReturnValue({
extensions: [
usePluginLinksMock.mockReturnValue({
links: [
{
pluginId: 'grafana',
id: '1',
@ -215,7 +215,7 @@ describe('ToolbarExtensionPoint', () => {
describe('without extension points', () => {
beforeAll(() => {
contextSrvMock.hasPermission.mockReturnValue(true);
usePluginLinkExtensionsMock.mockReturnValue({ extensions: [], isLoading: false });
usePluginLinksMock.mockReturnValue({ links: [], isLoading: false });
});
it('should render "add to dashboard" action button if one pane is visible', async () => {
@ -233,7 +233,7 @@ describe('ToolbarExtensionPoint', () => {
describe('with insufficient permissions', () => {
beforeAll(() => {
contextSrvMock.hasPermission.mockReturnValue(false);
usePluginLinkExtensionsMock.mockReturnValue({ extensions: [], isLoading: false });
usePluginLinksMock.mockReturnValue({ links: [], isLoading: false });
});
it('should not render "add to dashboard" action button', async () => {

View File

@ -1,7 +1,7 @@
import { lazy, ReactElement, Suspense, useMemo, useState } from 'react';
import { type PluginExtensionLink, PluginExtensionPoints, RawTimeRange, getTimeZone } from '@grafana/data';
import { config, usePluginLinkExtensions } from '@grafana/runtime';
import { config, usePluginLinks } from '@grafana/runtime';
import { DataQuery, TimeZone } from '@grafana/schema';
import { Dropdown, ToolbarButton } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
@ -26,7 +26,7 @@ export function ToolbarExtensionPoint(props: Props): ReactElement | null {
const [selectedExtension, setSelectedExtension] = useState<PluginExtensionLink | undefined>();
const [isOpen, setIsOpen] = useState<boolean>(false);
const context = useExtensionPointContext(props);
const { extensions } = usePluginLinkExtensions({
const { links } = usePluginLinks({
extensionPointId: PluginExtensionPoints.ExploreToolbarAction,
context: context,
limitPerPlugin: 3,
@ -36,7 +36,7 @@ export function ToolbarExtensionPoint(props: Props): ReactElement | null {
// If we only have the explore core extension point registered we show the old way of
// adding a query to a dashboard.
if (extensions.length <= 1) {
if (links.length <= 1) {
const canAddPanelToDashboard =
contextSrv.hasPermission(AccessControlAction.DashboardsCreate) ||
contextSrv.hasPermission(AccessControlAction.DashboardsWrite);
@ -52,7 +52,7 @@ export function ToolbarExtensionPoint(props: Props): ReactElement | null {
);
}
const menu = <ToolbarExtensionPointMenu extensions={extensions} onSelect={setSelectedExtension} />;
const menu = <ToolbarExtensionPointMenu extensions={links} onSelect={setSelectedExtension} />;
return (
<>

View File

@ -21,12 +21,12 @@ import {
locationService,
HistoryWrapper,
LocationService,
setPluginExtensionsHook,
setBackendSrv,
getBackendSrv,
getDataSourceSrv,
getEchoSrv,
setLocationService,
setPluginLinksHook,
} from '@grafana/runtime';
import { DataSourceRef } from '@grafana/schema';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
@ -89,7 +89,7 @@ export function setupExplore(options?: SetupOptions): {
request: jest.fn().mockRejectedValue(undefined),
});
setPluginExtensionsHook(() => ({ extensions: [], isLoading: false }));
setPluginLinksHook(() => ({ links: [], isLoading: false }));
// Clear this up otherwise it persists data source selection
// TODO: probably add test for that too

View File

@ -11,7 +11,7 @@ jest.mock('@grafana/runtime', () => ({
useChromeHeaderHeight: jest.fn(),
getBackendSrv: () => ({ get: getMock }),
getDataSourceSrv: () => ({ get: getDatasource, getInstanceSettings }),
usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
describe('Dashboard reload', () => {

View File

@ -12,7 +12,7 @@ jest.mock('@grafana/runtime', () => ({
useChromeHeaderHeight: jest.fn(),
getBackendSrv: () => ({ get: getMock }),
getDataSourceSrv: () => ({ get: getDatasource, getInstanceSettings }),
usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
const runTest = async (passScopes: boolean, kubernetesApi: boolean) => {

View File

@ -28,7 +28,7 @@ jest.mock('@grafana/runtime', () => ({
useChromeHeaderHeight: jest.fn(),
getBackendSrv: () => ({ get: getMock }),
getDataSourceSrv: () => ({ get: getDatasource, getInstanceSettings }),
usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
describe('Dashboards list', () => {

View File

@ -11,7 +11,7 @@ jest.mock('@grafana/runtime', () => ({
useChromeHeaderHeight: jest.fn(),
getBackendSrv: () => ({ get: getMock }),
getDataSourceSrv: () => ({ get: getDatasource, getInstanceSettings }),
usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
describe('Feature flag off', () => {

View File

@ -15,7 +15,7 @@ jest.mock('@grafana/runtime', () => ({
useChromeHeaderHeight: jest.fn(),
getBackendSrv: () => ({ get: getMock }),
getDataSourceSrv: () => ({ get: getDatasource, getInstanceSettings }),
usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
describe('Selector', () => {

View File

@ -46,7 +46,7 @@ jest.mock('@grafana/runtime', () => ({
useChromeHeaderHeight: jest.fn(),
getBackendSrv: () => ({ get: getMock }),
getDataSourceSrv: () => ({ get: getDatasource, getInstanceSettings }),
usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
describe('Tree', () => {

View File

@ -14,7 +14,7 @@ jest.mock('@grafana/runtime', () => ({
useChromeHeaderHeight: jest.fn(),
getBackendSrv: () => ({ get: getMock }),
getDataSourceSrv: () => ({ get: getDatasource, getInstanceSettings }),
usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
describe('View mode', () => {

View File

@ -4,7 +4,7 @@ import { Provider } from 'react-redux';
import { byRole, byText } from 'testing-library-selector';
import { FieldConfigSource, getDefaultTimeRange, LoadingState, PanelProps, PluginExtensionTypes } from '@grafana/data';
import { TimeRangeUpdatedEvent, usePluginLinkExtensions } from '@grafana/runtime';
import { TimeRangeUpdatedEvent, usePluginLinks } from '@grafana/runtime';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
import { mockPromRulesApiResponse } from 'app/features/alerting/unified/mocks/grafanaRulerApi';
import { mockRulerRulesApiResponse } from 'app/features/alerting/unified/mocks/rulerApi';
@ -56,12 +56,12 @@ const grafanaRuleMock = {
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
usePluginLinkExtensions: jest.fn(),
usePluginLinks: jest.fn(),
}));
jest.mock('app/features/alerting/unified/api/alertmanager');
const mocks = {
usePluginLinkExtensionsMock: jest.mocked(usePluginLinkExtensions),
usePluginLinksMock: jest.mocked(usePluginLinks),
};
const fakeResponse: PromRulesResponse = {
@ -84,8 +84,8 @@ beforeEach(() => {
mockRulerRulesApiResponse(server, 'grafana', {
'folder-one': [{ name: 'group1', interval: '20s', rules: [originRule] }],
});
mocks.usePluginLinkExtensionsMock.mockReturnValue({
extensions: [
mocks.usePluginLinksMock.mockReturnValue({
links: [
{
pluginId: 'grafana-ml-app',
id: '1',