diff --git a/packages/kbn-esql-editor/src/esql_editor.tsx b/packages/kbn-esql-editor/src/esql_editor.tsx index 767bc9026348c..13aa821eb5c8b 100644 --- a/packages/kbn-esql-editor/src/esql_editor.tsx +++ b/packages/kbn-esql-editor/src/esql_editor.tsx @@ -84,6 +84,7 @@ export const ESQLEditor = memo(function ESQLEditor({ hideQueryHistory, hasOutline, displayDocumentationAsFlyout, + canCreateEnrichPolicy = false, }: ESQLEditorProps) { const popoverRef = useRef(null); const datePickerOpenStatusRef = useRef(false); @@ -389,6 +390,7 @@ export const ESQLEditor = memo(function ESQLEditor({ }, // @ts-expect-error To prevent circular type import, type defined here is partial of full client getFieldsMetadata: fieldsMetadata?.getClient(), + canCreateEnrichPolicy: () => canCreateEnrichPolicy, }; return callbacks; }, [ @@ -404,6 +406,7 @@ export const ESQLEditor = memo(function ESQLEditor({ indexManagementApiService, histogramBarTarget, fieldsMetadata, + canCreateEnrichPolicy, ]); const queryRunButtonProperties = useMemo(() => { diff --git a/packages/kbn-esql-editor/src/types.ts b/packages/kbn-esql-editor/src/types.ts index a5fcaba885b0a..5197cc8649dad 100644 --- a/packages/kbn-esql-editor/src/types.ts +++ b/packages/kbn-esql-editor/src/types.ts @@ -66,6 +66,8 @@ export interface ESQLEditorProps { /** adds a documentation icon in the footer which opens the inline docs as a flyout **/ displayDocumentationAsFlyout?: boolean; + + canCreateEnrichPolicy?: boolean; } export interface ESQLEditorDeps { diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts index c49b05985c86a..102eca3758d52 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts @@ -271,7 +271,7 @@ export function createCustomCallbackMocks( matchField: string; enrichFields: string[]; }> -) { +): ESQLCallbacks { const finalColumnsSinceLastCommand = customColumnsSinceLastCommand || fields.filter(({ type }) => !NOT_SUGGESTED_TYPES.includes(type)); @@ -281,6 +281,7 @@ export function createCustomCallbackMocks( getColumnsFor: jest.fn(async () => finalColumnsSinceLastCommand), getSources: jest.fn(async () => finalSources), getPolicies: jest.fn(async () => finalPolicies), + canCreateEnrichPolicy: jest.fn(() => true), }; } diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index 2a37155358e85..9cdb15a5b22a0 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -219,6 +219,9 @@ export async function suggest( getFieldsMap, getPolicies, getPolicyMetadata, + resourceRetriever?.canCreateEnrichPolicy + ? resourceRetriever?.canCreateEnrichPolicy + : () => false, resourceRetriever?.getPreferences, fullAst ); @@ -398,6 +401,7 @@ async function getSuggestionsWithinCommandExpression( getFieldsMap: GetFieldsMapFn, getPolicies: GetPoliciesFn, getPolicyMetadata: GetPolicyMetadataFn, + canCreateEnrichPolicy: () => boolean, getPreferences?: () => Promise<{ histogramBarTarget: number } | undefined>, fullAst?: ESQLAst ) { @@ -431,7 +435,8 @@ async function getSuggestionsWithinCommandExpression( getColumnsByType, getFieldsMap, getPolicies, - getPolicyMetadata + getPolicyMetadata, + canCreateEnrichPolicy ); } } @@ -456,7 +461,8 @@ async function getExpressionSuggestionsByType( getFieldsByType: GetColumnsByTypeFn, getFieldsMap: GetFieldsMapFn, getPolicies: GetPoliciesFn, - getPolicyMetadata: GetPolicyMetadataFn + getPolicyMetadata: GetPolicyMetadataFn, + canCreateEnrichPolicy: () => boolean ) { const commandDef = getCommandDefinition(command.name); const { argIndex, prevIndex, lastArg, nodeArg } = extractArgMeta(command, node); @@ -880,7 +886,12 @@ async function getExpressionSuggestionsByType( }); }); } - suggestions.push(...(policies.length ? policies : [buildNoPoliciesAvailableDefinition()])); + + suggestions.push( + ...(policies.length + ? policies + : [buildNoPoliciesAvailableDefinition(canCreateEnrichPolicy())]) + ); } else { const indexes = getSourcesFromCommands(commands, 'index'); const lastIndex = indexes[indexes.length - 1]; diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index d9813bb0e91a1..0e75d1a563f9e 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -412,26 +412,36 @@ export const buildSettingDefinitions = ( })); }; -export const buildNoPoliciesAvailableDefinition = (): SuggestionRawDefinition => ({ - label: i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.noPoliciesLabel', { - defaultMessage: 'No available policy', - }), - text: '', - kind: 'Issue', - detail: i18n.translate( - 'kbn-esql-validation-autocomplete.esql.autocomplete.noPoliciesLabelsFound', - { - defaultMessage: 'Click to create', - } - ), - sortText: 'D', - command: { - id: 'esql.policies.create', - title: i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.createNewPolicy', { - defaultMessage: 'Click to create', +export const buildNoPoliciesAvailableDefinition = ( + canCreateEnrichPolicy: boolean +): SuggestionRawDefinition => { + const noPoliciesDef: SuggestionRawDefinition = { + label: i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.noPoliciesLabel', { + defaultMessage: 'No available policy', }), - }, -}); + text: '', + kind: 'Issue', + detail: '', + }; + + if (canCreateEnrichPolicy) { + noPoliciesDef.detail = i18n.translate( + 'kbn-esql-validation-autocomplete.esql.autocomplete.noPoliciesLabelsFound', + { + defaultMessage: 'Click to create', + } + ); + noPoliciesDef.sortText = 'D'; + noPoliciesDef.command = { + id: 'esql.policies.create', + title: i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.createNewPolicy', { + defaultMessage: 'Click to create', + }), + }; + } + + return noPoliciesDef; +}; export function getUnitDuration(unit: number = 1) { const filteredTimeLiteral = timeUnitsToSuggest.filter(({ name }) => { diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/types.ts b/packages/kbn-esql-validation-autocomplete/src/shared/types.ts index 1caa2c480864e..d29eb32d35bb0 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/types.ts @@ -46,6 +46,7 @@ export interface ESQLCallbacks { >; getPreferences?: () => Promise<{ histogramBarTarget: number }>; getFieldsMetadata?: Promise; + canCreateEnrichPolicy?: () => boolean; } export type ReasonTypes = 'missingCommand' | 'unsupportedFunction' | 'unknownFunction'; diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index 03102474f6314..1a1d8d415032e 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -1728,6 +1728,7 @@ describe('validation logic', () => { getColumnsFor: /Unknown column|Argument of|it is unsupported or not indexed/, getPreferences: /Unknown/, getFieldsMetadata: /Unknown/, + canCreateEnrichPolicy: /Unknown/, }; return excludedCallback.map((callback) => contentByCallback[callback]) || []; } diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts index b3076d107f850..87b1767cc6f62 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -1252,6 +1252,7 @@ export const ignoreErrorsMap: Record = { getPolicies: ['unknownPolicy'], getPreferences: [], getFieldsMetadata: [], + canCreateEnrichPolicy: [], }; /** diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx index 4d4db4438d74d..77b9d23bd91b5 100644 --- a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx @@ -275,6 +275,7 @@ export const QueryBarTopRow = React.memo( docLinks, http, dataViews, + application, } = kibana.services; const isQueryLangSelected = props.query && !isOfQueryType(props.query); @@ -745,6 +746,7 @@ export const QueryBarTopRow = React.memo( hideRunQueryText={true} data-test-subj="unifiedTextLangEditor" isLoading={props.isLoading} + canCreateEnrichPolicy={!!application.capabilities.index_management?.manageEnrich} /> ) ); diff --git a/src/plugins/unified_search/public/search_bar/search_bar.test.tsx b/src/plugins/unified_search/public/search_bar/search_bar.test.tsx index 89c8dead51eac..61bff19c57c6e 100644 --- a/src/plugins/unified_search/public/search_bar/search_bar.test.tsx +++ b/src/plugins/unified_search/public/search_bar/search_bar.test.tsx @@ -82,6 +82,9 @@ function wrapSearchBarInContext(testProps: any) { theme: startMock.theme, docLinks: startMock.docLinks, storage: createMockStorage(), + application: { + capabilities: { index_management: { manageEnrich: true } }, + }, data: { query: { savedQueries: { diff --git a/x-pack/plugins/index_management/server/plugin.ts b/x-pack/plugins/index_management/server/plugin.ts index 0ba15c463d4ec..79f5c6f7a42a9 100644 --- a/x-pack/plugins/index_management/server/plugin.ts +++ b/x-pack/plugins/index_management/server/plugin.ts @@ -41,6 +41,10 @@ export class IndexMgmtServerPlugin implements Plugin