From 501e547bea87eb2ebed9b553b773f6a9a6c750a0 Mon Sep 17 00:00:00 2001 From: Andrej Ocenas Date: Wed, 20 Sep 2023 12:29:56 +0200 Subject: [PATCH] Pyroscope: Fix error when no profile types are returned (#75143) --- .../QueryEditor/ProfileTypesCascader.tsx | 2 + .../QueryEditor/QueryEditor.test.tsx | 30 +++++++++++++-- .../QueryEditor/QueryEditor.tsx | 37 ++++++++++--------- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/ProfileTypesCascader.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/ProfileTypesCascader.tsx index 7708cb1862a..07026f2de0c 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/ProfileTypesCascader.tsx +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/ProfileTypesCascader.tsx @@ -9,6 +9,7 @@ type Props = { initialProfileTypeId?: string; profileTypes?: ProfileTypeMessage[]; onChange: (value: string) => void; + placeholder?: string; }; export function ProfileTypesCascader(props: Props) { @@ -16,6 +17,7 @@ export function ProfileTypesCascader(props: Props) { return ( { expect(await screen.findByDisplayValue('process_cpu-cpu')).toBeDefined(); }); + it('should render without error if empty profileTypes', async () => { + const ds = setupDs(); + ds.getProfileTypes = jest.fn().mockResolvedValue([]); + setup({ + props: { + datasource: ds, + query: { + queryType: 'both', + labelSelector: '', + profileTypeId: '', + refId: 'A', + maxNodes: 1000, + groupBy: [], + }, + }, + }); + + expect(await screen.findByPlaceholderText('No profile types found')).toBeDefined(); + }); + it('should render options', async () => { setup(); await openOptions(); @@ -41,8 +61,7 @@ async function openOptions() { await userEvent.click(options); } -function setup(options: { props: Partial } = { props: {} }) { - const onChange = jest.fn(); +function setupDs() { const ds = new PhlareDataSource({ name: 'test', uid: 'test', @@ -85,6 +104,11 @@ function setup(options: { props: Partial } = { props: {} }) { }, ] as ProfileTypeMessage[]); + return ds; +} + +function setup(options: { props: Partial } = { props: {} }) { + const onChange = jest.fn(); const utils = render( } = { props: {} }) { maxNodes: 1000, groupBy: [], }} - datasource={ds} + datasource={setupDs()} onChange={onChange} onRunQuery={() => {}} app={CoreApp.Explore} diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.tsx index 28379aee471..c354a41649b 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.tsx +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.tsx @@ -28,25 +28,28 @@ export function QueryEditor(props: Props) { const { labels, getLabelValues, onLabelSelectorChange } = useLabels(range, datasource, query, onChange); useNormalizeQuery(query, profileTypes, onChange, app); + let cascader = ; + + // The cascader is uncontrolled component so if we want to set some default value we can do it only on initial + // render, so we are waiting until we have the profileTypes and know what the default value should be before + // rendering. + if (profileTypes && query.profileTypeId !== undefined) { + cascader = ( + { + onChange({ ...query, profileTypeId: val }); + }} + /> + ); + } + return ( - {/* - The cascader is uncontrolled component so if we want to set some default value we can do it only on initial - render, so we are waiting until we have the profileTypes and know what the default value should be before - rendering. - */} - {profileTypes && query.profileTypeId ? ( - { - onChange({ ...query, profileTypeId: val }); - }} - /> - ) : ( - - )} + {cascader}