Pyroscope: Fix error when no profile types are returned (#75143)

This commit is contained in:
Andrej Ocenas 2023-09-20 12:29:56 +02:00 committed by GitHub
parent c999979bc5
commit 501e547bea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 20 deletions

View File

@ -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 (
<Cascader
placeholder={props.placeholder}
separator={'-'}
displayAllSelectedLevels={true}
initialValue={props.initialProfileTypeId}

View File

@ -16,6 +16,26 @@ describe('QueryEditor', () => {
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> } = { 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> } = { props: {} }) {
},
] as ProfileTypeMessage[]);
return ds;
}
function setup(options: { props: Partial<Props> } = { props: {} }) {
const onChange = jest.fn();
const utils = render(
<QueryEditor
query={{
@ -95,7 +119,7 @@ function setup(options: { props: Partial<Props> } = { props: {} }) {
maxNodes: 1000,
groupBy: [],
}}
datasource={ds}
datasource={setupDs()}
onChange={onChange}
onRunQuery={() => {}}
app={CoreApp.Explore}

View File

@ -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 = <LoadingPlaceholder text={'Loading'} />;
// 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 = (
<ProfileTypesCascader
placeholder={profileTypes.length === 0 ? 'No profile types found' : 'Select profile type'}
profileTypes={profileTypes}
initialProfileTypeId={query.profileTypeId}
onChange={(val) => {
onChange({ ...query, profileTypeId: val });
}}
/>
);
}
return (
<EditorRows>
<EditorRow stackProps={{ wrap: false, gap: 1 }}>
{/*
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 ? (
<ProfileTypesCascader
profileTypes={profileTypes}
initialProfileTypeId={query.profileTypeId}
onChange={(val) => {
onChange({ ...query, profileTypeId: val });
}}
/>
) : (
<LoadingPlaceholder text={'Loading'} />
)}
{cascader}
<LabelsEditor
value={query.labelSelector}
onChange={onLabelSelectorChange}
@ -98,7 +101,7 @@ function defaultProfileType(profileTypes: ProfileTypeMessage[]): string {
}
// Fallback to first profile type from response data
return profileTypes[0].id;
return profileTypes[0]?.id || '';
}
function useLabels(