mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 18:30:41 -06:00
Sidecar: Remove extension helpers and use the sidecar service directly (#94979)
This commit is contained in:
parent
94f5e21493
commit
5b1d99b8c4
@ -75,10 +75,7 @@ export type PluginExtensionAddedComponentConfig<Props = {}> = PluginExtensionCon
|
||||
component: React.ComponentType<Props>;
|
||||
};
|
||||
|
||||
export type PluginAddedLinksConfigureFunc<Context extends object> = (
|
||||
context: Readonly<Context> | undefined,
|
||||
helpers: PluginExtensionHelpers
|
||||
) =>
|
||||
export type PluginAddedLinksConfigureFunc<Context extends object> = (context: Readonly<Context> | undefined) =>
|
||||
| Partial<{
|
||||
title: string;
|
||||
description: string;
|
||||
@ -145,27 +142,11 @@ export type PluginExtensionOpenModalOptions = {
|
||||
height?: string | number;
|
||||
};
|
||||
|
||||
type PluginExtensionHelpers = {
|
||||
/** Checks if the app plugin (that registers the extension) is currently visible (either in the main view or in the side view)
|
||||
* @experimental
|
||||
*/
|
||||
isAppOpened: () => boolean;
|
||||
};
|
||||
|
||||
export type PluginExtensionEventHelpers<Context extends object = object> = {
|
||||
context?: Readonly<Context>;
|
||||
// Opens a modal dialog and renders the provided React component inside it
|
||||
openModal: (options: PluginExtensionOpenModalOptions) => void;
|
||||
|
||||
/** Opens the app plugin (that registers the extensions) in a side view
|
||||
* @experimental
|
||||
*/
|
||||
openAppInSideview: (context?: unknown) => void;
|
||||
/** Closes the side view for the app plugin (that registers the extensions) in case it was open
|
||||
* @experimental
|
||||
*/
|
||||
closeAppInSideview: () => void;
|
||||
} & PluginExtensionHelpers;
|
||||
};
|
||||
|
||||
// Extension Points & Contexts
|
||||
// --------------------------------------------------------
|
||||
|
@ -0,0 +1,47 @@
|
||||
import { config } from '../config';
|
||||
|
||||
import { SidecarService_EXPERIMENTAL } from './SidecarService_EXPERIMENTAL';
|
||||
|
||||
describe('SidecarService_EXPERIMENTAL', () => {
|
||||
beforeEach(() => {
|
||||
config.featureToggles.appSidecar = true;
|
||||
});
|
||||
afterEach(() => {
|
||||
config.featureToggles.appSidecar = undefined;
|
||||
});
|
||||
|
||||
it('has the correct state after opening and closing an app', () => {
|
||||
const sidecarService = new SidecarService_EXPERIMENTAL({});
|
||||
sidecarService.openApp('pluginId', { filter: 'test' });
|
||||
|
||||
expect(sidecarService.activePluginId).toBe('pluginId');
|
||||
expect(sidecarService.initialContext).toMatchObject({ filter: 'test' });
|
||||
|
||||
sidecarService.closeApp('pluginId');
|
||||
expect(sidecarService.activePluginId).toBe(undefined);
|
||||
expect(sidecarService.initialContext).toBe(undefined);
|
||||
});
|
||||
|
||||
it('reports correct opened state', () => {
|
||||
const sidecarService = new SidecarService_EXPERIMENTAL({});
|
||||
expect(sidecarService.isAppOpened('pluginId')).toBe(false);
|
||||
|
||||
sidecarService.openApp('pluginId');
|
||||
|
||||
expect(sidecarService.isAppOpened('pluginId')).toBe(true);
|
||||
|
||||
sidecarService.closeApp('pluginId');
|
||||
|
||||
expect(sidecarService.isAppOpened('pluginId')).toBe(false);
|
||||
});
|
||||
|
||||
it('does not close app that is not opened', () => {
|
||||
const sidecarService = new SidecarService_EXPERIMENTAL({});
|
||||
sidecarService.openApp('pluginId');
|
||||
|
||||
sidecarService.closeApp('foobar');
|
||||
|
||||
expect(sidecarService.isAppOpened('pluginId')).toBe(true);
|
||||
expect(sidecarService.activePluginId).toBe('pluginId');
|
||||
});
|
||||
});
|
@ -97,7 +97,7 @@ func createIndexMappings() *mapping.IndexMappingImpl {
|
||||
indexMapping.TypeField = "Kind"
|
||||
|
||||
// for all kinds, create their index mappings
|
||||
for k, _ := range getSpecObjectMappings() {
|
||||
for k := range getSpecObjectMappings() {
|
||||
objMapping := createIndexMappingForKind(k)
|
||||
indexMapping.AddDocumentMapping(k, objMapping)
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ describe('getExploreExtensionConfigs', () => {
|
||||
const extensions = getExploreExtensionConfigs();
|
||||
const [extension] = extensions;
|
||||
|
||||
expect(extension?.configure?.(undefined, { isAppOpened: () => false })).toBeUndefined();
|
||||
expect(extension?.configure?.(undefined)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return empty object if sufficient permissions', () => {
|
||||
@ -52,7 +52,7 @@ describe('getExploreExtensionConfigs', () => {
|
||||
const extensions = getExploreExtensionConfigs();
|
||||
const [extension] = extensions;
|
||||
|
||||
expect(extension?.configure?.(undefined, { isAppOpened: () => false })).toEqual({});
|
||||
expect(extension?.configure?.(undefined)).toEqual({});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -186,10 +186,7 @@ describe('getPluginExtensions()', () => {
|
||||
getPluginExtensions({ ...registries, context, extensionPointId: extensionPoint2 });
|
||||
|
||||
expect(link2.configure).toHaveBeenCalledTimes(1);
|
||||
expect(link2.configure).toHaveBeenCalledWith(
|
||||
context,
|
||||
expect.objectContaining({ isAppOpened: expect.any(Function) })
|
||||
);
|
||||
expect(link2.configure).toHaveBeenCalledWith(context);
|
||||
});
|
||||
|
||||
test('should be possible to update the basic properties with the configure() function', async () => {
|
||||
|
@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
||||
import { useObservable } from 'react-use';
|
||||
|
||||
import { PluginExtension, usePluginContext } from '@grafana/data';
|
||||
import { GetPluginExtensionsOptions, UsePluginExtensionsResult, useSidecar_EXPERIMENTAL } from '@grafana/runtime';
|
||||
import { GetPluginExtensionsOptions, UsePluginExtensionsResult } from '@grafana/runtime';
|
||||
|
||||
import { getPluginExtensions } from './getPluginExtensions';
|
||||
import { log } from './logs/log';
|
||||
@ -18,7 +18,6 @@ export function createUsePluginExtensions(registries: PluginExtensionRegistries)
|
||||
const pluginContext = usePluginContext();
|
||||
const addedComponentsRegistry = useObservable(observableAddedComponentsRegistry);
|
||||
const addedLinksRegistry = useObservable(observableAddedLinksRegistry);
|
||||
const { activePluginId } = useSidecar_EXPERIMENTAL();
|
||||
const { extensionPointId, context, limitPerPlugin } = options;
|
||||
|
||||
const { extensions } = useMemo(() => {
|
||||
@ -65,15 +64,7 @@ export function createUsePluginExtensions(registries: PluginExtensionRegistries)
|
||||
// options object so we are checking it's simple value attributes.
|
||||
// The context though still has to be memoized though and not mutated.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: refactor `getPluginExtensions` to accept service dependencies as arguments instead of relying on the sidecar singleton under the hood
|
||||
}, [
|
||||
addedLinksRegistry,
|
||||
addedComponentsRegistry,
|
||||
extensionPointId,
|
||||
context,
|
||||
limitPerPlugin,
|
||||
activePluginId,
|
||||
pluginContext,
|
||||
]);
|
||||
}, [addedLinksRegistry, addedComponentsRegistry, extensionPointId, context, limitPerPlugin, pluginContext]);
|
||||
|
||||
return { extensions, isLoading: false };
|
||||
};
|
||||
|
@ -20,12 +20,7 @@ import {
|
||||
PluginExtensionExposedComponentConfig,
|
||||
PluginExtensionAddedComponentConfig,
|
||||
} from '@grafana/data';
|
||||
import {
|
||||
reportInteraction,
|
||||
config,
|
||||
// TODO: instead of depending on the service as a singleton, inject it as an argument from the React context
|
||||
sidecarServiceSingleton_EXPERIMENTAL,
|
||||
} from '@grafana/runtime';
|
||||
import { reportInteraction, config } from '@grafana/runtime';
|
||||
import { Modal } from '@grafana/ui';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { getPluginSettings } from 'app/features/plugins/pluginSettings';
|
||||
@ -312,7 +307,7 @@ export function getLinkExtensionOverrides(
|
||||
context?: object
|
||||
) {
|
||||
try {
|
||||
const overrides = config.configure?.(context, { isAppOpened: () => isAppOpened(pluginId) });
|
||||
const overrides = config.configure?.(context);
|
||||
|
||||
// Hiding the extension
|
||||
if (overrides === undefined) {
|
||||
@ -390,9 +385,6 @@ export function getLinkExtensionOnClick(
|
||||
const helpers: PluginExtensionEventHelpers = {
|
||||
context,
|
||||
openModal: createOpenModalFunction(pluginId),
|
||||
isAppOpened: () => isAppOpened(pluginId),
|
||||
openAppInSideview: (context?: unknown) => openAppInSideview(pluginId, context),
|
||||
closeAppInSideview: () => closeAppInSideview(pluginId),
|
||||
};
|
||||
|
||||
log.debug(`onClick '${config.title}' at '${extensionPointId}'`);
|
||||
@ -429,13 +421,6 @@ export function getLinkExtensionPathWithTracking(pluginId: string, path: string,
|
||||
);
|
||||
}
|
||||
|
||||
export const openAppInSideview = (pluginId: string, context?: unknown) =>
|
||||
sidecarServiceSingleton_EXPERIMENTAL.openApp(pluginId, context);
|
||||
|
||||
export const closeAppInSideview = (pluginId: string) => sidecarServiceSingleton_EXPERIMENTAL.closeApp(pluginId);
|
||||
|
||||
export const isAppOpened = (pluginId: string) => sidecarServiceSingleton_EXPERIMENTAL.isAppOpened(pluginId);
|
||||
|
||||
// Comes from the `app_mode` setting in the Grafana config (defaults to "development")
|
||||
// Can be set with the `GF_DEFAULT_APP_MODE` environment variable
|
||||
export const isGrafanaDevMode = () => config.buildInfo.env === 'development';
|
||||
|
@ -71,7 +71,7 @@ describe('Plugin Extension Validators', () => {
|
||||
title: 'Title',
|
||||
description: 'Description',
|
||||
targets: 'grafana/some-page/extension-point-a',
|
||||
configure: (_, {}) => {},
|
||||
configure: () => {},
|
||||
} as PluginExtensionAddedLinkConfig);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user