[8.x] [ES|QL] Adds license knowledge to the editor (#217796) (#218096)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[ES|QL] Adds license knowledge to the editor
(#217796)](https://github.com/elastic/kibana/pull/217796)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Stratoula
Kalafateli","email":"efstratia.kalafateli@elastic.co"},"sourceCommit":{"committedDate":"2025-04-14T10:52:10Z","message":"[ES|QL]
Adds license knowledge to the editor (#217796)\n\n## Summary\n\nPart of
https://github.com/elastic/kibana/issues/216791\n\n- Suggests remote
indices if ES license plugin enables it \n\n<img width=\"580\"
alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/a237f646-286e-489c-b41b-a1ce7d82440a\"\n/>\n\n\n\n-
Doesn't suggest remote indices for basic license\n<img width=\"292\"
alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/2bc9e512-91ab-4b20-94ce-d1931732567e\"\n/>\n\n\n###
Checklist\n\n- [ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"708917df6ea4c60b666d2ed11cb0b3865034b342","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Feature:ES|QL","Team:ESQL","backport:version","v9.1.0","v8.19.0"],"title":"[ES|QL]
Adds license knowledge to the
editor","number":217796,"url":"https://github.com/elastic/kibana/pull/217796","mergeCommit":{"message":"[ES|QL]
Adds license knowledge to the editor (#217796)\n\n## Summary\n\nPart of
https://github.com/elastic/kibana/issues/216791\n\n- Suggests remote
indices if ES license plugin enables it \n\n<img width=\"580\"
alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/a237f646-286e-489c-b41b-a1ce7d82440a\"\n/>\n\n\n\n-
Doesn't suggest remote indices for basic license\n<img width=\"292\"
alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/2bc9e512-91ab-4b20-94ce-d1931732567e\"\n/>\n\n\n###
Checklist\n\n- [ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"708917df6ea4c60b666d2ed11cb0b3865034b342"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/217796","number":217796,"mergeCommit":{"message":"[ES|QL]
Adds license knowledge to the editor (#217796)\n\n## Summary\n\nPart of
https://github.com/elastic/kibana/issues/216791\n\n- Suggests remote
indices if ES license plugin enables it \n\n<img width=\"580\"
alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/a237f646-286e-489c-b41b-a1ce7d82440a\"\n/>\n\n\n\n-
Doesn't suggest remote indices for basic license\n<img width=\"292\"
alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/2bc9e512-91ab-4b20-94ce-d1931732567e\"\n/>\n\n\n###
Checklist\n\n- [ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"708917df6ea4c60b666d2ed11cb0b3865034b342"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
This commit is contained in:
Stratoula Kalafateli 2025-04-15 08:01:15 +02:00 committed by GitHub
parent 0da581350d
commit 1761809f29
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 76 additions and 8 deletions

View file

@ -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<ILicense | undefined>(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;

View file

@ -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([]);
});
});
});

View file

@ -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),
]);

View file

@ -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<JoinIndicesAutocompleteResult>;
variablesService: ESQLVariableService;
getLicense: () => Promise<ILicense | undefined>;
}
export interface ESQLEditorDeps {

View file

@ -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/**/*",

View file

@ -11,7 +11,8 @@
"optionalPlugins": [
"indexManagement",
"fieldsMetadata",
"usageCollection"
"usageCollection",
"licensing"
],
"requiredPlugins": [
"data",

View file

@ -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(

View file

@ -35,6 +35,7 @@
"@kbn/i18n-react",
"@kbn/visualization-utils",
"@kbn/esql-types",
"@kbn/licensing-plugin"
],
"exclude": [
"target/**/*",