diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/breakdown.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/breakdown.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/breakdown.ts rename to x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/breakdown.ts diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/normalize_indices.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/normalize_indices.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/normalize_indices.ts rename to x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/normalize_indices.ts diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/normalize_times.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/normalize_times.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/normalize_times.ts rename to x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/normalize_times.ts diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/processed_search_response.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/processed_search_response.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/processed_search_response.ts rename to x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/processed_search_response.ts diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/search_response.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/search_response.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/fixtures/search_response.ts rename to x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/fixtures/search_response.ts diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/init_data.test.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/init_data.test.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/init_data.test.ts rename to x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/init_data.test.ts diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/profile_tree.test.tsx b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/profile_tree.test.tsx similarity index 89% rename from x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/profile_tree.test.tsx rename to x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/profile_tree.test.tsx index 1286f30d69c26..64f77e8b4e52c 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/profile_tree.test.tsx +++ b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/profile_tree.test.tsx @@ -14,6 +14,7 @@ describe('ProfileTree', () => { onHighlight: () => {}, target: 'searches', data: searchResponse, + onDataInitError: jest.fn(), }; const init = registerTestBed(ProfileTree); await init(props); @@ -24,10 +25,12 @@ describe('ProfileTree', () => { const props: Props = { onHighlight: () => {}, target: 'searches', + onDataInitError: jest.fn(), data: [{}] as any, }; const init = registerTestBed(ProfileTree); await init(props); + expect(props.onDataInitError).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/unsafe_utils.test.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/unsafe_utils.test.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/unsafe_utils.test.ts rename to x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/unsafe_utils.test.ts diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/utils.test.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/utils.test.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/components/profile_tree/__tests__/utils.test.ts rename to x-pack/plugins/searchprofiler/public/application/components/profile_tree/__jest__/utils.test.ts diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/profile_tree.tsx b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/profile_tree.tsx index 1dec8f0161c52..ade547a7d440f 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/profile_tree.tsx +++ b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/profile_tree.tsx @@ -17,9 +17,10 @@ export interface Props { target: Targets; data: ShardSerialized[] | null; onHighlight: (args: OnHighlightChangeArgs) => void; + onDataInitError: (error: Error) => void; } -export const ProfileTree = memo(({ data, target, onHighlight }: Props) => { +export const ProfileTree = memo(({ data, target, onHighlight, onDataInitError }: Props) => { if (!data || data.length === 0) { return null; } @@ -28,8 +29,7 @@ export const ProfileTree = memo(({ data, target, onHighlight }: Props) => { try { sortedIndices = initDataFor(target)(data); } catch (e) { - // eslint-disable-next-line no-console - console.error(e); + onDataInitError(e); return null; } diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/shard_details/shard_details.tsx b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/shard_details/shard_details.tsx index 5ca8ad4ecd979..ac2a2997515d5 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_tree/shard_details/shard_details.tsx +++ b/x-pack/plugins/searchprofiler/public/application/components/profile_tree/shard_details/shard_details.tsx @@ -18,10 +18,24 @@ interface Props { operations: Operation[]; } +const hasVisibleOperation = (ops: Operation[]): boolean => { + for (const op of ops) { + if (op.visible) { + return true; + } + if (op.children?.length && hasVisibleOperation(op.children)) { + return true; + } + } + return false; +}; + export const ShardDetails = ({ index, shard, operations }: Props) => { const { relative, time } = shard; - const [shardVisibility, setShardVisibility] = useState(false); + const [shardVisibility, setShardVisibility] = useState(() => + hasVisibleOperation(operations.map(op => op.treeRoot ?? op)) + ); return ( <> diff --git a/x-pack/plugins/searchprofiler/public/application/containers/main/main.tsx b/x-pack/plugins/searchprofiler/public/application/containers/main/main.tsx index aa6c20aa6a7f3..11dbc6b320531 100644 --- a/x-pack/plugins/searchprofiler/public/application/containers/main/main.tsx +++ b/x-pack/plugins/searchprofiler/public/application/containers/main/main.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import React, { useCallback } from 'react'; import { @@ -33,7 +34,7 @@ import { useProfilerActionContext, useProfilerReadContext } from '../../contexts import { hasAggregations, hasSearch } from '../../utils'; export const Main = () => { - const { getLicenseStatus } = useAppContext(); + const { getLicenseStatus, notifications } = useAppContext(); const { activeTab, @@ -42,8 +43,17 @@ export const Main = () => { pristine, profiling, } = useProfilerReadContext(); + const dispatch = useProfilerActionContext(); + const handleProfileTreeError = (e: Error) => { + notifications.addError(e, { + title: i18n.translate('xpack.searchProfiler.profileTreeErrorRenderTitle', { + defaultMessage: 'Profile data cannot be parsed.', + }), + }); + }; + const setActiveTab = useCallback( (target: Targets) => dispatch({ type: 'setActiveTab', value: target }), [dispatch] @@ -70,7 +80,12 @@ export const Main = () => { if (activeTab) { return (
- +
); } diff --git a/x-pack/plugins/searchprofiler/public/application/hooks/use_request_profile.ts b/x-pack/plugins/searchprofiler/public/application/hooks/use_request_profile.ts index 3d8bee1d62b27..435db4a98c552 100644 --- a/x-pack/plugins/searchprofiler/public/application/hooks/use_request_profile.ts +++ b/x-pack/plugins/searchprofiler/public/application/hooks/use_request_profile.ts @@ -22,7 +22,9 @@ interface ReturnValue { const extractProfilerErrorMessage = (e: any): string | undefined => { if (e.body?.attributes?.error?.reason) { const { reason, line, col } = e.body.attributes.error; - return `${reason} at line: ${line - 1} col: ${col}`; + if (typeof line === 'number' && typeof col === 'number') { + return `${reason} at line: ${line - 1} col: ${col}`; + } } if (e.body?.message) { diff --git a/x-pack/plugins/searchprofiler/public/application/types.ts b/x-pack/plugins/searchprofiler/public/application/types.ts index 9866f8d5b1ccb..896af0851eb52 100644 --- a/x-pack/plugins/searchprofiler/public/application/types.ts +++ b/x-pack/plugins/searchprofiler/public/application/types.ts @@ -49,7 +49,14 @@ export interface Operation { parent: Operation | null; children: Operation[]; - // Only exists on top level + /** + * Only exists on top level. + * + * @remark + * For now, when we init profile data for rendering we take a top-level + * operation and designate it the root of the operations tree - this is not + * information we get from ES. + */ treeRoot?: Operation; depth?: number;