mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 02:40:26 -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>;
|
component: React.ComponentType<Props>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PluginAddedLinksConfigureFunc<Context extends object> = (
|
export type PluginAddedLinksConfigureFunc<Context extends object> = (context: Readonly<Context> | undefined) =>
|
||||||
context: Readonly<Context> | undefined,
|
|
||||||
helpers: PluginExtensionHelpers
|
|
||||||
) =>
|
|
||||||
| Partial<{
|
| Partial<{
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@ -145,27 +142,11 @@ export type PluginExtensionOpenModalOptions = {
|
|||||||
height?: string | number;
|
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> = {
|
export type PluginExtensionEventHelpers<Context extends object = object> = {
|
||||||
context?: Readonly<Context>;
|
context?: Readonly<Context>;
|
||||||
// Opens a modal dialog and renders the provided React component inside it
|
// Opens a modal dialog and renders the provided React component inside it
|
||||||
openModal: (options: PluginExtensionOpenModalOptions) => void;
|
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
|
// 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"
|
indexMapping.TypeField = "Kind"
|
||||||
|
|
||||||
// for all kinds, create their index mappings
|
// for all kinds, create their index mappings
|
||||||
for k, _ := range getSpecObjectMappings() {
|
for k := range getSpecObjectMappings() {
|
||||||
objMapping := createIndexMappingForKind(k)
|
objMapping := createIndexMappingForKind(k)
|
||||||
indexMapping.AddDocumentMapping(k, objMapping)
|
indexMapping.AddDocumentMapping(k, objMapping)
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ describe('getExploreExtensionConfigs', () => {
|
|||||||
const extensions = getExploreExtensionConfigs();
|
const extensions = getExploreExtensionConfigs();
|
||||||
const [extension] = extensions;
|
const [extension] = extensions;
|
||||||
|
|
||||||
expect(extension?.configure?.(undefined, { isAppOpened: () => false })).toBeUndefined();
|
expect(extension?.configure?.(undefined)).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty object if sufficient permissions', () => {
|
it('should return empty object if sufficient permissions', () => {
|
||||||
@ -52,7 +52,7 @@ describe('getExploreExtensionConfigs', () => {
|
|||||||
const extensions = getExploreExtensionConfigs();
|
const extensions = getExploreExtensionConfigs();
|
||||||
const [extension] = extensions;
|
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 });
|
getPluginExtensions({ ...registries, context, extensionPointId: extensionPoint2 });
|
||||||
|
|
||||||
expect(link2.configure).toHaveBeenCalledTimes(1);
|
expect(link2.configure).toHaveBeenCalledTimes(1);
|
||||||
expect(link2.configure).toHaveBeenCalledWith(
|
expect(link2.configure).toHaveBeenCalledWith(context);
|
||||||
context,
|
|
||||||
expect.objectContaining({ isAppOpened: expect.any(Function) })
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be possible to update the basic properties with the configure() function', async () => {
|
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 { useObservable } from 'react-use';
|
||||||
|
|
||||||
import { PluginExtension, usePluginContext } from '@grafana/data';
|
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 { getPluginExtensions } from './getPluginExtensions';
|
||||||
import { log } from './logs/log';
|
import { log } from './logs/log';
|
||||||
@ -18,7 +18,6 @@ export function createUsePluginExtensions(registries: PluginExtensionRegistries)
|
|||||||
const pluginContext = usePluginContext();
|
const pluginContext = usePluginContext();
|
||||||
const addedComponentsRegistry = useObservable(observableAddedComponentsRegistry);
|
const addedComponentsRegistry = useObservable(observableAddedComponentsRegistry);
|
||||||
const addedLinksRegistry = useObservable(observableAddedLinksRegistry);
|
const addedLinksRegistry = useObservable(observableAddedLinksRegistry);
|
||||||
const { activePluginId } = useSidecar_EXPERIMENTAL();
|
|
||||||
const { extensionPointId, context, limitPerPlugin } = options;
|
const { extensionPointId, context, limitPerPlugin } = options;
|
||||||
|
|
||||||
const { extensions } = useMemo(() => {
|
const { extensions } = useMemo(() => {
|
||||||
@ -65,15 +64,7 @@ export function createUsePluginExtensions(registries: PluginExtensionRegistries)
|
|||||||
// options object so we are checking it's simple value attributes.
|
// options object so we are checking it's simple value attributes.
|
||||||
// The context though still has to be memoized though and not mutated.
|
// 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
|
// 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, pluginContext]);
|
||||||
addedLinksRegistry,
|
|
||||||
addedComponentsRegistry,
|
|
||||||
extensionPointId,
|
|
||||||
context,
|
|
||||||
limitPerPlugin,
|
|
||||||
activePluginId,
|
|
||||||
pluginContext,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return { extensions, isLoading: false };
|
return { extensions, isLoading: false };
|
||||||
};
|
};
|
||||||
|
@ -20,12 +20,7 @@ import {
|
|||||||
PluginExtensionExposedComponentConfig,
|
PluginExtensionExposedComponentConfig,
|
||||||
PluginExtensionAddedComponentConfig,
|
PluginExtensionAddedComponentConfig,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import {
|
import { reportInteraction, config } from '@grafana/runtime';
|
||||||
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 { Modal } from '@grafana/ui';
|
import { Modal } from '@grafana/ui';
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
import { getPluginSettings } from 'app/features/plugins/pluginSettings';
|
import { getPluginSettings } from 'app/features/plugins/pluginSettings';
|
||||||
@ -312,7 +307,7 @@ export function getLinkExtensionOverrides(
|
|||||||
context?: object
|
context?: object
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const overrides = config.configure?.(context, { isAppOpened: () => isAppOpened(pluginId) });
|
const overrides = config.configure?.(context);
|
||||||
|
|
||||||
// Hiding the extension
|
// Hiding the extension
|
||||||
if (overrides === undefined) {
|
if (overrides === undefined) {
|
||||||
@ -390,9 +385,6 @@ export function getLinkExtensionOnClick(
|
|||||||
const helpers: PluginExtensionEventHelpers = {
|
const helpers: PluginExtensionEventHelpers = {
|
||||||
context,
|
context,
|
||||||
openModal: createOpenModalFunction(pluginId),
|
openModal: createOpenModalFunction(pluginId),
|
||||||
isAppOpened: () => isAppOpened(pluginId),
|
|
||||||
openAppInSideview: (context?: unknown) => openAppInSideview(pluginId, context),
|
|
||||||
closeAppInSideview: () => closeAppInSideview(pluginId),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
log.debug(`onClick '${config.title}' at '${extensionPointId}'`);
|
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")
|
// Comes from the `app_mode` setting in the Grafana config (defaults to "development")
|
||||||
// Can be set with the `GF_DEFAULT_APP_MODE` environment variable
|
// Can be set with the `GF_DEFAULT_APP_MODE` environment variable
|
||||||
export const isGrafanaDevMode = () => config.buildInfo.env === 'development';
|
export const isGrafanaDevMode = () => config.buildInfo.env === 'development';
|
||||||
|
@ -71,7 +71,7 @@ describe('Plugin Extension Validators', () => {
|
|||||||
title: 'Title',
|
title: 'Title',
|
||||||
description: 'Description',
|
description: 'Description',
|
||||||
targets: 'grafana/some-page/extension-point-a',
|
targets: 'grafana/some-page/extension-point-a',
|
||||||
configure: (_, {}) => {},
|
configure: () => {},
|
||||||
} as PluginExtensionAddedLinkConfig);
|
} as PluginExtensionAddedLinkConfig);
|
||||||
}).not.toThrowError();
|
}).not.toThrowError();
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user