mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Lens] Move esql editor to layer_panel.tsx (#208354)
## Summary moves esql editor to layer_panel.tsx as preparation to enable esql editing on each layer. how to test this: - create esql visualization in discover and put it on a dashboard - edit visualization on the dashboard (esql query etc) - everything should work exactly as before --------- Co-authored-by: Stratoula Kalafateli <efstratia.kalafateli@elastic.co> Co-authored-by: dej611 <dej611@gmail.com> Co-authored-by: Marco Liberati <dej611@users.noreply.github.com>
This commit is contained in:
parent
73c8a5184f
commit
907abc687b
15 changed files with 479 additions and 232 deletions
|
@ -92,6 +92,7 @@ describe('Lens inline editing helpers', () => {
|
|||
createMockStartDependencies() as unknown as LensPluginStartDependencies;
|
||||
const dataViews = dataViewPluginMocks.createStartContract();
|
||||
dataViews.create.mockResolvedValue(mockDataViewWithTimefield);
|
||||
mockStartDependencies.data.dataViews = dataViews;
|
||||
const dataviewSpecArr = [
|
||||
{
|
||||
id: 'd2588ae7-9ea0-4439-9f5b-f808754a3b97',
|
||||
|
@ -113,7 +114,7 @@ describe('Lens inline editing helpers', () => {
|
|||
it('returns the suggestions attributes correctly', async () => {
|
||||
const suggestionsAttributes = await getSuggestions(
|
||||
query,
|
||||
startDependencies,
|
||||
startDependencies.data,
|
||||
mockDatasourceMap(),
|
||||
mockVisualizationMap(),
|
||||
dataviewSpecArr,
|
||||
|
@ -129,7 +130,7 @@ describe('Lens inline editing helpers', () => {
|
|||
mockSuggestionApi.mockResolvedValueOnce([]);
|
||||
const suggestionsAttributes = await getSuggestions(
|
||||
query,
|
||||
startDependencies,
|
||||
startDependencies.data,
|
||||
mockDatasourceMap(),
|
||||
mockVisualizationMap(),
|
||||
dataviewSpecArr,
|
||||
|
@ -145,7 +146,7 @@ describe('Lens inline editing helpers', () => {
|
|||
const setErrorsSpy = jest.fn();
|
||||
const suggestionsAttributes = await getSuggestions(
|
||||
query,
|
||||
startDependencies,
|
||||
startDependencies.data,
|
||||
mockDatasourceMap(),
|
||||
mockVisualizationMap(),
|
||||
dataviewSpecArr,
|
||||
|
|
|
@ -26,7 +26,6 @@ import type { DatatableColumn } from '@kbn/expressions-plugin/common';
|
|||
import { getTime } from '@kbn/data-plugin/common';
|
||||
import { type DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { TypedLensSerializedState } from '../../../react_embeddable/types';
|
||||
import type { LensPluginStartDependencies } from '../../../plugin';
|
||||
import type { DatasourceMap, VisualizationMap } from '../../../types';
|
||||
import { suggestionsApi } from '../../../lens_suggestions_api';
|
||||
|
||||
|
@ -54,7 +53,7 @@ const getDSLFilter = (queryService: DataPublicPluginStart['query'], timeFieldNam
|
|||
export const getGridAttrs = async (
|
||||
query: AggregateQuery,
|
||||
adHocDataViews: DataViewSpec[],
|
||||
deps: LensPluginStartDependencies,
|
||||
data: DataPublicPluginStart,
|
||||
abortController?: AbortController,
|
||||
esqlVariables: ESQLControlVariable[] = []
|
||||
): Promise<ESQLDataGridAttrs> => {
|
||||
|
@ -64,18 +63,18 @@ export const getGridAttrs = async (
|
|||
});
|
||||
|
||||
const dataView = dataViewSpec
|
||||
? await deps.dataViews.create(dataViewSpec)
|
||||
: await getESQLAdHocDataview(query.esql, deps.dataViews);
|
||||
? await data.dataViews.create(dataViewSpec)
|
||||
: await getESQLAdHocDataview(query.esql, data.dataViews);
|
||||
|
||||
const filter = getDSLFilter(deps.data.query, dataView.timeFieldName);
|
||||
const filter = getDSLFilter(data.query, dataView.timeFieldName);
|
||||
|
||||
const results = await getESQLResults({
|
||||
esqlQuery: query.esql,
|
||||
search: deps.data.search.search,
|
||||
search: data.search.search,
|
||||
signal: abortController?.signal,
|
||||
filter,
|
||||
dropNullColumns: true,
|
||||
timeRange: deps.data.query.timefilter.timefilter.getAbsoluteTime(),
|
||||
timeRange: data.query.timefilter.timefilter.getAbsoluteTime(),
|
||||
variables: esqlVariables,
|
||||
});
|
||||
|
||||
|
@ -90,7 +89,7 @@ export const getGridAttrs = async (
|
|||
|
||||
export const getSuggestions = async (
|
||||
query: AggregateQuery,
|
||||
deps: LensPluginStartDependencies,
|
||||
data: DataPublicPluginStart,
|
||||
datasourceMap: DatasourceMap,
|
||||
visualizationMap: VisualizationMap,
|
||||
adHocDataViews: DataViewSpec[],
|
||||
|
@ -105,7 +104,7 @@ export const getSuggestions = async (
|
|||
const { dataView, columns, rows } = await getGridAttrs(
|
||||
query,
|
||||
adHocDataViews,
|
||||
deps,
|
||||
data,
|
||||
abortController,
|
||||
esqlVariables
|
||||
);
|
||||
|
|
|
@ -28,6 +28,15 @@ export function LayerConfiguration({
|
|||
setIsInlineFlyoutVisible,
|
||||
getUserMessages,
|
||||
onlyAllowSwitchToSubtypes,
|
||||
lensAdapters,
|
||||
dataLoading$,
|
||||
setCurrentAttributes,
|
||||
updateSuggestion,
|
||||
parentApi,
|
||||
panelId,
|
||||
closeFlyout,
|
||||
canEditTextBasedQuery,
|
||||
editorContainer,
|
||||
}: LayerConfigurationProps) {
|
||||
const dispatch = useLensDispatch();
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
@ -51,6 +60,9 @@ export function LayerConfiguration({
|
|||
);
|
||||
|
||||
const layerPanelsProps = {
|
||||
attributes,
|
||||
lensAdapters,
|
||||
dataLoading$,
|
||||
framePublicAPI,
|
||||
datasourceMap,
|
||||
visualizationMap,
|
||||
|
@ -63,6 +75,14 @@ export function LayerConfiguration({
|
|||
indexPatternService,
|
||||
setIsInlineFlyoutVisible,
|
||||
getUserMessages,
|
||||
data: startDependencies.data,
|
||||
setCurrentAttributes,
|
||||
updateSuggestion,
|
||||
parentApi,
|
||||
panelId,
|
||||
closeFlyout,
|
||||
canEditTextBasedQuery,
|
||||
editorContainer,
|
||||
};
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useMemo, useCallback, useRef, useEffect, useState } from 'react';
|
||||
import React, { useMemo, useCallback, useRef, useState } from 'react';
|
||||
import { isEqual } from 'lodash';
|
||||
import { css } from '@emotion/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -21,36 +21,17 @@ import {
|
|||
keys,
|
||||
} from '@elastic/eui';
|
||||
import { euiThemeVars } from '@kbn/ui-theme';
|
||||
import {
|
||||
getAggregateQueryMode,
|
||||
isOfAggregateQueryType,
|
||||
getLanguageDisplayName,
|
||||
} from '@kbn/es-query';
|
||||
import type { AggregateQuery, Query } from '@kbn/es-query';
|
||||
import { useStateFromPublishingSubject } from '@kbn/presentation-publishing';
|
||||
import { ESQLLangEditor } from '@kbn/esql/public';
|
||||
import { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common';
|
||||
import { getLanguageDisplayName, isOfAggregateQueryType } from '@kbn/es-query';
|
||||
import type { TypedLensSerializedState } from '../../../react_embeddable/types';
|
||||
import { buildExpression } from '../../../editor_frame_service/editor_frame/expression_helpers';
|
||||
import { MAX_NUM_OF_COLUMNS } from '../../../datasources/text_based/utils';
|
||||
import {
|
||||
useLensSelector,
|
||||
selectFramePublicAPI,
|
||||
onActiveDataChange,
|
||||
useLensDispatch,
|
||||
} from '../../../state_management';
|
||||
import { useLensSelector, selectFramePublicAPI, useLensDispatch } from '../../../state_management';
|
||||
import { EXPRESSION_BUILD_ERROR_ID, getAbsoluteDateRange } from '../../../utils';
|
||||
import { LayerConfiguration } from './layer_configuration_section';
|
||||
import type { EditConfigPanelProps } from './types';
|
||||
import { FlyoutWrapper } from './flyout_wrapper';
|
||||
import { getSuggestions, type ESQLDataGridAttrs } from './helpers';
|
||||
import { SuggestionPanel } from '../../../editor_frame_service/editor_frame/suggestion_panel';
|
||||
import { useApplicationUserMessages } from '../../get_application_user_messages';
|
||||
import { trackSaveUiCounterEvents } from '../../../lens_ui_telemetry';
|
||||
import { ESQLDataGridAccordion } from './esql_data_grid_accordion';
|
||||
import { isApiESQLVariablesCompatible } from '../../../react_embeddable/types';
|
||||
import { useESQLVariables } from './use_esql_variables';
|
||||
import { getActiveDataFromDatatable } from '../../../state_management/shared_logic';
|
||||
import { useCurrentAttributes } from './use_current_attributes';
|
||||
|
||||
export function LensEditConfigurationFlyout({
|
||||
|
@ -82,31 +63,10 @@ export function LensEditConfigurationFlyout({
|
|||
}: EditConfigPanelProps) {
|
||||
const euiTheme = useEuiTheme();
|
||||
const previousAttributes = useRef<TypedLensSerializedState['attributes']>(attributes);
|
||||
const previousAdapters = useRef<Partial<DefaultInspectorAdapters> | undefined>(lensAdapters);
|
||||
const prevQuery = useRef<AggregateQuery | Query>(attributes.state.query);
|
||||
const [query, setQuery] = useState<AggregateQuery | Query>(attributes.state.query);
|
||||
|
||||
const [errors, setErrors] = useState<Error[] | undefined>();
|
||||
const [isInlineFlyoutVisible, setIsInlineFlyoutVisible] = useState(true);
|
||||
const [isLayerAccordionOpen, setIsLayerAccordionOpen] = useState(true);
|
||||
const [suggestsLimitedColumns, setSuggestsLimitedColumns] = useState(false);
|
||||
const [isSuggestionsAccordionOpen, setIsSuggestionsAccordionOpen] = useState(false);
|
||||
const [isESQLResultsAccordionOpen, setIsESQLResultsAccordionOpen] = useState(false);
|
||||
const [isVisualizationLoading, setIsVisualizationLoading] = useState(false);
|
||||
const [dataGridAttrs, setDataGridAttrs] = useState<ESQLDataGridAttrs | undefined>(undefined);
|
||||
const datasourceState = attributes.state.datasourceStates[datasourceId];
|
||||
const activeDatasource = datasourceMap[datasourceId];
|
||||
|
||||
const esqlVariables = useStateFromPublishingSubject(
|
||||
isApiESQLVariablesCompatible(parentApi) ? parentApi?.esqlVariables$ : undefined
|
||||
);
|
||||
|
||||
const { onSaveControl, onCancelControl } = useESQLVariables({
|
||||
parentApi,
|
||||
panelId,
|
||||
attributes,
|
||||
closeFlyout,
|
||||
});
|
||||
|
||||
const { datasourceStates, visualization, isLoading, annotationGroups, searchSessionId } =
|
||||
useLensSelector((state) => state.lens);
|
||||
|
@ -120,44 +80,7 @@ export function LensEditConfigurationFlyout({
|
|||
startDependencies.data.query.timefilter.timefilter
|
||||
);
|
||||
|
||||
const layers = useMemo(
|
||||
() => activeDatasource.getLayers(datasourceState),
|
||||
[activeDatasource, datasourceState]
|
||||
);
|
||||
|
||||
// needed for text based languages mode which works ONLY with adHoc dataviews
|
||||
const adHocDataViews = Object.values(attributes.state.adHocDataViews ?? {});
|
||||
|
||||
const dispatch = useLensDispatch();
|
||||
useEffect(() => {
|
||||
const s = dataLoading$?.subscribe((isDataLoading) => {
|
||||
// go thru only when the loading is complete
|
||||
if (isDataLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [defaultLayerId] = Object.keys(framePublicAPI.datasourceLayers);
|
||||
const activeData = getActiveDataFromDatatable(
|
||||
defaultLayerId,
|
||||
previousAdapters.current?.tables?.tables
|
||||
);
|
||||
|
||||
layers.forEach((layer) => {
|
||||
const table = activeData[layer];
|
||||
|
||||
if (table) {
|
||||
// there are cases where a query can return a big amount of columns
|
||||
// at this case we don't suggest all columns in a table but the first `MAX_NUM_OF_COLUMNS`
|
||||
setSuggestsLimitedColumns(table.columns.length >= MAX_NUM_OF_COLUMNS);
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(activeData).length > 0) {
|
||||
dispatch(onActiveDataChange({ activeData }));
|
||||
}
|
||||
});
|
||||
return () => s?.unsubscribe();
|
||||
}, [dispatch, dataLoading$, layers, framePublicAPI.datasourceLayers]);
|
||||
|
||||
const attributesChanged: boolean = useMemo(() => {
|
||||
const previousAttrs = previousAttributes.current;
|
||||
|
@ -234,10 +157,7 @@ export function LensEditConfigurationFlyout({
|
|||
onCancelCallback,
|
||||
]);
|
||||
|
||||
const textBasedMode = useMemo(
|
||||
() => (isOfAggregateQueryType(query) ? getAggregateQueryMode(query) : undefined),
|
||||
[query]
|
||||
);
|
||||
const textBasedMode = isOfAggregateQueryType(attributes.state.query);
|
||||
|
||||
const currentAttributes = useCurrentAttributes({
|
||||
textBasedMode,
|
||||
|
@ -247,7 +167,7 @@ export function LensEditConfigurationFlyout({
|
|||
});
|
||||
|
||||
const onApply = useCallback(() => {
|
||||
if (visualization.activeId == null) {
|
||||
if (visualization.activeId == null || !currentAttributes) {
|
||||
return;
|
||||
}
|
||||
if (savedObjectId) {
|
||||
|
@ -272,12 +192,12 @@ export function LensEditConfigurationFlyout({
|
|||
closeFlyout?.();
|
||||
}, [
|
||||
visualization.activeId,
|
||||
visualization.state,
|
||||
savedObjectId,
|
||||
activeVisualization,
|
||||
onApplyCallback,
|
||||
currentAttributes,
|
||||
closeFlyout,
|
||||
onApplyCallback,
|
||||
visualization.state,
|
||||
activeVisualization,
|
||||
currentAttributes,
|
||||
saveByRef,
|
||||
updateByRefInput,
|
||||
]);
|
||||
|
@ -294,63 +214,7 @@ export function LensEditConfigurationFlyout({
|
|||
visualizationState: visualization,
|
||||
});
|
||||
|
||||
const runQuery = useCallback(
|
||||
async (q: AggregateQuery, abortController?: AbortController, shouldUpdateAttrs?: boolean) => {
|
||||
const attrs = await getSuggestions(
|
||||
q,
|
||||
startDependencies,
|
||||
datasourceMap,
|
||||
visualizationMap,
|
||||
adHocDataViews,
|
||||
setErrors,
|
||||
abortController,
|
||||
setDataGridAttrs,
|
||||
esqlVariables,
|
||||
shouldUpdateAttrs,
|
||||
currentAttributes
|
||||
);
|
||||
if (attrs) {
|
||||
setCurrentAttributes?.(attrs);
|
||||
setErrors([]);
|
||||
updateSuggestion?.(attrs);
|
||||
}
|
||||
prevQuery.current = q;
|
||||
setIsVisualizationLoading(false);
|
||||
},
|
||||
[
|
||||
startDependencies,
|
||||
datasourceMap,
|
||||
visualizationMap,
|
||||
adHocDataViews,
|
||||
esqlVariables,
|
||||
currentAttributes,
|
||||
setCurrentAttributes,
|
||||
updateSuggestion,
|
||||
]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
const initializeChart = async () => {
|
||||
if (isOfAggregateQueryType(query) && !dataGridAttrs) {
|
||||
try {
|
||||
await runQuery(query, abortController, Boolean(attributes.state.needsRefresh));
|
||||
} catch (e) {
|
||||
setErrors([e]);
|
||||
prevQuery.current = query;
|
||||
}
|
||||
}
|
||||
};
|
||||
initializeChart();
|
||||
}, [
|
||||
adHocDataViews,
|
||||
runQuery,
|
||||
esqlVariables,
|
||||
query,
|
||||
startDependencies,
|
||||
dataGridAttrs,
|
||||
attributes.state.needsRefresh,
|
||||
]);
|
||||
const editorContainer = useRef(null);
|
||||
|
||||
const isSaveable = useMemo(() => {
|
||||
if (!attributesChanged) {
|
||||
|
@ -430,6 +294,12 @@ export function LensEditConfigurationFlyout({
|
|||
hasPadding
|
||||
framePublicAPI={framePublicAPI}
|
||||
setIsInlineFlyoutVisible={setIsInlineFlyoutVisible}
|
||||
updateSuggestion={updateSuggestion}
|
||||
setCurrentAttributes={setCurrentAttributes}
|
||||
closeFlyout={closeFlyout}
|
||||
parentApi={parentApi}
|
||||
panelId={panelId}
|
||||
canEditTextBasedQuery={canEditTextBasedQuery}
|
||||
/>
|
||||
</FlyoutWrapper>
|
||||
</>
|
||||
|
@ -445,9 +315,9 @@ export function LensEditConfigurationFlyout({
|
|||
onCancel={onCancel}
|
||||
navigateToLensEditor={navigateToLensEditor}
|
||||
onApply={onApply}
|
||||
language={textBasedMode ? getLanguageDisplayName(textBasedMode) : ''}
|
||||
isSaveable={isSaveable}
|
||||
isScrollable={false}
|
||||
language={textBasedMode ? getLanguageDisplayName('esql') : ''}
|
||||
isNewPanel={isNewPanel}
|
||||
>
|
||||
<EuiFlexGroup
|
||||
|
@ -489,60 +359,7 @@ export function LensEditConfigurationFlyout({
|
|||
direction="column"
|
||||
gutterSize="none"
|
||||
>
|
||||
{isOfAggregateQueryType(query) && canEditTextBasedQuery && (
|
||||
<EuiFlexItem grow={false} data-test-subj="InlineEditingESQLEditor">
|
||||
<ESQLLangEditor
|
||||
query={query}
|
||||
onTextLangQueryChange={(q) => {
|
||||
setQuery(q);
|
||||
}}
|
||||
detectedTimestamp={adHocDataViews?.[0]?.timeFieldName}
|
||||
hideTimeFilterInfo={hideTimeFilterInfo}
|
||||
errors={errors}
|
||||
warning={
|
||||
suggestsLimitedColumns
|
||||
? i18n.translate('xpack.lens.config.configFlyoutCallout', {
|
||||
defaultMessage:
|
||||
'Displaying a limited portion of the available fields. Add more from the configuration panel.',
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
editorIsInline
|
||||
supportsControls
|
||||
hideRunQueryText
|
||||
onTextLangQuerySubmit={async (q, a) => {
|
||||
// do not run the suggestions if the query is the same as the previous one
|
||||
if (q && !isEqual(q, prevQuery.current)) {
|
||||
setIsVisualizationLoading(true);
|
||||
await runQuery(q, a);
|
||||
}
|
||||
}}
|
||||
isDisabled={false}
|
||||
allowQueryCancellation
|
||||
isLoading={isVisualizationLoading}
|
||||
onSaveControl={onSaveControl}
|
||||
onCancelControl={onCancelControl}
|
||||
esqlVariables={esqlVariables}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
{isOfAggregateQueryType(query) && canEditTextBasedQuery && dataGridAttrs && (
|
||||
<ESQLDataGridAccordion
|
||||
dataGridAttrs={dataGridAttrs}
|
||||
isAccordionOpen={isESQLResultsAccordionOpen}
|
||||
setIsAccordionOpen={setIsESQLResultsAccordionOpen}
|
||||
query={query}
|
||||
isTableView={attributes.visualizationType !== 'lnsDatatable'}
|
||||
onAccordionToggleCb={(status) => {
|
||||
if (status && isSuggestionsAccordionOpen) {
|
||||
setIsSuggestionsAccordionOpen(!status);
|
||||
}
|
||||
if (status && isLayerAccordionOpen) {
|
||||
setIsLayerAccordionOpen(!status);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div ref={editorContainer} />
|
||||
<EuiFlexItem
|
||||
grow={isLayerAccordionOpen ? 1 : false}
|
||||
css={css`
|
||||
|
@ -558,8 +375,9 @@ export function LensEditConfigurationFlyout({
|
|||
<EuiTitle
|
||||
size="xxs"
|
||||
css={css`
|
||||
padding: 2px;
|
||||
`}
|
||||
padding: 2px;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<h5>
|
||||
{i18n.translate('xpack.lens.config.visualizationConfigurationLabel', {
|
||||
|
@ -586,6 +404,8 @@ export function LensEditConfigurationFlyout({
|
|||
<>
|
||||
<LayerConfiguration
|
||||
attributes={attributes}
|
||||
dataLoading$={dataLoading$}
|
||||
lensAdapters={lensAdapters}
|
||||
getUserMessages={getUserMessages}
|
||||
coreStart={coreStart}
|
||||
startDependencies={startDependencies}
|
||||
|
@ -594,6 +414,13 @@ export function LensEditConfigurationFlyout({
|
|||
datasourceId={datasourceId}
|
||||
framePublicAPI={framePublicAPI}
|
||||
setIsInlineFlyoutVisible={setIsInlineFlyoutVisible}
|
||||
updateSuggestion={updateSuggestion}
|
||||
setCurrentAttributes={setCurrentAttributes}
|
||||
closeFlyout={closeFlyout}
|
||||
parentApi={parentApi}
|
||||
panelId={panelId}
|
||||
canEditTextBasedQuery={canEditTextBasedQuery}
|
||||
editorContainer={editorContainer.current || undefined}
|
||||
/>
|
||||
<EuiSpacer />
|
||||
</>
|
||||
|
|
|
@ -92,6 +92,10 @@ export interface EditConfigPanelProps {
|
|||
|
||||
export interface LayerConfigurationProps {
|
||||
attributes: TypedLensSerializedState['attributes'];
|
||||
/** Embeddable output observable, useful for dashboard flyout */
|
||||
dataLoading$?: PublishingSubject<boolean | undefined>;
|
||||
/** Contains the active data, necessary for some panel configuration such as coloring */
|
||||
lensAdapters?: ReturnType<LensInspector['getInspectorAdapters']>;
|
||||
coreStart: CoreStart;
|
||||
startDependencies: LensPluginStartDependencies;
|
||||
visualizationMap: VisualizationMap;
|
||||
|
@ -102,4 +106,12 @@ export interface LayerConfigurationProps {
|
|||
setIsInlineFlyoutVisible: (flag: boolean) => void;
|
||||
getUserMessages: UserMessagesGetter;
|
||||
onlyAllowSwitchToSubtypes?: boolean;
|
||||
updateSuggestion?: (attrs: TypedLensSerializedState['attributes']) => void;
|
||||
/** Set the attributes state */
|
||||
setCurrentAttributes?: (attrs: TypedLensSerializedState['attributes']) => void;
|
||||
parentApi?: unknown;
|
||||
panelId?: string;
|
||||
closeFlyout?: () => void;
|
||||
canEditTextBasedQuery?: boolean;
|
||||
editorContainer?: HTMLElement;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
import { isEqual } from 'lodash';
|
||||
import { createEmptyLensState } from '../../../react_embeddable/helper';
|
||||
import type { TypedLensSerializedState } from '../../../react_embeddable/types';
|
||||
import { useLensSelector } from '../../../state_management';
|
||||
import { extractReferencesFromState } from '../../../utils';
|
||||
|
@ -17,20 +18,25 @@ export const useCurrentAttributes = ({
|
|||
datasourceMap,
|
||||
visualizationMap,
|
||||
}: {
|
||||
initialAttributes: TypedLensSerializedState['attributes'];
|
||||
initialAttributes?: TypedLensSerializedState['attributes'];
|
||||
datasourceMap: DatasourceMap;
|
||||
visualizationMap: VisualizationMap;
|
||||
textBasedMode?: string;
|
||||
textBasedMode?: boolean;
|
||||
}) => {
|
||||
const { datasourceStates, visualization } = useLensSelector((state) => state.lens);
|
||||
// use the latest activeId, but fallback to attributes
|
||||
const activeVisualization =
|
||||
visualizationMap[visualization.activeId ?? initialAttributes.visualizationType];
|
||||
|
||||
const [currentAttributes, setCurrentAttributes] =
|
||||
useState<TypedLensSerializedState['attributes']>(initialAttributes);
|
||||
const [currentAttributes, setCurrentAttributes] = useState<
|
||||
TypedLensSerializedState['attributes'] | undefined
|
||||
>(initialAttributes);
|
||||
|
||||
// use the latest activeId, but fallback to attributes
|
||||
const visualizationType = visualization.activeId ?? initialAttributes?.visualizationType;
|
||||
const activeVisualization = visualizationType ? visualizationMap[visualizationType] : undefined;
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeVisualization) {
|
||||
return;
|
||||
}
|
||||
const dsStates = Object.fromEntries(
|
||||
Object.entries(datasourceStates).map(([id, ds]) => {
|
||||
const dsState = ds.state;
|
||||
|
@ -53,15 +59,16 @@ export const useCurrentAttributes = ({
|
|||
activeVisualization,
|
||||
})
|
||||
: [];
|
||||
const attributes = initialAttributes ?? createEmptyLensState().attributes;
|
||||
const attrs: TypedLensSerializedState['attributes'] = {
|
||||
...initialAttributes,
|
||||
...attributes,
|
||||
state: {
|
||||
...initialAttributes.state,
|
||||
...attributes.state,
|
||||
visualization: visualization.state,
|
||||
datasourceStates: dsStates,
|
||||
},
|
||||
references,
|
||||
visualizationType: visualization.activeId ?? initialAttributes.visualizationType,
|
||||
visualizationType: activeVisualization.id,
|
||||
};
|
||||
if (!isEqual(attrs, currentAttributes)) {
|
||||
setCurrentAttributes(attrs);
|
||||
|
|
|
@ -20,7 +20,7 @@ export const useESQLVariables = ({
|
|||
closeFlyout,
|
||||
}: {
|
||||
parentApi: unknown;
|
||||
attributes: TypedLensSerializedState['attributes'];
|
||||
attributes?: TypedLensSerializedState['attributes'];
|
||||
panelId?: string;
|
||||
closeFlyout?: () => void;
|
||||
}) => {
|
||||
|
@ -55,7 +55,7 @@ export const useESQLVariables = ({
|
|||
id: uuidv4(),
|
||||
},
|
||||
});
|
||||
if (panel && updatedQuery) {
|
||||
if (panel && updatedQuery && attributes) {
|
||||
panel.updateAttributes({
|
||||
...attributes,
|
||||
state: {
|
||||
|
|
|
@ -30,6 +30,7 @@ import { ReactWrapper } from 'enzyme';
|
|||
import { createIndexPatternServiceMock } from '../../../mocks/data_views_service_mock';
|
||||
import { AddLayerButton } from '../../../visualizations/xy/add_layer';
|
||||
import { LayerType } from '@kbn/visualizations-plugin/common';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
|
||||
jest.mock('../../../id_generator');
|
||||
|
||||
|
@ -155,6 +156,7 @@ describe('ConfigPanel', () => {
|
|||
toggleFullscreen: jest.fn(),
|
||||
uiActions,
|
||||
dataViews: {} as DataViewsPublicPluginStart,
|
||||
data: dataPluginMock.createStartContract(),
|
||||
getUserMessages: () => [],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -264,6 +264,11 @@ export function LayerPanels(
|
|||
!hidden && (
|
||||
<LayerPanel
|
||||
{...props}
|
||||
attributes={props.attributes}
|
||||
data={props.data}
|
||||
setCurrentAttributes={props.setCurrentAttributes}
|
||||
updateSuggestion={props.updateSuggestion}
|
||||
dataLoading$={props.dataLoading$}
|
||||
onDropToDimension={handleDimensionDrop}
|
||||
registerLibraryAnnotationGroup={registerLibraryAnnotationGroupFunction}
|
||||
dimensionGroups={groups}
|
||||
|
@ -327,6 +332,9 @@ export function LayerPanels(
|
|||
}}
|
||||
toggleFullscreen={toggleFullscreen}
|
||||
indexPatternService={indexPatternService}
|
||||
panelId={props.panelId}
|
||||
parentApi={props.parentApi}
|
||||
closeFlyout={props.closeFlyout}
|
||||
/>
|
||||
)
|
||||
);
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { createPortal } from 'react-dom';
|
||||
import { EuiFlexItem } from '@elastic/eui';
|
||||
import { AggregateQuery, Query, isOfAggregateQueryType } from '@kbn/es-query';
|
||||
import { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common';
|
||||
import { useStateFromPublishingSubject } from '@kbn/presentation-publishing';
|
||||
import { isEqual } from 'lodash';
|
||||
import { MutableRefObject, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { ESQLLangEditor } from '@kbn/esql/public';
|
||||
import type { ESQLControlVariable } from '@kbn/esql-types';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { DataViewSpec } from '@kbn/data-views-plugin/common';
|
||||
import { useCurrentAttributes } from '../../../app_plugin/shared/edit_on_the_fly/use_current_attributes';
|
||||
import { getActiveDataFromDatatable } from '../../../state_management/shared_logic';
|
||||
import type { Simplify } from '../../../types';
|
||||
import { onActiveDataChange, useLensDispatch } from '../../../state_management';
|
||||
import {
|
||||
ESQLDataGridAttrs,
|
||||
getSuggestions,
|
||||
} from '../../../app_plugin/shared/edit_on_the_fly/helpers';
|
||||
import { useESQLVariables } from '../../../app_plugin/shared/edit_on_the_fly/use_esql_variables';
|
||||
import { MAX_NUM_OF_COLUMNS } from '../../../datasources/text_based/utils';
|
||||
import { isApiESQLVariablesCompatible } from '../../../react_embeddable/types';
|
||||
import type { LayerPanelProps } from './types';
|
||||
import { ESQLDataGridAccordion } from '../../../app_plugin/shared/edit_on_the_fly/esql_data_grid_accordion';
|
||||
|
||||
export type ESQLEditorProps = Simplify<
|
||||
{
|
||||
isTextBasedLanguage: boolean;
|
||||
} & Pick<
|
||||
LayerPanelProps,
|
||||
| 'attributes'
|
||||
| 'framePublicAPI'
|
||||
| 'datasourceMap'
|
||||
| 'lensAdapters'
|
||||
| 'parentApi'
|
||||
| 'layerId'
|
||||
| 'panelId'
|
||||
| 'closeFlyout'
|
||||
| 'data'
|
||||
| 'canEditTextBasedQuery'
|
||||
| 'editorContainer'
|
||||
| 'visualizationMap'
|
||||
| 'setCurrentAttributes'
|
||||
| 'updateSuggestion'
|
||||
| 'dataLoading$'
|
||||
| 'parentApi'
|
||||
>
|
||||
>;
|
||||
|
||||
/**
|
||||
* This is a wrapper around the Monaco ESQL editor for Lens
|
||||
* It handles its internal state and update both attributes & activeData on changes
|
||||
* in the Redux store.
|
||||
* Mind that this component will render either inline (classic React)
|
||||
* or in a portal if the editorContainer props is provided
|
||||
*/
|
||||
export function ESQLEditor({
|
||||
data,
|
||||
attributes,
|
||||
framePublicAPI,
|
||||
isTextBasedLanguage,
|
||||
datasourceMap,
|
||||
visualizationMap,
|
||||
lensAdapters,
|
||||
parentApi,
|
||||
panelId,
|
||||
layerId,
|
||||
closeFlyout,
|
||||
editorContainer,
|
||||
canEditTextBasedQuery,
|
||||
dataLoading$,
|
||||
setCurrentAttributes,
|
||||
updateSuggestion,
|
||||
}: ESQLEditorProps) {
|
||||
const prevQuery = useRef<AggregateQuery | Query>(attributes?.state.query || { esql: '' });
|
||||
const [query, setQuery] = useState<AggregateQuery | Query>(
|
||||
attributes?.state.query || { esql: '' }
|
||||
);
|
||||
const [errors, setErrors] = useState<Error[]>([]);
|
||||
const [isLayerAccordionOpen, setIsLayerAccordionOpen] = useState(true);
|
||||
const [suggestsLimitedColumns, setSuggestsLimitedColumns] = useState(false);
|
||||
const [isVisualizationLoading, setIsVisualizationLoading] = useState(false);
|
||||
const [dataGridAttrs, setDataGridAttrs] = useState<ESQLDataGridAttrs | undefined>(undefined);
|
||||
const [isSuggestionsAccordionOpen, setIsSuggestionsAccordionOpen] = useState(false);
|
||||
const [isESQLResultsAccordionOpen, setIsESQLResultsAccordionOpen] = useState(false);
|
||||
|
||||
const currentAttributes = useCurrentAttributes({
|
||||
textBasedMode: isTextBasedLanguage,
|
||||
initialAttributes: attributes,
|
||||
datasourceMap,
|
||||
visualizationMap,
|
||||
});
|
||||
|
||||
const adHocDataViews =
|
||||
attributes && attributes.state.adHocDataViews
|
||||
? Object.values(attributes.state.adHocDataViews)
|
||||
: Object.values(framePublicAPI.dataViews.indexPatterns).map((index) => index.spec);
|
||||
|
||||
const previousAdapters = useRef<Partial<DefaultInspectorAdapters> | undefined>(lensAdapters);
|
||||
|
||||
const esqlVariables = useStateFromPublishingSubject(
|
||||
isApiESQLVariablesCompatible(parentApi) ? parentApi?.esqlVariables$ : undefined
|
||||
);
|
||||
|
||||
const dispatch = useLensDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
const s = dataLoading$?.subscribe((isDataLoading) => {
|
||||
// go thru only when the loading is complete
|
||||
if (isDataLoading) {
|
||||
return;
|
||||
}
|
||||
const activeData = getActiveDataFromDatatable(
|
||||
layerId,
|
||||
previousAdapters.current?.tables?.tables
|
||||
);
|
||||
const table = activeData?.[layerId];
|
||||
|
||||
if (table) {
|
||||
// there are cases where a query can return a big amount of columns
|
||||
// at this case we don't suggest all columns in a table but the first `MAX_NUM_OF_COLUMNS`
|
||||
setSuggestsLimitedColumns(table.columns.length >= MAX_NUM_OF_COLUMNS);
|
||||
}
|
||||
|
||||
if (Object.keys(activeData).length > 0) {
|
||||
dispatch(onActiveDataChange({ activeData }));
|
||||
}
|
||||
});
|
||||
return () => s?.unsubscribe();
|
||||
}, [dataLoading$, dispatch, layerId]);
|
||||
|
||||
const runQuery = useCallback(
|
||||
async (q: AggregateQuery, abortController?: AbortController, shouldUpdateAttrs?: boolean) => {
|
||||
const attrs = await getSuggestions(
|
||||
q,
|
||||
data,
|
||||
datasourceMap,
|
||||
visualizationMap,
|
||||
adHocDataViews,
|
||||
setErrors,
|
||||
abortController,
|
||||
setDataGridAttrs,
|
||||
esqlVariables,
|
||||
shouldUpdateAttrs,
|
||||
currentAttributes
|
||||
);
|
||||
if (attrs) {
|
||||
setCurrentAttributes?.(attrs);
|
||||
setErrors([]);
|
||||
updateSuggestion?.(attrs);
|
||||
}
|
||||
prevQuery.current = q;
|
||||
setIsVisualizationLoading(false);
|
||||
},
|
||||
[
|
||||
data,
|
||||
datasourceMap,
|
||||
visualizationMap,
|
||||
adHocDataViews,
|
||||
esqlVariables,
|
||||
setCurrentAttributes,
|
||||
updateSuggestion,
|
||||
currentAttributes,
|
||||
]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
const initializeChart = async () => {
|
||||
if (isTextBasedLanguage && isOfAggregateQueryType(query) && !dataGridAttrs) {
|
||||
try {
|
||||
await runQuery(query, abortController, Boolean(attributes?.state.needsRefresh));
|
||||
} catch (e) {
|
||||
setErrors([e]);
|
||||
prevQuery.current = query;
|
||||
}
|
||||
}
|
||||
};
|
||||
initializeChart();
|
||||
}, [
|
||||
adHocDataViews,
|
||||
runQuery,
|
||||
esqlVariables,
|
||||
query,
|
||||
data,
|
||||
dataGridAttrs,
|
||||
attributes?.state.needsRefresh,
|
||||
isTextBasedLanguage,
|
||||
]);
|
||||
|
||||
// Early exit if it's not in TextBased mode
|
||||
if (!isTextBasedLanguage || !canEditTextBasedQuery || !isOfAggregateQueryType(query)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const EditorComponent = (
|
||||
<>
|
||||
<InnerESQLEditor
|
||||
query={query}
|
||||
prevQuery={prevQuery}
|
||||
setQuery={setQuery}
|
||||
runQuery={runQuery}
|
||||
adHocDataViews={adHocDataViews}
|
||||
errors={errors}
|
||||
suggestsLimitedColumns={suggestsLimitedColumns}
|
||||
isVisualizationLoading={isVisualizationLoading}
|
||||
esqlVariables={esqlVariables}
|
||||
closeFlyout={closeFlyout}
|
||||
panelId={panelId}
|
||||
attributes={attributes}
|
||||
parentApi={parentApi}
|
||||
/>
|
||||
{dataGridAttrs ? (
|
||||
<ESQLDataGridAccordion
|
||||
dataGridAttrs={dataGridAttrs}
|
||||
isAccordionOpen={isESQLResultsAccordionOpen}
|
||||
isTableView={attributes?.visualizationType !== 'lnsDatatable'}
|
||||
setIsAccordionOpen={setIsESQLResultsAccordionOpen}
|
||||
query={query}
|
||||
onAccordionToggleCb={(status) => {
|
||||
if (status && isSuggestionsAccordionOpen) {
|
||||
setIsSuggestionsAccordionOpen(!status);
|
||||
}
|
||||
if (status && isLayerAccordionOpen) {
|
||||
setIsLayerAccordionOpen(!status);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
|
||||
if (editorContainer) {
|
||||
return <>{createPortal(EditorComponent, editorContainer)}</>;
|
||||
}
|
||||
return EditorComponent;
|
||||
}
|
||||
|
||||
type InnerEditorProps = Simplify<
|
||||
{
|
||||
query: AggregateQuery;
|
||||
prevQuery: MutableRefObject<AggregateQuery | Query>;
|
||||
setQuery: (query: AggregateQuery | Query) => void;
|
||||
runQuery: (
|
||||
q: AggregateQuery,
|
||||
abortController?: AbortController,
|
||||
shouldUpdateAttrs?: boolean
|
||||
) => Promise<void>;
|
||||
errors: Error[];
|
||||
isVisualizationLoading: boolean | undefined;
|
||||
suggestsLimitedColumns: boolean;
|
||||
adHocDataViews: DataViewSpec[];
|
||||
esqlVariables: ESQLControlVariable[] | undefined;
|
||||
} & Pick<LayerPanelProps, 'attributes' | 'parentApi' | 'panelId' | 'closeFlyout'>
|
||||
>;
|
||||
|
||||
function InnerESQLEditor({
|
||||
query,
|
||||
adHocDataViews,
|
||||
errors,
|
||||
suggestsLimitedColumns,
|
||||
attributes,
|
||||
parentApi,
|
||||
panelId,
|
||||
closeFlyout,
|
||||
setQuery,
|
||||
isVisualizationLoading,
|
||||
prevQuery,
|
||||
runQuery,
|
||||
esqlVariables,
|
||||
}: InnerEditorProps) {
|
||||
const { onSaveControl, onCancelControl } = useESQLVariables({
|
||||
parentApi,
|
||||
panelId,
|
||||
attributes,
|
||||
closeFlyout,
|
||||
});
|
||||
|
||||
const hideTimeFilterInfo = false;
|
||||
return (
|
||||
<EuiFlexItem grow={false} data-test-subj="InlineEditingESQLEditor">
|
||||
<ESQLLangEditor
|
||||
query={query}
|
||||
onTextLangQueryChange={setQuery}
|
||||
detectedTimestamp={adHocDataViews?.[0]?.timeFieldName}
|
||||
hideTimeFilterInfo={hideTimeFilterInfo}
|
||||
errors={errors}
|
||||
warning={
|
||||
suggestsLimitedColumns
|
||||
? i18n.translate('xpack.lens.config.configFlyoutCallout', {
|
||||
defaultMessage:
|
||||
'Displaying a limited portion of the available fields. Add more from the configuration panel.',
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
editorIsInline
|
||||
hideRunQueryText
|
||||
onTextLangQuerySubmit={async (q, a) => {
|
||||
// do not run the suggestions if the query is the same as the previous one
|
||||
if (q && !isEqual(q, prevQuery.current)) {
|
||||
// setIsVisualizationLoading(true);
|
||||
await runQuery(q, a);
|
||||
}
|
||||
}}
|
||||
isDisabled={false}
|
||||
allowQueryCancellation
|
||||
isLoading={isVisualizationLoading}
|
||||
supportsControls={parentApi !== undefined}
|
||||
esqlVariables={esqlVariables}
|
||||
onCancelControl={onCancelControl}
|
||||
onSaveControl={onSaveControl}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
|
@ -27,6 +27,7 @@ import { DimensionButton } from '@kbn/visualization-ui-components';
|
|||
import { LensAppState } from '../../../state_management';
|
||||
import type { ProviderProps } from '@kbn/dom-drag-drop/src';
|
||||
import { LayerPanelProps } from './types';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
|
||||
jest.mock('../../../id_generator');
|
||||
|
||||
|
@ -117,6 +118,7 @@ describe('LayerPanel', () => {
|
|||
getUserMessages: () => [],
|
||||
displayLayerSettings: true,
|
||||
onDropToDimension,
|
||||
data: dataPluginMock.createStartContract(),
|
||||
};
|
||||
}
|
||||
let props: LayerPanelProps;
|
||||
|
|
|
@ -22,6 +22,7 @@ import { css } from '@emotion/react';
|
|||
import { euiThemeVars } from '@kbn/ui-theme';
|
||||
import { DragDropIdentifier, ReorderProvider, DropType } from '@kbn/dom-drag-drop';
|
||||
import { DimensionButton } from '@kbn/visualization-ui-components';
|
||||
import { isOfAggregateQueryType } from '@kbn/es-query';
|
||||
import { LayerActions } from './layer_actions';
|
||||
import { isOperation, LayerAction, VisualizationDimensionGroupConfig } from '../../../types';
|
||||
import { LayerHeader } from './layer_header';
|
||||
|
@ -40,6 +41,7 @@ import { getSharedActions } from './layer_actions/layer_actions';
|
|||
import { FlyoutContainer } from '../../../shared_components/flyout_container';
|
||||
import { FakeDimensionButton } from './buttons/fake_dimension_button';
|
||||
import { getLongMessage } from '../../../user_messages_utils';
|
||||
import { ESQLEditor } from './esql_editor';
|
||||
|
||||
export function LayerPanel(props: LayerPanelProps) {
|
||||
const [openDimension, setOpenDimension] = useState<{
|
||||
|
@ -73,6 +75,7 @@ export function LayerPanel(props: LayerPanelProps) {
|
|||
onDropToDimension,
|
||||
setIsInlineFlyoutVisible,
|
||||
onlyAllowSwitchToSubtypes,
|
||||
...editorProps
|
||||
} = props;
|
||||
|
||||
const isInlineEditing = Boolean(props?.setIsInlineFlyoutVisible);
|
||||
|
@ -125,8 +128,8 @@ export function LayerPanel(props: LayerPanelProps) {
|
|||
};
|
||||
|
||||
const datasourcePublicAPI = framePublicAPI.datasourceLayers?.[layerId];
|
||||
const datasourceId = datasourcePublicAPI?.datasourceId;
|
||||
let layerDatasourceState = datasourceId ? datasourceStates?.[datasourceId]?.state : undefined;
|
||||
const datasourceId = datasourcePublicAPI?.datasourceId! as 'formBased' | 'textBased';
|
||||
let layerDatasourceState = datasourceStates?.[datasourceId]?.state;
|
||||
// try again with aliases
|
||||
if (!layerDatasourceState && datasourcePublicAPI?.datasourceAliasIds && datasourceStates) {
|
||||
const aliasId = datasourcePublicAPI.datasourceAliasIds.find(
|
||||
|
@ -284,7 +287,10 @@ export function LayerPanel(props: LayerPanelProps) {
|
|||
|
||||
const { dataViews } = props.framePublicAPI;
|
||||
const [datasource] = Object.values(framePublicAPI.datasourceLayers);
|
||||
const isTextBasedLanguage = Boolean(datasource?.isTextBasedLanguage());
|
||||
const isTextBasedLanguage =
|
||||
datasource?.isTextBasedLanguage() ||
|
||||
isOfAggregateQueryType(editorProps.attributes?.state.query) ||
|
||||
false;
|
||||
|
||||
const visualizationLayerSettings = useMemo(
|
||||
() =>
|
||||
|
@ -400,7 +406,7 @@ export function LayerPanel(props: LayerPanelProps) {
|
|||
(layerDatasource || activeVisualization.LayerPanelComponent) && (
|
||||
<EuiSpacer size="s" />
|
||||
)}
|
||||
{layerDatasource && props.indexPatternService && (
|
||||
{layerDatasource && props.indexPatternService && !isTextBasedLanguage && (
|
||||
<layerDatasource.LayerPanelComponent
|
||||
{...{
|
||||
layerId,
|
||||
|
@ -412,6 +418,14 @@ export function LayerPanel(props: LayerPanelProps) {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
<ESQLEditor
|
||||
isTextBasedLanguage={isTextBasedLanguage}
|
||||
framePublicAPI={framePublicAPI}
|
||||
datasourceMap={datasourceMap}
|
||||
layerId={layerId}
|
||||
visualizationMap={visualizationMap}
|
||||
{...editorProps}
|
||||
/>
|
||||
{activeVisualization.LayerPanelComponent && (
|
||||
<activeVisualization.LayerPanelComponent
|
||||
{...{
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
|
||||
import { DragDropIdentifier, DropType } from '@kbn/dom-drag-drop';
|
||||
import { PublishingSubject } from '@kbn/presentation-publishing';
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { LensInspector } from '../../../lens_inspector_service';
|
||||
import type { TypedLensSerializedState } from '../../../react_embeddable/types';
|
||||
import type { IndexPatternServiceAPI } from '../../../data_views_service/service';
|
||||
|
||||
import {
|
||||
|
@ -30,15 +34,38 @@ export interface ConfigPanelWrapperProps {
|
|||
visualizationMap: VisualizationMap;
|
||||
core: DatasourceDimensionEditorProps['core'];
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
data: DataPublicPluginStart;
|
||||
indexPatternService?: IndexPatternServiceAPI;
|
||||
uiActions: UiActionsStart;
|
||||
getUserMessages?: UserMessagesGetter;
|
||||
hideLayerHeader?: boolean;
|
||||
setIsInlineFlyoutVisible?: (status: boolean) => void;
|
||||
onlyAllowSwitchToSubtypes?: boolean;
|
||||
attributes?: TypedLensSerializedState['attributes'];
|
||||
/** Embeddable output observable, useful for dashboard flyout */
|
||||
dataLoading$?: PublishingSubject<boolean | undefined>;
|
||||
/** Contains the active data, necessary for some panel configuration such as coloring */
|
||||
lensAdapters?: ReturnType<LensInspector['getInspectorAdapters']>;
|
||||
updateSuggestion?: (attrs: TypedLensSerializedState['attributes']) => void;
|
||||
/** Set the attributes state */
|
||||
setCurrentAttributes?: (attrs: TypedLensSerializedState['attributes']) => void;
|
||||
parentApi?: unknown;
|
||||
panelId?: string;
|
||||
closeFlyout?: () => void;
|
||||
canEditTextBasedQuery?: boolean;
|
||||
editorContainer?: HTMLElement;
|
||||
}
|
||||
|
||||
export interface LayerPanelProps {
|
||||
attributes?: TypedLensSerializedState['attributes'];
|
||||
/** Embeddable output observable, useful for dashboard flyout */
|
||||
dataLoading$?: PublishingSubject<boolean | undefined>;
|
||||
/** Contains the active data, necessary for some panel configuration such as coloring */
|
||||
lensAdapters?: ReturnType<LensInspector['getInspectorAdapters']>;
|
||||
data: DataPublicPluginStart;
|
||||
updateSuggestion?: (attrs: TypedLensSerializedState['attributes']) => void;
|
||||
/** Set the attributes state */
|
||||
setCurrentAttributes?: (attrs: TypedLensSerializedState['attributes']) => void;
|
||||
visualizationState: unknown;
|
||||
datasourceMap: DatasourceMap;
|
||||
visualizationMap: VisualizationMap;
|
||||
|
@ -85,6 +112,11 @@ export interface LayerPanelProps {
|
|||
displayLayerSettings: boolean;
|
||||
setIsInlineFlyoutVisible?: (status: boolean) => void;
|
||||
onlyAllowSwitchToSubtypes?: boolean;
|
||||
panelId?: string;
|
||||
parentApi?: unknown;
|
||||
closeFlyout?: () => void;
|
||||
canEditTextBasedQuery?: boolean;
|
||||
editorContainer?: HTMLElement;
|
||||
}
|
||||
|
||||
export interface LayerDatasourceDropProps {
|
||||
|
|
|
@ -158,6 +158,7 @@ export function EditorFrame(props: EditorFrameProps) {
|
|||
framePublicAPI={framePublicAPI}
|
||||
uiActions={props.plugins.uiActions}
|
||||
dataViews={props.plugins.dataViews}
|
||||
data={props.plugins.data}
|
||||
indexPatternService={props.indexPatternService}
|
||||
getUserMessages={props.getUserMessages}
|
||||
/>
|
||||
|
|
|
@ -55,7 +55,7 @@ export function createMockSetupDependencies() {
|
|||
|
||||
export function createMockStartDependencies() {
|
||||
return {
|
||||
data: dataPluginMock.createSetupContract(),
|
||||
data: dataPluginMock.createStartContract(),
|
||||
embeddable: embeddablePluginMock.createStartContract(),
|
||||
expressions: expressionsPluginMock.createStartContract(),
|
||||
charts: chartPluginMock.createStartContract(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue