diff --git a/.betterer.results b/.betterer.results index e718efde2b2..e76e868a54f 100644 --- a/.betterer.results +++ b/.betterer.results @@ -765,6 +765,9 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "11"], [0, 0, 0, "Unexpected any. Specify a different type.", "12"] ], + "packages/grafana-runtime/src/services/pluginExtensions/getPluginExtensions.ts:5381": [ + [0, 0, 0, "Do not use any type assertions.", "0"] + ], "packages/grafana-runtime/src/utils/DataSourceWithBackend.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] @@ -2947,9 +2950,6 @@ exports[`better eslint`] = { "public/app/features/datasources/components/DataSourceTypeCardList.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], - "public/app/features/datasources/components/EditDataSource.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], "public/app/features/datasources/components/picker/DataSourceCard.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"], diff --git a/packages/grafana-data/src/types/app.ts b/packages/grafana-data/src/types/app.ts index fcb58a7ccb1..626ab368bf2 100644 --- a/packages/grafana-data/src/types/app.ts +++ b/packages/grafana-data/src/types/app.ts @@ -111,9 +111,7 @@ export class AppPlugin extends GrafanaPlugin( - extension: Omit, 'type'> - ) { + configureExtensionComponent(extension: Omit, 'type'>) { this._extensionConfigs.push({ ...extension, type: PluginExtensionTypes.component, diff --git a/packages/grafana-data/src/types/pluginExtensions.ts b/packages/grafana-data/src/types/pluginExtensions.ts index 68fa3c7d1d8..e7a26223c34 100644 --- a/packages/grafana-data/src/types/pluginExtensions.ts +++ b/packages/grafana-data/src/types/pluginExtensions.ts @@ -32,9 +32,9 @@ export type PluginExtensionLink = PluginExtensionBase & { category?: string; }; -export type PluginExtensionComponent = PluginExtensionBase & { +export type PluginExtensionComponent = PluginExtensionBase & { type: PluginExtensionTypes.component; - component: React.ComponentType; + component: React.ComponentType; }; export type PluginExtension = PluginExtensionLink | PluginExtensionComponent; @@ -77,16 +77,14 @@ export type PluginExtensionLinkConfig = { category?: string; }; -export type PluginExtensionComponentConfig = { +export type PluginExtensionComponentConfig = { type: PluginExtensionTypes.component; title: string; description: string; // The React component that will be rendered as the extension - // (This component receives the context as a prop when it is rendered. You can just return `null` from the component to hide for certain contexts) - component: React.ComponentType<{ - context?: Context; - }>; + // (This component receives contextual information as props when it is rendered. You can just return `null` from the component to hide it.) + component: React.ComponentType; // The unique identifier of the Extension Point // (Core Grafana extension point ids are available in the `PluginExtensionPoints` enum) diff --git a/packages/grafana-runtime/src/services/pluginExtensions/getPluginExtensions.ts b/packages/grafana-runtime/src/services/pluginExtensions/getPluginExtensions.ts index 66f2cf2abc3..dcd52b200b2 100644 --- a/packages/grafana-runtime/src/services/pluginExtensions/getPluginExtensions.ts +++ b/packages/grafana-runtime/src/services/pluginExtensions/getPluginExtensions.ts @@ -41,10 +41,15 @@ export const getPluginLinkExtensions: GetPluginExtensions = }; }; -export const getPluginComponentExtensions: GetPluginExtensions = (options) => { +// This getter doesn't support the `context` option (contextual information can be passed in as component props) +export const getPluginComponentExtensions = (options: { + extensionPointId: string; + limitPerPlugin?: number; +}): { extensions: Array> } => { const { extensions } = getPluginExtensions(options); + const componentExtensions = extensions.filter(isPluginExtensionComponent) as Array>; return { - extensions: extensions.filter(isPluginExtensionComponent), + extensions: componentExtensions, }; }; diff --git a/public/app/features/datasources/components/EditDataSource.tsx b/public/app/features/datasources/components/EditDataSource.tsx index d141d19c253..e4802f21b49 100644 --- a/public/app/features/datasources/components/EditDataSource.tsx +++ b/public/app/features/datasources/components/EditDataSource.tsx @@ -139,7 +139,9 @@ export function EditDataSourceView({ const extensions = useMemo(() => { const allowedPluginIds = ['grafana-pdc-app', 'grafana-auth-app']; const extensionPointId = PluginExtensionPoints.DataSourceConfig; - const { extensions } = getPluginComponentExtensions({ extensionPointId }); + const { extensions } = getPluginComponentExtensions<{ + context: PluginExtensionDataSourceConfigContext; + }>({ extensionPointId }); return extensions.filter((e) => allowedPluginIds.includes(e.pluginId)); }, []); @@ -202,9 +204,7 @@ export function EditDataSourceView({ {/* Extension point */} {extensions.map((extension) => { - const Component = extension.component as React.ComponentType<{ - context: PluginExtensionDataSourceConfigContext; - }>; + const Component = extension.component; return (
diff --git a/public/app/features/plugins/extensions/utils.test.tsx b/public/app/features/plugins/extensions/utils.test.tsx index ee4b742f5f4..93958e05c90 100644 --- a/public/app/features/plugins/extensions/utils.test.tsx +++ b/public/app/features/plugins/extensions/utils.test.tsx @@ -445,12 +445,18 @@ describe('Plugin Extensions / Utils', () => { }); describe('wrapExtensionComponentWithContext()', () => { - const ExampleComponent = () => { + type ExampleComponentProps = { + audience?: string; + }; + + const ExampleComponent = (props: ExampleComponentProps) => { const { meta } = usePluginContext(); + const audience = props.audience || 'Grafana'; + return (
-

Hello Grafana!

Version: {meta.info.version} +

Hello {audience}!

Version: {meta.info.version}
); }; @@ -464,5 +470,15 @@ describe('Plugin Extensions / Utils', () => { expect(await screen.findByText('Hello Grafana!')).toBeVisible(); expect(screen.getByText('Version: 1.0.0')).toBeVisible(); }); + + it('should pass the properties into the wrapped component', async () => { + const pluginId = 'grafana-worldmap-panel'; + const Component = wrapWithPluginContext(pluginId, ExampleComponent); + + render(); + + expect(await screen.findByText('Hello folks!')).toBeVisible(); + expect(screen.getByText('Version: 1.0.0')).toBeVisible(); + }); }); }); diff --git a/public/app/features/profile/UserProfileEditPage.tsx b/public/app/features/profile/UserProfileEditPage.tsx index e86583393f4..ffb9c64b00c 100644 --- a/public/app/features/profile/UserProfileEditPage.tsx +++ b/public/app/features/profile/UserProfileEditPage.tsx @@ -79,7 +79,6 @@ export function UserProfileEditPage({ const extensionComponents = useMemo(() => { const { extensions } = getPluginComponentExtensions({ extensionPointId: PluginExtensionPoints.UserProfileTab, - context: {}, }); return extensions;