mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
Update example plugins to stop using deprecated APIs (#121547)
This commit is contained in:
parent
f1bb5ea96c
commit
2fa5a87a5f
18 changed files with 199 additions and 208 deletions
|
@ -20,23 +20,20 @@ import {
|
||||||
DefaultItemAction,
|
DefaultItemAction,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
import { AppMountParameters } from '../../../src/core/public';
|
import { AppMountParameters } from '../../../src/core/public';
|
||||||
import {
|
import { DataPublicPluginStart } from '../../../src/plugins/data/public';
|
||||||
DataPublicPluginStart,
|
import type { DataView, DataViewField } from '../../../src/plugins/data_views/public';
|
||||||
IndexPattern,
|
|
||||||
IndexPatternField,
|
|
||||||
} from '../../../src/plugins/data/public';
|
|
||||||
import { IndexPatternFieldEditorStart } from '../../../src/plugins/data_view_field_editor/public';
|
import { IndexPatternFieldEditorStart } from '../../../src/plugins/data_view_field_editor/public';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
indexPattern?: IndexPattern;
|
dataView?: DataView;
|
||||||
dataViewFieldEditor: IndexPatternFieldEditorStart;
|
dataViewFieldEditor: IndexPatternFieldEditorStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IndexPatternFieldEditorExample = ({ indexPattern, dataViewFieldEditor }: Props) => {
|
const DataViewFieldEditorExample = ({ dataView, dataViewFieldEditor }: Props) => {
|
||||||
const [fields, setFields] = useState<IndexPatternField[]>(
|
const [fields, setFields] = useState<DataViewField[]>(
|
||||||
indexPattern?.getNonScriptedFields() || []
|
dataView?.fields.getAll().filter((f) => !f.scripted) || []
|
||||||
);
|
);
|
||||||
const refreshFields = () => setFields(indexPattern?.getNonScriptedFields() || []);
|
const refreshFields = () => setFields(dataView?.fields.getAll().filter((f) => !f.scripted) || []);
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
field: 'name',
|
field: 'name',
|
||||||
|
@ -51,9 +48,9 @@ const IndexPatternFieldEditorExample = ({ indexPattern, dataViewFieldEditor }: P
|
||||||
icon: 'pencil',
|
icon: 'pencil',
|
||||||
type: 'icon',
|
type: 'icon',
|
||||||
'data-test-subj': 'editField',
|
'data-test-subj': 'editField',
|
||||||
onClick: (fld: IndexPatternField) =>
|
onClick: (fld: DataViewField) =>
|
||||||
dataViewFieldEditor.openEditor({
|
dataViewFieldEditor.openEditor({
|
||||||
ctx: { dataView: indexPattern! },
|
ctx: { dataView: dataView! },
|
||||||
fieldName: fld.name,
|
fieldName: fld.name,
|
||||||
onSave: refreshFields,
|
onSave: refreshFields,
|
||||||
}),
|
}),
|
||||||
|
@ -65,27 +62,27 @@ const IndexPatternFieldEditorExample = ({ indexPattern, dataViewFieldEditor }: P
|
||||||
type: 'icon',
|
type: 'icon',
|
||||||
'data-test-subj': 'deleteField',
|
'data-test-subj': 'deleteField',
|
||||||
available: (fld) => !!fld.runtimeField,
|
available: (fld) => !!fld.runtimeField,
|
||||||
onClick: (fld: IndexPatternField) =>
|
onClick: (fld: DataViewField) =>
|
||||||
dataViewFieldEditor.openDeleteModal({
|
dataViewFieldEditor.openDeleteModal({
|
||||||
fieldName: fld.name,
|
fieldName: fld.name,
|
||||||
ctx: {
|
ctx: {
|
||||||
dataView: indexPattern!,
|
dataView: dataView!,
|
||||||
},
|
},
|
||||||
onDelete: refreshFields,
|
onDelete: refreshFields,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
] as Array<DefaultItemAction<IndexPatternField>>,
|
] as Array<DefaultItemAction<DataViewField>>,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const content = indexPattern ? (
|
const content = dataView ? (
|
||||||
<>
|
<>
|
||||||
<EuiText data-test-subj="indexPatternTitle">Index pattern: {indexPattern?.title}</EuiText>
|
<EuiText data-test-subj="dataViewTitle">Data view: {dataView.title}</EuiText>
|
||||||
<div>
|
<div>
|
||||||
<EuiButton
|
<EuiButton
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
dataViewFieldEditor.openEditor({
|
dataViewFieldEditor.openEditor({
|
||||||
ctx: { dataView: indexPattern! },
|
ctx: { dataView },
|
||||||
onSave: refreshFields,
|
onSave: refreshFields,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -94,7 +91,7 @@ const IndexPatternFieldEditorExample = ({ indexPattern, dataViewFieldEditor }: P
|
||||||
Add field
|
Add field
|
||||||
</EuiButton>
|
</EuiButton>
|
||||||
</div>
|
</div>
|
||||||
<EuiInMemoryTable<IndexPatternField>
|
<EuiInMemoryTable<DataViewField>
|
||||||
items={fields}
|
items={fields}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={true}
|
pagination={true}
|
||||||
|
@ -108,13 +105,13 @@ const IndexPatternFieldEditorExample = ({ indexPattern, dataViewFieldEditor }: P
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<p>Please create an index pattern</p>
|
<p>Please create a data view</p>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EuiPage>
|
<EuiPage>
|
||||||
<EuiPageBody>
|
<EuiPageBody>
|
||||||
<EuiPageHeader>Index pattern field editor demo</EuiPageHeader>
|
<EuiPageHeader>Data view field editor demo</EuiPageHeader>
|
||||||
<EuiPageContent>
|
<EuiPageContent>
|
||||||
<EuiPageContentBody>{content}</EuiPageContentBody>
|
<EuiPageContentBody>{content}</EuiPageContentBody>
|
||||||
</EuiPageContent>
|
</EuiPageContent>
|
||||||
|
@ -132,12 +129,9 @@ export const renderApp = async (
|
||||||
{ data, dataViewFieldEditor }: RenderAppDependencies,
|
{ data, dataViewFieldEditor }: RenderAppDependencies,
|
||||||
{ element }: AppMountParameters
|
{ element }: AppMountParameters
|
||||||
) => {
|
) => {
|
||||||
const indexPattern = (await data.indexPatterns.getDefault()) || undefined;
|
const dataView = (await data.dataViews.getDefault()) || undefined;
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<IndexPatternFieldEditorExample
|
<DataViewFieldEditorExample dataView={dataView} dataViewFieldEditor={dataViewFieldEditor} />,
|
||||||
indexPattern={indexPattern}
|
|
||||||
dataViewFieldEditor={dataViewFieldEditor}
|
|
||||||
/>,
|
|
||||||
element
|
element
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,6 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IndexPatternFieldEditorPlugin } from './plugin';
|
import { DataViewFieldEditorPlugin } from './plugin';
|
||||||
|
|
||||||
export const plugin = () => new IndexPatternFieldEditorPlugin();
|
export const plugin = () => new DataViewFieldEditorPlugin();
|
||||||
|
|
|
@ -20,11 +20,11 @@ interface SetupDeps {
|
||||||
developerExamples: DeveloperExamplesSetup;
|
developerExamples: DeveloperExamplesSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IndexPatternFieldEditorPlugin implements Plugin<void, void, SetupDeps, StartDeps> {
|
export class DataViewFieldEditorPlugin implements Plugin<void, void, SetupDeps, StartDeps> {
|
||||||
public setup(core: CoreSetup<StartDeps>, deps: SetupDeps) {
|
public setup(core: CoreSetup<StartDeps>, deps: SetupDeps) {
|
||||||
core.application.register({
|
core.application.register({
|
||||||
id: 'indexPatternFieldEditorExample',
|
id: 'dataViewFieldEditorExample',
|
||||||
title: 'Index pattern field editor example',
|
title: 'Data view field editor example',
|
||||||
navLinkStatus: AppNavLinkStatus.hidden,
|
navLinkStatus: AppNavLinkStatus.hidden,
|
||||||
async mount(params: AppMountParameters) {
|
async mount(params: AppMountParameters) {
|
||||||
const [, depsStart] = await core.getStartServices();
|
const [, depsStart] = await core.getStartServices();
|
||||||
|
@ -34,13 +34,13 @@ export class IndexPatternFieldEditorPlugin implements Plugin<void, void, SetupDe
|
||||||
});
|
});
|
||||||
|
|
||||||
deps.developerExamples.register({
|
deps.developerExamples.register({
|
||||||
appId: 'indexPatternFieldEditorExample',
|
appId: 'dataViewFieldEditorExample',
|
||||||
title: 'Index pattern field editor',
|
title: 'Data view field editor',
|
||||||
description: `IndexPatternFieldEditor provides a UI for editing index pattern fields directly from Kibana apps. This example plugin demonstrates integration.`,
|
description: `DataViewFieldEditor provides a UI for editing data view fields directly from Kibana apps. This example plugin demonstrates integration.`,
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'README',
|
label: 'README',
|
||||||
href: 'https://github.com/elastic/kibana/blob/main/src/plugins/index_pattern_field_editor/README.md',
|
href: 'https://github.com/elastic/kibana/blob/main/src/plugins/data_view_field_editor/README.md',
|
||||||
iconType: 'logoGithub',
|
iconType: 'logoGithub',
|
||||||
size: 's',
|
size: 's',
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
{ "path": "../../src/core/tsconfig.json" },
|
{ "path": "../../src/core/tsconfig.json" },
|
||||||
{ "path": "../../src/plugins/kibana_react/tsconfig.json" },
|
{ "path": "../../src/plugins/kibana_react/tsconfig.json" },
|
||||||
{ "path": "../../src/plugins/data/tsconfig.json" },
|
{ "path": "../../src/plugins/data/tsconfig.json" },
|
||||||
|
{ "path": "../../src/plugins/data_views/tsconfig.json" },
|
||||||
{ "path": "../../src/plugins/data_view_field_editor/tsconfig.json" },
|
{ "path": "../../src/plugins/data_view_field_editor/tsconfig.json" },
|
||||||
{ "path": "../developer_examples/tsconfig.json" },
|
{ "path": "../developer_examples/tsconfig.json" },
|
||||||
]
|
]
|
||||||
|
|
|
@ -43,7 +43,7 @@ export interface Deps {
|
||||||
/**
|
/**
|
||||||
* Just for demo purposes
|
* Just for demo purposes
|
||||||
*/
|
*/
|
||||||
openIndexPatternNumberFieldEditor: () => void;
|
openDateViewNumberFieldEditor: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UsingAnExistingFieldFormatExample: React.FC<{ deps: Deps }> = (props) => {
|
const UsingAnExistingFieldFormatExample: React.FC<{ deps: Deps }> = (props) => {
|
||||||
|
@ -123,15 +123,15 @@ const CreatingCustomFieldFormat: React.FC<{ deps: Deps }> = (props) => {
|
||||||
<EuiSpacer size={'s'} />
|
<EuiSpacer size={'s'} />
|
||||||
|
|
||||||
<EuiCallOut
|
<EuiCallOut
|
||||||
title="Seamless integration with index patterns!"
|
title="Seamless integration with data views!"
|
||||||
color="success"
|
color="success"
|
||||||
iconType="indexManagementApp"
|
iconType="indexManagementApp"
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
Currency formatter that we've just created is already integrated with index patterns.
|
Currency formatter that we've just created is already integrated with data views. It
|
||||||
It can be applied to any <EuiCode>numeric</EuiCode> field of any index pattern.{' '}
|
can be applied to any <EuiCode>numeric</EuiCode> field of any data view.{' '}
|
||||||
<EuiLink onClick={() => props.deps.openIndexPatternNumberFieldEditor()}>
|
<EuiLink onClick={() => props.deps.openDateViewNumberFieldEditor()}>
|
||||||
Open index pattern field editor to give it a try.
|
Open data view field editor to give it a try.
|
||||||
</EuiLink>
|
</EuiLink>
|
||||||
</p>
|
</p>
|
||||||
</EuiCallOut>
|
</EuiCallOut>
|
||||||
|
@ -155,15 +155,15 @@ const CreatingCustomFieldFormatEditor: React.FC<{ deps: Deps }> = (props) => {
|
||||||
<EuiSpacer size={'s'} />
|
<EuiSpacer size={'s'} />
|
||||||
|
|
||||||
<EuiCallOut
|
<EuiCallOut
|
||||||
title="Check the result in the index pattern field editor!"
|
title="Check the result in the data view field editor!"
|
||||||
color="primary"
|
color="primary"
|
||||||
iconType="indexManagementApp"
|
iconType="indexManagementApp"
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
Currency formatter and its custom editor are integrated with index patterns. It can be
|
Currency formatter and its custom editor are integrated with data views. It can be applied
|
||||||
applied to any <EuiCode>numeric</EuiCode> field of any index pattern.{' '}
|
to any <EuiCode>numeric</EuiCode> field of any data view.{' '}
|
||||||
<EuiLink onClick={() => props.deps.openIndexPatternNumberFieldEditor()}>
|
<EuiLink onClick={() => props.deps.openDateViewNumberFieldEditor()}>
|
||||||
Open index pattern field editor to give it a try.
|
Open date view field editor to give it a try.
|
||||||
</EuiLink>
|
</EuiLink>
|
||||||
</p>
|
</p>
|
||||||
</EuiCallOut>
|
</EuiCallOut>
|
||||||
|
|
|
@ -45,29 +45,29 @@ export class FieldFormatsExamplePlugin implements Plugin<void, void, SetupDeps,
|
||||||
registerExampleFormatEditor(deps.dataViewFieldEditor);
|
registerExampleFormatEditor(deps.dataViewFieldEditor);
|
||||||
|
|
||||||
// just for demonstration purposes:
|
// just for demonstration purposes:
|
||||||
// opens a field editor using default index pattern and first number field
|
// opens a field editor using default data view and first number field
|
||||||
const openIndexPatternNumberFieldEditor = async () => {
|
const openDateViewNumberFieldEditor = async () => {
|
||||||
const [, plugins] = await core.getStartServices();
|
const [, plugins] = await core.getStartServices();
|
||||||
const indexPattern = await plugins.data.indexPatterns.getDefault();
|
const dataView = await plugins.data.dataViews.getDefault();
|
||||||
if (!indexPattern) {
|
if (!dataView) {
|
||||||
alert('Creating at least one index pattern to continue with this example');
|
alert('Create at least one data view to continue with this example');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const numberField = indexPattern
|
const numberField = dataView.fields
|
||||||
.getNonScriptedFields()
|
.getAll()
|
||||||
.find((f) => !f.name.startsWith('_') && f.type === KBN_FIELD_TYPES.NUMBER);
|
.find((f) => !f.name.startsWith('_') && f.type === KBN_FIELD_TYPES.NUMBER && !f.scripted);
|
||||||
|
|
||||||
if (!numberField) {
|
if (!numberField) {
|
||||||
alert(
|
alert(
|
||||||
'Default index pattern needs at least a single field of type `number` to continue with this example'
|
'Default data view needs at least a single field of type `number` to continue with this example'
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins.dataViewFieldEditor.openEditor({
|
plugins.dataViewFieldEditor.openEditor({
|
||||||
ctx: {
|
ctx: {
|
||||||
dataView: indexPattern,
|
dataView,
|
||||||
},
|
},
|
||||||
fieldName: numberField.name,
|
fieldName: numberField.name,
|
||||||
});
|
});
|
||||||
|
@ -81,7 +81,7 @@ export class FieldFormatsExamplePlugin implements Plugin<void, void, SetupDeps,
|
||||||
async mount({ element }: AppMountParameters) {
|
async mount({ element }: AppMountParameters) {
|
||||||
const [, plugins] = await core.getStartServices();
|
const [, plugins] = await core.getStartServices();
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<App deps={{ fieldFormats: plugins.fieldFormats, openIndexPatternNumberFieldEditor }} />,
|
<App deps={{ fieldFormats: plugins.fieldFormats, openDateViewNumberFieldEditor }} />,
|
||||||
element
|
element
|
||||||
);
|
);
|
||||||
return () => ReactDOM.unmountComponentAtNode(element);
|
return () => ReactDOM.unmountComponentAtNode(element);
|
||||||
|
|
|
@ -41,11 +41,10 @@ import { PLUGIN_ID, PLUGIN_NAME, SERVER_SEARCH_ROUTE_PATH } from '../../common';
|
||||||
import {
|
import {
|
||||||
DataPublicPluginStart,
|
DataPublicPluginStart,
|
||||||
IKibanaSearchResponse,
|
IKibanaSearchResponse,
|
||||||
IndexPattern,
|
|
||||||
IndexPatternField,
|
|
||||||
isCompleteResponse,
|
isCompleteResponse,
|
||||||
isErrorResponse,
|
isErrorResponse,
|
||||||
} from '../../../../src/plugins/data/public';
|
} from '../../../../src/plugins/data/public';
|
||||||
|
import type { DataViewField, DataView } from '../../../../src/plugins/data_views/public';
|
||||||
import { IMyStrategyResponse } from '../../common/types';
|
import { IMyStrategyResponse } from '../../common/types';
|
||||||
import { AbortError } from '../../../../src/plugins/kibana_utils/common';
|
import { AbortError } from '../../../../src/plugins/kibana_utils/common';
|
||||||
|
|
||||||
|
@ -56,22 +55,22 @@ interface SearchExamplesAppDeps {
|
||||||
data: DataPublicPluginStart;
|
data: DataPublicPluginStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNumeric(fields?: IndexPatternField[]) {
|
function getNumeric(fields?: DataViewField[]) {
|
||||||
if (!fields) return [];
|
if (!fields) return [];
|
||||||
return fields?.filter((f) => f.type === 'number' && f.aggregatable);
|
return fields?.filter((f) => f.type === 'number' && f.aggregatable);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAggregatableStrings(fields?: IndexPatternField[]) {
|
function getAggregatableStrings(fields?: DataViewField[]) {
|
||||||
if (!fields) return [];
|
if (!fields) return [];
|
||||||
return fields?.filter((f) => f.type === 'string' && f.aggregatable);
|
return fields?.filter((f) => f.type === 'string' && f.aggregatable);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatFieldToComboBox(field?: IndexPatternField | null) {
|
function formatFieldToComboBox(field?: DataViewField | null) {
|
||||||
if (!field) return [];
|
if (!field) return [];
|
||||||
return formatFieldsToComboBox([field]);
|
return formatFieldsToComboBox([field]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatFieldsToComboBox(fields?: IndexPatternField[]) {
|
function formatFieldsToComboBox(fields?: DataViewField[]) {
|
||||||
if (!fields) return [];
|
if (!fields) return [];
|
||||||
|
|
||||||
return fields?.map((field) => {
|
return fields?.map((field) => {
|
||||||
|
@ -93,14 +92,14 @@ export const SearchExamplesApp = ({
|
||||||
const [timeTook, setTimeTook] = useState<number | undefined>();
|
const [timeTook, setTimeTook] = useState<number | undefined>();
|
||||||
const [total, setTotal] = useState<number>(100);
|
const [total, setTotal] = useState<number>(100);
|
||||||
const [loaded, setLoaded] = useState<number>(0);
|
const [loaded, setLoaded] = useState<number>(0);
|
||||||
const [indexPattern, setIndexPattern] = useState<IndexPattern | null>();
|
const [dataView, setDataView] = useState<DataView | null>();
|
||||||
const [fields, setFields] = useState<IndexPatternField[]>();
|
const [fields, setFields] = useState<DataViewField[]>();
|
||||||
const [selectedFields, setSelectedFields] = useState<IndexPatternField[]>([]);
|
const [selectedFields, setSelectedFields] = useState<DataViewField[]>([]);
|
||||||
const [selectedNumericField, setSelectedNumericField] = useState<
|
const [selectedNumericField, setSelectedNumericField] = useState<
|
||||||
IndexPatternField | null | undefined
|
DataViewField | null | undefined
|
||||||
>();
|
>();
|
||||||
const [selectedBucketField, setSelectedBucketField] = useState<
|
const [selectedBucketField, setSelectedBucketField] = useState<
|
||||||
IndexPatternField | null | undefined
|
DataViewField | null | undefined
|
||||||
>();
|
>();
|
||||||
const [request, setRequest] = useState<Record<string, any>>({});
|
const [request, setRequest] = useState<Record<string, any>>({});
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
@ -115,20 +114,20 @@ export const SearchExamplesApp = ({
|
||||||
setTimeTook(response.rawResponse.took);
|
setTimeTook(response.rawResponse.took);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the default index pattern using the `data.indexPatterns` service, as the component is mounted.
|
// Fetch the default data view using the `data.dataViews` service, as the component is mounted.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const setDefaultIndexPattern = async () => {
|
const setDefaultDataView = async () => {
|
||||||
const defaultIndexPattern = await data.indexPatterns.getDefault();
|
const defaultDataView = await data.dataViews.getDefault();
|
||||||
setIndexPattern(defaultIndexPattern);
|
setDataView(defaultDataView);
|
||||||
};
|
};
|
||||||
|
|
||||||
setDefaultIndexPattern();
|
setDefaultDataView();
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
// Update the fields list every time the index pattern is modified.
|
// Update the fields list every time the data view is modified.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFields(indexPattern?.fields);
|
setFields(dataView?.fields);
|
||||||
}, [indexPattern]);
|
}, [dataView]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedBucketField(fields?.length ? getAggregatableStrings(fields)[0] : null);
|
setSelectedBucketField(fields?.length ? getAggregatableStrings(fields)[0] : null);
|
||||||
setSelectedNumericField(fields?.length ? getNumeric(fields)[0] : null);
|
setSelectedNumericField(fields?.length ? getNumeric(fields)[0] : null);
|
||||||
|
@ -140,10 +139,10 @@ export const SearchExamplesApp = ({
|
||||||
addWarning: boolean = false,
|
addWarning: boolean = false,
|
||||||
addError: boolean = false
|
addError: boolean = false
|
||||||
) => {
|
) => {
|
||||||
if (!indexPattern || !selectedNumericField) return;
|
if (!dataView || !selectedNumericField) return;
|
||||||
|
|
||||||
// Construct the query portion of the search request
|
// Construct the query portion of the search request
|
||||||
const query = data.query.getEsQuery(indexPattern);
|
const query = data.query.getEsQuery(dataView);
|
||||||
|
|
||||||
if (addWarning) {
|
if (addWarning) {
|
||||||
query.bool.must.push({
|
query.bool.must.push({
|
||||||
|
@ -151,7 +150,7 @@ export const SearchExamplesApp = ({
|
||||||
error_query: {
|
error_query: {
|
||||||
indices: [
|
indices: [
|
||||||
{
|
{
|
||||||
name: indexPattern.title,
|
name: dataView.title,
|
||||||
error_type: 'warning',
|
error_type: 'warning',
|
||||||
message: 'Watch out!',
|
message: 'Watch out!',
|
||||||
},
|
},
|
||||||
|
@ -165,7 +164,7 @@ export const SearchExamplesApp = ({
|
||||||
error_query: {
|
error_query: {
|
||||||
indices: [
|
indices: [
|
||||||
{
|
{
|
||||||
name: indexPattern.title,
|
name: dataView.title,
|
||||||
error_type: 'exception',
|
error_type: 'exception',
|
||||||
message: 'Watch out!',
|
message: 'Watch out!',
|
||||||
},
|
},
|
||||||
|
@ -176,11 +175,11 @@ export const SearchExamplesApp = ({
|
||||||
|
|
||||||
// Construct the aggregations portion of the search request by using the `data.search.aggs` service.
|
// 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: 'avg', params: { field: selectedNumericField!.name } }];
|
||||||
const aggsDsl = data.search.aggs.createAggConfigs(indexPattern, aggs).toDsl();
|
const aggsDsl = data.search.aggs.createAggConfigs(dataView, aggs).toDsl();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
params: {
|
params: {
|
||||||
index: indexPattern.title,
|
index: dataView.title,
|
||||||
body: {
|
body: {
|
||||||
aggs: aggsDsl,
|
aggs: aggsDsl,
|
||||||
query,
|
query,
|
||||||
|
@ -264,11 +263,11 @@ export const SearchExamplesApp = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const doSearchSourceSearch = async (otherBucket: boolean) => {
|
const doSearchSourceSearch = async (otherBucket: boolean) => {
|
||||||
if (!indexPattern) return;
|
if (!dataView) return;
|
||||||
|
|
||||||
const query = data.query.queryString.getQuery();
|
const query = data.query.queryString.getQuery();
|
||||||
const filters = data.query.filterManager.getFilters();
|
const filters = data.query.filterManager.getFilters();
|
||||||
const timefilter = data.query.timefilter.timefilter.createFilter(indexPattern);
|
const timefilter = data.query.timefilter.timefilter.createFilter(dataView);
|
||||||
if (timefilter) {
|
if (timefilter) {
|
||||||
filters.push(timefilter);
|
filters.push(timefilter);
|
||||||
}
|
}
|
||||||
|
@ -277,7 +276,7 @@ export const SearchExamplesApp = ({
|
||||||
const searchSource = await data.search.searchSource.create();
|
const searchSource = await data.search.searchSource.create();
|
||||||
|
|
||||||
searchSource
|
searchSource
|
||||||
.setField('index', indexPattern)
|
.setField('index', dataView)
|
||||||
.setField('filter', filters)
|
.setField('filter', filters)
|
||||||
.setField('query', query)
|
.setField('query', query)
|
||||||
.setField('fields', selectedFields.length ? selectedFields.map((f) => f.name) : [''])
|
.setField('fields', selectedFields.length ? selectedFields.map((f) => f.name) : [''])
|
||||||
|
@ -296,7 +295,7 @@ export const SearchExamplesApp = ({
|
||||||
aggDef.push({ type: 'avg', params: { field: selectedNumericField.name } });
|
aggDef.push({ type: 'avg', params: { field: selectedNumericField.name } });
|
||||||
}
|
}
|
||||||
if (aggDef.length > 0) {
|
if (aggDef.length > 0) {
|
||||||
const ac = data.search.aggs.createAggConfigs(indexPattern, aggDef);
|
const ac = data.search.aggs.createAggConfigs(dataView, aggDef);
|
||||||
searchSource.setField('aggs', ac);
|
searchSource.setField('aggs', ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,14 +406,14 @@ export const SearchExamplesApp = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const onServerClickHandler = async () => {
|
const onServerClickHandler = async () => {
|
||||||
if (!indexPattern || !selectedNumericField) return;
|
if (!dataView || !selectedNumericField) return;
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
setAbortController(abortController);
|
setAbortController(abortController);
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await http.get(SERVER_SEARCH_ROUTE_PATH, {
|
const res = await http.get(SERVER_SEARCH_ROUTE_PATH, {
|
||||||
query: {
|
query: {
|
||||||
index: indexPattern.title,
|
index: dataView.title,
|
||||||
field: selectedNumericField!.name,
|
field: selectedNumericField!.name,
|
||||||
},
|
},
|
||||||
signal: abortController.signal,
|
signal: abortController.signal,
|
||||||
|
@ -510,22 +509,26 @@ export const SearchExamplesApp = ({
|
||||||
appName={PLUGIN_ID}
|
appName={PLUGIN_ID}
|
||||||
showSearchBar={true}
|
showSearchBar={true}
|
||||||
useDefaultBehaviors={true}
|
useDefaultBehaviors={true}
|
||||||
indexPatterns={indexPattern ? [indexPattern] : undefined}
|
indexPatterns={dataView ? [dataView] : undefined}
|
||||||
/>
|
/>
|
||||||
<EuiFlexGrid columns={4}>
|
<EuiFlexGrid columns={4}>
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
<EuiFormLabel>Index Pattern</EuiFormLabel>
|
<EuiFormLabel>Data view</EuiFormLabel>
|
||||||
<IndexPatternSelect
|
<IndexPatternSelect
|
||||||
placeholder={i18n.translate('searchSessionExample.selectIndexPatternPlaceholder', {
|
placeholder={i18n.translate('searchSessionExample.selectDataViewPlaceholder', {
|
||||||
defaultMessage: 'Select index pattern',
|
defaultMessage: 'Select data view',
|
||||||
})}
|
})}
|
||||||
indexPatternId={indexPattern?.id || ''}
|
indexPatternId={dataView?.id || ''}
|
||||||
onChange={async (newIndexPatternId: any) => {
|
onChange={async (dataViewId?: string) => {
|
||||||
const newIndexPattern = await data.indexPatterns.get(newIndexPatternId);
|
if (dataViewId) {
|
||||||
setIndexPattern(newIndexPattern);
|
const newDataView = await data.dataViews.get(dataViewId);
|
||||||
|
setDataView(newDataView);
|
||||||
|
} else {
|
||||||
|
setDataView(undefined);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
isClearable={false}
|
isClearable={false}
|
||||||
data-test-subj="indexPatternSelector"
|
data-test-subj="dataViewSelector"
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
|
@ -536,7 +539,7 @@ export const SearchExamplesApp = ({
|
||||||
singleSelection={true}
|
singleSelection={true}
|
||||||
onChange={(option) => {
|
onChange={(option) => {
|
||||||
if (option.length) {
|
if (option.length) {
|
||||||
const fld = indexPattern?.getFieldByName(option[0].label);
|
const fld = dataView?.getFieldByName(option[0].label);
|
||||||
setSelectedBucketField(fld || null);
|
setSelectedBucketField(fld || null);
|
||||||
} else {
|
} else {
|
||||||
setSelectedBucketField(null);
|
setSelectedBucketField(null);
|
||||||
|
@ -554,7 +557,7 @@ export const SearchExamplesApp = ({
|
||||||
singleSelection={true}
|
singleSelection={true}
|
||||||
onChange={(option) => {
|
onChange={(option) => {
|
||||||
if (option.length) {
|
if (option.length) {
|
||||||
const fld = indexPattern?.getFieldByName(option[0].label);
|
const fld = dataView?.getFieldByName(option[0].label);
|
||||||
setSelectedNumericField(fld || null);
|
setSelectedNumericField(fld || null);
|
||||||
} else {
|
} else {
|
||||||
setSelectedNumericField(null);
|
setSelectedNumericField(null);
|
||||||
|
@ -572,9 +575,9 @@ export const SearchExamplesApp = ({
|
||||||
singleSelection={false}
|
singleSelection={false}
|
||||||
onChange={(option) => {
|
onChange={(option) => {
|
||||||
const flds = option
|
const flds = option
|
||||||
.map((opt) => indexPattern?.getFieldByName(opt?.label))
|
.map((opt) => dataView?.getFieldByName(opt?.label))
|
||||||
.filter((f) => f);
|
.filter((f) => f);
|
||||||
setSelectedFields(flds.length ? (flds as IndexPatternField[]) : []);
|
setSelectedFields(flds.length ? (flds as DataViewField[]) : []);
|
||||||
}}
|
}}
|
||||||
sortMatchesBy="startsWith"
|
sortMatchesBy="startsWith"
|
||||||
/>
|
/>
|
||||||
|
@ -590,9 +593,8 @@ export const SearchExamplesApp = ({
|
||||||
</EuiTitle>
|
</EuiTitle>
|
||||||
<EuiText>
|
<EuiText>
|
||||||
If you want to fetch data from Elasticsearch, you can use the different services
|
If you want to fetch data from Elasticsearch, you can use the different services
|
||||||
provided by the <EuiCode>data</EuiCode> plugin. These help you get the index pattern
|
provided by the <EuiCode>data</EuiCode> plugin. These help you get the data view and
|
||||||
and search bar configuration, format them into a DSL query and send it to
|
search bar configuration, format them into a DSL query and send it to Elasticsearch.
|
||||||
Elasticsearch.
|
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
<EuiButtonEmpty size="xs" onClick={onClickHandler} iconType="play">
|
<EuiButtonEmpty size="xs" onClick={onClickHandler} iconType="play">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|
|
@ -43,14 +43,13 @@ import {
|
||||||
DataPublicPluginStart,
|
DataPublicPluginStart,
|
||||||
IEsSearchRequest,
|
IEsSearchRequest,
|
||||||
IEsSearchResponse,
|
IEsSearchResponse,
|
||||||
IndexPattern,
|
|
||||||
IndexPatternField,
|
|
||||||
isCompleteResponse,
|
isCompleteResponse,
|
||||||
isErrorResponse,
|
isErrorResponse,
|
||||||
QueryState,
|
QueryState,
|
||||||
SearchSessionState,
|
SearchSessionState,
|
||||||
TimeRange,
|
TimeRange,
|
||||||
} from '../../../../src/plugins/data/public';
|
} from '../../../../src/plugins/data/public';
|
||||||
|
import type { DataView, DataViewField } from '../../../../src/plugins/data_views/public';
|
||||||
import {
|
import {
|
||||||
createStateContainer,
|
createStateContainer,
|
||||||
useContainerState,
|
useContainerState,
|
||||||
|
@ -77,7 +76,7 @@ enum DemoStep {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State extends QueryState {
|
interface State extends QueryState {
|
||||||
indexPatternId?: string;
|
dataViewId?: string;
|
||||||
numericFieldName?: string;
|
numericFieldName?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,10 +122,10 @@ export const SearchSessionsExampleApp = ({
|
||||||
|
|
||||||
const {
|
const {
|
||||||
numericFieldName,
|
numericFieldName,
|
||||||
indexPattern,
|
dataView,
|
||||||
selectedField,
|
selectedField,
|
||||||
fields,
|
fields,
|
||||||
setIndexPattern,
|
setDataView,
|
||||||
setNumericFieldName,
|
setNumericFieldName,
|
||||||
state,
|
state,
|
||||||
} = useAppState({ data });
|
} = useAppState({ data });
|
||||||
|
@ -141,14 +140,14 @@ export const SearchSessionsExampleApp = ({
|
||||||
time: data.query.timefilter.timefilter.getTime(),
|
time: data.query.timefilter.timefilter.getTime(),
|
||||||
filters: data.query.filterManager.getFilters(),
|
filters: data.query.filterManager.getFilters(),
|
||||||
query: data.query.queryString.getQuery(),
|
query: data.query.queryString.getQuery(),
|
||||||
indexPatternId: indexPattern?.id,
|
dataViewId: dataView?.id,
|
||||||
numericFieldName,
|
numericFieldName,
|
||||||
},
|
},
|
||||||
restoreState: {
|
restoreState: {
|
||||||
time: data.query.timefilter.timefilter.getAbsoluteTime(),
|
time: data.query.timefilter.timefilter.getAbsoluteTime(),
|
||||||
filters: data.query.filterManager.getFilters(),
|
filters: data.query.filterManager.getFilters(),
|
||||||
query: data.query.queryString.getQuery(),
|
query: data.query.queryString.getQuery(),
|
||||||
indexPatternId: indexPattern?.id,
|
dataViewId: dataView?.id,
|
||||||
numericFieldName,
|
numericFieldName,
|
||||||
searchSessionId: data.search.session.getSessionId(),
|
searchSessionId: data.search.session.getSessionId(),
|
||||||
},
|
},
|
||||||
|
@ -160,7 +159,7 @@ export const SearchSessionsExampleApp = ({
|
||||||
data.query.queryString,
|
data.query.queryString,
|
||||||
data.query.timefilter.timefilter,
|
data.query.timefilter.timefilter,
|
||||||
data.search.session,
|
data.search.session,
|
||||||
indexPattern?.id,
|
dataView?.id,
|
||||||
numericFieldName,
|
numericFieldName,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -198,11 +197,11 @@ export const SearchSessionsExampleApp = ({
|
||||||
|
|
||||||
const search = useCallback(
|
const search = useCallback(
|
||||||
(restoreSearchSessionId?: string) => {
|
(restoreSearchSessionId?: string) => {
|
||||||
if (!indexPattern) return;
|
if (!dataView) return;
|
||||||
if (!numericFieldName) return;
|
if (!numericFieldName) return;
|
||||||
setIsSearching(true);
|
setIsSearching(true);
|
||||||
const requestId = ++nextRequestIdRef.current;
|
const requestId = ++nextRequestIdRef.current;
|
||||||
doSearch({ indexPattern, numericFieldName, restoreSearchSessionId }, { data, notifications })
|
doSearch({ dataView, numericFieldName, restoreSearchSessionId }, { data, notifications })
|
||||||
.then(({ response: res, request: req, tookMs: _tookMs }) => {
|
.then(({ response: res, request: req, tookMs: _tookMs }) => {
|
||||||
if (requestId !== nextRequestIdRef.current) return; // no longer interested in this result
|
if (requestId !== nextRequestIdRef.current) return; // no longer interested in this result
|
||||||
if (restoreSearchSessionId) {
|
if (restoreSearchSessionId) {
|
||||||
|
@ -220,7 +219,7 @@ export const SearchSessionsExampleApp = ({
|
||||||
setIsSearching(false);
|
setIsSearching(false);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[data, notifications, indexPattern, numericFieldName]
|
[data, notifications, dataView, numericFieldName]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -243,9 +242,9 @@ export const SearchSessionsExampleApp = ({
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!indexPattern && (
|
{!dataView && (
|
||||||
<>
|
<>
|
||||||
<NoIndexPatternsCallout />
|
<NoDataViewsCallout />
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -280,26 +279,23 @@ export const SearchSessionsExampleApp = ({
|
||||||
appName={PLUGIN_ID}
|
appName={PLUGIN_ID}
|
||||||
showSearchBar={true}
|
showSearchBar={true}
|
||||||
useDefaultBehaviors={true}
|
useDefaultBehaviors={true}
|
||||||
indexPatterns={indexPattern ? [indexPattern] : undefined}
|
indexPatterns={dataView ? [dataView] : undefined}
|
||||||
onQuerySubmit={reset}
|
onQuerySubmit={reset}
|
||||||
/>
|
/>
|
||||||
<EuiFlexGroup justifyContent={'flexStart'}>
|
<EuiFlexGroup justifyContent={'flexStart'}>
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<EuiFormLabel>Index Pattern</EuiFormLabel>
|
<EuiFormLabel>Data view</EuiFormLabel>
|
||||||
<IndexPatternSelect
|
<IndexPatternSelect
|
||||||
placeholder={i18n.translate(
|
placeholder={i18n.translate('searchSessionExample.selectDataViewPlaceholder', {
|
||||||
'searchSessionExample.selectIndexPatternPlaceholder',
|
defaultMessage: 'Select data view',
|
||||||
{
|
})}
|
||||||
defaultMessage: 'Select index pattern',
|
indexPatternId={dataView?.id ?? ''}
|
||||||
}
|
|
||||||
)}
|
|
||||||
indexPatternId={indexPattern?.id ?? ''}
|
|
||||||
onChange={(id) => {
|
onChange={(id) => {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
setIndexPattern(id);
|
setDataView(id);
|
||||||
}}
|
}}
|
||||||
isClearable={false}
|
isClearable={false}
|
||||||
data-test-subj="indexPatternSelector"
|
data-test-subj="dataViewSelector"
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
|
@ -309,7 +305,7 @@ export const SearchSessionsExampleApp = ({
|
||||||
selectedOptions={formatFieldToComboBox(selectedField)}
|
selectedOptions={formatFieldToComboBox(selectedField)}
|
||||||
singleSelection={true}
|
singleSelection={true}
|
||||||
onChange={(option) => {
|
onChange={(option) => {
|
||||||
const fld = indexPattern?.getFieldByName(option[0].label);
|
const fld = dataView?.getFieldByName(option[0].label);
|
||||||
if (!fld) return;
|
if (!fld) return;
|
||||||
setNumericFieldName(fld?.name);
|
setNumericFieldName(fld?.name);
|
||||||
}}
|
}}
|
||||||
|
@ -336,7 +332,7 @@ export const SearchSessionsExampleApp = ({
|
||||||
size="xs"
|
size="xs"
|
||||||
onClick={() => search()}
|
onClick={() => search()}
|
||||||
iconType="play"
|
iconType="play"
|
||||||
disabled={isSearching || !indexPattern || !numericFieldName}
|
disabled={isSearching || !dataView || !numericFieldName}
|
||||||
data-test-subj={'startSearch'}
|
data-test-subj={'startSearch'}
|
||||||
>
|
>
|
||||||
Start the search from low-level client (data.search.search)
|
Start the search from low-level client (data.search.search)
|
||||||
|
@ -540,7 +536,7 @@ function SearchInspector({
|
||||||
|
|
||||||
function useAppState({ data }: { data: DataPublicPluginStart }) {
|
function useAppState({ data }: { data: DataPublicPluginStart }) {
|
||||||
const stateContainer = useMemo(() => {
|
const stateContainer = useMemo(() => {
|
||||||
const { filters, time, searchSessionId, numericFieldName, indexPatternId, query } =
|
const { filters, time, searchSessionId, numericFieldName, dataViewId, query } =
|
||||||
getInitialStateFromUrl();
|
getInitialStateFromUrl();
|
||||||
|
|
||||||
if (filters) {
|
if (filters) {
|
||||||
|
@ -558,7 +554,7 @@ function useAppState({ data }: { data: DataPublicPluginStart }) {
|
||||||
return createStateContainer<State>({
|
return createStateContainer<State>({
|
||||||
restoreSessionId: searchSessionId,
|
restoreSessionId: searchSessionId,
|
||||||
numericFieldName,
|
numericFieldName,
|
||||||
indexPatternId,
|
dataViewId,
|
||||||
});
|
});
|
||||||
}, [data.query.filterManager, data.query.queryString, data.query.timefilter.timefilter]);
|
}, [data.query.filterManager, data.query.queryString, data.query.timefilter.timefilter]);
|
||||||
const setState = useCallback(
|
const setState = useCallback(
|
||||||
|
@ -575,78 +571,78 @@ function useAppState({ data }: { data: DataPublicPluginStart }) {
|
||||||
});
|
});
|
||||||
}, [stateContainer, data.query]);
|
}, [stateContainer, data.query]);
|
||||||
|
|
||||||
const [fields, setFields] = useState<IndexPatternField[]>();
|
const [fields, setFields] = useState<DataViewField[]>();
|
||||||
const [indexPattern, setIndexPattern] = useState<IndexPattern | null>();
|
const [dataView, setDataView] = useState<DataView | null>();
|
||||||
|
|
||||||
// Fetch the default index pattern using the `data.indexPatterns` service, as the component is mounted.
|
// Fetch the default data view using the `data.dataViews` service, as the component is mounted.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let canceled = false;
|
let canceled = false;
|
||||||
const loadIndexPattern = async () => {
|
const loadDataView = async () => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn('Loading default index pattern');
|
console.warn('Loading default data view');
|
||||||
let loadedIndexPattern = state.indexPatternId
|
let loadedDataView = state.dataViewId
|
||||||
? await data.indexPatterns.get(state.indexPatternId)
|
? await data.dataViews.get(state.dataViewId)
|
||||||
: await data.indexPatterns.getDefault();
|
: await data.dataViews.getDefault();
|
||||||
if (!loadedIndexPattern) {
|
if (!loadedDataView) {
|
||||||
// try to find any available index pattern
|
// try to find any available data view
|
||||||
const [id] = await data.indexPatterns.getIds(true);
|
const [id] = await data.dataViews.getIds(true);
|
||||||
if (id) {
|
if (id) {
|
||||||
loadedIndexPattern = await data.indexPatterns.get(id);
|
loadedDataView = await data.dataViews.get(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
if (!loadedIndexPattern) {
|
if (!loadedDataView) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn('No index patterns to pick from');
|
console.warn('No data view to pick from');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!state.indexPatternId) {
|
if (!state.dataViewId) {
|
||||||
setState({
|
setState({
|
||||||
indexPatternId: loadedIndexPattern.id,
|
dataViewId: loadedDataView.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setIndexPattern(loadedIndexPattern);
|
setDataView(loadedDataView);
|
||||||
};
|
};
|
||||||
|
|
||||||
loadIndexPattern();
|
loadDataView();
|
||||||
return () => {
|
return () => {
|
||||||
canceled = true;
|
canceled = true;
|
||||||
};
|
};
|
||||||
}, [data, setState, state.indexPatternId]);
|
}, [data, setState, state.dataViewId]);
|
||||||
|
|
||||||
// Update the fields list every time the index pattern is modified.
|
// Update the fields list every time the data view is modified.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFields(indexPattern?.fields);
|
setFields(dataView?.fields);
|
||||||
}, [indexPattern]);
|
}, [dataView]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.numericFieldName) return;
|
if (state.numericFieldName) return;
|
||||||
setState({ numericFieldName: fields?.length ? getNumeric(fields)[0]?.name : undefined });
|
setState({ numericFieldName: fields?.length ? getNumeric(fields)[0]?.name : undefined });
|
||||||
}, [setState, fields, state.numericFieldName]);
|
}, [setState, fields, state.numericFieldName]);
|
||||||
|
|
||||||
const selectedField: IndexPatternField | undefined = useMemo(
|
const selectedField: DataViewField | undefined = useMemo(
|
||||||
() => indexPattern?.fields.find((field) => field.name === state.numericFieldName),
|
() => dataView?.fields.find((field) => field.name === state.numericFieldName),
|
||||||
[indexPattern?.fields, state.numericFieldName]
|
[dataView?.fields, state.numericFieldName]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedField,
|
selectedField,
|
||||||
indexPattern,
|
dataView,
|
||||||
numericFieldName: state.numericFieldName,
|
numericFieldName: state.numericFieldName,
|
||||||
fields,
|
fields,
|
||||||
setNumericFieldName: (field: string) => setState({ numericFieldName: field }),
|
setNumericFieldName: (field: string) => setState({ numericFieldName: field }),
|
||||||
setIndexPattern: (indexPatternId: string) => setState({ indexPatternId }),
|
setDataView: (dataViewId: string) => setState({ dataViewId }),
|
||||||
state,
|
state,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function doSearch(
|
function doSearch(
|
||||||
{
|
{
|
||||||
indexPattern,
|
dataView,
|
||||||
numericFieldName,
|
numericFieldName,
|
||||||
restoreSearchSessionId,
|
restoreSearchSessionId,
|
||||||
}: {
|
}: {
|
||||||
indexPattern: IndexPattern;
|
dataView: DataView;
|
||||||
numericFieldName: string;
|
numericFieldName: string;
|
||||||
restoreSearchSessionId?: string;
|
restoreSearchSessionId?: string;
|
||||||
},
|
},
|
||||||
|
@ -655,7 +651,7 @@ function doSearch(
|
||||||
notifications,
|
notifications,
|
||||||
}: { data: DataPublicPluginStart; notifications: CoreStart['notifications'] }
|
}: { data: DataPublicPluginStart; notifications: CoreStart['notifications'] }
|
||||||
): Promise<{ request: IEsSearchRequest; response: IEsSearchResponse; tookMs?: number }> {
|
): Promise<{ request: IEsSearchRequest; response: IEsSearchResponse; tookMs?: number }> {
|
||||||
if (!indexPattern) return Promise.reject('Select an index patten');
|
if (!dataView) return Promise.reject('Select a data view');
|
||||||
if (!numericFieldName) return Promise.reject('Select a field to aggregate on');
|
if (!numericFieldName) return Promise.reject('Select a field to aggregate on');
|
||||||
|
|
||||||
// start a new session or restore an existing one
|
// start a new session or restore an existing one
|
||||||
|
@ -668,7 +664,7 @@ function doSearch(
|
||||||
const sessionId = restoreSearchSessionId ? restoreSearchSessionId : data.search.session.start();
|
const sessionId = restoreSearchSessionId ? restoreSearchSessionId : data.search.session.start();
|
||||||
|
|
||||||
// Construct the query portion of the search request
|
// Construct the query portion of the search request
|
||||||
const query = data.query.getEsQuery(indexPattern, restoreTimeRange);
|
const query = data.query.getEsQuery(dataView, restoreTimeRange);
|
||||||
|
|
||||||
// Construct the aggregations portion of the search request by using the `data.search.aggs` service.
|
// Construct the aggregations portion of the search request by using the `data.search.aggs` service.
|
||||||
|
|
||||||
|
@ -679,11 +675,11 @@ function doSearch(
|
||||||
]
|
]
|
||||||
: [{ type: 'avg', params: { field: numericFieldName } }];
|
: [{ type: 'avg', params: { field: numericFieldName } }];
|
||||||
|
|
||||||
const aggsDsl = data.search.aggs.createAggConfigs(indexPattern, aggs).toDsl();
|
const aggsDsl = data.search.aggs.createAggConfigs(dataView, aggs).toDsl();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
params: {
|
params: {
|
||||||
index: indexPattern.title,
|
index: dataView.title,
|
||||||
body: {
|
body: {
|
||||||
aggs: aggsDsl,
|
aggs: aggsDsl,
|
||||||
query,
|
query,
|
||||||
|
@ -728,17 +724,17 @@ function doSearch(
|
||||||
.toPromise();
|
.toPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNumeric(fields?: IndexPatternField[]) {
|
function getNumeric(fields?: DataViewField[]) {
|
||||||
if (!fields) return [];
|
if (!fields) return [];
|
||||||
return fields?.filter((f) => f.type === 'number' && f.aggregatable);
|
return fields?.filter((f) => f.type === 'number' && f.aggregatable);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatFieldToComboBox(field?: IndexPatternField | null) {
|
function formatFieldToComboBox(field?: DataViewField | null) {
|
||||||
if (!field) return [];
|
if (!field) return [];
|
||||||
return formatFieldsToComboBox([field]);
|
return formatFieldsToComboBox([field]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatFieldsToComboBox(fields?: IndexPatternField[]) {
|
function formatFieldsToComboBox(fields?: DataViewField[]) {
|
||||||
if (!fields) return [];
|
if (!fields) return [];
|
||||||
|
|
||||||
return fields?.map((field) => {
|
return fields?.map((field) => {
|
||||||
|
@ -781,10 +777,10 @@ function NoShardDelayCallout() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function NoIndexPatternsCallout() {
|
function NoDataViewsCallout() {
|
||||||
return (
|
return (
|
||||||
<EuiCallOut title={<>Missing index patterns!</>} color="warning" iconType="help">
|
<EuiCallOut title={<>Missing data views!</>} color="warning" iconType="help">
|
||||||
<p>This demo requires at least one index pattern.</p>
|
<p>This demo requires at least one data view.</p>
|
||||||
</EuiCallOut>
|
</EuiCallOut>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SerializableRecord } from '@kbn/utility-types';
|
import { SerializableRecord } from '@kbn/utility-types';
|
||||||
import { esFilters, Filter, Query, TimeRange } from '../../../../src/plugins/data/public';
|
import { Filter, Query, isFilterPinned } from '@kbn/es-query';
|
||||||
|
import type { TimeRange } from '../../../../src/plugins/data/public';
|
||||||
import { getStatesFromKbnUrl, setStateToKbnUrl } from '../../../../src/plugins/kibana_utils/public';
|
import { getStatesFromKbnUrl, setStateToKbnUrl } from '../../../../src/plugins/kibana_utils/public';
|
||||||
import { LocatorDefinition } from '../../../../src/plugins/share/common';
|
import { LocatorDefinition } from '../../../../src/plugins/share/common';
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ export const SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR = 'SEARCH_SESSIONS_EXAMPLES_AP
|
||||||
export interface AppUrlState extends SerializableRecord {
|
export interface AppUrlState extends SerializableRecord {
|
||||||
filters?: Filter[];
|
filters?: Filter[];
|
||||||
query?: Query;
|
query?: Query;
|
||||||
indexPatternId?: string;
|
dataViewId?: string;
|
||||||
numericFieldName?: string;
|
numericFieldName?: string;
|
||||||
searchSessionId?: string;
|
searchSessionId?: string;
|
||||||
}
|
}
|
||||||
|
@ -46,8 +47,8 @@ export class SearchSessionsExamplesAppLocatorDefinition
|
||||||
STATE_STORAGE_KEY,
|
STATE_STORAGE_KEY,
|
||||||
{
|
{
|
||||||
query: params.query,
|
query: params.query,
|
||||||
filters: params.filters?.filter((f) => !esFilters.isFilterPinned(f)),
|
filters: params.filters?.filter((f) => !isFilterPinned(f)),
|
||||||
indexPatternId: params.indexPatternId,
|
dataViewId: params.dataViewId,
|
||||||
numericFieldName: params.numericFieldName,
|
numericFieldName: params.numericFieldName,
|
||||||
searchSessionId: params.searchSessionId,
|
searchSessionId: params.searchSessionId,
|
||||||
} as AppUrlState,
|
} as AppUrlState,
|
||||||
|
@ -59,7 +60,7 @@ export class SearchSessionsExamplesAppLocatorDefinition
|
||||||
GLOBAL_STATE_STORAGE_KEY,
|
GLOBAL_STATE_STORAGE_KEY,
|
||||||
{
|
{
|
||||||
time: params.time,
|
time: params.time,
|
||||||
filters: params.filters?.filter((f) => esFilters.isFilterPinned(f)),
|
filters: params.filters?.filter((f) => isFilterPinned(f)),
|
||||||
} as GlobalUrlState,
|
} as GlobalUrlState,
|
||||||
{ useHash: false, storeInHashQuery: false },
|
{ useHash: false, storeInHashQuery: false },
|
||||||
url
|
url
|
||||||
|
@ -75,7 +76,7 @@ export class SearchSessionsExamplesAppLocatorDefinition
|
||||||
|
|
||||||
export function getInitialStateFromUrl(): SearchSessionsExamplesAppLocatorParams {
|
export function getInitialStateFromUrl(): SearchSessionsExamplesAppLocatorParams {
|
||||||
const {
|
const {
|
||||||
_a: { numericFieldName, indexPatternId, searchSessionId, filters: aFilters, query } = {},
|
_a: { numericFieldName, dataViewId, searchSessionId, filters: aFilters, query } = {},
|
||||||
_g: { filters: gFilters, time } = {},
|
_g: { filters: gFilters, time } = {},
|
||||||
} = getStatesFromKbnUrl<{ _a: AppUrlState; _g: GlobalUrlState }>(
|
} = getStatesFromKbnUrl<{ _a: AppUrlState; _g: GlobalUrlState }>(
|
||||||
window.location.href,
|
window.location.href,
|
||||||
|
@ -90,7 +91,7 @@ export function getInitialStateFromUrl(): SearchSessionsExamplesAppLocatorParams
|
||||||
searchSessionId,
|
searchSessionId,
|
||||||
time,
|
time,
|
||||||
filters: [...(gFilters ?? []), ...(aFilters ?? [])],
|
filters: [...(gFilters ?? []), ...(aFilters ?? [])],
|
||||||
indexPatternId,
|
dataViewId,
|
||||||
query,
|
query,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../../src/core/tsconfig.json" },
|
{ "path": "../../src/core/tsconfig.json" },
|
||||||
{ "path": "../../src/plugins/data/tsconfig.json" },
|
{ "path": "../../src/plugins/data/tsconfig.json" },
|
||||||
|
{ "path": "../../src/plugins/data_views/tsconfig.json" },
|
||||||
{ "path": "../../src/plugins/kibana_utils/tsconfig.json" },
|
{ "path": "../../src/plugins/kibana_utils/tsconfig.json" },
|
||||||
{ "path": "../../src/plugins/kibana_react/tsconfig.json" },
|
{ "path": "../../src/plugins/kibana_react/tsconfig.json" },
|
||||||
{ "path": "../../src/plugins/navigation/tsconfig.json" },
|
{ "path": "../../src/plugins/navigation/tsconfig.json" },
|
||||||
|
|
|
@ -18,19 +18,18 @@ import {
|
||||||
EuiText,
|
EuiText,
|
||||||
EuiTitle,
|
EuiTitle,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
|
import { Filter, FilterStateStore } from '@kbn/es-query';
|
||||||
import { CoreStart } from 'kibana/public';
|
import { CoreStart } from 'kibana/public';
|
||||||
import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public';
|
import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
connectToQueryState,
|
connectToQueryState,
|
||||||
DataPublicPluginStart,
|
DataPublicPluginStart,
|
||||||
esFilters,
|
|
||||||
Filter,
|
|
||||||
IndexPattern,
|
|
||||||
Query,
|
Query,
|
||||||
QueryState,
|
QueryState,
|
||||||
syncQueryStateWithUrl,
|
syncQueryStateWithUrl,
|
||||||
} from '../../../../src/plugins/data/public';
|
} from '../../../../src/plugins/data/public';
|
||||||
|
import type { DataView } from '../../../../src/plugins/data_views/public';
|
||||||
import {
|
import {
|
||||||
BaseStateContainer,
|
BaseStateContainer,
|
||||||
createStateContainer,
|
createStateContainer,
|
||||||
|
@ -73,13 +72,9 @@ export const App = ({
|
||||||
useGlobalStateSyncing(data.query, kbnUrlStateStorage);
|
useGlobalStateSyncing(data.query, kbnUrlStateStorage);
|
||||||
useAppStateSyncing(appStateContainer, data.query, kbnUrlStateStorage);
|
useAppStateSyncing(appStateContainer, data.query, kbnUrlStateStorage);
|
||||||
|
|
||||||
const indexPattern = useIndexPattern(data);
|
const dataView = useDataView(data);
|
||||||
if (!indexPattern)
|
if (!dataView)
|
||||||
return (
|
return <div>No data view found. Please create a data view before trying this example...</div>;
|
||||||
<div>
|
|
||||||
No index pattern found. Please create an index pattern before trying this example...
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
// Note that `navigation.ui.TopNavMenu` is a stateful component exported on the `navigation` plugin's start contract.
|
// Note that `navigation.ui.TopNavMenu` is a stateful component exported on the `navigation` plugin's start contract.
|
||||||
return (
|
return (
|
||||||
|
@ -102,7 +97,7 @@ export const App = ({
|
||||||
<navigation.ui.TopNavMenu
|
<navigation.ui.TopNavMenu
|
||||||
appName={'Example'}
|
appName={'Example'}
|
||||||
showSearchBar={true}
|
showSearchBar={true}
|
||||||
indexPatterns={[indexPattern]}
|
indexPatterns={[dataView]}
|
||||||
useDefaultBehaviors={true}
|
useDefaultBehaviors={true}
|
||||||
showSaveQuery={true}
|
showSaveQuery={true}
|
||||||
/>
|
/>
|
||||||
|
@ -126,19 +121,19 @@ export const App = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function useIndexPattern(data: DataPublicPluginStart) {
|
function useDataView(data: DataPublicPluginStart) {
|
||||||
const [indexPattern, setIndexPattern] = useState<IndexPattern>();
|
const [dataView, setDataView] = useState<DataView>();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchIndexPattern = async () => {
|
const fetchDataView = async () => {
|
||||||
const defaultIndexPattern = await data.indexPatterns.getDefault();
|
const defaultDataView = await data.dataViews.getDefault();
|
||||||
if (defaultIndexPattern) {
|
if (defaultDataView) {
|
||||||
setIndexPattern(defaultIndexPattern);
|
setDataView(defaultDataView);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fetchIndexPattern();
|
fetchDataView();
|
||||||
}, [data.indexPatterns]);
|
}, [data.dataViews]);
|
||||||
|
|
||||||
return indexPattern;
|
return dataView;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useGlobalStateSyncing(
|
function useGlobalStateSyncing(
|
||||||
|
@ -167,7 +162,7 @@ function useAppStateSyncing<AppState extends QueryState>(
|
||||||
const stopSyncingQueryAppStateWithStateContainer = connectToQueryState(
|
const stopSyncingQueryAppStateWithStateContainer = connectToQueryState(
|
||||||
query,
|
query,
|
||||||
appStateContainer,
|
appStateContainer,
|
||||||
{ filters: esFilters.FilterStateStore.APP_STATE, query: true }
|
{ filters: FilterStateStore.APP_STATE, query: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
// sets up syncing app state container with url
|
// sets up syncing app state container with url
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
{ "path": "../../src/plugins/kibana_react/tsconfig.json" },
|
{ "path": "../../src/plugins/kibana_react/tsconfig.json" },
|
||||||
{ "path": "../../src/plugins/navigation/tsconfig.json" },
|
{ "path": "../../src/plugins/navigation/tsconfig.json" },
|
||||||
{ "path": "../../src/plugins/data/tsconfig.json" },
|
{ "path": "../../src/plugins/data/tsconfig.json" },
|
||||||
|
{ "path": "../../src/plugins/data_views/tsconfig.json" },
|
||||||
{ "path": "../developer_examples/tsconfig.json" },
|
{ "path": "../developer_examples/tsconfig.json" },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default async function ({ readConfigFile }) {
|
||||||
require.resolve('./state_sync'),
|
require.resolve('./state_sync'),
|
||||||
require.resolve('./routing'),
|
require.resolve('./routing'),
|
||||||
require.resolve('./expressions_explorer'),
|
require.resolve('./expressions_explorer'),
|
||||||
require.resolve('./index_pattern_field_editor_example'),
|
require.resolve('./data_view_field_editor_example'),
|
||||||
require.resolve('./field_formats'),
|
require.resolve('./field_formats'),
|
||||||
require.resolve('./partial_results'),
|
require.resolve('./partial_results'),
|
||||||
],
|
],
|
||||||
|
|
|
@ -13,8 +13,8 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
||||||
const testSubjects = getService('testSubjects');
|
const testSubjects = getService('testSubjects');
|
||||||
|
|
||||||
describe('', () => {
|
describe('', () => {
|
||||||
it('finds an index pattern', async () => {
|
it('finds a data view', async () => {
|
||||||
await testSubjects.existOrFail('indexPatternTitle');
|
await testSubjects.existOrFail('dataViewTitle');
|
||||||
});
|
});
|
||||||
it('opens the field editor', async () => {
|
it('opens the field editor', async () => {
|
||||||
await testSubjects.click('addField');
|
await testSubjects.click('addField');
|
|
@ -19,7 +19,7 @@ export default function ({
|
||||||
const es = getService('es');
|
const es = getService('es');
|
||||||
const PageObjects = getPageObjects(['common', 'header', 'settings']);
|
const PageObjects = getPageObjects(['common', 'header', 'settings']);
|
||||||
|
|
||||||
describe('index pattern field editor example', function () {
|
describe('data view field editor example', function () {
|
||||||
this.tags('ciGroup2');
|
this.tags('ciGroup2');
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await esArchiver.emptyKibanaIndex();
|
await esArchiver.emptyKibanaIndex();
|
||||||
|
@ -32,9 +32,9 @@ export default function ({
|
||||||
|
|
||||||
await PageObjects.settings.navigateTo();
|
await PageObjects.settings.navigateTo();
|
||||||
await PageObjects.settings.createIndexPattern('blogs', null);
|
await PageObjects.settings.createIndexPattern('blogs', null);
|
||||||
await PageObjects.common.navigateToApp('indexPatternFieldEditorExample');
|
await PageObjects.common.navigateToApp('dataViewFieldEditorExample');
|
||||||
});
|
});
|
||||||
|
|
||||||
loadTestFile(require.resolve('./index_pattern_field_editor_example'));
|
loadTestFile(require.resolve('./data_view_field_editor_example'));
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
await PageObjects.common.navigateToApp(appId, { insertTimestamp: false });
|
await PageObjects.common.navigateToApp(appId, { insertTimestamp: false });
|
||||||
await comboBox.setCustom('indexPatternSelector', 'logstash-*');
|
await comboBox.setCustom('dataViewSelector', 'logstash-*');
|
||||||
await comboBox.set('searchBucketField', 'geo.src');
|
await comboBox.set('searchBucketField', 'geo.src');
|
||||||
await comboBox.set('searchMetricField', 'memory');
|
await comboBox.set('searchMetricField', 'memory');
|
||||||
await PageObjects.timePicker.setAbsoluteRange(
|
await PageObjects.timePicker.setAbsoluteRange(
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should start search, save session, restore session using "restore" button', async () => {
|
it('should start search, save session, restore session using "restore" button', async () => {
|
||||||
await comboBox.setCustom('indexPatternSelector', 'logstash-*');
|
await comboBox.setCustom('dataViewSelector', 'logstash-*');
|
||||||
await comboBox.setCustom('searchMetricField', 'bytes');
|
await comboBox.setCustom('searchMetricField', 'bytes');
|
||||||
await testSubjects.clickWhenNotDisabled('startSearch');
|
await testSubjects.clickWhenNotDisabled('startSearch');
|
||||||
await testSubjects.find('searchResults-1');
|
await testSubjects.find('searchResults-1');
|
||||||
|
|
|
@ -32,7 +32,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
await PageObjects.common.navigateToApp(appId, { insertTimestamp: false });
|
await PageObjects.common.navigateToApp(appId, { insertTimestamp: false });
|
||||||
await comboBox.setCustom('indexPatternSelector', 'logstash-*');
|
await comboBox.setCustom('dataViewSelector', 'logstash-*');
|
||||||
await comboBox.set('searchBucketField', 'extension.raw');
|
await comboBox.set('searchBucketField', 'extension.raw');
|
||||||
await comboBox.set('searchMetricField', 'phpmemory');
|
await comboBox.set('searchMetricField', 'phpmemory');
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue