diff --git a/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx b/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx index 619d355b803b8..eebe978cf7902 100644 --- a/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx +++ b/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx @@ -34,6 +34,7 @@ import { monaco, type ESQLCallbacks, } from '@kbn/monaco'; +import type { ILicense } from '@kbn/licensing-plugin/public'; import memoize from 'lodash/memoize'; import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { fixESQLQueryWithVariables } from '@kbn/esql-utils'; @@ -161,6 +162,7 @@ export const ESQLEditor = memo(function ESQLEditor({ const [isCodeEditorExpandedFocused, setIsCodeEditorExpandedFocused] = useState(false); const [isQueryLoading, setIsQueryLoading] = useState(true); const [abortController, setAbortController] = useState(new AbortController()); + const [license, setLicense] = useState(undefined); // contains both client side validation and server messages const [editorMessages, setEditorMessages] = useState<{ @@ -443,7 +445,7 @@ export const ESQLEditor = memo(function ESQLEditor({ }, []); const { cache: dataSourcesCache, memoizedSources } = useMemo(() => { - const fn = memoize((...args: [DataViewsPublicPluginStart, CoreStart]) => ({ + const fn = memoize((...args: [DataViewsPublicPluginStart, CoreStart, boolean]) => ({ timestamp: Date.now(), result: getESQLSources(...args), })); @@ -455,7 +457,9 @@ export const ESQLEditor = memo(function ESQLEditor({ const callbacks: ESQLCallbacks = { getSources: async () => { clearCacheWhenOld(dataSourcesCache, fixedQuery); - const sources = await memoizedSources(dataViews, core).result; + const ccrFeature = license?.getFeature('ccr'); + const areRemoteIndicesAvailable = ccrFeature?.isAvailable ?? false; + const sources = await memoizedSources(dataViews, core, areRemoteIndicesAvailable).result; return sources; }, getColumnsFor: async ({ query: queryToExecute }: { query?: string } | undefined = {}) => { @@ -517,6 +521,7 @@ export const ESQLEditor = memo(function ESQLEditor({ return callbacks; }, [ fieldsMetadata, + license, kibana.services?.esql?.getJoinIndicesAutocomplete, dataSourcesCache, fixedQuery, @@ -593,6 +598,20 @@ export const ESQLEditor = memo(function ESQLEditor({ } }, [isLoading, isQueryLoading, parseMessages, code]); + useEffect(() => { + async function fetchLicense() { + try { + const ls = await kibana.services?.esql?.getLicense(); + if (!isEqual(license, ls)) { + setLicense(ls); + } + } catch (error) { + // failed to fetch + } + } + fetchLicense(); + }, [kibana.services?.esql, license]); + const queryValidation = useCallback( async ({ active }: { active: boolean }) => { if (!editorModel.current || editorModel.current.isDisposed()) return; diff --git a/src/platform/packages/private/kbn-esql-editor/src/helpers.test.ts b/src/platform/packages/private/kbn-esql-editor/src/helpers.test.ts index 779ef4f8f306e..c58609636d5b2 100644 --- a/src/platform/packages/private/kbn-esql-editor/src/helpers.test.ts +++ b/src/platform/packages/private/kbn-esql-editor/src/helpers.test.ts @@ -313,8 +313,38 @@ describe('helpers', function () { }, ]), }; - const indices = await getRemoteIndicesList(updatedDataViewsMock); + const indices = await getRemoteIndicesList(updatedDataViewsMock, true); expect(indices).toStrictEqual([{ name: 'remote:logs', hidden: false, type: 'Index' }]); }); + + it('should not suggest ccs indices if not allowed', async function () { + const dataViewsMock = dataViewPluginMocks.createStartContract(); + const updatedDataViewsMock = { + ...dataViewsMock, + getIndices: jest.fn().mockResolvedValue([ + { + name: 'remote: alias1', + item: { + indices: ['index1'], + }, + }, + { + name: 'remote:.system1', + item: { + name: 'system', + }, + }, + { + name: 'remote:logs', + item: { + name: 'logs', + timestamp_field: '@timestamp', + }, + }, + ]), + }; + const indices = await getRemoteIndicesList(updatedDataViewsMock, false); + expect(indices).toStrictEqual([]); + }); }); }); diff --git a/src/platform/packages/private/kbn-esql-editor/src/helpers.ts b/src/platform/packages/private/kbn-esql-editor/src/helpers.ts index 7b332b7c6b3dd..0cdee35a16203 100644 --- a/src/platform/packages/private/kbn-esql-editor/src/helpers.ts +++ b/src/platform/packages/private/kbn-esql-editor/src/helpers.ts @@ -196,7 +196,13 @@ export const getIndicesList = async (dataViews: DataViewsPublicPluginStart) => { }); }; -export const getRemoteIndicesList = async (dataViews: DataViewsPublicPluginStart) => { +export const getRemoteIndicesList = async ( + dataViews: DataViewsPublicPluginStart, + areRemoteIndicesAvailable: boolean +) => { + if (!areRemoteIndicesAvailable) { + return []; + } const indices = await dataViews.getIndices({ showAllIndices: false, pattern: '*:*', @@ -255,9 +261,13 @@ const getIntegrations = async (core: CoreStart) => { ); }; -export const getESQLSources = async (dataViews: DataViewsPublicPluginStart, core: CoreStart) => { +export const getESQLSources = async ( + dataViews: DataViewsPublicPluginStart, + core: CoreStart, + areRemoteIndicesAvailable: boolean +) => { const [remoteIndices, localIndices, integrations] = await Promise.all([ - getRemoteIndicesList(dataViews), + getRemoteIndicesList(dataViews, areRemoteIndicesAvailable), getIndicesList(dataViews), getIntegrations(core), ]); diff --git a/src/platform/packages/private/kbn-esql-editor/src/types.ts b/src/platform/packages/private/kbn-esql-editor/src/types.ts index 19754f2bbf2b3..d92f96499ee7d 100644 --- a/src/platform/packages/private/kbn-esql-editor/src/types.ts +++ b/src/platform/packages/private/kbn-esql-editor/src/types.ts @@ -13,6 +13,7 @@ import type { AggregateQuery } from '@kbn/es-query'; import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; import type { IndexManagementPluginSetup } from '@kbn/index-management-shared-types'; import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; +import type { ILicense } from '@kbn/licensing-plugin/public'; import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; @@ -107,6 +108,7 @@ interface ESQLVariableService { export interface EsqlPluginStartBase { getJoinIndicesAutocomplete: () => Promise; variablesService: ESQLVariableService; + getLicense: () => Promise; } export interface ESQLEditorDeps { diff --git a/src/platform/packages/private/kbn-esql-editor/tsconfig.json b/src/platform/packages/private/kbn-esql-editor/tsconfig.json index 56e1d3fbbcf7b..213b4fee7ab3d 100644 --- a/src/platform/packages/private/kbn-esql-editor/tsconfig.json +++ b/src/platform/packages/private/kbn-esql-editor/tsconfig.json @@ -34,7 +34,8 @@ "@kbn/kibana-utils-plugin", "@kbn/ui-actions-plugin", "@kbn/shared-ux-table-persist", - "@kbn/esql-types" + "@kbn/esql-types", + "@kbn/licensing-plugin" ], "exclude": [ "target/**/*", diff --git a/src/platform/plugins/shared/esql/kibana.jsonc b/src/platform/plugins/shared/esql/kibana.jsonc index 56fb397f09870..fdb27385a7219 100644 --- a/src/platform/plugins/shared/esql/kibana.jsonc +++ b/src/platform/plugins/shared/esql/kibana.jsonc @@ -11,7 +11,8 @@ "optionalPlugins": [ "indexManagement", "fieldsMetadata", - "usageCollection" + "usageCollection", + "licensing" ], "requiredPlugins": [ "data", diff --git a/src/platform/plugins/shared/esql/public/plugin.ts b/src/platform/plugins/shared/esql/public/plugin.ts index b45f406b0a75e..8c70d88a9aca1 100755 --- a/src/platform/plugins/shared/esql/public/plugin.ts +++ b/src/platform/plugins/shared/esql/public/plugin.ts @@ -10,6 +10,7 @@ import type { Plugin, CoreStart, CoreSetup } from '@kbn/core/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; +import { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { IndexManagementPluginSetup } from '@kbn/index-management-shared-types'; import type { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public'; @@ -41,6 +42,7 @@ interface EsqlPluginStartDependencies { uiActions: UiActionsStart; data: DataPublicPluginStart; fieldsMetadata: FieldsMetadataPublicStart; + licensing?: LicensingPluginStart; usageCollection?: UsageCollectionStart; } @@ -70,6 +72,7 @@ export class EsqlPlugin implements Plugin<{}, EsqlPluginStart> { uiActions, fieldsMetadata, usageCollection, + licensing, }: EsqlPluginStartDependencies ): EsqlPluginStart { const storage = new Storage(localStorage); @@ -112,6 +115,7 @@ export class EsqlPlugin implements Plugin<{}, EsqlPluginStart> { const start = { getJoinIndicesAutocomplete, variablesService, + getLicense: async () => await licensing?.getLicense(), }; setKibanaServices( diff --git a/src/platform/plugins/shared/esql/tsconfig.json b/src/platform/plugins/shared/esql/tsconfig.json index 1d32d6dcde8f5..4ef5fd0f84190 100644 --- a/src/platform/plugins/shared/esql/tsconfig.json +++ b/src/platform/plugins/shared/esql/tsconfig.json @@ -35,6 +35,7 @@ "@kbn/i18n-react", "@kbn/visualization-utils", "@kbn/esql-types", + "@kbn/licensing-plugin" ], "exclude": [ "target/**/*",