diff --git a/.bazeliskversion b/.bazeliskversion index 4dae2985b58cc..1cac385c6cb86 100644 --- a/.bazeliskversion +++ b/.bazeliskversion @@ -1 +1 @@ -1.10.1 +1.11.0 diff --git a/.buildkite/scripts/steps/cloud/purge.js b/.buildkite/scripts/steps/cloud/purge.js index b14a3be8f8daf..336f7daf736ae 100644 --- a/.buildkite/scripts/steps/cloud/purge.js +++ b/.buildkite/scripts/steps/cloud/purge.js @@ -26,7 +26,7 @@ for (const deployment of prDeployments) { const lastCommit = pullRequest.commits.slice(-1)[0]; const lastCommitTimestamp = new Date(lastCommit.committedDate).getTime() / 1000; - if (pullRequest.state !== 'open') { + if (pullRequest.state !== 'OPEN') { console.log(`Pull Request #${prNumber} is no longer open, will delete associated deployment`); deploymentsToPurge.push(deployment); } else if (!pullRequest.labels.filter((label) => label.name === 'ci:deploy-cloud')) { diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3f36f4b67e56b..a8619643d1b2e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -138,13 +138,11 @@ # Uptime /x-pack/plugins/uptime @elastic/uptime /x-pack/plugins/ux @elastic/uptime -/x-pack/plugins/observability/public/components/shared/exploratory_view @elastic/uptime /x-pack/test/functional_with_es_ssl/apps/uptime @elastic/uptime /x-pack/test/functional/apps/uptime @elastic/uptime /x-pack/test/functional/es_archives/uptime @elastic/uptime /x-pack/test/functional/services/uptime @elastic/uptime /x-pack/test/api_integration/apis/uptime @elastic/uptime -/x-pack/plugins/observability/public/components/shared/exploratory_view @elastic/uptime # Client Side Monitoring / Uptime (lives in APM directories but owned by Uptime) /x-pack/plugins/apm/public/application/uxApp.tsx @elastic/uptime diff --git a/.github/ISSUE_TEMPLATE/APM.yml b/.github/ISSUE_TEMPLATE/APM.yml deleted file mode 100644 index cbcabdee25718..0000000000000 --- a/.github/ISSUE_TEMPLATE/APM.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: APM Issue -description: Issues related to the curated APM UI in Kibana -labels: Team:apm -title: "[APM] " -body: - - type: markdown - attributes: - value: | - Thank you for our interest in Elastic APM. This issue tracker is meant for reporting bugs and problems with APM UI. For questions around how to use or setup APM, please refer to our [Discuss Forum](https://discuss.elastic.co/) - - type: input - attributes: - label: Kibana version - validations: - required: true - - type: input - attributes: - label: APM Server version (if applicable) - validations: - required: false - - type: input - attributes: - label: Elasticsearch version (if applicable) - validations: - required: false - - type: textarea - attributes: - label: Steps to Reproduce - description: Steps to reproduce the behavior. - validations: - required: false - - type: textarea - attributes: - label: Expected Behavior - description: A concise description of what you expected to happen. - validations: - required: false - - type: textarea - attributes: - label: Actual Behavior - description: A concise description of what you're experiencing. - validations: - required: false - - diff --git a/.github/workflows/add-to-fleet-project.yml b/.github/workflows/add-to-fleet-project.yml index fc5676887f3ae..59b3513c85284 100644 --- a/.github/workflows/add-to-fleet-project.yml +++ b/.github/workflows/add-to-fleet-project.yml @@ -10,7 +10,9 @@ jobs: contains(github.event.issue.labels.*.name, 'Team:Fleet') && ( contains(github.event.issue.labels.*.name, 'technical debt') || contains(github.event.issue.labels.*.name, 'bug') || - contains(github.event.issue.labels.*.name, 'performance') + contains(github.event.issue.labels.*.name, 'performance') || + contains(github.event.issue.labels.*.name, 'failed-test') || + contains(github.event.issue.labels.*.name, 'chore') ) steps: - uses: octokit/graphql-action@v2.x @@ -28,5 +30,7 @@ jobs: projectid: ${{ env.PROJECT_ID }} contentid: ${{ github.event.issue.node_id }} env: + # https://github.com/orgs/elastic/projects/763 PROJECT_ID: "PN_kwDOAGc3Zs4AAsH6" + # Token with `write:org` access GITHUB_TOKEN: ${{ secrets.FLEET_TECH_KIBANA_USER_TOKEN }} diff --git a/.github/workflows/label-qa-fixed-in.yml b/.github/workflows/label-qa-fixed-in.yml new file mode 100644 index 0000000000000..e1dafa061f623 --- /dev/null +++ b/.github/workflows/label-qa-fixed-in.yml @@ -0,0 +1,78 @@ +name: Add QA labels to Fleet issues +on: + pull_request: + types: + - closed + +jobs: + fetch_issues_to_label: + runs-on: ubuntu-latest + # Only run on PRs that were merged for the Fleet team + if: | + github.event.pull_request.merged_at && + contains(github.event.pull_request.labels.*.name, 'Team:Fleet') + outputs: + matrix: ${{ steps.issues_to_label.outputs.value }} + label_ids: ${{ steps.label_ids.outputs.value }} + steps: + - uses: octokit/graphql-action@v2.x + id: closing_issues + with: + query: | + query closingIssueNumbersQuery($prnumber: Int!) { + repository(owner: "elastic", name: "kibana") { + pullRequest(number: $prnumber) { + closingIssuesReferences(first: 10) { + nodes { + id + labels(first: 20) { + nodes { + id + name + } + } + } + } + } + } + } + prnumber: ${{ github.event.number }} + token: ${{ secrets.GITHUB_TOKEN }} + - uses: sergeysova/jq-action@v2 + id: issues_to_label + with: + # Map to the issues' node id + cmd: echo $CLOSING_ISSUES | jq -c '.repository.pullRequest.closingIssuesReferences.nodes | map(.id)' + multiline: true + env: + CLOSING_ISSUES: ${{ steps.closing_issues.outputs.data }} + - uses: sergeysova/jq-action@v2 + id: label_ids + with: + # Get list of version labels on pull request and map to label's node id, append 'QA:Ready For Testing' id ("MDU6TGFiZWwyNTQ1NjcwOTI4") + cmd: echo $PR_LABELS | jq -c 'map(select(.name | test("v[0-9]+\\.[0-9]+\\.[0-9]+")) | .node_id) + ["MDU6TGFiZWwyNTQ1NjcwOTI4"]' + multiline: true + env: + PR_LABELS: ${{ toJSON(github.event.pull_request.labels) }} + + label_issues: + needs: fetch_issues_to_label + runs-on: ubuntu-latest + # For each issue closed by the PR run this job + strategy: + matrix: + issueNodeId: ${{ fromJSON(needs.fetch_issues_to_label.outputs.matrix) }} + name: Label issue ${{ matrix.issueNodeId }} + steps: + - uses: octokit/graphql-action@v2.x + id: add_labels_to_closed_issue + with: + query: | + mutation add_label($issueid:String!, $labelids:[String!]!) { + addLabelsToLabelable(input: {labelableId: $issueid, labelIds: $labelids}) { + clientMutationId + } + } + issueid: ${{ matrix.issueNodeId }} + labelids: ${{ needs.fetch_issues_to_label.outputs.label_ids }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/dev_docs/key_concepts/building_blocks.mdx b/dev_docs/key_concepts/building_blocks.mdx index 6536019f668cf..61e3a711775c3 100644 --- a/dev_docs/key_concepts/building_blocks.mdx +++ b/dev_docs/key_concepts/building_blocks.mdx @@ -122,6 +122,12 @@ sharing and space isolation, and tags. **Github labels**: `Team:Core`, `Feature:Saved Objects` +## Advanced Settings + + + - + - + - + +`uiSettings` are registered synchronously during `core`'s setup lifecycle phase. This means that once you add a new advanced setting, you cannot change or remove it without . + +### Configuration with Advanced Settings UI + +The `uiSettings` service is the programmatic interface to Kibana's Advanced Settings UI. Kibana plugins use the service to extend Kibana UI Settings Management with custom settings for a plugin. + +Configuration through the Advanced Settings UI is restricted to users authorised to access the Advanced Settings page. Users who don't have permissions to change these values default to using the csettings configuration defined for the space that they are in. The `config` saved object can be shared between spaces. + +### Configuration with UI settings overrides + +When a setting is configured as an override in `kibana.yml`, it overrides any other value store in the `config` saved object. The override applies to Kibana as a whole for all spaces and users, and the option is disabled on the Advanced Settings page. We refer to these as "global" overrides. + +Note: If an override is misconfigured, it fails config validation and prevents Kibana from starting up. Validation is, however, limited to value _type_ and not to _key_ (name). For example, when a plugin registers the `my_plugin_foo: 42` setting , then declares the following override, the config validation fails: + +```kibana.yml +uiSettings.overrides: + my_plugin_foo: "42" +``` +The following override results in a successful config validation: + +```kibana.yml +uiSettings.overrides: + my_pluginFoo: 42 +``` + +### Client side usage + +On the client, the `uiSettings` service is accessible directly from `core` and the client provides plugins access to the `config` entries stored in Elasticsearch. + + + Refer to [the client-side uiSettings service API docs](https://github.com/elastic/kibana/blob/main/docs/development/core/server/kibana-plugin-core-public.iuisettingsclient.md) + + +The following is a basic example for using the `uiSettings` service: + +**src/plugins/charts/public/plugin.ts** +```ts +import { Plugin, CoreSetup } from 'kibana/public'; +import { ExpressionsSetup } from '../../expressions/public'; +import { palette, systemPalette } from '../common'; + +import { ThemeService, LegacyColorsService } from './services'; +import { PaletteService } from './services/palettes/service'; +import { ActiveCursor } from './services/active_cursor'; + +export type Theme = Omit; +export type Color = Omit; + +interface SetupDependencies { + expressions: ExpressionsSetup; +} + +/** @public */ +export interface ChartsPluginSetup { + legacyColors: Color; + theme: Theme; + palettes: ReturnType; +} + +/** @public */ +export type ChartsPluginStart = ChartsPluginSetup & { + activeCursor: ActiveCursor; +}; + +/** @public */ +export class ChartsPlugin implements Plugin { + private readonly themeService = new ThemeService(); + private readonly legacyColorsService = new LegacyColorsService(); + private readonly paletteService = new PaletteService(); + private readonly activeCursor = new ActiveCursor(); + + private palettes: undefined | ReturnType; + + public setup(core: CoreSetup, dependencies: SetupDependencies): ChartsPluginSetup { + dependencies.expressions.registerFunction(palette); + dependencies.expressions.registerFunction(systemPalette); + this.themeService.init(core.uiSettings); + this.legacyColorsService.init(core.uiSettings); + this.palettes = this.paletteService.setup(this.legacyColorsService); + + this.activeCursor.setup(); + + return { + legacyColors: this.legacyColorsService, + theme: this.themeService, + palettes: this.palettes, + }; + } + + public start(): ChartsPluginStart { + return { + legacyColors: this.legacyColorsService, + theme: this.themeService, + palettes: this.palettes!, + activeCursor: this.activeCursor, + }; + } +} + +``` + +### Server side usage + +On the server side, `uiSettings` are accessible directly from `core`. The following example shows how to register a new setting with the minimum required schema parameter against which validations are performed on read and write. +The example also shows how plugins can leverage the optional deprecation parameter on registration for handling deprecation notices and renames. The deprecation warnings are rendered in the Advanced Settings UI and should also be added to the Configure Kibana guide. + + + Refer to [the server-side uiSettings service API docs](https://github.com/elastic/kibana/blob/main/docs/development/core/server/kibana-plugin-core-server.iuisettingsclient.md) + + +**src/plugins/charts/server/plugin.ts** + +```ts +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; +import { CoreSetup, Plugin } from 'kibana/server'; +import { COLOR_MAPPING_SETTING, LEGACY_TIME_AXIS, palette, systemPalette } from '../common'; +import { ExpressionsServerSetup } from '../../expressions/server'; + +interface SetupDependencies { + expressions: ExpressionsServerSetup; +} + +export class ChartsServerPlugin implements Plugin { + public setup(core: CoreSetup, dependencies: SetupDependencies) { + dependencies.expressions.registerFunction(palette); + dependencies.expressions.registerFunction(systemPalette); + core.uiSettings.register({ + [COLOR_MAPPING_SETTING]: { + name: i18n.translate('charts.advancedSettings.visualization.colorMappingTitle', { + defaultMessage: 'Color mapping', + }), + value: JSON.stringify({ + Count: '#00A69B', + }), + type: 'json', + description: i18n.translate('charts.advancedSettings.visualization.colorMappingText', { + defaultMessage: + 'Maps values to specific colors in charts using the Compatibility palette.', + }), + deprecation: { + message: i18n.translate( + 'charts.advancedSettings.visualization.colorMappingTextDeprecation', + { + defaultMessage: + 'This setting is deprecated and will not be supported in a future version.', + } + ), + docLinksKey: 'visualizationSettings', + }, + category: ['visualization'], + schema: schema.string(), + }, + ... + }); + + return {}; + } + + public start() { + return {}; + } + + public stop() {} +} +``` +For optimal Kibana performance, `uiSettings` are cached. Any changes that require a cache refresh should use the `requiresPageReload` parameter on registration. + +For example, changing the time filter refresh interval triggers a prompt in the UI that the page needs to be refreshed to save the new value: + +**src/plugins/data/server/ui_settings.ts** + +```ts +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; +import type { DocLinksServiceSetup, UiSettingsParams } from 'kibana/server'; +import { DEFAULT_QUERY_LANGUAGE, UI_SETTINGS } from '../common'; + +export function getUiSettings( + docLinks: DocLinksServiceSetup +): Record> { + return { + ... + [UI_SETTINGS.TIMEPICKER_REFRESH_INTERVAL_DEFAULTS]: { + name: i18n.translate('data.advancedSettings.timepicker.refreshIntervalDefaultsTitle', { + defaultMessage: 'Time filter refresh interval', + }), + value: `{ + "pause": false, + "value": 0 + }`, + type: 'json', + description: i18n.translate('data.advancedSettings.timepicker.refreshIntervalDefaultsText', { + defaultMessage: `The timefilter's default refresh interval. The "value" needs to be specified in milliseconds.`, + }), + requiresPageReload: true, + schema: schema.object({ + pause: schema.boolean(), + value: schema.number(), + }), + }, + ... + } +} +``` + +### Registering Migrations +To change or remove a `uiSetting`, you must migrate the whole `config` Saved Object. `uiSettings` migrations are declared directly in the service. + +For example, in 7.9.0, `siem` as renamed to `securitySolution`, and in 8.0.0, `theme:version` was removed: + +**src/core/server/ui_settings/saved_objects/migrations.ts** + +```ts +import { SavedObjectUnsanitizedDoc, SavedObjectSanitizedDoc } from 'kibana/server'; + +export const migrations = { + '7.9.0': (doc: SavedObjectUnsanitizedDoc): SavedObjectSanitizedDoc => ({ + ...doc, + ...(doc.attributes && { + attributes: Object.keys(doc.attributes).reduce( + (acc, key) => + key.startsWith('siem:') + ? { + ...acc, + [key.replace('siem', 'securitySolution')]: doc.attributes[key], + } + : { + ...acc, + [key]: doc.attributes[key], + }, + {} + ), + }), + references: doc.references || [], + }), + '7.12.0': (doc: SavedObjectUnsanitizedDoc): SavedObjectSanitizedDoc => ({...}), + '7.13.0': (doc: SavedObjectUnsanitizedDoc): SavedObjectSanitizedDoc => ({...}), + '8.0.0': (doc: SavedObjectUnsanitizedDoc): SavedObjectSanitizedDoc => ({ + ...doc, + ...(doc.attributes && { + attributes: Object.keys(doc.attributes).reduce( + (acc, key) => + [ + // owner: Team:Geo [1] + 'visualization:regionmap:showWarnings', + ... + // owner: Team:Core + ... + 'theme:version', + // owner: Team:AppServices + ... + ].includes(key) + ? { + ...acc, + } + : { + ...acc, + [key]: doc.attributes[key], + }, + {} + ), + }), + references: doc.references || [], + }), + '8.1.0': (doc: SavedObjectUnsanitizedDoc): SavedObjectSanitizedDoc => ({...}), +}; +``` +[1] Since all `uiSettings` migrations are added to the same migration function, while not required, grouping settings by team is good practice. diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 446c305c03b95..3101b649b09a5 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -10,6 +10,7 @@ Review important information about the {kib} 8.0.0 releases. +* <> * <> * <> * <> @@ -17,6 +18,113 @@ Review important information about the {kib} 8.0.0 releases. * <> -- +[[release-notes-8.0.0]] +== {kib} 8.0.0 + +coming::[8.0.0] + +Review the {kib} 8.0.0 changes, then use the {kibana-ref-all}/7.17/upgrade-assistant.html[Upgrade Assistant] to complete the upgrade. + +[float] +[[breaking-changes-8.0.0]] +=== Breaking change + +Breaking changes can prevent your application from optimal operation and performance. +Before you upgrade to 8.0.0, review the breaking change, then mitigate the impact to your application. + +// tag::notable-breaking-changes[] + +[discrete] +[[breaking-123754]] +.Removes the `console.ssl` setting +[%collapsible] +==== +*Details* + +The `console.ssl` setting has been removed. For more information, refer to {kibana-pull}123754[#123754]. + +*Impact* + +Before you upgrade to 8.0.0, remove `console.ssl` from kibana.yml. +==== + +// end::notable-breaking-changes[] + + +To review the breaking changes in previous versions, refer to the following: + +<> | <> | <> | <> | +<> + +[float] +[[deprecations-8.0.0]] +=== Deprecation + +The following functionality is deprecated in 8.0.0, and will be removed in 9.0.0. +Deprecated functionality does not have an immediate impact on your application, but we strongly recommend +you make the necessary updates after you upgrade to 8.0.0. + +[discrete] +[[deprecation-123229]] +.Removes support for `monitoring.cluster_alerts.allowedSpaces` +[%collapsible] +==== +*Details* + +The `monitoring.cluster_alerts.allowedSpaces` setting, which {kib} uses to create Stack Monitoring alerts, has been removed. For more information, refer to {kibana-pull}123229[#123229]. + +*Impact* + +Before you upgrade to 8.0.0, remove `monitoring.cluster_alerts.allowedSpaces` from kibana.yml. +==== + +To review the deprecations in previous versions, refer to the following: + +<> | <> + +[float] +[[features-8.0.0]] +=== Features +For information about the features introduced in 8.0.0, refer to <>. + +Elastic Security:: +For the Elastic Security 8.0.0 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. + +To review the features in previous versions, refer to the following: + +<> | <> | <> | <> + +[[enhancements-and-bug-fixes-v8.0.0]] +=== Enhancements and bug fixes + +For detailed information about the 8.0.0 release, review the enhancements and bug fixes. + +[float] +[[enhancement-v8.0.0]] +==== Enhancements +Dashboard:: +Clone ReferenceOrValueEmbeddables by value {kibana-pull}122199[#122199] + +Elastic Security:: +For the Elastic Security 8.0.0 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. + +[float] +[[fixes-v8.0.0]] +==== Bug Fixes +APM:: +Restrict aggregated transaction metrics search to date range {kibana-pull}123445[#123445] + +Elastic Security:: +For the Elastic Security 8.0.0 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. + +Fleet:: +Allow empty strings for required text fields in package policies {kibana-pull}123610[#123610] + +Maps:: +Fixes Label border color is not removed from legend when disabled {kibana-pull}122705[#122705] + +Monitoring:: +Ensure logstash getNodes always contains a uuid {kibana-pull}124201[#124201] + +Security:: +Long-running requests no longer cause sporadic logouts in certain cases, even when user sessions are active {kibana-pull}122155[#122155] + [[release-notes-8.0.0-rc2]] == {kib} 8.0.0-rc2 @@ -29,8 +137,6 @@ For information about the {kib} 8.0.0-rc2 release, review the following informat Breaking changes can prevent your application from optimal operation and performance. Before you upgrade, review the breaking change, then mitigate the impact to your application. -// tag::notable-breaking-changes[] - [discrete] [[breaking-122722]] .Removes the ability to use `elasticsearch.username: elastic` in production @@ -42,8 +148,6 @@ In production, you are no longer able to use the `elastic` superuser to authenti *Impact* + When you configure `elasticsearch.username: elastic`, {kib} fails. ==== - -// end::notable-breaking-changes[] To review the breaking changes in previous versions, refer to the following: @@ -1304,7 +1408,7 @@ Use the `xpack.monitoring.clusterAlertsEmail` in kibana.yml. ==== [float] -[[enhancements-and-bug-fixes-v8.0.0]] +[[enhancements-and-bug-fixes-v8.0.0-alpha1]] === Bug fix The 8.0.0-alpha1 release includes the following bug fix. diff --git a/docs/developer/architecture/development-visualize-index.asciidoc b/docs/developer/architecture/development-visualize-index.asciidoc index d41ee32c1fb27..b941cdedf9df9 100644 --- a/docs/developer/architecture/development-visualize-index.asciidoc +++ b/docs/developer/architecture/development-visualize-index.asciidoc @@ -19,7 +19,7 @@ We would recommend waiting until later in `7.x` to upgrade your plugins if possi If you would like to keep up with progress on the visualizations plugin in the meantime, here are a few resources: -* The <> documentation, where we try to capture any changes to the APIs as they occur across minors. +* The <> documentation, where we try to capture any changes to the APIs as they occur across minors. * link:https://github.com/elastic/kibana/issues/44121[Meta issue] which is tracking the move of the plugin to the new {kib} platform * Our link:https://www.elastic.co/blog/join-our-elastic-stack-workspace-on-slack[Elastic Stack workspace on Slack]. * The {kib-repo}blob/{branch}/src/plugins/visualizations[source code], which will continue to be diff --git a/docs/development/core/public/kibana-plugin-core-public.iexternalurl.isinternalurl.md b/docs/development/core/public/kibana-plugin-core-public.iexternalurl.isinternalurl.md new file mode 100644 index 0000000000000..396e5586f1fed --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.iexternalurl.isinternalurl.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [IExternalUrl](./kibana-plugin-core-public.iexternalurl.md) > [isInternalUrl](./kibana-plugin-core-public.iexternalurl.isinternalurl.md) + +## IExternalUrl.isInternalUrl() method + +Determines if the provided URL is an internal url. + +Signature: + +```typescript +isInternalUrl(relativeOrAbsoluteUrl: string): boolean; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| relativeOrAbsoluteUrl | string | | + +Returns: + +boolean + diff --git a/docs/development/core/public/kibana-plugin-core-public.iexternalurl.md b/docs/development/core/public/kibana-plugin-core-public.iexternalurl.md index 5a598281c7be7..d0d4e6a3a4464 100644 --- a/docs/development/core/public/kibana-plugin-core-public.iexternalurl.md +++ b/docs/development/core/public/kibana-plugin-core-public.iexternalurl.md @@ -16,5 +16,6 @@ export interface IExternalUrl | Method | Description | | --- | --- | +| [isInternalUrl(relativeOrAbsoluteUrl)](./kibana-plugin-core-public.iexternalurl.isinternalurl.md) | Determines if the provided URL is an internal url. | | [validateUrl(relativeOrAbsoluteUrl)](./kibana-plugin-core-public.iexternalurl.validateurl.md) | Determines if the provided URL is a valid location to send users. Validation is based on the configured allow list in kibana.yml.If the URL is valid, then a URL will be returned. Otherwise, this will return null. | diff --git a/docs/index.asciidoc b/docs/index.asciidoc index ec1a99fa5bffc..668a6edcad3db 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -24,8 +24,6 @@ include::user/index.asciidoc[] include::accessibility.asciidoc[] -include::migration.asciidoc[] - include::CHANGELOG.asciidoc[] include::developer/index.asciidoc[] diff --git a/docs/management/connectors/pre-configured-connectors.asciidoc b/docs/management/connectors/pre-configured-connectors.asciidoc index 4d304cdd6c5a2..aaef1b673d0b6 100644 --- a/docs/management/connectors/pre-configured-connectors.asciidoc +++ b/docs/management/connectors/pre-configured-connectors.asciidoc @@ -11,6 +11,8 @@ action are predefined, including the connector name and ID. - Appear in all spaces because they are not saved objects. - Cannot be edited or deleted. +NOTE: Preconfigured connectors cannot be used with cases. + [float] [[preconfigured-connector-example]] ==== Preconfigured connectors example @@ -70,4 +72,4 @@ image::images/pre-configured-connectors-managing.png[Connectors managing tab wit Clicking a preconfigured connector shows the description, but not the configuration. A message indicates that this is a preconfigured connector. [role="screenshot"] -image::images/pre-configured-connectors-view-screen.png[Pre-configured connector view details] \ No newline at end of file +image::images/pre-configured-connectors-view-screen.png[Pre-configured connector view details] diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index 0ca518c3a8788..6a34076f10988 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -400,3 +400,8 @@ This content has moved. Refer to <>. == Upgrade Assistant This content has moved. Refer to {kibana-ref-all}/7.17/upgrade-assistant.html[Upgrade Assistant]. + +[role="exclude",id="brew"] +== Install {kib} on macOS with Homebrew + +This page has been deleted. Refer to <>. diff --git a/docs/settings/security-settings.asciidoc b/docs/settings/security-settings.asciidoc index 56d08ee24efe1..787efa64f0775 100644 --- a/docs/settings/security-settings.asciidoc +++ b/docs/settings/security-settings.asciidoc @@ -8,10 +8,6 @@ You do not need to configure any additional settings to use the {security-features} in {kib}. They are enabled by default. -[float] -[[general-security-settings]] -==== General security settings - [float] [[authentication-security-settings]] ==== Authentication security settings @@ -46,123 +42,80 @@ xpack.security.authc: <3> Specifies the settings for the SAML authentication provider with a `saml1` name. <4> Specifies the settings for the SAML authentication provider with a `saml2` name. -The valid settings in the `xpack.security.authc.providers` namespace vary depending on the authentication provider type. For more information, refer to <>. - [float] [[authentication-provider-settings]] -===== Valid settings for all authentication providers - -[cols="2*<"] -|=== -| `xpack.security.authc.providers.` -`..enabled` {ess-icon} -| Determines if the authentication provider should be enabled. By default, {kib} enables the provider as soon as you configure any of its properties. - -| `xpack.security.authc.providers.` -`..order` {ess-icon} -| Order of the provider in the authentication chain and on the Login Selector UI. - -| `xpack.security.authc.providers.` -`..description` {ess-icon} -| Custom description of the provider entry displayed on the Login Selector UI. - -| `xpack.security.authc.providers.` -`..hint` {ess-icon} -| Custom hint for the provider entry displayed on the Login Selector UI. - -| `xpack.security.authc.providers.` -`..icon` {ess-icon} -| Custom icon for the provider entry displayed on the Login Selector UI. - -| `xpack.security.authc.providers..` -`.showInSelector` {ess-icon} -| Flag that indicates if the provider should have an entry on the Login Selector UI. Setting this to `false` doesn't remove the provider from the authentication chain. - -2+a| -[TIP] -[NOTE] -============ -You are unable to set this setting to `false` for `basic` and `token` authentication providers. -============ - -| `xpack.security.authc.providers..` -`.accessAgreement.message` {ess-icon} -| Access agreement text in Markdown format. For more information, refer to <>. - -| [[xpack-security-provider-session-idleTimeout]] `xpack.security.authc.providers..` -`.session.idleTimeout` {ess-icon} -| Ensures that user sessions will expire after a period of inactivity. Setting this to `0` will prevent sessions from expiring because of inactivity. By default, this setting is equal to <>. - -2+a| -[TIP] -============ -Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). -============ - -| [[xpack-security-provider-session-lifespan]] `xpack.security.authc.providers..` -`.session.lifespan` {ess-icon} -| Ensures that user sessions will expire after the defined time period. This behavior is also known as an "absolute timeout". If -this is set to `0`, user sessions could stay active indefinitely. By default, this setting is equal to <>. +==== Valid settings for all authentication providers + +The valid settings in the `xpack.security.authc.providers` namespace vary depending on the authentication provider type. For more information, refer to <>. + +xpack.security.authc.providers...enabled {ess-icon}:: +Determines if the authentication provider should be enabled. By default, {kib} enables the provider as soon as you configure any of its properties. + +xpack.security.authc.providers...order {ess-icon}:: +Order of the provider in the authentication chain and on the Login Selector UI. + +xpack.security.authc.providers...description {ess-icon}:: +Custom description of the provider entry displayed on the Login Selector UI. -2+a| -[TIP] -============ -Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). -============ +xpack.security.authc.providers...hint {ess-icon}:: +Custom hint for the provider entry displayed on the Login Selector UI. -|=== +xpack.security.authc.providers...icon {ess-icon}:: +Custom icon for the provider entry displayed on the Login Selector UI. + +xpack.security.authc.providers...showInSelector {ess-icon}:: +Flag that indicates if the provider should have an entry on the Login Selector UI. Setting this to `false` doesn't remove the provider from the authentication chain. ++ +NOTE: You are unable to set this setting to `false` for `basic` and `token` authentication providers. + +xpack.security.authc.providers...accessAgreement.message {ess-icon}:: +Access agreement text in Markdown format. For more information, refer to <>. + +[[xpack-security-provider-session-idleTimeout]] xpack.security.authc.providers...session.idleTimeout {ess-icon}:: +Ensures that user sessions will expire after a period of inactivity. Setting this to `0` will prevent sessions from expiring because of inactivity. By default, this setting is equal to <>. ++ +NOTE: Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). + +[[xpack-security-provider-session-lifespan]] xpack.security.authc.providers...session.lifespan {ess-icon}:: +Ensures that user sessions will expire after the defined time period. This behavior is also known as an "absolute timeout". If +this is set to `0`, user sessions could stay active indefinitely. By default, this setting is equal to <>. ++ +NOTE: Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). [float] [[saml-authentication-provider-settings]] -===== SAML authentication provider settings +==== SAML authentication provider settings In addition to <>, you can specify the following settings: -[cols="2*<"] -|=== -| `xpack.security.authc.providers.` -`saml..realm` {ess-icon} -| SAML realm in {es} that provider should use. +xpack.security.authc.providers.saml..realm {ess-icon}:: +SAML realm in {es} that provider should use. -| `xpack.security.authc.providers.` -`saml..useRelayStateDeepLink` {ess-icon} -| Determines if the provider should treat the `RelayState` parameter as a deep link in {kib} during Identity Provider initiated log in. By default, this setting is set to `false`. The link specified in `RelayState` should be a relative, URL-encoded {kib} URL. For example, the `/app/dashboards#/list` link in `RelayState` parameter would look like this: `RelayState=%2Fapp%2Fdashboards%23%2Flist`. - -|=== +xpack.security.authc.providers.saml..useRelayStateDeepLink {ess-icon}:: +Determines if the provider should treat the `RelayState` parameter as a deep link in {kib} during Identity Provider initiated log in. By default, this setting is set to `false`. The link specified in `RelayState` should be a relative, URL-encoded {kib} URL. For example, the `/app/dashboards#/list` link in `RelayState` parameter would look like this: `RelayState=%2Fapp%2Fdashboards%23%2Flist`. [float] [[oidc-authentication-provider-settings]] -===== OpenID Connect authentication provider settings +==== OpenID Connect authentication provider settings In addition to <>, you can specify the following settings: -[cols="2*<"] -|=== -| `xpack.security.authc.providers.` -`oidc..realm` {ess-icon} -| OpenID Connect realm in {es} that the provider should use. - -|=== +xpack.security.authc.providers.oidc..realm {ess-icon}:: +OpenID Connect realm in {es} that the provider should use. [float] [[anonymous-authentication-provider-settings]] -===== Anonymous authentication provider settings +==== Anonymous authentication provider settings In addition to <>, you can specify the following settings: -[NOTE] -============ -You can configure only one anonymous provider per {kib} instance. -============ - -[cols="2*<"] -|=== -| `xpack.security.authc.providers.` -`anonymous..credentials` {ess-icon} -| Credentials that {kib} should use internally to authenticate anonymous requests to {es}. Possible values are: username and password, API key, or the constant `elasticsearch_anonymous_user` if you want to leverage {ref}/anonymous-access.html[{es} anonymous access]. - -2+a| For example: +NOTE: You can configure only one anonymous provider per {kib} instance. +xpack.security.authc.providers.anonymous..credentials {ess-icon}:: +Credentials that {kib} should use internally to authenticate anonymous requests to {es}. Possible values are: username and password, API key, or the constant `elasticsearch_anonymous_user` if you want to leverage {ref}/anonymous-access.html[{es} anonymous access]. ++ +For example: ++ [source,yaml] ---------------------------------------- # Username and password credentials @@ -187,45 +140,35 @@ xpack.security.authc.providers.anonymous.anonymous1: credentials: "elasticsearch_anonymous_user" ---------------------------------------- -|=== - [float] [[http-authentication-settings]] -===== HTTP authentication settings +==== HTTP authentication settings There is a very limited set of cases when you'd want to change these settings. For more information, refer to <>. -[cols="2*<"] -|=== -| `xpack.security.authc.http.enabled` -| Determines if HTTP authentication should be enabled. By default, this setting is set to `true`. - -| `xpack.security.authc.http.autoSchemesEnabled` -| Determines if HTTP authentication schemes used by the enabled authentication providers should be automatically supported during HTTP authentication. By default, this setting is set to `true`. +xpack.security.authc.http.enabled:: +Determines if HTTP authentication should be enabled. By default, this setting is set to `true`. -| `xpack.security.authc.http.schemes[]` -| List of HTTP authentication schemes that {kib} HTTP authentication should support. By default, this setting is set to `['apikey', 'bearer']` to support HTTP authentication with the <> and <> schemes. +xpack.security.authc.http.autoSchemesEnabled:: +Determines if HTTP authentication schemes used by the enabled authentication providers should be automatically supported during HTTP authentication. By default, this setting is set to `true`. -|=== +xpack.security.authc.http.schemes[]:: +List of HTTP authentication schemes that {kib} HTTP authentication should support. By default, this setting is set to `['apikey', 'bearer']` to support HTTP authentication with the <> and <> schemes. [float] [[login-ui-settings]] -===== Login user interface settings +==== Login user interface settings You can configure the following settings in the `kibana.yml` file. -[cols="2*<"] -|=== -| `xpack.security.loginAssistanceMessage` {ess-icon} -| Adds a message to the login UI. Useful for displaying information about maintenance windows, links to corporate sign up pages, and so on. +xpack.security.loginAssistanceMessage {ess-icon}:: +Adds a message to the login UI. Useful for displaying information about maintenance windows, links to corporate sign up pages, and so on. -| `xpack.security.loginHelp` {ess-icon} -| Adds a message accessible at the login UI with additional help information for the login process. +xpack.security.loginHelp {ess-icon}:: +Adds a message accessible at the login UI with additional help information for the login process. -| `xpack.security.authc.selector.enabled` {ess-icon} -| Determines if the login selector UI should be enabled. By default, this setting is set to `true` if more than one authentication provider is configured. - -|=== +xpack.security.authc.selector.enabled {ess-icon}:: +Determines if the login selector UI should be enabled. By default, this setting is set to `true` if more than one authentication provider is configured. [float] [[security-session-and-cookie-settings]] @@ -233,81 +176,49 @@ You can configure the following settings in the `kibana.yml` file. You can configure the following settings in the `kibana.yml` file. -[cols="2*<"] -|=== -| `xpack.security.cookieName` - | Sets the name of the cookie used for the session. The default value is `"sid"`. - -|[[xpack-security-encryptionKey]] `xpack.security.encryptionKey` - | An arbitrary string of 32 characters or more that is used to encrypt session information. Do **not** expose this key to users of {kib}. By - default, a value is automatically generated in memory. If you use that default - behavior, all sessions are invalidated when {kib} restarts. - In addition, high-availability deployments of {kib} will behave unexpectedly - if this setting isn't the same for all instances of {kib}. - -|[[xpack-security-secureCookies]] `xpack.security.secureCookies` - | Sets the `secure` flag of the session cookie. The default value is `false`. It - is automatically set to `true` if <> is set to `true`. Set - this to `true` if SSL is configured outside of {kib} (for example, you are - routing requests through a load balancer or proxy). - -| [[xpack-security-sameSiteCookies]] `xpack.security.sameSiteCookies` {ess-icon} - | Sets the `SameSite` attribute of the session cookie. This allows you to declare whether your cookie should be restricted to a first-party or same-site context. - Valid values are `Strict`, `Lax`, `None`. - This is *not set* by default, which modern browsers will treat as `Lax`. If you use Kibana embedded in an iframe in modern browsers, you might need to set it to `None`. Setting this value to `None` requires cookies to be sent over a secure connection by setting <>: `true`. - -|[[xpack-session-idleTimeout]] `xpack.security.session.idleTimeout` {ess-icon} - | Ensures that user sessions will expire after a period of inactivity. This and <> are both -highly recommended. You can also specify this setting for <>. If this is set to `0`, then sessions will never expire due to inactivity. By default, this value is 8 hours. - -2+a| -[TIP] -============ -Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). -============ - -|[[xpack-session-lifespan]] `xpack.security.session.lifespan` {ess-icon} - | Ensures that user sessions will expire after the defined time period. This behavior is also known as an "absolute timeout". If -this is set to `0`, user sessions could stay active indefinitely. This and <> are both highly -recommended. You can also specify this setting for <>. By default, this value is 30 days. +xpack.security.cookieName:: +Sets the name of the cookie used for the session. The default value is `"sid"`. -2+a| -[TIP] -============ -Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). -============ +[[xpack-security-encryptionKey]] xpack.security.encryptionKey:: +An arbitrary string of 32 characters or more that is used to encrypt session information. Do **not** expose this key to users of {kib}. By default, a value is automatically generated in memory. If you use that default behavior, all sessions are invalidated when {kib} restarts. In addition, high-availability deployments of {kib} will behave unexpectedly if this setting isn't the same for all instances of {kib}. -| `xpack.security.session.cleanupInterval` {ess-icon} -| Sets the interval at which {kib} tries to remove expired and invalid sessions from the session index. By default, this value is 1 hour. The minimum value is 10 seconds. +[[xpack-security-secureCookies]] xpack.security.secureCookies:: +Sets the `secure` flag of the session cookie. The default value is `false`. It +is automatically set to `true` if <> is set to `true`. Set this to `true` if SSL is configured outside of {kib} (for example, you are routing requests through a load balancer or proxy). -2+a| -[TIP] -============ -Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). -============ +[[xpack-security-sameSiteCookies]] xpack.security.sameSiteCookies {ess-icon}:: +Sets the `SameSite` attribute of the session cookie. This allows you to declare whether your cookie should be restricted to a first-party or same-site context. +Valid values are `Strict`, `Lax`, `None`. +This is *not set* by default, which modern browsers will treat as `Lax`. If you use Kibana embedded in an iframe in modern browsers, you might need to set it to `None`. Setting this value to `None` requires cookies to be sent over a secure connection by setting <>: `true`. -|=== +[[xpack-session-idleTimeout]] xpack.security.session.idleTimeout {ess-icon}:: +Ensures that user sessions will expire after a period of inactivity. This and <> are both highly recommended. You can also specify this setting for <>. If this is set to `0`, then sessions will never expire due to inactivity. By default, this value is 8 hours. ++ +NOTE: Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). + +[[xpack-session-lifespan]] xpack.security.session.lifespan {ess-icon}:: +Ensures that user sessions will expire after the defined time period. This behavior is also known as an "absolute timeout". If this is set to `0`, user sessions could stay active indefinitely. This and <> are both highly +recommended. You can also specify this setting for <>. By default, this value is 30 days. ++ +TIP: Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). + +xpack.security.session.cleanupInterval {ess-icon}:: +Sets the interval at which {kib} tries to remove expired and invalid sessions from the session index. By default, this value is 1 hour. The minimum value is 10 seconds. ++ +TIP: Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). [[security-encrypted-saved-objects-settings]] ==== Encrypted saved objects settings These settings control the encryption of saved objects with sensitive data. For more details, refer to <>. -[IMPORTANT] -============ -In high-availability deployments, make sure you use the same encryption and decryption keys for all instances of {kib}. Although the keys can be specified in clear text in `kibana.yml`, it's recommended to store them securely in the <>. -============ +IMPORTANT: In high-availability deployments, make sure you use the same encryption and decryption keys for all instances of {kib}. Although the keys can be specified in clear text in `kibana.yml`, it's recommended to store them securely in the <>. -[cols="2*<"] -|=== -| [[xpack-encryptedSavedObjects-encryptionKey]] `xpack.encryptedSavedObjects.` -`encryptionKey` -| An arbitrary string of at least 32 characters that is used to encrypt sensitive properties of saved objects before they're stored in {es}. If not set, {kib} will generate a random key on startup, but certain features won't be available until you set the encryption key explicitly. +[[xpack-encryptedSavedObjects-encryptionKey]] xpack.encryptedSavedObjects.encryptionKey:: +An arbitrary string of at least 32 characters that is used to encrypt sensitive properties of saved objects before they're stored in {es}. If not set, {kib} will generate a random key on startup, but certain features won't be available until you set the encryption key explicitly. -| [[xpack-encryptedSavedObjects-keyRotation-decryptionOnlyKeys]] `xpack.encryptedSavedObjects.` -`keyRotation.decryptionOnlyKeys` -| An optional list of previously used encryption keys. Like <>, these must be at least 32 characters in length. {kib} doesn't use these keys for encryption, but may still require them to decrypt some existing saved objects. Use this setting if you wish to change your encryption key, but don't want to lose access to saved objects that were previously encrypted with a different key. -|=== +[[xpack-encryptedSavedObjects-keyRotation-decryptionOnlyKeys]] xpack.encryptedSavedObjects.keyRotation.decryptionOnlyKeys:: +An optional list of previously used encryption keys. Like <>, these must be at least 32 characters in length. {kib} doesn't use these keys for encryption, but may still require them to decrypt some existing saved objects. Use this setting if you wish to change your encryption key, but don't want to lose access to saved objects that were previously encrypted with a different key. [float] [[audit-logging-settings]] @@ -315,18 +226,17 @@ In high-availability deployments, make sure you use the same encryption and decr You can enable audit logging to support compliance, accountability, and security. When enabled, {kib} will capture: -- Who performed an action -- What action was performed -- When the action occurred +* Who performed an action +* What action was performed +* When the action occurred For more details and a reference of audit events, refer to <>. -[cols="2*<"] -|====== -| `xpack.security.audit.enabled` {ess-icon} -| Set to `true` to enable audit logging`. *Default:* `false` - -2+a| For example: +xpack.security.audit.enabled {ess-icon}:: +Set to `true` to enable audit logging`. *Default:* `false` ++ +For example: ++ [source,yaml] ---------------------------------------- xpack.security.audit.enabled: true @@ -346,128 +256,103 @@ xpack.security.audit.appender: <1> <2> Rotates log files every 24 hours. <3> Keeps maximum of 10 log files before deleting older ones. -| `xpack.security.audit.appender` -| Optional. Specifies where audit logs should be written to and how they should be formatted. If no appender is specified, a default appender will be used (see above). - -| `xpack.security.audit.appender.type` -| Required. Specifies where audit logs should be written to. Allowed values are `console`, `file`, or `rolling-file`. +xpack.security.audit.appender:: +Optional. Specifies where audit logs should be written to and how they should be formatted. If no appender is specified, a default appender will be used (see above). +xpack.security.audit.appender.type:: +Required. Specifies where audit logs should be written to. Allowed values are `console`, `file`, or `rolling-file`. ++ Refer to <> and <> for appender specific settings. -| `xpack.security.audit.appender.layout.type` -| Required. Specifies how audit logs should be formatted. Allowed values are `json` or `pattern`. - +xpack.security.audit.appender.layout.type:: +Required. Specifies how audit logs should be formatted. Allowed values are `json` or `pattern`. ++ Refer to <> for layout specific settings. - -2+a| -[TIP] -============ -We recommend using `json` format to allow ingesting {kib} audit logs into {es} using Filebeat. -============ - -|====== ++ +TIP: We recommend using `json` format to allow ingesting {kib} audit logs into {es} using Filebeat. [float] [[audit-logging-file-appender,file appender]] -===== File appender +==== File appender The `file` appender writes to a file and can be configured using the following settings: -[cols="2*<"] -|====== -| `xpack.security.audit.appender.fileName` -| Required. Full file path the log file should be written to. -|====== +xpack.security.audit.appender.fileName:: +Required. Full file path the log file should be written to. [float] [[audit-logging-rolling-file-appender, rolling file appender]] -===== Rolling file appender +==== Rolling file appender The `rolling-file` appender writes to a file and rotates it using a rolling strategy, when a particular policy is triggered: -[cols="2*<"] -|====== -| `xpack.security.audit.appender.fileName` -| Required. Full file path the log file should be written to. - -| `xpack.security.audit.appender.policy.type` -| Specifies when a rollover should occur. Allowed values are `size-limit` and `time-interval`. *Default:* `time-interval`. +xpack.security.audit.appender.fileName:: +Required. Full file path the log file should be written to. +xpack.security.audit.appender.policy.type:: +Specifies when a rollover should occur. Allowed values are `size-limit` and `time-interval`. *Default:* `time-interval`. ++ Refer to <> and <> for policy specific settings. -| `xpack.security.audit.appender.strategy.type` -| Specifies how the rollover should occur. Only allowed value is currently `numeric`. *Default:* `numeric` +xpack.security.audit.appender.strategy.type:: +Specifies how the rollover should occur. Only allowed value is currently `numeric`. *Default:* `numeric` ++ Refer to <> for strategy specific settings. -|====== [float] [[audit-logging-size-limit-policy, size limit policy]] -===== Size limit triggering policy +==== Size limit triggering policy The `size-limit` triggering policy will rotate the file when it reaches a certain size: -[cols="2*<"] -|====== -| `xpack.security.audit.appender.policy.size` -| Maximum size the log file should reach before a rollover should be performed. *Default:* `100mb` -|====== +xpack.security.audit.appender.policy.size:: +Maximum size the log file should reach before a rollover should be performed. *Default:* `100mb` [float] [[audit-logging-time-interval-policy, time interval policy]] -===== Time interval triggering policy +==== Time interval triggering policy The `time-interval` triggering policy will rotate the file every given interval of time: -[cols="2*<"] -|====== -| `xpack.security.audit.appender.policy.interval` -| How often a rollover should occur. *Default:* `24h` +xpack.security.audit.appender.policy.interval:: +How often a rollover should occur. *Default:* `24h` -| `xpack.security.audit.appender.policy.modulate` -| Whether the interval should be adjusted to cause the next rollover to occur on the interval boundary. *Default:* `true` -|====== +xpack.security.audit.appender.policy.modulate:: +Whether the interval should be adjusted to cause the next rollover to occur on the interval boundary. *Default:* `true` [float] [[audit-logging-numeric-strategy, numeric strategy]] -===== Numeric rolling strategy +==== Numeric rolling strategy The `numeric` rolling strategy will suffix the log file with a given pattern when rolling over, and will retain a fixed number of rolled files: -[cols="2*<"] -|====== -| `xpack.security.audit.appender.strategy.pattern` -| Suffix to append to the file name when rolling over. Must include `%i`. *Default:* `-%i` +xpack.security.audit.appender.strategy.pattern:: +Suffix to append to the file name when rolling over. Must include `%i`. *Default:* `-%i` -| `xpack.security.audit.appender.strategy.max` -| Maximum number of files to keep. Once this number is reached, oldest files will be deleted. *Default:* `7` -|====== +xpack.security.audit.appender.strategy.max:: +Maximum number of files to keep. Once this number is reached, oldest files will be deleted. *Default:* `7` [float] [[audit-logging-pattern-layout, pattern layout]] -===== Pattern layout +==== Pattern layout The `pattern` layout outputs a string, formatted using a pattern with special placeholders, which will be replaced with data from the actual log message: -[cols="2*<"] -|====== -| `xpack.security.audit.appender.layout.pattern` -| Optional. Specifies how the log line should be formatted. *Default:* `[%date][%level][%logger]%meta %message` +xpack.security.audit.appender.layout.pattern:: +Optional. Specifies how the log line should be formatted. *Default:* `[%date][%level][%logger]%meta %message` -| `xpack.security.audit.appender.layout.highlight` -| Optional. Set to `true` to enable highlighting log messages with colors. -|====== +xpack.security.audit.appender.layout.highlight:: +Optional. Set to `true` to enable highlighting log messages with colors. [float] [[audit-logging-ignore-filters]] -===== Ignore filters - -[cols="2*<"] -|====== -| `xpack.security.audit.ignore_filters[]` {ess-icon} -| List of filters that determine which events should be excluded from the audit log. An event will get filtered out if at least one of the provided filters matches. - -2+a| For example: +==== Ignore filters +xpack.security.audit.ignore_filters[] {ess-icon}:: +List of filters that determine which events should be excluded from the audit log. An event will get filtered out if at least one of the provided filters matches. ++ +For example: ++ [source,yaml] ---------------------------------------- xpack.security.audit.ignore_filters: @@ -478,15 +363,14 @@ xpack.security.audit.ignore_filters: <1> Filters out HTTP request events <2> Filters out any data write events -| `xpack.security.audit.ignore_filters[].actions[]` {ess-icon} -| List of values matched against the `event.action` field of an audit event. Refer to <> for a list of available events. +xpack.security.audit.ignore_filters[].actions[] {ess-icon}:: +List of values matched against the `event.action` field of an audit event. Refer to <> for a list of available events. -| `xpack.security.audit.ignore_filters[].categories[]` {ess-icon} -| List of values matched against the `event.category` field of an audit event. Refer to https://www.elastic.co/guide/en/ecs/1.5/ecs-allowed-values-event-category.html[ECS categorization field] for allowed values. +xpack.security.audit.ignore_filters[].categories[] {ess-icon}:: +List of values matched against the `event.category` field of an audit event. Refer to https://www.elastic.co/guide/en/ecs/1.5/ecs-allowed-values-event-category.html[ECS categorization field] for allowed values. -| `xpack.security.audit.ignore_filters[].types[]` {ess-icon} -| List of values matched against the `event.type` field of an audit event. Refer to https://www.elastic.co/guide/en/ecs/1.5/ecs-allowed-values-event-type.html[ECS type field] for allowed values. +xpack.security.audit.ignore_filters[].types[] {ess-icon}:: +List of values matched against the `event.type` field of an audit event. Refer to https://www.elastic.co/guide/en/ecs/1.5/ecs-allowed-values-event-type.html[ECS type field] for allowed values. -| `xpack.security.audit.ignore_filters[].outcomes[]` {ess-icon} -| List of values matched against the `event.outcome` field of an audit event. Refer to https://www.elastic.co/guide/en/ecs/1.5/ecs-allowed-values-event-outcome.html[ECS outcome field] for allowed values. -|====== +xpack.security.audit.ignore_filters[].outcomes[] {ess-icon}:: +List of values matched against the `event.outcome` field of an audit event. Refer to https://www.elastic.co/guide/en/ecs/1.5/ecs-allowed-values-event-outcome.html[ECS outcome field] for allowed values. \ No newline at end of file diff --git a/docs/setup/install.asciidoc b/docs/setup/install.asciidoc index 8b64bdf5fe2a2..ac49946d877bc 100644 --- a/docs/setup/install.asciidoc +++ b/docs/setup/install.asciidoc @@ -46,12 +46,6 @@ downloaded from the Elastic Docker Registry. + <> -`brew`:: - -Formulae are available from the Elastic Homebrew tap for installing {kib} on macOS with the Homebrew package manager. -+ -<> - IMPORTANT: If your Elasticsearch installation is protected by {ref}/elasticsearch-security.html[{stack-security-features}] see {kibana-ref}/using-kibana-with-security.html[Configuring security in {kib}] for @@ -66,5 +60,3 @@ include::install/deb.asciidoc[] include::install/rpm.asciidoc[] include::{kib-repo-dir}/setup/docker.asciidoc[] - -include::install/brew.asciidoc[] diff --git a/docs/setup/install/brew-running.asciidoc b/docs/setup/install/brew-running.asciidoc deleted file mode 100644 index d73102b098ec1..0000000000000 --- a/docs/setup/install/brew-running.asciidoc +++ /dev/null @@ -1,9 +0,0 @@ -==== Run {kib} with `brew services` - -With Homebrew, Kibana can be started and stopped as follows: - -[source,sh] --------------------------------------------------- -brew services start elastic/tap/kibana-full -brew services stop elastic/tap/kibana-full --------------------------------------------------- diff --git a/docs/setup/install/brew.asciidoc b/docs/setup/install/brew.asciidoc deleted file mode 100644 index eeba869a259d4..0000000000000 --- a/docs/setup/install/brew.asciidoc +++ /dev/null @@ -1,65 +0,0 @@ -[[brew]] -=== Install {kib} on macOS with Homebrew -++++ -Install on macOS with Homebrew -++++ - -Elastic publishes Homebrew formulae so you can install {kib} with the https://brew.sh/[Homebrew] package manager. - -To install with Homebrew, you first need to tap the Elastic Homebrew repository: - -[source,sh] -------------------------- -brew tap elastic/tap -------------------------- - -Once you've tapped the Elastic Homebrew repo, you can use `brew install` to -install the **latest version** of {kib}: - -[source,sh] -------------------------- -brew install elastic/tap/kibana-full -------------------------- - -[[brew-layout]] -==== Directory layout for Homebrew installs - -When you install {kib} with `brew install`, the config files, logs, -and data directory are stored in the following locations. - -[cols="> -when required. +When required, {kib} automatically migrates <>. In case of an upgrade failure, you can roll back to an earlier version of {kib}. To roll back, you **must** have a {ref}/snapshot-restore.html[backup snapshot] that includes the `kibana` feature -state. Snapshots include this feature state by default. +state. By default, snapshots include the `kibana` feature state. ==== For more information about upgrading, refer to {stack-ref}/upgrading-elastic-stack.html[Upgrading to Elastic {version}.] IMPORTANT: You can upgrade to pre-release versions for testing, -but upgrading from a pre-release to the General Available version is not supported. -Pre-releases should only be used for testing in a temporary environment. +but upgrading from a pre-release to the General Available version is unsupported. +You should use pre-release versions only for testing in a temporary environment. include::upgrade/upgrade-migrations.asciidoc[leveloffset=-1] diff --git a/docs/setup/upgrade/logging-configuration-changes.asciidoc b/docs/setup/upgrade/logging-configuration-changes.asciidoc index 4d5f5f732536e..4a9d03d3b5312 100644 --- a/docs/setup/upgrade/logging-configuration-changes.asciidoc +++ b/docs/setup/upgrade/logging-configuration-changes.asciidoc @@ -2,7 +2,7 @@ [[logging-config-changes]] === Logging configuration changes -WARNING: {kib} 8.0 and later uses a new logging system. Be sure to read the documentation for your version of {kib} before proceeding. +WARNING: {kib} 8.0.0 and later uses a new logging system. Before you upgrade, read the documentation for your {kib} version. [[logging-pattern-format-old-and-new-example]] [options="header"] diff --git a/docs/setup/upgrade/upgrade-migrations.asciidoc b/docs/setup/upgrade/upgrade-migrations.asciidoc index 7136011a4f8f8..059ae47d2e476 100644 --- a/docs/setup/upgrade/upgrade-migrations.asciidoc +++ b/docs/setup/upgrade/upgrade-migrations.asciidoc @@ -2,14 +2,14 @@ [[saved-object-migrations]] === Saved object migrations -Every time {kib} is upgraded it will perform an upgrade migration to ensure that all <> are compatible with the new version. +Each time you upgrade {kib}, an upgrade migration is performed to ensure that all <> are compatible with the new version. -NOTE: 6.7 includes an https://www.elastic.co/guide/en/kibana/6.7/upgrade-assistant.html[Upgrade Assistant] -to help you prepare for your upgrade to 7.0. To access the assistant, go to *Management > 7.0 Upgrade Assistant*. +NOTE: To help you prepare for the upgrade to 7.0.0, 6.7.0 includes an https://www.elastic.co/guide/en/kibana/6.7/upgrade-assistant.html[*Upgrade Assistant*]. +To access the assistant, go to *Management > 7.0 Upgrade Assistant*. -WARNING: {kib} 7.12.0 and later uses a new migration process and index naming scheme. Be sure to read the documentation for your version of {kib} before proceeding. +WARNING: {kib} 7.12.0 and later uses a new migration process and index naming scheme. Before you upgrade, read the documentation for your version of {kib}. -WARNING: The following instructions assumes {kib} is using the default index names. If the `kibana.index` or `xpack.tasks.index` configuration settings were changed these instructions will have to be adapted accordingly. +WARNING: The following instructions assumes {kib} is using the default index names. If the `kibana.index` or `xpack.tasks.index` configuration settings are different from the default, adapt the instructions accordingly. [float] [[upgrade-migrations-process]] @@ -17,13 +17,16 @@ WARNING: The following instructions assumes {kib} is using the default index nam Saved objects are stored in two indices: -* `.kibana_{kibana_version}_001`, e.g. for Kibana v7.12.0 `.kibana_7.12.0_001`. -* `.kibana_task_manager_{kibana_version}_001`, e.g. for Kibana v7.12.0 `.kibana_task_manager_7.12.0_001`. +* `.kibana_{kibana_version}_001`, e.g. for {kib} 7.12.0 `.kibana_7.12.0_001`. +* `.kibana_task_manager_{kibana_version}_001`, e.g. for {kib} 7.12.0 `.kibana_task_manager_7.12.0_001`. -The index aliases `.kibana` and `.kibana_task_manager` will always point to +The index aliases `.kibana` and `.kibana_task_manager` always point to the most up-to-date saved object indices. -The first time a newer {kib} starts, it will first perform an upgrade migration before starting plugins or serving HTTP traffic. To prevent losing acknowledged writes old nodes should be shutdown before starting the upgrade. To reduce the likelihood of old nodes losing acknowledged writes, {kib} 7.12.0 and later will add a write block to the outdated index. Table 1 lists the saved objects indices used by previous versions of {kib}. +When you start a new {kib} installation, an upgrade migration is performed before starting plugins or serving HTTP traffic. +Before you upgrade, shut down old nodes to prevent losing acknowledged writes. +To reduce the likelihood of old nodes losing acknowledged writes, {kib} 7.12.0 and later +adds a write block to the outdated index. Table 1 lists the saved objects indices used by previous {kib} versions. .Saved object indices and aliases per {kib} version [options="header"] @@ -40,22 +43,26 @@ The first time a newer {kib} starts, it will first perform an upgrade migration |======================= ==== Upgrading multiple {kib} instances -When upgrading several {kib} instances connected to the same {es} cluster, ensure that all outdated instances are shutdown before starting the upgrade. +When upgrading several {kib} instances connected to the same {es} cluster, +ensure that all outdated instances are shut down before starting the upgrade. -Kibana does not support rolling upgrades. However, once outdated instances are shutdown, all upgraded instances can be started in parallel in which case all instances will participate in the upgrade migration in parallel. +Rolling upgrades are unsupported in {kib}. However, when outdated instances are shut down, you can start all upgraded instances in parallel, +which allows all instances to participate in the upgrade migration in parallel. -For large deployments with more than 10 {kib} instances and more than 10 000 saved objects, the upgrade downtime can be reduced by bringing up a single {kib} instance and waiting for it to complete the upgrade migration before bringing up the remaining instances. +For large deployments with more than 10 {kib} instances, and more than 10,000 saved objects, +you can reduce the upgrade downtime by bringing up a single {kib} instance and waiting for it to +complete the upgrade migration before bringing up the remaining instances. [float] [[preventing-migration-failures]] ==== Preventing migration failures -This section highlights common causes of {kib} upgrade failures and how to prevent them. +Review the common causes of {kib} upgrade failures and how to prevent them. [float] ===== timeout_exception or receive_timeout_transport_exception -There is a known issue in v7.12.0 for users who tried the fleet beta. Upgrade migrations fail because of a large number of documents in the `.kibana` index. +There is a known issue in 7.12.0 for users who tried the {fleet} beta. +Upgrade migrations fail because of a large number of documents in the `.kibana` index, which causes {kib} to log errors such as: -This can cause Kibana to log errors like: [source,sh] -------------------------------------------- @@ -64,24 +71,25 @@ Error: Unable to complete saved object migrations for the [.kibana] index. Pleas Error: Unable to complete saved object migrations for the [.kibana] index. Please check the health of your Elasticsearch cluster and try again. Error: [timeout_exception]: Timed out waiting for completion of [org.elasticsearch.index.reindex.BulkByScrollTask@6a74c54] -------------------------------------------- -Instructions to work around this issue are in https://github.com/elastic/kibana/issues/95321[this GitHub issue]. +For instructions on how to mitigate the known issue, refer to https://github.com/elastic/kibana/issues/95321[the GitHub issue]. [float] ===== Corrupt saved objects -We highly recommend testing your {kib} upgrade in a development cluster to discover and remedy problems caused by corrupt documents, especially when there are custom integrations creating saved objects in your environment. +To find and remedy problems caused by corrupt documents, we highly recommend testing your {kib} upgrade in a development cluster, +especially when there are custom integrations that create saved objects in your environment. -Saved objects that were corrupted through manual editing or integrations will cause migration -failures with a log message like `Unable to migrate the corrupt Saved Object document ...`. -Corrupt documents will have to be fixed or deleted before an upgrade migration can succeed. +Saved objects that are corrupted through manual editing or integrations cause migration +failures with a log message, such as `Unable to migrate the corrupt Saved Object document ...`. +For a successful upgrade migration, you must fix or delete corrupt documents. -For example, given the following error message: +For example, you receive the following error message: [source,sh] -------------------------------------------- Unable to migrate the corrupt saved object document with _id: 'marketing_space:dashboard:e3c5fc71-ac71-4805-bcab-2bcc9cc93275'. To allow migrations to proceed, please delete this document from the [.kibana_7.12.0_001] index. -------------------------------------------- -The following steps must be followed to delete the document that is causing the migration to fail: +To delete the documents that cause migrations to fail, take the following steps: . Remove the write block which the migration system has placed on the previous index: + @@ -104,18 +112,18 @@ DELETE .kibana_7.12.0_001/_doc/marketing_space:dashboard:e3c5fc71-ac71-4805-bcab . Restart {kib}. + -In this example, the Dashboard with ID `e3c5fc71-ac71-4805-bcab-2bcc9cc93275` that belongs to the space `marketing_space` **will no longer be available**. +The dashboard with the `e3c5fc71-ac71-4805-bcab-2bcc9cc93275` ID that belongs to the `marketing_space` space **is no longer available**. -Be sure you have a snapshot before you delete the corrupt document. If restoring from a snapshot is not an option, it is recommended to also delete the `temp` and `target` indices the migration created before restarting {kib} and retrying. +Be sure you have a snapshot before you delete the corrupt document. If you are unable to restore from a snapshot, it is recommended to also delete the `temp` and `target` indices the migration creates before you restart {kib} and retry the snapshot restore. [float] -===== User defined index templates that causes new `.kibana*` indices to have incompatible settings or mappings -Matching index templates which specify `settings.refresh_interval` or `mappings` are known to interfere with {kib} upgrades. +===== User defined index templates that cause new `.kibana*` indices to have incompatible settings or mappings +Matching index templates that specify `settings.refresh_interval` or `mappings` are known to interfere with {kib} upgrades. -Prevention: narrow down the index patterns of any user-defined index templates to ensure that these won't apply to new `.kibana*` indices. +To make sure the index templates won't apply to new `.kibana*` indices, narrow down the {data-sources} of any user-defined index templates. -NOTE: {kib} < 6.5 creates it's own index template called `kibana_index_template:.kibana` -and uses an index pattern of `.kibana`. This index template will not interfere and does not need to be changed or removed. +NOTE: In {kib} 6.5.0 and earlier, {kib} creates a `kibana_index_template:.kibana` index template +and uses a `.kibana` index pattern. You do not need to change or remove the index template. [float] ===== An unhealthy {es} cluster @@ -127,68 +135,76 @@ Problems with your {es} cluster can prevent {kib} upgrades from succeeding. Ensu [float] ===== Different versions of {kib} connected to the same {es} index -When different versions of {kib} are attempting an upgrade migration in parallel this can lead to migration failures. Ensure that all {kib} instances are running the same version, configuration and plugins. +When you perform an upgrade migration of different {kib} versions, the migration can fail. +Ensure that all {kib} instances are running the same version, configuration, and plugins. [float] ===== Incompatible `xpack.tasks.index` configuration setting -For {kib} versions prior to 7.5.1, if the task manager index is set to `.tasks` with the configuration setting `xpack.tasks.index: ".tasks"`, upgrade migrations will fail. {kib} 7.5.1 and later prevents this by refusing to start with an incompatible configuration setting. +In {kib} 7.5.0 and earlier, when the task manager index is set to `.tasks` with the configuration setting `xpack.tasks.index: ".tasks"`, +upgrade migrations fail. In {kib} 7.5.1 and later, the incompatible configuration setting prevents upgrade migrations from starting. [float] [[resolve-migrations-failures]] ==== Resolving migration failures -If {kib} terminates unexpectedly while migrating a saved object index it will automatically attempt to -perform the migration again once the process has restarted. Do not delete any saved objects indices to -attempt to fix a failed migration. Unlike previous versions, {kib} version 7.12.0 and -later does not require deleting any indices to release a failed migration lock. +If {kib} unexpectedly terminates while migrating a saved object index, {kib} automatically attempts to +perform the migration again when the process restarts. Do not delete any saved objects indices to +to fix a failed migration. Unlike previous versions, {kib} 7.12.0 and +later does not require deleting indices to release a failed migration lock. -If upgrade migrations fail repeatedly, follow the advice in +If upgrade migrations fail repeatedly, refer to <>. -Once the root cause for the migration failure has been addressed, -{kib} will automatically retry the migration without any further intervention. -If you're unable to resolve a failed migration following these steps, please contact support. +When you address the root cause for the migration failure, +{kib} automatically retries the migration. +If you're unable to resolve a failed migration, contact Support. [float] [[upgrade-migrations-rolling-back]] ==== Rolling back to a previous version of {kib} -If you've followed the advice in <> -and <> and -{kib} is still not able to upgrade successfully, you might choose to rollback {kib} until +If you've followed <> +and <>, and +{kib} is still unable to successfully upgrade, rollback {kib} until you're able to identify and fix the root cause. -WARNING: Before rolling back {kib}, ensure that the version you wish to rollback to is compatible with -your {es} cluster. If the version you're rolling back to is not compatible, you will have to also rollback {es}. -Any changes made after an upgrade will be lost when rolling back to a previous version. +WARNING: Before you roll back {kib}, ensure that the version you want to roll back to is compatible with +your {es} cluster. If the version you want to roll back to is not compatible, you must also rollback {es}. +Any changes made after an upgrade are lost when you roll back to a previous version. -In order to rollback after a failed upgrade migration, the saved object indices have to be -rolled back to be compatible with the previous {kib} version. +To roll back after a failed upgrade migration, you must also rollback the saved object indices to be compatible with the previous {kib} version. [float] -===== Rollback by restoring a backup snapshot: +===== Roll back by restoring a backup snapshot -1. Before proceeding, {ref}/snapshots-take-snapshot.html[take a snapshot] that contains the `kibana` feature state. - Snapshots include this feature state by default. -2. Shutdown all {kib} instances to be 100% sure that there are no instances currently performing a migration. -3. Delete all saved object indices with `DELETE /.kibana*` -4. {ref}/snapshots-restore-snapshot.html[Restore] the `kibana` feature state from the snapshot. -5. Start up all {kib} instances on the older version you wish to rollback to. +. Before proceeding, {ref}/snapshots-take-snapshot.html[take a snapshot] that contains the `kibana` feature state. + By default, snapshots include the `kibana` feature state. +. To make sure no {kib} instances are performing an upgrade migration, shut down all {kib} instances. +. To delete all saved object indices, use `DELETE /.kibana*`. +. {ref}/snapshots-restore-snapshot.html[Restore] the `kibana` feature state from the snapshot. +. Start all {kib} instances on the older version you want to rollback to. [float] -===== (Not recommended) Rollback without a backup snapshot: +===== (Not recommended) Roll back without a backup snapshot -1. Shutdown all {kib} instances to be 100% sure that there are no {kib} instances currently performing a migration. -2. {ref}/snapshots-take-snapshot.html[Take a snapshot] that includes the `kibana` feature state. Snapshots include this feature state by default. -3. Delete the version specific indices created by the failed upgrade migration. For example, if you wish to rollback from a failed upgrade to v7.12.0 `DELETE /.kibana_7.12.0_*,.kibana_task_manager_7.12.0_*` -4. Inspect the output of `GET /_cat/aliases`. -If either the `.kibana` and/or `.kibana_task_manager` alias is missing, these will have to be created manually. +. To make sure no {kib} instances are performing an upgrade migration, shut down all {kib} instances. +. {ref}/snapshots-take-snapshot.html[Take a snapshot] that includes the `kibana` feature state. By default, snapshots include the `kibana` feature state. +. Delete the version-specific indices created by the failed upgrade migration. ++ +For example, to rollback from a failed upgrade +to v7.12.0, use `DELETE /.kibana_7.12.0_*,.kibana_task_manager_7.12.0_*`. +. Inspect the output of `GET /_cat/aliases`. ++ +If the `.kibana` or `.kibana_task_manager` aliases are missing, you must create them manually. Find the latest index from the output of `GET /_cat/indices` and create the missing alias to point to the latest index. -For example. if the `.kibana` alias was missing and the latest index is `.kibana_3` create a new alias with `POST /.kibana_3/_aliases/.kibana`. -5. Remove the write block from the rollback indices. `PUT /.kibana,.kibana_task_manager/_settings {"index.blocks.write": false}` -6. Start up {kib} on the older version you wish to rollback to. +For example, if the `.kibana` alias is missing, and the latest index is `.kibana_3`, create a new alias using `POST /.kibana_3/_aliases/.kibana`. +. To remove the write block from the roll back indices, use +`PUT /.kibana,.kibana_task_manager/_settings {"index.blocks.write": false}` +. Start {kib} on the older version you want to rollback to. [float] [[upgrade-migrations-old-indices]] ==== Handling old `.kibana_N` indices -After migrations have completed, there will be multiple {kib} indices in {es}: (`.kibana_1`, `.kibana_2`, `.kibana_7.12.0` etc). {kib} only uses the index that the `.kibana` and `.kibana_task_manager` alias points to. The other {kib} indices can be safely deleted, but are left around as a matter of historical record, and to facilitate rolling {kib} back to a previous version. +After the migrations complete, multiple {kib} indices are created in {es}: (`.kibana_1`, `.kibana_2`, `.kibana_7.12.0` etc). +{kib} only uses the index that the `.kibana` and `.kibana_task_manager` aliases point to. +The other {kib} indices can be safely deleted, but are left around as a matter of historical record, and to facilitate rolling {kib} back to a previous version. diff --git a/docs/setup/upgrade/upgrade-standard.asciidoc b/docs/setup/upgrade/upgrade-standard.asciidoc index b43da6aef9765..b01759b4f3511 100644 --- a/docs/setup/upgrade/upgrade-standard.asciidoc +++ b/docs/setup/upgrade/upgrade-standard.asciidoc @@ -37,7 +37,7 @@ from 4.x, you will need to copy the configurations from your old config (`/etc/kibana/kibana.yml`). Make sure you remove or update any configurations -that are indicated in the <> documentation +that are indicated in the <> documentation otherwise {kib} will fail to start. -- . Upgrade any plugins by removing the existing plugin and reinstalling the @@ -58,7 +58,7 @@ and becomes a new instance in the monitoring data. -- . Copy the files from the `config` directory from your old installation to your new installation. Make sure you remove or update any configurations that are - indicated in the <> documentation + indicated in the <> documentation otherwise {kib} will fail to start. . Copy the files from the `data` directory from your old installation to your new installation. diff --git a/docs/user/whats-new.asciidoc b/docs/user/whats-new.asciidoc index 587f4588bb442..aa16a98a27fdb 100644 --- a/docs/user/whats-new.asciidoc +++ b/docs/user/whats-new.asciidoc @@ -2,7 +2,7 @@ == What's new in 8.0 This section summarizes the most important changes in each release. For the -full list, see <> and <>. +full list, see <> and <>. coming[8.0.0] diff --git a/package.json b/package.json index 9ea3e8335f886..d0f659ffec9f7 100644 --- a/package.json +++ b/package.json @@ -217,7 +217,7 @@ "constate": "^1.3.2", "content-disposition": "0.5.3", "copy-to-clipboard": "^3.0.8", - "core-js": "^3.20.3", + "core-js": "^3.21.0", "cronstrue": "^1.51.0", "cytoscape": "^3.10.0", "cytoscape-dagre": "^2.2.2", @@ -232,7 +232,7 @@ "deep-freeze-strict": "^1.1.1", "deepmerge": "^4.2.2", "del": "^5.1.0", - "elastic-apm-node": "^3.27.0", + "elastic-apm-node": "^3.28.0", "execa": "^4.0.2", "exit-hook": "^2.2.0", "expiry-js": "0.1.7", @@ -618,6 +618,7 @@ "@types/kbn__telemetry-tools": "link:bazel-bin/packages/kbn-telemetry-tools/npm_module_types", "@types/kbn__test": "link:bazel-bin/packages/kbn-test/npm_module_types", "@types/kbn__test-jest-helpers": "link:bazel-bin/packages/kbn-test-jest-helpers/npm_module_types", + "@types/kbn__typed-react-router-config": "link:bazel-bin/packages/kbn-typed-react-router-config/npm_module_types", "@types/kbn__ui-shared-deps-npm": "link:bazel-bin/packages/kbn-ui-shared-deps-npm/npm_module_types", "@types/kbn__ui-shared-deps-src": "link:bazel-bin/packages/kbn-ui-shared-deps-src/npm_module_types", "@types/kbn__ui-theme": "link:bazel-bin/packages/kbn-ui-theme/npm_module_types", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index 6421f36bf73b7..02e82476cd88d 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -132,6 +132,7 @@ filegroup( "//packages/kbn-telemetry-tools:build_types", "//packages/kbn-test:build_types", "//packages/kbn-test-jest-helpers:build_types", + "//packages/kbn-typed-react-router-config:build_types", "//packages/kbn-ui-shared-deps-npm:build_types", "//packages/kbn-ui-shared-deps-src:build_types", "//packages/kbn-ui-theme:build_types", diff --git a/packages/kbn-typed-react-router-config/BUILD.bazel b/packages/kbn-typed-react-router-config/BUILD.bazel index 6f4e53e58fff7..62fd6adf5bb26 100644 --- a/packages/kbn-typed-react-router-config/BUILD.bazel +++ b/packages/kbn-typed-react-router-config/BUILD.bazel @@ -1,9 +1,10 @@ -load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") -load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") -load("//src/dev/bazel:index.bzl", "jsts_transpiler") +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") PKG_BASE_NAME = "kbn-typed-react-router-config" PKG_REQUIRE_NAME = "@kbn/typed-react-router-config" +TYPES_PKG_REQUIRE_NAME = "@types/kbn__typed-react-router-config" SOURCE_FILES = glob( [ @@ -28,23 +29,30 @@ NPM_MODULE_EXTRA_FILES = [ RUNTIME_DEPS = [ "//packages/kbn-io-ts-utils", - "@npm//tslib", - "@npm//utility-types", + "@npm//fp-ts", + "@npm//history", "@npm//io-ts", + "@npm//lodash", "@npm//query-string", + "@npm//react", "@npm//react-router-config", "@npm//react-router-dom", + "@npm//tslib", + "@npm//utility-types", ] TYPES_DEPS = [ "//packages/kbn-io-ts-utils:npm_module_types", + "@npm//fp-ts", "@npm//query-string", "@npm//utility-types", + "@npm//@types/history", "@npm//@types/jest", + "@npm//@types/lodash", "@npm//@types/node", + "@npm//@types/react", "@npm//@types/react-router-config", "@npm//@types/react-router-dom", - "@npm//@types/history", ] jsts_transpiler( @@ -86,7 +94,7 @@ ts_project( js_library( name = PKG_BASE_NAME, srcs = NPM_MODULE_EXTRA_FILES, - deps = RUNTIME_DEPS + [":target_node", ":target_web", ":tsc_types"], + deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], ) @@ -105,3 +113,20 @@ filegroup( ], visibility = ["//visibility:public"], ) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = TYPES_PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [ + ":npm_module_types", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-typed-react-router-config/package.json b/packages/kbn-typed-react-router-config/package.json index 50c2e4b5d7e89..0f45f63f4ab2d 100644 --- a/packages/kbn-typed-react-router-config/package.json +++ b/packages/kbn-typed-react-router-config/package.json @@ -1,7 +1,6 @@ { "name": "@kbn/typed-react-router-config", "main": "target_node/index.js", - "types": "target_types/index.d.ts", "browser": "target_web/index.js", "version": "1.0.0", "license": "SSPL-1.0 OR Elastic License 2.0", diff --git a/src/core/public/http/external_url_service.test.ts b/src/core/public/http/external_url_service.test.ts index ee757c5046760..4ce3709ff6366 100644 --- a/src/core/public/http/external_url_service.test.ts +++ b/src/core/public/http/external_url_service.test.ts @@ -73,6 +73,23 @@ const internalRequestScenarios = [ ]; describe('External Url Service', () => { + describe('#isInternalUrl', () => { + const { setup } = setupService({ + location: new URL('https://example.com/app/management?q=1&bar=false#some-hash'), + serverBasePath: '', + policy: [], + }); + + it('internal request', () => { + expect(setup.isInternalUrl('/')).toBeTruthy(); + expect(setup.isInternalUrl('https://example.com/')).toBeTruthy(); + }); + + it('external request', () => { + expect(setup.isInternalUrl('https://elastic.co/')).toBeFalsy(); + }); + }); + describe('#validateUrl', () => { describe('internal requests with a server base path', () => { const serverBasePath = '/base-path'; diff --git a/src/core/public/http/external_url_service.ts b/src/core/public/http/external_url_service.ts index 166e167b3b994..0fb1c85d48257 100644 --- a/src/core/public/http/external_url_service.ts +++ b/src/core/public/http/external_url_service.ts @@ -50,20 +50,33 @@ function normalizeProtocol(protocol: string) { return protocol.endsWith(':') ? protocol.slice(0, -1).toLowerCase() : protocol.toLowerCase(); } +const createIsInternalUrlValidation = ( + location: Pick, + serverBasePath: string +) => { + return function isInternallUrl(next: string) { + const base = new URL(location.href); + const url = new URL(next, base); + + return ( + url.origin === base.origin && + (!serverBasePath || url.pathname.startsWith(`${serverBasePath}/`)) + ); + }; +}; + const createExternalUrlValidation = ( rules: IExternalUrlPolicy[], location: Pick, serverBasePath: string ) => { + const isInternalUrl = createIsInternalUrlValidation(location, serverBasePath); + return function validateExternalUrl(next: string) { const base = new URL(location.href); const url = new URL(next, base); - const isInternalURL = - url.origin === base.origin && - (!serverBasePath || url.pathname.startsWith(`${serverBasePath}/`)); - - if (isInternalURL) { + if (isInternalUrl(next)) { return url; } @@ -90,6 +103,7 @@ export class ExternalUrlService implements CoreService { const { policy } = injectedMetadata.getExternalUrlConfig(); return { + isInternalUrl: createIsInternalUrlValidation(location, serverBasePath), validateUrl: createExternalUrlValidation(policy, location, serverBasePath), }; } diff --git a/src/core/public/http/http_service.mock.ts b/src/core/public/http/http_service.mock.ts index fff99d84a76a6..bfd81a1003736 100644 --- a/src/core/public/http/http_service.mock.ts +++ b/src/core/public/http/http_service.mock.ts @@ -36,6 +36,7 @@ const createServiceMock = ({ isAnonymous: jest.fn(), }, externalUrl: { + isInternalUrl: jest.fn(), validateUrl: jest.fn(), }, addLoadingCountSource: jest.fn(), diff --git a/src/core/public/http/types.ts b/src/core/public/http/types.ts index 876799765ea1c..afe1d653c599c 100644 --- a/src/core/public/http/types.ts +++ b/src/core/public/http/types.ts @@ -110,6 +110,13 @@ export interface IBasePath { * @public */ export interface IExternalUrl { + /** + * Determines if the provided URL is an internal url. + * + * @param relativeOrAbsoluteUrl + */ + isInternalUrl(relativeOrAbsoluteUrl: string): boolean; + /** * Determines if the provided URL is a valid location to send users. * Validation is based on the configured allow list in kibana.yml. diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index db132e267807e..d8cf4706ceb16 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -686,6 +686,7 @@ export interface IBasePath { // @public export interface IExternalUrl { + isInternalUrl(relativeOrAbsoluteUrl: string): boolean; validateUrl(relativeOrAbsoluteUrl: string): URL | null; } diff --git a/src/plugins/dashboard/public/application/embeddable/empty_screen/__snapshots__/dashboard_empty_screen.test.tsx.snap b/src/plugins/dashboard/public/application/embeddable/empty_screen/__snapshots__/dashboard_empty_screen.test.tsx.snap index 70a21438754bd..e416dced4f8a1 100644 --- a/src/plugins/dashboard/public/application/embeddable/empty_screen/__snapshots__/dashboard_empty_screen.test.tsx.snap +++ b/src/plugins/dashboard/public/application/embeddable/empty_screen/__snapshots__/dashboard_empty_screen.test.tsx.snap @@ -19,6 +19,7 @@ exports[`DashboardEmptyScreen renders correctly with edit mode 1`] = ` }, "delete": [MockFunction], "externalUrl": Object { + "isInternalUrl": [MockFunction], "validateUrl": [MockFunction], }, "fetch": [MockFunction], @@ -343,6 +344,7 @@ exports[`DashboardEmptyScreen renders correctly with readonly mode 1`] = ` }, "delete": [MockFunction], "externalUrl": Object { + "isInternalUrl": [MockFunction], "validateUrl": [MockFunction], }, "fetch": [MockFunction], @@ -706,6 +708,7 @@ exports[`DashboardEmptyScreen renders correctly with view mode 1`] = ` }, "delete": [MockFunction], "externalUrl": Object { + "isInternalUrl": [MockFunction], "validateUrl": [MockFunction], }, "fetch": [MockFunction], diff --git a/src/plugins/dashboard/public/application/lib/sync_dashboard_url_state.ts b/src/plugins/dashboard/public/application/lib/sync_dashboard_url_state.ts index e0a1526baa473..392b37bb4d8e0 100644 --- a/src/plugins/dashboard/public/application/lib/sync_dashboard_url_state.ts +++ b/src/plugins/dashboard/public/application/lib/sync_dashboard_url_state.ts @@ -94,13 +94,13 @@ const loadDashboardUrlState = ({ if (!awaitingRemoval) { awaitingRemoval = true; kbnUrlStateStorage.kbnUrlControls.updateAsync((nextUrl) => { + awaitingRemoval = false; if (nextUrl.includes(DASHBOARD_STATE_STORAGE_KEY)) { return replaceUrlHashQuery(nextUrl, (query) => { delete query[DASHBOARD_STATE_STORAGE_KEY]; return query; }); } - awaitingRemoval = false; return nextUrl; }, true); } diff --git a/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts b/src/plugins/dashboard/public/services/saved_object_loader.ts similarity index 95% rename from src/plugins/saved_objects/public/saved_object/saved_object_loader.ts rename to src/plugins/dashboard/public/services/saved_object_loader.ts index 10872b5d9cd1a..521d6645e30f9 100644 --- a/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts +++ b/src/plugins/dashboard/public/services/saved_object_loader.ts @@ -12,9 +12,13 @@ import { SavedObjectsFindOptionsReference, SavedObjectReference, } from 'kibana/public'; -import { SavedObject } from '../types'; -import { StringUtils } from './helpers/string_utils'; +import { SavedObject } from '../../../saved_objects/public'; +import { upperFirst } from './string_utils'; +/** + * @deprecated + * @removeBy 8.0 + */ export interface SavedObjectLoaderFindOptions { size?: number; fields?: string[]; @@ -23,6 +27,8 @@ export interface SavedObjectLoaderFindOptions { /** * @deprecated + * @removeBy 8.0 + * * The SavedObjectLoader class provides some convenience functions * to load and save one kind of saved objects (specified in the constructor). * @@ -46,7 +52,7 @@ export class SavedObjectLoader { this.loaderProperties = { name: `${this.lowercaseType}s`, - noun: StringUtils.upperFirst(this.type), + noun: upperFirst(this.type), nouns: `${this.lowercaseType}s`, }; } diff --git a/src/plugins/dashboard/public/services/saved_objects.ts b/src/plugins/dashboard/public/services/saved_objects.ts index 305ff3c2014f8..afd778d78b271 100644 --- a/src/plugins/dashboard/public/services/saved_objects.ts +++ b/src/plugins/dashboard/public/services/saved_objects.ts @@ -11,11 +11,11 @@ export type { SavedObject, SavedObjectsStart, SavedObjectSaveOpts, - SavedObjectLoaderFindOptions, } from '../../../saved_objects/public'; export { showSaveModal, - SavedObjectLoader, SavedObjectSaveModal, getSavedObjectFinder, } from '../../../saved_objects/public'; +export { SavedObjectLoader } from './saved_object_loader'; +export type { SavedObjectLoaderFindOptions } from './saved_object_loader'; diff --git a/src/plugins/saved_objects/public/saved_object/helpers/string_utils.test.ts b/src/plugins/dashboard/public/services/string_utils.test.ts similarity index 53% rename from src/plugins/saved_objects/public/saved_object/helpers/string_utils.test.ts rename to src/plugins/dashboard/public/services/string_utils.test.ts index 4e7258f1575dc..ed96cb4f1a0a1 100644 --- a/src/plugins/saved_objects/public/saved_object/helpers/string_utils.test.ts +++ b/src/plugins/dashboard/public/services/string_utils.test.ts @@ -6,17 +6,17 @@ * Side Public License, v 1. */ -import { StringUtils } from './string_utils'; +import { upperFirst } from './string_utils'; -describe('StringUtils class', () => { - describe('static upperFirst', () => { +describe('StringUtils', () => { + describe('upperFirst', () => { test('should converts the first character of string to upper case', () => { - expect(StringUtils.upperFirst()).toBe(''); - expect(StringUtils.upperFirst('')).toBe(''); + expect(upperFirst()).toBe(''); + expect(upperFirst('')).toBe(''); - expect(StringUtils.upperFirst('Fred')).toBe('Fred'); - expect(StringUtils.upperFirst('fred')).toBe('Fred'); - expect(StringUtils.upperFirst('FRED')).toBe('FRED'); + expect(upperFirst('Fred')).toBe('Fred'); + expect(upperFirst('fred')).toBe('Fred'); + expect(upperFirst('FRED')).toBe('FRED'); }); }); }); diff --git a/src/plugins/saved_objects/public/saved_object/helpers/string_utils.ts b/src/plugins/dashboard/public/services/string_utils.ts similarity index 55% rename from src/plugins/saved_objects/public/saved_object/helpers/string_utils.ts rename to src/plugins/dashboard/public/services/string_utils.ts index 5d4551f0c200c..31a36b38155d7 100644 --- a/src/plugins/saved_objects/public/saved_object/helpers/string_utils.ts +++ b/src/plugins/dashboard/public/services/string_utils.ts @@ -6,13 +6,11 @@ * Side Public License, v 1. */ -export class StringUtils { - /** - * Returns a version of the string with the first letter capitalized. - * @param str {string} - * @returns {string} - */ - public static upperFirst(str: string = ''): string { - return str ? str.charAt(0).toUpperCase() + str.slice(1) : ''; - } +/** + * Returns a version of the string with the first letter capitalized. + * @param str {string} + * @returns {string} + */ +export function upperFirst(str: string = ''): string { + return str ? str.charAt(0).toUpperCase() + str.slice(1) : ''; } diff --git a/src/plugins/data/common/search/tabify/tabify.test.ts b/src/plugins/data/common/search/tabify/tabify.test.ts index 6cdf9a3547d48..3e1b856de4100 100644 --- a/src/plugins/data/common/search/tabify/tabify.test.ts +++ b/src/plugins/data/common/search/tabify/tabify.test.ts @@ -8,7 +8,7 @@ import { tabifyAggResponse } from './tabify'; import { IndexPattern } from '../..'; -import { AggConfigs, IAggConfig, IAggConfigs } from '../aggs'; +import { AggConfigs, BucketAggParam, IAggConfig, IAggConfigs } from '../aggs'; import { mockAggTypesRegistry } from '../aggs/test_helpers'; import { metricOnly, threeTermBuckets } from './fixtures/fake_hierarchical_data'; @@ -54,6 +54,42 @@ describe('tabifyAggResponse Integration', () => { expect(resp.columns[0]).toHaveProperty('name', aggConfigs.aggs[0].makeLabel()); }); + describe('scaleMetricValues performance check', () => { + beforeAll(() => { + typesRegistry.get('count').params.push({ + name: 'scaleMetricValues', + default: false, + write: () => {}, + advanced: true, + } as any as BucketAggParam); + }); + test('does not call write if scaleMetricValues is not set', () => { + const aggConfigs = createAggConfigs([{ type: 'count' } as any]); + + const writeMock = jest.fn(); + aggConfigs.getRequestAggs()[0].write = writeMock; + + tabifyAggResponse(aggConfigs, metricOnly, { + metricsAtAllLevels: true, + }); + expect(writeMock).not.toHaveBeenCalled(); + }); + + test('does call write if scaleMetricValues is set', () => { + const aggConfigs = createAggConfigs([ + { type: 'count', params: { scaleMetricValues: true } } as any, + ]); + + const writeMock = jest.fn(() => ({})); + aggConfigs.getRequestAggs()[0].write = writeMock; + + tabifyAggResponse(aggConfigs, metricOnly, { + metricsAtAllLevels: true, + }); + expect(writeMock).toHaveBeenCalled(); + }); + }); + describe('transforms a complex response', () => { let esResp: typeof threeTermBuckets; let aggConfigs: IAggConfigs; diff --git a/src/plugins/data/common/search/tabify/tabify.ts b/src/plugins/data/common/search/tabify/tabify.ts index 5b1247a8f1719..1bdca61d654f7 100644 --- a/src/plugins/data/common/search/tabify/tabify.ts +++ b/src/plugins/data/common/search/tabify/tabify.ts @@ -37,8 +37,10 @@ export function tabifyAggResponse( if (column) { const agg = column.aggConfig; - const aggInfo = agg.write(aggs); - aggScale *= aggInfo.metricScale || 1; + if (agg.getParam('scaleMetricValues')) { + const aggInfo = agg.write(aggs); + aggScale *= aggInfo.metricScale || 1; + } switch (agg.type.type) { case AggGroupNames.Buckets: diff --git a/src/plugins/data_view_editor/public/components/form_schema.test.ts b/src/plugins/data_view_editor/public/components/form_schema.test.ts new file mode 100644 index 0000000000000..b2e1f697843c6 --- /dev/null +++ b/src/plugins/data_view_editor/public/components/form_schema.test.ts @@ -0,0 +1,22 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { singleAstriskValidator } from './form_schema'; +import { ValidationFuncArg } from '../shared_imports'; + +describe('validators', () => { + test('singleAstriskValidator should pass', async () => { + const result = singleAstriskValidator({ value: 'kibana*' } as ValidationFuncArg); + expect(result).toBeUndefined(); + }); + test('singleAstriskValidator should fail', async () => { + const result = singleAstriskValidator({ value: '*' } as ValidationFuncArg); + // returns error + expect(result).toBeDefined(); + }); +}); diff --git a/src/plugins/data_view_editor/public/components/form_schema.ts b/src/plugins/data_view_editor/public/components/form_schema.ts index a6df0c4206d2a..178fedda2de34 100644 --- a/src/plugins/data_view_editor/public/components/form_schema.ts +++ b/src/plugins/data_view_editor/public/components/form_schema.ts @@ -7,9 +7,21 @@ */ import { i18n } from '@kbn/i18n'; -import { fieldValidators } from '../shared_imports'; +import { fieldValidators, ValidationFunc } from '../shared_imports'; import { INDEX_PATTERN_TYPE } from '../types'; +export const singleAstriskValidator = ( + ...args: Parameters +): ReturnType => { + const [{ value, path }] = args; + + const message = i18n.translate('indexPatternEditor.validations.noSingleAstriskPattern', { + defaultMessage: "A single '*' is not an allowed index pattern", + }); + + return value === '*' ? { code: 'ERR_FIELD_MISSING', path, message } : undefined; +}; + export const schema = { title: { label: i18n.translate('indexPatternEditor.editor.form.titleLabel', { @@ -28,6 +40,9 @@ export const schema = { }) ), }, + { + validator: singleAstriskValidator, + }, ], }, timestampField: { diff --git a/src/plugins/data_view_editor/public/shared_imports.ts b/src/plugins/data_view_editor/public/shared_imports.ts index cca695bc9a95e..dd9b8ea2a0e41 100644 --- a/src/plugins/data_view_editor/public/shared_imports.ts +++ b/src/plugins/data_view_editor/public/shared_imports.ts @@ -28,6 +28,7 @@ export type { ValidationFunc, FieldConfig, ValidationConfig, + ValidationFuncArg, } from '../../es_ui_shared/static/forms/hook_form_lib'; export { useForm, diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx index 0f41c08fbc6fe..2d8469975430b 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx @@ -70,7 +70,11 @@ export const CreateEditField = withRouter( if (spec) { return ( <> - + { - const { application, uiSettings, overlays, chrome, dataViews } = + const { uiSettings, overlays, chrome, dataViews } = useKibana().services; const [fields, setFields] = useState(indexPattern.getNonScriptedFields()); const [conflictedFields, setConflictedFields] = useState( @@ -143,15 +143,16 @@ export const EditIndexPattern = withRouter( const showTagsSection = Boolean(indexPattern.timeFieldName || (tags && tags.length > 0)); const kibana = useKibana(); const docsUrl = kibana.services.docLinks!.links.elasticsearch.mapping; - const userEditPermission = !!application?.capabilities?.indexPatterns?.save; + const userEditPermission = dataViews.getCanSaveSync(); return (
{showTagsSection && ( diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/index_header/index_header.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/index_header/index_header.tsx index b64aed5c0811c..e40ef6a7ddf2f 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/index_header/index_header.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/index_header/index_header.tsx @@ -16,6 +16,7 @@ interface IndexHeaderProps { defaultIndex?: string; setDefault?: () => void; deleteIndexPatternClick?: () => void; + canSave: boolean; } const setDefaultAriaLabel = i18n.translate('indexPatternManagement.editDataView.setDefaultAria', { @@ -40,12 +41,13 @@ export const IndexHeader: React.FC = ({ setDefault, deleteIndexPatternClick, children, + canSave, }) => { return ( {indexPattern.title}} rightSideItems={[ - defaultIndex !== indexPattern.id && setDefault && ( + defaultIndex !== indexPattern.id && setDefault && canSave && ( = ({ /> ), - deleteIndexPatternClick && ( + canSave && (
`; @@ -178,6 +198,47 @@ exports[`IndexedFieldsTable should filter based on the query bar 1`] = ` }, ] } + openModal={[Function]} + theme={Object {}} + /> + +`; + +exports[`IndexedFieldsTable should filter based on the schema filter 1`] = ` +
+ `; @@ -212,6 +273,8 @@ exports[`IndexedFieldsTable should filter based on the type filter 1`] = ` }, ] } + openModal={[Function]} + theme={Object {}} /> `; @@ -291,8 +354,28 @@ exports[`IndexedFieldsTable should render normally 1`] = ` "name": "amount", "type": "long", }, + Object { + "displayName": "runtime", + "excluded": false, + "format": "", + "hasRuntime": true, + "info": Array [], + "isMapped": false, + "isUserEditable": false, + "kbnType": "number", + "name": "runtime", + "runtimeField": Object { + "script": Object { + "source": "emit('Hello');", + }, + "type": "long", + }, + "type": "long", + }, ] } + openModal={[Function]} + theme={Object {}} /> `; diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.test.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.test.tsx index 4773dbff38a28..c7b92c227a5d9 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.test.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.test.tsx @@ -11,6 +11,7 @@ import { shallow, ShallowWrapper } from 'enzyme'; import { DataViewField, DataView, DataViewType } from 'src/plugins/data_views/public'; import { IndexedFieldsTable } from './indexed_fields_table'; import { getFieldInfo } from '../../utils'; +import { RuntimeField } from 'src/plugins/data_views/common'; jest.mock('@elastic/eui', () => ({ EuiFlexGroup: 'eui-flex-group', @@ -67,11 +68,12 @@ const rollupIndexPattern = { } as unknown as DataView; const mockFieldToIndexPatternField = ( - spec: Record + spec: Record ) => { return new DataViewField(spec as unknown as DataViewField['spec']); }; +const runtimeField: RuntimeField = { type: 'long', script: { source: "emit('Hello');" } }; const fields = [ { name: 'Elastic', @@ -88,8 +90,19 @@ const fields = [ isUserEditable: true, }, { name: 'amount', displayName: 'amount', esTypes: ['long'], isUserEditable: true }, + { + name: 'runtime', + displayName: 'runtime', + runtimeField, + }, ].map(mockFieldToIndexPatternField); +const mockedServices = { + userEditPermission: false, + openModal: () => ({ onClose: new Promise(() => {}), close: async () => {} }), + theme: {} as any, +}; + describe('IndexedFieldsTable', () => { test('should render normally', async () => { const component: ShallowWrapper, React.Component<{}, {}, any>> = shallow( @@ -100,10 +113,12 @@ describe('IndexedFieldsTable', () => { fieldWildcardMatcher={() => { return () => false; }} - indexedFieldTypeFilter="" + indexedFieldTypeFilter={[]} + schemaFieldTypeFilter={[]} fieldFilter="" + {...mockedServices} /> - ).dive(); + ); await new Promise((resolve) => process.nextTick(resolve)); component.update(); @@ -120,10 +135,12 @@ describe('IndexedFieldsTable', () => { fieldWildcardMatcher={() => { return () => false; }} - indexedFieldTypeFilter="" + indexedFieldTypeFilter={[]} + schemaFieldTypeFilter={[]} fieldFilter="" + {...mockedServices} /> - ).dive(); + ); await new Promise((resolve) => process.nextTick(resolve)); component.setProps({ fieldFilter: 'Elast' }); @@ -141,13 +158,38 @@ describe('IndexedFieldsTable', () => { fieldWildcardMatcher={() => { return () => false; }} - indexedFieldTypeFilter="" + indexedFieldTypeFilter={[]} + schemaFieldTypeFilter={[]} + fieldFilter="" + {...mockedServices} + /> + ); + + await new Promise((resolve) => process.nextTick(resolve)); + component.setProps({ indexedFieldTypeFilter: ['date'] }); + component.update(); + + expect(component).toMatchSnapshot(); + }); + + test('should filter based on the schema filter', async () => { + const component: ShallowWrapper, React.Component<{}, {}, any>> = shallow( + { + return () => false; + }} + indexedFieldTypeFilter={[]} + schemaFieldTypeFilter={[]} fieldFilter="" + {...mockedServices} /> - ).dive(); + ); await new Promise((resolve) => process.nextTick(resolve)); - component.setProps({ indexedFieldTypeFilter: 'date' }); + component.setProps({ schemaFieldTypeFilter: ['runtime'] }); component.update(); expect(component).toMatchSnapshot(); @@ -163,10 +205,12 @@ describe('IndexedFieldsTable', () => { fieldWildcardMatcher={() => { return () => false; }} - indexedFieldTypeFilter="" + indexedFieldTypeFilter={[]} + schemaFieldTypeFilter={[]} fieldFilter="" + {...mockedServices} /> - ).dive(); + ); await new Promise((resolve) => process.nextTick(resolve)); component.update(); diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx index 667a4e029e02b..ad85499009db0 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx @@ -10,16 +10,15 @@ import React, { Component } from 'react'; import { createSelector } from 'reselect'; import { OverlayStart, ThemeServiceStart } from 'src/core/public'; import { DataViewField, DataView } from '../../../../../../plugins/data_views/public'; -import { useKibana } from '../../../../../../plugins/kibana_react/public'; import { Table } from './components/table'; import { IndexedFieldItem } from './types'; -import { IndexPatternManagmentContext } from '../../../types'; interface IndexedFieldsTableProps { fields: DataViewField[]; indexPattern: DataView; fieldFilter?: string; - indexedFieldTypeFilter?: string; + indexedFieldTypeFilter: string[]; + schemaFieldTypeFilter: string[]; helpers: { editField: (fieldName: string) => void; deleteField: (fieldName: string) => void; @@ -35,16 +34,10 @@ interface IndexedFieldsTableState { fields: IndexedFieldItem[]; } -const withHooks = (Comp: typeof Component) => { - return (props: any) => { - const { application } = useKibana().services; - const userEditPermission = !!application?.capabilities?.indexPatterns?.save; - - return ; - }; -}; - -class IndexedFields extends Component { +export class IndexedFieldsTable extends Component< + IndexedFieldsTableProps, + IndexedFieldsTableState +> { constructor(props: IndexedFieldsTableProps) { super(props); @@ -93,7 +86,8 @@ class IndexedFields extends Component props.fieldFilter, (state: IndexedFieldsTableState, props: IndexedFieldsTableProps) => props.indexedFieldTypeFilter, - (fields, fieldFilter, indexedFieldTypeFilter) => { + (state: IndexedFieldsTableState, props: IndexedFieldsTableProps) => props.schemaFieldTypeFilter, + (fields, fieldFilter, indexedFieldTypeFilter, schemaFieldTypeFilter) => { if (fieldFilter) { const normalizedFieldFilter = fieldFilter.toLowerCase(); fields = fields.filter( @@ -103,14 +97,34 @@ class IndexedFields extends Component { - if (indexedFieldTypeFilter === 'conflict' && field.kbnType === 'conflict') { + if (indexedFieldTypeFilter.includes('conflict') && field.kbnType === 'conflict') { + return true; + } + if ( + 'runtimeField' in field && + field.runtimeField?.type && + indexedFieldTypeFilter.includes(field.runtimeField?.type) + ) { return true; } // match one of multiple types on a field - return field.esTypes?.length && field.esTypes?.indexOf(indexedFieldTypeFilter) !== -1; + return ( + field.esTypes?.length && + field.esTypes.filter((val) => indexedFieldTypeFilter.includes(val)).length + ); + }); + } + + if (schemaFieldTypeFilter.length) { + // match fields of schema type + fields = fields.filter((field) => { + return ( + (schemaFieldTypeFilter.includes('runtime') && 'runtimeField' in field) || + (schemaFieldTypeFilter.includes('indexed') && !('runtimeField' in field)) + ); }); } @@ -136,5 +150,3 @@ class IndexedFields extends Component { - const { application, docLinks } = useKibana().services; + const { dataViews, docLinks } = useKibana().services; const links = docLinks?.links; - const userEditPermission = !!application?.capabilities?.indexPatterns?.save; + const userEditPermission = dataViews.getCanSaveSync(); return ( diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/scripted_fields_table/scripted_field_table.test.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/scripted_fields_table/scripted_field_table.test.tsx index aa74ae8c78fae..4febfdf0e1219 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/scripted_fields_table/scripted_field_table.test.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/scripted_fields_table/scripted_field_table.test.tsx @@ -68,8 +68,10 @@ describe('ScriptedFieldsTable', () => { helpers={helpers} painlessDocLink={'painlessDoc'} saveIndexPattern={async () => {}} + userEditPermission={false} + scriptedFieldLanguageFilter={[]} /> - ).dive(); + ); // Allow the componentWillMount code to execute // https://github.com/airbnb/enzyme/issues/450 @@ -86,8 +88,10 @@ describe('ScriptedFieldsTable', () => { helpers={helpers} painlessDocLink={'painlessDoc'} saveIndexPattern={async () => {}} + userEditPermission={false} + scriptedFieldLanguageFilter={[]} /> - ).dive(); + ); // Allow the componentWillMount code to execute // https://github.com/airbnb/enzyme/issues/450 @@ -117,15 +121,17 @@ describe('ScriptedFieldsTable', () => { painlessDocLink={'painlessDoc'} helpers={helpers} saveIndexPattern={async () => {}} + userEditPermission={false} + scriptedFieldLanguageFilter={[]} /> - ).dive(); + ); // Allow the componentWillMount code to execute // https://github.com/airbnb/enzyme/issues/450 await component.update(); // Fire `componentWillMount()` await component.update(); // Force update the component post async actions - component.setProps({ scriptedFieldLanguageFilter: 'painless' }); + component.setProps({ scriptedFieldLanguageFilter: ['painless'] }); component.update(); expect(component).toMatchSnapshot(); @@ -142,8 +148,10 @@ describe('ScriptedFieldsTable', () => { painlessDocLink={'painlessDoc'} helpers={helpers} saveIndexPattern={async () => {}} + userEditPermission={false} + scriptedFieldLanguageFilter={[]} /> - ).dive(); + ); // Allow the componentWillMount code to execute // https://github.com/airbnb/enzyme/issues/450 @@ -162,8 +170,10 @@ describe('ScriptedFieldsTable', () => { helpers={helpers} painlessDocLink={'painlessDoc'} saveIndexPattern={async () => {}} + userEditPermission={false} + scriptedFieldLanguageFilter={[]} /> - ).dive(); + ); await component.update(); // Fire `componentWillMount()` // @ts-expect-error lang is not valid @@ -189,8 +199,10 @@ describe('ScriptedFieldsTable', () => { helpers={helpers} painlessDocLink={'painlessDoc'} saveIndexPattern={async () => {}} + userEditPermission={false} + scriptedFieldLanguageFilter={[]} /> - ).dive(); + ); await component.update(); // Fire `componentWillMount()` // @ts-expect-error diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx index 2e3657b23c331..540131c50b236 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx @@ -15,15 +15,13 @@ import { import { Table, Header, CallOuts, DeleteScritpedFieldConfirmationModal } from './components'; import { ScriptedFieldItem } from './types'; -import { IndexPatternManagmentContext } from '../../../types'; import { DataView, DataViewsPublicPluginStart } from '../../../../../../plugins/data_views/public'; -import { useKibana } from '../../../../../../plugins/kibana_react/public'; interface ScriptedFieldsTableProps { indexPattern: DataView; fieldFilter?: string; - scriptedFieldLanguageFilter?: string; + scriptedFieldLanguageFilter: string[]; helpers: { redirectToRoute: Function; getRouteHref?: Function; @@ -41,16 +39,10 @@ interface ScriptedFieldsTableState { fields: ScriptedFieldItem[]; } -const withHooks = (Comp: typeof Component) => { - return (props: any) => { - const { application } = useKibana().services; - const userEditPermission = !!application?.capabilities?.indexPatterns?.save; - - return ; - }; -}; - -class ScriptedFields extends Component { +export class ScriptedFieldsTable extends Component< + ScriptedFieldsTableProps, + ScriptedFieldsTableState +> { constructor(props: ScriptedFieldsTableProps) { super(props); @@ -92,9 +84,9 @@ class ScriptedFields extends Component field.lang === this.props.scriptedFieldLanguageFilter + if (scriptedFieldLanguageFilter.length) { + languageFilteredFields = fields.filter((field) => + scriptedFieldLanguageFilter.includes(field.lang) ); } @@ -168,5 +160,3 @@ class ScriptedFields extends Component { @@ -44,6 +47,12 @@ interface TabsProps extends Pick { refreshFields: () => void; } +interface FilterItems { + value: string; + name: string; + checked?: FilterChecked; +} + const searchAriaLabel = i18n.translate( 'indexPatternManagement.editIndexPattern.fields.searchAria', { @@ -51,6 +60,10 @@ const searchAriaLabel = i18n.translate( } ); +const filterLabel = i18n.translate('indexPatternManagement.editIndexPattern.fields.filter', { + defaultMessage: 'Field type', +}); + const filterAriaLabel = i18n.translate( 'indexPatternManagement.editIndexPattern.fields.filterAria', { @@ -58,6 +71,45 @@ const filterAriaLabel = i18n.translate( } ); +const schemaFilterLabel = i18n.translate('indexPatternManagement.editIndexPattern.fields.schema', { + defaultMessage: 'Schema type', +}); + +const schemaAriaLabel = i18n.translate( + 'indexPatternManagement.editIndexPattern.fields.schemaAria', + { + defaultMessage: 'Filter schema types', + } +); + +const scriptedFieldFilterLabel = i18n.translate( + 'indexPatternManagement.editIndexPattern.fields.scriptedFieldFilter', + { + defaultMessage: 'All languages', + } +); + +const scriptedFieldAriaLabel = i18n.translate( + 'indexPatternManagement.editIndexPattern.fields.scriptedFieldFilterAria', + { + defaultMessage: 'Filter scripted field languages', + } +); + +const schemaOptionRuntime = i18n.translate( + 'indexPatternManagement.editIndexPattern.fields.runtime', + { + defaultMessage: 'Runtime', + } +); + +const schemaOptionIndexed = i18n.translate( + 'indexPatternManagement.editIndexPattern.fields.indexed', + { + defaultMessage: 'Indexed', + } +); + const filterPlaceholder = i18n.translate( 'indexPatternManagement.editIndexPattern.fields.filterPlaceholder', { @@ -80,19 +132,56 @@ export function Tabs({ location, refreshFields, }: TabsProps) { - const { application, uiSettings, docLinks, dataViewFieldEditor, overlays, theme } = + const { uiSettings, docLinks, dataViewFieldEditor, overlays, theme, dataViews } = useKibana().services; const [fieldFilter, setFieldFilter] = useState(''); - const [indexedFieldTypeFilter, setIndexedFieldTypeFilter] = useState(''); - const [scriptedFieldLanguageFilter, setScriptedFieldLanguageFilter] = useState(''); - const [indexedFieldTypes, setIndexedFieldType] = useState([]); - const [scriptedFieldLanguages, setScriptedFieldLanguages] = useState([]); const [syncingStateFunc, setSyncingStateFunc] = useState({ getCurrentTab: () => TAB_INDEXED_FIELDS, }); + const [scriptedFieldLanguageFilter, setScriptedFieldLanguageFilter] = useState([]); + const [isScriptedFieldFilterOpen, setIsScriptedFieldFilterOpen] = useState(false); + const [scriptedFieldLanguages, setScriptedFieldLanguages] = useState([]); + const [indexedFieldTypeFilter, setIndexedFieldTypeFilter] = useState([]); + const [isIndexedFilterOpen, setIsIndexedFilterOpen] = useState(false); + const [indexedFieldTypes, setIndexedFieldTypes] = useState([]); + const [schemaFieldTypeFilter, setSchemaFieldTypeFilter] = useState([]); + const [isSchemaFilterOpen, setIsSchemaFilterOpen] = useState(false); + const [schemaItems, setSchemaItems] = useState([ + { + value: 'runtime', + name: schemaOptionRuntime, + }, + { + value: 'indexed', + name: schemaOptionIndexed, + }, + ]); const closeEditorHandler = useRef<() => void | undefined>(); const { DeleteRuntimeFieldProvider } = dataViewFieldEditor; + const updateFilterItem = ( + items: FilterItems[], + index: number, + updater: (a: FilterItems[]) => void + ) => { + if (!items[index]) { + return; + } + + const newItems = [...items]; + + switch (newItems[index].checked) { + case 'on': + newItems[index].checked = undefined; + break; + + default: + newItems[index].checked = 'on'; + } + + updater(newItems); + }; + const refreshFilters = useCallback(() => { const tempIndexedFieldTypes: string[] = []; const tempScriptedFieldLanguages: string[] = []; @@ -113,10 +202,8 @@ export function Tabs({ } }); - setIndexedFieldType(convertToEuiSelectOption(tempIndexedFieldTypes, 'indexedFiledTypes')); - setScriptedFieldLanguages( - convertToEuiSelectOption(tempScriptedFieldLanguages, 'scriptedFieldLanguages') - ); + setIndexedFieldTypes(convertToEuiFilterOptions(tempIndexedFieldTypes)); + setScriptedFieldLanguages(convertToEuiFilterOptions(tempScriptedFieldLanguages)); }, [indexPattern]); const closeFieldEditor = useCallback(() => { @@ -154,7 +241,7 @@ export function Tabs({ [uiSettings] ); - const userEditPermission = !!application?.capabilities?.indexPatterns?.save; + const userEditPermission = dataViews.getCanSaveSync(); const getFilterSection = useCallback( (type: string) => { return ( @@ -172,13 +259,92 @@ export function Tabs({ {type === TAB_INDEXED_FIELDS && indexedFieldTypes.length > 0 && ( <> - setIndexedFieldTypeFilter(e.target.value)} - data-test-subj="indexedFieldTypeFilterDropdown" - aria-label={filterAriaLabel} - /> + + setIsIndexedFilterOpen(!isIndexedFilterOpen)} + isSelected={isIndexedFilterOpen} + numFilters={indexedFieldTypes.length} + hasActiveFilters={!!indexedFieldTypes.find((item) => item.checked === 'on')} + numActiveFilters={ + indexedFieldTypes.filter((item) => item.checked === 'on').length + } + > + {filterLabel} + + } + isOpen={isIndexedFilterOpen} + closePopover={() => setIsIndexedFilterOpen(false)} + > + {indexedFieldTypes.map((item, index) => ( + { + setIndexedFieldTypeFilter( + item.checked + ? indexedFieldTypeFilter.filter((f) => f !== item.value) + : [...indexedFieldTypeFilter, item.value] + ); + updateFilterItem(indexedFieldTypes, index, setIndexedFieldTypes); + }} + data-test-subj={`indexedFieldTypeFilterDropdown-option-${item.value}${ + item.checked ? '-checked' : '' + }`} + > + {item.name} + + ))} + + setIsSchemaFilterOpen(!isSchemaFilterOpen)} + isSelected={isSchemaFilterOpen} + numFilters={schemaItems.length} + hasActiveFilters={!!schemaItems.find((item) => item.checked === 'on')} + numActiveFilters={ + schemaItems.filter((item) => item.checked === 'on').length + } + > + {schemaFilterLabel} + + } + isOpen={isSchemaFilterOpen} + closePopover={() => setIsSchemaFilterOpen(false)} + > + {schemaItems.map((item, index) => ( + { + setSchemaFieldTypeFilter( + item.checked + ? schemaFieldTypeFilter.filter((f) => f !== item.value) + : [...schemaFieldTypeFilter, item.value] + ); + updateFilterItem(schemaItems, index, setSchemaItems); + }} + data-test-subj={`schemaFieldTypeFilterDropdown-option-${item.value}${ + item.checked ? '-checked' : '' + }`} + > + {item.name} + + ))} + + {userEditPermission && ( @@ -191,12 +357,52 @@ export function Tabs({ )} {type === TAB_SCRIPTED_FIELDS && scriptedFieldLanguages.length > 0 && ( - setScriptedFieldLanguageFilter(e.target.value)} - data-test-subj="scriptedFieldLanguageFilterDropdown" - /> + + setIsScriptedFieldFilterOpen(!isScriptedFieldFilterOpen)} + isSelected={isScriptedFieldFilterOpen} + numFilters={scriptedFieldLanguages.length} + hasActiveFilters={ + !!scriptedFieldLanguages.find((item) => item.checked === 'on') + } + numActiveFilters={ + scriptedFieldLanguages.filter((item) => item.checked === 'on').length + } + > + {scriptedFieldFilterLabel} + + } + isOpen={isScriptedFieldFilterOpen} + closePopover={() => setIsScriptedFieldFilterOpen(false)} + > + {scriptedFieldLanguages.map((item, index) => ( + { + setScriptedFieldLanguageFilter( + item.checked + ? scriptedFieldLanguageFilter.filter((f) => f !== item.value) + : [...scriptedFieldLanguageFilter, item.value] + ); + updateFilterItem(scriptedFieldLanguages, index, setScriptedFieldLanguages); + }} + data-test-subj={`scriptedFieldLanguageFilterDropdown-option-${item.value}${ + item.checked ? '-checked' : '' + }`} + > + {item.name} + + ))} + + )} @@ -206,8 +412,13 @@ export function Tabs({ fieldFilter, indexedFieldTypeFilter, indexedFieldTypes, + isIndexedFilterOpen, scriptedFieldLanguageFilter, scriptedFieldLanguages, + isScriptedFieldFilterOpen, + schemaItems, + schemaFieldTypeFilter, + isSchemaFilterOpen, openFieldEditor, userEditPermission, ] @@ -230,13 +441,15 @@ export function Tabs({ fieldFilter={fieldFilter} fieldWildcardMatcher={fieldWildcardMatcherDecorated} indexedFieldTypeFilter={indexedFieldTypeFilter} + schemaFieldTypeFilter={schemaFieldTypeFilter} helpers={{ editField: openFieldEditor, deleteField, getFieldInfo, }} openModal={overlays.openModal} - theme={theme} + theme={theme!} + userEditPermission={dataViews.getCanSaveSync()} /> )} @@ -260,6 +473,7 @@ export function Tabs({ }} onRemoveField={refreshFilters} painlessDocLink={docLinks.links.scriptedFields.painless} + userEditPermission={dataViews.getCanSaveSync()} /> ); @@ -289,6 +503,7 @@ export function Tabs({ history, indexPattern, indexedFieldTypeFilter, + schemaFieldTypeFilter, refreshFilters, scriptedFieldLanguageFilter, saveIndexPattern, @@ -297,6 +512,7 @@ export function Tabs({ refreshFields, overlays, theme, + dataViews, ] ); 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 0ea8d9d9e28f3..e82722b1a5127 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 @@ -105,36 +105,11 @@ export function getPath(field: DataViewField, indexPattern: DataView) { return `/dataView/${indexPattern?.id}/field/${encodeURIComponent(field.name)}`; } -const allTypesDropDown = i18n.translate( - 'indexPatternManagement.editIndexPattern.fields.allTypesDropDown', - { - defaultMessage: 'All field types', - } -); - -const allLangsDropDown = i18n.translate( - 'indexPatternManagement.editIndexPattern.fields.allLangsDropDown', - { - defaultMessage: 'All languages', - } -); - -export function convertToEuiSelectOption(options: string[], type: string) { - const euiOptions = - options.length > 0 - ? [ - { - value: '', - text: type === 'scriptedFieldLanguages' ? allLangsDropDown : allTypesDropDown, - }, - ] - : []; - return euiOptions.concat( - uniq(options).map((option) => { - return { - value: option, - text: option, - }; - }) - ); +export function convertToEuiFilterOptions(options: string[]) { + return uniq(options).map((option) => { + return { + value: option, + name: option, + }; + }); } 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 1b876e34a42fb..e4978acbc9d17 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 @@ -39,7 +39,7 @@ export async function mountManagementSection( params: ManagementAppMountParams ) { const [ - { chrome, application, uiSettings, notifications, overlays, http, docLinks, theme }, + { chrome, uiSettings, notifications, overlays, http, docLinks, theme }, { data, dataViewFieldEditor, dataViewEditor, dataViews, fieldFormats }, indexPatternManagementStart, ] = await getStartServices(); @@ -51,7 +51,6 @@ export async function mountManagementSection( const deps: IndexPatternManagmentContext = { chrome, - application, uiSettings, notifications, overlays, diff --git a/src/plugins/data_view_management/public/mocks.ts b/src/plugins/data_view_management/public/mocks.ts index 3404ca4912c88..54c1900d37f4c 100644 --- a/src/plugins/data_view_management/public/mocks.ts +++ b/src/plugins/data_view_management/public/mocks.ts @@ -13,6 +13,7 @@ import { urlForwardingPluginMock } from '../../url_forwarding/public/mocks'; import { dataPluginMock } from '../../data/public/mocks'; import { indexPatternFieldEditorPluginMock } from '../../data_view_field_editor/public/mocks'; import { indexPatternEditorPluginMock } from '../../data_view_editor/public/mocks'; +import { dataViewPluginMocks } from '../../data_views/public/mocks'; import { IndexPatternManagementSetup, IndexPatternManagementStart, @@ -54,15 +55,14 @@ const docLinks = { const createIndexPatternManagmentContext = (): { [key in keyof IndexPatternManagmentContext]: any; } => { - const { chrome, application, uiSettings, notifications, overlays } = coreMock.createStart(); + const { chrome, uiSettings, notifications, overlays } = coreMock.createStart(); const { http } = coreMock.createSetup(); const data = dataPluginMock.createStartContract(); const dataViewFieldEditor = indexPatternFieldEditorPluginMock.createStartContract(); - const dataViews = data.indexPatterns; + const dataViews = dataViewPluginMocks.createStartContract(); return { chrome, - application, uiSettings, notifications, overlays, diff --git a/src/plugins/data_view_management/public/types.ts b/src/plugins/data_view_management/public/types.ts index dc5e0198a64f1..f0a79416892ef 100644 --- a/src/plugins/data_view_management/public/types.ts +++ b/src/plugins/data_view_management/public/types.ts @@ -8,7 +8,6 @@ import { ChromeStart, - ApplicationStart, IUiSettingsClient, OverlayStart, NotificationsStart, @@ -26,7 +25,6 @@ import { FieldFormatsStart } from '../../field_formats/public'; export interface IndexPatternManagmentContext { chrome: ChromeStart; - application: ApplicationStart; uiSettings: IUiSettingsClient; notifications: NotificationsStart; overlays: OverlayStart; diff --git a/src/plugins/data_views/public/mocks.ts b/src/plugins/data_views/public/mocks.ts index c9aece61c4e02..61713c9406c23 100644 --- a/src/plugins/data_views/public/mocks.ts +++ b/src/plugins/data_views/public/mocks.ts @@ -27,6 +27,7 @@ const createStartContract = (): Start => { }), get: jest.fn().mockReturnValue(Promise.resolve({})), clearCache: jest.fn(), + getCanSaveSync: jest.fn(), } as unknown as jest.Mocked; }; diff --git a/src/plugins/discover/public/utils/get_sharing_data.test.ts b/src/plugins/discover/public/utils/get_sharing_data.test.ts index aef9bcff15403..cc37599ef12c0 100644 --- a/src/plugins/discover/public/utils/get_sharing_data.test.ts +++ b/src/plugins/discover/public/utils/get_sharing_data.test.ts @@ -11,7 +11,11 @@ import type { DataView } from 'src/plugins/data/common'; import type { DiscoverServices } from '../build_services'; import { dataPluginMock } from '../../../data/public/mocks'; import { createSearchSourceMock } from '../../../data/common/search/search_source/mocks'; -import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../common'; +import { + DOC_HIDE_TIME_COLUMN_SETTING, + SORT_DEFAULT_ORDER_SETTING, + SEARCH_FIELDS_FROM_SOURCE, +} from '../../common'; import { indexPatternMock } from '../__mocks__/index_pattern'; import { getSharingData, showPublicUrlSwitch } from './get_sharing_data'; @@ -23,6 +27,9 @@ describe('getSharingData', () => { data: dataPluginMock.createStartContract(), uiSettings: { get: (key: string) => { + if (key === SEARCH_FIELDS_FROM_SOURCE) { + return false; + } if (key === SORT_DEFAULT_ORDER_SETTING) { return 'desc'; } @@ -64,6 +71,91 @@ describe('getSharingData', () => { `); }); + test('getSearchSource does not add fields to the searchSource', async () => { + const index = { ...indexPatternMock } as DataView; + index.timeFieldName = 'cool-timefield'; + const searchSourceMock = createSearchSourceMock({ index }); + const { getSearchSource } = await getSharingData(searchSourceMock, {}, services); + expect(getSearchSource()).toMatchInlineSnapshot(` + Object { + "index": "the-index-pattern-id", + "sort": Array [ + Object { + "_doc": "desc", + }, + ], + } + `); + }); + + test(`getSearchSource does not add fields to the searchSource with 'discover:searchFieldsFromSource=true'`, async () => { + const originalGet = services.uiSettings.get; + services.uiSettings = { + get: (key: string, ...args: unknown[]) => { + if (key === SEARCH_FIELDS_FROM_SOURCE) { + return true; + } + return originalGet(key, ...args); + }, + } as unknown as IUiSettingsClient; + const index = { ...indexPatternMock } as DataView; + index.timeFieldName = 'cool-timefield'; + const searchSourceMock = createSearchSourceMock({ index }); + const { getSearchSource } = await getSharingData( + searchSourceMock, + { + columns: [ + 'cool-field-1', + 'cool-field-2', + 'cool-field-3', + 'cool-field-4', + 'cool-field-5', + 'cool-field-6', + ], + }, + services + ); + expect(getSearchSource()).toMatchInlineSnapshot(` + Object { + "index": "the-index-pattern-id", + "sort": Array [ + Object { + "_doc": "desc", + }, + ], + } + `); + }); + + test('getSearchSource does add fields to the searchSource when columns are selected', async () => { + const index = { ...indexPatternMock } as DataView; + index.timeFieldName = 'cool-timefield'; + const searchSourceMock = createSearchSourceMock({ index }); + const { getSearchSource } = await getSharingData( + searchSourceMock, + { + columns: [ + 'cool-field-1', + 'cool-field-2', + 'cool-field-3', + 'cool-field-4', + 'cool-field-5', + 'cool-field-6', + ], + }, + services + ); + expect(getSearchSource().fields).toStrictEqual([ + 'cool-timefield', + 'cool-field-1', + 'cool-field-2', + 'cool-field-3', + 'cool-field-4', + 'cool-field-5', + 'cool-field-6', + ]); + }); + test('fields have prepended timeField', async () => { const index = { ...indexPatternMock } as DataView; index.timeFieldName = 'cool-timefield'; diff --git a/src/plugins/discover/public/utils/get_sharing_data.ts b/src/plugins/discover/public/utils/get_sharing_data.ts index e14ae252da95e..cd00fc5e3c70e 100644 --- a/src/plugins/discover/public/utils/get_sharing_data.ts +++ b/src/plugins/discover/public/utils/get_sharing_data.ts @@ -10,7 +10,11 @@ import type { Capabilities } from 'kibana/public'; import type { IUiSettingsClient } from 'kibana/public'; import type { DataPublicPluginStart } from 'src/plugins/data/public'; import type { Filter, ISearchSource, SerializedSearchSourceFields } from 'src/plugins/data/common'; -import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../common'; +import { + DOC_HIDE_TIME_COLUMN_SETTING, + SEARCH_FIELDS_FROM_SOURCE, + SORT_DEFAULT_ORDER_SETTING, +} from '../../common'; import type { SavedSearch, SortOrder } from '../services/saved_searches'; import { getSortForSearchSource } from '../components/doc_table'; import { AppState } from '../application/main/services/discover_state'; @@ -72,6 +76,15 @@ export async function getSharingData( searchSource.setField('filter', filter); } + /* + * For downstream querying performance, the searchSource object must have fields set. + * Otherwise, the requests will ask for all fields, even if only a few are really needed. + * Discover does not set fields, since having all fields is needed for the UI. + */ + const useFieldsApi = !config.get(SEARCH_FIELDS_FROM_SOURCE); + if (useFieldsApi && columns.length) { + searchSource.setField('fields', columns); + } return searchSource.getSerializedFields(true); }, columns, diff --git a/src/plugins/home/public/application/components/__snapshots__/home.test.tsx.snap b/src/plugins/home/public/application/components/__snapshots__/home.test.tsx.snap index 373fc8ea59b6f..ab6ad1b6cc0c5 100644 --- a/src/plugins/home/public/application/components/__snapshots__/home.test.tsx.snap +++ b/src/plugins/home/public/application/components/__snapshots__/home.test.tsx.snap @@ -396,6 +396,7 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to true when th }, "delete": [MockFunction], "externalUrl": Object { + "isInternalUrl": [MockFunction], "validateUrl": [MockFunction], }, "fetch": [MockFunction], @@ -464,6 +465,7 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to true when th }, "delete": [MockFunction], "externalUrl": Object { + "isInternalUrl": [MockFunction], "validateUrl": [MockFunction], }, "fetch": [MockFunction], @@ -533,6 +535,7 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to true when th }, "delete": [MockFunction], "externalUrl": Object { + "isInternalUrl": [MockFunction], "validateUrl": [MockFunction], }, "fetch": [MockFunction], diff --git a/src/plugins/kibana_react/public/code_editor/__snapshots__/code_editor.test.tsx.snap b/src/plugins/kibana_react/public/code_editor/__snapshots__/code_editor.test.tsx.snap index b05abbcece0b9..9a4511f8b03f5 100644 --- a/src/plugins/kibana_react/public/code_editor/__snapshots__/code_editor.test.tsx.snap +++ b/src/plugins/kibana_react/public/code_editor/__snapshots__/code_editor.test.tsx.snap @@ -126,6 +126,7 @@ exports[` is rendered 1`] = ` >
is rendered 1`] = ` /> - + -
-
-