diff --git a/src/plugins/data/common/search/search_source/create_search_source.test.ts b/src/plugins/data/common/search/search_source/create_search_source.test.ts index 491673dc8ebca..709b065c1ec41 100644 --- a/src/plugins/data/common/search/search_source/create_search_source.test.ts +++ b/src/plugins/data/common/search/search_source/create_search_source.test.ts @@ -23,6 +23,7 @@ describe('createSearchSource', () => { getConfig: jest.fn(), search: jest.fn(), onResponse: (req, res) => res, + scriptedFieldsEnabled: true, }; indexPatternContractMock = { diff --git a/src/plugins/data/common/search/search_source/mocks.ts b/src/plugins/data/common/search/search_source/mocks.ts index a980004bd1ceb..6bcd2a76d9aca 100644 --- a/src/plugins/data/common/search/search_source/mocks.ts +++ b/src/plugins/data/common/search/search_source/mocks.ts @@ -71,4 +71,5 @@ export const createSearchSourceMock = ( ) ), onResponse: jest.fn().mockImplementation((req, res) => res), + scriptedFieldsEnabled: true, }); diff --git a/src/plugins/data/common/search/search_source/search_source.test.ts b/src/plugins/data/common/search/search_source/search_source.test.ts index f4146cc5634de..eeb4c5a972e3a 100644 --- a/src/plugins/data/common/search/search_source/search_source.test.ts +++ b/src/plugins/data/common/search/search_source/search_source.test.ts @@ -94,6 +94,7 @@ describe('SearchSource', () => { getConfig: getConfigMock, search: mockSearchMethod, onResponse: jest.fn().mockImplementation((_, res) => res), + scriptedFieldsEnabled: true, }; searchSource = new SearchSource({}, searchSourceDependencies); @@ -651,6 +652,22 @@ describe('SearchSource', () => { const request = searchSource.getSearchRequestBody(); expect(request.script_fields).toEqual({ hello: {}, world: {} }); }); + + test('ignores scripted fields when scripted fields are disabled', async () => { + searchSource.setField('index', { + ...indexPattern, + getComputedFields: () => ({ + storedFields: [], + scriptFields: { hello: {}, world: {} }, + docvalueFields: [], + }), + } as unknown as DataView); + searchSourceDependencies.scriptedFieldsEnabled = false; + searchSource.setField('fields', ['timestamp', '*']); + + const request = searchSource.getSearchRequestBody(); + expect(request.script_fields).toEqual({}); + }); }); describe('handling for when specific fields are provided', () => { diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index a9d48108d296d..c11289439885b 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -138,6 +138,7 @@ export const searchSourceRequiredUiSettings = [ export interface SearchSourceDependencies extends FetchHandlers { aggs: AggsStart; search: ISearchGeneric; + scriptedFieldsEnabled: boolean; } interface ExpressionAstOptions { @@ -798,10 +799,12 @@ export class SearchSource { // set defaults let fieldsFromSource = searchRequest.fieldsFromSource || []; body.fields = body.fields || []; - body.script_fields = { - ...body.script_fields, - ...scriptFields, - }; + body.script_fields = this.dependencies.scriptedFieldsEnabled + ? { + ...body.script_fields, + ...scriptFields, + } + : {}; body.stored_fields = storedFields; body.runtime_mappings = runtimeFields || {}; diff --git a/src/plugins/data/common/search/search_source/search_source_service.test.ts b/src/plugins/data/common/search/search_source/search_source_service.test.ts index 70448db335a07..8e03f56fe0421 100644 --- a/src/plugins/data/common/search/search_source/search_source_service.test.ts +++ b/src/plugins/data/common/search/search_source/search_source_service.test.ts @@ -19,6 +19,7 @@ describe('SearchSource service', () => { getConfig: jest.fn(), search: jest.fn(), onResponse: jest.fn(), + scriptedFieldsEnabled: true, }; }); diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 8f4e37afb29b2..a2ed53fde7704 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -138,6 +138,7 @@ export class DataPublicPlugin fieldFormats, indexPatterns: dataViews, screenshotMode, + scriptedFieldsEnabled: dataViews.scriptedFieldsEnabled, }); setSearchService(search); diff --git a/src/plugins/data/public/search/search_service.test.ts b/src/plugins/data/public/search/search_service.test.ts index a64b90772900a..c94cde6b8f747 100644 --- a/src/plugins/data/public/search/search_service.test.ts +++ b/src/plugins/data/public/search/search_service.test.ts @@ -69,6 +69,7 @@ describe('Search service', () => { fieldFormats: {} as FieldFormatsStart, indexPatterns: {} as DataViewsContract, screenshotMode: screenshotModePluginMock.createStartContract(), + scriptedFieldsEnabled: true, }); }); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index d9033e0eed5f1..4a16d9487d2ea 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -86,6 +86,7 @@ export interface SearchServiceStartDependencies { fieldFormats: FieldFormatsStart; indexPatterns: DataViewsContract; screenshotMode: ScreenshotModePluginStart; + scriptedFieldsEnabled: boolean; } export class SearchService implements Plugin { @@ -216,7 +217,12 @@ export class SearchService implements Plugin { public start( { http, theme, uiSettings, chrome, application }: CoreStart, - { fieldFormats, indexPatterns, screenshotMode }: SearchServiceStartDependencies + { + fieldFormats, + indexPatterns, + screenshotMode, + scriptedFieldsEnabled, + }: SearchServiceStartDependencies ): ISearchStart { const search = ((request, options = {}) => { return this.searchInterceptor.search(request, options); @@ -245,6 +251,7 @@ export class SearchService implements Plugin { } return response; }, + scriptedFieldsEnabled, }; const config = this.initializerContext.config.get(); diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 0387cb820f165..dd199403c53af 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -302,6 +302,7 @@ export class SearchService implements Plugin { getConfig: (key: string): T => uiSettingsCache[key], search: this.asScoped(request).search, onResponse: (req, res) => res, + scriptedFieldsEnabled: true, }; return this.searchSourceService.start(scopedIndexPatterns, searchSourceDependencies); diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx index 075869ab6fdc2..4d18244d6476c 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx @@ -569,7 +569,7 @@ export function Tabs({ const euiTabs: EuiTabbedContentTab[] = useMemo( () => - getTabs(indexPattern, fieldFilter, relationships.length).map( + getTabs(indexPattern, fieldFilter, relationships.length, dataViews.scriptedFieldsEnabled).map( (tab: Pick) => { return { ...tab, @@ -577,7 +577,7 @@ export function Tabs({ }; } ), - [fieldFilter, getContent, indexPattern, relationships] + [fieldFilter, getContent, indexPattern, relationships, dataViews.scriptedFieldsEnabled] ); const [selectedTabId, setSelectedTabId] = useState(euiTabs[0].id); diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/utils.ts b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/utils.ts index 00b08037e52fe..1c372e13dbe4b 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/utils.ts +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/utils.ts @@ -15,7 +15,7 @@ import { TAB_SOURCE_FILTERS, TAB_RELATIONSHIPS, } from '../constants'; -import { areScriptedFieldsEnabled } from '../../utils'; +import { isRollup } from '../../utils'; function filterByName(items: DataViewField[], filter: string) { const lowercaseFilter = (filter || '').toLowerCase(); @@ -73,7 +73,12 @@ function getTitle(type: string, filteredCount: Dictionary, totalCount: D return title + count; } -export function getTabs(indexPattern: DataView, fieldFilter: string, relationshipCount = 0) { +export function getTabs( + indexPattern: DataView, + fieldFilter: string, + relationshipCount = 0, + scriptedFieldsEnabled: boolean +) { const totalCount = getCounts(indexPattern.fields.getAll(), indexPattern.getSourceFiltering()); const filteredCount = getCounts( indexPattern.fields.getAll(), @@ -89,7 +94,7 @@ export function getTabs(indexPattern: DataView, fieldFilter: string, relationshi 'data-test-subj': 'tab-indexedFields', }); - if (areScriptedFieldsEnabled(indexPattern)) { + if (!isRollup(indexPattern.type) && scriptedFieldsEnabled) { tabs.push({ name: getTitle('scripted', filteredCount, totalCount), id: TAB_SCRIPTED_FIELDS, diff --git a/src/plugins/data_view_management/public/components/index_pattern_table/index_pattern_table.tsx b/src/plugins/data_view_management/public/components/index_pattern_table/index_pattern_table.tsx index f2ab10098e4d6..0d0215e6342d7 100644 --- a/src/plugins/data_view_management/public/components/index_pattern_table/index_pattern_table.tsx +++ b/src/plugins/data_view_management/public/components/index_pattern_table/index_pattern_table.tsx @@ -213,7 +213,10 @@ export const IndexPatternTable = ({ width: '70%', render: (name: string, dataView: IndexPatternTableItem) => (
- + {dataView.getName()} {dataView.name ? ( <> diff --git a/src/plugins/data_view_management/public/components/utils.ts b/src/plugins/data_view_management/public/components/utils.ts index 5ba434048dc4d..722ad5059a598 100644 --- a/src/plugins/data_view_management/public/components/utils.ts +++ b/src/plugins/data_view_management/public/components/utils.ts @@ -28,7 +28,7 @@ const rollupIndexPatternListName = i18n.translate( } ); -const isRollup = (indexPatternType: string = '') => { +export const isRollup = (indexPatternType: string = '') => { return indexPatternType === 'rollup'; }; @@ -85,10 +85,6 @@ export const getTags = (indexPattern: DataViewListItem | DataView, isDefault: bo return tags; }; -export const areScriptedFieldsEnabled = (indexPattern: DataViewListItem | DataView) => { - return !isRollup(indexPattern.type); -}; - export const getFieldInfo = (indexPattern: DataViewListItem | DataView, field: DataViewField) => { if (!isRollup(indexPattern.type)) { return []; diff --git a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx index d7b21b395fdde..0e3c1758d2992 100644 --- a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx @@ -92,6 +92,10 @@ export async function mountManagementSection( savedObjectsManagement, }; + const editPath = '/dataView/:id/field/:fieldName'; + const createPath = '/dataView/:id/create-field/'; + const createEditPath = dataViews.scriptedFieldsEnabled ? [editPath, createPath] : [editPath]; + ReactDOM.render( @@ -100,7 +104,7 @@ export async function mountManagementSection( - + diff --git a/src/plugins/data_views/common/data_views/data_views.test.ts b/src/plugins/data_views/common/data_views/data_views.test.ts index 2ea7726cc2bb9..5c05832e7b0c4 100644 --- a/src/plugins/data_views/common/data_views/data_views.test.ts +++ b/src/plugins/data_views/common/data_views/data_views.test.ts @@ -115,6 +115,7 @@ describe('IndexPatterns', () => { onRedirectNoIndexPattern: () => {}, getCanSave: () => Promise.resolve(true), getCanSaveAdvancedSettings: () => Promise.resolve(true), + scriptedFieldsEnabled: true, }); indexPatternsNoAccess = new DataViewsService({ @@ -127,6 +128,7 @@ describe('IndexPatterns', () => { onRedirectNoIndexPattern: () => {}, getCanSave: () => Promise.resolve(false), getCanSaveAdvancedSettings: () => Promise.resolve(false), + scriptedFieldsEnabled: true, }); }); diff --git a/src/plugins/data_views/common/data_views/data_views.ts b/src/plugins/data_views/common/data_views/data_views.ts index 9537526046266..7e74a468d3ce8 100644 --- a/src/plugins/data_views/common/data_views/data_views.ts +++ b/src/plugins/data_views/common/data_views/data_views.ts @@ -120,6 +120,8 @@ export interface DataViewsServiceDeps { * Determines whether the user can save advancedSettings (used for defaultIndex) */ getCanSaveAdvancedSettings: () => Promise; + + scriptedFieldsEnabled: boolean; } /** @@ -325,6 +327,8 @@ export class DataViewsService { * Can the user save data views? */ public getCanSave: () => Promise; + + public readonly scriptedFieldsEnabled: boolean; /** * DataViewsService constructor * @param deps Service dependencies @@ -339,6 +343,7 @@ export class DataViewsService { onError, getCanSave = () => Promise.resolve(false), getCanSaveAdvancedSettings, + scriptedFieldsEnabled, } = deps; this.apiClient = apiClient; this.config = uiSettings; @@ -350,6 +355,7 @@ export class DataViewsService { this.getCanSaveAdvancedSettings = getCanSaveAdvancedSettings; this.dataViewCache = createDataViewCache(); + this.scriptedFieldsEnabled = scriptedFieldsEnabled; } /** @@ -591,7 +597,9 @@ export class DataViewsService { private refreshFieldsFn = async (indexPattern: DataView) => { const { fields, indices } = await this.getFieldsAndIndicesForDataView(indexPattern); fields.forEach((field) => (field.isMapped = true)); - const scripted = indexPattern.getScriptedFields().map((field) => field.spec); + const scripted = this.scriptedFieldsEnabled + ? indexPattern.getScriptedFields().map((field) => field.spec) + : []; const fieldAttrs = indexPattern.getFieldAttrs(); const fieldsWithSavedAttrs = Object.values( this.fieldArrayToMap([...fields, ...scripted], fieldAttrs) @@ -655,7 +663,9 @@ export class DataViewsService { displayErrors: boolean = true ) => { const fieldsAsArr = Object.values(fields); - const scriptedFields = fieldsAsArr.filter((field) => field.scripted); + const scriptedFields = this.scriptedFieldsEnabled + ? fieldsAsArr.filter((field) => field.scripted) + : []; try { let updatedFieldList: FieldSpec[]; const { fields: newFields, indices } = await this.getFieldsAndIndicesForWildcard(options); diff --git a/src/plugins/data_views/common/types.ts b/src/plugins/data_views/common/types.ts index 97d76941ea40c..9061c4643dce9 100644 --- a/src/plugins/data_views/common/types.ts +++ b/src/plugins/data_views/common/types.ts @@ -525,3 +525,7 @@ export interface HasDataService { hasUserDataView: () => Promise; hasDataView: () => Promise; } + +export interface ClientConfigType { + scriptedFieldsEnabled?: boolean; +} diff --git a/src/plugins/data_views/public/data_views_service_public.ts b/src/plugins/data_views/public/data_views_service_public.ts index 30625b1b59da5..73f4fb6987fa0 100644 --- a/src/plugins/data_views/public/data_views_service_public.ts +++ b/src/plugins/data_views/public/data_views_service_public.ts @@ -29,6 +29,7 @@ export interface DataViewsServicePublicDeps extends DataViewsServiceDeps { showAllIndices?: boolean; isRollupIndex: (indexName: string) => boolean; }) => Promise; + scriptedFieldsEnabled: boolean; } /** @@ -44,6 +45,7 @@ export class DataViewsServicePublic extends DataViewsService { isRollupIndex: (indexName: string) => boolean; }) => Promise; public hasData: HasDataService; + public readonly scriptedFieldsEnabled: boolean; /** * Constructor @@ -55,5 +57,6 @@ export class DataViewsServicePublic extends DataViewsService { this.getCanSaveSync = deps.getCanSaveSync; this.hasData = deps.hasData; this.getIndices = deps.getIndices; + this.scriptedFieldsEnabled = deps.scriptedFieldsEnabled; } } diff --git a/src/plugins/data_views/public/index.ts b/src/plugins/data_views/public/index.ts index 777e386189d62..f690552b5a147 100644 --- a/src/plugins/data_views/public/index.ts +++ b/src/plugins/data_views/public/index.ts @@ -6,6 +6,8 @@ * Side Public License, v 1. */ +import { PluginInitializerContext } from '@kbn/core/public'; + export { ILLEGAL_CHARACTERS_KEY, CONTAINS_SPACES_KEY, @@ -55,8 +57,8 @@ export { UiSettingsPublicToCommon } from './ui_settings_wrapper'; import { DataViewsPublicPlugin } from './plugin'; -export function plugin() { - return new DataViewsPublicPlugin(); +export function plugin(initializerContext: PluginInitializerContext) { + return new DataViewsPublicPlugin(initializerContext); } export type { diff --git a/src/plugins/data_views/public/plugin.ts b/src/plugins/data_views/public/plugin.ts index 119d785139c90..98558c803da10 100644 --- a/src/plugins/data_views/public/plugin.ts +++ b/src/plugins/data_views/public/plugin.ts @@ -6,9 +6,10 @@ * Side Public License, v 1. */ -import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { getIndexPatternLoad } from './expressions'; +import type { ClientConfigType } from '../common/types'; import { DataViewsPublicPluginSetup, DataViewsPublicPluginStart, @@ -40,6 +41,8 @@ export class DataViewsPublicPlugin { private readonly hasData = new HasData(); + constructor(private readonly initializerContext: PluginInitializerContext) {} + public setup( core: CoreSetup, { expressions, contentManagement }: DataViewsPublicSetupDependencies @@ -74,6 +77,8 @@ export class DataViewsPublicPlugin 10000 ); + const config = this.initializerContext.config.get(); + return new DataViewsServicePublic({ hasData: this.hasData.start(core), uiSettings: new UiSettingsPublicToCommon(uiSettings), @@ -91,6 +96,7 @@ export class DataViewsPublicPlugin getCanSaveAdvancedSettings: () => Promise.resolve(application.capabilities.advancedSettings.save === true), getIndices: (props) => getIndices({ ...props, http: core.http }), + scriptedFieldsEnabled: config.scriptedFieldsEnabled === false ? false : true, // accounting for null value }); } diff --git a/src/plugins/data_views/public/types.ts b/src/plugins/data_views/public/types.ts index c30aebe9243e0..fde0828748f93 100644 --- a/src/plugins/data_views/public/types.ts +++ b/src/plugins/data_views/public/types.ts @@ -120,6 +120,7 @@ export interface DataViewsServicePublic extends DataViewsServicePublicMethods { showAllIndices?: boolean; isRollupIndex: (indexName: string) => boolean; }) => Promise; + scriptedFieldsEnabled: boolean; } export type DataViewsContract = DataViewsServicePublic; diff --git a/src/plugins/data_views/server/data_views_service_factory.ts b/src/plugins/data_views/server/data_views_service_factory.ts index ac27ad0bc8093..e5324b2eb02d2 100644 --- a/src/plugins/data_views/server/data_views_service_factory.ts +++ b/src/plugins/data_views/server/data_views_service_factory.ts @@ -25,6 +25,7 @@ interface DataViewsServiceFactoryDeps { uiSettings: UiSettingsServiceStart; fieldFormats: FieldFormatsStart; capabilities: CoreStart['capabilities']; + scriptedFieldsEnabled: boolean; rollupsEnabled: boolean; } @@ -70,5 +71,6 @@ export const dataViewsServiceFactory = (deps: DataViewsServiceFactoryDeps) => : request ? (await capabilities.resolveCapabilities(request)).advancedSettings.save === true : false, + scriptedFieldsEnabled: deps.scriptedFieldsEnabled, }); }; diff --git a/src/plugins/data_views/server/index.ts b/src/plugins/data_views/server/index.ts index 33e93df3be894..a489feabbf935 100644 --- a/src/plugins/data_views/server/index.ts +++ b/src/plugins/data_views/server/index.ts @@ -6,6 +6,8 @@ * Side Public License, v 1. */ +import { schema, TypeOf } from '@kbn/config-schema'; +import type { PluginConfigDescriptor } from '@kbn/core/server'; export { getFieldByName, findIndexPatternById } from './utils'; export type { FieldDescriptor, RollupIndexCapability } from './fetcher'; export { IndexPatternsFetcher, getCapabilitiesForRollupIndices } from './fetcher'; @@ -36,6 +38,24 @@ export type { }; export { DataViewsServerPlugin as Plugin }; +const configSchema = schema.object({ + scriptedFieldsEnabled: schema.conditional( + schema.contextRef('serverless'), + true, + schema.boolean({ defaultValue: false }), + schema.never() + ), +}); + +type ConfigType = TypeOf; + +export const config: PluginConfigDescriptor = { + schema: configSchema, + exposeToBrowser: { + scriptedFieldsEnabled: true, + }, +}; + export { SERVICE_PATH, SERVICE_PATH_LEGACY, diff --git a/src/plugins/data_views/server/mocks.ts b/src/plugins/data_views/server/mocks.ts index 82595f7dc51a1..1e142d2e1650b 100644 --- a/src/plugins/data_views/server/mocks.ts +++ b/src/plugins/data_views/server/mocks.ts @@ -12,6 +12,7 @@ export function createIndexPatternsStartMock() { const dataViewsServiceFactory = jest.fn().mockResolvedValue({ get: jest.fn() }); return { dataViewsServiceFactory, + getScriptedFieldsEnabled: jest.fn().mockReturnValue(true), }; } diff --git a/src/plugins/data_views/server/plugin.ts b/src/plugins/data_views/server/plugin.ts index c96de2e4294f0..2be269b1a7636 100644 --- a/src/plugins/data_views/server/plugin.ts +++ b/src/plugins/data_views/server/plugin.ts @@ -15,6 +15,7 @@ import { getIndexPatternLoad } from './expressions'; import { registerIndexPatternsUsageCollector } from './register_index_pattern_usage_collection'; import { createScriptedFieldsDeprecationsConfig } from './deprecations'; import { DATA_VIEW_SAVED_OBJECT_TYPE, LATEST_VERSION } from '../common'; +import type { ClientConfigType } from '../common/types'; import { DataViewsServerPluginSetup, DataViewsServerPluginStart, @@ -35,7 +36,7 @@ export class DataViewsServerPlugin private readonly logger: Logger; private rollupsEnabled: boolean = false; - constructor(initializerContext: PluginInitializerContext) { + constructor(private readonly initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get('dataView'); } @@ -75,16 +76,21 @@ export class DataViewsServerPlugin { uiSettings, capabilities }: CoreStart, { fieldFormats }: DataViewsServerPluginStartDependencies ) { + const config = this.initializerContext.config.get(); + const scriptedFieldsEnabled = config.scriptedFieldsEnabled === false ? false : true; // accounting for null value + const serviceFactory = dataViewsServiceFactory({ logger: this.logger.get('indexPatterns'), uiSettings, fieldFormats, capabilities, + scriptedFieldsEnabled, rollupsEnabled: this.rollupsEnabled, }); return { dataViewsServiceFactory: serviceFactory, + getScriptedFieldsEnabled: () => scriptedFieldsEnabled, }; } diff --git a/src/plugins/data_views/server/types.ts b/src/plugins/data_views/server/types.ts index d595f6e04b275..6bf438dc634bd 100644 --- a/src/plugins/data_views/server/types.ts +++ b/src/plugins/data_views/server/types.ts @@ -48,6 +48,10 @@ export interface DataViewsServerPluginStart { * Returns a DataViews service instance */ dataViewsServiceFactory: ServiceFactory; + /** + * + */ + getScriptedFieldsEnabled: () => boolean; } /** diff --git a/src/plugins/saved_search/common/service/saved_searches_utils.test.ts b/src/plugins/saved_search/common/service/saved_searches_utils.test.ts index 8286276bb898e..67f368637d3f5 100644 --- a/src/plugins/saved_search/common/service/saved_searches_utils.test.ts +++ b/src/plugins/saved_search/common/service/saved_searches_utils.test.ts @@ -60,6 +60,7 @@ describe('saved_searches_utils', () => { }, "getConfig": [MockFunction], "onResponse": [MockFunction], + "scriptedFieldsEnabled": true, "search": [MockFunction], }, "fields": Object {}, diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index f19cf47d37bf8..e46d730221a20 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -23,7 +23,7 @@ declare global { } const EXPOSED_CONFIG_SETTINGS_ERROR = - 'Actual config settings exposed to the browser do not match what is expected; this assertion fails if extra settings are present and/or expected settings are missing'; + 'Actual config settings exposed to the browser do not match list defined in test; this assertion fails if extra settings are present and/or expected settings are missing'; export default function ({ getService }: PluginFunctionalProviderContext) { const appsMenu = getService('appsMenu'); @@ -104,6 +104,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'data.search.sessions.management.refreshTimeout (duration)', 'data.search.sessions.maxUpdateRetries (number)', 'data.search.sessions.notTouchedTimeout (duration)', + 'data_views.scriptedFieldsEnabled (any)', // It's a boolean (any because schema.conditional) 'dev_tools.deeplinks.navLinkStatus (string)', 'enterpriseSearch.canDeployEntSearch (boolean)', 'enterpriseSearch.host (string)', diff --git a/x-pack/plugins/alerting/server/plugin.test.ts b/x-pack/plugins/alerting/server/plugin.test.ts index e14ba71c6c1bf..859e69b6da131 100644 --- a/x-pack/plugins/alerting/server/plugin.test.ts +++ b/x-pack/plugins/alerting/server/plugin.test.ts @@ -270,6 +270,7 @@ describe('Alerting Plugin', () => { dataViewsServiceFactory: jest .fn() .mockResolvedValue(dataViewPluginMocks.createStartContract()), + getScriptedFieldsEnabled: jest.fn().mockReturnValue(true), } as DataViewsServerPluginStart, }); @@ -318,6 +319,7 @@ describe('Alerting Plugin', () => { dataViewsServiceFactory: jest .fn() .mockResolvedValue(dataViewPluginMocks.createStartContract()), + getScriptedFieldsEnabled: jest.fn().mockReturnValue(true), } as DataViewsServerPluginStart, }); @@ -377,6 +379,7 @@ describe('Alerting Plugin', () => { dataViewsServiceFactory: jest .fn() .mockResolvedValue(dataViewPluginMocks.createStartContract()), + getScriptedFieldsEnabled: jest.fn().mockReturnValue(true), } as DataViewsServerPluginStart, }); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index ceb0c80270881..4e40531a49f2b 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -133,6 +133,7 @@ describe('Task Runner', () => { const inMemoryMetrics = inMemoryMetricsMock.create(); const dataViewsMock = { dataViewsServiceFactory: jest.fn().mockResolvedValue(dataViewPluginMocks.createStartContract()), + getScriptedFieldsEnabled: jest.fn().mockReturnValue(true), } as DataViewsServerPluginStart; const alertsService = alertsServiceMock.create(); const maintenanceWindowClient = maintenanceWindowClientMock.create(); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts index 73d60259b8610..58f2520ce1f4a 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts @@ -129,6 +129,7 @@ describe('Task Runner', () => { const inMemoryMetrics = inMemoryMetricsMock.create(); const dataViewsMock = { dataViewsServiceFactory: jest.fn().mockResolvedValue(dataViewPluginMocks.createStartContract()), + getScriptedFieldsEnabled: jest.fn().mockReturnValue(true), } as DataViewsServerPluginStart; const mockAlertsService = alertsServiceMock.create(); const mockAlertsClient = alertsClientMock.create(); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts index 527a5d58d34d9..870cad51ed4b7 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts @@ -76,6 +76,7 @@ const alertingEventLogger = alertingEventLoggerMock.create(); const logger: ReturnType = loggingSystemMock.createLogger(); const dataViewsMock = { dataViewsServiceFactory: jest.fn().mockResolvedValue(dataViewPluginMocks.createStartContract()), + getScriptedFieldsEnabled: jest.fn().mockReturnValue(true), } as DataViewsServerPluginStart; const alertsService = alertsServiceMock.create(); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts index 69480563c355e..3cfa7dde78341 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts @@ -45,6 +45,7 @@ const elasticsearchService = elasticsearchServiceMock.createInternalStart(); const dataPlugin = dataPluginMock.createStartContract(); const dataViewsMock = { dataViewsServiceFactory: jest.fn().mockResolvedValue(dataViewPluginMocks.createStartContract()), + getScriptedFieldsEnabled: jest.fn().mockReturnValue(true), } as DataViewsServerPluginStart; const ruleType: UntypedNormalizedRuleType = { id: 'test', diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/index.ts index 1bfb13f2c5f2c..e7b3bacdbeb5f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/index.ts @@ -13,6 +13,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./spaces')); loadTestFile(require.resolve('./security_response_headers')); loadTestFile(require.resolve('./rollups')); + loadTestFile(require.resolve('./scripted_fields')); loadTestFile(require.resolve('./index_management')); loadTestFile(require.resolve('./alerting')); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts b/x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts new file mode 100644 index 0000000000000..f3969e07eea7e --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts @@ -0,0 +1,48 @@ +/* + * 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 expect from 'expect'; +import { DATA_VIEW_PATH } from '@kbn/data-views-plugin/server'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + describe('scripted fields disabled', function () { + before(async () => { + await esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index'); + }); + + after(async () => { + await esArchiver.unload( + 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' + ); + }); + it('scripted fields are ignored when disabled', async () => { + const response = await supertest + .post(DATA_VIEW_PATH) + .set('kbn-xsrf', 'some-xsrf-token') + .send({ + data_view: { + title: 'basic_index', + fields: { + foo_scripted: { + name: 'foo_scripted', + type: 'string', + scripted: true, + script: "doc['field_name'].value", + }, + }, + }, + }); + + expect(response.status).toBe(200); + expect(response.body.data_view.fields.foo_scripted).toBeUndefined(); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/data_view_mgmt.ts b/x-pack/test_serverless/functional/test_suites/common/data_view_mgmt.ts new file mode 100644 index 0000000000000..7e41ed68f8def --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/data_view_mgmt.ts @@ -0,0 +1,54 @@ +/* + * 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 expect from 'expect'; +import { DATA_VIEW_PATH } from '@kbn/data-views-plugin/server'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +const archivePath = 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['settings', 'common', 'header']); + const esArchiver = getService('esArchiver'); + const supertest = getService('supertest'); + const testSubjects = getService('testSubjects'); + + describe('Data View Management', function () { + let dataViewId = ''; + + before(async () => { + await esArchiver.load(archivePath); + + const response = await supertest + .post(DATA_VIEW_PATH) + .set('kbn-xsrf', 'some-xsrf-token') + .send({ + data_view: { + title: 'basic_index', + }, + override: true, + }); + + expect(response.status).toBe(200); + dataViewId = response.body.data_view.id; + }); + + after(async () => { + await esArchiver.unload(archivePath); + await supertest.delete(`${DATA_VIEW_PATH}/${dataViewId}`).set('kbn-xsrf', 'some-xsrf-token'); + }); + + it('Scripted fields tab is missing', async () => { + await PageObjects.common.navigateToUrl('management', 'kibana/dataViews', { + shouldUseHashForSubUrl: false, + }); + await testSubjects.click('detail-link-basic_index'); + await testSubjects.exists('tab-indexedFields'); + await testSubjects.missingOrFail('tab-scriptedFields'); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/index.ts b/x-pack/test_serverless/functional/test_suites/common/index.ts index 7150589527b04..08e816c9bdfda 100644 --- a/x-pack/test_serverless/functional/test_suites/common/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/index.ts @@ -17,5 +17,8 @@ export default function ({ loadTestFile }: FtrProviderContext) { // Management loadTestFile(require.resolve('./index_management')); + + // Data View Management + loadTestFile(require.resolve('./data_view_mgmt')); }); }