mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[8.x] [Data Views] Backport Upgrade Assistant changes to warn about scripted field creation removal in 9.0 (#205561)
## Summary This PR backports the Upgrade Assistant changes from #202250 to warn about the upcoming scripted field creation removal in 9.0. It also includes some of the documentation changes and cleanup in the Data Views Management UI. ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
parent
b44cff196e
commit
8b42d98561
19 changed files with 362 additions and 128 deletions
|
@ -170,7 +170,7 @@ Edit the settings for runtime fields, or remove runtime fields from data views.
|
|||
[[scripted-fields]]
|
||||
=== Add scripted fields to data views
|
||||
|
||||
deprecated::[7.13,Use {ref}/runtime.html[runtime fields] instead of scripted fields. Runtime fields support Painless scripts and provide greater flexibility.]
|
||||
deprecated::[7.13,Use {ref}/runtime.html[runtime fields] instead of scripted fields. Runtime fields support Painless scripting and provide greater flexibility. You can also use the {ref}/esql.html[Elasticsearch Query Language (ES|QL)] to compute values directly at query time.]
|
||||
|
||||
Scripted fields compute data on the fly from the data in your {es} indices. The data is shown on
|
||||
the Discover tab as part of the document data, and you can use scripted fields in your visualizations. You query scripted fields with the <<kuery-query, {kib} query language>>, and can filter them using the filter bar. The scripted field values are computed at query time, so they aren't indexed and cannot be searched using the {kib} default
|
||||
|
@ -192,6 +192,110 @@ doc['field_name'].value
|
|||
For more information on scripted fields and additional examples, refer to
|
||||
https://www.elastic.co/blog/using-painless-kibana-scripted-fields[Using Painless in {kib} scripted fields]
|
||||
|
||||
[float]
|
||||
[[migrate-off-scripted-fields]]
|
||||
==== Migrate to runtime fields or ES|QL queries
|
||||
|
||||
The following code snippets demonstrate how an example scripted field called `computed_values` on the Kibana Sample Data Logs data view could be migrated to either a runtime field or an ES|QL query, highlighting the differences between each approach.
|
||||
|
||||
[float]
|
||||
[[scripted-field-example]]
|
||||
===== Scripted field
|
||||
|
||||
In the scripted field example, variables are created to track all values the script will need to access or return. Since scripted fields can only return a single value, the created variables must be returned together as an array at the end of the script.
|
||||
|
||||
[source,text]
|
||||
----
|
||||
def hour_of_day = $('@timestamp', ZonedDateTime.parse('1970-01-01T00:00:00Z')).getHour();
|
||||
def time_of_day = '';
|
||||
|
||||
if (hour_of_day >= 22 || hour_of_day < 5)
|
||||
time_of_day = 'Night';
|
||||
else if (hour_of_day < 12)
|
||||
time_of_day = 'Morning';
|
||||
else if (hour_of_day < 18)
|
||||
time_of_day = 'Afternoon';
|
||||
else
|
||||
time_of_day = 'Evening';
|
||||
|
||||
def response_int = Integer.parseInt($('response.keyword', '200'));
|
||||
def response_category = '';
|
||||
|
||||
if (response_int < 200)
|
||||
response_category = 'Informational';
|
||||
else if (response_int < 300)
|
||||
response_category = 'Successful';
|
||||
else if (response_int < 400)
|
||||
response_category = 'Redirection';
|
||||
else if (response_int < 500)
|
||||
response_category = 'Client Error';
|
||||
else
|
||||
response_category = 'Server Error';
|
||||
|
||||
return [time_of_day, response_category];
|
||||
----
|
||||
|
||||
[float]
|
||||
[[runtime-field-example]]
|
||||
===== Runtime field
|
||||
|
||||
Unlike scripted fields, runtime fields do not need to return a single value and can emit values at any point in the script, which will be combined and returned as a multi-value field. This allows for more flexibility in the script logic and removes the need to manually manage an array of values.
|
||||
|
||||
[source,text]
|
||||
----
|
||||
def hour_of_day = $('@timestamp', ZonedDateTime.parse('1970-01-01T00:00:00Z')).getHour();
|
||||
|
||||
if (hour_of_day >= 22 || hour_of_day < 5)
|
||||
emit('Night');
|
||||
else if (hour_of_day < 12)
|
||||
emit('Morning');
|
||||
else if (hour_of_day < 18)
|
||||
emit('Afternoon');
|
||||
else
|
||||
emit('Evening');
|
||||
|
||||
def response_int = Integer.parseInt($('response.keyword', '200'));
|
||||
|
||||
if (response_int < 200)
|
||||
emit('Informational');
|
||||
else if (response_int < 300)
|
||||
emit('Successful');
|
||||
else if (response_int < 400)
|
||||
emit('Redirection');
|
||||
else if (response_int < 500)
|
||||
emit('Client Error');
|
||||
else
|
||||
emit('Server Error');
|
||||
----
|
||||
|
||||
[float]
|
||||
[[esql-example]]
|
||||
===== ES|QL query
|
||||
|
||||
Alternatively, ES|QL can be used to skip the need for data view management entirely and simply compute the values you need at query time. ES|QL supports computing multiple field values in a single query, using computed values with its rich set of commands and functions, and even aggregations against computed values. This makes it an excellent solution for one-off queries and realtime data analysis.
|
||||
|
||||
[source,esql]
|
||||
----
|
||||
FROM kibana_sample_data_logs
|
||||
| EVAL hour_of_day = DATE_EXTRACT("HOUR_OF_DAY", @timestamp)
|
||||
| EVAL time_of_day = CASE(
|
||||
hour_of_day >= 22 OR hour_of_day < 5, "Night",
|
||||
hour_of_day < 12, "Morning",
|
||||
hour_of_day < 18, "Afternoon",
|
||||
"Evening"
|
||||
)
|
||||
| EVAL response_int = TO_INTEGER(response)
|
||||
| EVAL response_category = CASE(
|
||||
response_int < 200, "Informational",
|
||||
response_int < 300, "Successful",
|
||||
response_int < 400, "Redirection",
|
||||
response_int < 500, "Client Error",
|
||||
"Server Error"
|
||||
)
|
||||
| EVAL computed_values = MV_APPEND(time_of_day, response_category)
|
||||
| DROP hour_of_day, time_of_day, response_int, response_category
|
||||
----
|
||||
|
||||
[float]
|
||||
[[create-scripted-field]]
|
||||
==== Create scripted fields
|
||||
|
@ -214,6 +318,8 @@ For more information about scripted fields in {es}, refer to {ref}/modules-scrip
|
|||
[[update-scripted-field]]
|
||||
==== Manage scripted fields
|
||||
|
||||
WARNING: The ability to create new scripted fields has been removed from the *Data Views* management page in 9.0. Existing scripted fields can still be edited or deleted, and the creation UI can be accessed by navigating directly to `/app/management/kibana/dataViews/dataView/{dataViewId}/create-field`, but we recommend migrating to runtime fields or ES|QL queries instead to prepare for removal.
|
||||
|
||||
. Go to the *Data Views* management page using the navigation menu or the <<kibana-navigation-search,global search field>>.
|
||||
|
||||
. Select the data view that contains the scripted field you want to manage.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
export type {
|
||||
DeprecationDetailsMessage,
|
||||
BaseDeprecationDetails,
|
||||
ConfigDeprecationDetails,
|
||||
FeatureDeprecationDetails,
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
export interface DeprecationDetailsMessage {
|
||||
type: 'markdown' | 'text';
|
||||
content: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base properties shared by all types of deprecations
|
||||
*
|
||||
|
@ -22,7 +27,7 @@ export interface BaseDeprecationDetails {
|
|||
* The description message to be displayed for the deprecation.
|
||||
* Check the README for writing deprecations in `src/core/server/deprecations/README.mdx`
|
||||
*/
|
||||
message: string | string[];
|
||||
message: string | DeprecationDetailsMessage | Array<string | DeprecationDetailsMessage>;
|
||||
/**
|
||||
* levels:
|
||||
* - warning: will not break deployment upon upgrade
|
||||
|
|
|
@ -349,6 +349,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
|
|||
fieldFormattersNumber: `${KIBANA_DOCS}numeral.html`,
|
||||
fieldFormattersString: `${KIBANA_DOCS}managing-data-views.html#string-field-formatters`,
|
||||
runtimeFields: `${KIBANA_DOCS}managing-data-views.html#runtime-fields`,
|
||||
migrateOffScriptedFields: `${KIBANA_DOCS}managing-data-views.html#migrate-off-scripted-fields`,
|
||||
},
|
||||
addData: `${KIBANA_DOCS}connect-to-elasticsearch.html`,
|
||||
kibana: {
|
||||
|
|
|
@ -307,6 +307,7 @@ export interface DocLinks {
|
|||
readonly fieldFormattersNumber: string;
|
||||
readonly fieldFormattersString: string;
|
||||
readonly runtimeFields: string;
|
||||
readonly migrateOffScriptedFields: string;
|
||||
};
|
||||
readonly addData: string;
|
||||
readonly kibana: {
|
||||
|
|
|
@ -2,19 +2,22 @@
|
|||
|
||||
exports[`CallOuts should render normally 1`] = `
|
||||
<Fragment>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
title={
|
||||
<Memo(MemoizedFormattedMessage)
|
||||
defaultMessage="Deprecation languages in use"
|
||||
id="indexPatternManagement.editIndexPattern.scripted.deprecationLangHeader"
|
||||
defaultMessage="Deprecated languages in use"
|
||||
id="indexPatternManagement.editIndexPattern.scripted.deprecatedLangHeader"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<p>
|
||||
<MemoizedFormattedMessage
|
||||
defaultMessage="The following deprecated languages are in use: {deprecatedLangsInUse}. Support for these languages will be removed in the next major version of Kibana and Elasticsearch. Convert you scripted fields to {link} to avoid any problems."
|
||||
defaultMessage="The following deprecated languages are in use: {deprecatedLangsInUse}. Support for these languages will be removed in the next major version of Kibana and Elasticsearch. Convert your scripted fields to {link} to avoid any problems."
|
||||
id="indexPatternManagement.editIndexPattern.scripted.deprecationLangLabel.deprecationLangDetail"
|
||||
values={
|
||||
Object {
|
||||
|
@ -32,9 +35,6 @@ exports[`CallOuts should render normally 1`] = `
|
|||
/>
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
|
|
|
@ -24,11 +24,12 @@ export const CallOuts = ({ deprecatedLangsInUse, painlessDocLink }: CallOutsProp
|
|||
|
||||
return (
|
||||
<>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.editIndexPattern.scripted.deprecationLangHeader"
|
||||
defaultMessage="Deprecation languages in use"
|
||||
id="indexPatternManagement.editIndexPattern.scripted.deprecatedLangHeader"
|
||||
defaultMessage="Deprecated languages in use"
|
||||
/>
|
||||
}
|
||||
color="danger"
|
||||
|
@ -38,7 +39,7 @@ export const CallOuts = ({ deprecatedLangsInUse, painlessDocLink }: CallOutsProp
|
|||
<FormattedMessage
|
||||
id="indexPatternManagement.editIndexPattern.scripted.deprecationLangLabel.deprecationLangDetail"
|
||||
defaultMessage="The following deprecated languages are in use: {deprecatedLangsInUse}. Support for these languages will be
|
||||
removed in the next major version of Kibana and Elasticsearch. Convert you scripted fields to {link} to avoid any problems."
|
||||
removed in the next major version of Kibana and Elasticsearch. Convert your scripted fields to {link} to avoid any problems."
|
||||
values={{
|
||||
deprecatedLangsInUse: deprecatedLangsInUse.join(', '),
|
||||
link: (
|
||||
|
@ -53,7 +54,6 @@ export const CallOuts = ({ deprecatedLangsInUse, painlessDocLink }: CallOutsProp
|
|||
/>
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,11 +2,53 @@
|
|||
|
||||
exports[`Header should render normally 1`] = `
|
||||
<div
|
||||
class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-center-row"
|
||||
class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-flexStart-row"
|
||||
>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||
>
|
||||
<div
|
||||
class="euiPanel euiPanel--warning euiPanel--paddingMedium euiCallOut euiCallOut--warning emotion-euiPanel-none-m-warning-euiCallOut"
|
||||
>
|
||||
<p
|
||||
class="euiTitle euiCallOutHeader__title emotion-euiTitle-xs-euiCallOutHeader-warning"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="emotion-euiCallOut__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="warning"
|
||||
/>
|
||||
Scripted fields are deprecated
|
||||
</p>
|
||||
<div
|
||||
class="euiSpacer euiSpacer--s emotion-euiSpacer-s"
|
||||
/>
|
||||
<div
|
||||
class="euiText emotion-euiText-s-euiTextColor-default"
|
||||
>
|
||||
<span>
|
||||
Use
|
||||
<button
|
||||
class="euiLink emotion-euiLink-primary"
|
||||
type="button"
|
||||
>
|
||||
runtime fields
|
||||
</button>
|
||||
instead of scripted fields. Runtime fields support Painless scripting and provide greater flexibility. You can also use the
|
||||
<button
|
||||
class="euiLink emotion-euiLink-primary"
|
||||
type="button"
|
||||
>
|
||||
Elasticsearch Query Language (ES|QL)
|
||||
</button>
|
||||
to compute values directly at query time.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="euiSpacer euiSpacer--m emotion-euiSpacer-m"
|
||||
/>
|
||||
<div
|
||||
class="euiText emotion-euiText-s"
|
||||
>
|
||||
|
@ -14,22 +56,6 @@ exports[`Header should render normally 1`] = `
|
|||
<span>
|
||||
Scripted fields can be used in visualizations and displayed in documents. However, they cannot be searched.
|
||||
</span>
|
||||
<br />
|
||||
<span
|
||||
class="emotion-EuiIcon"
|
||||
color="warning"
|
||||
data-euiicon-type="warning"
|
||||
/>
|
||||
<span>
|
||||
Scripted fields are deprecated. Use
|
||||
<button
|
||||
class="euiLink emotion-euiLink-primary"
|
||||
type="button"
|
||||
>
|
||||
runtime fields
|
||||
</button>
|
||||
instead.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,9 +9,19 @@
|
|||
|
||||
import React from 'react';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiText, EuiLink, EuiIcon } from '@elastic/eui';
|
||||
import {
|
||||
EuiCallOut,
|
||||
EuiButton,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiText,
|
||||
EuiLink,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { ScopedHistory } from '@kbn/core/public';
|
||||
|
||||
import { reactRouterNavigate, useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
|
@ -27,8 +37,40 @@ export const Header = withRouter(({ indexPatternId, history }: HeaderProps) => {
|
|||
const links = docLinks?.links;
|
||||
const userEditPermission = dataViews.getCanSaveSync();
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexGroup alignItems="flexStart">
|
||||
<EuiFlexItem>
|
||||
<EuiCallOut
|
||||
title={i18n.translate('indexPatternManagement.editIndexPattern.deprecation.title', {
|
||||
defaultMessage: 'Scripted fields are deprecated',
|
||||
})}
|
||||
color="warning"
|
||||
iconType="warning"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.editIndexPattern.deprecation.message"
|
||||
tagName="span"
|
||||
defaultMessage="Use {runtimeFieldsLink} instead of scripted fields. Runtime fields support Painless scripting and provide greater flexibility. You can also use the {esqlLink} to compute values directly at query time."
|
||||
values={{
|
||||
runtimeFieldsLink: (
|
||||
<EuiLink target="_blank" href={links.indexPatterns.runtimeFields}>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.header.runtimeLink"
|
||||
defaultMessage="runtime fields"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
esqlLink: (
|
||||
<EuiLink target="_blank" href={links.query.queryESQL}>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.header.esqlLink"
|
||||
defaultMessage="Elasticsearch Query Language (ES|QL)"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
|
@ -36,23 +78,6 @@ export const Header = withRouter(({ indexPatternId, history }: HeaderProps) => {
|
|||
id="indexPatternManagement.editIndexPattern.scriptedLabel"
|
||||
defaultMessage="Scripted fields can be used in visualizations and displayed in documents. However, they cannot be searched."
|
||||
/>
|
||||
<br />
|
||||
<EuiIcon type="warning" color="warning" css={{ marginRight: '4px' }} />
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.editIndexPattern.deprecation"
|
||||
tagName="span"
|
||||
defaultMessage="Scripted fields are deprecated. Use {runtimeDocs} instead."
|
||||
values={{
|
||||
runtimeDocs: (
|
||||
<EuiLink target="_blank" href={links.runtimeFields.overview}>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.header.runtimeLink"
|
||||
defaultMessage="runtime fields"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -59,7 +59,7 @@ export class ScriptedFieldsTable extends Component<
|
|||
}
|
||||
|
||||
fetchFields = async () => {
|
||||
const fields = await (this.props.indexPattern.getScriptedFields() as ScriptedFieldItem[]);
|
||||
const fields = this.props.indexPattern.getScriptedFields() as ScriptedFieldItem[];
|
||||
|
||||
const deprecatedLangsInUse = [];
|
||||
const deprecatedLangs = getDeprecatedScriptingLanguages();
|
||||
|
@ -67,7 +67,7 @@ export class ScriptedFieldsTable extends Component<
|
|||
|
||||
for (const field of fields) {
|
||||
const lang = field.lang;
|
||||
if (deprecatedLangs.includes(lang) || !supportedLangs.includes(lang)) {
|
||||
if (lang && (deprecatedLangs.includes(lang) || !supportedLangs.includes(lang))) {
|
||||
deprecatedLangsInUse.push(lang);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ const docLinks = {
|
|||
indexPatterns: {},
|
||||
scriptedFields: {},
|
||||
runtimeFields: {},
|
||||
query: {},
|
||||
} as any,
|
||||
};
|
||||
|
||||
|
|
|
@ -7,85 +7,83 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import {
|
||||
import type {
|
||||
CoreSetup,
|
||||
DeprecationsDetails,
|
||||
GetDeprecationsContext,
|
||||
RegisterDeprecationsConfig,
|
||||
SavedObjectsFindResult,
|
||||
} from '@kbn/core/server';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { DataViewAttributes } from '../../common';
|
||||
import type { DocLinks } from '@kbn/doc-links';
|
||||
import type { DeprecationDetailsMessage } from '@kbn/core-deprecations-common';
|
||||
import type { DataViewAttributes } from '../../common';
|
||||
|
||||
type IndexPatternAttributesWithFields = Pick<DataViewAttributes, 'title' | 'fields'>;
|
||||
type DataViewAttributesWithFields = Pick<DataViewAttributes, 'name' | 'title' | 'fields'>;
|
||||
|
||||
export const createScriptedFieldsDeprecationsConfig: (
|
||||
core: CoreSetup
|
||||
) => RegisterDeprecationsConfig = (core: CoreSetup) => ({
|
||||
getDeprecations: async (context: GetDeprecationsContext): Promise<DeprecationsDetails[]> => {
|
||||
const finder =
|
||||
context.savedObjectsClient.createPointInTimeFinder<IndexPatternAttributesWithFields>({
|
||||
const finder = context.savedObjectsClient.createPointInTimeFinder<DataViewAttributesWithFields>(
|
||||
{
|
||||
type: 'index-pattern',
|
||||
perPage: 1000,
|
||||
fields: ['title', 'fields'],
|
||||
fields: ['name', 'title', 'fields'],
|
||||
namespaces: ['*'],
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const dataViewsWithScriptedFields: Array<SavedObjectsFindResult<DataViewAttributesWithFields>> =
|
||||
[];
|
||||
|
||||
const indexPatternsWithScriptedFields: IndexPatternAttributesWithFields[] = [];
|
||||
for await (const response of finder.find()) {
|
||||
indexPatternsWithScriptedFields.push(
|
||||
...response.saved_objects.map((so) => so.attributes).filter(hasScriptedField)
|
||||
dataViewsWithScriptedFields.push(
|
||||
...response.saved_objects.filter((so) => hasScriptedField(so.attributes))
|
||||
);
|
||||
}
|
||||
|
||||
if (indexPatternsWithScriptedFields.length > 0) {
|
||||
const PREVIEW_LIMIT = 3;
|
||||
const indexPatternTitles = indexPatternsWithScriptedFields.map((ip) => ip.title);
|
||||
|
||||
return [
|
||||
{
|
||||
title: i18n.translate('dataViews.deprecations.scriptedFieldsTitle', {
|
||||
defaultMessage: 'Found data views using scripted fields',
|
||||
}),
|
||||
message: i18n.translate('dataViews.deprecations.scriptedFieldsMessage', {
|
||||
defaultMessage: `You have {numberOfIndexPatternsWithScriptedFields} data views ({titlesPreview}...) that use scripted fields. Scripted fields are deprecated and will be removed in future. Use runtime fields instead.`,
|
||||
values: {
|
||||
titlesPreview: indexPatternTitles.slice(0, PREVIEW_LIMIT).join('; '),
|
||||
numberOfIndexPatternsWithScriptedFields: indexPatternsWithScriptedFields.length,
|
||||
},
|
||||
}),
|
||||
documentationUrl:
|
||||
'https://www.elastic.co/guide/en/elasticsearch/reference/7.x/runtime.html', // TODO: documentation service is not available serverside https://github.com/elastic/kibana/issues/95389
|
||||
level: 'warning', // warning because it is not set in stone WHEN we remove scripted fields, hence this deprecation is not a blocker for 8.0 upgrade
|
||||
correctiveActions: {
|
||||
manualSteps: [
|
||||
i18n.translate('dataViews.deprecations.scriptedFields.manualStepOneMessage', {
|
||||
defaultMessage: 'Navigate to Stack Management > Kibana > Data Views.',
|
||||
}),
|
||||
i18n.translate('dataViews.deprecations.scriptedFields.manualStepTwoMessage', {
|
||||
defaultMessage:
|
||||
'Update {numberOfIndexPatternsWithScriptedFields} data views that have scripted fields to use runtime fields instead. In most cases, to migrate existing scripts, you will need to change "return <value>;" to "emit(<value>);". Data views with at least one scripted field: {allTitles}',
|
||||
values: {
|
||||
allTitles: indexPatternTitles.join('; '),
|
||||
numberOfIndexPatternsWithScriptedFields: indexPatternsWithScriptedFields.length,
|
||||
},
|
||||
ignoreTag: true,
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
} else {
|
||||
if (!dataViewsWithScriptedFields.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
title: i18n.translate('dataViews.deprecations.scriptedFieldsTitle', {
|
||||
defaultMessage: 'Found data views using scripted fields',
|
||||
}),
|
||||
message: buildMessage({
|
||||
dataViewsWithScriptedFields,
|
||||
docLinks: core.docLinks.links,
|
||||
}),
|
||||
documentationUrl: core.docLinks.links.indexPatterns.migrateOffScriptedFields,
|
||||
deprecationType: 'feature',
|
||||
level: 'warning', // warning because it is not set in stone WHEN we remove scripted fields, hence this deprecation is not a blocker for 9.0 upgrade
|
||||
correctiveActions: {
|
||||
manualSteps: [
|
||||
i18n.translate('dataViews.deprecations.scriptedFields.manualStepOneMessage', {
|
||||
defaultMessage: 'Navigate to Stack Management > Kibana > Data Views.',
|
||||
}),
|
||||
i18n.translate('dataViews.deprecations.scriptedFields.manualStepTwoMessage', {
|
||||
defaultMessage:
|
||||
'Update data views that have scripted fields to use runtime fields instead. In most cases, you will only need to change "return <value>;" to "emit(<value>);".',
|
||||
ignoreTag: true,
|
||||
}),
|
||||
i18n.translate('dataViews.deprecations.scriptedFields.manualStepThreeMessage', {
|
||||
defaultMessage:
|
||||
'Alternatively, you can achieve similar functionality by computing values at query time using the Elasticsearch Query Language (ES|QL).',
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
export function hasScriptedField(indexPattern: IndexPatternAttributesWithFields) {
|
||||
if (indexPattern.fields) {
|
||||
export function hasScriptedField(dataView: DataViewAttributesWithFields) {
|
||||
if (dataView.fields) {
|
||||
try {
|
||||
return JSON.parse(indexPattern.fields).some(
|
||||
(field: { scripted?: boolean }) => field?.scripted
|
||||
);
|
||||
return JSON.parse(dataView.fields).some((field: { scripted?: boolean }) => field?.scripted);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
@ -93,3 +91,55 @@ export function hasScriptedField(indexPattern: IndexPatternAttributesWithFields)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const dataViewIdLabel = i18n.translate('dataViews.deprecations.scriptedFields.dataViewIdLabel', {
|
||||
defaultMessage: 'ID',
|
||||
});
|
||||
|
||||
const dataViewNameLabel = i18n.translate(
|
||||
'dataViews.deprecations.scriptedFields.dataViewNameLabel',
|
||||
{
|
||||
defaultMessage: 'Name',
|
||||
}
|
||||
);
|
||||
|
||||
const dataViewSpacesLabel = i18n.translate(
|
||||
'dataViews.deprecations.scriptedFields.dataViewSpacesLabel',
|
||||
{
|
||||
defaultMessage: 'Spaces',
|
||||
}
|
||||
);
|
||||
|
||||
const buildDataViewsListEntry = (
|
||||
so: SavedObjectsFindResult<DataViewAttributesWithFields>
|
||||
) => `- **${dataViewIdLabel}:** ${so.id}
|
||||
- **${dataViewNameLabel}:** ${
|
||||
so.attributes.name
|
||||
? `!{tooltip[${so.attributes.name}](${so.attributes.title})}`
|
||||
: so.attributes.title
|
||||
}
|
||||
- **${dataViewSpacesLabel}:** ${so.namespaces?.join(', ')}`;
|
||||
|
||||
const buildMessage = ({
|
||||
dataViewsWithScriptedFields,
|
||||
docLinks,
|
||||
}: {
|
||||
dataViewsWithScriptedFields: Array<SavedObjectsFindResult<DataViewAttributesWithFields>>;
|
||||
docLinks: DocLinks;
|
||||
}): DeprecationDetailsMessage => ({
|
||||
type: 'markdown',
|
||||
content: i18n.translate('dataViews.deprecations.scriptedFieldsMessage', {
|
||||
defaultMessage: `You have {numberOfDataViewsWithScriptedFields} {numberOfDataViewsWithScriptedFields, plural, one {data view} other {data views}} containing scripted fields. Scripted fields are deprecated and will be removed in the future.
|
||||
|
||||
The ability to create new scripted fields in the Data Views management page has been disabled in 9.0, and it is recommended to migrate to [runtime fields]({runtimeFieldsLink}) or the [Elasticsearch Query Language (ES|QL)]({esqlLink}) instead.
|
||||
|
||||
The following is a list of all data views with scripted fields and their associated spaces:
|
||||
{dataViewsList}`,
|
||||
values: {
|
||||
numberOfDataViewsWithScriptedFields: dataViewsWithScriptedFields.length,
|
||||
runtimeFieldsLink: docLinks.indexPatterns.runtimeFields,
|
||||
esqlLink: docLinks.query.queryESQL,
|
||||
dataViewsList: dataViewsWithScriptedFields.map(buildDataViewsListEntry).join('\n'),
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
"@kbn/core-http-browser",
|
||||
"@kbn/core-http-browser-internal",
|
||||
"@kbn/logging-mocks",
|
||||
"@kbn/doc-links",
|
||||
"@kbn/core-deprecations-common",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
import expect from '@kbn/expect';
|
||||
import type { DeprecationsGetResponse } from '@kbn/core/server';
|
||||
import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import type { DeprecationDetailsMessage } from '@kbn/core-deprecations-common';
|
||||
import type { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
@ -75,7 +76,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
);
|
||||
|
||||
expect(dataPluginDeprecations.length).to.be(1);
|
||||
expect(dataPluginDeprecations[0].message).to.contain(title);
|
||||
expect((dataPluginDeprecations[0].message as DeprecationDetailsMessage).content).to.contain(
|
||||
title
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -77,5 +77,6 @@
|
|||
"@kbn/default-nav-devtools",
|
||||
"@kbn/core-saved-objects-import-export-server-internal",
|
||||
"@kbn/management-settings-ids",
|
||||
"@kbn/core-deprecations-common",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2463,9 +2463,6 @@
|
|||
"dataViews.contentManagementType": "Vue de données",
|
||||
"dataViews.dataStreamLabel": "Flux de données",
|
||||
"dataViews.deprecations.scriptedFields.manualStepOneMessage": "Accédez à Gestion de la Suite > Kibana > Vues de données.",
|
||||
"dataViews.deprecations.scriptedFields.manualStepTwoMessage": "Mettez à jour les vues de données {numberOfIndexPatternsWithScriptedFields} qui ont des champs scriptés pour qu’elles utilisent des champs d'exécution. Dans la plupart des cas, pour migrer des scripts existants, vous devrez remplacer \"return <value>;\" par \"emit(<value>);\". Vues de données avec au moins un champ scripté : {allTitles}",
|
||||
"dataViews.deprecations.scriptedFieldsMessage": "Vous avez {numberOfIndexPatternsWithScriptedFields} vues de données ({titlesPreview}...) qui utilisent des champs scriptés. Les champs scriptés sont déclassés et seront supprimés à l'avenir. Utilisez plutôt des champs d'exécution.",
|
||||
"dataViews.deprecations.scriptedFieldsTitle": "Vues de données utilisant des champs scriptés trouvées",
|
||||
"dataViews.fetchFieldErrorTitle": "Erreur lors de l'extraction des champs pour la vue de données {title} (ID : {id})",
|
||||
"dataViews.frozenLabel": "Frozen",
|
||||
"dataViews.functions.dataViewLoad.help": "Charge une vue de données",
|
||||
|
@ -5018,7 +5015,6 @@
|
|||
"indexPatternManagement.editIndexPattern.couldNotLoadMessage": "La vue de données ayant l'ID {objectId} n'a pas pu être chargée. Essayez d'en créer une nouvelle.",
|
||||
"indexPatternManagement.editIndexPattern.couldNotLoadTitle": "Impossible de charger la vue de données",
|
||||
"indexPatternManagement.editIndexPattern.deleteButton": "Supprimer",
|
||||
"indexPatternManagement.editIndexPattern.deprecation": "Les champs scriptés sont déclassés. Utilisez {runtimeDocs} à la place.",
|
||||
"indexPatternManagement.editIndexPattern.fields.addFieldButtonLabel": "Ajouter un champ",
|
||||
"indexPatternManagement.editIndexPattern.fields.conflictModal.closeBtn": "Fermer",
|
||||
"indexPatternManagement.editIndexPattern.fields.conflictModal.description": "Le type de champ {fieldName} change entre les index et peut ne pas être disponible pour la recherche, les visualisations et d'autres analyses.",
|
||||
|
@ -5070,8 +5066,6 @@
|
|||
"indexPatternManagement.editIndexPattern.scripted.deleteField.cancelButton": "Annuler",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deleteField.deleteButton": "Supprimer",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deleteFieldLabel": "Supprimer le champ scripté \"{fieldName}\" ?",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deprecationLangHeader": "Langages déclassés en cours d'utilisation",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deprecationLangLabel.deprecationLangDetail": "Les langages déclassés suivants sont en cours d'utilisation : {deprecatedLangsInUse}. La prise en charge de ces langages sera supprimée dans la prochaine version majeure de Kibana et d'Elasticsearch. Convertissez vos champs scriptés en {link} pour éviter tout problème.",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deprecationLangLabel.painlessDescription": "Painless",
|
||||
"indexPatternManagement.editIndexPattern.scripted.newFieldPlaceholder": "Nouveau champ scripté",
|
||||
"indexPatternManagement.editIndexPattern.scripted.table.deleteDescription": "Supprimer ce champ",
|
||||
|
|
|
@ -2462,9 +2462,6 @@
|
|||
"dataViews.contentManagementType": "データビュー",
|
||||
"dataViews.dataStreamLabel": "データストリーム",
|
||||
"dataViews.deprecations.scriptedFields.manualStepOneMessage": "[スタック管理]>[Kibana]>[データビュー]に移動します。",
|
||||
"dataViews.deprecations.scriptedFields.manualStepTwoMessage": "ランタイムフィールドを使用するには、スクリプト化されたフィールドがある{numberOfIndexPatternsWithScriptedFields}データビューを更新します。ほとんどの場合、既存のスクリプトを移行するには、「return <value>;」から「emit(<value>);」に変更する必要があります。1つ以上のスクリプト化されたフィールドがあるデータビュー:{allTitles}",
|
||||
"dataViews.deprecations.scriptedFieldsMessage": "スクリプト化されたフィールドを使用する{numberOfIndexPatternsWithScriptedFields}データビュー({titlesPreview}...)があります。スクリプト化されたフィールドは廃止予定であり、今後は削除されます。ランタイムフィールドを使用してください。",
|
||||
"dataViews.deprecations.scriptedFieldsTitle": "スクリプト化されたフィールドを使用しているデータビューが見つかりました。",
|
||||
"dataViews.fetchFieldErrorTitle": "データビューのフィールド取得中にエラーが発生 {title}(ID:{id})",
|
||||
"dataViews.frozenLabel": "凍結",
|
||||
"dataViews.functions.dataViewLoad.help": "データビューを読み込みます",
|
||||
|
@ -5012,7 +5009,6 @@
|
|||
"indexPatternManagement.editIndexPattern.couldNotLoadMessage": "ID {objectId}のデータビューを読み込めませんでした。新規作成してください。",
|
||||
"indexPatternManagement.editIndexPattern.couldNotLoadTitle": "データビューを読み込めません",
|
||||
"indexPatternManagement.editIndexPattern.deleteButton": "削除",
|
||||
"indexPatternManagement.editIndexPattern.deprecation": "スクリプトフィールドは廃止予定です。代わりに{runtimeDocs}を使用してください。",
|
||||
"indexPatternManagement.editIndexPattern.fields.addFieldButtonLabel": "フィールドの追加",
|
||||
"indexPatternManagement.editIndexPattern.fields.conflictModal.closeBtn": "閉じる",
|
||||
"indexPatternManagement.editIndexPattern.fields.conflictModal.description": "{fieldName}フィールドの型がインデックス全体で変更され、検索、視覚化、他の分析で使用できない可能性があります。",
|
||||
|
@ -5064,8 +5060,6 @@
|
|||
"indexPatternManagement.editIndexPattern.scripted.deleteField.cancelButton": "キャンセル",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deleteField.deleteButton": "削除",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deleteFieldLabel": "スクリプトフィールド''{fieldName}''を削除しますか?",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deprecationLangHeader": "廃止された言語が使用されています",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deprecationLangLabel.deprecationLangDetail": "次の廃止された言語が使用されています。{deprecatedLangsInUse}これらの言語は、KibanaとElasticsearchの次のメジャーバージョンでサポートされなくなります。問題を避けるため、スクリプトフィールドを{link}に変換してください。",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deprecationLangLabel.painlessDescription": "Painless",
|
||||
"indexPatternManagement.editIndexPattern.scripted.newFieldPlaceholder": "新規スクリプトフィールド",
|
||||
"indexPatternManagement.editIndexPattern.scripted.table.deleteDescription": "このフィールドを削除します",
|
||||
|
|
|
@ -2491,9 +2491,6 @@
|
|||
"dataViews.contentManagementType": "数据视图",
|
||||
"dataViews.dataStreamLabel": "数据流",
|
||||
"dataViews.deprecations.scriptedFields.manualStepOneMessage": "导航到“堆栈管理”>“Kibana”>“数据视图”。",
|
||||
"dataViews.deprecations.scriptedFields.manualStepTwoMessage": "更新 {numberOfIndexPatternsWithScriptedFields} 个具有脚本字段的数据视图以改为使用运行时字段。多数情况下,要迁移现有脚本,您需要将“return <value>;”更改为“emit(<value>);”。至少有一个脚本字段的数据视图:{allTitles}",
|
||||
"dataViews.deprecations.scriptedFieldsMessage": "您具有 {numberOfIndexPatternsWithScriptedFields} 个使用脚本字段的数据视图 ({titlesPreview}...)。脚本字段已过时,将在未来移除。请改为使用运行时脚本。",
|
||||
"dataViews.deprecations.scriptedFieldsTitle": "找到使用脚本字段的数据视图",
|
||||
"dataViews.fetchFieldErrorTitle": "提取数据视图 {title}(ID:{id})的字段时出错",
|
||||
"dataViews.frozenLabel": "已冻结",
|
||||
"dataViews.functions.dataViewLoad.help": "加载数据视图",
|
||||
|
@ -5051,7 +5048,6 @@
|
|||
"indexPatternManagement.editIndexPattern.couldNotLoadMessage": "无法加载 ID 为 {objectId} 的数据视图。尝试创建新视图。",
|
||||
"indexPatternManagement.editIndexPattern.couldNotLoadTitle": "无法加载数据视图",
|
||||
"indexPatternManagement.editIndexPattern.deleteButton": "删除",
|
||||
"indexPatternManagement.editIndexPattern.deprecation": "脚本字段已弃用。改用 {runtimeDocs}。",
|
||||
"indexPatternManagement.editIndexPattern.fields.addFieldButtonLabel": "添加字段",
|
||||
"indexPatternManagement.editIndexPattern.fields.conflictModal.closeBtn": "关闭",
|
||||
"indexPatternManagement.editIndexPattern.fields.conflictModal.description": "{fieldName} 字段的类型在不同索引中会有所不同,并且可能无法用于搜索、可视化和其他分析。",
|
||||
|
@ -5103,8 +5099,6 @@
|
|||
"indexPatternManagement.editIndexPattern.scripted.deleteField.cancelButton": "取消",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deleteField.deleteButton": "删除",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deleteFieldLabel": "删除脚本字段“{fieldName}”?",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deprecationLangHeader": "在用的过时语言",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deprecationLangLabel.deprecationLangDetail": "以下过时的语言仍在使用:{deprecatedLangsInUse}。Kibana 和 Elasticsearch 的下一主要版本将移除对这些语言的支持。将您的脚本字段转换成 {link} 以避免问题。",
|
||||
"indexPatternManagement.editIndexPattern.scripted.deprecationLangLabel.painlessDescription": "Painless",
|
||||
"indexPatternManagement.editIndexPattern.scripted.newFieldPlaceholder": "新建脚本字段",
|
||||
"indexPatternManagement.editIndexPattern.scripted.table.deleteDescription": "删除此字段",
|
||||
|
|
|
@ -22,6 +22,9 @@ import {
|
|||
EuiText,
|
||||
EuiCallOut,
|
||||
EuiSpacer,
|
||||
EuiMarkdownFormat,
|
||||
getDefaultEuiMarkdownPlugins,
|
||||
useEuiFontSize,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { uiMetricService, UIM_KIBANA_QUICK_RESOLVE_CLICK } from '../../lib/ui_metric';
|
||||
|
@ -103,6 +106,12 @@ const i18nTexts = {
|
|||
),
|
||||
};
|
||||
|
||||
const { processingPlugins } = getDefaultEuiMarkdownPlugins({
|
||||
processingConfig: {
|
||||
linkProps: { target: '_blank' },
|
||||
},
|
||||
});
|
||||
|
||||
interface AvailableCorrectiveActions {
|
||||
api: boolean;
|
||||
manual: boolean;
|
||||
|
@ -158,6 +167,8 @@ export const DeprecationDetailsFlyout = ({
|
|||
resolveDeprecation(deprecation);
|
||||
}, [deprecation, resolveDeprecation]);
|
||||
|
||||
const { lineHeight: lineHeightMedium } = useEuiFontSize('m');
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
|
@ -185,11 +196,30 @@ export const DeprecationDetailsFlyout = ({
|
|||
)}
|
||||
|
||||
<EuiText>
|
||||
{messages.map((m, i) => (
|
||||
<p key={i} className="eui-textBreakWord">
|
||||
{m}
|
||||
</p>
|
||||
))}
|
||||
{messages.map((currentMessage, i) => {
|
||||
if (typeof currentMessage === 'object' && currentMessage.type === 'markdown') {
|
||||
return (
|
||||
<EuiMarkdownFormat
|
||||
key={i}
|
||||
className="eui-textBreakWord"
|
||||
textSize="relative"
|
||||
processingPluginList={processingPlugins}
|
||||
css={{ marginBlockEnd: lineHeightMedium }}
|
||||
>
|
||||
{currentMessage.content}
|
||||
</EuiMarkdownFormat>
|
||||
);
|
||||
}
|
||||
|
||||
const textContent =
|
||||
typeof currentMessage === 'string' ? currentMessage : currentMessage.content;
|
||||
|
||||
return (
|
||||
<p key={i} className="eui-textBreakWord">
|
||||
{textContent}
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
{documentationUrl && (
|
||||
<p>
|
||||
<DeprecationFlyoutLearnMoreLink documentationUrl={documentationUrl} />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue