mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* feat: add a reactive extension registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: add hooks to work with the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: start using the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "command palette" extension point to use the hook * feat: update the "alerting" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "explore" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "datasources config" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "panel menu" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "pyroscope datasource" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "user profile page" extension point to use the hooks * chore: update betterer * fix: update the hooks to not re-render unnecessarily * chore: remove the old `createPluginExtensionRegistry` impementation * chore: add "TODO" for `PanelMenuBehaviour` extension point * feat: update the return value of the hooks to contain a `{ isLoading }` param * tests: add more tests for the usePluginExtensions() hook * fix: exclude the cloud-home-app from being non-awaited * refactor: use uuidv4() for random ID generation (for the registry object) * fix: linting issue * feat: use the hooks for the new alerting extension point * feat: use `useMemo()` for `AlertInstanceAction` extension point context --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
105 lines
3.0 KiB
TypeScript
105 lines
3.0 KiB
TypeScript
import { css } from '@emotion/css';
|
|
import React from 'react';
|
|
import { useAsync } from 'react-use';
|
|
|
|
import { GrafanaTheme2, QueryEditorProps, TimeRange } from '@grafana/data';
|
|
import { getBackendSrv, usePluginLinkExtensions } from '@grafana/runtime';
|
|
import { LinkButton, useStyles2 } from '@grafana/ui';
|
|
|
|
import { PyroscopeDataSource } from '../datasource';
|
|
import { PyroscopeDataSourceOptions, Query } from '../types';
|
|
|
|
const EXTENSION_POINT_ID = 'plugins/grafana-pyroscope-datasource/query-links';
|
|
|
|
/** A subset of the datasource settings that are relevant for this integration */
|
|
type PyroscopeDatasourceSettings = {
|
|
uid: string;
|
|
url: string;
|
|
type: string;
|
|
basicAuthUser: string;
|
|
};
|
|
|
|
/** The context object that will be shared with the link extension's configure function */
|
|
type ExtensionQueryLinksContext = {
|
|
datasourceUid: string;
|
|
query: Query;
|
|
range?: TimeRange | undefined;
|
|
datasourceSettings?: PyroscopeDatasourceSettings;
|
|
};
|
|
|
|
/* Global promises to fetch pyroscope datasource settings by uid as encountered */
|
|
const pyroscopeDatasourceSettingsByUid: Record<string, PyroscopeDatasourceSettings> = {};
|
|
|
|
/* Reset promises for testing purposes */
|
|
export function resetPyroscopeQueryLinkExtensionsFetches() {
|
|
Object.keys(pyroscopeDatasourceSettingsByUid).forEach((key) => delete pyroscopeDatasourceSettingsByUid[key]);
|
|
}
|
|
|
|
/** A subset of the `PyroscopeDataSource` `QueryEditorProps` */
|
|
export type Props = Pick<
|
|
QueryEditorProps<PyroscopeDataSource, Query, PyroscopeDataSourceOptions>,
|
|
'datasource' | 'query' | 'range'
|
|
>;
|
|
|
|
export function PyroscopeQueryLinkExtensions(props: Props) {
|
|
const {
|
|
datasource: { uid: datasourceUid },
|
|
query,
|
|
range,
|
|
} = props;
|
|
|
|
const { value: datasourceSettings } = useAsync(async () => {
|
|
if (pyroscopeDatasourceSettingsByUid[datasourceUid]) {
|
|
return pyroscopeDatasourceSettingsByUid[datasourceUid];
|
|
}
|
|
const settings = await getBackendSrv().get<PyroscopeDatasourceSettings>(`/api/datasources/uid/${datasourceUid}`);
|
|
pyroscopeDatasourceSettingsByUid[datasourceUid] = settings;
|
|
return settings;
|
|
}, [datasourceUid]);
|
|
|
|
const context: ExtensionQueryLinksContext = {
|
|
datasourceUid,
|
|
query,
|
|
range,
|
|
datasourceSettings,
|
|
};
|
|
|
|
const { extensions } = usePluginLinkExtensions({
|
|
extensionPointId: EXTENSION_POINT_ID,
|
|
context,
|
|
});
|
|
|
|
const styles = useStyles2(getStyles);
|
|
|
|
if (extensions.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{extensions.map((extension) => (
|
|
<LinkButton
|
|
className={styles.linkButton}
|
|
key={`${extension.id}`}
|
|
variant="secondary"
|
|
icon={extension.icon || 'external-link-alt'}
|
|
tooltip={extension.description}
|
|
target="_blank"
|
|
href={extension.path}
|
|
onClick={extension.onClick}
|
|
>
|
|
{extension.title}
|
|
</LinkButton>
|
|
))}
|
|
</>
|
|
);
|
|
}
|
|
|
|
function getStyles(theme: GrafanaTheme2) {
|
|
return {
|
|
linkButton: css({
|
|
marginLeft: theme.spacing(1),
|
|
}),
|
|
};
|
|
}
|