mirror of https://github.com/grafana/grafana
fix: pyroscope datasource remove link extension (#89512)
It has been decided that we will not be using this moving forward.pull/89633/head
parent
7d8afd9578
commit
f5d9c247d9
@ -1,131 +0,0 @@ |
||||
import { render, screen } from '@testing-library/react'; |
||||
import React from 'react'; |
||||
import { act } from 'react-dom/test-utils'; |
||||
|
||||
import { PluginType, rangeUtil, PluginExtensionLink, PluginExtensionTypes } from '@grafana/data'; |
||||
import { usePluginLinkExtensions } from '@grafana/runtime'; |
||||
|
||||
import { PyroscopeDataSource } from '../datasource'; |
||||
import { mockFetchPyroscopeDatasourceSettings } from '../datasource.test'; |
||||
|
||||
import { Props, PyroscopeQueryLinkExtensions, resetPyroscopeQueryLinkExtensionsFetches } from './QueryLinkExtension'; |
||||
|
||||
// Constants copied from `QueryLinkExtension.tsx`
|
||||
const EXTENSION_POINT_ID = 'plugins/grafana-pyroscope-datasource/query-links'; |
||||
|
||||
jest.mock('@grafana/runtime', () => ({ |
||||
...jest.requireActual('@grafana/runtime'), |
||||
usePluginLinkExtensions: jest.fn(), |
||||
getTemplateSrv: () => { |
||||
return { |
||||
replace: (query: string): string => { |
||||
return query.replace(/\$var/g, 'interpolated'); |
||||
}, |
||||
}; |
||||
}, |
||||
})); |
||||
|
||||
const usePluginLinkExtensionsMock = jest.mocked(usePluginLinkExtensions); |
||||
|
||||
const defaultPyroscopeDataSourceSettings = { |
||||
uid: 'default-pyroscope', |
||||
url: 'http://pyroscope', |
||||
basicAuthUser: 'pyroscope_user', |
||||
}; |
||||
|
||||
describe('PyroscopeQueryLinkExtensions', () => { |
||||
const EXPECTED_BUTTON_LABEL = 'Profiles App'; |
||||
const DEFAULT_EXTENSION_PATH = 'a/mock-path-app/fake-path'; |
||||
|
||||
function createExtension(overrides?: Partial<PluginExtensionLink>) { |
||||
return { |
||||
...{ |
||||
description: 'unremarkable-description', |
||||
extensionPointId: EXTENSION_POINT_ID, |
||||
title: EXPECTED_BUTTON_LABEL, |
||||
path: DEFAULT_EXTENSION_PATH, |
||||
type: PluginExtensionTypes.link, |
||||
category: 'unremarkable-category', |
||||
icon: 'heart', |
||||
onClick() {}, |
||||
pluginId: 'mock-path-app', |
||||
id: `${Date.now()}}`, |
||||
}, |
||||
...overrides, |
||||
} as PluginExtensionLink; |
||||
} |
||||
|
||||
beforeEach(() => { |
||||
resetPyroscopeQueryLinkExtensionsFetches(); |
||||
mockFetchPyroscopeDatasourceSettings(defaultPyroscopeDataSourceSettings); |
||||
|
||||
usePluginLinkExtensionsMock.mockRestore(); |
||||
usePluginLinkExtensionsMock.mockReturnValue({ extensions: [], isLoading: false }); // Unless stated otherwise, no extensions
|
||||
}); |
||||
|
||||
it('should render if extension present', async () => { |
||||
usePluginLinkExtensionsMock.mockReturnValue({ extensions: [createExtension()], isLoading: false }); // Default extension
|
||||
|
||||
await act(setup); |
||||
expect(await screen.findAllByText(EXPECTED_BUTTON_LABEL)).toBeDefined(); |
||||
}); |
||||
|
||||
it('Should not render if no extension present', async () => { |
||||
await act(setup); |
||||
expect(screen.queryByText(EXPECTED_BUTTON_LABEL)).toBeNull(); |
||||
}); |
||||
}); |
||||
|
||||
function setupDs() { |
||||
const ds = new PyroscopeDataSource({ |
||||
...defaultPyroscopeDataSourceSettings, |
||||
name: 'test', |
||||
type: PluginType.datasource, |
||||
access: 'proxy', |
||||
id: 1, |
||||
jsonData: {}, |
||||
meta: { |
||||
name: '', |
||||
id: '', |
||||
type: PluginType.datasource, |
||||
baseUrl: '', |
||||
info: { |
||||
author: { |
||||
name: '', |
||||
}, |
||||
description: '', |
||||
links: [], |
||||
logos: { |
||||
large: '', |
||||
small: '', |
||||
}, |
||||
screenshots: [], |
||||
updated: '', |
||||
version: '', |
||||
}, |
||||
module: '', |
||||
}, |
||||
readOnly: false, |
||||
}); |
||||
|
||||
return ds; |
||||
} |
||||
|
||||
async function setup(options: { props: Partial<Props> } = { props: {} }) { |
||||
const utils = render( |
||||
<PyroscopeQueryLinkExtensions |
||||
query={{ |
||||
queryType: 'both', |
||||
labelSelector: '', |
||||
profileTypeId: 'process_cpu:cpu', |
||||
refId: 'A', |
||||
maxNodes: 1000, |
||||
groupBy: [], |
||||
}} |
||||
datasource={setupDs()} |
||||
range={rangeUtil.convertRawToRange({ from: 'now-1h', to: 'now' })} |
||||
{...options.props} |
||||
/> |
||||
); |
||||
return { ...utils }; |
||||
} |
||||
@ -1,104 +0,0 @@ |
||||
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), |
||||
}), |
||||
}; |
||||
} |
||||
Loading…
Reference in new issue