Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into task/olm-956-even…
Browse files Browse the repository at this point in the history
…t-filter-delete
  • Loading branch information
paul-tavares committed May 11, 2021
2 parents af8dacc + 6e8ccdb commit 1de90c7
Show file tree
Hide file tree
Showing 116 changed files with 3,903 additions and 683 deletions.
21 changes: 11 additions & 10 deletions api_docs/spaces_oss.json
Original file line number Diff line number Diff line change
Expand Up @@ -577,15 +577,11 @@
"deprecated": false,
"children": [
{
"parentPluginId": "spacesOss",
"id": "def-public.SpacesApi.activeSpace$",
"type": "Object",
"tags": [],
"label": "activeSpace$",
"description": [
"\nObservable representing the currently active space.\nThe details of the space can change without a full page reload (such as display name, color, etc.)"
],
"id": "def-public.SpacesApi.getActiveSpace$",
"type": "Function",
"label": "getActiveSpace$",
"signature": [
"() => ",
"Observable",
"<",
{
Expand All @@ -597,11 +593,16 @@
},
">"
],
"description": [
"\nObservable representing the currently active space.\nThe details of the space can change without a full page reload (such as display name, color, etc.)"
],
"children": [],
"tags": [],
"returnComment": [],
"source": {
"path": "src/plugins/spaces_oss/public/api.ts",
"lineNumber": 22
},
"deprecated": false
}
},
{
"parentPluginId": "spacesOss",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export default function (/* { providerAPI } */) {
-----------

**Services**:::
Services are named singleton values produced by a Service Provider. Tests and other services can retrieve service instances by asking for them by name. All functionality except the mocha API is exposed via services.\
Services are named singleton values produced by a Service Provider. Tests and other services can retrieve service instances by asking for them by name. All functionality except the mocha API is exposed via services.

**Page objects**:::
Page objects are a special type of service that encapsulate behaviors common to a particular page or plugin. When you write your own plugin, you’ll likely want to add a page object (or several) that describes the common interactions your tests need to execute.
Expand Down
19 changes: 12 additions & 7 deletions docs/user/dashboard/tsvb.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
=== TSVB

*TSVB* enables you to visualize the data from multiple data series, supports <<aggregation-reference,
most {es} metric aggregations>>, multiple visualization types, custom functions, and some math. To use *TSVB*, your data must have a date field.
most {es} metric aggregations>>, multiple visualization types, custom functions, and some math.
To create *TSVB* visualization panels, your data must have a time field.

[role="screenshot"]
image::visualize/images/tsvb-screenshot.png[TSVB overview]
Expand All @@ -17,15 +18,19 @@ Open *TSVB*, then make sure the required settings are configured.

. On the *New visualization* window, click *TSVB*.

. In *TSVB*, click *Panel options*, then make sure the following settings are configured:
. In *TSVB*, click *Panel options*, then specify the required *Data* settings.

* *Index pattern*
* *Time field*
* *Interval*
.. From the *Index pattern* dropdown, select the index pattern you want to visualize.
+
To visualize an {es} index, open the *Index pattern select mode* menu, deselect *Use only {kib} index patterns*, then enter the {es} index.

.. From the *Time field* dropdown, select the field you want to visualize, then enter the field *Interval*.

. Select a *Drop last bucket* option. It is dropped by default because the time filter intersects the time range of the last bucket, but can be enabled to see the partial data.
.. Select a *Drop last bucket* option.
+
By default, *TSVB* drops the last bucket because the time filter intersects the time range of the last bucket. To view the partial data, select *No*.

. In the *Panel filter* field, specify any <<kuery-query, KQL filters>> to select specific documents.
.. In the *Panel filter* field, enter <<kuery-query, KQL filters>> to view specific documents.

[float]
[[configure-the-data-series]]
Expand Down
10 changes: 0 additions & 10 deletions examples/search_examples/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,7 @@
* Side Public License, v 1.
*/

import { IEsSearchResponse, IEsSearchRequest } from '../../../src/plugins/data/common';

export const PLUGIN_ID = 'searchExamples';
export const PLUGIN_NAME = 'Search Examples';

export interface IMyStrategyRequest extends IEsSearchRequest {
get_cool: boolean;
}
export interface IMyStrategyResponse extends IEsSearchResponse {
cool: string;
executed_at: number;
}

export const SERVER_SEARCH_ROUTE_PATH = '/api/examples/search';
26 changes: 26 additions & 0 deletions examples/search_examples/common/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import {
IEsSearchRequest,
IEsSearchResponse,
IKibanaSearchRequest,
IKibanaSearchResponse,
} from '../../../src/plugins/data/common';

export interface IMyStrategyRequest extends IEsSearchRequest {
get_cool: boolean;
}
export interface IMyStrategyResponse extends IEsSearchResponse {
cool: string;
executed_at: number;
}

export type FibonacciRequest = IKibanaSearchRequest<{ n: number }>;

export type FibonacciResponse = IKibanaSearchResponse<{ values: number[] }>;
110 changes: 96 additions & 14 deletions examples/search_examples/public/search/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,27 @@ import {
EuiCode,
EuiComboBox,
EuiFormLabel,
EuiFieldNumber,
EuiProgress,
EuiTabbedContent,
EuiTabbedContentTab,
} from '@elastic/eui';

import { CoreStart } from '../../../../src/core/public';
import { mountReactNode } from '../../../../src/core/public/utils';
import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public';

import {
PLUGIN_ID,
PLUGIN_NAME,
IMyStrategyResponse,
SERVER_SEARCH_ROUTE_PATH,
} from '../../common';
import { PLUGIN_ID, PLUGIN_NAME, SERVER_SEARCH_ROUTE_PATH } from '../../common';

import {
DataPublicPluginStart,
IKibanaSearchResponse,
IndexPattern,
IndexPatternField,
isCompleteResponse,
isErrorResponse,
} from '../../../../src/plugins/data/public';
import { IMyStrategyResponse } from '../../common/types';

interface SearchExamplesAppDeps {
notifications: CoreStart['notifications'];
Expand Down Expand Up @@ -88,7 +88,10 @@ export const SearchExamplesApp = ({
}: SearchExamplesAppDeps) => {
const { IndexPatternSelect } = data.ui;
const [getCool, setGetCool] = useState<boolean>(false);
const [fibonacciN, setFibonacciN] = useState<number>(10);
const [timeTook, setTimeTook] = useState<number | undefined>();
const [total, setTotal] = useState<number>(100);
const [loaded, setLoaded] = useState<number>(0);
const [indexPattern, setIndexPattern] = useState<IndexPattern | null>();
const [fields, setFields] = useState<IndexPatternField[]>();
const [selectedFields, setSelectedFields] = useState<IndexPatternField[]>([]);
Expand All @@ -99,7 +102,15 @@ export const SearchExamplesApp = ({
IndexPatternField | null | undefined
>();
const [request, setRequest] = useState<Record<string, any>>({});
const [response, setResponse] = useState<Record<string, any>>({});
const [rawResponse, setRawResponse] = useState<Record<string, any>>({});
const [selectedTab, setSelectedTab] = useState(0);

function setResponse(response: IKibanaSearchResponse) {
setRawResponse(response.rawResponse);
setLoaded(response.loaded!);
setTotal(response.total!);
setTimeTook(response.rawResponse.took);
}

// Fetch the default index pattern using the `data.indexPatterns` service, as the component is mounted.
useEffect(() => {
Expand Down Expand Up @@ -152,8 +163,7 @@ export const SearchExamplesApp = ({
.subscribe({
next: (res) => {
if (isCompleteResponse(res)) {
setResponse(res.rawResponse);
setTimeTook(res.rawResponse.took);
setResponse(res);
const avgResult: 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
Expand Down Expand Up @@ -234,7 +244,7 @@ export const SearchExamplesApp = ({

setRequest(searchSource.getSearchRequestBody());
const { rawResponse: res } = await searchSource.fetch$().toPromise();
setResponse(res);
setRawResponse(res);

const message = <EuiText>Searched {res.hits.total} documents.</EuiText>;
notifications.toasts.addSuccess(
Expand All @@ -247,7 +257,7 @@ export const SearchExamplesApp = ({
}
);
} catch (e) {
setResponse(e.body);
setRawResponse(e.body);
notifications.toasts.addWarning(`An error has occurred: ${e.message}`);
}
};
Expand All @@ -260,6 +270,41 @@ export const SearchExamplesApp = ({
doAsyncSearch('myStrategy');
};

const onPartialResultsClickHandler = () => {
setSelectedTab(1);
const req = {
params: {
n: fibonacciN,
},
};

// Submit the search request using the `data.search` service.
setRequest(req.params);
const searchSubscription$ = data.search
.search(req, {
strategy: 'fibonacciStrategy',
})
.subscribe({
next: (res) => {
setResponse(res);
if (isCompleteResponse(res)) {
notifications.toasts.addSuccess({
title: 'Query result',
text: 'Query finished',
});
searchSubscription$.unsubscribe();
} else if (isErrorResponse(res)) {
// TODO: Make response error status clearer
notifications.toasts.addWarning('An error has occurred');
searchSubscription$.unsubscribe();
}
},
error: () => {
notifications.toasts.addDanger('Failed to run search');
},
});
};

const onClientSideSessionCacheClickHandler = () => {
doAsyncSearch('myStrategy', data.search.session.getSessionId());
};
Expand All @@ -284,7 +329,7 @@ export const SearchExamplesApp = ({
doSearchSourceSearch(withOtherBucket);
};

const reqTabs = [
const reqTabs: EuiTabbedContentTab[] = [
{
id: 'request',
name: <EuiText data-test-subj="requestTab">Request</EuiText>,
Expand Down Expand Up @@ -318,6 +363,7 @@ export const SearchExamplesApp = ({
values={{ time: timeTook ?? 'Unknown' }}
/>
</EuiText>
<EuiProgress value={loaded} max={total} size="xs" data-test-subj="progressBar" />
<EuiCodeBlock
language="json"
fontSize="s"
Expand All @@ -326,7 +372,7 @@ export const SearchExamplesApp = ({
isCopyable
data-test-subj="responseCodeBlock"
>
{JSON.stringify(response, null, 2)}
{JSON.stringify(rawResponse, null, 2)}
</EuiCodeBlock>
</>
),
Expand Down Expand Up @@ -484,6 +530,37 @@ export const SearchExamplesApp = ({
</EuiText>
</EuiText>
<EuiSpacer />
<EuiTitle size="xs">
<h3>Handling partial results</h3>
</EuiTitle>
<EuiText>
The observable returned from <EuiCode>data.search</EuiCode> provides partial results
when the response is not yet complete. These can be handled to update a chart or
simply a progress bar:
<EuiSpacer />
<EuiCodeBlock language="html" fontSize="s" paddingSize="s" overflowHeight={450}>
&lt;EuiProgress value=&#123;response.loaded&#125; max=&#123;response.total&#125;
/&gt;
</EuiCodeBlock>
Below is an example showing a custom search strategy that emits partial Fibonacci
sequences up to the length provided, updates the response with each partial result,
and updates a progress bar (see the Response tab).
<EuiFieldNumber
id="FibonacciN"
placeholder="Number of Fibonacci numbers to generate"
value={fibonacciN}
onChange={(event) => setFibonacciN(parseInt(event.target.value, 10))}
/>
<EuiButtonEmpty
size="xs"
onClick={onPartialResultsClickHandler}
iconType="play"
data-test-subj="requestFibonacci"
>
Request Fibonacci sequence
</EuiButtonEmpty>
</EuiText>
<EuiSpacer />
<EuiTitle size="s">
<h3>Writing a custom search strategy</h3>
</EuiTitle>
Expand Down Expand Up @@ -567,8 +644,13 @@ export const SearchExamplesApp = ({
</EuiButtonEmpty>
</EuiText>
</EuiFlexItem>

<EuiFlexItem style={{ width: '60%' }}>
<EuiTabbedContent tabs={reqTabs} />
<EuiTabbedContent
tabs={reqTabs}
selectedTab={reqTabs[selectedTab]}
onTabClick={(tab) => setSelectedTab(reqTabs.indexOf(tab))}
/>
</EuiFlexItem>
</EuiFlexGrid>
</EuiPageContentBody>
Expand Down
52 changes: 52 additions & 0 deletions examples/search_examples/server/fibonacci_strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import uuid from 'uuid';
import { ISearchStrategy } from '../../../src/plugins/data/server';
import { FibonacciRequest, FibonacciResponse } from '../common/types';

export const fibonacciStrategyProvider = (): ISearchStrategy<
FibonacciRequest,
FibonacciResponse
> => {
const responseMap = new Map<string, [number[], number, number]>();
return ({
search: (request: FibonacciRequest) => {
const id = request.id ?? uuid();
const [sequence, total, started] = responseMap.get(id) ?? [
[],
request.params?.n ?? 0,
Date.now(),
];
if (sequence.length < 2) {
if (total > 0) sequence.push(sequence.length);
} else {
const [a, b] = sequence.slice(-2);
sequence.push(a + b);
}
const loaded = sequence.length;
responseMap.set(id, [sequence, total, started]);
if (loaded >= total) {
responseMap.delete(id);
}

const isRunning = loaded < total;
const isPartial = isRunning;
const took = Date.now() - started;
const values = sequence.slice(0, loaded);

// Usually we'd do something like "of()" but for some reason it breaks in tests with the error
// "You provided an invalid object where a stream was expected." which is why we have to cast
// down below as well
return [{ id, loaded, total, isRunning, isPartial, rawResponse: { took, values } }];
},
cancel: async (id: string) => {
responseMap.delete(id);
},
} as unknown) as ISearchStrategy<FibonacciRequest, FibonacciResponse>;
};
Loading

0 comments on commit 1de90c7

Please sign in to comment.