[UnifiedFieldList] Remove redundant server routes. Create new example plugin for unified field list components and migrate tests. (#158377)

- Closes https://github.com/elastic/kibana/issues/147885
- Closes https://github.com/elastic/kibana/issues/157109

## Summary

**Before:**

Unified Field List plugin has internal routes (wrappers for client code)
which exist only to run api functional tests against them:
 - `/api/unified_field_list/existing_fields/{dataViewId}`
 - `/api/unified_field_list/field_stats`

Client code does not call these routes directly. So there is no reason
in keeping and versioning them.

**After:**
- Internal routes are removed 
- A new "Unified Field List Examples" page was created
http://localhost:5601/app/unifiedFieldListExamples
- API functional tests (which used the routes) were converted to
functional tests against this new example page
- Created a new `unifiedFieldList` page object which is used now in
functional tests (methods are extracted from existing `discover` page
object).

**For testing:**

Steps:
1. Run Kibana with examples: `yarn start --run-examples` 
2. Install sample data
3. And navigate to Developer Examples > Unified Field List Examples
page.

![May-26-2023
13-24-03](5a2149f7-beb8-40a5-b7d5-9eeaabfd42ca)


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Julia Rechkunova 2023-05-31 13:25:47 +02:00 committed by GitHub
parent f43096a78f
commit 8d399fe3aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
90 changed files with 2104 additions and 1846 deletions

View file

@ -0,0 +1,9 @@
# unified_field_list_examples
Examples of unified field list components.
To run this example, ensure you have data to search against (for example, the sample datasets) and start kibana with the `--run-examples` flag.
```bash
yarn start --run-examples
```

View file

@ -0,0 +1,10 @@
/*
* 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.
*/
export const PLUGIN_ID = 'unifiedFieldListExamples';
export const PLUGIN_NAME = 'Unified Field List Examples';

View file

@ -0,0 +1,24 @@
{
"type": "plugin",
"id": "@kbn/unified-field-list-examples-plugin",
"owner": "@elastic/kibana-data-discovery",
"description": "Examples for using unified field list.",
"plugin": {
"id": "unifiedFieldListExamples",
"server": false,
"browser": true,
"requiredPlugins": [
"navigation",
"developerExamples",
"inspector",
"kibanaUtils",
"unifiedSearch",
"unifiedFieldList",
"data",
"dataViews",
"dataViewFieldEditor",
"charts",
"fieldFormats"
]
}
}

View file

@ -0,0 +1,37 @@
/*
* 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 React from 'react';
import ReactDOM from 'react-dom';
import { I18nProvider } from '@kbn/i18n-react';
import type { AppMountParameters, CoreStart } from '@kbn/core/public';
import { AppPluginStartDependencies } from './types';
import { UnifiedFieldListExampleApp } from './example_app';
export const renderApp = (
core: CoreStart,
deps: AppPluginStartDependencies,
{ element }: AppMountParameters
) => {
ReactDOM.render(
<I18nProvider>
<UnifiedFieldListExampleApp
services={{
core,
uiSettings: core.uiSettings,
...deps,
}}
/>
</I18nProvider>,
element
);
return () => {
ReactDOM.unmountComponentAtNode(element);
};
};

View file

@ -0,0 +1,161 @@
/*
* 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 React, { useCallback, useEffect, useState } from 'react';
import { css } from '@emotion/react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiPage,
EuiPageBody,
EuiPageSidebar,
EuiTitle,
EuiEmptyPrompt,
EuiLoadingLogo,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import type { DataView } from '@kbn/data-views-plugin/public';
import { RootDragDropProvider } from '@kbn/dom-drag-drop';
import type { DataViewField } from '@kbn/data-views-plugin/public';
import { PLUGIN_ID, PLUGIN_NAME } from '../common';
import { FieldListSidebar, FieldListSidebarProps } from './field_list_sidebar';
import { ExampleDropZone } from './example_drop_zone';
interface UnifiedFieldListExampleAppProps {
services: FieldListSidebarProps['services'];
}
export const UnifiedFieldListExampleApp: React.FC<UnifiedFieldListExampleAppProps> = ({
services,
}) => {
const { navigation, data, unifiedSearch } = services;
const { IndexPatternSelect } = unifiedSearch.ui;
const [dataView, setDataView] = useState<DataView | null>();
const [selectedFieldNames, setSelectedFieldNames] = useState<string[]>([]);
const onAddFieldToWorkplace = useCallback(
(field: DataViewField) => {
setSelectedFieldNames((names) => [...names, field.name]);
},
[setSelectedFieldNames]
);
const onRemoveFieldFromWorkspace = useCallback(
(field: DataViewField) => {
setSelectedFieldNames((names) => names.filter((name) => name !== field.name));
},
[setSelectedFieldNames]
);
const onDropFieldToWorkplace = useCallback(
(fieldName: string) => {
setSelectedFieldNames((names) => [...names.filter((name) => name !== fieldName), fieldName]);
},
[setSelectedFieldNames]
);
// Fetch the default data view using the `data.dataViews` service, as the component is mounted.
useEffect(() => {
const setDefaultDataView = async () => {
try {
const defaultDataView = await data.dataViews.getDefault();
setDataView(defaultDataView);
} catch (e) {
setDataView(null);
}
};
setDefaultDataView();
}, [data]);
if (typeof dataView === 'undefined') {
return (
<EuiEmptyPrompt
icon={<EuiLoadingLogo logo="logoKibana" size="xl" />}
title={<h2>{PLUGIN_NAME}</h2>}
body={<p>Loading...</p>}
/>
);
}
return (
<EuiPage grow={true}>
<EuiPageBody paddingSize="s">
<EuiFlexGroup direction="column" gutterSize="xs">
<EuiFlexItem grow={false}>
<EuiTitle>
<h1>{PLUGIN_NAME}</h1>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<IndexPatternSelect
placeholder={i18n.translate('searchSessionExample.selectDataViewPlaceholder', {
defaultMessage: 'Select data view',
})}
indexPatternId={dataView?.id || ''}
onChange={async (dataViewId?: string) => {
if (dataViewId) {
const newDataView = await data.dataViews.get(dataViewId);
setDataView(newDataView);
} else {
setDataView(undefined);
}
}}
isClearable={false}
data-test-subj="dataViewSelector"
/>
</EuiFlexItem>
{dataView ? (
<>
<EuiFlexItem grow={false}>
<navigation.ui.TopNavMenu
appName={PLUGIN_ID}
showSearchBar={true}
useDefaultBehaviors={true}
indexPatterns={dataView ? [dataView] : undefined}
/>
</EuiFlexItem>
<EuiFlexItem grow={true}>
<RootDragDropProvider>
<EuiFlexGroup direction="row" alignItems="stretch">
<EuiFlexItem grow={false}>
<EuiPageSidebar
css={css`
flex: 1;
width: 320px;
`}
>
<FieldListSidebar
services={services}
dataView={dataView}
selectedFieldNames={selectedFieldNames}
onAddFieldToWorkplace={onAddFieldToWorkplace}
onRemoveFieldFromWorkspace={onRemoveFieldFromWorkspace}
/>
</EuiPageSidebar>
</EuiFlexItem>
<EuiFlexItem>
<ExampleDropZone onDropField={onDropFieldToWorkplace} />
</EuiFlexItem>
</EuiFlexGroup>
</RootDragDropProvider>
</EuiFlexItem>
</>
) : (
<EuiEmptyPrompt
iconType="warning"
color="warning"
title={<h2>Select a data view</h2>}
body={<p>Make sure to have at least one data view or install sample data.</p>}
/>
)}
</EuiFlexGroup>
</EuiPageBody>
</EuiPage>
);
};

View file

@ -0,0 +1,73 @@
/*
* 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.
*/
/*
* 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 React, { useContext, useMemo } from 'react';
import { DragContext, DragDrop, DropOverlayWrapper, DropType } from '@kbn/dom-drag-drop';
import { EuiEmptyPrompt, EuiPanel } from '@elastic/eui';
const DROP_PROPS = {
value: {
id: 'exampleDropZone',
humanData: {
label: 'Drop zone for selecting fields',
},
},
order: [1, 0, 0, 0],
types: ['field_add'] as DropType[],
};
export interface ExampleDropZoneProps {
onDropField: (fieldName: string) => void;
}
export const ExampleDropZone: React.FC<ExampleDropZoneProps> = ({ onDropField }) => {
const dragDropContext = useContext(DragContext);
const draggingFieldName = dragDropContext.dragging?.id;
const onDroppingField = useMemo(() => {
if (!draggingFieldName) {
return undefined;
}
return () => onDropField(draggingFieldName);
}, [onDropField, draggingFieldName]);
const isDropAllowed = Boolean(onDroppingField);
return (
<DragDrop
draggable={false}
dropTypes={isDropAllowed ? DROP_PROPS.types : undefined}
value={DROP_PROPS.value}
order={DROP_PROPS.order}
onDrop={onDroppingField}
>
<DropOverlayWrapper isVisible={isDropAllowed}>
<EuiPanel hasShadow={false} paddingSize="l" className="eui-fullHeight">
<EuiEmptyPrompt
iconType="beaker"
title={<h3>Example drop zone</h3>}
body={
<p>
Drop <strong>{draggingFieldName || 'a field'}</strong> here to select it
</p>
}
/>
</EuiPanel>
</DropOverlayWrapper>
</DragDrop>
);
};

View file

@ -0,0 +1,225 @@
/*
* 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.
*/
/*
* 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 React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { DataViewField, DataView } from '@kbn/data-views-plugin/common';
import { DragDrop } from '@kbn/dom-drag-drop';
import {
AddFieldFilterHandler,
FieldItemButton,
FieldItemButtonProps,
FieldPopover,
FieldPopoverHeader,
FieldsGroupNames,
FieldStats,
hasQuerySubscriberData,
RenderFieldItemParams,
useQuerySubscriber,
} from '@kbn/unified-field-list-plugin/public';
import { generateFilters } from '@kbn/data-plugin/public';
import type { CoreStart } from '@kbn/core-lifecycle-browser';
import type { AppPluginStartDependencies } from './types';
export interface FieldListItemProps extends RenderFieldItemParams<DataViewField> {
dataView: DataView;
services: AppPluginStartDependencies & {
core: CoreStart;
uiSettings: CoreStart['uiSettings'];
};
isSelected: boolean;
onAddFieldToWorkspace: FieldItemButtonProps<DataViewField>['onAddFieldToWorkspace'];
onRemoveFieldFromWorkspace: FieldItemButtonProps<DataViewField>['onRemoveFieldFromWorkspace'];
onRefreshFields: () => void;
}
export function FieldListItem({
dataView,
services,
isSelected,
field,
fieldSearchHighlight,
groupIndex,
groupName,
itemIndex,
hideDetails,
onRefreshFields,
onAddFieldToWorkspace,
onRemoveFieldFromWorkspace,
}: FieldListItemProps) {
const { dataViewFieldEditor, data } = services;
const querySubscriberResult = useQuerySubscriber({ data, listenToSearchSessionUpdates: false }); // this example app does not use search sessions
const filterManager = data?.query?.filterManager;
const [infoIsOpen, setOpen] = useState(false);
const togglePopover = useCallback(() => {
setOpen((value) => !value);
}, [setOpen]);
const closePopover = useCallback(() => {
setOpen(false);
}, [setOpen]);
const closeFieldEditor = useRef<() => void | undefined>();
const setFieldEditorRef = useCallback((ref: () => void | undefined) => {
closeFieldEditor.current = ref;
}, []);
const value = useMemo(
() => ({
id: field.name,
humanData: { label: field.displayName || field.name },
}),
[field]
);
const order = useMemo(() => [0, groupIndex, itemIndex], [groupIndex, itemIndex]);
const addFilterAndClose: AddFieldFilterHandler | undefined = useMemo(
() =>
filterManager && dataView
? (clickedField, values, operation) => {
closePopover();
const newFilters = generateFilters(
filterManager,
clickedField,
values,
operation,
dataView
);
filterManager.addFilters(newFilters);
}
: undefined,
[dataView, filterManager, closePopover]
);
const editFieldAndClose = useMemo(
() =>
dataView
? (fieldName?: string) => {
const ref = dataViewFieldEditor.openEditor({
ctx: {
dataView,
},
fieldName,
onSave: async () => {
onRefreshFields();
},
});
if (setFieldEditorRef) {
setFieldEditorRef(ref);
}
closePopover();
}
: undefined,
[dataViewFieldEditor, dataView, setFieldEditorRef, closePopover, onRefreshFields]
);
const removeFieldAndClose = useMemo(
() =>
dataView
? async (fieldName: string) => {
const ref = dataViewFieldEditor.openDeleteModal({
ctx: {
dataView,
},
fieldName,
onDelete: async () => {
onRefreshFields();
},
});
if (setFieldEditorRef) {
setFieldEditorRef(ref);
}
closePopover();
}
: undefined,
[dataView, setFieldEditorRef, closePopover, dataViewFieldEditor, onRefreshFields]
);
useEffect(() => {
const cleanup = () => {
if (closeFieldEditor?.current) {
closeFieldEditor?.current();
}
};
return () => {
// Make sure to close the editor when unmounting
cleanup();
};
}, []);
return (
<li>
<FieldPopover
isOpen={infoIsOpen}
closePopover={closePopover}
button={
<DragDrop
draggable
order={order}
value={value}
dataTestSubj={`fieldListPanelField-${field.name}`}
onDragStart={closePopover}
>
<FieldItemButton
field={field}
fieldSearchHighlight={fieldSearchHighlight}
size="xs"
isActive={infoIsOpen}
isEmpty={groupName === FieldsGroupNames.EmptyFields}
isSelected={isSelected}
onClick={togglePopover}
onAddFieldToWorkspace={onAddFieldToWorkspace}
onRemoveFieldFromWorkspace={onRemoveFieldFromWorkspace}
/>
</DragDrop>
}
renderHeader={() => {
return (
<FieldPopoverHeader
field={field}
closePopover={closePopover}
onAddFieldToWorkspace={!isSelected ? onAddFieldToWorkspace : undefined}
onAddFilter={addFilterAndClose}
onEditField={editFieldAndClose}
onDeleteField={removeFieldAndClose}
/>
);
}}
renderContent={
!hideDetails
? () => (
<>
{hasQuerySubscriberData(querySubscriberResult) && (
<FieldStats
services={services}
query={querySubscriberResult.query}
filters={querySubscriberResult.filters}
fromDate={querySubscriberResult.fromDate}
toDate={querySubscriberResult.toDate}
dataViewOrDataViewId={dataView}
onAddFilter={addFilterAndClose}
field={field}
/>
)}
</>
)
: undefined
}
/>
</li>
);
}

View file

@ -0,0 +1,127 @@
/*
* 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.
*/
/*
* 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 React, { useCallback, useContext, useMemo } from 'react';
import type { DataView, DataViewField } from '@kbn/data-views-plugin/public';
import { ChildDragDropProvider, DragContext } from '@kbn/dom-drag-drop';
import {
FieldList,
FieldListFilters,
FieldListGrouped,
FieldListGroupedProps,
FieldsGroupNames,
useExistingFieldsFetcher,
useGroupedFields,
useQuerySubscriber,
} from '@kbn/unified-field-list-plugin/public';
import { FieldListItem, FieldListItemProps } from './field_list_item';
export interface FieldListSidebarProps {
dataView: DataView;
selectedFieldNames: string[];
services: FieldListItemProps['services'];
onAddFieldToWorkplace: FieldListItemProps['onAddFieldToWorkspace'];
onRemoveFieldFromWorkspace: FieldListItemProps['onRemoveFieldFromWorkspace'];
}
export const FieldListSidebar: React.FC<FieldListSidebarProps> = ({
dataView,
selectedFieldNames,
services,
onAddFieldToWorkplace,
onRemoveFieldFromWorkspace,
}) => {
const dragDropContext = useContext(DragContext);
const allFields = dataView.fields;
const activeDataViews = useMemo(() => [dataView], [dataView]);
const querySubscriberResult = useQuerySubscriber({
data: services.data,
listenToSearchSessionUpdates: false, // this example app does not use search sessions
});
const onSelectedFieldFilter = useCallback(
(field: DataViewField) => {
return selectedFieldNames.includes(field.name);
},
[selectedFieldNames]
);
const { refetchFieldsExistenceInfo, isProcessing } = useExistingFieldsFetcher({
dataViews: activeDataViews, // if you need field existence info for more than one data view, you can specify it here
query: querySubscriberResult.query,
filters: querySubscriberResult.filters,
fromDate: querySubscriberResult.fromDate,
toDate: querySubscriberResult.toDate,
services,
});
const { fieldListFiltersProps, fieldListGroupedProps } = useGroupedFields({
dataViewId: dataView.id ?? null,
allFields,
services,
isAffectedByGlobalFilter: Boolean(querySubscriberResult.filters?.length),
onSupportedFieldFilter,
onSelectedFieldFilter,
});
const onRefreshFields = useCallback(() => {
refetchFieldsExistenceInfo();
}, [refetchFieldsExistenceInfo]);
const renderFieldItem: FieldListGroupedProps<DataViewField>['renderFieldItem'] = useCallback(
(params) => (
<FieldListItem
dataView={dataView}
services={services}
isSelected={
params.groupName === FieldsGroupNames.SelectedFields ||
selectedFieldNames.includes(params.field.name)
}
onRefreshFields={onRefreshFields}
onAddFieldToWorkspace={onAddFieldToWorkplace}
onRemoveFieldFromWorkspace={onRemoveFieldFromWorkspace}
{...params}
/>
),
[
dataView,
services,
onRefreshFields,
selectedFieldNames,
onAddFieldToWorkplace,
onRemoveFieldFromWorkspace,
]
);
return (
<ChildDragDropProvider {...dragDropContext}>
<FieldList
isProcessing={isProcessing}
prepend={<FieldListFilters {...fieldListFiltersProps} />}
>
<FieldListGrouped
{...fieldListGroupedProps}
renderFieldItem={renderFieldItem}
localStorageKeyPrefix="examples"
/>
</FieldList>
</ChildDragDropProvider>
);
};
function onSupportedFieldFilter(field: DataViewField): boolean {
return field.name !== '_source';
}

View file

@ -0,0 +1,19 @@
/*
* 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 { UnifiedFieldListExamplesPlugin } from './plugin';
// This exports static code and TypeScript types,
// as well as, Kibana Platform `plugin()` initializer.
export function plugin() {
return new UnifiedFieldListExamplesPlugin();
}
export type {
UnifiedFieldListExamplesPluginSetup,
UnifiedFieldListExamplesPluginStart,
} from './types';

View file

@ -0,0 +1,77 @@
/*
* 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 {
AppMountParameters,
AppNavLinkStatus,
CoreSetup,
CoreStart,
Plugin,
} from '@kbn/core/public';
import {
AppPluginSetupDependencies,
AppPluginStartDependencies,
UnifiedFieldListExamplesPluginSetup,
UnifiedFieldListExamplesPluginStart,
} from './types';
import { PLUGIN_ID, PLUGIN_NAME } from '../common';
import image from './unified_field_list.png';
export class UnifiedFieldListExamplesPlugin
implements
Plugin<
UnifiedFieldListExamplesPluginSetup,
UnifiedFieldListExamplesPluginStart,
AppPluginSetupDependencies,
AppPluginStartDependencies
>
{
public setup(
core: CoreSetup<AppPluginStartDependencies>,
{ developerExamples }: AppPluginSetupDependencies
): UnifiedFieldListExamplesPluginSetup {
// Register an application into the side navigation menu
core.application.register({
id: PLUGIN_ID,
title: PLUGIN_NAME,
navLinkStatus: AppNavLinkStatus.hidden,
mount: async (params: AppMountParameters) => {
// Load application bundle
const { renderApp } = await import('./application');
// Get start services as specified in kibana.json
const [coreStart, depsStart] = await core.getStartServices();
// Render the application
return renderApp(coreStart, depsStart, params);
},
});
developerExamples.register({
appId: PLUGIN_ID,
title: PLUGIN_NAME,
description: `Examples of unified field list functionality.`,
image,
links: [
{
label: 'README',
href: 'https://github.com/elastic/kibana/tree/main/src/plugins/unified_field_list/README.md',
iconType: 'logoGithub',
target: '_blank',
size: 's',
},
],
});
return {};
}
public start(core: CoreStart): UnifiedFieldListExamplesPluginStart {
return {};
}
public stop() {}
}

View file

@ -0,0 +1,35 @@
/*
* 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 type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
import type { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public';
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import type { ChartsPluginStart } from '@kbn/charts-plugin/public';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import type { DataViewFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface UnifiedFieldListExamplesPluginSetup {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface UnifiedFieldListExamplesPluginStart {}
export interface AppPluginSetupDependencies {
developerExamples: DeveloperExamplesSetup;
}
export interface AppPluginStartDependencies {
navigation: NavigationPublicPluginStart;
data: DataPublicPluginStart;
dataViews: DataViewsPublicPluginStart;
dataViewFieldEditor: DataViewFieldEditorStart;
unifiedSearch: UnifiedSearchPublicPluginStart;
charts: ChartsPluginStart;
fieldFormats: FieldFormatsStart;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View file

@ -0,0 +1,32 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types"
},
"include": [
"index.ts",
"common/**/*.ts",
"public/**/*.ts",
"public/**/*.tsx",
"../../typings/**/*",
],
"exclude": [
"target/**/*",
],
"kbn_references": [
"@kbn/core",
"@kbn/data-plugin",
"@kbn/data-views-plugin",
"@kbn/navigation-plugin",
"@kbn/developer-examples-plugin",
"@kbn/unified-search-plugin",
"@kbn/i18n-react",
"@kbn/i18n",
"@kbn/dom-drag-drop",
"@kbn/unified-field-list-plugin",
"@kbn/core-lifecycle-browser",
"@kbn/charts-plugin",
"@kbn/field-formats-plugin",
"@kbn/data-view-field-editor-plugin",
]
}