Skip to content

Commit

Permalink
Merge branch 'main' into 137759-support-stack-aligned-bundled-package…
Browse files Browse the repository at this point in the history
…-versions
  • Loading branch information
kibanamachine authored Aug 31, 2022
2 parents 3e060fa + 160058a commit 796431d
Show file tree
Hide file tree
Showing 201 changed files with 3,999 additions and 987 deletions.
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ x-pack/examples/files_example @elastic/kibana-app-services
/src/core/types/elasticsearch @elastic/apm-ui
/packages/kbn-apm-synthtrace/ @elastic/apm-ui
/packages/kbn-shared-svg @elastic/apm-ui
/packages/kbn-utility-types/src/dot.ts @dgieselaar
/packages/kbn-utility-types/src/dot_test.ts @dgieselaar
#CC# /src/plugins/apm_oss/ @elastic/apm-ui
#CC# /x-pack/plugins/observability/ @elastic/apm-ui

Expand Down
2 changes: 1 addition & 1 deletion examples/search_examples/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"description": "Example plugin of how to use data plugin search services",
"server": true,
"ui": true,
"requiredPlugins": ["navigation", "data", "developerExamples", "kibanaUtils", "share", "unifiedSearch"],
"requiredPlugins": ["navigation", "data", "developerExamples", "inspector", "kibanaUtils", "share", "unifiedSearch"],
"optionalPlugins": [],
"requiredBundles": ["kibanaReact"],
"owner": {
Expand Down
200 changes: 118 additions & 82 deletions examples/search_examples/public/search/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,48 @@
* Side Public License, v 1.
*/

import React, { useState, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';

import {
EuiButtonEmpty,
EuiCheckbox,
EuiCode,
EuiCodeBlock,
EuiComboBox,
EuiFieldNumber,
EuiFlexGrid,
EuiFlexItem,
EuiFormLabel,
EuiHorizontalRule,
EuiPageBody,
EuiPageContent,
EuiPageContentBody,
EuiPageHeader,
EuiTitle,
EuiText,
EuiFlexGrid,
EuiFlexItem,
EuiCheckbox,
EuiSpacer,
EuiCode,
EuiComboBox,
EuiFormLabel,
EuiFieldNumber,
EuiProgress,
EuiSpacer,
EuiTabbedContent,
EuiTabbedContentTab,
EuiText,
EuiTitle,
} from '@elastic/eui';

import { lastValueFrom } from 'rxjs';
import { CoreStart } from '@kbn/core/public';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';

import { IInspectorInfo } from '@kbn/data-plugin/common';
import {
DataPublicPluginStart,
IKibanaSearchResponse,
isCompleteResponse,
isErrorResponse,
} from '@kbn/data-plugin/public';
import { SearchResponseWarning } from '@kbn/data-plugin/public/search/types';
import type { DataView, DataViewField } from '@kbn/data-views-plugin/public';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { RequestAdapter } from '@kbn/inspector-plugin/common';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
import type { DataViewField, DataView } from '@kbn/data-views-plugin/public';
import { AbortError } from '@kbn/kibana-utils-plugin/common';
import { IMyStrategyResponse } from '../../common/types';
import React, { useEffect, useState } from 'react';
import { lastValueFrom } from 'rxjs';
import { PLUGIN_ID, PLUGIN_NAME, SERVER_SEARCH_ROUTE_PATH } from '../../common';
import { IMyStrategyResponse } from '../../common/types';

interface SearchExamplesAppDeps {
notifications: CoreStart['notifications'];
Expand Down Expand Up @@ -82,6 +82,9 @@ function formatFieldsToComboBox(fields?: DataViewField[]) {
});
}

const bucketAggType = 'terms';
const metricAggType = 'median';

export const SearchExamplesApp = ({
http,
notifications,
Expand All @@ -108,9 +111,11 @@ export const SearchExamplesApp = ({
const [isLoading, setIsLoading] = useState<boolean>(false);
const [currentAbortController, setAbortController] = useState<AbortController>();
const [rawResponse, setRawResponse] = useState<Record<string, any>>({});
const [warningContents, setWarningContents] = useState<SearchResponseWarning[]>([]);
const [selectedTab, setSelectedTab] = useState(0);

function setResponse(response: IKibanaSearchResponse) {
setWarningContents([]);
setRawResponse(response.rawResponse);
setLoaded(response.loaded!);
setTotal(response.total!);
Expand Down Expand Up @@ -177,7 +182,7 @@ export const SearchExamplesApp = ({
}

// Construct the aggregations portion of the search request by using the `data.search.aggs` service.
const aggs = [{ type: 'avg', params: { field: selectedNumericField!.name } }];
const aggs = [{ type: metricAggType, params: { field: selectedNumericField!.name } }];
const aggsDsl = data.search.aggs.createAggConfigs(dataView, aggs).toDsl();

const req = {
Expand Down Expand Up @@ -210,7 +215,7 @@ export const SearchExamplesApp = ({
if (isCompleteResponse(res)) {
setIsLoading(false);
setResponse(res);
const avgResult: number | undefined = res.rawResponse.aggregations
const aggResult: number | undefined = res.rawResponse.aggregations
? // @ts-expect-error @elastic/elasticsearch no way to declare a type for aggregation in the search response
res.rawResponse.aggregations[1].value
: undefined;
Expand All @@ -219,8 +224,8 @@ export const SearchExamplesApp = ({
const message = (
<EuiText>
Searched {res.rawResponse.hits.total} documents. <br />
The average of {selectedNumericField!.name} is{' '}
{avgResult ? Math.floor(avgResult) : 0}.
The ${metricAggType} of {selectedNumericField!.name} is{' '}
{aggResult ? Math.floor(aggResult) : 0}.
<br />
{isCool ? `Is it Cool? ${isCool}` : undefined}
<br />
Expand Down Expand Up @@ -251,21 +256,15 @@ export const SearchExamplesApp = ({
},
error: (e) => {
setIsLoading(false);
if (e instanceof AbortError) {
notifications.toasts.addWarning({
title: e.message,
});
} else {
notifications.toasts.addDanger({
title: 'Failed to run search',
text: e.message,
});
}
data.search.showError(e);
},
});
};

const doSearchSourceSearch = async (otherBucket: boolean) => {
const doSearchSourceSearch = async (
otherBucket: boolean,
showWarningToastNotifications = true
) => {
if (!dataView) return;

const query = data.query.queryString.getQuery();
Expand All @@ -289,29 +288,58 @@ export const SearchExamplesApp = ({
const aggDef = [];
if (selectedBucketField) {
aggDef.push({
type: 'terms',
type: bucketAggType,
schema: 'split',
params: { field: selectedBucketField.name, size: 2, otherBucket },
});
}
if (selectedNumericField) {
aggDef.push({ type: 'avg', params: { field: selectedNumericField.name } });
aggDef.push({ type: metricAggType, params: { field: selectedNumericField.name } });
}
if (aggDef.length > 0) {
const ac = data.search.aggs.createAggConfigs(dataView, aggDef);
searchSource.setField('aggs', ac);
}

setRequest(searchSource.getSearchRequestBody());
const abortController = new AbortController();

const inspector: Required<IInspectorInfo> = {
adapter: new RequestAdapter(),
title: 'Example App Inspector!',
id: 'greatest-example-app-inspector',
description: 'Use the `description` field for more info about the inspector.',
};

setAbortController(abortController);
setIsLoading(true);
const { rawResponse: res } = await lastValueFrom(
searchSource.fetch$({ abortSignal: abortController.signal })
const result = await lastValueFrom(
searchSource.fetch$({
abortSignal: abortController.signal,
disableShardFailureWarning: !showWarningToastNotifications,
inspector,
})
);
setRawResponse(res);
setRawResponse(result.rawResponse);

/* Here is an example of using showWarnings on the search service, using an optional callback to
* intercept the warnings before notification warnings are shown.
*
* Suppressing the shard failure warning notification from appearing by default requires setting
* { disableShardFailureWarning: true } in the SearchSourceSearchOptions passed to $fetch
*/
if (showWarningToastNotifications) {
setWarningContents([]);
} else {
const warnings: SearchResponseWarning[] = [];
data.search.showWarnings(inspector.adapter, (warning) => {
warnings.push(warning);
return false; // allow search service from showing this warning on its own
});
// click the warnings tab to see the warnings
setWarningContents(warnings);
}

const message = <EuiText>Searched {res.hits.total} documents.</EuiText>;
const message = <EuiText>Searched {result.rawResponse.hits.total} documents.</EuiText>;
notifications.toasts.addSuccess(
{
title: 'Query result',
Expand All @@ -323,16 +351,7 @@ export const SearchExamplesApp = ({
);
} catch (e) {
setRawResponse(e.body);
if (e instanceof AbortError) {
notifications.toasts.addWarning({
title: e.message,
});
} else {
notifications.toasts.addDanger({
title: 'Failed to run search',
text: e.message,
});
}
data.search.showError(e);
} finally {
setIsLoading(false);
}
Expand Down Expand Up @@ -390,16 +409,7 @@ export const SearchExamplesApp = ({
},
error: (e) => {
setIsLoading(false);
if (e instanceof AbortError) {
notifications.toasts.addWarning({
title: e.message,
});
} else {
notifications.toasts.addDanger({
title: 'Failed to run search',
text: e.message,
});
}
data.search.showError(e);
},
});
};
Expand All @@ -424,23 +434,17 @@ export const SearchExamplesApp = ({

notifications.toasts.addSuccess(`Server returned ${JSON.stringify(res)}`);
} catch (e) {
if (e?.name === 'AbortError') {
notifications.toasts.addWarning({
title: e.message,
});
} else {
notifications.toasts.addDanger({
title: 'Failed to run search',
text: e.message,
});
}
data.search.showError(e);
} finally {
setIsLoading(false);
}
};

const onSearchSourceClickHandler = (withOtherBucket: boolean) => {
doSearchSourceSearch(withOtherBucket);
const onSearchSourceClickHandler = (
withOtherBucket: boolean,
showWarningToastNotifications: boolean
) => {
doSearchSourceSearch(withOtherBucket, showWarningToastNotifications);
};

const reqTabs: EuiTabbedContentTab[] = [
Expand Down Expand Up @@ -491,6 +495,35 @@ export const SearchExamplesApp = ({
</>
),
},
{
id: 'warnings',
name: <EuiText data-test-subj="warningsTab">Warnings</EuiText>,
content: (
<>
{' '}
<EuiSpacer />{' '}
<EuiText size="xs">
{' '}
<FormattedMessage
id="searchExamples.warningsObject"
defaultMessage="Timeout and shard failure warnings for high-level search may be handled in a callback to the showWarnings method on the search service."
/>{' '}
</EuiText>{' '}
<EuiProgress value={loaded} max={total} size="xs" data-test-subj="progressBar" />{' '}
<EuiCodeBlock
language="json"
fontSize="s"
paddingSize="s"
overflowHeight={450}
isCopyable
data-test-subj="warningsCodeBlock"
>
{' '}
{JSON.stringify(warningContents, null, 2)}{' '}
</EuiCodeBlock>{' '}
</>
),
},
];

return (
Expand Down Expand Up @@ -535,7 +568,7 @@ export const SearchExamplesApp = ({
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormLabel>Field (bucket)</EuiFormLabel>
<EuiFormLabel>Field (using {bucketAggType} buckets)</EuiFormLabel>
<EuiComboBox
options={formatFieldsToComboBox(getAggregatableStrings(fields))}
selectedOptions={formatFieldToComboBox(selectedBucketField)}
Expand All @@ -553,7 +586,7 @@ export const SearchExamplesApp = ({
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormLabel>Numeric Field (metric)</EuiFormLabel>
<EuiFormLabel>Numeric Field (using {metricAggType} metrics)</EuiFormLabel>
<EuiComboBox
options={formatFieldsToComboBox(getNumeric(fields))}
selectedOptions={formatFieldToComboBox(selectedNumericField)}
Expand Down Expand Up @@ -586,6 +619,9 @@ export const SearchExamplesApp = ({
/>
</EuiFlexItem>
</EuiFlexGrid>

<EuiHorizontalRule />

<EuiFlexGrid columns={2}>
<EuiFlexItem style={{ width: '40%' }}>
<EuiSpacer />
Expand Down Expand Up @@ -613,7 +649,7 @@ export const SearchExamplesApp = ({
</EuiText>
<EuiButtonEmpty
size="xs"
onClick={() => onSearchSourceClickHandler(true)}
onClick={() => onSearchSourceClickHandler(true, true)}
iconType="play"
data-test-subj="searchSourceWithOther"
>
Expand All @@ -625,12 +661,12 @@ export const SearchExamplesApp = ({
<EuiText size="xs" color="subdued" className="searchExampleStepDsc">
<FormattedMessage
id="searchExamples.buttonText"
defaultMessage="Bucket and metrics aggregations with other bucket."
defaultMessage="Bucket and metrics aggregations, with other bucket and default warnings."
/>
</EuiText>
<EuiButtonEmpty
size="xs"
onClick={() => onSearchSourceClickHandler(false)}
onClick={() => onSearchSourceClickHandler(false, false)}
iconType="play"
data-test-subj="searchSourceWithoutOther"
>
Expand All @@ -642,7 +678,7 @@ export const SearchExamplesApp = ({
<EuiText size="xs" color="subdued" className="searchExampleStepDsc">
<FormattedMessage
id="searchExamples.buttonText"
defaultMessage="Bucket and metrics aggregations without other bucket."
defaultMessage="Bucket and metrics aggregations, without other bucket and with custom logic to handle warnings."
/>
</EuiText>
</EuiText>
Expand Down
Loading

0 comments on commit 796431d

Please sign in to comment.