From 87507ff863b367e543f3a0e3725ec16bdcbd0c96 Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Tue, 22 Oct 2024 14:05:58 +0200 Subject: [PATCH] Redirect ECS k8s entities to dashboards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create entity_client functions Create entity_client functions Fix entityLatest flatten object Fix redirection to service overview Fix redirection to service overview Add tests Add tests Refactoring and tests Clean up [CI] Auto-commit changed files from 'node scripts/yarn_deduplicate' fix after rebase Fix build [Dataset Quality]Fix elastic doc test (#197835) Found a bug while backporting another PR. The elastic docs in main always refer to master, but once a release is cut, it check for specific version in the URL. hence updated the test P.S: This does not need backport to 8.x as this has already been fixed in 8.x [FTR][Ownership] Assign visualize, etc (#197664) Assign test files to small number of reviewers Assigned visualize due to the name Assigned functional_execution_context due to https://github.com/elastic/kibana/blob/main/x-pack/test/functional_execution_context/plugins/alerts/kibana.jsonc#L4 Assigned kubernetes_security per https://github.com/elastic/kibana/blob/main/x-pack/plugins/kubernetes_security/kibana.jsonc#L4 Assigned licensing_plugin due to https://github.com/elastic/kibana/blob/main/x-pack/plugins/licensing/kibana.jsonc#L4 Assigned rule_registry due to https://github.com/elastic/kibana/blob/main/x-pack/plugins/rule_registry/kibana.jsonc#L4-L5 Assigned usage_collection due to https://github.com/elastic/kibana/blob/main/api_docs/usage_collection.mdx#L18 - It says `Contact @elastic/kibana-core for questions regarding this plugin.` Assigned observability_onboarding_api_integration due to https://github.com/elastic/kibana/blob/main/api_docs/observability_onboarding.mdx#L18 - It says `Contact @elastic/obs-ux-logs-team for questions regarding this plugin.` Contributes to: https://github.com/elastic/kibana/issues/194817 [React@18 failing tests] Dataset quality handles user privileges (#197830) [Security Solution] Add data source editable component (#196948) **Partially addresses:** https://github.com/elastic/kibana/issues/171520 This PR adds is built on top of https://github.com/elastic/kibana/pull/193828 and add a Data Source editable component for final edit side of Three Way Diff tab of the upgrade prebuilt rule workflow. https://github.com/elastic/kibana/issues/171520 required adding editable components for each field diffable rule field. It imposes some difficulties since it's quite problematic to reuse existing especially complex components like Data Source from Define Rule step component. This PR make little refactoring to the Define Rule step component to make it simpler and make it easier to reuse Data Source related code chunks scattered in Define Rule step component. You may notice some copy-paste chunks of Data Source editable component in the PR. At this stage it's the simplest way to proceed to avoid huge refactoring and potential new bugs. Taking into account deadlines for the task it looks like a good trade off. There is a plan to work on improvements for rules creation/editing forms later on. search: move getting started to footer (#197849) Moved the `Getting Started` link to the footer ![image](https://github.com/user-attachments/assets/4d388fba-c6a4-4a72-b9f1-5ea839e435fe) [OpenAPI][DOCS] Add descriptions, examples, responses for role APIs (#195527) Co-authored-by: Elena Shostak <165678770+elena-shostak@users.noreply.github.com> [Security Solution] Unskips Timeline Cypress tests (#195721) Fixes below Flaky tests issues : - [x] https://github.com/elastic/kibana/issues/180688 - [x] https://github.com/elastic/kibana/issues/176945 - [x] https://github.com/elastic/kibana/issues/175180 - [x] https://github.com/elastic/kibana/issues/181466 - [x] https://github.com/elastic/kibana/issues/182021 - [x] https://github.com/elastic/kibana/issues/183085 - [x] https://github.com/elastic/kibana/issues/175180 --------- Co-authored-by: Michael Olorunnisola [ci] Use es snapshot cache on miscellaneous steps, adjust schedule (#197294) The schedule adjustment is due to 7.17 verification taking longer than other branches. Currently, we only rebuild once when main is updated. This is a stopgap until a cache-only update can be introduced to avoid continuous image rebuilds. [SR] Add tooltips for disabled fields on managed SLM repository and policy (#196565) Closes https://github.com/elastic/kibana/issues/173124#issuecomment-2352968634 by adding tooltips details when hovering the disabled SLM repository or policy fields. **SLM managed repository** ![Screenshot 2024-10-16 at 1 38 19](https://github.com/user-attachments/assets/3bd11ea5-f846-433f-8615-b51de184336b) **SLM managed policy** ![Screenshot 2024-10-16 at 1 37 57](https://github.com/user-attachments/assets/d11757bd-bda5-4b4f-8c1e-e795e01b1fa2) - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) - [x] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Elena Stoeva <59341489+ElenaStoeva@users.noreply.github.com> [Security GenAI] When indices referenced in KB index entries are deleted from OUTSIDE the AI Assistant KB UI, there is not indication to the user (#197156) (#197722) Bug https://github.com/elastic/kibana/issues/197156 This is a UI part of the bug that warns a user about missing indices used in knowledge base entries. 1. Add an index entry that uses existing index 2. Remove that index 3. Go back to knowledge base entries page 4. You should see warning icon next to the name of the index entry which uses removed index. Also, when you edit that entry you will see `Index doesn't exist` error next to the `Index` field in the flyout Screenshot 2024-10-24 at 19 54 36 Screenshot 2024-10-24 at 19 54 52 Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios [Security Solution][Endpoint] Ensure that DS indices for response actions are created prior to sending action to Endpoint (#196953) PR adds changes to Security Solution so that DOT indices (restricted in Serverless) are created in Kibana prior to Elastic Defend (Endpoint) attempting to stream documents to these indices. The indices that are now created in kibana are: - `.logs-endpoint.diagnostic.collection-` - `.logs-endpoint.action.responses-` - `.logs-endpoint.heartbeat-` _(⚠️ created only in serverless only)_ - Added support for the following two server-side extension points: - `packagePolicyPostUpdate` : callbacks invoked after an integration policy has been updated successfully - `agentPolicyPostUpdate` : callbacks invoked after an agent policy has been updated successfully - Logic was added to the following Fleet server-side extension points that checks if the necessary indices exist and if not, it creates them: - After creating an Elastic Defend integration policy - After updating an Elastic Defend integration policy - After updating a Fleet Agent Policy that includes Elastic Defend integration policy Mark connector param validation failures as user errors (#197812) Resolves https://github.com/elastic/response-ops-team/issues/255 In this PR, I'm changing the type of error thrown when connector parameter validation fails so it indicates it's a user type of error. This will allow us to exclude these errors from our serverless monitoring given the users define the parameters the connectors receive when they run. Mainly via alerting rule mustache templates, which are easy to render empty strings and such. [Security Solution][Notes] - fix createdBy filter for notes management page (#197706) [Search][Fix] Index Details: poll mappings (#197885) [Security GenAI] When a "global" Knowledge Base entry is updated to "private", a duplicate "private" entry gets created and the global entry remains unchanged (#197157) (#197516) Original ticket describing the BUG: https://github.com/elastic/kibana/issues/197157 These changes fix two issues: 1. Updating an entry from Global to Private duplicates it. After discussing with the team we decided that this is an expected behaviour and we would add a modal dialog which warns users about it. See more details here https://github.com/elastic/kibana/issues/197157#issuecomment-2432592394 2. Editing Private entry and switching the sharing option twice from Private => Global => Private causes the issue where we would treat selected entry as a new one and thus calling "create entry" instead of "update". * Edit private entry * Update entry's name * Switch sharing option to Global * Switch sharing option back to Private * Save the entry **Current behaviour**: a new private entry is created **Expected behaviour**: existing private entry is updated https://github.com/user-attachments/assets/e11e14bd-c557-401e-a23f-e01ac7aedf30 Delete any items that are not applicable to this PR. - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios Update docker.elastic.co/wolfi/chainguard-base:latest Docker digest to de4d5b0 (main) (#197917) [Response Ops][Maintenance Window] Fix Maintenance Window Wildcard Scoped Queries (#194777) Issue: https://github.com/elastic/sdh-kibana/issues/4923 Fixes maintenance window scoped query using wildcards by injecting the `analyze_wildcard` property to the DSL used to determine which alerts should be associated with the maintenance window. Also fixes the update route to correctly take into account the user's `allowLeadingWildcard` flag. It was implemented for the create route but not the update route. Fixes: https://github.com/elastic/kibana/issues/194763 1. Install sample data: ![image](https://github.com/user-attachments/assets/4be72fc8-e4ab-47a3-b5db-48f97b1827ae) 2. Create a maintenance window with the following scoped query: ![image](https://github.com/user-attachments/assets/e2d37fd0-b957-4e76-bea3-8d954651c557) 3. Create a ES query rule and trigger actions: ![image](https://github.com/user-attachments/assets/551f5145-9ab7-48c4-a48e-e674b4f0509a) 4. Assert the `maintenance_window_id` on the 4 alerts are set ![image](https://github.com/user-attachments/assets/7ace95d3-d992-4305-a564-cf3004c9ae9e) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios) --------- Co-authored-by: Elastic Machine [api-docs] 2024-10-27 Daily api_docs build (#197930) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/873 [Cloud Security] Clicking on Contextual Flyout popout Icon now opens page in new tab (#196763) Currently when user clicks on Popout icon on Misconfiguration or Vulnerabilities Contextual flyout, user gets redirected to Findings page but in the same tab. Popout Icon implies that it should navigate user to other page on separate Tabs as such the current behaviour is not right. This PR addresses that issue --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> [ES|QL] Update function metadata (#197940) This PR updates the function definitions and inline docs based on the latest metadata from Elasticsearch. [Security Solution] Remove index pattern field from Sourcerer (#190113) This PR removes index pattern field from the sourcerer model, replacing it with direct access to data view spec. The end goal for the sourcerer is to just utilize platform wide Data View Types, instead of some custom abstractions / containers such as indexPattern field which is effectively a DataViewSpec, just packed up differently. [Cloud Security] add posture type for CSPM dashboard accounts link (#197633) - fixes https://github.com/elastic/security-team/issues/10914 [Observability Onboarding] Show search bar even when category is not selected (#197825) Closes https://github.com/elastic/observability-dev/issues/4065 🔒 Fixes an issue when search bar is not visible unless a category is selected. ![CleanShot 2024-10-25 at 14 53 44@2x](https://github.com/user-attachments/assets/774d2fe2-e4f0-4a46-a851-a0f756a96b12) Fix typo in the file name CR fixes [ResponseOps][Cases] Miscount of total numbers of alerts in telemetry (#196112) Closes https://github.com/elastic/kibana/issues/177208 Problem: - the metrics collected in telemetry for alerts don't count the total number of alerts on a case correctly. Solution: - added new aggregation function: getUniqueAlertCommentsCountQuery, which is now responsible for defining the cardinality aggregation for counting unique alert comments by alertId. - in the aggs section of the savedObjectsClient.find, the new cardinality aggregation query was added - the total number of alerts is updated to be the result extracted from the new aggregation Example: ![Screenshot 2024-10-22 at 15 20 40](https://github.com/user-attachments/assets/c418c82e-2e35-4c7f-969d-7f4f25bdbc9d) - in the telemetry object, we have the following info: Screenshot 2024-10-22 at 15 21 40 --------- Co-authored-by: Antonio [ResponseOps][Cases]Add instructions of how to create a connector in the create case form (#197041) Closes https://github.com/elastic/kibana/issues/189246 - A helper text was added in the create case form to tell the user that needs to create a connector in the stack management > cases > settings before attaching it to a case - A new "add connector" button was placed in the stack management > cases > settings page, in the connectors section https://github.com/user-attachments/assets/7866b41a-11b5-4ca3-bd65-988412ab1e2f --------- Co-authored-by: Antonio [Discover][ES|QL] Rename Documents tab to Results (#197833) This PR renames Documents label to Results for ES|QL mode. Screenshot 2024-10-25 at 15 44 32 Screenshot 2024-10-25 at 15 52 55 - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios [EDR Workflows] Enable Blocklist CY in MKI (#197952) Since adding this test file was tied to changes in Kibana, we initially couldn’t enable it in the MKI. The MKI relies on a Kibana image built from the main branch, and at that time, the necessary changes for these tests to pass hadn’t yet been merged. Now that these updates are included in the main branch, the Kibana image used in MKI has the required changes, so we can proceed with enabling the tests. Manual MKI run - https://buildkite.com/elastic/kibana-serverless-security-solution-quality-gate-defend-workflows/builds/1545 [Security Solution][Detection Engine] removes legacy alerting endpoints from Security Solution dev scripts (#197424) - addresses https://github.com/elastic/kibana/issues/95842 --------- Co-authored-by: Ryland Herrick [CodeQL] Local run script (#194272) This PR introduces a script that allows developers to run CodeQL analysis locally. It uses a Docker container with prebuilt CodeQL queries to facilitate easy setup and execution. The script has the following key steps: - Creating a CodeQL database from the source code. The database is essentially a representation of the codebase that CodeQL uses to analyze for potential issues. - Running the analysis on the created database, `javascript-security-and-quality` suit is used. ``` bash scripts/codeql/quick_check.sh -s path/to/your-source-dir ``` For example ``` bash scripts/codeql/quick_check.sh -s ./x-pack/plugins/security_solution/public/common/components/ml/conditional_links ``` The `-s` option allows you to specify the path to the source code directory that you wish to analyze. Checked the ability to use MSFT image for local run https://github.com/microsoft/codeql-container. Turned out it has several problems: 1. The published one has an error with [execute permissions](https://github.com/microsoft/codeql-container/issues/53). 2. Container has outdated nodejs version, so it didn't parse our syntax (like `??`) and failed. 3. The technique used in the repository to download the CodeQL binaries and precompile the queries is outdated in the sense that GitHub now offers pre-compiled queries you can just download. Follow this [comment](https://github.com/microsoft/codeql-container/issues/53#issuecomment-1875879512). Taking this into consideration I have created a lightweight docker image without extraneous dependencies for go/.net/java. There are issues sometimes when analyze run returns no results, particularly when analyzing a single folder. It might be due to the missing context for the data flow graph CodeQL generates or context for interdependencies. This is actually a trade off of running it locally for a subset of source directories. We need to explicitly state that in the documentation and advise to expand the scope of source code directories involved for local scan. Documentation for triaging issues will be updated separately. __Closes: https://github.com/elastic/kibana/issues/195740__ chore(slo): remove tests migrated to agnostic framework (#197711) Resolves https://github.com/elastic/kibana/issues/183397 This PR is a follow up of https://github.com/elastic/kibana/pull/195927, that removes the old and migrated tests to the agnostic framework. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Dzmitry Lemechko [Response Ops][Task Manager] change task claiming interface to stop using observables (#196196) Resolves https://github.com/elastic/kibana/issues/184952 Changing task claimers to return promises instead of observables. This is a code refactor and should not have any effect on task claiming functionality. --------- Co-authored-by: Elastic Machine [Fleet] Fix agents count in agent list table and add tooltip with correct info (#197834) Fixes https://github.com/elastic/kibana/issues/195441 Selection agent count on agent list table gets incorrect when there are multiple hosted agents, especially if they are on inactive state. In fact to calculate the selected number of agents we were getting hosted agents, but without taking into account the filtering applied on the page, i.e. we were always getting all the hosted agent (inactive too). This caused the final calculation to be off. In this PR I'm fixing [the query](https://github.com/elastic/kibana/pull/197834/files#diff-9707a4b93a96749876e4cf173a0b39cd5a620e311e2652c5ed4b8670ca7e6becR309-R320) used to get those agents to take in account the filters and I'm also adding a small tooltip that breaks up the number of agents (selected, total, hosted) - Make sure to have many agents, hosted and not in different states (inactive, unenrolled) - To make a hosted agent inactive follow the steps explained [here](https://github.com/elastic/kibana/issues/195441) - Verify that the selection numbers are correct: select agents on all pages and hover on the new tooltip shown besides the "selected agents". This number should match the number shown on the actions dropdown Screenshot 2024-10-25 at 17 00 44 Screenshot 2024-10-25 at 17 00 59 https://github.com/user-attachments/assets/c153c491-29a1-481c-a3e3-25bab6412963 - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Elastic Machine [Cloud Security] exclude unknown findings from compliance score calculation (#197829) Findings from 3rd party date can have `result.evaluation: unknown`. This leads to incorrect posture/compliance score in our flows. This PR removes these findings from the score calculation and graphical representation. properly introducing `unknown` in the compliance score UX flows will be solved separately - fixes https://github.com/elastic/security-team/issues/10913 Screenshot 2024-10-25 at 14 19 03 Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) [Authz] OAS Descriptions for Route Authz (#197001) Closes https://github.com/elastic/kibana/issues/191714 Update process router to generate authz descriptions based on the new Route Security objects. Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine Add tags to connector run failures indicating if it's user or framework error (#197818) Resolves https://github.com/elastic/kibana/issues/197315 In this PR, I'm adding the following tags to the connector failure logs so it makes it easier to filter for systematic errors. - `connector-run-failed` for logs specific to connector run failures - `user-error` for errors caused by the user - `framework-error` for systematic errors You can either use the jest test to observe the returned flags or set your logging to JSON and make connectors fail. kibana.yml to set logging to JSON ``` logging: appenders: json-layout: type: console layout: type: json root: appenders: [json-layout] ``` [EDR Workflows] Fix Cypress tests failing on Alerts step (#197384) Delete data when clearing security entity store (#197938) Fixed a bug where the "Clear all entities" button in the security entity store didn't delete data due to a missing query parameter. FTR SAML Auth - Adjust stateful internal request header (#197994) This PR adds the `x-elastic-internal-origin` header to the stateful internal request headers used by FTR. This fixes an issue that we're seeing when running deployment agnostic tests against ESS on 9.0.0-SNAPSHOT. [SKIP ON MKI] reporting datastream (#197958) See details: https://github.com/elastic/kibana/issues/197955 [SKIP ON MKI] discover reporting (#197959) See details: https://github.com/elastic/kibana/issues/197957 fix: [Stateful:Connectors:New connector page]Configuration form missing instructions and field names from announcement (#197963) Closes: #197586 Forms, requiring user input, should have clear instructions on how to fill them. Specific fields can have their own help (guidance) text on how to fill them with examples. All fields which are present in the form can be programmatically determined, especially for the users using assistive technology to understand what fields are present, what input is expected. 1. `aria-label` values ​​are explicitly set for `ConnectorConfigurationField` child components. I suspect that due to the dynamic nature of this component, the standard mechanism does not work properly. image [ES|QL] detect the type of `COUNT(*)` (#197914) We weren't properly detecting the type of the expression `COUNT(*)`. Now we are! Before: Screenshot 2024-10-25 at 4 38 08 PM After: Screenshot 2024-10-25 at 4 35 44 PM - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios Co-authored-by: Stratoula Kalafateli [ES|QL] remove signatures from function suggestion labels (#197842) Showing a single acceptable function signature in the suggestions list is confusing since it may imply that other options are not accepted. Instead, this PR follows the Typescript tooling and simply shows the function name in the list. ![Screenshot 2024-10-25 at 8 17 38 AM](https://github.com/user-attachments/assets/9caf4998-b144-45d4-8a53-b41846714d5b) The signatures are still available in the details flyout. Screenshot 2024-10-25 at 8 50 01 AM - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios Co-authored-by: Stratoula Kalafateli [Response Ops][Task Manager] Propagate `msearch` error status code so backpressure mechanism responds correctly (#197501) Resolves https://github.com/elastic/response-ops-team/issues/240 Creating an `MsearchError` class that preserves the status code from any msearch errors. These errors are already piped to the managed configuration observable that watches for and responds to ES errors from the update by query claim strategy so I updated that filter to filter for msearch 429 and 503 errors as well. 1. Make sure you're using the mget claim strategy (`xpack.task_manager.claim_strategy: 'mget'`) and start ES and Kibana. 2. Inject a 429 error into an msearch response. ``` --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -571,6 +571,8 @@ export class TaskStore { }); const { responses } = result; + responses[0].status = 429; + const versionMap = this.createVersionMap([]); ``` 3. See task manager log the msearch errors and eventually reduce polling capacity ``` [2024-10-23T15:35:59.255-04:00][ERROR][plugins.taskManager] Failed to poll for work: Unexpected status code from taskStore::msearch: 429 [2024-10-23T15:35:59.756-04:00][ERROR][plugins.taskManager] Failed to poll for work: Unexpected status code from taskStore::msearch: 429 [2024-10-23T15:36:00.257-04:00][ERROR][plugins.taskManager] Failed to poll for work: Unexpected status code from taskStore::msearch: 429 [2024-10-23T15:36:00.757-04:00][ERROR][plugins.taskManager] Failed to poll for work: Unexpected status code from taskStore::msearch: 429 ... [2024-10-23T15:36:06.267-04:00][WARN ][plugins.taskManager] Poll interval configuration is temporarily increased after Elasticsearch returned 19 "too many request" and/or "execute [inline] script" error(s). [2024-10-23T15:36:06.268-04:00][WARN ][plugins.taskManager] Capacity configuration is temporarily reduced after Elasticsearch returned 19 "too many request" and/or "execute [inline] script" error(s). ``` --------- Co-authored-by: Elastic Machine [Stateful sidenav] Fix dashboard listing breadcrumbs (#197986) [Onboarding] Check for user privileges before creating an API key (#197964) Resolves https://github.com/elastic/kibana/issues/192983 Check for user privileges before creating an API key Screenshot 2024-10-28 at 10 28 58 [Fleet] Couple agent and package policies spaces (#197487) Consolidate Rule schemas (#195613) Towards: #172513 This PR removes `RawRule` type from `alerting/server/type` and `RuleAttributes` schema/types. And uses the `RawRule` that is used for ModelVersions instead of them. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Improve header button spacing (#197896) Closes #197873 - Fix spacing between 'Give feedback' and AI button. - While in the neighborhood, I noticed the search button had some extra padding, so I fixed that quick too. - Lastly, I pushed the project switcher to the far right. This is only used for local development of Serverless and was otherwise appearing between production buttons. To test, you'll need to run this in serverless mode where the 'Give feedback' button appears. You can force it on by setting the following line equal to `true`. https://github.com/elastic/kibana/blob/ae9c0d385015f3068a04af46678e18e2f00b519a/src/plugins/guided_onboarding/public/plugin.tsx#L50 Co-authored-by: Elastic Machine [Security Solution][Detection Engine] fixes preview logs issue when switching between rules (#197098) - addresses https://github.com/elastic/kibana/issues/196616 [Lens] fix showing points on line by default (#197828) Fix the missing style to show points in line charts. Line charts should show data points whenever the distance between points is larger than 40px. [Fleet] Fix flaky agentless test (#197951) Fixes https://github.com/elastic/kibana/issues/189038 Attempt to fix [this flaky test ](https://buildkite.com/elastic/kibana-on-merge/builds/53472#0192c57d-51ca-4b9b-a934-dc13b0b9b7ca) failing with ``` Timed out in waitForNextUpdate after 1000ms. --   |     | at waitForNextUpdate (node_modules/@testing-library/react-hooks/lib/core/asyncUtils.js:96:13) ``` I'm adding a longer timeout hoping to resolve this issue. There is no way to run jest tests with flaky test runner so I'm not sure how to verify that the flakiness is really gone. --------- Co-authored-by: Elastic Machine Serverless tests - enable dot-prefixed index validation (#197141) This PR enables Elasticsearch dot-prefixed index validation for serverless tests. [ObsUx][Infra] Remove no longer used feature flags for GA features (#197684) Closes #197612 This PR removes the feature flags (`observability:enableInfrastructureHostsView` and `enableInfrastructureContainerAssetView` ) for host and container views Feature settings under `Infrastructure > Settings` (ignore the profiling one) | Before | After | | ------ | ----- | |![image](https://github.com/user-attachments/assets/f7ee9585-e96c-4492-9116-8de3c5e0c9c6) | ![image](https://github.com/user-attachments/assets/1c75e229-bd29-45c5-a354-cfdcb324ea9d) | The feature flags should not appear in the settings The Host menu item should be visible The Container asset views should be always enabled and visible (without an option to disable them) The Host asset views should be always enabled and visible (without an option to disable them) https://github.com/user-attachments/assets/a4d574d0-2669-4f96-88a4-a40c2f5023c2 do not set full screen mode on ExitFullScreenButton re-render (#198012) https://github.com/elastic/kibana/pull/194892 is refactoring [DashboardRenderer](https://github.com/elastic/kibana/blob/3391344e8dc8377d359b918521b6c48838cde8ae/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx) component to replace Dashboard Embeddable with a plain old javascript object. Dashboard Embeddable rendered its contents in a new react tree. The new implementation does not. Since the new implementation does not render the dashboard in a new react tree, any re-render in `DashboardViewport` parent components causes `ExitFullScreenButton` to re-render. In its current form, re-rendering `ExitFullScreenButton` calls `onExit`, which causing dashboard to exit full screen mode. This PR makes use of `useCallback` to fix the issue where re-rending `ExitFullScreenButton` calls `onExit`. 1) Open dashboard that ships with sample web logs data set 2) switch to view mode 3) click "Full screen" button 4) Maximize a panel. Verify dashboard stays in full screen mode. [ci] Run linting before tests (#197310) Linting is a frequent source of build failures. By increasing the cpu count we can run this check before starting our highly-parallel tests without impacting total build time. Fix documentation for session lifespan default (#198065) This pull request includes an update to the `docs/settings/security-settings.asciidoc` file to clarify the default session lifespan settings for different installation environments. Documentation update: * [`docs/settings/security-settings.asciidoc`](diffhunk://#diff-97a4c4e3696b33b246f55ddd794608530b693f0a7a66ae1361a32b67c7461523L204-R204): Clarified that the default session lifespan is 30 days for on-prem installations and 24 hours for Elastic Cloud installations. [FTR][Ownership] Assign aiops, custom branding, etc (#197468) Assign test files to small number of reviewers Assigned custom_branding due to https://github.com/elastic/kibana/blob/main/x-pack/plugins/custom_branding/kibana.jsonc#L4 Assigned response_ops_docs due to the name Assigned monitoring due to https://github.com/elastic/kibana/blob/main/x-pack/plugins/monitoring/kibana.jsonc#L4 Assigned so managment due to https://github.com/elastic/kibana/blob/main/src/plugins/saved_objects_management/kibana.jsonc#L4 Assigned aiops due to https://github.com/elastic/kibana/blob/main/x-pack/plugins/aiops/kibana.jsonc#L4 Assigned banners_functional due to Pierre being all over the git blame. :lol: Assigned x-pack/test/screenshot_creation due to https://github.com/elastic/kibana/pull/197468#discussion_r1817460031 Contributes to: https://github.com/elastic/kibana/issues/194817 [Security GenAI][BUG] KB index entry created via pdf upload does not give the right response (#198020) These changes fix the issue with the wrong response of the AI Assistant using knowledge base tool and index entry generated from a PDF file. The issue happens because we are using the first chunk of uploaded PDF document as a context that we pass to LLM instead of using inner hits chunks which are actual parts of the document relevant to the questions. Here is [the blog post](https://www.elastic.co/search-labs/blog/semantic-text-with-amazon-bedrock) that talks about the strategy of using inner hits to get the most relevant documents. (see `Strategy 1: API Calls` section) 1. Navigate to Integrations page 2. Select "Upload a file" 3. Select and upload a PDF file 4. Press Import button 5. Switch to Advanced tab 6. Fill in "Index name" 7. Add additional field > Add semantic text field > Fill in form * Field: `attachment.content` * Copy to field: `content` * Inference endpoint: `elser_model_2` 8. Press Add button 9. Press Import button 1. Navigate to AI Assistant's Knowledge Base page 2. New > Index 3. Fill in "New index entry" form (below are main fields) * Name: `[add entry name]` * Index: `[select index name created during uploading a PDF file]` * Field: `content` 4. Press Save button Enable knowledge base feature via ``` xpack.securitySolution.enableExperimental: - 'assistantKnowledgeBaseByDefault' ``` **PDF document**: [Elastic Global Threat Report 2024](https://github.com/user-attachments/files/17544720/elastic-global-threat-report-2024.pdf) **KB Index entry**: Data Description: "Use this tool to answer questions about the Elastic Global Threat Report (GTR) 2024" Query Instruction: "Key terms to return data relevant to the Elastic Global Threat Report (GTR) 2024" **Questions**: 1. Who are the authors of the GTR 2024? 2. What is the forecast for the coming year in GTR 2024? 3. What are top 10 Process Injection by rules in Windows endpoints in GTR 2024? 4. What is the most widely adopted cloud service provider this year according to GTR 2024? 6. Give a brief conclusion of the GTR 2024 **Current behaviour**: Screenshot 2024-10-28 at 16 43 48 **Fixed behaviour**: Screenshot 2024-10-28 at 16 44 47 Improves pattern matching for data telemetry (#197876) Addresses concerns with Regex matching. Co-authored-by: Elastic Machine [Synthetics] Refactor delete route !! (#195387) Fixes https://github.com/elastic/kibana/issues/193790 !! Refactor delete route !! Make sure to send delete response in bulk to synthetics service !! [Fleet] Prevent hosted policies space change (#198043) Revert "[Canvas] Update kbn/flot to remove table.replace() issue" (#198067) Fixes #197998 Reverts elastic/kibana#195643 skip failing test suite (#181466) [Global Search] Instantly set `isLoading=true` when search value changes (#197750) Close https://github.com/elastic/kibana/issues/77059 This PR solves the bug by setting the `isLoading` flag outside of the block of debounced code whenever the search term changes. This also makes a few slight cleanups to `search_bar.tsx`, which is quite large. I avoided doing any serious cleanups that would make the diff hard to read or detract from the fix. skip flaky suite (#178404) skip flaky suite (#197335) skip flaky suite (#189038) skip flaky suite (#192126) skip flaky suite (#197765) skip flaky suite (#189739) skip flaky suite (#196766) skip flaky suite (#174661) Added redirect option after Entity CSV upload (#197937) Added a redirect button to view Entities after a successful Asset Criticality CSV file upload process Additionally, made some small changes to the copy for the Entity Store management workflows Screenshot 2024-10-27 at 9 49 17 PM Co-authored-by: Elastic Machine Update dependency msw to ^2.4.12 (main) (#198060) This PR contains the following updates: | Package | Type | Update | Change | Pending | |---|---|---|---|---| | [msw](https://mswjs.io) ([source](https://togithub.com/mswjs/msw)) | devDependencies | patch | [`^2.4.11` -> `^2.4.12`](https://renovatebot.com/diffs/npm/msw/2.4.11/2.4.12) | `2.5.2` (+3) | ---
mswjs/msw (msw) [Compare Source](https://togithub.com/mswjs/msw/compare/v2.4.11...v2.4.12) - **node:** preserve headers instanceof when recording raw headers ([#​2321](https://togithub.com/mswjs/msw/issues/2321)) ([`a58a300`](https://togithub.com/mswjs/msw/commit/a58a300687a48e13c0268403a71183cf7825f748)) [@​paoloricciuti](https://togithub.com/paoloricciuti)
--- 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> [CI] Disable UpdateCLI workflow on forks (#196624) The UpdateCLI workflow is running against forks when it shouldn't be: https://github.com/Ikuni17/kibana/actions/runs/11359905941 Fix Dev Container KBN_DIR (#195810) In #193488, `KBN_DIR` was changed to be a dynamic variable. It wasn't being properly propagated through the build process in the Dockerfile and the full path to `env.sh` wasn't being set. This passes the directory as a build `ARG` as well to fix the path. [api-docs] 2024-10-29 Daily api_docs build (#198103) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/875 [Security Solution][Hotfix] Avoid blocking prebuilt rule upgrade upon conflicts with disabled feature flag (#198106) It turned out some of the update rule buttons are disabled. This is a side effect of the functionality not fully hidden under a feature flag. This PR hides prebuilt rule customisation functionality disabling update rule buttons under `prebuiltRulesCustomizationEnabled` feature flag. ![image](https://github.com/user-attachments/assets/b7ca5ff8-be37-47a7-ad7e-b85386909f38) image image [Infra] Fix anomalies flyout navigation failing test (#197999) Closes #192882 The issue was that the url was checked too early which resulted in checking the locator url instead of the page url after navigating so I added a check for loading before the URL check and this solved the issue. https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7284 [ObsUx][Infra] Unskip and try to fix hosts view test (#197861) Closes #191806 The parts of the unskipped test were fixed here - the only case I couldn't find the reason for failing after unskipping it is `should have an option to open the chart in lens` - for some reason, the whole menu is gone when checking the CI and I couldn't reproduce that so this will be the only skipped part so we can at least have all the other `Hosts view` tests [Cloud Security] Fix flaky metering tests [Observability Onboarding] Set tech preview badges correctly (#197831) As discussed, adjust the first onboarding page: * Remove tech preview labels from EA flows * Change wording Screenshot 2024-10-25 at 15 23 47 Screenshot 2024-10-25 at 15 23 59 [EDR Workflows] Skip Osquery test in MKI (#198117) [EDR Workflows] Improve on unavailable shard exception flakiness in cypress (#197864) The cypress task `cy.task('indexEndpointHosts')` sometimes throws `no_shard_available_action_exception`, when transforms are stopped. This looks like a temporary issue, and in other tests it is simply retried. This PR adds the retry logic for this type of error, and unskips some tests. closes #194135 closes #191914 Delete any items that are not applicable to this PR. - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed [Cloud Security] add vulnerabilties data set to filter for links from CNVM dashboard (#197648) - fixes https://github.com/elastic/security-team/issues/10915 [Entity Analytics] [Entity Store] Telemetry (#196880) This PR adds telemetry for the Entity Store. Client side tracks UI enablement actions, whilst Kibana side tracks execution time of the store initialisation process and execution time of the enrich policy task. Finally we also track number of entities in the store Update docker.elastic.co/wolfi/chainguard-base:latest Docker digest to 1815394 (main) (#198099) This PR contains the following updates: | Package | Update | Change | |---|---|---| | docker.elastic.co/wolfi/chainguard-base | digest | `de4d5b0` -> `1815394` | --- 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> Update dependency @launchdarkly/node-server-sdk to ^9.6.1 (main) (#196897) [ML] Data Frame Analytics: removing scss overrides for exploration pages (#197724) Related meta issue: https://github.com/elastic/kibana/issues/140695 Regression model evaluation before: image After: image Classification evaluation before: image After switching fully to flex layout as we no longer support IE11 and all the workarounds were no longer needed (Note it's all left aligned now): image Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: Elastic Machine [ES|QL] separate `KEEP`, `DROP`, and `SORT` autocomplete routines (#197744) This PR begins the refactor described in https://github.com/elastic/kibana/issues/195418. The autocomplete engine now delegates to command-specific routines attached to the command definitions for `KEEP`, `DROP`, and `SORT`. The naming of `getFieldsFor` has been broadened to `getColumnsFor` because the response from Elasticsearch can contain variables as well as fields, depending on the query that is used to fetch the columns. No user-facing behavior should have changed. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Elastic Machine [CI] Fix project build & deploy job (#196562) In #195581 we've added the option to deploy through the clickable triggers. But in it's current state, it's broken in several aspects. (1) It's not starting on click. Triggers was resulting in a 422 on Buildkite's side, and after digging more into it, this was the error: Screenshot 2024-10-16 at 16 53 13 Apparently, building PRs needs to be enabled on jobs that want to be triggered through the PR bot. (2) It is set up to run regardless of the labels (3) There's no feedback on runs This PR: - enables buildability in the pipeline's config - exits early if deploy labels are missing - adds a comment on the PR if a deploy job is started or finished - removes the kibana build step, it's not needed, as we have a step to build the docker image TODO: - [x] Add feedback about a started job (either through a non-required check, or a github comment) - [x] Early exit if a label is missing There are several other builds started right now, because the logic that would trigger a build on changing a draft to ready. To be fixed in https://github.com/elastic/buildkite-pr-bot/issues/78 Tested after manually by enabling the option on the UI, and triggering through the checkbox: https://buildkite.com/elastic/kibana-deploy-project-from-pr/builds/23 Expand README (#197880) Adds a bit more general background, intro to concepts, and guidelines about what to use FF for and what not to Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) - [ ] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Alejandro Fernández Haro Fix Typo: Change 'dashaboard' to 'dashboard' on APM-service Dashboards page #195773 (#196969) **Title:** Fix Typo: Change 'dashaboard' to 'dashboard' on APM-service Dashboards page **Description:** This PR fixes a typo on the "Dashboards" page for APM-service. The typo "dashaboard" has been corrected to "dashboard" to ensure proper functionality and readability. closes #195773 **Changes Made:** - Corrected the typo in the text "To get started, add your dashaboard" to "To get started, add your dashboard." **Testing:** - Verified the change on the Dashboards page for APM-service. - Ensured no other instances of the typo exist in the codebase. **Release note:** Fixes a typo on the "Dashboards" page for APM-service, changing 'dashaboard' to 'dashboard'. **Additional Notes:** No additional notes. Summarize your PR. If it involves visual changes include a screenshot or gif. Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) - [ ] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Cauê Marcondes <55978943+cauemarcondes@users.noreply.github.com> Co-authored-by: Nathan L Smith Co-authored-by: jennypavlova [Response Ops][Actions] Remove deprecated HTTP APIs (#197510) Resolves https://github.com/elastic/kibana/issues/90382 Removes legacy action APIs for 9.0 and updates all tests that still used the legacy APIs to use the current APIs. Also did some renaming of action -> connector in the files I had to touch. Co-authored-by: Elastic Machine [Fleet] Prevent duplication of managed policy !! (#197575) Fixes https://github.com/elastic/kibana/issues/194149 Prevent duplication of managed policy !! image [Security Solution][Notes] - switch the securitySolutionNotesEnables feature flag to securitySolutionNotesDisabled (#196778) This PR switches the `securitySolutionNotesEnabled` to `securitySolutionNotesDisabled` (with a `false` value by default) to enable the new Notes functionality in `8.16`. Customers can set the new `securitySolutionNotesDisabled` feature flag to true in their environment if they want to go back to the old notes system. The PR also fixes a tiny bug with the badge showing the number of notes in the Timeline Notes tab. The new system was not taking into account a timeline description, so if the timeline had a description the number of notes was always 1 lower than the actual number of notes displayed below. This issue was highlighted by a Cypress test! The goal is to remove the old system entirely within a few releases (maybe `8.18` or `9.0`). - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios https://github.com/elastic/kibana/issues/189879 [ci] Fix cloud deployments (#198086) Our build scripts are relying on a step that was removed in https://github.com/elastic/elasticsearch/pull/115357. The image that was produced by this script is eventually consumed by cloud deployments from pull requests. This updates our scripts to use the cloud-ess variant instead. There should not be any functional difference. We'll need the image to go through our promotion pipeline to be tested via label. https://buildkite.com/elastic/kibana-elasticsearch-snapshot-build/builds/4673 [ci] Use es snapshot cache on miscellaneous steps 2 (#198078) Adds the remaining steps missing snapshot loading from cache that I missed on the first loop. [Observability] Update breadcrumbs for observability project based navigation (#196785) ~⚠️ I'm still putting out some fires with tests, but this is ready to start being reviewed.~ A continuation of https://github.com/elastic/kibana/pull/196169 for Observability (please read that PR description first). Related: https://github.com/elastic/kibana/issues/192050 There are essentially three types of breadcrumbs - serverless (which is project style), stateful project style (set through spaces settings), and classic style (the old breadcrumbs we've seen for years). Whilst serverless and stateful project style both use the project based style the navigation trees are slightly different, so the breadcrumbs results are not identical [when they derive the "nav crumbs"](https://github.com/elastic/kibana/blob/9577aa980dd1565fba05e34292fb5c0bba692889/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx#L55). Here "project style" will refer to serverless and stateful project style. In these changes I've, for the most part, tried to refactor things so Observability solutions route their breadcrumbs through the observability-shared `useBreadcrumbs` hook, this way the logic around project style, adding an Observability crumb in classic etc is consolidated in one place. [For several solutions `absolute` breadcrumbs are being used](https://github.com/elastic/kibana/blob/9577aa980dd1565fba05e34292fb5c0bba692889/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx#L46), and this means we'll roughly have the same breadcrumbs across the 3 experiences (bar Observability being prepended). Teams may want to refine this going forward to pass curated breadcrumbs that take into account the navigation derived "nav crumbs" (again, bearing in mind the trees from serverless and project based chrome do differ), and not use absolute mode. APM is an example of this at the moment. Right now this is an 8.16 bug though, so this aims to make things acceptable, but not necessarily perfect. - Project style chrome crumbs have been modelled off the serverless ones. The navigation trees here are the same so this should be fine. - The `infra` `useBreadcrumbs` hook has been removed, it was only being used by logs. Logs now goes via the Observability shared hook using `classicOnly`. - Metrics (`useMetricsBreadcrumbs` hook) has been slightly amended to route more of it's logic through the shared hook. - Wasn't setting any nested breadcrumbs at the moment so the logic has been simplified to just set some classic crumbs, and defer the rest to the nav crumbs via the shared hook. - Removed custom logic around prepending Observability, adding link handlers etc in favour of the shared hook. - Simple breadcrumb needs so these are mostly setting `classicOnly` and deferring to the nav crumbs in project style. Several solutions have had their usage of the shared hook updated to pass in the `serverless` plugin. This was missing before, so calls to `serverless.setBreadcrumbs` weren't explicitly happening. - Add the following to your `kibana.dev.yml`: ```yml xpack.cloud.id: "ftr_fake_cloud_id:aGVsbG8uY29tOjQ0MyRFUzEyM2FiYyRrYm4xMjNhYmM=" xpack.cloud.base_url: "https://cloud.elastic.co" ``` - For testing stateful project style chrome you'll need to go to Stack Management > Spaces and change the solution view: ![Screenshot 2024-10-21 at 12 44 21](https://github.com/user-attachments/assets/e3d9fe64-f79f-4e31-a5b6-45a06ca4915d) - Set the above to Classic to test classic breadcrumbs. - As a reviewer please check your solution against the 3 modes. Before these changes we'd see something like the following in APM: ![Screenshot 2024-10-11 at 10 56 54](https://github.com/user-attachments/assets/4938b31e-9d4a-429e-abf0-add04d69b62a) Now we'll see something like this in project style: ![Screenshot 2024-10-21 at 12 48 54](https://github.com/user-attachments/assets/0645a3ae-909e-4a70-a077-d9f83bd1d639) [Dashboard] [Collapsable Panels] Reduce re-renders (#197343) Closes https://github.com/elastic/kibana/issues/191131 This PR greatly reduces the number of React re-renders that happen as panels get dragged around and/or resized. Now, the actions that trigger a panel to get rendered are as follows: 1. Obviously, when the grid first loads, every panel has to be rendered. 2. When a panel gets dragged from one row to the next, both the original row and the new row will re-render all of their panels because the panel IDs in both rows changed - however, because of the `key` prop on the `GridPanel` component, only the **dragged** panel will actually be fully re-mounted. 3. When a panel gets collapsed and expanded, all panels in that row will get re-mounted and rendered. 4. When a panel ID gets changed (this currently isn't possible, but in theory, this would also trigger the panel to get re-rendered due to the `key` prop on the `GridPanel` component) In order to accomplish this, we are now handling **all style changes** via a subscription rather than setting the CSS directly; so, as the `gridLayout$` behaviour subjects publishes changes, we update the row + panel styles via the panel reference. This allows us to change how the grid looks without triggering React to rerender the entire panel. **How to Test:** Add a `console.log` to the `renderPanelContents` in `examples/grid_example/public/app.tsx` - this will tell you when a panel is getting re-rendered. - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) - [ ] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> [Search][Connectors] Confirmation modal before leaving the connector creation flow (#197646) This PR shows a confirmation modal when users leave the connectors creation flow before providing all necessary info, asking for intentional confirmation after leaving the experience. Setting `isFormDirty = true` only after generating the connectors config and letting users leave the experience setting `isFormDirty = false` when we arrive to the Finish up step ![CleanShot 2024-10-24 at 18 56 11](https://github.com/user-attachments/assets/90f355e2-d227-4d2a-a45e-bcfbb743d588) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine Co-authored-by: Jedr Blaszyk [Search][Connectors] Create connector via try in console (#197757) This PR enables the possibility of creating a connector opening the embedded console in the start step. ![CleanShot 2024-10-28 at 10 00 04](https://github.com/user-attachments/assets/bf2c0a89-1c18-4fcd-8c2b-4fbbe3ef80a9) --------- Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com> Co-authored-by: Elastic Machine [Security solution] Knowledge base tour video update (#198158) [8.15] [Kibana data view] Fix issue empty user-hash in data view request headers (#197863) to fix not compliant HTTP request Fix not compliant HTTP request for example, request "GET /s//internal/data_views/fields?pattern=abc" Sometimes request headers have a user-hash field with an empty value and this makes the request not HTTP compliant in some scenarios the request will be dropped by WAF or by another security edge for example. ![image](https://github.com/user-attachments/assets/de606665-12e6-475c-a2e4-c2e594957f11) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine Co-authored-by: mabdelgaber.SEC Change spaces button loading design (#197922) Closes #197916 One less loading spinner. Instead, uses a skeleton loader for a load-in-place effect that is visually less busy and jumpy. *Before* *After* https://github.com/user-attachments/assets/33cc2d39-2895-4c53-8903-9c3b18d586f9 skip failing test suite (#198066) skip flaky suite (#174682) skip flaky suite (#171177) skip flaky suite (#192144) [api-docs] 2024-10-30 Daily api_docs build (#198250) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/876 [kbn-test] fix junit report test for local run (#198120) When I run test locally with `node scripts/jest --config packages/kbn-test/jest.config.js`, it fails with ``` FAIL packages/kbn-test/src/mocha/junit_report_generation.test.js ● dev/mocha/junit report generation › reports on failed setup hooks expect(received).toEqual(expected) // deep equality - Expected - 1 + Received + 1 @@ -1,7 +1,7 @@ Object { - "command-line": "node scripts/jest --config=packages/kbn-test/jest.config.js --runInBand --coverage=false --passWithNoTests", + "command-line": "node node_modules/jest-worker/build/workers/processChild.js", "failures": "2", "metadata-json": "{}", "name": "test", "skipped": "1", "tests": "4", ``` This PR uses `process.env.CI` as a condition to apply different value for `command-line` property so test will pass locally too. [Security Solution][Notes] - fix the notes link that is shown twice in the search bar (#198200) This PR fixes a minor inconvenience where the Kibana search bar was showing 2 entries for the new Notes management page. | Before fix | After fix | | ------------- | ------------- | | ![Screenshot 2024-10-29 at 11 53 44 AM](https://github.com/user-attachments/assets/77bd4b5a-d8d4-4f4f-8378-6aff1ec1b00b) | ![Screenshot 2024-10-29 at 11 53 19 AM](https://github.com/user-attachments/assets/d138e307-b4ea-473b-9102-eb7e7b540bff) | Notes: this fix does not fix an issue happening in the space-specific search, where Notes, Timelines and maybe other entries are appearing twice. That issue seems to be related to the way we are removing then adding back links to work with the new navigation. I looked into it but could not find a way to fix yet, so this will be part of a follow up PR https://github.com/elastic/kibana/issues/197694 [Stream] Fix callout privileges (#198030) closes https://github.com/elastic/kibana/issues/197044 closes https://github.com/elastic/kibana/issues/197988 The PR targets fixing 3 bugs: 1. The callout shouldn't be shown if `Logs Explorer` isn't available, otherwise the link displayed in the callout will cause a problem. [Fix here](https://github.com/elastic/kibana/pull/198030/files#diff-8c5f793d1bf0d933c73047f31ded8a5a65f91e4f8d5230fc4e40dfb9b245fec1R66) 2. The callout shouldn't be shown if `Logs Explorer` is available but the user doesn't have privilege to access it, otherwise we end up in `Application Not Found` page. [Fix here](https://github.com/elastic/kibana/pull/198030/files#diff-8c5f793d1bf0d933c73047f31ded8a5a65f91e4f8d5230fc4e40dfb9b245fec1R66) 3. The side nav entry for `Logs Explorer` should be hidden if `Logs Explorer` is disabled. [Fix here](https://github.com/elastic/kibana/pull/198030/files#diff-ad4e42fbe4d2a7a99ec5d52fbf127ded12f0efe02a10e3afa0409b40be1f4bcfR397) [ResponseOps][Cases] Introduce number custom field type (#195245) Issue: https://github.com/elastic/kibana/issues/187208 In this PR I've added new number custom field. It includes both: FE and BE. Only safe integers (the safe integers consist of all integers from -(2^53 - 1) to 2^53 - 1) are allowed as values. Testing: For testing Postman/Insomnia can be used. Go to Case - Settings. New configure will be created. After that you can use this endpoint: `PATCH http://localhost:5601/hcr/api/cases/configure/7377ed43-af0c-46f1-bbe5-fd0b147d591d`
Body looks something like this: { "closure_type": "close-by-user", "customFields": [ { "type": "number", "key": "54d2abf2-be0e-4fec-ac33-cbce94cf1a10", "label": "num", "required": false, "defaultValue": 123 }, { "type": "number", "key": "6f165838-a8d2-49f7-bbf6-ab3ad96d0d46", "label": "num2", "required": false, "defaultValue": -10 } ], "templates": [], "connector": { "id": "none", "type": ".none", "fields": null, "name": "none" }, "version": "WzIyLDFd" }
![Screenshot 2024-10-07 at 16 23 15](https://github.com/user-attachments/assets/2d769049-e339-47bb-a17d-189569b8785d) Try different numbers: positive and negative. Try to add not number types as a default value with `"type": "number"` - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> [Observability Onboarding] Adjust wording for instrumentation and doc links (#198164) Closes https://github.com/elastic/kibana/issues/197620 ![Image](https://github.com/user-attachments/assets/e94dd9ff-bd5b-49a6-9b39-fdf54a4e3e58) * Newly introduced cert-manager doc link goes to https://ela.st/8-16-otel-cert-manager * Instrumentation docs link goes to https://ela.st/8-16-otel-apm-instrumentation * Code sample for instrumentation replaced --------- Co-authored-by: Mykola Harmash [Discover] Update docs to remove discover:showLegacyFieldTopValues (#197981) This PR updates docs as a followup for https://github.com/elastic/kibana/pull/155503 - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials Co-authored-by: Davis McPhee [SecuritySolution] Update Entity Store transform to read frequency and delay from config (#197992) Update Entity Store transform to read frequency and delay from config. New Config: ``` xpack.securitySolution.entityAnalytics.entityStore.frequency: '60s' xpack.securitySolution.entityAnalytics.entityStore.syncDelay: '60s' ``` * Update Kibana config * Start the entity store *** If you update the config after the entity store is installed it has no effect [Observability AI Assistant] Input box can be resized off-screen (elastic #181408) (#197063) fixes [181408](https://github.com/elastic/kibana/issues/181408) This PR addresses the issue where the Observability AI Assistant input box can be resized outside the boundaries of the browser window. Allows the input box to resize dynamically while ensuring it remains usable, even when the cursor moves outside the screen during resizing. [Observability Onboarding] Change CTA for System integration in Auto Detect (#197836) Closes https://github.com/elastic/observability-dev/issues/4053 🔒 * Adds an option to specify metadata for integrations installed from registry as a third parameter in the TSV provided to the `/integrations/install` endpoint. For now only `system` integration has metadata with a hostname, but it's made generic to support other integrations when needed. * Changes CTA for the System integration to point to the Host details * Adds sorting in the detected integrations in the UI to alway show System integration at the top [ML] Removing anomaly detection scss files (#197447) Removes last remaining scss files in favour of inline css with emotion. **Before** ![image](https://github.com/user-attachments/assets/16910734-8e28-459c-b798-d55d7ab10323) **After** ![image](https://github.com/user-attachments/assets/5f8a07b7-8796-4302-af24-6facebeb3b48) **Before** ![image](https://github.com/user-attachments/assets/06657e7f-b913-4393-aeaa-50fc0c53831c) **After** ![image](https://github.com/user-attachments/assets/fd9eab67-ab91-45c6-9ad9-5addce40a76e) [ftr] update svl shared config with cluster settings (#196336) Adding Elasticsearch cluster settings to replicate MKI cluster setup for FTR. Fixes session timeout toast countdown (#198266) A regression was introduced when upgrading to react-intl v6, and the `FormattedRelative` component was replaced by the `FormattedRelativeTime` component. The new component requires an addition property be specified in order to have the same behavior as the previous - formatting seconds > 60 as minutes, and counting down when below 1 minute. This PR adds the `updateIntervalInSeconds` property to the `FormattedRelativeTime` component of the session expiration toast. This PR also adds a unit test case to check the time format when > 60s remain. 1. Add the following Kibana configuration setting ``` xpack.security.session.idleTimeout: "2m" # can be anything over 1m, shorter is better for testing ``` 2. Start ES & Kibana, log in 3. Verify the session expiration toast appears and first displays minutes. Leave the toast open. 4. Verify that after 1 minute, the toast begins counting down seconds 5. Repeat the test from main and verify that the toast only shows the initial number of seconds A bug was fixed that caused the session expiration toast to incorrectly render the remaining time. [SecuritySolution] Fix Pagination should reset when a new filter is applied to the entity table (#198129) Fix "Pagination should reset when a new filter is applied to the entity table" * Extra changes: I demoted some error logs to warning as part of https://github.com/elastic/security-team/issues/10951 https://github.com/user-attachments/assets/16357db1-5e77-4c7f-ae94-9371d71c4970 * Start kibana with data * Navigate to the security solution / entity analytics dashboard * Start the entity store * Navigate between pages and change the filter, sorting, and query. [Synthetics] For lens embeddable apply styling workaround for panel border !! (#198270) Fixes https://github.com/elastic/kibana/issues/198273 For lens embeddable apply styling workaround for panel border !! image [OneDiscover] Contextual App Menu Extension Point (#195448) - Closes https://github.com/elastic/kibana/issues/194269 This PR introduces a new extension point `getAppMenu` which allows to: - add custom App Menu items (as a button or a submenu with more actions) - extend Alerts menu item with more custom actions Additionally, this PR rearranges the existing Discover menu items. The primary actions are rendered as an icon only now. ![Oct-16-2024 17-43-29](https://github.com/user-attachments/assets/dbb67513-05bb-43a4-bd7b-cf958c58a167) The example usage of the new extension point can be found in https://github.com/elastic/kibana/blob/e7964f08e3c13bba36d13823575e54b40fabd9bc/src/plugins/discover/public/context_awareness/profile_providers/example/example_data_source_profile/profile.tsx#L81-L168 1. Add `discover.experimental.enabledProfiles: ['example-root-profile', 'example-data-source-profile', 'example-document-profile']` to `kibana.dev.yml` 2. Run the following in DevTools ``` POST _aliases { "actions": [ { "add": { "index": "kibana_sample_data_logs", "alias": "my-example-logs" } } ] } ``` 3. Create and use Data View with `my-custom-logs` index pattern - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Davis McPhee Co-authored-by: Davis McPhee [Security Solution][Endpoint] Add step to the security solution plugin `start` phase (non-blocking) to check endpoint policy indices (#198089) - adds a step to the plugin `start` phase to retrieve all Endpoint policies from Fleet and check to ensure they have backing DOT indices. - This is a follow up to PR #196953 - this check will be removed once it is deployed to Serverless, since it only needs to run once in that flavor of kibana [ResponseOps][MaintenanceWindow] Introduce pagination for MW find API (#197172) Fixes: https://github.com/elastic/kibana/issues/193076 This PR introduce pagination for our MW find API. How to test: Use postman/insomnia/curl. Do not forget to add this header: `x-elastic-internal-origin: Kibana`, because this endpoint in internal. Basically you need to do something like this: ``` GET http://localhost:5601/top/internal/alerting/rules/maintenance_window/_find?page=3&per_page=3 ``` Try different page and per_page combination. Try without them. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Update dependency @types/lodash to ^4.17.13 (main) (#198275) Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> [Inventory][ECO] Entities Group By View (#195475) This PR introduces the API and Page for doing grouped views for the Inventory Page. Alongside the plain list view, the page now by default shows a grouped view of entities. In this PR, the only current supported grouping is by Entity Type. https://github.com/user-attachments/assets/a07db592-d6c6-4ec1-a00b-bb469908aa6a Tests TBA - Navigate to the new Inventory Page - By default, the page should load into a grouped view (Type) - The page should show all entities currently grouped by their type. - If a group has enough entities, pagination navigation should only apply to the list within the group. - The plain list view should function same as before. - Using the search/filter bar should function the same with grouped and list view. Closes #194740 --------- Co-authored-by: Bryce Buchanan Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine [ftr] use getopts to fetch server args (#198227) This PR simplifies the code to read server arguments by using `getopts` module as @jbudz suggested. Handle DOM storage being disabled (#197798) This PR aims to improve the message shown to users when Kibana can't be started due to disabled DOM storage (#121189). The visuals here follow the same pattern as other fatal errors (see ![image](https://github.com/user-attachments/assets/19832830-49e3-4789-9b83-0c1f14d7980d) The `isDomStorageDisabled` check has to be done before `CoreService` gets instantiated because of issues described below. Closes: #121189 What actually happens when you disable all cookies in a browser? Aside from cookies, the browser disables the whole DOM storage - `localStorage` and `sessionStorage`. Trying to access those will result in an error. `getSessionId`https://github.com/elastic/kibana/blob/3bc5e2db73799dc9c7831b6f9da4a52063cf112f/packages/core/analytics/core-analytics-browser-internal/src/get_session_id.ts#L17 and `isSidenavCollapsed$`https://github.com/elastic/kibana/blob/3bc5e2db73799dc9c7831b6f9da4a52063cf112f/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx#L91 Both of those try to access either `localStorage` or `sessionStorage` and both of those are triggered when you create an instance of `CoreSystem` which gets instantiated in `kbn_bootstrap` https://github.com/elastic/kibana/blob/6ef03697460aba0d3774c0c03fb7fb58c76c00bd/packages/core/root/core-root-browser-internal/src/kbn_bootstrap.ts#L42 Trying to access DOM storage in `CoreSystem` will cause it to throw an error and this means that `FatalErrorService`https://github.com/elastic/kibana/blob/6ef03697460aba0d3774c0c03fb7fb58c76c00bd/packages/core/fatal-errors/core-fatal-errors-browser-internal/src/fatal_errors_service.tsx#L32 will never instantiate and the `failure`https://github.com/elastic/kibana/blob/6ef03697460aba0d3774c0c03fb7fb58c76c00bd/packages/core/rendering/core-rendering-server-internal/src/bootstrap/render_template.ts#L68 function which styles the errors and makes them visible will never trigger and all the user will see is permament `Loading Kibana` spinner. Wrapping `getSessionId` and `isSidenavCollapsed$` in `try-catch` block allows `FatalErrorService` to work properly, which will catch an unhandled exception (`Detected an unhandled Promise rejection.`) with an error about `sessionStorage` being disabled, which gets thrown by `LicensingPlugin` (and possibly in other places). This is not an actual solution though - this behavior would happen again if another line of code trying to access DOM storage gets added to `CoreSystem`. I think it would be best to handle this directly in `kbn_bootstrap.ts` by some check like the one below: ```javascript const isDOMStorageDisabled = () => { try { const key = 'kbn_bootrasrap_domStorageEnabled'; sessionStorage.setItem(key, 'true'); sessionStorage.removeItem(key); return false; } catch (e) { return true; } }; const domStorageDisabled = isDOMStorageDisabled() /* ...some additonal logic */ ``` This would then require some error displaying logic that doesn't use `FatalErrorService`. Looking for some feedback on how to properly solve this. [AI Assistant] Add scopes telemetry to AI Assistant events (#197983) This adds telemetry to the Observability and Search assistant to judge whether it's search or observability. [Fleet] Fix update query when change agent policy spaces (#198175) [Security Solution] Fix code scanning alert (#198142) Fixes [https://github.com/elastic/kibana/security/code-scanning/365](https://github.com/elastic/kibana/security/code-scanning/365) To fix the problem, we need to ensure that both double quotes and backslashes are properly escaped in the `escapeValue` function. This can be achieved by using a regular expression that replaces both characters globally. Specifically, we should replace backslashes with double backslashes (`\\`) and double quotes with escaped double quotes (`\"`). - Update the `escapeValue` function to use a regular expression that handles both double quotes and backslashes. - Ensure that the regular expression has the global flag (`g`) to replace all occurrences of the characters. Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> [Search] Refactor: abstracting classic nav items (#196579) Moved the base set of sidenav items from being statically defined in useEnterpriseSearchNav to using a function that can be shared with the plugin. Additionally wrapped this generation in a `useMemo` to improve performance. This will support the ability to share the classic navigation items for Search to other plugins so that they can render their own UIs without sharing components with enterprise_search just to have access to the side nav defined by enterprise_search. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed --------- Co-authored-by: Elastic Machine [Reporting] Unskip and optimize tests that generate test reports (#198207) This PR re-enables test reports that have been consistently failing in the serverless test environment. Investigation shows the reason for flakiness _may_ be due to the fact that the reports are exporting a large amount of data, which causes timeouts, including authentication tokens to time out. To speed up the tests, date range filters and field selections have been added to the report job parameters, which leads to a lower amount of data being exported. The tests that are updated in this PR now generate an export with 2 documents, where previously they were exporting up to 4675 documents. [ML] Fix the Trained Models table expanded row refresh (#198149) Fixes a regression introduced in https://github.com/elastic/kibana/pull/194614/, where the content of expanded rows in the Trained Model table stopped being updated on refresh. Co-authored-by: Elastic Machine [Dashboard/Markdown] Add tabindex (#197848) This PR adds `tabIndex` to [markdown_vis_controller.tsx](https://github.com/elastic/kibana/compare/main...kowalczyk-krzysztof:kibana:fix/dashboard-markdown-panel?expand=1#diff-47267cf2f7d8f9e72e157ddb40292226a88ad5e51f9c92486799d381c5085e5f). Closes: #186559 https://github.com/user-attachments/assets/8264c584-e7ca-4647-946a-7b9bd9f7aa8f This video demonstrates the markdown panel being tabbable and the scrollbar in being controlled with keyboard. Include k8s cluster dashboard redirection [Entity Analytics] [Entity Store] Run init requests sequentially to prevent resource exists error (#198268) This PR fixes an issue where running init for both `user` and `host` entity engines in parallel would cause a race condition while enabling the risk engine, resulting in a `Resource already exists` error. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> [Search] Fix playground crash when adding connector (#198365) Fixes an issue where Playground occasionally crashed because a connector model is undefined. [DOCS] Fine-tunes inference connector and action docs (#198345) [SLO] Overview embeddable chart use proper theme !! (#198299) Fixes https://github.com/elastic/kibana/issues/198298 Overview embeddable chart use proper theme !! image image [Obs AI Assistant] Fix chat on the Alerts page (#197126) Closes https://github.com/elastic/kibana/issues/184214 The Observability AI Assistant doesn't work on the Alerts page - errors out with a 400 status code from OpenAI. The reason for this is that the description for the function `get_data_on_screen` is too long, and there is a token limit for function descriptions by OpenAI. **Note:** This error does not occur with Gemini or Bedrock because simulated function calling is enabled by default for them. With simulated function calling, all functions and their descriptions are appended to the system message, therefore doesn't run into a token limit error as opposed to OpenAI. Append the function description to the system message instead of sending it with the function. The implementation includes: - Registering an AdHoc instruction - Retrieving AdHoc instructions - Combine the retrieved AdHoc instructions with the other adHoc instructions passed to the chat and pass all AdHoc instructions to the `getSystemMessageFromInstructions` function. This correctly orders the description for the `get_data_on_screen` function at the end of the system message _OpenAI request object **before** the above update:_
Click to expand JSON ```json { "messages": [ { "role": "system", "content": "You are a helpful assistant for Elastic Observability. Your goal is to help the Elastic Observability users to quickly assess what is happening in their observed systems. You can help them visualise and analyze data, investigate their systems, perform root cause analysis or identify optimisation opportunities.\n\n It's very important to not assume what the user is meaning. Ask them for clarification if needed.\n\n If you are unsure about which function should be used and with what arguments, ask the user for clarification or confirmation.\n\n In KQL (\"kqlFilter\")) escaping happens with double quotes, not single quotes. Some characters that need escaping are: ':()\\ /\". Always put a field value in double quotes. Best: service.name:\"opbeans-go\". Wrong: service.name:opbeans-go. This is very important!\n\n You can use Github-flavored Markdown in your responses. If a function returns an array, consider using a Markdown table to format the response.\n\n Note that ES|QL (the Elasticsearch Query Language which is a new piped language) is the preferred query language.\n\n If you want to call a function or tool, only call it a single time per message. Wait until the function has been executed and its results\n returned to you, before executing the same tool or another tool again if needed.\n\n DO NOT UNDER ANY CIRCUMSTANCES USE ES|QL syntax (`service.name == \"foo\"`) with \"kqlFilter\" (`service.name:\"foo\"`).\n\n The user is able to change the language which they want you to reply in on the settings page of the AI Assistant for Observability, which can be found in the Stack Management app under the option AI Assistants.\n If the user asks how to change the language, reply in the same language the user asked in.\n\nYou MUST use the \"query\" function when the user wants to:\n - visualize data\n - run any arbitrary query\n - breakdown or filter ES|QL queries that are displayed on the current page\n - convert queries from another language to ES|QL\n - asks general questions about ES|QL\n\n DO NOT UNDER ANY CIRCUMSTANCES generate ES|QL queries or explain anything about the ES|QL query language yourself.\n DO NOT UNDER ANY CIRCUMSTANCES try to correct an ES|QL query yourself - always use the \"query\" function for this.\n\n If the user asks for a query, and one of the dataset info functions was called and returned no results, you should still call the query function to generate an example query.\n\n Even if the \"query\" function was used before that, follow it up with the \"query\" function. If a query fails, do not attempt to correct it yourself. Again you should call the \"query\" function,\n even if it has been called before.\n\n When the \"visualize_query\" function has been called, a visualization has been displayed to the user. DO NOT UNDER ANY CIRCUMSTANCES follow up a \"visualize_query\" function call with your own visualization attempt.\n If the \"execute_query\" function has been called, summarize these results for the user. The user does not see a visualization in this case.\n\nYou MUST use the \"get_dataset_info\" function before calling the \"query\" or the \"changes\" functions.\n\nIf a function requires an index, you MUST use the results from the dataset info functions.\n\nYou have access to data on the screen by calling the \"get_data_on_screen\" function.\nUse it to help the user understand what they are looking at. A short summary of what they are looking at is available in the return of the \"context\" function.\nData that is compact enough automatically gets included in the response for the \"context\" function.\n\nYou can use the \"summarize\" function to store new information you have learned in a knowledge database.\nOnly use this function when the user asks for it.\nAll summaries MUST be created in English, even if the conversation was carried out in a different language." }, { "role": "user", "content": "Can you explain this page?" }, { "role": "assistant", "content": "", "function_call": { "name": "context", "arguments": "{}" } }, { "role": "user", "content": "{\"screen_description\":\"The user is looking at http://localhost:5601/phq/app/observability/alerts?_a=(filters:!(),kuery:%27%27,rangeFrom:now-24h,rangeTo:now,status:all). The current time range is 2024-10-21T18:23:54.539Z - 2024-10-21T18:38:54.539Z.\",\"learnings\":[],\"data_on_screen\":[{\"name\":\".es-query\",\"value\":\"Elasticsearch query Alert when matches are found during the latest query run.\",\"description\":\"An available rule is Elasticsearch query.\"},{\"name\":\"observability.rules.custom_threshold\",\"value\":\"Custom threshold Alert when any Observability data type reaches or exceeds a given value.\",\"description\":\"An available rule is Custom threshold.\"},{\"name\":\"xpack.ml.anomaly_detection_alert\",\"value\":\"Anomaly detection Alert when anomaly detection jobs results match the condition.\",\"description\":\"An available rule is Anomaly detection.\"},{\"name\":\"slo.rules.burnRate\",\"value\":\"SLO burn rate Alert when your SLO burn rate is too high over a defined period of time.\",\"description\":\"An available rule is SLO burn rate.\"},{\"name\":\"metrics.alert.threshold\",\"value\":\"Metric threshold Alert when the metrics aggregation exceeds the threshold.\",\"description\":\"An available rule is Metric threshold.\"},{\"name\":\"metrics.alert.inventory.threshold\",\"value\":\"Inventory Alert when the inventory exceeds a defined threshold.\",\"description\":\"An available rule is Inventory.\"},{\"name\":\"logs.alert.document.count\",\"value\":\"Log threshold Alert when the log aggregation exceeds the threshold.\",\"description\":\"An available rule is Log threshold.\"},{\"name\":\"xpack.uptime.alerts.tlsCertificate\",\"value\":\"Uptime TLS Alert when the TLS certificate of an Uptime monitor is about to expire.\",\"description\":\"An available rule is Uptime TLS.\"},{\"name\":\"xpack.uptime.alerts.monitorStatus\",\"value\":\"Uptime monitor status Alert when a monitor is down or an availability threshold is breached.\",\"description\":\"An available rule is Uptime monitor status.\"},{\"name\":\"xpack.uptime.alerts.durationAnomaly\",\"value\":\"Uptime Duration Anomaly Alert when the Uptime monitor duration is anomalous.\",\"description\":\"An available rule is Uptime Duration Anomaly.\"},{\"name\":\"xpack.synthetics.alerts.monitorStatus\",\"value\":\"Synthetics monitor status Alert when a monitor is down.\",\"description\":\"An available rule is Synthetics monitor status.\"},{\"name\":\"xpack.synthetics.alerts.tls\",\"value\":\"Synthetics TLS certificate Alert when the TLS certificate of a Synthetics monitor is about to expire.\",\"description\":\"An available rule is Synthetics TLS certificate.\"},{\"name\":\"apm.error_rate\",\"value\":\"Error count threshold Alert when the number of errors in a service exceeds a defined threshold.\",\"description\":\"An available rule is Error count threshold.\"},{\"name\":\"apm.transaction_error_rate\",\"value\":\"Failed transaction rate threshold Alert when the rate of transaction errors in a service exceeds a defined threshold.\",\"description\":\"An available rule is Failed transaction rate threshold.\"},{\"name\":\"apm.transaction_duration\",\"value\":\"Latency threshold Alert when the latency of a specific transaction type in a service exceeds a defined threshold.\",\"description\":\"An available rule is Latency threshold.\"},{\"name\":\"apm.anomaly\",\"value\":\"APM Anomaly Alert when either the latency, throughput, or failed transaction rate of a service is anomalous.\",\"description\":\"An available rule is APM Anomaly.\"}]}", "name": "context" } ], "stream": true, "tools": [ { "function": { "name": "get_data_on_screen", "description": "Get data that is on the screen:\n.es-query: An available rule is Elasticsearch query.\nobservability.rules.custom_threshold: An available rule is Custom threshold.\nxpack.ml.anomaly_detection_alert: An available rule is Anomaly detection.\nslo.rules.burnRate: An available rule is SLO burn rate.\nmetrics.alert.threshold: An available rule is Metric threshold.\nmetrics.alert.inventory.threshold: An available rule is Inventory.\nlogs.alert.document.count: An available rule is Log threshold.\nxpack.uptime.alerts.tlsCertificate: An available rule is Uptime TLS.\nxpack.uptime.alerts.monitorStatus: An available rule is Uptime monitor status.\nxpack.uptime.alerts.durationAnomaly: An available rule is Uptime Duration Anomaly.\nxpack.synthetics.alerts.monitorStatus: An available rule is Synthetics monitor status.\nxpack.synthetics.alerts.tls: An available rule is Synthetics TLS certificate.\napm.error_rate: An available rule is Error count threshold.\napm.transaction_error_rate: An available rule is Failed transaction rate threshold.\napm.transaction_duration: An available rule is Latency threshold.\napm.anomaly: An available rule is APM Anomaly.", "parameters": { "type": "object", "properties": { "data": { "type": "array", "description": "The pieces of data you want to look at it. You can request one, or multiple", "items": { "type": "string", "enum": [ ".es-query", "observability.rules.custom_threshold", "xpack.ml.anomaly_detection_alert", "slo.rules.burnRate", "metrics.alert.threshold", "metrics.alert.inventory.threshold", "logs.alert.document.count", "xpack.uptime.alerts.tlsCertificate", "xpack.uptime.alerts.monitorStatus", "xpack.uptime.alerts.durationAnomaly", "xpack.synthetics.alerts.monitorStatus", "xpack.synthetics.alerts.tls", "apm.error_rate", "apm.transaction_error_rate", "apm.transaction_duration", "apm.anomaly" ] } } }, "required": ["data"] } }, "type": "function" }, { "function": { "name": "query", "description": "This function generates, executes and/or visualizes a query\n based on the user's request. It also explains how ES|QL works and how to\n convert queries from one language to another. Make sure you call one of\n the get_dataset functions first if you need index or field names. This\n function takes no input.", "parameters": { "type": "object", "properties": {} } }, "type": "function" }, { "function": { "name": "get_alerts_dataset_info", "description": "Use this function to get information about alerts data.", "parameters": { "type": "object", "properties": { "start": { "type": "string", "description": "The start of the current time range, in datemath, like now-24h or an ISO timestamp" }, "end": { "type": "string", "description": "The end of the current time range, in datemath, like now-24h or an ISO timestamp" } } } }, "type": "function" }, { "function": { "name": "alerts", "description": "Get alerts for Observability. Make sure get_alerts_dataset_info was called before.\n Use this to get open (and optionally recovered) alerts for Observability assets, like services,\n hosts or containers.\n Display the response in tabular format if appropriate.\n ", "parameters": { "type": "object", "properties": { "start": { "type": "string", "description": "The start of the time range, in Elasticsearch date math, like `now`." }, "end": { "type": "string", "description": "The end of the time range, in Elasticsearch date math, like `now-24h`." }, "kqlFilter": { "type": "string", "description": "Filter alerts by field:value pairs" }, "includeRecovered": { "type": "boolean", "description": "Whether to include recovered/closed alerts. Defaults to false, which means only active alerts will be returned" } }, "required": ["start", "end"] } }, "type": "function" }, { "function": { "name": "changes", "description": "Returns change points like spikes and dips for logs and metrics.", "parameters": { "type": "object", "properties": { "start": { "type": "string", "description": "The beginning of the time range, in datemath, like now-24h, or an ISO timestamp" }, "end": { "type": "string", "description": "The end of the time range, in datemath, like now, or an ISO timestamp" }, "logs": { "description": "Analyze changes in log patterns. If no index is given, the default logs index pattern will be used", "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of this set of logs" }, "index": { "type": "string", "description": "The index or index pattern where to find the logs" }, "kqlFilter": { "type": "string", "description": "A KQL filter to filter the log documents by, e.g. my_field:foo" }, "field": { "type": "string", "description": "The text field that contains the message to be analyzed, usually `message`. ONLY use field names from the conversation." } }, "required": ["name"] } }, "metrics": { "description": "Analyze changes in metrics. DO NOT UNDER ANY CIRCUMSTANCES use date or metric fields for groupBy, leave empty unless needed.", "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of this set of metrics" }, "index": { "type": "string", "description": "The index or index pattern where to find the metrics" }, "kqlFilter": { "type": "string", "description": "A KQL filter to filter the log documents by, e.g. my_field:foo" }, "field": { "type": "string", "description": "Metric field that contains the metric. Only use if the metric aggregation type is not count." }, "type": { "type": "string", "description": "The type of metric aggregation to perform. Defaults to count", "enum": ["count", "avg", "sum", "min", "max", "p95", "p99"] }, "groupBy": { "type": "array", "description": "Optional keyword fields to group metrics by.", "items": { "type": "string" } } }, "required": ["index", "name"] } } }, "required": ["start", "end"] } }, "type": "function" }, { "function": { "name": "summarize", "description": "Use this function to store facts in the knowledge database if the user requests it.\n You can score the learnings with a confidence metric, whether it is a correction on a previous learning.\n An embedding will be created that you can recall later with a semantic search.\n When you create this summarisation, make sure you craft it in a way that can be recalled with a semantic\n search later, and that it would have answered the user's original request.", "parameters": { "type": "object", "properties": { "id": { "type": "string", "description": "An id for the document. This should be a short human-readable keyword field with only alphabetic characters and underscores, that allow you to update it later." }, "text": { "type": "string", "description": "A human-readable summary of what you have learned, described in such a way that you can recall it later with semantic search, and that it would have answered the user's original request." }, "is_correction": { "type": "boolean", "description": "Whether this is a correction for a previous learning." }, "confidence": { "type": "string", "description": "How confident you are about this being a correct and useful learning", "enum": ["low", "medium", "high"] }, "public": { "type": "boolean", "description": "Whether this information is specific to the user, or generally applicable to any user of the product" } }, "required": ["id", "text", "is_correction", "confidence", "public"] } }, "type": "function" }, { "function": { "name": "elasticsearch", "description": "Call Elasticsearch APIs on behalf of the user. Make sure the request body is valid for the API that you are using. Only call this function when the user has explicitly requested it.", "parameters": { "type": "object", "properties": { "method": { "type": "string", "description": "The HTTP method of the Elasticsearch endpoint", "enum": ["GET", "PUT", "POST", "DELETE", "PATCH"] }, "path": { "type": "string", "description": "The path of the Elasticsearch endpoint, including query parameters" }, "body": { "type": "object", "description": "The body of the request" } }, "required": ["method", "path"] } }, "type": "function" }, { "function": { "name": "kibana", "description": "Call Kibana APIs on behalf of the user. Only call this function when the user has explicitly requested it, and you know how to call it, for example by querying the knowledge base or having the user explain it to you. Assume that pathnames, bodies and query parameters may have changed since your knowledge cut off date.", "parameters": { "type": "object", "properties": { "method": { "type": "string", "description": "The HTTP method of the Kibana endpoint", "enum": ["GET", "PUT", "POST", "DELETE", "PATCH"] }, "pathname": { "type": "string", "description": "The pathname of the Kibana endpoint, excluding query parameters" }, "query": { "type": "object", "description": "The query parameters, as an object" }, "body": { "type": "object", "description": "The body of the request" } }, "required": ["method", "pathname"] } }, "type": "function" }, { "function": { "name": "get_dataset_info", "description": "Use this function to get information about indices/datasets available and the fields available on them.\n\n providing empty string as index name will retrieve all indices\n else list of all fields for the given index will be given. if no fields are returned this means no indices were matched by provided index pattern.\n wildcards can be part of index name.", "parameters": { "type": "object", "properties": { "index": { "type": "string", "description": "index pattern the user is interested in or empty string to get information about all available indices" } }, "required": ["index"] } }, "type": "function" }, { "function": { "name": "execute_connector", "description": "Use this function when user explicitly asks to call a kibana connector.", "parameters": { "type": "object", "properties": { "id": { "type": "string", "description": "The id of the connector" }, "params": { "type": "object", "description": "The connector parameters" } }, "required": ["id", "params"] } }, "type": "function" } ], "temperature": 0 } ```
_OpenAI request object **after** the above update:_
Click to expand JSON ```json { "messages": [ { "role": "system", "content": "You are a helpful assistant for Elastic Observability. Your goal is to help the Elastic Observability users to quickly assess what is happening in their observed systems. You can help them visualise and analyze data, investigate their systems, perform root cause analysis or identify optimisation opportunities.\n\n It's very important to not assume what the user is meaning. Ask them for clarification if needed.\n\n If you are unsure about which function should be used and with what arguments, ask the user for clarification or confirmation.\n\n In KQL (\"kqlFilter\")) escaping happens with double quotes, not single quotes. Some characters that need escaping are: ':()\\ /\". Always put a field value in double quotes. Best: service.name:\"opbeans-go\". Wrong: service.name:opbeans-go. This is very important!\n\n You can use Github-flavored Markdown in your responses. If a function returns an array, consider using a Markdown table to format the response.\n\n Note that ES|QL (the Elasticsearch Query Language which is a new piped language) is the preferred query language.\n\n If you want to call a function or tool, only call it a single time per message. Wait until the function has been executed and its results\n returned to you, before executing the same tool or another tool again if needed.\n\n DO NOT UNDER ANY CIRCUMSTANCES USE ES|QL syntax (`service.name == \"foo\"`) with \"kqlFilter\" (`service.name:\"foo\"`).\n\n The user is able to change the language which they want you to reply in on the settings page of the AI Assistant for Observability, which can be found in the Stack Management app under the option AI Assistants.\n If the user asks how to change the language, reply in the same language the user asked in.\n\nYou MUST use the \"query\" function when the user wants to:\n - visualize data\n - run any arbitrary query\n - breakdown or filter ES|QL queries that are displayed on the current page\n - convert queries from another language to ES|QL\n - asks general questions about ES|QL\n\n DO NOT UNDER ANY CIRCUMSTANCES generate ES|QL queries or explain anything about the ES|QL query language yourself.\n DO NOT UNDER ANY CIRCUMSTANCES try to correct an ES|QL query yourself - always use the \"query\" function for this.\n\n If the user asks for a query, and one of the dataset info functions was called and returned no results, you should still call the query function to generate an example query.\n\n Even if the \"query\" function was used before that, follow it up with the \"query\" function. If a query fails, do not attempt to correct it yourself. Again you should call the \"query\" function,\n even if it has been called before.\n\n When the \"visualize_query\" function has been called, a visualization has been displayed to the user. DO NOT UNDER ANY CIRCUMSTANCES follow up a \"visualize_query\" function call with your own visualization attempt.\n If the \"execute_query\" function has been called, summarize these results for the user. The user does not see a visualization in this case.\n\nYou MUST use the \"get_dataset_info\" function before calling the \"query\" or the \"changes\" functions.\n\nIf a function requires an index, you MUST use the results from the dataset info functions.\n\nYou have access to data on the screen by calling the \"get_data_on_screen\" function.\nUse it to help the user understand what they are looking at. A short summary of what they are looking at is available in the return of the \"context\" function.\nData that is compact enough automatically gets included in the response for the \"context\" function.\n\nYou can use the \"summarize\" function to store new information you have learned in a knowledge database.\nOnly use this function when the user asks for it.\nAll summaries MUST be created in English, even if the conversation was carried out in a different language.\nThe \"get_data_on_screen\" function will Get data that is on the screen:\n.es-query: An available rule is Elasticsearch query.\nobservability.rules.custom_threshold: An available rule is Custom threshold.\nxpack.ml.anomaly_detection_alert: An available rule is Anomaly detection.\nslo.rules.burnRate: An available rule is SLO burn rate.\nmetrics.alert.threshold: An available rule is Metric threshold.\nmetrics.alert.inventory.threshold: An available rule is Inventory.\nlogs.alert.document.count: An available rule is Log threshold.\nxpack.uptime.alerts.tlsCertificate: An available rule is Uptime TLS.\nxpack.uptime.alerts.monitorStatus: An available rule is Uptime monitor status.\nxpack.uptime.alerts.durationAnomaly: An available rule is Uptime Duration Anomaly.\nxpack.synthetics.alerts.monitorStatus: An available rule is Synthetics monitor status.\nxpack.synthetics.alerts.tls: An available rule is Synthetics TLS certificate.\napm.error_rate: An available rule is Error count threshold.\napm.transaction_error_rate: An available rule is Failed transaction rate threshold.\napm.transaction_duration: An available rule is Latency threshold.\napm.anomaly: An available rule is APM Anomaly." }, { "role": "user", "content": "Can you explain this page?" }, { "role": "assistant", "content": "", "function_call": { "name": "context", "arguments": "{}" } }, { "role": "user", "content": "{\"screen_description\":\"The user is looking at http://localhost:5601/phq/app/observability/alerts?_a=(filters:!(),kuery:%27%27,rangeFrom:now-24h,rangeTo:now,status:all). The current time range is 2024-10-21T18:23:54.539Z - 2024-10-21T18:38:54.539Z.\",\"learnings\":[],\"data_on_screen\":[{\"name\":\".es-query\",\"value\":\"Elasticsearch query Alert when matches are found during the latest query run.\",\"description\":\"An available rule is Elasticsearch query.\"},{\"name\":\"observability.rules.custom_threshold\",\"value\":\"Custom threshold Alert when any Observability data type reaches or exceeds a given value.\",\"description\":\"An available rule is Custom threshold.\"},{\"name\":\"xpack.ml.anomaly_detection_alert\",\"value\":\"Anomaly detection Alert when anomaly detection jobs results match the condition.\",\"description\":\"An available rule is Anomaly detection.\"},{\"name\":\"slo.rules.burnRate\",\"value\":\"SLO burn rate Alert when your SLO burn rate is too high over a defined period of time.\",\"description\":\"An available rule is SLO burn rate.\"},{\"name\":\"metrics.alert.threshold\",\"value\":\"Metric threshold Alert when the metrics aggregation exceeds the threshold.\",\"description\":\"An available rule is Metric threshold.\"},{\"name\":\"metrics.alert.inventory.threshold\",\"value\":\"Inventory Alert when the inventory exceeds a defined threshold.\",\"description\":\"An available rule is Inventory.\"},{\"name\":\"logs.alert.document.count\",\"value\":\"Log threshold Alert when the log aggregation exceeds the threshold.\",\"description\":\"An available rule is Log threshold.\"},{\"name\":\"xpack.uptime.alerts.tlsCertificate\",\"value\":\"Uptime TLS Alert when the TLS certificate of an Uptime monitor is about to expire.\",\"description\":\"An available rule is Uptime TLS.\"},{\"name\":\"xpack.uptime.alerts.monitorStatus\",\"value\":\"Uptime monitor status Alert when a monitor is down or an availability threshold is breached.\",\"description\":\"An available rule is Uptime monitor status.\"},{\"name\":\"xpack.uptime.alerts.durationAnomaly\",\"value\":\"Uptime Duration Anomaly Alert when the Uptime monitor duration is anomalous.\",\"description\":\"An available rule is Uptime Duration Anomaly.\"},{\"name\":\"xpack.synthetics.alerts.monitorStatus\",\"value\":\"Synthetics monitor status Alert when a monitor is down.\",\"description\":\"An available rule is Synthetics monitor status.\"},{\"name\":\"xpack.synthetics.alerts.tls\",\"value\":\"Synthetics TLS certificate Alert when the TLS certificate of a Synthetics monitor is about to expire.\",\"description\":\"An available rule is Synthetics TLS certificate.\"},{\"name\":\"apm.error_rate\",\"value\":\"Error count threshold Alert when the number of errors in a service exceeds a defined threshold.\",\"description\":\"An available rule is Error count threshold.\"},{\"name\":\"apm.transaction_error_rate\",\"value\":\"Failed transaction rate threshold Alert when the rate of transaction errors in a service exceeds a defined threshold.\",\"description\":\"An available rule is Failed transaction rate threshold.\"},{\"name\":\"apm.transaction_duration\",\"value\":\"Latency threshold Alert when the latency of a specific transaction type in a service exceeds a defined threshold.\",\"description\":\"An available rule is Latency threshold.\"},{\"name\":\"apm.anomaly\",\"value\":\"APM Anomaly Alert when either the latency, throughput, or failed transaction rate of a service is anomalous.\",\"description\":\"An available rule is APM Anomaly.\"}]}", "name": "context" } ], "stream": true, "tools": [ { "function": { "name": "get_data_on_screen", "parameters": { "type": "object", "properties": { "data": { "type": "array", "description": "The pieces of data you want to look at it. You can request one, or multiple", "items": { "type": "string", "enum": [ ".es-query", "observability.rules.custom_threshold", "xpack.ml.anomaly_detection_alert", "slo.rules.burnRate", "metrics.alert.threshold", "metrics.alert.inventory.threshold", "logs.alert.document.count", "xpack.uptime.alerts.tlsCertificate", "xpack.uptime.alerts.monitorStatus", "xpack.uptime.alerts.durationAnomaly", "xpack.synthetics.alerts.monitorStatus", "xpack.synthetics.alerts.tls", "apm.error_rate", "apm.transaction_error_rate", "apm.transaction_duration", "apm.anomaly" ] } } }, "required": ["data"] } }, "type": "function" }, { "function": { "name": "query", "description": "This function generates, executes and/or visualizes a query\n based on the user's request. It also explains how ES|QL works and how to\n convert queries from one language to another. Make sure you call one of\n the get_dataset functions first if you need index or field names. This\n function takes no input.", "parameters": { "type": "object", "properties": {} } }, "type": "function" }, { "function": { "name": "get_alerts_dataset_info", "description": "Use this function to get information about alerts data.", "parameters": { "type": "object", "properties": { "start": { "type": "string", "description": "The start of the current time range, in datemath, like now-24h or an ISO timestamp" }, "end": { "type": "string", "description": "The end of the current time range, in datemath, like now-24h or an ISO timestamp" } } } }, "type": "function" }, { "function": { "name": "alerts", "description": "Get alerts for Observability. Make sure get_alerts_dataset_info was called before.\n Use this to get open (and optionally recovered) alerts for Observability assets, like services,\n hosts or containers.\n Display the response in tabular format if appropriate.\n ", "parameters": { "type": "object", "properties": { "start": { "type": "string", "description": "The start of the time range, in Elasticsearch date math, like `now`." }, "end": { "type": "string", "description": "The end of the time range, in Elasticsearch date math, like `now-24h`." }, "kqlFilter": { "type": "string", "description": "Filter alerts by field:value pairs" }, "includeRecovered": { "type": "boolean", "description": "Whether to include recovered/closed alerts. Defaults to false, which means only active alerts will be returned" } }, "required": ["start", "end"] } }, "type": "function" }, { "function": { "name": "changes", "description": "Returns change points like spikes and dips for logs and metrics.", "parameters": { "type": "object", "properties": { "start": { "type": "string", "description": "The beginning of the time range, in datemath, like now-24h, or an ISO timestamp" }, "end": { "type": "string", "description": "The end of the time range, in datemath, like now, or an ISO timestamp" }, "logs": { "description": "Analyze changes in log patterns. If no index is given, the default logs index pattern will be used", "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of this set of logs" }, "index": { "type": "string", "description": "The index or index pattern where to find the logs" }, "kqlFilter": { "type": "string", "description": "A KQL filter to filter the log documents by, e.g. my_field:foo" }, "field": { "type": "string", "description": "The text field that contains the message to be analyzed, usually `message`. ONLY use field names from the conversation." } }, "required": ["name"] } }, "metrics": { "description": "Analyze changes in metrics. DO NOT UNDER ANY CIRCUMSTANCES use date or metric fields for groupBy, leave empty unless needed.", "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of this set of metrics" }, "index": { "type": "string", "description": "The index or index pattern where to find the metrics" }, "kqlFilter": { "type": "string", "description": "A KQL filter to filter the log documents by, e.g. my_field:foo" }, "field": { "type": "string", "description": "Metric field that contains the metric. Only use if the metric aggregation type is not count." }, "type": { "type": "string", "description": "The type of metric aggregation to perform. Defaults to count", "enum": ["count", "avg", "sum", "min", "max", "p95", "p99"] }, "groupBy": { "type": "array", "description": "Optional keyword fields to group metrics by.", "items": { "type": "string" } } }, "required": ["index", "name"] } } }, "required": ["start", "end"] } }, "type": "function" }, { "function": { "name": "summarize", "description": "Use this function to store facts in the knowledge database if the user requests it.\n You can score the learnings with a confidence metric, whether it is a correction on a previous learning.\n An embedding will be created that you can recall later with a semantic search.\n When you create this summarisation, make sure you craft it in a way that can be recalled with a semantic\n search later, and that it would have answered the user's original request.", "parameters": { "type": "object", "properties": { "id": { "type": "string", "description": "An id for the document. This should be a short human-readable keyword field with only alphabetic characters and underscores, that allow you to update it later." }, "text": { "type": "string", "description": "A human-readable summary of what you have learned, described in such a way that you can recall it later with semantic search, and that it would have answered the user's original request." }, "is_correction": { "type": "boolean", "description": "Whether this is a correction for a previous learning." }, "confidence": { "type": "string", "description": "How confident you are about this being a correct and useful learning", "enum": ["low", "medium", "high"] }, "public": { "type": "boolean", "description": "Whether this information is specific to the user, or generally applicable to any user of the product" } }, "required": ["id", "text", "is_correction", "confidence", "public"] } }, "type": "function" }, { "function": { "name": "elasticsearch", "description": "Call Elasticsearch APIs on behalf of the user. Make sure the request body is valid for the API that you are using. Only call this function when the user has explicitly requested it.", "parameters": { "type": "object", "properties": { "method": { "type": "string", "description": "The HTTP method of the Elasticsearch endpoint", "enum": ["GET", "PUT", "POST", "DELETE", "PATCH"] }, "path": { "type": "string", "description": "The path of the Elasticsearch endpoint, including query parameters" }, "body": { "type": "object", "description": "The body of the request" } }, "required": ["method", "path"] } }, "type": "function" }, { "function": { "name": "kibana", "description": "Call Kibana APIs on behalf of the user. Only call this function when the user has explicitly requested it, and you know how to call it, for example by querying the knowledge base or having the user explain it to you. Assume that pathnames, bodies and query parameters may have changed since your knowledge cut off date.", "parameters": { "type": "object", "properties": { "method": { "type": "string", "description": "The HTTP method of the Kibana endpoint", "enum": ["GET", "PUT", "POST", "DELETE", "PATCH"] }, "pathname": { "type": "string", "description": "The pathname of the Kibana endpoint, excluding query parameters" }, "query": { "type": "object", "description": "The query parameters, as an object" }, "body": { "type": "object", "description": "The body of the request" } }, "required": ["method", "pathname"] } }, "type": "function" }, { "function": { "name": "get_dataset_info", "description": "Use this function to get information about indices/datasets available and the fields available on them.\n\n providing empty string as index name will retrieve all indices\n else list of all fields for the given index will be given. if no fields are returned this means no indices were matched by provided index pattern.\n wildcards can be part of index name.", "parameters": { "type": "object", "properties": { "index": { "type": "string", "description": "index pattern the user is interested in or empty string to get information about all available indices" } }, "required": ["index"] } }, "type": "function" }, { "function": { "name": "execute_connector", "description": "Use this function when user explicitly asks to call a kibana connector.", "parameters": { "type": "object", "properties": { "id": { "type": "string", "description": "The id of the connector" }, "params": { "type": "object", "description": "The connector parameters" } }, "required": ["id", "params"] } }, "type": "function" } ], "temperature": 0 } ```
--------- Co-authored-by: Søren Louv-Jansen [Screenshotting] Organize dev docs for screenshotting/chromium (#198100) * Remove duplicated “File service” entry from nav * Move Screenshotting to main Tutorials section in nav * Add “Updating Puppeteer and Chromium” to nav as a sub-item of screenshotting * Move files for Screenshotting/Chromium out of the SharedUX space to `dev_docs/tutorials/screenshotting` Update docker.elastic.co/wolfi/chainguard-base:latest Docker digest to 8cff240 (main) (#198271) This PR contains the following updates: | Package | Update | Change | |---|---|---| | docker.elastic.co/wolfi/chainguard-base | digest | `1815394` -> `8cff240` | --- 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> [ML] Fix overall bucket request for large number of job IDs (#198292) Fixes https://github.com/elastic/kibana/issues/190591 Adds chunking for `over_buckets` request to prevent exceeding the request length URL. - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios [Security Solution][Alert details] - refactor UI on insights (#197349) This PR refactors the Insights section of the expandable flyout for alerts and events. The changes are applied to the following section: - Threat Intelligence: when the user clicks on the number, we open the left section to the Insights Threat Intelligence tab - Correlations: when the user clicks on the number, we open the left section to the Insights Correlations tab - Prevalence: no user interactions When in preview mode, none of the number are clickable and the buttons are disabled. | Normal flyout | Preview flyout | | ------------- | ------------- | | ![Screenshot 2024-10-22 at 6 01 38 PM](https://github.com/user-attachments/assets/de179a2b-c8ab-42f6-b5b7-839dae0139d5) | ![Screenshot 2024-10-22 at 6 01 54 PM](https://github.com/user-attachments/assets/63ed125e-5e3b-4c4c-a10e-7cc01d291660) | https://github.com/user-attachments/assets/30031a12-c2f3-47e6-a783-5b9482359ee5 https://github.com/elastic/security-team/issues/7033 - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios Fix flaky alert flapping test (#198013) Resolves https://github.com/elastic/kibana/issues/195573 In this PR, I'm un-skipping the alerts as data flapping tests. The flaky test runners weren't able to reproduce the flakiness. I believe it's because we needed to wait longer after changing the flapping settings for the cache to clear. This is already done in https://github.com/elastic/kibana/pull/197070/files#diff-3d57bae0b495bddd934b87ca29e2f43fa21bab9bf304b5d359d7e230284415c0 but it was merged after the test was skipped. Flaky test runners: - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7286 - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7293 - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7306 [Detection Engine][FTRs] Break down long running FTR groups and fix threshold preview bug (#197368) This PR breaks down long running FTR groups into smaller chunks that now run in <~15 min. - Addresses https://github.com/elastic/kibana/issues/192109 - There is no existing ticket but rule_execution group tests are taking ~55m to run and will soon be a bottle neck for us. - No edits made to any existing tests. - Purely just a reshuffle of the tests. See https://github.com/elastic/kibana/issues/198209 for details on bug. [Mappings editor] Handle unsupported types (#198185) Fixes https://github.com/elastic/kibana/issues/197592 This PR fixes the bug where the index Mappings details page crashes if the index has a mapping field with a type that is not recognized in Kibana. We fix this by using `getTypeLabelFromField` instead of directly fetching the `label` property of an object that might be `undefined` - `getTypeLabelFromField` takes care of this case. **How to test:** 1. Create the following index in Console (it has the unsupported `counted_keyword` field type): ``` PUT test { "mappings": { "properties": { "@timestamp": { "type": "date" }, "log": { "type": "text" }, "ids": { "type": "counted_keyword" } } } } ``` 2. Go to Index Management and click on the index that we just created 3. Go to Mappings tab 4. Verify that the page loads correctly 5. Check that the opening filter and selecting an option doesn't make the page crash. https://github.com/user-attachments/assets/4a595968-7cd8-4d36-9a53-264a0d5db50f [Authz] Added section for migration routes created by utility function (#198401) - Added section for migrating routes created by utility function. - Added `patch` method to route methods in eslint rule. - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials [ci] Run type checking before tests (#197539) [FTR][Ownership] Assign health_gateway, etc (#197980) Assigned health_gateway due to https://github.com/elastic/kibana/blob/main/test/health_gateway/plugins/status/kibana.jsonc#L4 Assigned interpreter_functional due to https://github.com/elastic/kibana/blob/main/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.jsonc#L4 - But it is an educated guess - same with "...saved_objects*" Assigned home due to https://github.com/elastic/kibana/blob/main/src/plugins/home/kibana.jsonc#L5 Assigned otel_metrics due to https://github.com/elastic/kibana/blob/main/test/common/plugins/otel_metrics/kibana.jsonc#L4 Assigned content_management due to https://github.com/elastic/kibana/blob/main/api_docs/content_management.mdx#L18 - It says "Contact @elastic/appex-sharedux for questions regarding this plugin." Assigned kibana_overview due to https://github.com/elastic/kibana/blob/main/api_docs/kibana_overview.mdx#L14 - Says the same as above Assigned node_roles_functional due to https://github.com/elastic/kibana/blob/main/test/node_roles_functional/plugins/core_plugin_initializer_context/kibana.jsonc#L4 Assigned app_link_test due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/app_link_test/kibana.jsonc#L4 Assigned data_search due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/data_search/kibana.jsonc#L4 Assigned elasticsearch_client_plugin due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/elasticsearch_client_plugin/kibana.jsonc#L4 Assigned eui_provider_dev_warning due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/eui_provider_dev_warning/kibana.jsonc#L4 Assigned index_patterns due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/index_patterns/kibana.jsonc#L4 Assigned kbn_sample_panel_action due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.jsonc#L3-L4 Assigned kbn_top_nav due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/kbn_top_nav/kibana.jsonc#L4 Assigned management_test_plugin due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/management_test_plugin/kibana.jsonc#L4 Contributes to: https://github.com/elastic/kibana/issues/192979 --------- Co-authored-by: Robert Oskamp Co-authored-by: Elastic Machine [OAS] Beautify generated operation ids (#198132) fix: kubectl annotate command (#198414) In kubectl annotate commands, we should use an equals sign (=) instead of a colon when setting the annotation value. ``` $ kubectl annotate namespace java instrumentation.opentelemetry.io/inject-java: "opentelemetry-operator-system/elastic-instrumentation" error: at least one annotation update is required $ kubectl annotate namespace java instrumentation.opentelemetry.io/inject-java="opentelemetry-operator-system/elastic-instrumentation" namespace/java annotated ``` Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) - [ ] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) [ci] More resources for check oas snapshot (#198433) This step doesn't have enough CPU/memory for the number of processes running. [Security Assistant] Knowledge base switch to use `semantic_text` (#197007) - `text_expansion` is deprecated, use `semantic_text` instead - fix KB index entry form field options - explicitly create inference endpoint on KB setup if `assistantKnowledgeBaseByDefault` is true - when upgrade from v1 update KB ingest pipeline and remove unnecessary processor, but keep the pipeline for the backward compatibility - switch to use `doc` update for KB entries due to the limitations od `semantic_text` https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-text.html#update-script - split loading Security labs content into smaller chunks --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Pedro Jaramillo [ResponseOps] Cleanup alerting RBAC exception code (#197719) Resolves https://github.com/elastic/response-ops-team/issues/250 This PR eliminates the alerting RBAC exemption code. It removes all references to `getAuthorizationModeBySource` and `bulkGetAuthorizationModeBySource`, along with the corresponding legacy RBAC usage counters. Additionally, downstream code paths that rely on RBAC for authorization have been updated, and all related test cases have been removed. [ES|QL] Add`SORT` command mutation APIs (#197185) Partially addresses https://github.com/elastic/kibana/issues/191812 - Adds traversal and manipulation APIs for `SORT` command. - `commands.sort.listCommands()` - `commands.sort.getCommand()` - `commands.sort.list()` - `commands.sort.findByPredicate()` - `commands.sort.find()` - `commands.sort.remove()` - `commands.sort.insertIntoCommand()` - `commands.sort.insertExpression()` - `commands.sort.insertCommand()` - Refactors "generic" AST manipulation routines into (1) `commands`, (2) `commands.args`, (3) `commands.options`. - `generic.commands.*` - `generic.commands.args.*` - `generic.commands.options.*` Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) --------- Co-authored-by: Stratoula Kalafateli [ObsUX][Infra] Add telemetry for anomaly job creation (#198061) Closes https://github.com/elastic/kibana/issues/189619 Telemetry events created: - Infra Anomaly Detection Job Setup ``` { "event_type":"Infra Anomaly Detection Job Setup", "context":{...} "properties": { "job_type":"host", "configured_fields":{"start_date":"2024-09-24T16:11:41.446Z","partition_field":"cloud.instance.id","filter_field": "host.name:\"gke-edge-lite-oblt-edge-lite-oblt-poo-f77db573-2249\"} } } ``` - Infra Anomaly Detection Job Date Field Change ``` { "event_type":" Infra Anomaly Detection Job Date Field Change", "context":{...} "properties": { "job_type":"host", "start_date":"2024-09-24T16:11:41.446Z" } } ``` - Infra Anomaly Detection Job Partition Field Change ``` { "event_type":" Infra Anomaly Detection Job Date Field Change", "context":{...} "properties": { "job_type":"host", "partition_field":"cloud.instance.id" } } ``` - Infra Anomaly Detection Job Filter Field Change ``` { "event_type":" Infra Anomaly Detection Job Date Field Change", "context":{...} "properties": { "job_type":"host", "filter_field": "host.name:\"gke-edge-lite-oblt-edge-lite-oblt-poo-f77db573-2249\" } } ``` [Security AI Assistant] Fixed license issue for Knowledge Base resources initialization (#198239) [UII] Replace `kibanaVersionCheckEnabled` default value instead of config setting (#198172) This PR removes `xpack.fleet.internal.registry.kibanaVersionCheckEnabled: false` from `kibana.yml` in favor of changing the default value that Fleet populates, so that we do not apply the Kibana version constraint to EPR requests for >= 9.0 deployments. Prior to this change, this setting was not applied to ESS deployments as `kibana.yml` is overridden there. I updated the related task in https://github.com/elastic/kibana/issues/192624 to reflect this change. [Entity Analytics] [Entity Store] Add audit logs (#196847) This PR adds audit logs for the different actions that can be performed on the entity store engines. improve loading UI in Discover mobile (#197939) Closes https://github.com/elastic/kibana/issues/151503 In this PR, use the EuiEmptyPrompt component to update the loading UI --------- Co-authored-by: Davis McPhee [Security solution] `assistantKnowledgeBaseByDefault` flag defaults to `true` (#198178) Upgrade EUI to v97.3.0 (#198087) `v97.2.0`⏩`v97.3.0` _[Questions? Please see our Kibana upgrade FAQ.](https://github.com/elastic/eui/blob/main/wiki/eui-team-processes/upgrading-kibana.md#faq-for-kibana-teams)_ --- - `EuiDataGrid` now supports a new `toolbarVisibility.showDisplaySelector.customRender` function that allows completely customizing the rendering of the display selector popover ([#8080](https://github.com/elastic/eui/pull/8080)) - `EuiDataGrid`'s row height/lines per row setting has been streamlined in both UI and UX ([#8080](https://github.com/elastic/eui/pull/8080)) - `EuiDataGrid` now accepts consumer-passed display setting updates even after users have changed their display preferences via UI ([#8080](https://github.com/elastic/eui/pull/8080)) - Updated `EuiDataGrid` to vertically center all `toolbarVisibility.additionalControls` nodes ([#8085](https://github.com/elastic/eui/pull/8085)) - Updated `EuiDataGrid` with a beta `rowHeightsOptions.autoBelowLineCount` feature flag ([#8096](https://github.com/elastic/eui/pull/8096)) - Updated `EuiContextMenuPanel` to allow disabling initial focus via `initialFocusedItemIndex={-1}` ([#8101](https://github.com/elastic/eui/pull/8101)) **Bug fixes** - Fixed `EuiComment`'s typing to correctly reflect all accepted props ([#8089](https://github.com/elastic/eui/pull/8089)) - Fixed `EuiSelectableTemplateSitewide`s within dark-themed `EuiHeader`s missing input borders ([#8100](https://github.com/elastic/eui/pull/8100)) [Entity Analytics] [Entity Store] Show errors on entity store enablement (#198263) This PR adds user feedback for errors that happen when enabling the entity store. Any errors during the async setup of store resources will show up as toasts, whist initial INIT request failures will appear as an error callout. ![Screenshot 2024-10-29 at 16 48 03](https://github.com/user-attachments/assets/12aa9af3-1e27-44b1-85e5-5053255bd333) ![Screenshot 2024-10-29 at 16 47 19](https://github.com/user-attachments/assets/31790981-599b-4fba-a423-b75e31dbe7be) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> [api-docs] 2024-10-31 Daily api_docs build (#198464) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/877 [Search][Connectors] Elastic managed as default and some typos (#197571) Fixing **Elastic managed** as a default option when creating a new connector. And fixing _Self managed_ typo to become _Self-managed_ --------- Co-authored-by: Elastic Machine Remove square brackets in FROM METADATA declaration (#196991) Hello, this PR addresses the deprecation of square brackets in FROM METADATA declarations in Elasticsearch queries, in preparation for Elasticsearch 9.0. Closes #196988 The changes involve removing square brackets around metadata fields (e.g., `[metadata _id]` becomes `metadata _id`) across various parts of the codebase. No functional changes to the UE, only internal query syntax updates. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) - [ ] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Stratoula Kalafateli [CI] Quiet quickcheck i18n output (#197871) The i18n check spews out ~5k lines of log. This makes it difficult to spot any errors, or even break the check through some buffer issue. This PR quiets output from i18n quick check, yet keeping the error outputs. We've tested it in https://github.com/elastic/kibana/pull/194379, and locally (to see if we still see the errors) - it seems to have fixed errors from @pgayvallet 's case. --------- Co-authored-by: Elastic Machine [Stateful sidenav] Update feedback urls (#198143) [Index Management] Add support for index mode (#197874) Closes https://github.com/elastic/kibana/issues/195772 This PR displays the index mode setting in Index templates (at Review step in creation flow and at template details flyout) and Data streams (in ds table and ds details flyout). Screenshot 2024-10-28 at 14 39 18 Screenshot 2024-10-28 at 19 05 29 Screenshot 2024-10-28 at 14 41 01 Screenshot 2024-10-28 at 14 41 09 **Creating a Logsdb index template and data stream:** 1. Go to Index Managament -> Index templates and start creating a new template 2. Add a name and an index pattern `test-logsdb` and then go to the Settings step 3. Add the setting `"index.mode": "logsdb`. 4. Go to last step (review) and verify that the index mode is correctly displayed in Summary. Save the template. 5. In the template flyout, verify that the index mode displays the correct label. 6. Go to Console and create a data stream that mathes the index pattern of the created index template: `PUT _data_stream/test-logsdb` 7. Go to Index Management -> Data streams 8. In the data streams table, verify that the index mode column is correct for the new data stream. 9. Open the new data stream and verify that the details flyout displays the correct index mode. **Creating a Time series index template and data stream:** 1. Go to Index Managament -> Index templates and start creating a new template 2. Add a name and an index pattern `test-tsds` and then go to the Settings step 3. Add the setting `"index.mode": "time_series`. 4. For time series index template, we also need to add a mapping with a `time_series_dimension` property. Go to the Mappings step, click on "Load JSON" and add the following mappings object: ``` { "properties": { "id": { "type": "keyword", "time_series_dimension": true } } } ``` 6. Go to last step (review) and verify that the index mode is correctly displayed in Summary. Save the template. 7. In the template flyout, verify that the index mode displays the correct label. 8. Go to Console and create a data stream that mathes the index pattern of the created index template: `PUT _data_stream/test-tsds` 9. Go to Index Management -> Data streams 10. In the data streams table, verify that the index mode column is correct for the new data stream. 11. Open the new data stream and verify that the details flyout displays the correct index mode. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7288 - [x] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> [FTR][Ownership] Assign rendering_plugin, etc (#198024) Assign ownership for a handful of reviewing teams. Assigned rendering_plugin due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/rendering_plugin/kibana.jsonc#L3-L4 Assigned session_notifications due to https://github.com/elastic/kibana/blob/main/test/plugin_functional/plugins/session_notifications/kibana.jsonc#L4 Assigned saml_provider due to https://github.com/elastic/kibana/blob/main/x-pack/test/cloud_integration/plugins/saml_provider/kibana.jsonc#L4 Assigned defend_workflows_cypress due to the name Assigned riggers_actions_ui_examples due to https://github.com/elastic/kibana/blob/main/api_docs/triggers_actions_ui.mdx#L18 - It says "Contact @elastic/response-ops for questions regarding this plugin." Assigned fleet_packages due to the name Assigned management due to the name Assigned painless_lab due to https://github.com/elastic/kibana/blob/main/x-pack/plugins/painless_lab/kibana.jsonc#L5 Assigned remote_clusters due to https://github.com/elastic/kibana/blob/main/api_docs/remote_clusters.mdx#L18 Assigned logstash due to the name Assigned license_management due to https://github.com/elastic/kibana/blob/main/api_docs/license_management.mdx#L18 - It says "Contact @elastic/kibana-management for questions regarding this plugin." Assigned iframe_embedded due to https://github.com/elastic/kibana/blob/main/x-pack/test/functional_embedded/plugins/iframe_embedded/kibana.jsonc#L3-L4 Assigned functional_solution_sidenav due to https://github.com/elastic/kibana/pull/189804 (and git blame) Assigned cases due to https://github.com/elastic/kibana/blob/main/api_docs/cases.mdx#L18 - It says "Contact @elastic/response-ops for questions regarding this plugin." Contributes to: https://github.com/elastic/kibana/issues/192979 --------- Co-authored-by: Robert Oskamp Co-authored-by: Elastic Machine [Security Solution] [Onboarding] AI connectors card privileges escenarios (#198014) Issue #197397 - Fix how AI connectors cards handle the lack of privileges for user. **Before:** When user has none privileges inside the AI connectors card an infinite spinner is rendered. ![379211667-8f565693-a9a6-43dc-9a88-d6b678f5692c](https://github.com/user-attachments/assets/d2d6330d-d464-413a-bf18-3737db8d573c) **Introduced by this PR:** Screenshot 2024-10-28 at 15 52 53 User capabilities: `actions.show`, `actions.save` & `actions.execute` **Case 1.1** - User does not have any connector Untitled (1) **Case 1.2** - User already has connectors Untitled User capabilities: `actions.show` & `actions.execute` Screenshot 2024-10-28 at 15 51 39 **Case 2.1** - User does not have any connector Untitled (3) **Case 2.2** - User already has connectors Untitled (2) Screenshot 2024-10-28 at 15 52 16 Untitled (4) Delete any items that are not applicable to this PR. - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Elastic Machine Co-authored-by: Angela Chuang <6295984+angorayc@users.noreply.github.com> [ML] Fixes link to anomaly explorer from anomaly embeddables when viewing by job group (#198256) Fix for: [#196509](https://github.com/elastic/kibana/issues/196509) After fix: https://github.com/user-attachments/assets/9d731676-fd47-41fe-8843-8b8e6c6e153d [Security Solution][Serverless] Fixed yaml format for detection engine quality gate (#198470) Fixed detection engine yaml format for quality gate. fix(slo): handle custom DSL query filters (#198073) [Security Solution][Data Quality Dashboard][Serverless] Fix fetchAvailableIndices in get_index_stats (#197065) addresses #196528 - Remove unused get_available_indices.ts params helper file. - Change fetchAvailableIndices to use creation_date from _cat api instead of targeting @timestamp field of indices Before: ![image](https://github.com/user-attachments/assets/1954a8b6-1760-4ec7-b3d3-167b724f8b3c) After: ![image](https://github.com/user-attachments/assets/232674a1-9691-4d49-862e-99873f22c3cf) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Apply task manager backpressure whenever a 500 error is returned in the task store (#198418) In this PR, I'm making the task manager apply backpressure whenever a 500 error is returned in the task store (msearch or other SO I/O). 1. Apply the following diff, run Kibana and notice logs about poll interval and capacity configuration changing ``` diff --git a/x-pack/plugins/task_manager/server/task_store.ts b/x-pack/plugins/task_manager/server/task_store.ts index 2b3440e87c0..d2ffaa2f50f 100644 --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -574,6 +574,8 @@ export class TaskStore { const versionMap = this.createVersionMap([]); let allTasks = new Array(); + responses[0].status = 500; + for (const response of responses) { if (response.status !== 200) { const err = new MsearchError(response.status); ``` 2. Undo previous changes, apply the following diff, run Kibana and notice logs about poll interval and capacity configuration changing ``` diff --git a/x-pack/plugins/task_manager/server/task_store.ts b/x-pack/plugins/task_manager/server/task_store.ts index 2b3440e87c0..95d14152e1d 100644 --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -12,6 +12,7 @@ import murmurhash from 'murmurhash'; import { v4 } from 'uuid'; import { Subject } from 'rxjs'; import { omit, defaults, get } from 'lodash'; +import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { SavedObjectError } from '@kbn/core-saved-objects-common'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; @@ -474,6 +475,7 @@ export class TaskStore { public async bulkGet(ids: string[]): Promise { let result; try { + throw SavedObjectsErrorHelpers.decorateGeneralError(new Error('foo')); result = await this.savedObjectsRepository.bulkGet( ids.map((id) => ({ type: 'task', id })) ); ``` [Index Management] Fix globalMaxRetention display error in data retention modal (#198113) Fixes #197314 **After fixup:** ![image](https://github.com/user-attachments/assets/9fa66906-fa06-4e12-81d8-7bcdaaff3ff3) ![image](https://github.com/user-attachments/assets/a7b9ee72-4ce3-4d2b-8c14-483ea2028597) --------- Co-authored-by: Elastic Machine Fix flaky connector adapters test (#198396) Resolves https://github.com/elastic/kibana/issues/198388 In this PR, I'm increasing the rule frequency to avoid rule actions running multiple times when asserting for the action to only have ran once. Flaky test runner: - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7307 [Search][Connectors] Validating connectors name (#198483) Validating connectors name field before letting press Generate config or Next. ![CleanShot 2024-10-31 at 10 36 26](https://github.com/user-attachments/assets/3a9a1d93-89a5-425f-a932-666c59a7019c) OpenAPI docs for APM UI APIs (#197946) Closes #197582 This PR adds missing OpenAPI specification for APM UI APIs. Documentation specs have been divided into files per path. See [readme](https://github.com/elastic/kibana/blob/88e55f92f91e04112e831023e163e4990018de52/x-pack/plugins/observability_solution/apm/docs/openapi/apm/README.md) for specific information. Update ftr (main) (#198455) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [chromedriver](https://togithub.com/giggio/node-chromedriver) | devDependencies | major | [`^129.0.0` -> `^130.0.1`](https://renovatebot.com/diffs/npm/chromedriver/129.0.1/130.0.1) | | [geckodriver](https://togithub.com/webdriverio-community/node-geckodriver) | devDependencies | minor | [`^4.4.4` -> `^4.5.1`](https://renovatebot.com/diffs/npm/geckodriver/4.4.4/4.5.1) | ---
giggio/node-chromedriver (chromedriver) [`v130.0.1`](https://togithub.com/giggio/node-chromedriver/compare/130.0.0...130.0.1) [Compare Source](https://togithub.com/giggio/node-chromedriver/compare/130.0.0...130.0.1) [`v130.0.0`](https://togithub.com/giggio/node-chromedriver/compare/129.0.4...130.0.0) [Compare Source](https://togithub.com/giggio/node-chromedriver/compare/129.0.4...130.0.0) [`v129.0.4`](https://togithub.com/giggio/node-chromedriver/compare/129.0.3...129.0.4) [Compare Source](https://togithub.com/giggio/node-chromedriver/compare/129.0.3...129.0.4) [`v129.0.3`](https://togithub.com/giggio/node-chromedriver/compare/129.0.2...129.0.3) [Compare Source](https://togithub.com/giggio/node-chromedriver/compare/129.0.2...129.0.3) [`v129.0.2`](https://togithub.com/giggio/node-chromedriver/compare/129.0.1...129.0.2) [Compare Source](https://togithub.com/giggio/node-chromedriver/compare/129.0.1...129.0.2)
webdriverio-community/node-geckodriver (geckodriver) [`v4.5.1`](https://togithub.com/webdriverio-community/node-geckodriver/releases/tag/v4.5.1): Release 4.5.1 [Compare Source](https://togithub.com/webdriverio-community/node-geckodriver/compare/v4.5.0...v4.5.1) - fix: correct type on gecko driver params to be logNoTruncate instead of logNoTruncated ([#​567](https://togithub.com/webdriverio-community/node-geckodriver/issues/567)) ([`138fde4`](https://togithub.com/webdriverio-community/node-geckodriver/commit/138fde4)) - chore(deps-dev): bump [@​vitest/coverage-v8](https://togithub.com/vitest/coverage-v8) from 2.1.1 to 2.1.2 ([#​562](https://togithub.com/webdriverio-community/node-geckodriver/issues/562)) ([`c67f71f`](https://togithub.com/webdriverio-community/node-geckodriver/commit/c67f71f)) - chore(deps-dev): bump eslint-plugin-unicorn from 55.0.0 to 56.0.0 ([#​563](https://togithub.com/webdriverio-community/node-geckodriver/issues/563)) ([`8976f2c`](https://togithub.com/webdriverio-community/node-geckodriver/commit/8976f2c)) - chore(deps-dev): bump release-it from 17.6.0 to 17.7.0 ([#​559](https://togithub.com/webdriverio-community/node-geckodriver/issues/559)) ([`81cee91`](https://togithub.com/webdriverio-community/node-geckodriver/commit/81cee91)) - chore(deps-dev): bump eslint-plugin-import from 2.30.0 to 2.31.0 ([#​561](https://togithub.com/webdriverio-community/node-geckodriver/issues/561)) ([`17fc269`](https://togithub.com/webdriverio-community/node-geckodriver/commit/17fc269)) - chore(deps-dev): bump [@​typescript-eslint/eslint-plugin](https://togithub.com/typescript-eslint/eslint-plugin) ([#​557](https://togithub.com/webdriverio-community/node-geckodriver/issues/557)) ([`0adbf99`](https://togithub.com/webdriverio-community/node-geckodriver/commit/0adbf99)) - chore(deps-dev): bump webdriverio from 9.0.9 to 9.1.2 ([#​555](https://togithub.com/webdriverio-community/node-geckodriver/issues/555)) ([`82d20c7`](https://togithub.com/webdriverio-community/node-geckodriver/commit/82d20c7)) - chore(deps-dev): bump [@​types/node](https://togithub.com/types/node) from 22.5.5 to 22.7.4 ([#​554](https://togithub.com/webdriverio-community/node-geckodriver/issues/554)) ([`15a13a8`](https://togithub.com/webdriverio-community/node-geckodriver/commit/15a13a8)) - chore(deps-dev): bump [@​typescript-eslint/parser](https://togithub.com/typescript-eslint/parser) from 8.6.0 to 8.7.0 ([#​556](https://togithub.com/webdriverio-community/node-geckodriver/issues/556)) ([`a15da9a`](https://togithub.com/webdriverio-community/node-geckodriver/commit/a15da9a)) [`v4.5.0`](https://togithub.com/webdriverio-community/node-geckodriver/releases/tag/v4.5.0): Release 4.5.0 [Compare Source](https://togithub.com/webdriverio-community/node-geckodriver/compare/v4.4.4...v4.5.0) - feat: support spawnOpts for geckodriver child process ([#​552](https://togithub.com/webdriverio-community/node-geckodriver/issues/552)) ([`3edaf8e`](https://togithub.com/webdriverio-community/node-geckodriver/commit/3edaf8e)) - chore(deps): bump rollup from 4.21.3 to 4.22.4 ([#​551](https://togithub.com/webdriverio-community/node-geckodriver/issues/551)) ([`2b429a4`](https://togithub.com/webdriverio-community/node-geckodriver/commit/2b429a4)) - chore(deps-dev): bump [@​typescript-eslint/parser](https://togithub.com/typescript-eslint/parser) from 8.5.0 to 8.6.0 ([#​548](https://togithub.com/webdriverio-community/node-geckodriver/issues/548)) ([`c24a4c6`](https://togithub.com/webdriverio-community/node-geckodriver/commit/c24a4c6)) - chore(deps-dev): bump [@​typescript-eslint/eslint-plugin](https://togithub.com/typescript-eslint/eslint-plugin) ([#​549](https://togithub.com/webdriverio-community/node-geckodriver/issues/549)) ([`6437865`](https://togithub.com/webdriverio-community/node-geckodriver/commit/6437865)) - chore(deps): bump vite from 5.4.5 to 5.4.6 ([#​546](https://togithub.com/webdriverio-community/node-geckodriver/issues/546)) ([`9ad9e72`](https://togithub.com/webdriverio-community/node-geckodriver/commit/9ad9e72)) - chore(deps-dev): bump husky from 9.1.5 to 9.1.6 ([#​540](https://togithub.com/webdriverio-community/node-geckodriver/issues/540)) ([`590a837`](https://togithub.com/webdriverio-community/node-geckodriver/commit/590a837)) - chore(deps-dev): bump [@​types/node](https://togithub.com/types/node) from 22.5.4 to 22.5.5 ([#​543](https://togithub.com/webdriverio-community/node-geckodriver/issues/543)) ([`e5f91da`](https://togithub.com/webdriverio-community/node-geckodriver/commit/e5f91da)) - chore(deps-dev): bump [@​vitest/coverage-v8](https://togithub.com/vitest/coverage-v8) from 2.0.5 to 2.1.1 ([#​544](https://togithub.com/webdriverio-community/node-geckodriver/issues/544)) ([`cc5c1aa`](https://togithub.com/webdriverio-community/node-geckodriver/commit/cc5c1aa)) - chore(deps-dev): bump npm-run-all2 from 6.2.2 to 6.2.3 ([#​538](https://togithub.com/webdriverio-community/node-geckodriver/issues/538)) ([`26d8383`](https://togithub.com/webdriverio-community/node-geckodriver/commit/26d8383)) - chore(deps-dev): bump typescript from 5.5.4 to 5.6.2 ([#​542](https://togithub.com/webdriverio-community/node-geckodriver/issues/542)) ([`9c97480`](https://togithub.com/webdriverio-community/node-geckodriver/commit/9c97480)) - chore(deps-dev): bump [@​typescript-eslint/parser](https://togithub.com/typescript-eslint/parser) from 8.4.0 to 8.5.0 ([#​541](https://togithub.com/webdriverio-community/node-geckodriver/issues/541)) ([`4bd169d`](https://togithub.com/webdriverio-community/node-geckodriver/commit/4bd169d)) - chore(deps-dev): bump tsx from 4.19.0 to 4.19.1 ([#​539](https://togithub.com/webdriverio-community/node-geckodriver/issues/539)) ([`2e366a9`](https://togithub.com/webdriverio-community/node-geckodriver/commit/2e366a9)) - chore(deps-dev): bump [@​types/node](https://togithub.com/types/node) from 22.5.2 to 22.5.4 ([#​537](https://togithub.com/webdriverio-community/node-geckodriver/issues/537)) ([`78502e3`](https://togithub.com/webdriverio-community/node-geckodriver/commit/78502e3)) - chore(deps-dev): bump [@​typescript-eslint/parser](https://togithub.com/typescript-eslint/parser) from 8.3.0 to 8.4.0 ([#​533](https://togithub.com/webdriverio-community/node-geckodriver/issues/533)) ([`9f71ec5`](https://togithub.com/webdriverio-community/node-geckodriver/commit/9f71ec5)) - chore(deps-dev): bump [@​typescript-eslint/eslint-plugin](https://togithub.com/typescript-eslint/eslint-plugin) ([#​531](https://togithub.com/webdriverio-community/node-geckodriver/issues/531)) ([`94aed15`](https://togithub.com/webdriverio-community/node-geckodriver/commit/94aed15)) - chore(deps-dev): bump webdriverio from 9.0.7 to 9.0.9 ([#​534](https://togithub.com/webdriverio-community/node-geckodriver/issues/534)) ([`fd6c4a6`](https://togithub.com/webdriverio-community/node-geckodriver/commit/fd6c4a6)) - chore(deps-dev): bump eslint-plugin-import from 2.29.1 to 2.30.0 ([#​532](https://togithub.com/webdriverio-community/node-geckodriver/issues/532)) ([`ae42ebd`](https://togithub.com/webdriverio-community/node-geckodriver/commit/ae42ebd))
--- 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://togithub.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> Co-authored-by: Jon [ML] Memory usage accessibility tests (#198306) Adds accessibility tests for the ML memory usage page. Update docker.elastic.co/wolfi/chainguard-base:latest Docker digest to 7082adc (main) (#198500) This PR contains the following updates: | Package | Update | Change | |---|---|---| | docker.elastic.co/wolfi/chainguard-base | digest | `8cff240` -> `7082adc` | --- 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> [ES|QL] Support ES|QL paramters in function names (#198486) Partially addresses https://github.com/elastic/kibana/issues/198251?reload=1?reload=1 - Improves for `param` node parsing inside `function` call nodes. - Adds the new `identifier` node type. - The `function` AST nodes now have `operator` property, which contains either a `param` or `identifier` node. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) [Logs Explorer] Fix privilege checks bug (#198368) This PR enhances the privilege checks for Logs Explorer side nav visibility. [ResponseOps]]MaintenaceWindow] Increase MW table limit to 1k (#198504) Here in this PR I am increasing the limit for MW to 1K. Even I've changed schema for query params(deleted maybe) I did not add additional tests, because we already have one integration test for the case, when we do not have `page` and `per_page` params. [Security Solution][Endpoint] Add FTR API tests that validates creation of DOT indices (#197899) - Adds new FTR API test suite for validating that DOT indices are created whenever a policy in fleet is created/updated - Renamed and moved `DEFAULT_DIAGNOSTIC_INDEX` `const` to security solution top-level `common` directory for better reuse - Moved utility function that builds an index name with the `namespace` included to top-level `common` directory for better reuse - Created some additional scripting methods in the Fleet services module for updating fleet policies [SecuritySolution][ProductFeatures] Add support for `security.authz.requiredPrivileges` for the API auth control (#198312) Adds support for the new API routes security authorization properties ([docs](https://docs.elastic.dev/kibana-dev-docs/key-concepts/security-api-authorization)) to the `ProductFeaturesService` API authorization control Closes: https://github.com/elastic/kibana/issues/194445 Related: https://github.com/elastic/kibana/issues/184674 --------- Co-authored-by: Elastic Machine [ML] Fix Trained model deletion with expanded row (#198530) Fixes #198408. Fixes trained model item deletion with expanded row. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios Authorized route migration for routes owned by @elastic/security-threat-hunting-explore (#198191) This PR migrates `access:` tags used in route definitions to new security configuration. Please refer to the documentation for more information: [Authorization API](https://docs.elastic.dev/kibana-dev-docs/key-concepts/security-api-authorization) Access control tags were defined in the `options` object of the route: ```ts router.get({ path: '/api/path', options: { tags: ['access:', 'access:'], }, ... }, handler); ``` Tags have been replaced with the more robust `security.authz.requiredPrivileges` field under `security`: ```ts router.get({ path: '/api/path', security: { authz: { requiredPrivileges: ['', ''], }, }, ... }, handler); ``` 1. Review the changes in this PR. 2. You might need to update your tests to reflect the new security configuration: - If you have tests that rely on checking `access` tags. - If you have snapshot tests that include the route definition. - If you have FTR tests that rely on checking unauthorized error message. The error message changed to also include missing privileges. If you have any questions or need help with API authorization, please reach out to the `@elastic/kibana-security` team. [Fleet] Use space prefixed default fleet server policy id (#197844) [EDR Workflows] Fix alert_test.cy.ts flakiness (#198516) [Security Solution] [Onboarding] design updates darkMode (#198124) Issue #196253 Update Onboarding footer icons and step card paddings for dark mode. Untitled (7) Untitled (6) Untitled (5) Delete any items that are not applicable to this PR. - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios [Response Ops][Alerting] Removing lifecycle executor from rule registry (#192576) All lifecycle rule types have been migrated to use the alerting framework alerts client so the lifecycle executor in the rule registry can be removed since it is no longer in use. Co-authored-by: Elastic Machine [Maps] Fix invalid index management link (#198499) This PR fixes invalid URL for `To modify the index, go to Index Management.` link. Closes: #125003 [Dashboard] fix Export CSV doesnt work (#198547) Closes https://github.com/elastic/kibana/issues/198517 https://github.com/elastic/kibana/pull/193644 refactored Dashboard services. Part of this refactor moved `fieldFormats` from `data.fieldFormats` to getting `fieldFormats` directly from the fieldFormats plugin. That is because `data.fieldFormats` is marked as deprecated. The problem is that the fieldFormats plugin was not defined under `requiredPlugins` and thus was undefined at runtime. 1) install web logs sample data 2) open web logs sample data dashboard 3) hover over "[Logs] Response Codes Over Time + Annotations" panel and select "three dots" icon. Then select "Download CSV". Verify there are no errors in web browser console and CSV is downloaded. Revert "[Synthetics] Revert 8.15 public API responses (#195295)" (#198511) Fixes https://github.com/elastic/kibana/issues/198518 This reverts commit d21495bbce07ed39fdcf077c9170d012adab74a4 and Create few HTTP, ICMP, TCP and Browser monitors via API in 8.15 and in this PR Compared JSOn diffs to make sure responses are same Update LaunchDarkly (main) (#198163) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [@launchdarkly/node-server-sdk](https://togithub.com/launchdarkly/js-core/tree/main/packages/sdk/server-node) ([source](https://togithub.com/launchdarkly/js-core)) | dependencies | patch | [`^9.6.1` -> `^9.7.0`](https://renovatebot.com/diffs/npm/@launchdarkly%2fnode-server-sdk/9.7.0/9.7.0) | | [launchdarkly-js-client-sdk](https://togithub.com/launchdarkly/js-client-sdk) | dependencies | minor | [`^3.4.0` -> `^3.5.0`](https://renovatebot.com/diffs/npm/launchdarkly-js-client-sdk/3.4.0/3.5.0) | ---
launchdarkly/js-client-sdk (launchdarkly-js-client-sdk) [`v3.5.0`](https://togithub.com/launchdarkly/js-client-sdk/blob/HEAD/CHANGELOG.md#350-2024-10-18) [Compare Source](https://togithub.com/launchdarkly/js-client-sdk/compare/3.4.0...3.5.0) - Add support for client-side prerequisite events. ([#​306](https://togithub.com/launchdarkly/js-client-sdk/issues/306)) ([fe51da0](https://togithub.com/launchdarkly/js-client-sdk/commit/fe51da0c2b974fb9b4d5fe99ad46cea35993a704))
--- 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://togithub.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). --------- Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> Co-authored-by: Alex Szabo Wait for backfill SOs to be deleted before running the invalidate API key task (#198422) Resolves https://github.com/elastic/kibana/issues/198168 Flaky test runners: - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7309 - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7314 Fix broken documentation links in the App Search plugin (#198572) [Docs] Update dashboard docs for interactive managed dashboard popover (#198226) Added a Duplicate dashboards page for the general duplicating process and then mentioned the new popover for duplicating managed dashboards. Linked to this page from other relevant mentions. [Obs AI Assistant] Fix error when opening an old conversation (#197745) Closes https://github.com/elastic/kibana/issues/176299 When a chat is started from contextual insights, `initialMessages` are being populated from the temp conversation created from the error. Because the `initialMessages` are present, when an old conversation is clicked, the conversation ID of that conversation and the `initalMessages` from the temp chat are passed to the conversation. This throws an error, as there is a condition which restricts both of these being passed to `useConversation` which is used by the `ChatBody`. - Only one of these should be passed (not both) With the current implementation, even though not passing `initialMessages` allows the user to open previous conversations successfully, it doesn't allow the user to start a new chat because as long as initial messages are set, they will be loaded when the New Chat button is clicked instead of showing a blank conversation. Clearing initial messages requires re-architecting how the Chat uses the conversation. Therefore, as the solution, when a chat is opened from contextual insights, the ConversationList will be hidden. The user can interact with the AI Assistant on the opened chat with initial messages from contextual insights. [Obs AI Assistant] Attempt to resolve flaky knowledge based user instructions test (#196026) Closes https://github.com/elastic/kibana/issues/192222 The "when creating private and public user instructions" test has been marked as flaky and has been skipped. Based on the error recorded in the ticket, 2 possible scenarios could be - **Race Conditions**: When multiple instructions are created asynchronously, the instructions might not be assigned to the right user or role. Data could be overwritten. - **Data Fetching Issues**: The API might return inconsistent data if the knowledge base is not properly cleared between tests, or if the instructions are not properly isolated per user. When running the test locally, the actual output and expected outcome are the same, therefore the test passes. The flaky test runner didn't output anything meaningful either. However, in order to resolve any missing entries, the before hook was updated to retry adding only the missing entries. Hopefully, this will help resolve the flakiness. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed Push the total request-body-bytes to usage-api (#194429) Resolves: https://github.com/elastic/response-ops-team/issues/209 This PR is a follow-on of https://github.com/elastic/kibana/pull/186804. Creates a new task that runs every 1 hour to push the total connector-request-body-bytes that have been saved in the event log to usage-api. [console] Restore font size flaky test (#197691) The test no longer appears flaky based on the flaky test runner. In addition to this PR there's also https://github.com/elastic/kibana/pull/197563 for 400+ passes. It should be noted that in one run 25 runs were skipped and one run failed due to an unrelated test. Closes https://github.com/elastic/kibana/issues/193868 [Canvas] Remove sample data (#197733) Removes the Canvas sample data from `main` (9.0). Some async feedback [here](https://github.com/elastic/kibana/pull/197733#issuecomment-2444234432) - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) [Security assistant] Fix `invoke_assistant_*` telemetry (#198594) basic enhancements for import logging (#196056) Hello, this is a follow up PR to #192234 . The previous PR added simplistic logging to the saved objects importer. The goal now is to enhance the logs with information on the saved objects being imported, how they are imported, and by displaying any errors. - Logs specific types being imported - Logs size limit and overwrite status - Logs Success/Fail messages - Passes the logger to `importSavedObjectsFromStream` - Removes "starting import" - Updates it for the new logger parameter - Uses the mock logger provided by core, instead of using a custom one - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) - [ ] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Elastic Machine Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Alejandro Fernández Haro skip failing test suite (#198632) [api-docs] 2024-11-01 Daily api_docs build (#198638) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/878 [ResponseOps][Cases] Make deprecated APIs internal in serverless (#198378) Fixes: https://github.com/elastic/kibana/issues/198407 Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) [Inference] create the `@kbn/inference-common` package (#193464) At the moment, all inference API related types and utilities (`chatComplete`, `output` and more) are living inside the `inference` plugin's common folder. This is somewhat problematic because it forces any consumers of those types to explicitly depends on the `inference` plugin (via plugin dep or ts ref), which could lead to any kind of cyclic dependency issues, in addition to being overall a bad design pattern. This also makes it more complicated that it should to try to split the inference logic / task framework / task implementation into distinct packages or plugins, due to some (concrete) utilities living in the inference plugin's code. It's also a bad experience for consumers, as it's quite difficult to easily resolve imports they need (we're mixing internal and public exports atm, plus not all types are exported from a single entry point, making it very tedious to find the right path for each individual import we need to consume the inference APIs) This PR addresses most of those points, by introducing a new `@kbn/inference-common` package and moving all the low level types and utilities to it, while exposing all of them from the package's entrypoint. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine [Cloud Security] Update Findings page runtime fields required for third party data compatibility (#198635) This PR enhances the solution proposed by [this PR](https://github.com/elastic/kibana/pull/195702), by picking only the fields that are currently not mapped by the current Third Party integrations, this fixes performance degradation identified during the QA cycle of 8.16.0. Fixes: - https://github.com/elastic/security-team/issues/11034 - **rule.benchmark.rule_number**: runtime mapping kept because this field is missing on `security_solution-aws.misconfiguration_latest-v1` causing filtering out data when sorting by **Rule Number** column on the Misconfigurations Data Table. - **rule.section**: runtime mapping kept because this field is missing on `security_solution-aws.misconfiguration_latest-v1` causing filtering out data when sorting by **Framework Section** column on the Misconfigurations Data Table. - **resource.sub_type**: runtime mapping kept because this field is missing on `security_solution-aws.misconfiguration_latest-v1` causing filtering out data when sorting by **Resource Type** column on the Misconfigurations Data Table. - **orchestrator.cluster.name**: runtime mapping kept because this field is missing on `security_solution-wiz.misconfiguration_latest-v1` causing filtering out data when grouping by **Kubernetes Cluster** column on the Misconfigurations page. - **cloud.account.name**: runtime mapping kept because this field is missing on `security_solution-aws.misconfiguration_latest-v1` causing filtering out data when grouping by **Kubernetes Cluster** column on the Misconfigurations page. - **observer.vendor**: runtime mapping added because this field is mapped as `text` on `security_solution-wiz.vulnerability_latest-v1` causing filtering out when sorting by the **Vendor** column on the Vulnerability Data Table - **cloud.provider**: runtime mapping added because this field is mapped as `text` on `security_solution-wiz.vulnerability_latest-v1` causing filtering out when grouping by **Cloud Account** on the Vulnerability page. (This field is needed in order to retrieve the Cloud Provider name and icon) https://github.com/user-attachments/assets/2cbdd8b7-131c-42e4-a881-632f8cd3854b https://github.com/user-attachments/assets/4372feb6-4c01-4047-a90a-d6728f9400fe https://github.com/user-attachments/assets/b9e32514-f2ee-4e4d-ba5f-ea3e20d4d0b2 [ES|QL] Fixes the error in the console (#198307) Closes https://github.com/elastic/kibana/issues/198258 - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Julia Rechkunova Authorized route migration for routes owned by kibana-security (#198380) This PR migrates `access:` tags used in route definitions to new security configuration. Please refer to the documentation for more information: [Authorization API](https://docs.elastic.dev/kibana-dev-docs/key-concepts/security-api-authorization) Access control tags were defined in the `options` object of the route: ```ts router.get({ path: '/api/path', options: { tags: ['access:', 'access:'], }, ... }, handler); ``` Tags have been replaced with the more robust `security.authz.requiredPrivileges` field under `security`: ```ts router.get({ path: '/api/path', security: { authz: { requiredPrivileges: ['', ''], }, }, ... }, handler); ``` 1. Review the changes in this PR. 2. You might need to update your tests to reflect the new security configuration: - If you have tests that rely on checking `access` tags. - If you have snapshot tests that include the route definition. - If you have FTR tests that rely on checking unauthorized error message. The error message changed to also include missing privileges. If you have any questions or need help with API authorization, please reach out to the `@elastic/kibana-security` team. --------- Co-authored-by: Elena Shostak [SecuritySolution] Fix dashboard page when the entity store state is stopped (#198645) Fix the dashboard page when the entity store state is stopped Previously, the EntityStoreDashboardPanels component didn't account for the installed but disabled state (stopped). I made the minimum changes necessary to fix the bug, but this component needs to be refactored, unit-tested, and written in a storybook with all possible states. Technical debt Issue: https://github.com/elastic/security-team/issues/11035 [Fleet] Remove deprecated APIs for agents endpoints (#198313) Remove stale tasks from task conflict count during task claiming (#198416) In this PR, I'm removing the count of stale tasks from the number of conflicts during the claiming cycle. I am also adding a new property to the task manager health report (`claim_stale_tasks`) so we can track those separately to ensure we have the proper page size. Apply the following diff, observe the new `claim_stale_tasks` in the TM health API and that conflicts are 0 ``` diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts index 4e74454e8c9..35d7fd872d8 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts @@ -145,6 +145,7 @@ async function claimAvailableTasks(opts: TaskClaimerOpts): Promise Redirect ECS k8s entities to dashboards Create entity_client functions Fix entityLatest flatten object Fix redirection to service overview Add tests --- .buildkite/ftr_oblt_stateful_configs.yml | 1 - .../ftr_security_serverless_configs.yml | 15 +- .buildkite/ftr_security_stateful_configs.yml | 15 +- .../kibana-deploy-project.yml | 2 + .../kibana-es-snapshots.yml | 2 +- .buildkite/pipeline-utils/github/github.ts | 20 + .buildkite/pipelines/on_merge.yml | 154 +- .../pipelines/pull_request/apm_cypress.yml | 3 + .buildkite/pipelines/pull_request/base.yml | 76 +- .../pipelines/pull_request/deploy_cloud.yml | 3 + .../pull_request/exploratory_view_plugin.yml | 3 + .buildkite/pipelines/pull_request/fips.yml | 3 + .../pipelines/pull_request/fleet_cypress.yml | 3 + .../pull_request/inventory_cypress.yml | 3 + .../pipelines/pull_request/kbn_handlebars.yml | 3 + .../observability_onboarding_cypress.yml | 3 + .../pull_request/profiling_cypress.yml | 3 + .../pipelines/pull_request/response_ops.yml | 3 + .../pull_request/response_ops_cases.yml | 3 + .../security_solution/ai_assistant.yml | 6 + .../cloud_security_posture.yml | 6 + .../security_solution/cypress_burn.yml | 12 + .../security_solution/defend_workflows.yml | 6 + .../security_solution/detection_engine.yml | 12 + .../security_solution/entity_analytics.yml | 6 + .../security_solution/explore.yml | 6 + .../security_solution/investigations.yml | 6 + .../security_solution/osquery_cypress.yml | 6 + .../security_solution/playwright.yml | 6 + .../security_solution/rule_management.yml | 12 + .../pipelines/pull_request/slo_plugin_e2e.yml | 3 + .../pull_request/synthetics_plugin.yml | 3 + .../pipelines/pull_request/uptime_plugin.yml | 3 + .../pipelines/pull_request/ux_plugin_e2e.yml | 3 + .../mki_periodic_detection_engine.yml | 202 +- .../mki_quality_gate_detection_engine.yml | 152 +- .../project-build-and-deploy-pr.yml | 121 +- .buildkite/pull_requests.json | 7 +- .buildkite/scripts/lifecycle/comment_on_pr.ts | 64 + .buildkite/scripts/steps/checks.sh | 1 + .../steps/checks/capture_oas_snapshot.sh | 5 +- .buildkite/scripts/steps/checks/i18n.sh | 2 +- .../scripts/steps/checks/quick_checks.txt | 1 - .../scripts/steps/cloud/build_and_deploy.sh | 2 +- .../scripts/steps/es_snapshots/build.sh | 8 +- .../scripts/steps/functional/apm_cypress.sh | 1 + .../steps/functional/defend_workflows_burn.sh | 1 + .../defend_workflows_serverless_burn.sh | 1 + .../functional/exploratory_view_plugin.sh | 1 + .../steps/functional/inventory_cypress.sh | 1 + .../observability_onboarding_cypress.sh | 1 + .../steps/functional/profiling_cypress.sh | 1 + .../steps/functional/slo_plugin_e2e.sh | 1 + .../scripts/steps/functional/synthetics.sh | 1 + .../steps/functional/synthetics_plugin.sh | 1 + .../scripts/steps/functional/uptime_plugin.sh | 1 + .../steps/functional/ux_synthetics_e2e.sh | 1 + .buildkite/scripts/steps/lint.sh | 4 +- .devcontainer/Dockerfile | 6 +- .devcontainer/devcontainer.json | 5 +- .github/CODEOWNERS | 45 +- .github/workflows/updatecli-compose.yml | 1 + .gitignore | 3 +- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 4 +- .../ai_assistant_management_selection.mdx | 2 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.devdocs.json | 10 +- api_docs/alerting.mdx | 2 +- api_docs/apm.mdx | 2 +- api_docs/apm_data_access.mdx | 2 +- api_docs/banners.mdx | 2 +- api_docs/bfetch.mdx | 2 +- api_docs/canvas.mdx | 2 +- api_docs/cases.devdocs.json | 40 +- api_docs/cases.mdx | 2 +- api_docs/charts.mdx | 2 +- api_docs/cloud.devdocs.json | 38 +- api_docs/cloud.mdx | 9 +- api_docs/cloud_data_migration.mdx | 2 +- api_docs/cloud_defend.mdx | 2 +- api_docs/cloud_security_posture.mdx | 2 +- api_docs/console.mdx | 2 +- api_docs/content_management.mdx | 2 +- api_docs/controls.mdx | 2 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.mdx | 2 +- api_docs/data_quality.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.mdx | 2 +- api_docs/data_usage.mdx | 2 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/dataset_quality.devdocs.json | 88 +- api_docs/dataset_quality.mdx | 2 +- api_docs/deprecations_by_api.mdx | 4 +- api_docs/deprecations_by_plugin.mdx | 11 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.devdocs.json | 36 - api_docs/discover.mdx | 4 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/discover_shared.mdx | 2 +- api_docs/ecs_data_quality_dashboard.mdx | 2 +- api_docs/elastic_assistant.mdx | 2 +- api_docs/embeddable.devdocs.json | 192 + api_docs/embeddable.mdx | 4 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.mdx | 2 +- api_docs/entities_data_access.mdx | 2 +- api_docs/entity_manager.mdx | 2 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/esql.mdx | 2 +- api_docs/esql_data_grid.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_annotation_listing.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/exploratory_view.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/fields_metadata.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/files.mdx | 2 +- api_docs/files_management.mdx | 2 +- api_docs/fleet.devdocs.json | 108 +- api_docs/fleet.mdx | 4 +- api_docs/global_search.mdx | 2 +- api_docs/guided_onboarding.mdx | 2 +- api_docs/home.mdx | 2 +- api_docs/image_embeddable.mdx | 2 +- api_docs/index_lifecycle_management.mdx | 2 +- api_docs/index_management.devdocs.json | 259 +- api_docs/index_management.mdx | 4 +- api_docs/inference.mdx | 2 +- api_docs/infra.mdx | 2 +- api_docs/ingest_pipelines.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/integration_assistant.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/inventory.devdocs.json | 30 + api_docs/inventory.mdx | 4 +- api_docs/investigate.mdx | 2 +- api_docs/investigate_app.mdx | 2 +- api_docs/kbn_actions_types.mdx | 2 +- api_docs/kbn_ai_assistant.devdocs.json | 28 +- api_docs/kbn_ai_assistant.mdx | 4 +- api_docs/kbn_ai_assistant_common.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_log_pattern_analysis.mdx | 2 +- api_docs/kbn_aiops_log_rate_analysis.mdx | 2 +- .../kbn_alerting_api_integration_helpers.mdx | 2 +- api_docs/kbn_alerting_comparators.mdx | 2 +- api_docs/kbn_alerting_state_types.mdx | 2 +- api_docs/kbn_alerting_types.devdocs.json | 2 +- api_docs/kbn_alerting_types.mdx | 2 +- api_docs/kbn_alerts_as_data_utils.mdx | 2 +- api_docs/kbn_alerts_grouping.mdx | 2 +- api_docs/kbn_alerts_ui_shared.mdx | 2 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_collection_utils.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_data_view.mdx | 2 +- api_docs/kbn_apm_synthtrace.mdx | 2 +- api_docs/kbn_apm_synthtrace_client.mdx | 2 +- api_docs/kbn_apm_types.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_avc_banner.mdx | 2 +- api_docs/kbn_axe_config.mdx | 2 +- api_docs/kbn_bfetch_error.mdx | 2 +- api_docs/kbn_calculate_auto.mdx | 2 +- .../kbn_calculate_width_from_char_count.mdx | 2 +- api_docs/kbn_cases_components.mdx | 2 +- api_docs/kbn_cbor.mdx | 2 +- api_docs/kbn_cell_actions.mdx | 2 +- api_docs/kbn_chart_expressions_common.mdx | 2 +- api_docs/kbn_chart_icons.mdx | 2 +- api_docs/kbn_ci_stats_core.mdx | 2 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 2 +- api_docs/kbn_ci_stats_reporter.mdx | 2 +- api_docs/kbn_cli_dev_mode.mdx | 2 +- .../kbn_cloud_security_posture.devdocs.json | 13 +- api_docs/kbn_cloud_security_posture.mdx | 4 +- .../kbn_cloud_security_posture_common.mdx | 2 +- ..._cloud_security_posture_graph.devdocs.json | 449 +++ api_docs/kbn_cloud_security_posture_graph.mdx | 36 + api_docs/kbn_code_editor.mdx | 2 +- api_docs/kbn_code_editor_mock.mdx | 2 +- api_docs/kbn_code_owners.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.mdx | 2 +- .../kbn_content_management_content_editor.mdx | 2 +- ...ent_management_content_insights_public.mdx | 2 +- ...ent_management_content_insights_server.mdx | 2 +- ...bn_content_management_favorites_public.mdx | 2 +- ...bn_content_management_favorites_server.mdx | 2 +- ...tent_management_tabbed_table_list_view.mdx | 2 +- ...kbn_content_management_table_list_view.mdx | 2 +- ...tent_management_table_list_view_common.mdx | 2 +- ...ntent_management_table_list_view_table.mdx | 2 +- .../kbn_content_management_user_profiles.mdx | 2 +- api_docs/kbn_content_management_utils.mdx | 2 +- .../kbn_core_analytics_browser.devdocs.json | 124 +- api_docs/kbn_core_analytics_browser.mdx | 2 +- .../kbn_core_analytics_browser_internal.mdx | 2 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 2 +- .../kbn_core_analytics_server.devdocs.json | 124 +- api_docs/kbn_core_analytics_server.mdx | 2 +- .../kbn_core_analytics_server_internal.mdx | 2 +- api_docs/kbn_core_analytics_server_mocks.mdx | 2 +- api_docs/kbn_core_application_browser.mdx | 2 +- .../kbn_core_application_browser_internal.mdx | 2 +- .../kbn_core_application_browser_mocks.mdx | 2 +- api_docs/kbn_core_application_common.mdx | 2 +- api_docs/kbn_core_apps_browser_internal.mdx | 2 +- api_docs/kbn_core_apps_browser_mocks.mdx | 2 +- api_docs/kbn_core_apps_server_internal.mdx | 2 +- api_docs/kbn_core_base_browser_mocks.mdx | 2 +- api_docs/kbn_core_base_common.mdx | 2 +- api_docs/kbn_core_base_server_internal.mdx | 2 +- api_docs/kbn_core_base_server_mocks.mdx | 2 +- .../kbn_core_capabilities_browser_mocks.mdx | 2 +- api_docs/kbn_core_capabilities_common.mdx | 2 +- api_docs/kbn_core_capabilities_server.mdx | 2 +- .../kbn_core_capabilities_server_mocks.mdx | 2 +- api_docs/kbn_core_chrome_browser.devdocs.json | 143 +- api_docs/kbn_core_chrome_browser.mdx | 4 +- api_docs/kbn_core_chrome_browser_mocks.mdx | 2 +- api_docs/kbn_core_config_server_internal.mdx | 2 +- api_docs/kbn_core_custom_branding_browser.mdx | 2 +- ..._core_custom_branding_browser_internal.mdx | 2 +- ...kbn_core_custom_branding_browser_mocks.mdx | 2 +- api_docs/kbn_core_custom_branding_common.mdx | 2 +- api_docs/kbn_core_custom_branding_server.mdx | 2 +- ...n_core_custom_branding_server_internal.mdx | 2 +- .../kbn_core_custom_branding_server_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_browser.mdx | 2 +- ...kbn_core_deprecations_browser_internal.mdx | 2 +- .../kbn_core_deprecations_browser_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_common.mdx | 2 +- api_docs/kbn_core_deprecations_server.mdx | 2 +- .../kbn_core_deprecations_server_internal.mdx | 2 +- .../kbn_core_deprecations_server_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_browser.mdx | 2 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_server.mdx | 2 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 2 +- ...e_elasticsearch_client_server_internal.mdx | 2 +- ...core_elasticsearch_client_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_server.mdx | 2 +- ...kbn_core_elasticsearch_server_internal.mdx | 2 +- .../kbn_core_elasticsearch_server_mocks.mdx | 2 +- .../kbn_core_environment_server_internal.mdx | 2 +- .../kbn_core_environment_server_mocks.mdx | 2 +- .../kbn_core_execution_context_browser.mdx | 2 +- ...ore_execution_context_browser_internal.mdx | 2 +- ...n_core_execution_context_browser_mocks.mdx | 2 +- .../kbn_core_execution_context_common.mdx | 2 +- .../kbn_core_execution_context_server.mdx | 2 +- ...core_execution_context_server_internal.mdx | 2 +- ...bn_core_execution_context_server_mocks.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser.mdx | 2 +- .../kbn_core_fatal_errors_browser_mocks.mdx | 2 +- api_docs/kbn_core_feature_flags_browser.mdx | 2 +- ...bn_core_feature_flags_browser_internal.mdx | 2 +- .../kbn_core_feature_flags_browser_mocks.mdx | 2 +- api_docs/kbn_core_feature_flags_server.mdx | 2 +- ...kbn_core_feature_flags_server_internal.mdx | 2 +- .../kbn_core_feature_flags_server_mocks.mdx | 2 +- api_docs/kbn_core_http_browser.mdx | 2 +- api_docs/kbn_core_http_browser_internal.mdx | 2 +- api_docs/kbn_core_http_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_common.mdx | 2 +- .../kbn_core_http_context_server_mocks.mdx | 2 +- ...re_http_request_handler_context_server.mdx | 2 +- api_docs/kbn_core_http_resources_server.mdx | 2 +- ...bn_core_http_resources_server_internal.mdx | 2 +- .../kbn_core_http_resources_server_mocks.mdx | 2 +- .../kbn_core_http_router_server_internal.mdx | 2 +- .../kbn_core_http_router_server_mocks.mdx | 2 +- api_docs/kbn_core_http_server.devdocs.json | 156 +- api_docs/kbn_core_http_server.mdx | 2 +- api_docs/kbn_core_http_server_internal.mdx | 2 +- api_docs/kbn_core_http_server_mocks.mdx | 2 +- api_docs/kbn_core_i18n_browser.mdx | 2 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 2 +- api_docs/kbn_core_i18n_server.mdx | 2 +- api_docs/kbn_core_i18n_server_internal.mdx | 2 +- api_docs/kbn_core_i18n_server_mocks.mdx | 2 +- ...n_core_injected_metadata_browser_mocks.mdx | 2 +- ...kbn_core_integrations_browser_internal.mdx | 2 +- .../kbn_core_integrations_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_browser.mdx | 2 +- api_docs/kbn_core_lifecycle_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_server.mdx | 2 +- api_docs/kbn_core_lifecycle_server_mocks.mdx | 2 +- api_docs/kbn_core_logging_browser_mocks.mdx | 2 +- api_docs/kbn_core_logging_common_internal.mdx | 2 +- api_docs/kbn_core_logging_server.mdx | 2 +- api_docs/kbn_core_logging_server_internal.mdx | 2 +- api_docs/kbn_core_logging_server_mocks.mdx | 2 +- ...ore_metrics_collectors_server_internal.mdx | 2 +- ...n_core_metrics_collectors_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_server.mdx | 2 +- api_docs/kbn_core_metrics_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_server_mocks.mdx | 2 +- api_docs/kbn_core_mount_utils_browser.mdx | 2 +- api_docs/kbn_core_node_server.mdx | 2 +- api_docs/kbn_core_node_server_internal.mdx | 2 +- api_docs/kbn_core_node_server_mocks.mdx | 2 +- api_docs/kbn_core_notifications_browser.mdx | 2 +- ...bn_core_notifications_browser_internal.mdx | 2 +- .../kbn_core_notifications_browser_mocks.mdx | 2 +- api_docs/kbn_core_overlays_browser.mdx | 2 +- .../kbn_core_overlays_browser_internal.mdx | 2 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 2 +- api_docs/kbn_core_plugins_browser.mdx | 2 +- api_docs/kbn_core_plugins_browser_mocks.mdx | 2 +- .../kbn_core_plugins_contracts_browser.mdx | 2 +- .../kbn_core_plugins_contracts_server.mdx | 2 +- api_docs/kbn_core_plugins_server.mdx | 2 +- api_docs/kbn_core_plugins_server_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- api_docs/kbn_core_rendering_browser_mocks.mdx | 2 +- .../kbn_core_rendering_server_internal.mdx | 2 +- api_docs/kbn_core_rendering_server_mocks.mdx | 2 +- api_docs/kbn_core_root_server_internal.mdx | 2 +- .../kbn_core_saved_objects_api_browser.mdx | 2 +- ...core_saved_objects_api_server.devdocs.json | 44 - .../kbn_core_saved_objects_api_server.mdx | 2 +- ...bn_core_saved_objects_api_server_mocks.mdx | 2 +- ...ore_saved_objects_base_server_internal.mdx | 2 +- ...n_core_saved_objects_base_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_browser.mdx | 2 +- ...bn_core_saved_objects_browser_internal.mdx | 2 +- .../kbn_core_saved_objects_browser_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_common.mdx | 2 +- ..._objects_import_export_server_internal.mdx | 2 +- ...ved_objects_import_export_server_mocks.mdx | 2 +- ...aved_objects_migration_server_internal.mdx | 2 +- ...e_saved_objects_migration_server_mocks.mdx | 2 +- ...kbn_core_saved_objects_server.devdocs.json | 44 - api_docs/kbn_core_saved_objects_server.mdx | 2 +- ...kbn_core_saved_objects_server_internal.mdx | 2 +- .../kbn_core_saved_objects_server_mocks.mdx | 2 +- .../kbn_core_saved_objects_utils_server.mdx | 2 +- api_docs/kbn_core_security_browser.mdx | 2 +- .../kbn_core_security_browser_internal.mdx | 2 +- api_docs/kbn_core_security_browser_mocks.mdx | 2 +- api_docs/kbn_core_security_common.mdx | 2 +- api_docs/kbn_core_security_server.mdx | 2 +- .../kbn_core_security_server_internal.mdx | 2 +- api_docs/kbn_core_security_server_mocks.mdx | 2 +- api_docs/kbn_core_status_common.mdx | 2 +- api_docs/kbn_core_status_common_internal.mdx | 2 +- api_docs/kbn_core_status_server.mdx | 2 +- api_docs/kbn_core_status_server_internal.mdx | 2 +- api_docs/kbn_core_status_server_mocks.mdx | 2 +- ...core_test_helpers_deprecations_getters.mdx | 2 +- ...n_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_test_helpers_kbn_server.mdx | 2 +- .../kbn_core_test_helpers_model_versions.mdx | 2 +- ...n_core_test_helpers_so_type_serializer.mdx | 2 +- api_docs/kbn_core_test_helpers_test_utils.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- .../kbn_core_ui_settings_browser_internal.mdx | 2 +- .../kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_core_ui_settings_server.mdx | 2 +- .../kbn_core_ui_settings_server_internal.mdx | 2 +- .../kbn_core_ui_settings_server_mocks.mdx | 2 +- api_docs/kbn_core_usage_data_server.mdx | 2 +- .../kbn_core_usage_data_server_internal.mdx | 2 +- api_docs/kbn_core_usage_data_server_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_browser.mdx | 2 +- ...kbn_core_user_profile_browser_internal.mdx | 2 +- .../kbn_core_user_profile_browser_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_common.mdx | 2 +- api_docs/kbn_core_user_profile_server.mdx | 2 +- .../kbn_core_user_profile_server_internal.mdx | 2 +- .../kbn_core_user_profile_server_mocks.mdx | 2 +- api_docs/kbn_core_user_settings_server.mdx | 2 +- .../kbn_core_user_settings_server_mocks.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_custom_icons.mdx | 2 +- api_docs/kbn_custom_integrations.mdx | 2 +- api_docs/kbn_cypress_config.mdx | 2 +- api_docs/kbn_data_forge.mdx | 2 +- api_docs/kbn_data_service.mdx | 2 +- api_docs/kbn_data_stream_adapter.devdocs.json | 8 +- api_docs/kbn_data_stream_adapter.mdx | 2 +- api_docs/kbn_data_view_utils.mdx | 2 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_deeplinks_analytics.mdx | 2 +- api_docs/kbn_deeplinks_devtools.mdx | 2 +- api_docs/kbn_deeplinks_fleet.mdx | 2 +- api_docs/kbn_deeplinks_management.mdx | 2 +- api_docs/kbn_deeplinks_ml.mdx | 2 +- api_docs/kbn_deeplinks_observability.mdx | 2 +- api_docs/kbn_deeplinks_search.devdocs.json | 62 +- api_docs/kbn_deeplinks_search.mdx | 4 +- api_docs/kbn_deeplinks_security.mdx | 2 +- api_docs/kbn_deeplinks_shared.mdx | 2 +- api_docs/kbn_default_nav_analytics.mdx | 2 +- api_docs/kbn_default_nav_devtools.mdx | 2 +- api_docs/kbn_default_nav_management.mdx | 2 +- api_docs/kbn_default_nav_ml.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- .../kbn_discover_contextual_components.mdx | 2 +- api_docs/kbn_discover_utils.devdocs.json | 1420 +++++++- api_docs/kbn_discover_utils.mdx | 7 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_dom_drag_drop.mdx | 2 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_ecs_data_quality_dashboard.mdx | 2 +- api_docs/kbn_elastic_agent_utils.mdx | 2 +- api_docs/kbn_elastic_assistant.mdx | 2 +- .../kbn_elastic_assistant_common.devdocs.json | 6 +- api_docs/kbn_elastic_assistant_common.mdx | 2 +- api_docs/kbn_entities_schema.mdx | 2 +- api_docs/kbn_es.mdx | 2 +- api_docs/kbn_es_archiver.mdx | 2 +- api_docs/kbn_es_errors.mdx | 2 +- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_es_types.mdx | 2 +- api_docs/kbn_eslint_plugin_imports.mdx | 2 +- api_docs/kbn_esql_ast.devdocs.json | 29 + api_docs/kbn_esql_ast.mdx | 4 +- api_docs/kbn_esql_editor.mdx | 2 +- api_docs/kbn_esql_utils.mdx | 2 +- ..._esql_validation_autocomplete.devdocs.json | 102 +- api_docs/kbn_esql_validation_autocomplete.mdx | 2 +- api_docs/kbn_event_annotation_common.mdx | 2 +- api_docs/kbn_event_annotation_components.mdx | 2 +- api_docs/kbn_expandable_flyout.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_field_utils.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- api_docs/kbn_formatters.mdx | 2 +- ...tr_common_functional_services.devdocs.json | 2 +- .../kbn_ftr_common_functional_services.mdx | 2 +- ...common_functional_ui_services.devdocs.json | 6 +- .../kbn_ftr_common_functional_ui_services.mdx | 2 +- api_docs/kbn_generate.mdx | 2 +- api_docs/kbn_generate_console_definitions.mdx | 2 +- api_docs/kbn_generate_csv.mdx | 2 +- api_docs/kbn_grid_layout.mdx | 2 +- api_docs/kbn_grouping.mdx | 2 +- api_docs/kbn_guided_onboarding.mdx | 2 +- api_docs/kbn_handlebars.mdx | 2 +- api_docs/kbn_hapi_mocks.mdx | 2 +- api_docs/kbn_health_gateway_server.mdx | 2 +- api_docs/kbn_home_sample_data_card.mdx | 2 +- api_docs/kbn_home_sample_data_tab.mdx | 2 +- api_docs/kbn_i18n.mdx | 2 +- api_docs/kbn_i18n_react.mdx | 2 +- api_docs/kbn_import_resolver.mdx | 2 +- ...index_management_shared_types.devdocs.json | 81 +- .../kbn_index_management_shared_types.mdx | 4 +- api_docs/kbn_inference_integration_flyout.mdx | 2 +- api_docs/kbn_infra_forge.mdx | 2 +- api_docs/kbn_interpreter.mdx | 2 +- api_docs/kbn_investigation_shared.mdx | 2 +- api_docs/kbn_io_ts_utils.mdx | 2 +- api_docs/kbn_ipynb.mdx | 2 +- api_docs/kbn_item_buffer.mdx | 2 +- api_docs/kbn_jest_serializers.mdx | 2 +- api_docs/kbn_journeys.mdx | 2 +- api_docs/kbn_json_ast.mdx | 2 +- api_docs/kbn_json_schemas.mdx | 2 +- api_docs/kbn_kibana_manifest_schema.mdx | 2 +- api_docs/kbn_language_documentation.mdx | 2 +- api_docs/kbn_lens_embeddable_utils.mdx | 2 +- api_docs/kbn_lens_formula_docs.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_content_badge.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_management_cards_navigation.mdx | 2 +- .../kbn_management_settings_application.mdx | 2 +- ...ent_settings_components_field_category.mdx | 2 +- ...gement_settings_components_field_input.mdx | 2 +- ...nagement_settings_components_field_row.mdx | 2 +- ...bn_management_settings_components_form.mdx | 2 +- ...n_management_settings_field_definition.mdx | 2 +- .../kbn_management_settings_ids.devdocs.json | 45 - api_docs/kbn_management_settings_ids.mdx | 4 +- ...n_management_settings_section_registry.mdx | 2 +- api_docs/kbn_management_settings_types.mdx | 2 +- .../kbn_management_settings_utilities.mdx | 2 +- api_docs/kbn_management_storybook_config.mdx | 2 +- api_docs/kbn_manifest.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_maps_vector_tile_utils.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_anomaly_utils.mdx | 2 +- api_docs/kbn_ml_cancellable_search.mdx | 2 +- api_docs/kbn_ml_category_validator.mdx | 2 +- api_docs/kbn_ml_chi2test.mdx | 2 +- .../kbn_ml_data_frame_analytics_utils.mdx | 2 +- api_docs/kbn_ml_data_grid.mdx | 2 +- api_docs/kbn_ml_date_picker.mdx | 2 +- api_docs/kbn_ml_date_utils.mdx | 2 +- api_docs/kbn_ml_error_utils.mdx | 2 +- api_docs/kbn_ml_field_stats_flyout.mdx | 2 +- api_docs/kbn_ml_in_memory_table.mdx | 2 +- api_docs/kbn_ml_is_defined.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_kibana_theme.mdx | 2 +- api_docs/kbn_ml_local_storage.mdx | 2 +- api_docs/kbn_ml_nested_property.mdx | 2 +- api_docs/kbn_ml_number_utils.mdx | 2 +- api_docs/kbn_ml_parse_interval.mdx | 2 +- api_docs/kbn_ml_query_utils.mdx | 2 +- api_docs/kbn_ml_random_sampler_utils.mdx | 2 +- api_docs/kbn_ml_route_utils.mdx | 2 +- api_docs/kbn_ml_runtime_field_utils.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_ml_time_buckets.mdx | 2 +- api_docs/kbn_ml_trained_models_utils.mdx | 2 +- api_docs/kbn_ml_ui_actions.mdx | 2 +- api_docs/kbn_ml_url_state.mdx | 2 +- api_docs/kbn_ml_validators.mdx | 2 +- api_docs/kbn_mock_idp_utils.mdx | 2 +- api_docs/kbn_monaco.devdocs.json | 4 +- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_object_versioning.mdx | 2 +- api_docs/kbn_object_versioning_utils.mdx | 2 +- api_docs/kbn_observability_alert_details.mdx | 2 +- .../kbn_observability_alerting_rule_utils.mdx | 2 +- .../kbn_observability_alerting_test_data.mdx | 2 +- ...ility_get_padded_alert_time_range_util.mdx | 2 +- api_docs/kbn_observability_logs_overview.mdx | 2 +- ...kbn_observability_synthetics_test_data.mdx | 2 +- api_docs/kbn_openapi_bundler.mdx | 2 +- api_docs/kbn_openapi_generator.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- api_docs/kbn_osquery_io_ts_types.mdx | 2 +- api_docs/kbn_panel_loader.mdx | 2 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_check.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_presentation_containers.mdx | 2 +- .../kbn_presentation_publishing.devdocs.json | 252 ++ api_docs/kbn_presentation_publishing.mdx | 4 +- api_docs/kbn_product_doc_artifact_builder.mdx | 2 +- api_docs/kbn_profiling_utils.mdx | 2 +- api_docs/kbn_random_sampling.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_react_hooks.mdx | 2 +- api_docs/kbn_react_kibana_context_common.mdx | 2 +- api_docs/kbn_react_kibana_context_render.mdx | 2 +- api_docs/kbn_react_kibana_context_root.mdx | 2 +- api_docs/kbn_react_kibana_context_styled.mdx | 2 +- api_docs/kbn_react_kibana_context_theme.mdx | 2 +- api_docs/kbn_react_kibana_mount.mdx | 2 +- api_docs/kbn_recently_accessed.mdx | 2 +- api_docs/kbn_repo_file_maps.mdx | 2 +- api_docs/kbn_repo_linter.mdx | 2 +- api_docs/kbn_repo_path.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_reporting_common.mdx | 2 +- api_docs/kbn_reporting_csv_share_panel.mdx | 2 +- api_docs/kbn_reporting_export_types_csv.mdx | 2 +- .../kbn_reporting_export_types_csv_common.mdx | 2 +- api_docs/kbn_reporting_export_types_pdf.mdx | 2 +- .../kbn_reporting_export_types_pdf_common.mdx | 2 +- api_docs/kbn_reporting_export_types_png.mdx | 2 +- .../kbn_reporting_export_types_png_common.mdx | 2 +- api_docs/kbn_reporting_mocks_server.mdx | 2 +- api_docs/kbn_reporting_public.mdx | 2 +- api_docs/kbn_reporting_server.mdx | 2 +- api_docs/kbn_resizable_layout.mdx | 2 +- .../kbn_response_ops_feature_flag_service.mdx | 2 +- api_docs/kbn_response_ops_rule_params.mdx | 2 +- api_docs/kbn_rison.mdx | 2 +- api_docs/kbn_rollup.mdx | 2 +- api_docs/kbn_router_to_openapispec.mdx | 2 +- api_docs/kbn_router_utils.mdx | 2 +- api_docs/kbn_rrule.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- api_docs/kbn_saved_objects_settings.mdx | 2 +- api_docs/kbn_screenshotting_server.mdx | 2 +- api_docs/kbn_search_api_keys_components.mdx | 2 +- api_docs/kbn_search_api_keys_server.mdx | 2 +- api_docs/kbn_search_api_panels.mdx | 2 +- api_docs/kbn_search_connectors.mdx | 2 +- api_docs/kbn_search_errors.mdx | 2 +- api_docs/kbn_search_index_documents.mdx | 2 +- api_docs/kbn_search_response_warnings.mdx | 2 +- api_docs/kbn_search_shared_ui.mdx | 2 +- api_docs/kbn_search_types.mdx | 2 +- api_docs/kbn_security_api_key_management.mdx | 2 +- api_docs/kbn_security_authorization_core.mdx | 2 +- ...kbn_security_authorization_core_common.mdx | 2 +- api_docs/kbn_security_form_components.mdx | 2 +- api_docs/kbn_security_hardening.mdx | 2 +- api_docs/kbn_security_plugin_types_common.mdx | 2 +- api_docs/kbn_security_plugin_types_public.mdx | 2 +- ..._security_plugin_types_server.devdocs.json | 4 + api_docs/kbn_security_plugin_types_server.mdx | 2 +- .../kbn_security_role_management_model.mdx | 2 +- .../kbn_security_solution_common.devdocs.json | 4 +- api_docs/kbn_security_solution_common.mdx | 2 +- ...kbn_security_solution_distribution_bar.mdx | 2 +- api_docs/kbn_security_solution_features.mdx | 2 +- api_docs/kbn_security_solution_navigation.mdx | 2 +- api_docs/kbn_security_solution_side_nav.mdx | 2 +- ...kbn_security_solution_storybook_config.mdx | 2 +- api_docs/kbn_security_ui_components.mdx | 2 +- .../kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_data_table.mdx | 2 +- api_docs/kbn_securitysolution_ecs.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- ...ritysolution_exception_list_components.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ..._securitysolution_io_ts_alerting_types.mdx | 2 +- .../kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- .../kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- .../kbn_server_route_repository_client.mdx | 2 +- .../kbn_server_route_repository_utils.mdx | 2 +- api_docs/kbn_serverless_common_settings.mdx | 2 +- .../kbn_serverless_observability_settings.mdx | 2 +- api_docs/kbn_serverless_project_switcher.mdx | 2 +- api_docs/kbn_serverless_search_settings.mdx | 2 +- api_docs/kbn_serverless_security_settings.mdx | 2 +- api_docs/kbn_serverless_storybook_config.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- api_docs/kbn_shared_ux_avatar_solution.mdx | 2 +- .../kbn_shared_ux_button_exit_full_screen.mdx | 2 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_chrome_navigation.mdx | 2 +- api_docs/kbn_shared_ux_error_boundary.mdx | 2 +- api_docs/kbn_shared_ux_file_context.mdx | 2 +- api_docs/kbn_shared_ux_file_image.mdx | 2 +- api_docs/kbn_shared_ux_file_image_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_picker.mdx | 2 +- api_docs/kbn_shared_ux_file_types.mdx | 2 +- api_docs/kbn_shared_ux_file_upload.mdx | 2 +- api_docs/kbn_shared_ux_file_util.mdx | 2 +- api_docs/kbn_shared_ux_link_redirect_app.mdx | 2 +- .../kbn_shared_ux_link_redirect_app_mocks.mdx | 2 +- api_docs/kbn_shared_ux_markdown.mdx | 2 +- api_docs/kbn_shared_ux_markdown_mocks.mdx | 2 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 2 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 2 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_template.mdx | 2 +- ...n_shared_ux_page_kibana_template_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data.mdx | 2 +- .../kbn_shared_ux_page_no_data_config.mdx | 2 +- ...bn_shared_ux_page_no_data_config_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_prompt_not_found.mdx | 2 +- api_docs/kbn_shared_ux_router.mdx | 2 +- api_docs/kbn_shared_ux_router_mocks.mdx | 2 +- api_docs/kbn_shared_ux_storybook_config.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_tabbed_modal.mdx | 2 +- api_docs/kbn_shared_ux_table_persist.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_slo_schema.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_sort_predicates.mdx | 2 +- api_docs/kbn_sse_utils.mdx | 2 +- api_docs/kbn_sse_utils_client.mdx | 2 +- api_docs/kbn_sse_utils_server.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_synthetics_e2e.mdx | 2 +- api_docs/kbn_synthetics_private_location.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.mdx | 2 +- api_docs/kbn_test_eui_helpers.mdx | 2 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_test_subj_selector.mdx | 2 +- api_docs/kbn_timerange.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_transpose_utils.mdx | 2 +- api_docs/kbn_triggers_actions_ui_types.mdx | 2 +- api_docs/kbn_try_in_console.mdx | 2 +- api_docs/kbn_ts_projects.mdx | 2 +- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kbn_ui_actions_browser.mdx | 2 +- api_docs/kbn_ui_shared_deps_src.mdx | 2 +- api_docs/kbn_ui_theme.mdx | 2 +- api_docs/kbn_unified_data_table.mdx | 2 +- api_docs/kbn_unified_doc_viewer.mdx | 2 +- api_docs/kbn_unified_field_list.mdx | 2 +- api_docs/kbn_unsaved_changes_badge.mdx | 2 +- api_docs/kbn_unsaved_changes_prompt.mdx | 2 +- api_docs/kbn_use_tracked_promise.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_visualization_ui_components.mdx | 2 +- api_docs/kbn_visualization_utils.mdx | 2 +- api_docs/kbn_xstate_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kbn_zod.mdx | 2 +- api_docs/kbn_zod_helpers.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.devdocs.json | 23 +- api_docs/lens.mdx | 2 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/links.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/logs_data_access.mdx | 2 +- api_docs/logs_explorer.mdx | 2 +- api_docs/logs_shared.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/metrics_data_access.mdx | 2 +- api_docs/ml.devdocs.json | 4 +- api_docs/ml.mdx | 2 +- api_docs/mock_idp_plugin.mdx | 2 +- api_docs/monitoring.mdx | 2 +- api_docs/monitoring_collection.mdx | 2 +- api_docs/navigation.devdocs.json | 16 +- api_docs/navigation.mdx | 4 +- api_docs/newsfeed.mdx | 2 +- api_docs/no_data_page.mdx | 2 +- api_docs/notifications.mdx | 2 +- api_docs/observability.devdocs.json | 228 -- api_docs/observability.mdx | 4 +- .../observability_a_i_assistant.devdocs.json | 20 +- api_docs/observability_a_i_assistant.mdx | 2 +- api_docs/observability_a_i_assistant_app.mdx | 2 +- .../observability_ai_assistant_management.mdx | 2 +- api_docs/observability_logs_explorer.mdx | 2 +- api_docs/observability_onboarding.mdx | 2 +- api_docs/observability_shared.devdocs.json | 34 +- api_docs/observability_shared.mdx | 4 +- api_docs/osquery.mdx | 2 +- api_docs/painless_lab.mdx | 2 +- api_docs/plugin_directory.mdx | 53 +- api_docs/presentation_panel.mdx | 2 +- api_docs/presentation_util.mdx | 2 +- api_docs/profiling.mdx | 2 +- api_docs/profiling_data_access.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.devdocs.json | 636 ---- api_docs/rule_registry.mdx | 4 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_finder.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.devdocs.json | 961 +---- api_docs/saved_objects_tagging.mdx | 7 +- .../saved_objects_tagging_oss.devdocs.json | 86 +- api_docs/saved_objects_tagging_oss.mdx | 4 +- api_docs/saved_search.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/search_assistant.mdx | 2 +- api_docs/search_connectors.mdx | 2 +- api_docs/search_homepage.mdx | 2 +- api_docs/search_indices.devdocs.json | 2 +- api_docs/search_indices.mdx | 2 +- api_docs/search_inference_endpoints.mdx | 2 +- api_docs/search_notebooks.mdx | 2 +- api_docs/search_playground.mdx | 2 +- api_docs/security.devdocs.json | 4 + api_docs/security.mdx | 2 +- api_docs/security_solution.devdocs.json | 14 +- api_docs/security_solution.mdx | 2 +- api_docs/security_solution_ess.mdx | 2 +- api_docs/security_solution_serverless.mdx | 2 +- api_docs/serverless.devdocs.json | 20 +- api_docs/serverless.mdx | 2 +- api_docs/serverless_observability.mdx | 2 +- api_docs/serverless_search.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.devdocs.json | 2 +- api_docs/share.mdx | 2 +- api_docs/slo.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.devdocs.json | 10 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/stack_connectors.mdx | 2 +- api_docs/task_manager.devdocs.json | 31 +- api_docs/task_manager.mdx | 4 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/threat_intelligence.mdx | 2 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_doc_viewer.mdx | 2 +- api_docs/unified_histogram.mdx | 2 +- api_docs/unified_search.mdx | 2 +- api_docs/unified_search_autocomplete.mdx | 2 +- api_docs/uptime.mdx | 2 +- api_docs/url_forwarding.mdx | 2 +- api_docs/usage_collection.mdx | 2 +- api_docs/ux.mdx | 2 +- api_docs/vis_default_editor.mdx | 2 +- api_docs/vis_type_gauge.mdx | 2 +- api_docs/vis_type_heatmap.mdx | 2 +- api_docs/vis_type_pie.mdx | 2 +- api_docs/vis_type_table.mdx | 2 +- api_docs/vis_type_timelion.mdx | 2 +- api_docs/vis_type_timeseries.mdx | 2 +- api_docs/vis_type_vega.mdx | 2 +- api_docs/vis_type_vislib.mdx | 2 +- api_docs/vis_type_xy.mdx | 2 +- api_docs/visualizations.devdocs.json | 10 +- api_docs/visualizations.mdx | 2 +- config/kibana.yml | 5 - dev_docs/key_concepts/api_authorization.mdx | 17 + dev_docs/nav-kibana-dev.docnav.json | 13 +- dev_docs/shared_ux/shared_ux_landing.mdx | 10 - .../browser_snapshots_filter1.png | Bin .../browser_snapshots_filter2.png | Bin .../browser_snapshots_listing.png | Bin .../chromium_version_command.png | Bin .../{ => screenshotting}/screenshotting.mdx | 0 ...tting_updating_puppeteer_and_chromium.mdx} | 0 docs/api/role-management.asciidoc | 18 +- docs/api/role-management/delete.asciidoc | 26 - docs/api/role-management/get-all.asciidoc | 80 - docs/api/role-management/get.asciidoc | 106 - docs/api/role-management/put-bulk.asciidoc | 377 -- docs/api/role-management/put.asciidoc | 238 -- .../architecture/security/rbac.asciidoc | 2 +- docs/management/action-types.asciidoc | 4 +- docs/management/advanced-options.asciidoc | 3 - .../action-types/inference.asciidoc | 32 +- docs/management/watcher-ui/index.asciidoc | 5 +- docs/redirects.asciidoc | 26 +- docs/settings/security-settings.asciidoc | 2 +- docs/setup/configuring-reporting.asciidoc | 5 +- .../user/dashboard/create-dashboards.asciidoc | 19 + docs/user/dashboard/dashboard.asciidoc | 2 +- docs/user/dashboard/drilldowns.asciidoc | 2 +- .../managed-dashboard-popover-8.16.0.png | Bin 0 -> 34533 bytes docs/user/introduction.asciidoc | 4 +- docs/user/security/api-keys/index.asciidoc | 2 +- .../authorization/kibana-privileges.asciidoc | 19 +- docs/user/security/index.asciidoc | 4 +- .../public/plugin.tsx | 108 +- .../tsconfig.json | 1 - .../components/esql_inspector/helpers.tsx | 2 + oas_docs/bundle.json | 2729 ++++---------- oas_docs/bundle.serverless.json | 2719 ++++---------- oas_docs/examples/create_role_request1.yaml | 23 + oas_docs/examples/create_role_request2.yaml | 16 + oas_docs/examples/create_role_request3.yaml | 14 + oas_docs/examples/create_role_request4.yaml | 34 + oas_docs/examples/get_role_response1.yaml | 41 + oas_docs/examples/get_roles_response1.yaml | 39 + .../output/kibana.serverless.staging.yaml | 0 oas_docs/output/kibana.serverless.yaml | 2804 ++++++++------- oas_docs/output/kibana.staging.yaml | 0 oas_docs/output/kibana.yaml | 3154 +++++++++-------- oas_docs/overlays/kibana.overlays.yaml | 37 +- oas_docs/scripts/merge_ess_oas.js | 2 +- oas_docs/scripts/merge_serverless_oas.js | 2 +- package.json | 15 +- .../src/chrome_service.tsx | 6 +- .../project_navigation_service.test.ts | 48 +- .../project_navigation_service.ts | 15 +- .../src/project_navigation/utils.ts | 4 +- .../core-chrome-browser-internal/src/types.ts | 5 +- .../src/ui/loading_indicator.scss | 5 + .../src/ui/project/header.tsx | 6 +- .../core/chrome/core-chrome-browser/index.ts | 1 + .../chrome/core-chrome-browser/src/index.ts | 1 + .../src/project_navigation.ts | 11 +- packages/core/feature-flags/README.mdx | 79 +- .../__snapshots__/i18n_service.test.tsx.snap | 9 +- .../src/i18n_eui_mapping.tsx | 15 +- .../src/kbn_bootstrap.ts | 70 + .../src/import/import_saved_objects.test.ts | 5 +- .../src/import/import_saved_objects.ts | 23 +- .../src/import/saved_objects_importer.ts | 2 +- packages/deeplinks/search/constants.ts | 4 + packages/deeplinks/search/deep_links.ts | 14 +- packages/deeplinks/search/index.ts | 4 + packages/kbn-alerting-types/r_rule_types.ts | 2 +- .../generated/observability_uptime_schema.ts | 1 + .../src/lib/entities/kubernetes/index.ts | 6 +- .../copy_to_clipboard/copy_to_clipboard.ts | 2 +- .../src/field_maps/types.ts | 2 + packages/kbn-discover-utils/index.ts | 1 + .../app_menu_registry.test.ts.snap | 184 + .../app_menu/app_menu_registry.test.ts | 188 + .../components/app_menu/app_menu_registry.ts | 214 ++ .../src/components/app_menu/types.ts | 148 + packages/kbn-discover-utils/src/index.ts | 1 + packages/kbn-discover-utils/src/types.ts | 2 + packages/kbn-discover-utils/tsconfig.json | 5 +- packages/kbn-es-types/src/search.ts | 1 + .../rules/no_deprecated_authz_config.js | 2 +- packages/kbn-esql-ast/src/builder/builder.ts | 92 +- .../src/mutate/commands/from/metadata.ts | 10 +- .../src/mutate/commands/from/sources.ts | 6 +- .../kbn-esql-ast/src/mutate/commands/index.ts | 3 +- .../src/mutate/commands/limit/index.ts | 8 +- .../src/mutate/commands/sort/index.test.ts | 527 +++ .../src/mutate/commands/sort/index.ts | 313 ++ packages/kbn-esql-ast/src/mutate/generic.ts | 287 -- .../generic/commands/args/index.test.ts | 132 + .../src/mutate/generic/commands/args/index.ts | 86 + .../commands/index.test.ts} | 77 +- .../src/mutate/generic/commands/index.ts | 131 + .../generic/commands/options/index.test.ts | 49 + .../mutate/generic/commands/options/index.ts | 130 + .../kbn-esql-ast/src/mutate/generic/index.ts | 10 + .../src/parser/__tests__/function.test.ts | 97 + packages/kbn-esql-ast/src/parser/factories.ts | 85 +- .../kbn-esql-ast/src/parser/formatting.ts | 4 + packages/kbn-esql-ast/src/parser/walkers.ts | 66 +- packages/kbn-esql-ast/src/types.ts | 17 +- packages/kbn-esql-editor/src/esql_editor.tsx | 2 +- .../src/__tests__/helpers.ts | 2 +- .../autocomplete.command.from.test.ts | 3 - .../__tests__/autocomplete.suggest.test.ts | 2 +- .../src/autocomplete/__tests__/helpers.ts | 23 +- .../src/autocomplete/autocomplete.test.ts | 64 +- .../src/autocomplete/autocomplete.ts | 473 +-- .../src/autocomplete/commands/drop/index.ts | 70 + .../src/autocomplete/commands/keep/index.ts | 70 + .../src/autocomplete/commands/sort/helper.ts | 38 + .../src/autocomplete/commands/sort/index.ts | 159 + .../src/autocomplete/complete_items.ts | 10 +- .../src/autocomplete/factories.ts | 4 +- .../src/autocomplete/helper.ts | 213 +- .../recommended_queries/suggestions.ts | 4 +- .../src/autocomplete/types.ts | 2 +- .../src/code_actions/actions.test.ts | 14 +- .../src/code_actions/actions.ts | 2 +- .../src/definitions/commands.ts | 9 +- .../generated/aggregation_functions.ts | 8 +- .../definitions/generated/scalar_functions.ts | 40 +- .../src/definitions/helpers.ts | 13 +- .../src/definitions/options.ts | 10 - .../src/definitions/types.ts | 24 +- .../src/shared/helpers.test.ts | 78 +- .../src/shared/helpers.ts | 44 +- .../src/shared/resources_helpers.ts | 2 +- .../src/shared/types.ts | 2 +- .../validation/__tests__/callbacks.test.ts | 4 +- .../test_suites/validation.command.from.ts | 73 +- .../__tests__/validation.ccs.test.ts | 34 +- .../esql_validation_meta_tests.json | 70 +- .../src/validation/validation.test.ts | 28 +- .../src/validation/validation.ts | 2 +- packages/kbn-flot-charts/lib/jquery_flot.js | 2415 ++++++------- .../saml_auth/default_request_headers.ts | 1 + .../saml_auth/serverless/auth_provider.ts | 24 +- .../kbn-grid-layout/grid/drag_preview.tsx | 71 + packages/kbn-grid-layout/grid/grid_layout.tsx | 37 +- packages/kbn-grid-layout/grid/grid_panel.tsx | 266 +- packages/kbn-grid-layout/grid/grid_row.tsx | 208 +- .../grid/use_grid_layout_events.ts | 7 +- .../grid/use_grid_layout_state.ts | 116 +- packages/kbn-grid-layout/tsconfig.json | 1 - .../sections/esql_documentation_sections.tsx | 24 +- .../settings/setting_ids/index.ts | 5 - .../src/worker/webpack.config.ts | 8 + .../__snapshots__/generate_oas.test.ts.snap | 18 +- .../src/extract_authz_description.test.ts | 81 + .../src/extract_authz_description.ts | 60 + .../src/generate_oas.test.fixture.ts | 6 +- .../src/generate_oas.ts | 5 +- .../src/operation_id_counter.test.ts | 32 - .../src/operation_id_counter.ts | 24 - .../src/process_router.test.ts | 44 +- .../src/process_router.ts | 19 +- .../src/process_versioned_router.test.ts | 27 +- .../src/process_versioned_router.ts | 15 +- .../kbn-router-to-openapispec/src/type.ts | 3 + .../src/util.test.ts | 82 + .../kbn-router-to-openapispec/src/util.ts | 47 +- .../kbn-router-to-openapispec/tsconfig.json | 2 +- packages/kbn-rrule/rrule.ts | 8 + .../connector_configuration_field.tsx | 12 +- .../src/extract_warnings.test.ts | 17 + .../src/extract_warnings.ts | 14 +- .../tsconfig.json | 1 + .../functional_tests/lib/run_elasticsearch.ts | 9 +- packages/kbn-test/src/jest/resolver.js | 7 + .../src/mocha/junit_report_generation.test.js | 9 +- .../settings/observability_project/index.ts | 2 - .../button/exit_full_screen/src/services.tsx | 12 +- .../navigation/__jest__/active_node.test.tsx | 2 +- .../__jest__/build_nav_tree.test.tsx | 11 + .../chrome/navigation/__jest__/panel.test.tsx | 6 + .../src/ui/components/feedback_btn.tsx | 15 +- .../navigation/src/ui/navigation.stories.tsx | 3 + .../chrome/navigation/src/ui/navigation.tsx | 5 +- scripts/codeql/codeql.dockerfile | 39 + scripts/codeql/quick_check.sh | 126 + .../check_registered_types.test.ts | 2 +- .../saved_objects/routes/import.test.ts | 15 +- .../tasks/os_packages/docker_generator/run.ts | 2 +- src/dev/i18n_tools/bin/run_i18n_check.ts | 18 +- src/dev/license_checker/config.ts | 2 +- .../public/components/xy_chart.test.tsx | 2 +- .../public/helpers/data_layers.tsx | 2 +- src/plugins/dashboard/kibana.jsonc | 1 + .../listing_page/dashboard_listing_page.tsx | 13 +- .../component/viewport/dashboard_viewport.tsx | 46 +- .../data_views/data_views_api_client.test.ts | 3 - .../data_views/data_views_api_client.ts | 3 +- .../convert_to_top_nav_item.test.ts | 118 + .../convert_to_top_nav_item.ts | 54 + .../get_alerts.test.tsx} | 44 +- .../top_nav/app_menu_actions/get_alerts.tsx | 179 + .../top_nav/app_menu_actions/get_inspect.tsx | 34 + .../app_menu_actions/get_new_search.tsx | 35 + .../app_menu_actions/get_open_search.tsx | 37 + .../top_nav/app_menu_actions/get_share.tsx | 135 + .../top_nav/app_menu_actions/index.ts | 16 + .../run_app_menu_action.test.tsx | 120 + .../app_menu_actions/run_app_menu_action.tsx | 189 + .../top_nav/app_menu_actions/types.ts | 12 + .../top_nav/discover_topnav.test.tsx | 51 +- .../components/top_nav/discover_topnav.tsx | 2 + .../top_nav/get_top_nav_badges.test.ts | 41 - .../components/top_nav/get_top_nav_badges.tsx | 22 +- .../top_nav/get_top_nav_links.test.ts | 154 - .../components/top_nav/get_top_nav_links.tsx | 316 -- .../top_nav/open_alerts_popover.tsx | 237 -- .../top_nav/show_open_search_panel.tsx | 47 - .../main/components/top_nav/top_nav.scss | 3 + .../components/top_nav/use_discover_topnav.ts | 35 +- .../top_nav/use_top_nav_links.test.tsx | 190 + .../components/top_nav/use_top_nav_links.tsx | 224 ++ .../total_documents/total_documents.tsx | 44 +- .../loading_indicator.test.tsx.snap | 44 +- .../components/common/loading_indicator.tsx | 10 +- .../view_mode_toggle.test.tsx | 2 + .../view_mode_toggle/view_mode_toggle.tsx | 9 +- .../example_data_source_profile/profile.tsx | 100 +- .../example/example_root_pofile/profile.tsx | 66 +- .../public/context_awareness/types.ts | 40 +- .../top_nav_customization.ts | 15 - .../components/saved_search_grid.tsx | 4 +- .../server/collectors/management/schema.ts | 8 - .../server/collectors/management/types.ts | 2 - src/plugins/navigation/public/plugin.test.ts | 2 +- src/plugins/navigation/public/plugin.tsx | 6 +- .../top_nav_menu_item.test.tsx.snap | 18 + .../public/top_nav_menu/top_nav_menu_data.tsx | 1 + .../top_nav_menu/top_nav_menu_item.test.tsx | 18 + .../public/top_nav_menu/top_nav_menu_item.tsx | 45 +- .../top_nav_menu/top_nav_menu_items.tsx | 10 +- .../saved_searches/to_saved_search.test.ts | 8 +- src/plugins/saved_search/tsconfig.json | 1 - src/plugins/telemetry/schema/oss_plugins.json | 12 - .../get_data_telemetry/get_data_telemetry.ts | 3 +- .../public/markdown_vis_controller.tsx | 1 + test/api_integration/apis/home/sample_data.ts | 26 +- .../customizations.ts | 6 - .../apps/console/_misc_console_behavior.ts | 3 +- .../extensions/_get_app_menu.ts | 73 + .../apps/discover/context_awareness/index.ts | 1 + .../discover/group6/_sidebar_field_stats.ts | 12 +- test/functional/page_objects/console_page.ts | 5 +- test/functional/page_objects/discover_page.ts | 1 + tsconfig.base.json | 2 + .../ai-infra/inference-common/README.md | 7 + .../ai-infra/inference-common/index.ts | 77 + .../ai-infra/inference-common/jest.config.js | 12 + .../ai-infra/inference-common/kibana.jsonc | 5 + .../ai-infra/inference-common/package.json | 7 + .../inference-common/src/chat_complete/api.ts | 69 + .../src}/chat_complete/errors.ts | 64 +- .../src/chat_complete/event_utils.ts | 81 + .../src/chat_complete/events.ts | 118 + .../src/chat_complete/index.ts | 55 + .../src/chat_complete/messages.ts | 75 + .../src}/chat_complete/tool_schema.ts | 6 + .../src}/chat_complete/tools.ts | 87 +- .../ai-infra/inference-common/src}/errors.ts | 12 +- .../inference-common/src}/inference_task.ts | 6 + .../inference-common/src/output/api.ts | 46 + .../src/output/event_utils.ts | 49 + .../inference-common/src/output/events.ts | 65 + .../inference-common/src/output/index.ts | 21 + .../ai-infra/inference-common/tsconfig.json | 20 + .../kbn-ai-assistant/src/chat/chat_flyout.tsx | 136 +- .../src/prompt_editor/prompt_editor.tsx | 7 +- .../prompt_editor_natural_language.tsx | 9 + .../public/index.ts | 2 +- .../src/constants/component_constants.ts | 1 + .../hooks/use_get_navigation_url_params.ts | 33 + .../public/src/hooks/use_navigate_findings.ts | 74 +- .../public/src/utils/query_utils.test.ts | 107 + .../public/src/utils/query_utils.ts | 62 + .../public/tsconfig.json | 1 + .../impl/capabilities/index.ts | 2 +- .../knowledge_base/crud_kb_route.gen.ts | 1 + .../knowledge_base/crud_kb_route.schema.yaml | 2 + .../entries/use_knowledge_base_entries.ts | 3 + .../use_knowledge_base_status.test.tsx | 1 + .../use_knowledge_base_status.tsx | 23 +- .../chat_send/use_chat_send.test.tsx | 3 + .../assistant/chat_send/use_chat_send.tsx | 8 +- .../inline_actions/index.tsx | 1 + .../impl/assistant/index.test.tsx | 79 - .../knowledge_base_settings.test.tsx | 3 + .../knowledge_base_settings.tsx | 16 +- .../document_entry_editor.tsx | 21 +- .../index.test.tsx | 209 +- .../index.tsx | 94 +- .../index_entry_editor.test.tsx | 17 + .../index_entry_editor.tsx | 32 +- .../translations.ts | 44 + .../use_knowledge_base_table.tsx | 84 +- .../setup_knowledge_base_button.tsx | 30 +- .../impl/tour/knowledge_base/overview.gif | Bin 1741049 -> 1050475 bytes .../tour/knowledge_base/video_toast.test.tsx | 12 +- .../impl/tour/knowledge_base/video_toast.tsx | 6 +- .../esql_result_to_plain_objects.test.ts | 66 + .../es/utils/esql_result_to_plain_objects.ts | 12 +- .../upselling/messages/index.tsx | 4 +- .../src/authorization/role_schema.ts | 147 +- x-pack/plugins/actions/kibana.jsonc | 3 +- .../actions_client/actions_client.test.ts | 118 +- .../server/actions_client/actions_client.ts | 65 +- .../actions/server/actions_config.test.ts | 5 +- .../connector/methods/execute/execute.ts | 64 +- .../connector/methods/get_all/get_all.test.ts | 19 - .../actions_authorization.test.ts | 19 - .../authorization/actions_authorization.ts | 68 +- .../get_authorization_mode_by_source.test.ts | 277 -- .../get_authorization_mode_by_source.ts | 90 - x-pack/plugins/actions/server/config.test.ts | 9 + x-pack/plugins/actions/server/config.ts | 19 +- .../axios_utils_connection.test.ts | 5 +- .../axios_utils_proxy.test.ts | 5 +- .../server/lib/action_executor.test.ts | 2 +- .../actions/server/lib/action_executor.ts | 11 + .../server/lib/custom_host_settings.test.ts | 5 +- .../server/lib/task_runner_factory.test.ts | 15 +- .../actions/server/lib/task_runner_factory.ts | 36 +- .../lib/track_legacy_rbac_exemption.test.ts | 44 - .../server/lib/track_legacy_rbac_exemption.ts | 22 - x-pack/plugins/actions/server/plugin.test.ts | 15 + x-pack/plugins/actions/server/plugin.ts | 33 +- .../{legacy => }/_mock_handler_arguments.ts | 8 +- .../routes/connector/create/create.test.ts | 2 +- .../routes/connector/delete/delete.test.ts | 2 +- .../routes/connector/execute/execute.test.ts | 2 +- .../server/routes/connector/get/get.test.ts | 2 +- .../routes/connector/get_all/get_all.test.ts | 2 +- .../get_all_system/get_all_system.test.ts | 2 +- .../connector/list_types/list_types.test.ts | 2 +- .../list_types_system.test.ts | 2 +- .../routes/connector/update/update.test.ts | 2 +- .../routes/get_global_execution_kpi.test.ts | 2 +- .../routes/get_global_execution_logs.test.ts | 2 +- .../routes/get_oauth_access_token.test.ts | 2 +- x-pack/plugins/actions/server/routes/index.ts | 5 +- .../server/routes/legacy/create.test.ts | 158 - .../actions/server/routes/legacy/create.ts | 67 - .../server/routes/legacy/delete.test.ts | 138 - .../actions/server/routes/legacy/delete.ts | 68 - .../server/routes/legacy/execute.test.ts | 214 -- .../actions/server/routes/legacy/execute.ts | 88 - .../actions/server/routes/legacy/get.test.ts | 165 - .../actions/server/routes/legacy/get.ts | 63 - .../server/routes/legacy/get_all.test.ts | 116 - .../actions/server/routes/legacy/get_all.ts | 45 - .../actions/server/routes/legacy/index.ts | 32 - .../routes/legacy/list_action_types.test.ts | 178 - .../server/routes/legacy/list_action_types.ts | 48 - .../server/routes/legacy/update.test.ts | 215 -- .../actions/server/routes/legacy/update.ts | 82 - .../routes/verify_access_and_context.test.ts | 2 +- .../connector_usage_reporting_task.test.ts | 394 ++ .../usage/connector_usage_reporting_task.ts | 309 ++ x-pack/plugins/actions/server/usage/types.ts | 15 + x-pack/plugins/actions/tsconfig.json | 3 +- .../maintenance_window/apis/find/index.ts | 18 +- .../apis/find/schemas/latest.ts} | 6 +- .../apis/find/schemas/v1.ts | 51 + .../apis/find/types/latest.ts | 2 +- .../maintenance_window/apis/find/types/v1.ts | 18 +- .../maintenance_window/response/schemas/v1.ts | 2 +- .../routes/r_rule/response/schemas/v1.ts | 130 +- .../common/routes/rule/response/schemas/v1.ts | 29 +- .../services/maintenance_windows_api/find.ts | 2 +- .../transform_maintenance_window_response.ts | 1 - .../lib/get_summarized_alerts_query.ts | 25 +- .../lib/inject_analyze_wildcard.test.ts | 169 + .../lib/inject_analyze_wildcard.ts | 30 + .../methods/schedule/schedule_backfill.ts | 8 +- .../archive/archive_maintenance_window.ts | 1 - .../find/find_maintenance_windows.test.ts | 47 +- .../methods/find/find_maintenance_windows.ts | 24 +- .../find_maintenance_window_params_schema.ts} | 11 +- .../find_maintenance_windows_result_schema.ts | 3 + .../methods/find/schemas/index.ts | 1 + .../types/find_maintenance_window_params.ts | 11 + .../methods/find/types/index.ts | 1 + .../finish/finish_maintenance_window.ts | 1 - .../update/update_maintenance_window.test.ts | 15 + .../update/update_maintenance_window.ts | 8 +- .../r_rule/schemas/r_rule_schema.ts | 20 +- .../methods/bulk_delete/bulk_delete_rules.ts | 21 +- .../bulk_disable/bulk_disable_rules.ts | 30 +- .../methods/bulk_edit/bulk_edit_rules.test.ts | 4 +- .../rule/methods/bulk_edit/bulk_edit_rules.ts | 45 +- .../methods/bulk_enable/bulk_enable_rules.ts | 24 +- .../rule/methods/clone/clone_rule.ts | 15 +- .../rule/methods/create/create_rule.ts | 8 +- .../rule/methods/delete/delete_rule.ts | 3 +- .../rule/methods/disable/disable_rule.ts | 3 +- .../rule/methods/mute_all/mute_all.ts | 3 +- .../rule/methods/unmute_all/unmute_all.ts | 3 +- .../rule/methods/update/update_rule.ts | 9 +- .../application/rule/schemas/rule_schemas.ts | 14 +- ...form_raw_actions_to_domain_actions.test.ts | 6 +- ...transform_raw_actions_to_domain_actions.ts | 13 +- ...orm_rule_attributes_to_rule_domain.test.ts | 8 +- ...ransform_rule_attributes_to_rule_domain.ts | 10 +- ...ransform_rule_domain_to_rule_attributes.ts | 12 +- .../methods/find_maintenance_window_so.ts | 2 +- .../data/r_rule/types/r_rule_attributes.ts | 18 +- .../data/rule/methods/bulk_create_rule_so.ts | 8 +- .../rule/methods/bulk_disable_rules_so.ts | 8 +- .../data/rule/methods/create_rule_so.ts | 6 +- .../server/data/rule/methods/find_rules_so.ts | 6 +- .../rule/methods/get_decrypted_rule_so.ts | 6 +- .../server/data/rule/methods/get_rule_so.ts | 6 +- .../data/rule/methods/resolve_rule_so.ts | 4 +- .../data/rule/methods/update_rule_so.ts | 10 +- .../alerting/server/data/rule/types/index.ts | 24 - .../server/data/rule/types/rule_attributes.ts | 189 - .../alert_as_data_fields.test.ts.snap | 20 + .../maintenance_window_client.ts | 8 +- .../manual_tests/action_param_templates.sh | 14 +- .../archive_maintenance_window_route.test.ts | 1 - .../find_maintenance_windows_route.test.ts | 49 +- .../find/find_maintenance_windows_route.ts | 47 +- .../apis/find/transforms/index.ts | 12 + .../latest.ts | 8 + .../v1.ts | 16 + .../latest.ts | 8 + .../v1.ts | 24 + .../finish_maintenance_window_route.test.ts | 1 - .../get/get_maintenance_window_route.test.ts | 1 - ...t_active_maintenance_windows_route.test.ts | 1 - .../update_maintenance_window_route.test.ts | 1 - .../transform_rule_to_rule_response/v1.ts | 2 +- .../rules_client/common/inject_references.ts | 3 +- .../common/retry_if_bulk_edit_conflicts.ts | 10 +- .../retry_if_bulk_operation_conflicts.ts | 6 +- .../rules_client/common/snooze_utils.ts | 17 +- .../lib/create_rule_saved_object.ts | 16 +- .../rules_client/lib/get_rule_saved_object.ts | 4 +- .../lib/increment_revision.test.ts | 5 +- .../rules_client/lib/increment_revision.ts | 5 +- .../lib/resolve_rule_saved_object.ts | 4 +- .../rules_client/lib/untrack_rule_alerts.ts | 5 +- .../server/rules_client/lib/update_meta.ts | 9 +- .../lib/update_meta_attributes.ts | 4 +- .../model_versions/rule_model_versions.ts | 9 +- .../partially_update_rule.test.ts | 4 +- .../saved_objects/partially_update_rule.ts | 8 +- .../saved_objects/schemas/raw_rule/index.ts | 3 + .../saved_objects/schemas/raw_rule/latest.ts | 25 + .../saved_objects/schemas/raw_rule/v2.ts | 1 + .../saved_objects/schemas/raw_rule/v3.ts | 299 ++ x-pack/plugins/alerting/server/types.ts | 105 +- x-pack/plugins/canvas/server/plugin.ts | 6 - .../sample_data/ecommerce_saved_objects.json | 1220 ------- .../sample_data/flights_saved_objects.json | 512 --- .../canvas/server/sample_data/index.ts | 16 - .../server/sample_data/load_sample_data.ts | 71 - .../sample_data/web_logs_saved_objects.json | 757 ---- .../plugins/cases/common/schema/index.test.ts | 66 + x-pack/plugins/cases/common/schema/index.ts | 18 + .../cases/common/types/api/case/v1.test.ts | 55 +- .../plugins/cases/common/types/api/case/v1.ts | 23 +- .../common/types/api/configure/v1.test.ts | 94 + .../cases/common/types/api/configure/v1.ts | 30 +- .../common/types/api/custom_field/v1.test.ts | 36 +- .../cases/common/types/api/custom_field/v1.ts | 14 +- .../cases/common/types/domain/case/v1.test.ts | 10 + .../common/types/domain/configure/v1.test.ts | 74 +- .../cases/common/types/domain/configure/v1.ts | 17 +- .../types/domain/custom_field/v1.test.ts | 26 + .../common/types/domain/custom_field/v1.ts | 15 +- .../cases/public/common/translations.ts | 6 + .../all_cases/columns_popover.test.tsx | 3 +- .../case_form_fields/custom_fields.test.tsx | 13 +- .../case_form_fields/index.test.tsx | 10 + .../components/custom_fields.test.tsx | 8 +- .../category/category_form_field.test.tsx | 3 +- .../configure_cases/connectors.test.tsx | 43 +- .../components/configure_cases/connectors.tsx | 23 +- .../connectors_dropdown.test.tsx | 26 - .../configure_cases/connectors_dropdown.tsx | 31 +- .../configure_cases/flyout.test.tsx | 10 + .../components/configure_cases/index.test.tsx | 29 +- .../components/configure_cases/index.tsx | 5 + .../configure_cases/translations.ts | 4 + .../components/connector_selector/form.tsx | 10 +- .../components/create/form_context.test.tsx | 11 + .../components/custom_fields/builder.tsx | 2 + .../custom_fields_list/index.test.tsx | 9 +- .../components/custom_fields/number/config.ts | 49 + .../custom_fields/number/configure.test.tsx | 108 + .../custom_fields/number/configure.tsx | 54 + .../number/configure_number_field.test.ts | 25 + .../number/configure_number_field.ts | 28 + .../custom_fields/number/create.test.tsx | 225 ++ .../custom_fields/number/create.tsx | 52 + .../custom_fields/number/edit.test.tsx | 475 +++ .../components/custom_fields/number/edit.tsx | 246 ++ .../number/get_eui_table_column.test.tsx | 48 + .../number/get_eui_table_column.tsx | 27 + .../custom_fields/number/view.test.tsx | 29 + .../components/custom_fields/number/view.tsx | 29 + .../text/configure_text_field.ts | 3 +- .../components/custom_fields/translations.ts | 4 + .../public/components/custom_fields/types.ts | 2 +- .../components/custom_fields/utils.test.ts | 35 + .../public/components/custom_fields/utils.ts | 9 + .../files/file_attachment_event.test.tsx | 3 +- .../editable_markdown_renderer.test.tsx | 3 +- .../public/components/templates/form.test.tsx | 24 +- .../components/templates/form_fields.test.tsx | 10 + .../cases/public/components/utils.test.ts | 85 +- .../plugins/cases/public/components/utils.ts | 22 +- .../plugins/cases/public/containers/mock.ts | 15 + .../containers/use_replace_custom_field.tsx | 2 +- .../plugins/cases/server/client/utils.test.ts | 2 +- .../cases/server/common/types/configure.ts | 2 +- .../server/connectors/cases/constants.ts | 13 +- .../cases/server/custom_fields/factory.ts | 2 + .../cases/server/custom_fields/number.ts | 21 + x-pack/plugins/cases/server/plugin.ts | 7 +- .../server/routes/api/cases/get_case.test.ts | 62 + .../cases/server/routes/api/cases/get_case.ts | 92 +- .../api/comments/get_all_comment.test.ts | 22 + .../routes/api/comments/get_all_comment.ts | 75 +- .../server/routes/api/get_external_routes.ts | 10 +- .../routes/api/stats/get_status.test.ts | 22 + .../server/routes/api/stats/get_status.ts | 65 +- .../user_actions/get_all_user_actions.test.ts | 22 + .../api/user_actions/get_all_user_actions.ts | 73 +- .../server/telemetry/queries/alerts.test.ts | 40 +- .../cases/server/telemetry/queries/alerts.ts | 7 +- .../server/telemetry/queries/utils.test.ts | 228 ++ .../cases/server/telemetry/queries/utils.ts | 122 +- .../plugins/cases/server/telemetry/types.ts | 4 + .../parse_onboarding_default_solution.ts | 6 +- x-pack/plugins/cloud/common/types.ts | 2 - x-pack/plugins/cloud/public/types.ts | 4 +- x-pack/plugins/cloud/server/plugin.ts | 4 +- x-pack/plugins/cloud/tsconfig.json | 1 + .../server/routes/policies/policies.ts | 2 +- .../common/utils/helpers.ts | 2 +- .../public/common/constants.ts | 30 + .../accounts_evaluated_widget.test.tsx | 1 + .../components/accounts_evaluated_widget.tsx | 6 +- .../public/components/cloud_provider_icon.tsx | 2 +- .../components/compliance_score_bar.test.tsx | 49 + .../components/compliance_score_bar.tsx | 18 +- .../public/components/test_subjects.ts | 4 + .../dashboard_sections/benchmarks_section.tsx | 2 +- .../dashboard_sections/summary_section.tsx | 2 +- .../latest_findings_group_renderer.test.tsx | 101 + .../latest_findings_group_renderer.tsx | 8 +- .../latest_findings/use_grouped_findings.tsx | 3 - .../latest_findings/use_latest_findings.ts | 22 +- .../use_latest_findings_grouping.tsx | 71 +- .../hooks/use_latest_vulnerabilities.tsx | 31 +- .../use_latest_vulnerabilities_grouping.tsx | 42 +- .../vulnerability_statistics.tsx | 4 +- .../vulnerability_table_panel_section.tsx | 6 +- .../vulnerability_trend_graph.tsx | 4 +- .../server/routes/benchmarks/v1.ts | 2 +- .../lib/fetch_available_indices.test.ts | 454 +++ .../server/lib/fetch_available_indices.ts | 64 +- .../server/lib/fetch_stats.ts | 14 +- .../server/routes/get_ilm_explain.ts | 6 +- .../server/routes/get_index_mappings.ts | 6 +- .../server/routes/get_index_stats.test.ts | 18 +- .../server/routes/get_index_stats.ts | 13 +- .../routes/results/get_index_results.ts | 6 +- .../results/get_index_results_latest.ts | 6 +- .../routes/results/post_index_results.ts | 6 +- .../ecs_data_quality_dashboard/tsconfig.json | 1 + .../server/__mocks__/msearch_query.ts | 10 +- .../server/__mocks__/vector_search_query.ts | 10 +- .../anonymization_fields/helpers.ts | 14 +- .../conversations/helpers.ts | 14 +- .../conversations/update_conversation.ts | 2 +- .../create_knowledge_base_entry.ts | 54 +- .../field_maps_configuration.ts | 8 + .../knowledge_base/helpers.ts | 54 +- .../knowledge_base/index.ts | 266 +- .../knowledge_base/ingest_pipeline.ts | 39 +- .../knowledge_base/types.ts | 3 + .../prompts/helpers.ts | 14 +- ...reate_resource_installation_helper.test.ts | 8 +- .../create_resource_installation_helper.ts | 4 +- .../server/ai_assistant_service/helpers.ts | 3 + .../server/ai_assistant_service/index.test.ts | 17 + .../server/ai_assistant_service/index.ts | 23 +- .../lib/data_stream/documents_data_writer.ts | 17 +- .../content_loaders/security_labs_loader.ts | 33 +- .../bulk_actions_route.ts | 36 +- .../anonymization_fields/find_route.test.ts | 14 +- .../routes/anonymization_fields/find_route.ts | 18 +- .../routes/chat/chat_complete_route.test.ts | 13 +- .../server/routes/chat/chat_complete_route.ts | 27 +- .../server/routes/evaluate/get_evaluate.ts | 7 +- .../server/routes/evaluate/post_evaluate.ts | 6 +- .../server/routes/helpers.ts | 92 +- .../server/routes/knowledge_base/constants.ts | 3 + .../entries/bulk_actions_route.ts | 11 +- .../knowledge_base/entries/create_route.ts | 6 +- .../knowledge_base/entries/find_route.ts | 8 +- .../get_knowledge_base_status.test.ts | 2 + .../get_knowledge_base_status.ts | 11 +- .../post_actions_connector_execute.test.ts | 13 +- .../routes/post_actions_connector_execute.ts | 22 +- .../routes/prompts/bulk_actions_route.ts | 27 +- .../server/routes/prompts/find_route.test.ts | 14 +- .../server/routes/prompts/find_route.ts | 17 +- .../server/routes/request_context_factory.ts | 5 + .../append_conversation_messages_route.ts | 24 +- .../user_conversations/bulk_actions_route.ts | 24 +- .../routes/user_conversations/create_route.ts | 6 +- .../routes/user_conversations/delete_route.ts | 25 +- .../user_conversations/find_route.test.ts | 7 +- .../routes/user_conversations/find_route.ts | 19 +- .../routes/user_conversations/read_route.ts | 24 +- .../routes/user_conversations/update_route.ts | 8 +- .../plugins/elastic_assistant/tsconfig.json | 3 +- .../enterprise_search/common/constants.ts | 67 +- .../__mocks__/kea_logic/kibana_logic.mock.ts | 1 + .../api_logs/components/empty_state.tsx | 4 +- .../crawler/components/crawl_rules_table.tsx | 4 +- .../deduplication_panel.tsx | 4 +- .../crawler/components/entry_points_table.tsx | 4 +- .../automatic_crawl_scheduler.tsx | 4 +- .../components/crawler/crawler_overview.tsx | 6 +- .../components/credentials/constants.ts | 4 - .../form_components/key_type.tsx | 6 +- .../credentials_list/credentials_list.tsx | 4 +- .../curations/components/empty_state.tsx | 4 +- .../api_code_example.tsx | 6 +- .../document_creation_buttons.tsx | 5 +- .../documents/components/empty_state.tsx | 4 +- .../engine_overview/engine_overview_empty.tsx | 4 +- .../components/empty_meta_engines_state.tsx | 4 +- .../meta_engine_creation/constants.tsx | 4 +- .../components/empty_state.tsx | 4 +- .../precision_slider/precision_slider.tsx | 8 +- .../relevance_tuning_callouts.tsx | 5 +- .../components/empty_state.tsx | 4 +- .../role_mappings/role_mappings.tsx | 6 +- .../schema/components/empty_state.tsx | 9 +- .../search_ui/components/empty_state.tsx | 4 +- .../components/search_ui/search_ui.tsx | 4 +- .../log_retention/log_retention_panel.tsx | 4 +- .../synonyms/components/empty_state.tsx | 4 +- .../public/applications/app_search/routes.ts | 24 - .../components/playground/page_template.tsx | 71 + .../components/playground/playground.tsx | 8 +- .../elasticsearch_guide.tsx | 2 +- .../components/layout/page_template.tsx | 3 +- .../components/manual_configuration.tsx | 143 +- .../create_connector/configuration_step.tsx | 7 +- .../create_connector/create_connector.tsx | 47 +- .../create_connector/start_step.tsx | 98 +- .../method_connector/new_connector_logic.ts | 10 + .../public/applications/index.tsx | 1 + .../shared/kibana/kibana_logic.ts | 3 + .../kibana_chrome/generate_breadcrumbs.ts | 28 +- .../shared/kibana_chrome/generate_title.ts | 17 +- .../shared/kibana_chrome/set_chrome.tsx | 25 +- .../applications/shared/layout/base_nav.tsx | 201 ++ .../shared/layout/classic_nav_helpers.test.ts | 189 + .../shared/layout/classic_nav_helpers.ts | 102 + .../applications/shared/layout/nav.test.tsx | 190 +- .../public/applications/shared/layout/nav.tsx | 256 +- .../shared/layout/nav_link_helpers.test.ts | 1 + .../shared/layout/nav_link_helpers.ts | 22 +- .../react_router_helpers/create_href.ts | 11 +- .../react_router_helpers/eui_components.tsx | 4 +- .../generate_react_router_props.test.ts | 2 + .../generate_react_router_props.ts | 14 +- .../shared/react_router_helpers/index.ts | 1 - .../public/applications/shared/types.ts | 39 + .../test_helpers/test_utils.test_helper.tsx | 1 + .../plugins/enterprise_search/tsconfig.json | 3 +- .../public/lib/entity_client.test.ts | 139 + .../public/lib/entity_client.ts | 40 + .../server/lib/entity_client.ts | 4 +- .../import_complete_view.test.tsx.snap | 4 +- .../components/import_complete_view.tsx | 2 +- .../plugins/fleet/common/constants/routes.ts | 4 - .../common/services/agent_policies_helpers.ts | 8 + .../fleet/common/types/rest_spec/agent.ts | 16 +- x-pack/plugins/fleet/kibana.jsonc | 4 +- .../hooks/use_quick_start_form.ts | 46 +- .../agent_policy/components/actions_menu.tsx | 11 +- .../agent_policy_advanced_fields/index.tsx | 2 +- .../hooks/setup_technology.test.ts | 25 +- .../single_page_layout/index.tsx | 4 +- .../components/settings/index.tsx | 4 +- .../edit_package_policy_page/index.tsx | 4 +- .../components/agents_selection_status.tsx | 50 +- .../components/bulk_actions.tsx | 2 +- .../components/table_header.tsx | 3 + .../hooks/use_fetch_agents_data.tsx | 21 +- .../sections/agents/agent_list_page/index.tsx | 1 + .../public/mock/create_test_renderer.tsx | 12 +- x-pack/plugins/fleet/server/config.ts | 114 +- x-pack/plugins/fleet/server/mocks/index.ts | 17 +- .../fleet/server/routes/agent/handlers.ts | 30 +- .../fleet/server/routes/agent/index.test.ts | 2 - .../fleet/server/routes/agent/index.ts | 35 - .../server/routes/agent_policy/handlers.ts | 2 + .../plugins/fleet/server/routes/app/index.ts | 18 - .../server/services/agent_policy.test.ts | 62 + .../fleet/server/services/agent_policy.ts | 27 +- .../server/services/agent_policy_create.ts | 15 +- .../server/services/package_policy.test.ts | 103 +- .../fleet/server/services/package_policy.ts | 201 +- .../server/services/package_policy_service.ts | 52 +- .../services/spaces/agent_policy.test.ts | 153 + .../server/services/spaces/agent_policy.ts | 41 +- .../server/services/spaces/package_policy.ts | 41 + .../plugins/fleet/server/types/extensions.ts | 23 +- .../fleet/server/types/rest_spec/agent.ts | 22 - .../public/components/search_bar.tsx | 51 +- .../public/telemetry/telemetry.test.tsx | 4 +- .../home/data_streams_tab.helpers.ts | 1 + .../home/data_streams_tab.test.ts | 62 +- .../common/lib/template_serialization.ts | 4 +- .../common/types/data_streams.ts | 4 + .../index_management/common/types/indices.ts | 33 +- .../components/mappings_editor/lib/utils.ts | 6 +- .../mappings_editor/use_state_listener.tsx | 4 +- .../template_form/steps/step_review.tsx | 14 + .../application/lib/data_streams.test.tsx | 34 +- .../public/application/lib/data_streams.tsx | 16 + .../application/lib/index_mode_labels.ts | 29 + .../data_stream_detail_panel.tsx | 13 + .../data_stream_table/data_stream_table.tsx | 11 + .../edit_data_retention_modal.tsx | 10 +- .../validations.test.ts | 20 + .../edit_data_retention_modal/validations.ts | 43 +- .../index_table/index_table_pagination.tsx | 4 +- .../template_details/tabs/tab_summary.tsx | 13 + .../server/lib/data_stream_serialization.ts | 3 + .../api/data_streams/register_get_route.ts | 30 + .../inference/common/chat_complete/index.ts | 99 - .../is_chat_completion_chunk_event.ts | 14 - .../chat_complete/is_chat_completion_event.ts | 17 - .../is_chat_completion_message_event.ts | 15 - .../chat_complete/without_chunk_events.ts | 19 - .../without_token_count_events.ts | 19 - x-pack/plugins/inference/common/connectors.ts | 4 - .../common/{output => }/create_output_api.ts | 14 +- .../request.ts => http_apis.ts} | 8 +- x-pack/plugins/inference/common/index.ts | 20 +- .../plugins/inference/common/output/index.ts | 81 - .../common/output/is_output_complete_event.ts | 14 - .../common/output/is_output_event.ts | 15 - .../output/without_output_update_events.ts | 18 - .../nl_to_esql/correct_query_with_actions.ts | 1 + .../common/{ => utils}/ensure_multi_turn.ts | 2 +- .../generate_fake_tool_call_id.ts | 0 .../common/{util => utils}/truncate_list.ts | 0 .../index.ts => chat_complete.ts} | 6 +- x-pack/plugins/inference/public/index.ts | 4 +- x-pack/plugins/inference/public/plugin.tsx | 7 +- x-pack/plugins/inference/public/types.ts | 4 +- .../create_observable_from_http_response.ts | 3 +- .../http_response_into_observable.test.ts | 8 +- .../util/http_response_into_observable.ts | 5 +- .../scripts/evaluation/evaluation_client.ts | 3 +- .../evaluation/scenarios/esql/index.spec.ts | 5 +- .../load_esql_docs/utils/output_executor.ts | 2 +- .../inference/scripts/util/cli_options.ts | 1 + .../inference/scripts/util/kibana_client.ts | 17 +- .../bedrock/bedrock_claude_adapter.test.ts | 3 +- .../bedrock/bedrock_claude_adapter.ts | 12 +- .../bedrock/process_completion_chunks.ts | 2 +- .../serde_eventstream_into_observable.ts | 2 +- .../adapters/gemini/gemini_adapter.test.ts | 3 +- .../adapters/gemini/gemini_adapter.ts | 11 +- .../gemini/process_vertex_stream.test.ts | 2 +- .../adapters/gemini/process_vertex_stream.ts | 2 +- .../adapters/openai/openai_adapter.test.ts | 2 +- .../adapters/openai/openai_adapter.ts | 8 +- .../inference/server/chat_complete/api.ts | 7 +- .../inference/server/chat_complete/errors.ts | 51 + .../get_system_instructions.ts | 2 +- .../parse_inline_function_calls.ts | 4 +- .../wrap_with_simulated_function_calling.ts | 13 +- .../inference/server/chat_complete/types.ts | 4 +- .../utils/chunks_into_message.test.ts | 5 +- .../utils/chunks_into_message.ts | 7 +- x-pack/plugins/inference/server/index.ts | 11 +- .../server/inference_client/index.ts | 2 +- .../inference/server/routes/chat_complete.ts | 5 +- .../tasks/nl_to_esql/actions/generate_esql.ts | 16 +- .../actions/request_documentation.ts | 12 +- .../server/tasks/nl_to_esql/actions/shared.ts | 2 +- .../inference/server/tasks/nl_to_esql/task.ts | 3 +- .../server/tasks/nl_to_esql/types.ts | 6 +- x-pack/plugins/inference/server/types.ts | 3 +- .../server/util/get_connector_by_id.ts | 2 +- ...bservable_into_event_source_stream.test.ts | 2 +- .../observable_into_event_source_stream.ts | 4 +- .../server/util/validate_tool_calls.test.ts | 3 +- .../server/util/validate_tool_calls.ts | 7 +- x-pack/plugins/inference/tsconfig.json | 2 +- .../job_selector/use_job_selection.ts | 22 +- .../data_frame_analytics/_index.scss | 4 +- .../_classification_exploration.scss | 47 - .../classification_exploration.tsx | 26 +- .../evaluate_panel.tsx | 382 +- .../evaluate_stat.tsx | 43 +- .../data_view_prompt/data_view_prompt.tsx | 58 +- .../expandable_section.scss | 13 - .../expandable_section/expandable_section.tsx | 116 +- .../expandable_section_results.tsx | 10 +- .../expandable_section_splom.tsx | 10 +- .../regression_exploration/_index.scss | 1 - .../_regression_exploration.scss | 3 - .../regression_exploration/evaluate_stat.tsx | 43 +- .../expanded_row_details_pane.scss | 8 - .../expanded_row_details_pane.tsx | 25 +- .../create_analytics_button/_index.scss | 4 - .../_time_range_selector.scss | 61 - .../time_range_selector.js | 6 +- .../time_range_selector_wrapper.tsx | 78 + .../components/split_cards/split_cards.tsx | 36 +- .../components/split_cards/style.scss | 4 - .../model_management/models_list.tsx | 18 + .../services/ml_api_service/index.ts | 36 +- .../timeseries_chart/timeseries_chart.js | 2 - .../apm/common/es_fields/entities.ts | 12 - .../apm/docs/openapi/apm.yaml | 186 - .../apm/docs/openapi/apm/README.md | 26 +- .../apm/docs/openapi/apm/bundled.json | 1827 ++++++++++ .../apm/docs/openapi/apm/bundled.yaml | 1162 ++++++ .../apm/docs/openapi/apm/components/README.md | 7 + .../headers/elastic_api_version.yaml | 9 + .../apm/components/headers/kbn_xsrf.yaml | 7 + .../apm/components/schemas/400_response.yaml | 14 + .../apm/components/schemas/401_response.yaml | 13 + .../apm/components/schemas/403_response.yaml | 13 + .../apm/components/schemas/404_response.yaml | 14 + .../apm/components/schemas/500_response.yaml | 13 + .../apm/components/schemas/501_response.yaml | 14 + .../agent_configuration_intake_object.yaml | 12 + .../schemas/agent_configuration_object.yaml | 27 + .../agent_configurations_response.yaml | 7 + .../components/schemas/agent_keys_object.yaml | 16 + .../schemas/agent_keys_response.yaml | 22 + .../schemas/annotation_search_response.yaml | 18 + .../schemas/base_source_map_object.yaml | 38 + .../schemas/create_annotation_object.yaml | 26 + .../schemas/create_annotation_response.yaml | 41 + .../delete_agent_configurations_response.yaml | 5 + .../search_agent_configuration_object.yaml | 15 + .../search_agent_configuration_response.yaml | 13 + .../schemas/service_agent_name_response.yaml | 6 + .../schemas/service_environment_object.yaml | 9 + .../service_environments_response.yaml | 7 + .../components/schemas/service_object.yaml | 11 + .../components/schemas/settings_object.yaml | 4 + .../single_agent_configuration_response.yaml | 8 + .../schemas/source_maps_response.yaml | 38 + .../schemas/upload_source_map_object.yaml | 22 + .../schemas/upload_source_maps_response.yaml | 6 + .../apm/docs/openapi/apm/entrypoint.yaml | 42 + .../apm/docs/openapi/apm/paths/README.md | 10 + .../openapi/apm/paths/api@apm@agent_keys.yaml | 46 + .../api@apm@fleet@apm_server_schema.yaml | 53 + ...pm@services@{service_name}@annotation.yaml | 52 + ...ices@{service_name}@annotation@search.yaml | 57 + .../api@apm@settings@agent_configuration.yaml | 128 + ...ttings@agent_configuration@agent_name.yaml | 40 + ...ings@agent_configuration@environments.yaml | 37 + ...m@settings@agent_configuration@search.yaml | 41 + ...apm@settings@agent_configuration@view.yaml | 44 + .../openapi/apm/paths/api@apm@sourcemaps.yaml | 101 + .../apm/paths/api@apm@sourcemaps@{id}.yaml | 53 + .../service_dashboards/empty_dashboards.tsx | 2 +- .../public/context/breadcrumbs/context.tsx | 2 +- .../context/breadcrumbs/use_breadcrumb.ts | 15 +- .../public/hooks/use_redirect_link.ts | 16 +- .../embeddable/embeddable.tsx | 3 + .../shared/exploratory_view/index.tsx | 2 +- .../infra/public/apps/logs_app.tsx | 31 +- .../asset_details/hooks/use_entity_summary.ts | 4 +- .../tabs/processes/processes.tsx | 4 +- .../asset_details/template/page.tsx | 21 +- .../components/logs_deprecation_callout.tsx | 26 +- .../ml/anomaly_detection/job_setup_screen.tsx | 59 +- .../infra/public/hooks/use_breadcrumbs.ts | 42 - .../public/hooks/use_logs_breadcrumbs.tsx | 12 +- .../public/hooks/use_metrics_breadcrumbs.tsx | 35 +- .../infra/public/pages/metrics/index.tsx | 6 +- .../inventory_view/components/waffle/node.tsx | 6 +- .../pages/metrics/metric_detail/index.tsx | 7 +- .../metric_detail/metric_detail_page.tsx | 21 +- .../settings/features_configuration_panel.tsx | 14 - .../source_configuration_settings.tsx | 4 - .../infra/public/plugin.ts | 194 +- .../telemetry/telemetry_client.mock.ts | 4 + .../services/telemetry/telemetry_client.ts | 35 + .../services/telemetry/telemetry_events.ts | 96 + .../telemetry/telemetry_service.test.ts | 108 + .../infra/public/services/telemetry/types.ts | 52 +- .../infra/public/translations.ts | 2 +- ...nventory_metric_threshold_executor.test.ts | 19 +- .../infra/server/routes/entities/index.ts | 6 +- .../server/services/rules/rules_service.ts | 8 +- .../infra/server/services/rules/types.ts | 9 +- .../inventory/common/entities.ts | 57 +- ...parse_identity_field_values_to_kql.test.ts | 91 - .../parse_identity_field_values_to_kql.ts | 34 - .../common/utils/unflatten_entity.ts | 13 + .../inventory/e2e/cypress/e2e/home.cy.ts | 71 +- .../alerts_badge/alerts_badge.test.tsx | 44 +- .../components/alerts_badge/alerts_badge.tsx | 7 +- .../entity_name/entity_name.test.tsx | 175 +- .../entities_grid/entity_name/index.tsx | 77 +- .../public/components/entity_icon/index.tsx | 11 +- .../grouped_inventory/group_selector.test.tsx | 45 + .../grouped_inventory/group_selector.tsx | 112 + .../grouped_entities_grid.tsx | 130 + .../components/grouped_inventory/index.tsx | 68 + .../inventory_group_accordion.test.tsx | 34 + .../inventory_group_accordion.tsx | 87 + .../inventory_panel_badge.tsx | 31 + .../inventory_summary.test.tsx | 43 + .../grouped_inventory/inventory_summary.tsx | 69 + .../mock/inventory_component_wrapper_mock.tsx | 38 + .../grouped_inventory/unified_inventory.tsx | 131 + .../public/components/search_bar/index.tsx | 11 +- .../index.tsx | 7 +- .../hooks/use_detail_view_redirect.test.ts | 170 + .../public/hooks/use_detail_view_redirect.ts | 114 + .../public/pages/inventory_page/index.tsx | 105 +- .../inventory/public/routes/config.tsx | 13 +- .../routes/entities/get_entity_groups.ts | 58 + .../entities/get_identify_fields.test.ts | 2 +- .../routes/entities/get_latest_entities.ts | 2 +- .../inventory/server/routes/entities/route.ts | 41 + .../server/routes/has_data/get_has_data.ts | 1 - .../inventory/tsconfig.json | 5 +- .../server/lib/get_sample_documents.ts | 2 +- .../observability/common/index.ts | 2 - .../observability/common/ui_settings_keys.ts | 3 - .../observability/public/index.ts | 2 - .../pages/alert_details/alert_details.tsx | 32 +- .../public/pages/alerts/alerts.tsx | 17 +- .../public/pages/overview/overview.tsx | 17 +- .../pages/rule_details/rule_details.tsx | 40 +- .../public/pages/rules/rules.tsx | 32 +- .../observability/server/ui_settings.ts | 27 - .../common/types.ts | 2 +- .../public/analytics/index.ts | 6 +- .../public/analytics/schemas/common.ts | 12 +- .../public/components/insight/insight.tsx | 1 + .../public/service/create_service.ts | 18 +- .../public/types.ts | 12 +- .../server/routes/functions/route.ts | 2 +- .../chat_function_client/index.test.ts | 52 +- .../service/chat_function_client/index.ts | 28 +- .../server/service/client/index.test.ts | 2 + .../server/service/client/index.ts | 7 +- .../client/operators/continue_conversation.ts | 7 +- .../server/service/types.ts | 3 + .../get_system_message_from_instructions.ts | 2 +- .../observability_ai_assistant/tsconfig.json | 3 +- .../common/convert_messages_for_inference.ts | 4 +- .../public/components/nav_control/index.tsx | 6 +- .../server/functions/query/index.ts | 7 +- .../server/rule_connector/index.test.ts | 1 + .../server/rule_connector/index.ts | 2 +- .../tsconfig.json | 1 + .../public/routes/main/main_route.tsx | 17 +- .../public/utils/breadcrumbs.tsx | 80 +- .../observability_logs_explorer/tsconfig.json | 1 - .../onboarding_flow_form.tsx | 55 +- .../use_custom_cards_for_category.tsx | 15 +- .../public/application/pages/auto_detect.tsx | 1 - .../public/application/pages/kubernetes.tsx | 1 - .../auto_detect/auto_detect_panel.tsx | 193 +- .../otel_kubernetes/otel_kubernetes_panel.tsx | 52 +- .../quickstart_flows/otel_logs/index.tsx | 23 +- .../public/assets/auto_detect.sh | 10 +- .../server/routes/flow/route.ts | 86 +- .../server/routes/logs/route.ts | 7 + .../server/routes/types.ts | 43 +- .../observability_onboarding_status.ts | 7 + .../common/entity/entity_types.ts | 26 +- .../common/entity/index.ts | 2 +- .../observability_shared/common/index.ts | 3 +- .../locators/apm/service_overview_locator.ts | 3 +- .../public/hooks/use_breadcrumbs.test.tsx | 52 +- .../public/hooks/use_breadcrumbs.ts | 74 +- .../slo/overview/slo_overview_grid.tsx | 24 +- .../public/hooks/use_fetch_active_alerts.ts | 4 +- .../public/pages/slo_details/slo_details.tsx | 3 +- .../components/common/query_search_bar.tsx | 20 +- .../slo/public/pages/slo_edit/slo_edit.tsx | 56 +- .../pages/slo_outdated_definitions/index.tsx | 32 +- .../pages/slo_settings/slo_settings.tsx | 20 +- .../card_view/slo_card_item_badges.tsx | 9 +- .../slo/public/pages/slos/slos.tsx | 22 +- .../synthetics/common/field_names.ts | 1 + .../common/requests/get_certs_request_body.ts | 3 +- .../common/rules/synthetics_rule_field_map.ts | 4 + .../synthetics/common/runtime_types/certs.ts | 1 + .../hooks/use_get_data_stream_statuses.ts | 1 + .../contexts/synthetics_settings_context.tsx | 4 - .../contexts/synthetics_shared_context.tsx | 1 + .../synthetics/hooks/use_breadcrumbs.test.tsx | 14 +- .../apps/synthetics/hooks/use_breadcrumbs.ts | 77 +- .../public/apps/synthetics/render_app.tsx | 1 - .../synthetics/utils/testing/rtl_helpers.tsx | 7 +- .../alert_rules/status_rule/message_utils.ts | 7 +- .../server/alert_rules/status_rule/types.ts | 1 + .../alert_rules/tls_rule/message_utils.ts | 4 + .../server/alert_rules/translations.ts | 9 + .../add_monitor/add_monitor_api.ts | 8 +- .../monitor_cruds/add_monitor_project.ts | 5 +- .../bulk_cruds/add_monitor_bulk.ts | 22 +- .../bulk_cruds/delete_monitor_bulk.ts | 24 +- .../routes/monitor_cruds/delete_monitor.ts | 207 +- .../monitor_cruds/delete_monitor_project.ts | 10 +- .../saved_object_to_monitor.test.ts | 94 +- .../formatters/saved_object_to_monitor.ts | 78 +- .../services/delete_monitor_api.ts | 122 + .../services/validate_space_id.ts | 21 + .../synthetics/tsconfig.json | 3 +- .../common/rules/uptime_rule_field_map.ts | 4 + .../public/application/application.test.tsx | 6 + .../observability_solution/ux/tsconfig.json | 3 +- .../all/alerts_automated_action_results.cy.ts | 3 +- .../cypress/e2e/all/alerts_cases.cy.ts | 6 +- .../cypress/e2e/all/alerts_linked_apps.cy.ts | 4 +- .../e2e/all/alerts_multiple_agents.cy.ts | 3 +- .../cypress/e2e/all/ecs_mappings.cy.ts | 3 +- .../cypress/e2e/roles/alert_test.cy.ts | 6 +- .../osquery/cypress/tasks/api_fixtures.ts | 2 +- .../osquery/cypress/tasks/live_query.ts | 3 +- .../fleet_wrapper/get_agent_policies.ts | 2 +- x-pack/plugins/rule_registry/server/index.ts | 7 - x-pack/plugins/rule_registry/server/mocks.ts | 2 - x-pack/plugins/rule_registry/server/plugin.ts | 3 - .../utils/create_lifecycle_executor.test.ts | 2408 ------------- .../server/utils/create_lifecycle_executor.ts | 479 --- .../create_lifecycle_rule_executor_mock.ts | 38 - .../utils/create_lifecycle_rule_type.test.ts | 512 --- .../create_lifecycle_rule_type_factory.ts | 45 - .../get_updated_flapping_history.test.ts | 207 -- .../utils/get_updated_flapping_history.ts | 64 - .../utils/lifecycle_alert_services.mock.ts | 41 - x-pack/plugins/rule_registry/tsconfig.json | 1 - .../search_indices/public/constants.ts | 1 + .../public/hooks/api/use_index_mappings.ts | 6 +- .../summarization_model.tsx | 4 +- .../session/session_expiration_toast.test.tsx | 19 +- .../session/session_expiration_toast.tsx | 2 +- .../routes/authorization/roles/delete.ts | 5 + .../server/routes/authorization/roles/get.ts | 23 +- .../routes/authorization/roles/get_all.ts | 16 +- .../roles/get_all_by_space.test.ts | 2 +- .../authorization/roles/get_all_by_space.ts | 6 +- .../authorization/roles/model/put_payload.ts | 19 +- .../server/routes/authorization/roles/post.ts | 5 + .../server/routes/authorization/roles/put.ts | 22 +- .../session_management/invalidate.test.ts | 3 +- .../routes/session_management/invalidate.ts | 7 +- .../routes/user_profile/bulk_get.test.ts | 2 +- .../server/routes/user_profile/bulk_get.ts | 6 +- .../entity_store/common.gen.ts | 1 + .../entity_store/common.schema.yaml | 2 + .../timeline/get_notes/get_notes_route.gen.ts | 2 +- .../get_notes/get_notes_route.schema.yaml | 2 +- .../common/endpoint/constants.ts | 3 + .../utils/index_name_utilities.test.ts | 19 + .../endpoint/utils/index_name_utilities.ts | 34 + .../common/experimental_features.ts | 6 +- ...alytics_api_2023_10_31.bundled.schema.yaml | 2 + ...imeline_api_2023_10_31.bundled.schema.yaml | 2 +- ...alytics_api_2023_10_31.bundled.schema.yaml | 2 + ...imeline_api_2023_10_31.bundled.schema.yaml | 2 +- .../top_values_popover/top_values_popover.tsx | 4 +- ...isconfiguration_findings_details_table.tsx | 45 +- ...vulnerabilities_findings_details_table.tsx | 60 +- .../misconfiguration_preview.tsx | 11 +- .../control_columns/row_action/index.tsx | 8 +- .../events_tab/events_query_tab_body.test.tsx | 35 +- .../events_tab/events_query_tab_body.tsx | 6 +- .../common/components/events_viewer/index.tsx | 9 +- .../components/header_actions/actions.tsx | 12 +- .../markdown_editor/plugins/insight/index.tsx | 6 +- .../plugins/insight/use_insight_query.ts | 6 +- .../common/components/top_n/index.test.tsx | 4 +- .../public/common/components/top_n/index.tsx | 8 +- .../common/components/top_n/top_n.test.tsx | 4 +- .../public/common/components/top_n/top_n.tsx | 7 +- .../alerts/alerts_by_status_donut.test.ts | 1 + .../common/alerts/alerts_histogram.test.ts | 1 + .../common/alerts/alerts_table.test.ts | 1 + .../common/alerts/rule_preview.test.ts | 1 + .../common/authentication.test.ts | 1 + .../lens_attributes/common/event.test.ts | 1 + .../common/external_alert.test.ts | 1 + .../hosts/kpi_host_area.test.ts | 1 + .../hosts/kpi_host_metric.test.ts | 1 + .../hosts/kpi_unique_ips_area.test.ts | 1 + .../hosts/kpi_unique_ips_bar.test.ts | 1 + .../kpi_unique_ips_destination_metric.test.ts | 1 + .../kpi_unique_ips_source_metric.test.ts | 1 + .../network/dns_top_domains.test.ts | 1 + .../network/kpi_dns_queries.test.ts | 1 + .../network/kpi_network_events.test.ts | 1 + .../network/kpi_tls_handshakes.test.ts | 1 + .../network/kpi_unique_flow_ids.test.ts | 1 + .../kpi_unique_private_ips_area.test.ts | 1 + .../kpi_unique_private_ips_bar.test.ts | 1 + ...que_private_ips_destination_metric.test.ts | 1 + ...i_unique_private_ips_source_metric.test.ts | 1 + .../users/kpi_total_users_area.test.ts | 1 + .../users/kpi_total_users_metric.test.ts | 1 + ...user_authentication_metric_failure.test.ts | 1 + .../kpi_user_authentications_area.test.ts | 1 + .../kpi_user_authentications_bar.test.ts | 1 + ...ser_authentications_metric_success.test.ts | 1 + .../use_lens_attributes.test.tsx | 5 + .../public/common/lib/kuery/index.test.ts | 6 +- .../public/common/lib/kuery/index.ts | 17 +- .../public/common/lib/telemetry/constants.ts | 2 + .../events/entity_analytics/index.ts | 33 + .../events/entity_analytics/types.ts | 21 +- .../lib/telemetry/events/telemetry_events.ts | 4 + .../lib/telemetry/telemetry_client.mock.ts | 2 + .../common/lib/telemetry/telemetry_client.ts | 10 + .../public/common/lib/telemetry/types.ts | 17 +- .../public/common/mock/global_state.ts | 2 +- .../public/common/mock/index_pattern.ts | 5 + .../logic/esql_validator.test.ts | 22 +- .../rule_creation/logic/esql_validator.ts | 2 +- .../data_view_selector/index.test.tsx | 84 - .../components/data_view_selector/index.tsx | 152 - .../__mocks__/use_data_views.ts | 11 + .../data_view_selector_field.test.tsx | 114 + .../data_view_selector_field.tsx | 95 + .../data_view_selector_field}/index.ts | 2 +- .../translations.tsx | 9 +- .../use_data_views.ts | 45 + .../components/rule_preview/index.tsx | 9 +- .../step_define_rule/index.test.tsx | 100 +- .../components/step_define_rule/index.tsx | 26 +- .../components/step_define_rule/schema.tsx | 49 +- .../rule_creation_ui/pages/form.tsx | 2 +- .../pages/rule_creation/index.tsx | 25 +- .../pages/rule_editing/index.tsx | 24 +- .../data_view_id_validator_factory.ts | 31 + .../index_pattern_validator_factory.ts | 21 + .../execution_log_table.test.tsx | 2 +- .../execution_log_table.tsx | 36 +- .../pages/rule_details/index.tsx | 2 +- .../rule_details/rule_definition_section.tsx | 2 +- .../final_edit/common_rule_field_edit.tsx | 4 +- .../custom_query_rule_field_edit.tsx | 20 +- .../final_edit/eql_rule_field_edit.tsx | 23 + .../fields/data_source/data_source_edit.tsx | 71 + .../data_source/data_source_edit_form.tsx | 104 + .../data_source/data_source_info_text.tsx | 36 + .../data_source_type_selector_field.tsx | 68 + .../fields/data_source/data_view_field.tsx | 18 + .../final_edit/fields/data_source/index.ts | 8 + .../fields/data_source/index_pattern_edit.tsx | 57 + .../fields/data_source/translations.tsx | 15 + .../final_edit/fields/kql_query.tsx | 239 -- .../final_edit/fields/kql_query/index.ts | 8 + .../fields/kql_query/kql_query_edit.tsx | 139 + .../fields/kql_query/kql_query_edit_form.tsx | 118 + .../fields/rule_field_edit_component_props.ts | 22 + .../rule_field_edit_form_wrapper.tsx} | 69 +- .../three_way_diff/final_edit/final_edit.tsx | 4 +- .../final_edit/new_terms_rule_field_edit.tsx | 20 +- .../saved_query_rule_field_edit.tsx | 20 +- .../threat_match_rule_field_edit.tsx | 20 +- .../final_edit/threshold_rule_field_edit.tsx | 20 +- .../use_default_index_pattern.tsx | 16 +- .../use_prebuilt_rules_upgrade_state.ts | 17 +- .../alerts_kpis/chart_panels/index.test.tsx | 1 + .../alerts_table/alerts_grouping.test.tsx | 1 + .../alerts_table/alerts_grouping.tsx | 8 +- .../alerts_table/alerts_sub_grouping.tsx | 8 +- .../components/alerts_table/index.tsx | 16 +- .../use_add_bulk_to_timeline.tsx | 7 +- .../detection_engine_filters.test.tsx | 4 +- .../detection_engine_filters.tsx | 9 +- .../render_cell_value.test.tsx | 1 + .../rules/use_rule_from_timeline.test.ts | 1 + .../use_actions_column.tsx | 6 +- .../use_persistent_controls.test.tsx | 1 + .../use_persistent_controls.tsx | 8 +- .../detection_engine.test.tsx | 5 +- .../detection_engine/detection_engine.tsx | 16 +- .../entity_analytics/api/entity_store.ts | 3 +- .../api/hooks/use_preview_risk_scores.ts | 60 +- .../components/result_step.tsx | 17 +- .../components/dashboard_panels.tsx | 120 +- .../entity_store/entities_list.test.tsx | 38 +- .../components/entity_store/entities_list.tsx | 7 +- .../hooks/use_entity_engine_status.ts | 13 + .../entity_store/hooks/use_entity_store.ts | 43 +- .../components/entity_store/translations.ts | 2 +- .../components/risk_score_preview_section.tsx | 41 +- .../index.tsx | 2 +- .../lens_attributes/risk_score_donut.test.ts | 1 + .../risk_score_over_time_area.test.ts | 1 + .../risk_score_summary.test.ts | 1 + .../pages/entity_store_management_page.tsx | 2 +- .../hosts/pages/details/details_tabs.test.tsx | 41 +- .../hosts/pages/details/details_tabs.tsx | 2 +- .../explore/hosts/pages/details/index.tsx | 10 +- .../explore/hosts/pages/details/types.ts | 5 +- .../public/explore/hosts/pages/hosts.tsx | 11 +- .../network/pages/details/index.test.tsx | 4 + .../explore/network/pages/details/index.tsx | 12 +- .../pages/navigation/network_routes.tsx | 9 +- .../explore/network/pages/navigation/types.ts | 5 +- .../explore/network/pages/network.test.tsx | 1 + .../public/explore/network/pages/network.tsx | 11 +- .../explore/users/pages/details/index.tsx | 10 +- .../explore/users/pages/details/types.ts | 5 +- .../public/explore/users/pages/users.tsx | 11 +- .../left/components/entities_details.test.tsx | 4 +- .../left/components/host_details.test.tsx | 4 +- .../left/components/session_view.test.tsx | 3 +- .../left/components/user_details.test.tsx | 4 +- .../use_threat_intelligence_details.test.ts | 3 +- .../hooks/use_threat_intelligence_details.ts | 2 +- .../flyout/document_details/left/index.tsx | 8 +- .../components/alert_header_title.test.tsx | 2 +- .../right/components/alert_header_title.tsx | 52 +- .../components/correlations_overview.test.tsx | 60 +- .../components/correlations_overview.tsx | 2 +- .../insights_summary_row.stories.tsx | 77 - .../components/insights_summary_row.test.tsx | 127 +- .../right/components/insights_summary_row.tsx | 135 +- .../components/prevalence_overview.test.tsx | 34 +- .../right/components/prevalence_overview.tsx | 22 +- .../related_alerts_by_ancestry.test.tsx | 76 +- .../components/related_alerts_by_ancestry.tsx | 25 +- ...lated_alerts_by_same_source_event.test.tsx | 83 +- .../related_alerts_by_same_source_event.tsx | 29 +- .../related_alerts_by_session.test.tsx | 76 +- .../components/related_alerts_by_session.tsx | 25 +- .../right/components/related_cases.test.tsx | 76 +- .../right/components/related_cases.tsx | 31 +- .../components/suppressed_alerts.test.tsx | 81 +- .../right/components/suppressed_alerts.tsx | 30 +- .../right/components/test_ids.ts | 7 +- .../threat_intelligence_overview.test.tsx | 190 +- .../threat_intelligence_overview.tsx | 81 +- .../shared/hooks/use_event_details.test.tsx | 3 +- .../shared/hooks/use_event_details.ts | 8 +- .../components/network_details.tsx | 4 +- .../public/kubernetes/pages/index.tsx | 9 +- .../utils/data_view_spec_to_index_pattern.ts | 15 + .../e2e/artifacts/artifacts_mocked_data.cy.ts | 3 +- .../cypress/e2e/artifacts/blocklist.cy.ts | 2 +- .../cypress/e2e/artifacts/event_filters.cy.ts | 3 +- .../automated_response_actions.cy.ts | 91 +- .../plugin_handlers/endpoint_data_loader.ts | 44 +- .../management/cypress/tasks/api_fixtures.ts | 2 +- .../public/management/cypress/tasks/fleet.ts | 8 +- .../public/management/cypress/tsconfig.json | 1 + .../public/management/links.ts | 5 +- .../public/management/pages/index.tsx | 6 +- .../pages/policy/view/policy_details.test.tsx | 2 +- .../pages/policy/view/policy_details.tsx | 2 +- .../security_solution/public/notes/api/api.ts | 6 +- ...sx => created_by_filter_dropdown.test.tsx} | 25 +- ...own.tsx => created_by_filter_dropdown.tsx} | 39 +- .../notes/components/search_row.test.tsx | 8 +- .../public/notes/components/search_row.tsx | 4 +- .../public/notes/components/test_ids.ts | 2 +- .../public/notes/components/utility_bar.tsx | 14 +- .../notes/hooks/use_fetch_notes.test.ts | 12 +- .../public/notes/hooks/use_fetch_notes.ts | 8 +- .../security_solution/public/notes/links.ts | 2 +- .../notes/pages/note_management_page.tsx | 14 +- .../public/notes/store/notes.slice.test.ts | 18 +- .../public/notes/store/notes.slice.ts | 22 +- .../cards/alerts/alerts_card.tsx | 20 +- .../cards/assistant/assistant_card.tsx | 99 +- .../assistant/assistant_check_complete.ts | 7 +- .../assistant/connectors/connector_cards.tsx | 119 +- .../connectors/create_connector_popover.tsx | 15 +- .../connectors/missing_privileges_tooltip.tsx | 41 + .../assistant/connectors/translations.ts | 43 + .../onboarding_body/cards/assistant/index.ts | 2 +- .../cards/assistant/translations.ts | 7 + .../onboarding_body/cards/assistant/types.ts | 2 + .../common/card_content_image_panel.styles.ts | 6 +- .../cards/dashboards/dashboards_card.tsx | 20 +- .../cards/rules/rules_card.tsx | 20 +- .../components/onboarding_footer/constants.ts | 1 - .../onboarding_footer/footer_items.ts | 142 +- .../onboarding_footer/images/demo_dark.png | Bin 0 -> 11618 bytes .../images/documentation_dark.png | Bin 0 -> 12021 bytes .../onboarding_footer/images/forum_dark.png | Bin 0 -> 9991 bytes .../onboarding_footer/images/labs_dark.png | Bin 0 -> 16924 bytes .../onboarding_footer/onboarding_footer.tsx | 3 +- .../components/event_counts/index.test.tsx | 4 +- .../components/event_counts/index.tsx | 16 +- .../components/events_by_dataset/index.tsx | 11 +- .../public/overview/pages/overview.tsx | 7 +- .../components/alerts_sourcerer.test.tsx | 1 + .../public/sourcerer/components/index.tsx | 4 +- .../components/sourcerer_integration.test.tsx | 1 + .../components/timeline_sourcerer.test.tsx | 1 + .../use_get_sourcerer_data_view.test.ts | 4 +- .../use_get_sourcerer_data_view.tsx | 2 +- .../sourcerer/containers/hooks.test.tsx | 7 +- .../public/sourcerer/containers/index.tsx | 4 +- .../public/sourcerer/containers/mocks.ts | 13 - .../public/sourcerer/store/model.ts | 8 +- .../actions/open_timeline_button.test.tsx | 6 +- .../components/modal/header/index.test.tsx | 3 + .../components/modal/header/index.tsx | 14 +- .../timelines/components/notes/old_notes.tsx | 2 +- .../components/timeline/kpi/kpi_container.tsx | 6 +- .../timeline/query_bar/eql/index.tsx | 42 +- .../components/timeline/query_bar/index.tsx | 16 +- .../timeline/search_or_filter/index.tsx | 27 +- .../components/timeline/tabs/eql/index.tsx | 10 +- .../components/timeline/tabs/index.tsx | 22 +- .../timeline/tabs/notes/index.test.tsx | 4 +- .../components/timeline/tabs/notes/index.tsx | 12 +- .../components/timeline/tabs/pinned/index.tsx | 10 +- .../timeline/tabs/query/index.test.tsx | 24 +- .../components/timeline/tabs/query/index.tsx | 15 +- .../timelines/pages/timelines_page.test.tsx | 2 + .../scripts/endpoint/common/fleet_services.ts | 130 + .../assistant/tools/esql/nl_to_esql_tool.ts | 6 +- .../security_solution/server/config.mock.ts | 3 + .../security_solution/server/config.ts | 2 + .../endpoint/endpoint_app_context_services.ts | 35 +- .../clients => }/lib/simple_mem_cache.test.ts | 7 + .../clients => }/lib/simple_mem_cache.ts | 6 + ...ensure_indices_exists_for_policies.test.ts | 47 + .../ensure_indices_exists_for_policies.ts | 31 + .../server/endpoint/mocks/mocks.ts | 11 +- .../lib/base_response_actions_client.ts | 8 +- .../endpoint_fleet_services_factory.mocks.ts | 22 +- .../endpoint_fleet_services_factory.test.ts | 181 + .../fleet/endpoint_fleet_services_factory.ts | 216 +- .../fleet_integration.test.ts | 54 +- .../fleet_integration/fleet_integration.ts | 91 +- .../create_policy_datastreams.test.ts | 119 + .../handlers/create_policy_datastreams.ts | 142 + .../lib/telemetry_helpers.ts | 6 +- .../threshold/get_threshold_signal_history.ts | 3 + ..._alert_types.sh => find_alerting_rules.sh} | 7 +- .../detection_engine/scripts/find_rules.sh | 1 + ...nstances.sh => get_alerting_rule_types.sh} | 6 +- .../entity_store/auditing/actions.ts | 17 + .../entity_store/auditing/resources.ts | 18 + .../entity_store/constants.ts | 2 - .../elasticsearch_assets/ingest_pipeline.ts | 2 +- .../entity_store_data_client.test.ts | 2 + .../entity_store/entity_store_data_client.ts | 228 +- .../entity_store/routes/stop.ts | 2 +- .../saved_object/engine_descriptor.ts | 8 +- .../task/field_retention_enrichment_task.ts | 72 +- .../entity_analytics/entity_store/types.ts | 3 + .../get_united_definition.test.ts | 12 + .../get_united_definition.ts | 6 + .../united_entity_definition.ts | 15 +- .../product_features_service.test.ts | 364 +- .../product_features_service.ts | 61 +- .../server/lib/telemetry/constants.ts | 2 - .../lib/telemetry/event_based/events.ts | 67 + .../server/lib/telemetry/receiver.ts | 4 +- .../telemetry/tasks/timelines_diagnostic.ts | 5 +- .../server/lib/timeline/routes/index.ts | 10 +- .../lib/timeline/routes/notes/get_notes.ts | 48 +- .../security_solution/server/plugin.ts | 10 +- .../server/request_context_factory.ts | 2 + .../security_solution/server/routes/index.ts | 2 +- .../plugins/security_solution/tsconfig.json | 2 + x-pack/plugins/serverless/public/plugin.tsx | 2 +- x-pack/plugins/serverless/public/types.ts | 3 +- .../public/navigation_tree.ts | 17 +- .../serverless_search/public/plugin.ts | 2 +- .../components/disable_tooltip.tsx | 52 + .../policy_form/steps/step_logistics.tsx | 83 +- .../type_settings/azure_settings.tsx | 79 +- .../type_settings/gcs_settings.tsx | 79 +- .../type_settings/s3_settings.tsx | 79 +- .../plugins/spaces/common/types/space/v1.ts | 4 +- .../nav_control_popover.test.tsx.snap | 16 +- .../spaces/public/nav_control/nav_control.tsx | 16 +- .../nav_control/nav_control_popover.tsx | 11 +- .../solution_view_tour/solution_view_tour.tsx | 4 +- .../default_space/create_default_space.ts | 4 +- .../default_space/default_space_service.ts | 4 +- .../routes/api/external/copy_to_space.ts | 14 +- .../api/internal/get_content_summary.test.ts | 2 +- .../api/internal/get_content_summary.ts | 6 +- x-pack/plugins/spaces/tsconfig.json | 4 +- .../lib/create_managed_configuration.test.ts | 61 +- .../lib/create_managed_configuration.ts | 7 +- .../task_manager/server/lib/fill_pool.test.ts | 93 +- .../task_manager/server/lib/fill_pool.ts | 109 +- .../task_manager/server/lib/msearch_error.ts | 25 + .../server/monitoring/task_run_statistics.ts | 13 +- .../server/polling_lifecycle.test.ts | 134 +- .../task_manager/server/polling_lifecycle.ts | 77 +- .../server/queries/task_claiming.ts | 42 +- .../task_manager/server/routes/health.test.ts | 1 + .../server/task_claimers/index.ts | 6 +- .../task_claimers/strategy_mget.test.ts | 179 +- .../server/task_claimers/strategy_mget.ts | 26 +- .../strategy_update_by_query.test.ts | 326 +- .../task_claimers/strategy_update_by_query.ts | 84 +- .../task_manager/server/task_store.test.ts | 12 +- .../plugins/task_manager/server/task_store.ts | 3 +- .../query_bar/hooks/use_filter_in_out.ts | 4 +- .../threat_intelligence/public/types.ts | 2 +- .../translations/translations/fr-FR.json | 28 +- .../translations/translations/ja-JP.json | 28 +- .../translations/translations/zh-CN.json | 28 +- .../apps/group2/ml_memory_usage.ts | 55 + .../actions/connector_types/cases_webhook.ts | 8 +- .../tests/actions/connector_types/email.ts | 10 +- .../tests/actions/connector_types/es_index.ts | 12 +- .../tests/actions/connector_types/jira.ts | 8 +- .../actions/connector_types/pagerduty.ts | 10 +- .../actions/connector_types/resilient.ts | 4 +- .../actions/connector_types/server_log.ts | 10 +- .../actions/connector_types/servicenow.ts | 8 +- .../tests/actions/connector_types/slack.ts | 10 +- .../tests/actions/connector_types/swimlane.ts | 8 +- .../tests/actions/connector_types/webhook.ts | 10 +- .../plugins/alerts/server/rule_types.ts | 47 +- .../common/plugins/alerts/tsconfig.json | 1 - .../group1/tests/alerting/backfill/api_key.ts | 11 + .../tests/alerting/backfill/task_runner.ts | 3 +- .../group1/tests/alerting/bulk_untrack.ts | 1 + .../tests/alerting/bulk_untrack_by_query.ts | 1 + .../group1/tests/alerting/retain_api_key.ts | 8 +- .../group2/tests/actions/bulk_enqueue.ts | 10 +- .../tests/actions/connector_types/bedrock.ts | 4 +- .../actions/connector_types/cases_webhook.ts | 10 +- .../actions/connector_types/d3security.ts | 4 +- .../tests/actions/connector_types/gemini.ts | 4 +- .../tests/actions/connector_types/jira.ts | 16 +- .../tests/actions/connector_types/openai.ts | 4 +- .../connector_types/servicenow_itom.ts | 6 +- .../connector_types/servicenow_itsm.ts | 12 +- .../actions/connector_types/servicenow_sir.ts | 12 +- .../tests/actions/connector_types/swimlane.ts | 8 +- .../tests/actions/connector_types/thehive.ts | 4 +- .../group2/tests/actions/create.ts | 36 +- .../group2/tests/actions/delete.ts | 38 +- .../group2/tests/actions/execute.ts | 66 +- .../group2/tests/actions/get.ts | 30 +- .../group2/tests/actions/get_all.ts | 34 +- .../group2/tests/actions/get_all_system.ts | 46 +- .../actions/sub_action_framework/index.ts | 22 +- .../group2/tests/actions/update.ts | 70 +- .../group2/tests/alerting/index.ts | 36 +- .../group2/tests/alerting/rbac_legacy.ts | 310 -- .../find_maintenance_windows.ts | 112 + .../group4/tests/alerting/alerts.ts | 62 +- .../tests/alerting/get_action_error_log.ts | 4 +- .../spaces_only/tests/actions/bulk_enqueue.ts | 10 +- .../tests/actions/connector_types.ts | 49 +- .../actions/connector_types/stack/webhook.ts | 22 +- .../spaces_only/tests/actions/create.ts | 68 +- .../spaces_only/tests/actions/delete.ts | 114 +- .../spaces_only/tests/actions/execute.ts | 129 +- .../tests/actions/execute_unsecured_action.ts | 12 +- .../spaces_only/tests/actions/get.ts | 112 +- .../spaces_only/tests/actions/get_all.ts | 157 +- .../tests/actions/get_all_system.ts | 30 +- .../actions/get_all_unsecured_actions.ts | 4 +- .../max_queued_actions_circuit_breaker.ts | 2 +- .../spaces_only/tests/actions/migrations.ts | 16 +- .../actions/schedule_unsecured_action.ts | 2 +- .../tests/actions/type_not_enabled.ts | 56 +- .../spaces_only/tests/actions/update.ts | 221 +- .../tests/alerting/group1/disable.ts | 1 + .../tests/alerting/group1/event_log.ts | 4 +- .../alerting/group1/get_action_error_log.ts | 6 +- .../alerting/group1/get_execution_log.ts | 4 +- .../group3/maintenance_window_scoped_query.ts | 67 + .../tests/alerting/group3/test_helpers.ts | 2 +- .../alerts_as_data_alert_delay.ts | 232 +- .../alerts_as_data/alerts_as_data_flapping.ts | 3 +- .../builtin_alert_types/auto_recover/rule.ts | 10 +- .../tests/alerting/group4/bulk_disable.ts | 1 + .../alerting/group4/capped_action_type.ts | 26 +- .../tests/alerting/group4/ephemeral.ts | 2 +- .../tests/alerting/group4/snooze.ts | 32 +- .../actions/connector_types/stack/webhook.ts | 24 +- .../index_management/data_streams.ts | 19 + .../lib/datastreams.helpers.ts | 7 +- .../test/api_integration/apis/slos/config.ts | 29 - .../api_integration/apis/slos/create_slo.ts | 488 --- .../api_integration/apis/slos/delete_slo.ts | 141 - .../apis/slos/fetch_historical_summary.ts | 134 - .../test/api_integration/apis/slos/get_slo.ts | 492 --- .../test/api_integration/apis/slos/index.ts | 19 - .../api_integration/apis/slos/reset_slo.ts | 93 - .../api_integration/apis/slos/update_slo.ts | 764 ---- .../apis/synthetics/add_monitor.ts | 9 +- .../apis/synthetics/get_monitor.ts | 1 - .../common/lib/api/connectors.ts | 2 +- .../common/lib/api/index.ts | 10 +- .../tests/common/cases/import_export.ts | 2 +- .../tests/common/cases/patch_cases.ts | 78 + .../tests/common/cases/post_case.ts | 64 +- .../tests/common/configure/get_configure.ts | 7 + .../tests/common/configure/patch_configure.ts | 11 + .../tests/common/configure/post_configure.ts | 34 + .../tests/common/telemetry.ts | 51 +- .../user_actions/get_all_user_actions.ts | 11 + .../tests/trial/cases/push_case.ts | 4 +- .../tests/trial/configure/get_configure.ts | 2 +- .../tests/trial/configure/get_connectors.ts | 14 +- .../tests/trial/configure/patch_configure.ts | 4 +- .../tests/trial/configure/post_configure.ts | 2 +- .../tests/trial/internal/get_connectors.ts | 10 +- .../trial/internal/get_user_action_stats.ts | 2 +- .../tests/trial/configure/get_configure.ts | 4 +- .../tests/trial/configure/get_connectors.ts | 26 +- .../tests/trial/configure/patch_configure.ts | 4 +- .../tests/trial/configure/post_configure.ts | 2 +- .../pages/alerts_flyout.ts | 3 +- .../fleet_api_integration/apis/agents/list.ts | 8 +- .../apis/agents/privileges.ts | 2 +- .../apis/agents/status.ts | 6 - .../apis/agents/update_agent_tags.ts | 2 +- .../apis/agents/upgrade.ts | 2 +- .../apis/fleet_telemetry.ts | 2 +- .../apis/service_tokens.ts | 4 - .../apis/space_awareness/agent_policies.ts | 16 + .../change_space_agent_policies.ts | 65 +- .../apis/space_awareness/helpers.ts | 10 + .../dataset_quality/degraded_field_flyout.ts | 4 +- .../data_streams_tab/data_streams_tab.ts | 41 + .../index_management/index_template_wizard.ts | 4 + .../test/functional/apps/infra/home_page.ts | 8 +- .../test/functional/apps/infra/hosts_view.ts | 12 +- .../apps/infra/metrics_anomalies.ts | 9 +- .../functional/apps/infra/node_details.ts | 30 +- .../model_management/model_list.ts | 3 +- x-pack/test/functional/config.base.js | 3 + x-pack/test/functional/page_objects/index.ts | 2 + .../page_objects/infra_hosts_view.ts | 2 +- .../page_objects/search_classic_navigation.ts | 118 + .../functional/services/ml/memory_usage.ts | 7 +- x-pack/test/functional_search/config.ts | 10 + x-pack/test/functional_search/index.ts | 1 + .../tests/classic_navigation.ts | 131 + .../apps/cases/group1/view_case.ts | 39 + .../apps/cases/group2/configure.ts | 55 +- .../triggers_actions_ui/connectors/general.ts | 36 +- .../triggers_actions_ui/connectors/jira.ts | 4 +- .../connectors/opsgenie.ts | 12 +- .../triggers_actions_ui/connectors/slack.ts | 8 +- .../triggers_actions_ui/connectors/tines.ts | 10 +- .../triggers_actions_ui/connectors/utils.ts | 6 +- .../apps/triggers_actions_ui/details.ts | 6 +- .../apps/triggers_actions_ui/home_page.ts | 8 +- .../rules_list/rules_list.ts | 6 +- .../lib/alert_api_actions.ts | 8 +- .../lib/get_test_data.ts | 2 +- .../knowledge_base_user_instructions.spec.ts | 14 +- .../pages/alerts/custom_threshold.ts | 3 +- .../check_registered_task_types.ts | 1 + .../reporting_and_security/datastream.ts | 1 + .../spaces_only/tests/trial/index.ts | 1 - .../tests/trial/lifecycle_executor.ts | 275 -- .../package.json | 94 +- .../trial_license_complete_tier/throttle.ts | 24 +- .../configs/ess.config.ts | 2 +- .../configs/serverless.config.ts | 2 +- .../basic_license_essentials_tier/date.ts | 0 .../basic_license_essentials_tier/index.ts | 13 + .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 16 + .../basic_license_essentials_tier/double.ts | 0 .../basic_license_essentials_tier/index.ts | 13 + .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 16 + .../basic_license_essentials_tier/float.ts | 0 .../basic_license_essentials_tier/index.ts | 13 + .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 16 + .../basic_license_essentials_tier/index.ts | 5 +- .../basic_license_essentials_tier/integer.ts | 0 .../execution_logic => }/README.md | 0 .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 21 + .../trial_license_complete_tier}/eql.ts | 2 +- .../eql_alert_suppression.ts | 0 .../eql/trial_license_complete_tier}/index.ts | 10 +- .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 21 + .../trial_license_complete_tier}/esql.ts | 0 .../esql_suppression.ts | 0 .../esql/trial_license_complete_tier/index.ts | 15 + .../configs/ess.config.ts | 4 +- .../configs/serverless.config.ts | 4 +- .../ignore_fields.ts | 6 +- .../trial_license_complete_tier/index.ts | 5 +- .../keyword_family/README.md | 0 .../keyword_family/const_keyword.ts | 6 +- .../keyword_family/index.ts | 2 +- .../keyword_family/keyword.ts | 6 +- .../keyword_mixed_with_const.ts | 6 +- .../non_ecs_fields.ts | 0 .../trial_license_complete_tier/runtime.ts | 4 +- .../synthetic_source.ts | 0 .../trial_license_complete_tier/timestamps.ts | 8 +- .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 21 + .../trial_license_complete_tier/index.ts | 15 + .../indicator_match.ts | 0 .../indicator_match_alert_suppression.ts | 3 +- .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 21 + .../trial_license_complete_tier/index.ts | 16 + .../machine_learning.ts | 2 +- .../machine_learning_alert_suppression.ts | 0 .../machine_learning_manual_run.ts | 0 .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 21 + .../trial_license_complete_tier/index.ts | 15 + .../trial_license_complete_tier}/new_terms.ts | 0 .../new_terms_alert_suppression.ts | 0 .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 21 + .../custom_query.ts | 0 .../trial_license_complete_tier/index.ts | 15 + .../saved_query.ts | 0 .../configs/ess.config.ts | 23 + .../configs/serverless.config.ts | 21 + .../trial_license_complete_tier/index.ts | 15 + .../trial_license_complete_tier}/threshold.ts | 0 .../threshold_alert_suppression.ts | 0 .../execution_logic/index.ts | 30 - .../execution_logic => }/utils.ts | 0 ...e_perform_prebuilt_rules.all_rules_mode.ts | 9 +- ...form_prebuilt_rules.specific_rules_mode.ts | 9 +- .../perform_bulk_action.ts | 9 +- .../perform_bulk_action_ess.ts | 9 +- .../delete_rules_bulk_legacy.ts | 14 +- .../delete_rules_legacy.ts | 8 +- .../trial_license_complete_tier/find_rules.ts | 8 +- .../find_rules_ess.ts | 6 +- .../trial_license_complete_tier/read_rules.ts | 8 +- .../read_rules_ess.ts | 6 +- .../actions/create_new_webhook_action.ts | 2 +- .../utils/actions/get_slack_action.ts | 2 +- .../utils/actions/get_web_hook_action.ts | 2 +- .../utils/rules/get_rule_actions.ts | 2 +- .../configs/ess.config.ts | 22 + .../configs/serverless.config.ts | 22 + .../datastream_index_creation.ts | 133 + .../trial_license_complete_tier/index.ts | 56 + .../entity_analytics/utils/entity_store.ts | 3 + .../configs/ess.config.ts | 5 + .../trial_license_complete_tier/entries.ts | 2 +- .../saved_objects/tests/notes.ts | 27 +- .../alerts/event_rendered_view.cy.ts | 15 +- .../alert_details_right_panel.cy.ts | 7 +- ...ert_details_right_panel_overview_tab.cy.ts | 27 +- .../investigations/timelines/creation.cy.ts | 37 +- .../timelines/data_providers.cy.ts | 26 +- .../discover_timeline_state_integration.cy.ts | 12 +- .../timelines/esql/esql_state.cy.ts | 38 +- .../timelines/esql/search_filter.cy.ts | 17 +- .../e2e/investigations/timelines/export.cy.ts | 8 +- .../timelines/flyout_button.cy.ts | 17 +- .../investigations/timelines/notes_tab.cy.ts | 2 +- .../timelines/row_renderers.cy.ts | 24 +- .../timelines/timelines_table.cy.ts | 2 +- .../cypress/screens/alerts.ts | 8 + .../cypress/screens/discover.ts | 8 +- .../alert_details_right_panel.ts | 4 +- .../alert_details_right_panel_overview_tab.ts | 18 +- .../cypress/screens/timeline.ts | 40 +- .../cypress/tasks/api_calls/connectors.ts | 8 +- .../cypress/tasks/discover.ts | 13 +- .../cypress/tasks/timeline.ts | 65 +- .../services/endpoint_policy.ts | 60 +- .../common/suites/copy_to_space.ts | 3 +- .../suites/resolve_copy_to_space_conflicts.ts | 3 +- .../api_integration/services/svl_cases/api.ts | 14 +- .../common/index_management/datastreams.ts | 2 + .../common/reporting/datastream.ts | 39 +- .../common/reporting/management.ts | 38 +- .../observability/cases/get_all_comments.ts | 45 + .../cases/get_all_user_actions.ts | 45 + .../observability/cases/get_case.ts | 19 +- .../observability/cases/get_status.ts | 45 + .../test_suites/observability/cases/index.ts | 3 + .../test_suites/observability/index.ts | 1 - .../observability/slos/create_slo.ts | 371 -- .../observability/slos/delete_slo.ts | 175 - .../slos/fetch_historical_summary.ts | 146 - .../test_suites/security/cases/get_case.ts | 19 +- .../cloud_security_metering.ts | 52 +- .../extensions/_get_app_menu.ts | 69 + .../discover/context_awareness/index.ts | 1 + .../common/discover/x_pack/reporting.ts | 4 +- .../customizations.ts | 6 - .../common/reporting/management.ts | 105 +- .../observability/cases/configure.ts | 3 +- .../dataset_quality/degraded_field_flyout.ts | 4 +- .../test_suites/observability/infra/infra.ts | 6 +- .../observability/infra/navigation.ts | 23 - .../observability/onboarding/auto_detect.ts | 2 +- .../security/ftr/cases/configure.ts | 3 +- x-pack/test_serverless/shared/config.base.ts | 5 + x-pack/test_serverless/tsconfig.json | 1 - yarn.lock | 179 +- 2605 files changed, 46574 insertions(+), 39165 deletions(-) create mode 100644 .buildkite/scripts/lifecycle/comment_on_pr.ts create mode 100644 api_docs/kbn_cloud_security_posture_graph.devdocs.json create mode 100644 api_docs/kbn_cloud_security_posture_graph.mdx rename dev_docs/{shared_ux => tutorials/screenshotting}/browser_snapshots_filter1.png (100%) rename dev_docs/{shared_ux => tutorials/screenshotting}/browser_snapshots_filter2.png (100%) rename dev_docs/{shared_ux => tutorials/screenshotting}/browser_snapshots_listing.png (100%) rename dev_docs/{shared_ux => tutorials/screenshotting}/chromium_version_command.png (100%) rename dev_docs/tutorials/{ => screenshotting}/screenshotting.mdx (100%) rename dev_docs/{shared_ux/updating_puppeteer_and_chromium.mdx => tutorials/screenshotting/screenshotting_updating_puppeteer_and_chromium.mdx} (100%) delete mode 100644 docs/api/role-management/delete.asciidoc delete mode 100644 docs/api/role-management/get-all.asciidoc delete mode 100644 docs/api/role-management/get.asciidoc delete mode 100644 docs/api/role-management/put-bulk.asciidoc delete mode 100644 docs/api/role-management/put.asciidoc create mode 100644 docs/user/dashboard/images/managed-dashboard-popover-8.16.0.png create mode 100644 oas_docs/examples/create_role_request1.yaml create mode 100644 oas_docs/examples/create_role_request2.yaml create mode 100644 oas_docs/examples/create_role_request3.yaml create mode 100644 oas_docs/examples/create_role_request4.yaml create mode 100644 oas_docs/examples/get_role_response1.yaml create mode 100644 oas_docs/examples/get_roles_response1.yaml create mode 100644 oas_docs/output/kibana.serverless.staging.yaml create mode 100644 oas_docs/output/kibana.staging.yaml create mode 100644 packages/kbn-discover-utils/src/components/app_menu/__snapshots__/app_menu_registry.test.ts.snap create mode 100644 packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.test.ts create mode 100644 packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts create mode 100644 packages/kbn-discover-utils/src/components/app_menu/types.ts create mode 100644 packages/kbn-esql-ast/src/mutate/commands/sort/index.test.ts create mode 100644 packages/kbn-esql-ast/src/mutate/commands/sort/index.ts delete mode 100644 packages/kbn-esql-ast/src/mutate/generic.ts create mode 100644 packages/kbn-esql-ast/src/mutate/generic/commands/args/index.test.ts create mode 100644 packages/kbn-esql-ast/src/mutate/generic/commands/args/index.ts rename packages/kbn-esql-ast/src/mutate/{generic.test.ts => generic/commands/index.test.ts} (54%) create mode 100644 packages/kbn-esql-ast/src/mutate/generic/commands/index.ts create mode 100644 packages/kbn-esql-ast/src/mutate/generic/commands/options/index.test.ts create mode 100644 packages/kbn-esql-ast/src/mutate/generic/commands/options/index.ts create mode 100644 packages/kbn-esql-ast/src/mutate/generic/index.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/drop/index.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/keep/index.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/sort/index.ts create mode 100644 packages/kbn-grid-layout/grid/drag_preview.tsx create mode 100644 packages/kbn-router-to-openapispec/src/extract_authz_description.test.ts create mode 100644 packages/kbn-router-to-openapispec/src/extract_authz_description.ts delete mode 100644 packages/kbn-router-to-openapispec/src/operation_id_counter.test.ts delete mode 100644 packages/kbn-router-to-openapispec/src/operation_id_counter.ts create mode 100644 scripts/codeql/codeql.dockerfile create mode 100644 scripts/codeql/quick_check.sh create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/convert_to_top_nav_item.test.ts create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/convert_to_top_nav_item.ts rename src/plugins/discover/public/application/main/components/top_nav/{open_alerts_popover.test.tsx => app_menu_actions/get_alerts.test.tsx} (74%) create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_alerts.tsx create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_inspect.tsx create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_new_search.tsx create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_open_search.tsx create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_share.tsx create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/index.ts create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/run_app_menu_action.test.tsx create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/run_app_menu_action.tsx create mode 100644 src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/types.ts delete mode 100644 src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.test.ts delete mode 100644 src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx delete mode 100644 src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.tsx delete mode 100644 src/plugins/discover/public/application/main/components/top_nav/show_open_search_panel.tsx create mode 100644 src/plugins/discover/public/application/main/components/top_nav/top_nav.scss create mode 100644 src/plugins/discover/public/application/main/components/top_nav/use_top_nav_links.test.tsx create mode 100644 src/plugins/discover/public/application/main/components/top_nav/use_top_nav_links.tsx create mode 100644 test/functional/apps/discover/context_awareness/extensions/_get_app_menu.ts create mode 100644 x-pack/packages/ai-infra/inference-common/README.md create mode 100644 x-pack/packages/ai-infra/inference-common/index.ts create mode 100644 x-pack/packages/ai-infra/inference-common/jest.config.js create mode 100644 x-pack/packages/ai-infra/inference-common/kibana.jsonc create mode 100644 x-pack/packages/ai-infra/inference-common/package.json create mode 100644 x-pack/packages/ai-infra/inference-common/src/chat_complete/api.ts rename x-pack/{plugins/inference/common => packages/ai-infra/inference-common/src}/chat_complete/errors.ts (61%) create mode 100644 x-pack/packages/ai-infra/inference-common/src/chat_complete/event_utils.ts create mode 100644 x-pack/packages/ai-infra/inference-common/src/chat_complete/events.ts create mode 100644 x-pack/packages/ai-infra/inference-common/src/chat_complete/index.ts create mode 100644 x-pack/packages/ai-infra/inference-common/src/chat_complete/messages.ts rename x-pack/{plugins/inference/common => packages/ai-infra/inference-common/src}/chat_complete/tool_schema.ts (95%) rename x-pack/{plugins/inference/common => packages/ai-infra/inference-common/src}/chat_complete/tools.ts (53%) rename x-pack/{plugins/inference/common => packages/ai-infra/inference-common/src}/errors.ts (93%) rename x-pack/{plugins/inference/common => packages/ai-infra/inference-common/src}/inference_task.ts (81%) create mode 100644 x-pack/packages/ai-infra/inference-common/src/output/api.ts create mode 100644 x-pack/packages/ai-infra/inference-common/src/output/event_utils.ts create mode 100644 x-pack/packages/ai-infra/inference-common/src/output/events.ts create mode 100644 x-pack/packages/ai-infra/inference-common/src/output/index.ts create mode 100644 x-pack/packages/ai-infra/inference-common/tsconfig.json create mode 100644 x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_get_navigation_url_params.ts create mode 100644 x-pack/packages/kbn-cloud-security-posture/public/src/utils/query_utils.test.ts create mode 100644 x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.test.ts delete mode 100644 x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.test.ts delete mode 100644 x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.ts delete mode 100644 x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.test.ts delete mode 100644 x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.ts rename x-pack/plugins/actions/server/routes/{legacy => }/_mock_handler_arguments.ts (87%) delete mode 100644 x-pack/plugins/actions/server/routes/legacy/create.test.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/create.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/delete.test.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/delete.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/execute.test.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/execute.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/get.test.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/get.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/get_all.test.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/get_all.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/index.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/list_action_types.test.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/list_action_types.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/update.test.ts delete mode 100644 x-pack/plugins/actions/server/routes/legacy/update.ts create mode 100644 x-pack/plugins/actions/server/usage/connector_usage_reporting_task.test.ts create mode 100644 x-pack/plugins/actions/server/usage/connector_usage_reporting_task.ts rename x-pack/plugins/{observability_solution/apm/common/entities/types.ts => alerting/common/routes/maintenance_window/apis/find/schemas/latest.ts} (72%) create mode 100644 x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/schemas/v1.ts create mode 100644 x-pack/plugins/alerting/server/alerts_client/lib/inject_analyze_wildcard.test.ts create mode 100644 x-pack/plugins/alerting/server/alerts_client/lib/inject_analyze_wildcard.ts rename x-pack/plugins/{inference/common/output/is_output_update_event.ts => alerting/server/application/maintenance_window/methods/find/schemas/find_maintenance_window_params_schema.ts} (51%) create mode 100644 x-pack/plugins/alerting/server/application/maintenance_window/methods/find/types/find_maintenance_window_params.ts delete mode 100644 x-pack/plugins/alerting/server/data/rule/types/index.ts delete mode 100644 x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts create mode 100644 x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/index.ts create mode 100644 x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_params/latest.ts create mode 100644 x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_params/v1.ts create mode 100644 x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_to_response/latest.ts create mode 100644 x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_to_response/v1.ts create mode 100644 x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/latest.ts create mode 100644 x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v3.ts delete mode 100644 x-pack/plugins/canvas/server/sample_data/ecommerce_saved_objects.json delete mode 100644 x-pack/plugins/canvas/server/sample_data/flights_saved_objects.json delete mode 100644 x-pack/plugins/canvas/server/sample_data/index.ts delete mode 100644 x-pack/plugins/canvas/server/sample_data/load_sample_data.ts delete mode 100644 x-pack/plugins/canvas/server/sample_data/web_logs_saved_objects.json create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/config.ts create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/configure.test.tsx create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/configure.tsx create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/configure_number_field.test.ts create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/configure_number_field.ts create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/create.tsx create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/edit.test.tsx create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/edit.tsx create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/get_eui_table_column.test.tsx create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/get_eui_table_column.tsx create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/view.test.tsx create mode 100644 x-pack/plugins/cases/public/components/custom_fields/number/view.tsx create mode 100644 x-pack/plugins/cases/server/custom_fields/number.ts create mode 100644 x-pack/plugins/cases/server/routes/api/cases/get_case.test.ts create mode 100644 x-pack/plugins/cases/server/routes/api/comments/get_all_comment.test.ts create mode 100644 x-pack/plugins/cases/server/routes/api/stats/get_status.test.ts create mode 100644 x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.test.ts create mode 100644 x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.test.tsx create mode 100644 x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.test.tsx create mode 100644 x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/applications/components/playground/page_template.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/layout/base_nav.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/layout/classic_nav_helpers.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/layout/classic_nav_helpers.ts create mode 100644 x-pack/plugins/entity_manager/public/lib/entity_client.test.ts create mode 100644 x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts create mode 100644 x-pack/plugins/fleet/server/services/spaces/package_policy.ts create mode 100644 x-pack/plugins/index_management/public/application/lib/index_mode_labels.ts delete mode 100644 x-pack/plugins/inference/common/chat_complete/index.ts delete mode 100644 x-pack/plugins/inference/common/chat_complete/is_chat_completion_chunk_event.ts delete mode 100644 x-pack/plugins/inference/common/chat_complete/is_chat_completion_event.ts delete mode 100644 x-pack/plugins/inference/common/chat_complete/is_chat_completion_message_event.ts delete mode 100644 x-pack/plugins/inference/common/chat_complete/without_chunk_events.ts delete mode 100644 x-pack/plugins/inference/common/chat_complete/without_token_count_events.ts rename x-pack/plugins/inference/common/{output => }/create_output_api.ts (85%) rename x-pack/plugins/inference/common/{chat_complete/request.ts => http_apis.ts} (66%) delete mode 100644 x-pack/plugins/inference/common/output/index.ts delete mode 100644 x-pack/plugins/inference/common/output/is_output_complete_event.ts delete mode 100644 x-pack/plugins/inference/common/output/is_output_event.ts delete mode 100644 x-pack/plugins/inference/common/output/without_output_update_events.ts rename x-pack/plugins/inference/common/{ => utils}/ensure_multi_turn.ts (92%) rename x-pack/plugins/inference/common/{chat_complete => utils}/generate_fake_tool_call_id.ts (100%) rename x-pack/plugins/inference/common/{util => utils}/truncate_list.ts (100%) rename x-pack/plugins/inference/public/{chat_complete/index.ts => chat_complete.ts} (79%) create mode 100644 x-pack/plugins/inference/server/chat_complete/errors.ts delete mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss delete mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss delete mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/_index.scss delete mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/_regression_exploration.scss delete mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.scss delete mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_button/_index.scss delete mode 100644 x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/_time_range_selector.scss create mode 100644 x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector_wrapper.tsx delete mode 100644 x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/style.scss delete mode 100644 x-pack/plugins/observability_solution/apm/common/es_fields/entities.ts delete mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.json create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/README.md create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/headers/elastic_api_version.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/headers/kbn_xsrf.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/400_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/401_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/403_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/404_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/500_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/501_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configuration_intake_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configuration_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configurations_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_keys_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_keys_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/annotation_search_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/base_source_map_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/create_annotation_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/create_annotation_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/delete_agent_configurations_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/search_agent_configuration_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/search_agent_configuration_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_agent_name_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_environment_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_environments_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/settings_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/single_agent_configuration_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/source_maps_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/upload_source_map_object.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/upload_source_maps_response.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/entrypoint.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/README.md create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@agent_keys.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@fleet@apm_server_schema.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@services@{service_name}@annotation.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@services@{service_name}@annotation@search.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@agent_name.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@environments.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@search.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@view.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@sourcemaps.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@sourcemaps@{id}.yaml delete mode 100644 x-pack/plugins/observability_solution/infra/public/hooks/use_breadcrumbs.ts delete mode 100644 x-pack/plugins/observability_solution/inventory/common/utils/parse_identity_field_values_to_kql.test.ts delete mode 100644 x-pack/plugins/observability_solution/inventory/common/utils/parse_identity_field_values_to_kql.ts create mode 100644 x-pack/plugins/observability_solution/inventory/common/utils/unflatten_entity.ts create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/mock/inventory_component_wrapper_mock.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/unified_inventory.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts create mode 100644 x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts create mode 100644 x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/delete_monitor_api.ts create mode 100644 x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/validate_space_id.ts delete mode 100644 x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts delete mode 100644 x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts delete mode 100644 x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_executor_mock.ts delete mode 100644 x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts delete mode 100644 x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type_factory.ts delete mode 100644 x-pack/plugins/rule_registry/server/utils/get_updated_flapping_history.test.ts delete mode 100644 x-pack/plugins/rule_registry/server/utils/get_updated_flapping_history.ts delete mode 100644 x-pack/plugins/rule_registry/server/utils/lifecycle_alert_services.mock.ts create mode 100644 x-pack/plugins/security_solution/common/endpoint/utils/index_name_utilities.test.ts create mode 100644 x-pack/plugins/security_solution/common/endpoint/utils/index_name_utilities.ts delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/index.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/index.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/__mocks__/use_data_views.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/data_view_selector_field.test.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/data_view_selector_field.tsx rename x-pack/plugins/{cloud/common => security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field}/index.ts (81%) rename x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/{data_view_selector => data_view_selector_field}/translations.tsx (84%) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/use_data_views.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/data_view_id_validator_factory.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/index_pattern_validator_factory.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/eql_rule_field_edit.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit_form.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_info_text.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_type_selector_field.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_view_field.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/index.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/index_pattern_edit.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/translations.tsx delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/index.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_component_props.ts rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/{field_form_wrapper.tsx => fields/rule_field_edit_form_wrapper.tsx} (61%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/{components/rule_details => hooks}/use_default_index_pattern.tsx (63%) delete mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.stories.tsx create mode 100644 x-pack/plugins/security_solution/public/kubernetes/pages/utils/data_view_spec_to_index_pattern.ts rename x-pack/plugins/security_solution/public/notes/components/{user_filter_dropdown.test.tsx => created_by_filter_dropdown.test.tsx} (74%) rename x-pack/plugins/security_solution/public/notes/components/{user_filter_dropdown.tsx => created_by_filter_dropdown.tsx} (68%) create mode 100644 x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/missing_privileges_tooltip.tsx create mode 100644 x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/translations.ts create mode 100644 x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/images/demo_dark.png create mode 100644 x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/images/documentation_dark.png create mode 100644 x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/images/forum_dark.png create mode 100644 x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/images/labs_dark.png rename x-pack/plugins/security_solution/server/endpoint/{services/actions/clients => }/lib/simple_mem_cache.test.ts (92%) rename x-pack/plugins/security_solution/server/endpoint/{services/actions/clients => }/lib/simple_mem_cache.ts (95%) create mode 100644 x-pack/plugins/security_solution/server/endpoint/migrations/ensure_indices_exists_for_policies.test.ts create mode 100644 x-pack/plugins/security_solution/server/endpoint/migrations/ensure_indices_exists_for_policies.ts create mode 100644 x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.test.ts create mode 100644 x-pack/plugins/security_solution/server/fleet_integration/handlers/create_policy_datastreams.test.ts create mode 100644 x-pack/plugins/security_solution/server/fleet_integration/handlers/create_policy_datastreams.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/scripts/{get_alert_types.sh => find_alerting_rules.sh} (59%) rename x-pack/plugins/security_solution/server/lib/detection_engine/scripts/{get_alert_instances.sh => get_alerting_rule_types.sh} (65%) create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/actions.ts create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/resources.ts create mode 100644 x-pack/plugins/snapshot_restore/public/application/components/disable_tooltip.tsx create mode 100644 x-pack/plugins/task_manager/server/lib/msearch_error.ts create mode 100644 x-pack/test/accessibility/apps/group2/ml_memory_usage.ts delete mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/rbac_legacy.ts delete mode 100644 x-pack/test/api_integration/apis/slos/config.ts delete mode 100644 x-pack/test/api_integration/apis/slos/create_slo.ts delete mode 100644 x-pack/test/api_integration/apis/slos/delete_slo.ts delete mode 100644 x-pack/test/api_integration/apis/slos/fetch_historical_summary.ts delete mode 100644 x-pack/test/api_integration/apis/slos/get_slo.ts delete mode 100644 x-pack/test/api_integration/apis/slos/index.ts delete mode 100644 x-pack/test/api_integration/apis/slos/reset_slo.ts delete mode 100644 x-pack/test/api_integration/apis/slos/update_slo.ts create mode 100644 x-pack/test/functional/page_objects/search_classic_navigation.ts create mode 100644 x-pack/test/functional_search/tests/classic_navigation.ts delete mode 100644 x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/{date_numeric_types => date_types}/basic_license_essentials_tier/configs/ess.config.ts (84%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/{date_numeric_types => date_types}/basic_license_essentials_tier/configs/serverless.config.ts (79%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/{date_numeric_types => date_types}/basic_license_essentials_tier/date.ts (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/date_types/basic_license_essentials_tier/index.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/double/basic_license_essentials_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/double/basic_license_essentials_tier/configs/serverless.config.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/{date_numeric_types => double}/basic_license_essentials_tier/double.ts (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/double/basic_license_essentials_tier/index.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/float/basic_license_essentials_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/float/basic_license_essentials_tier/configs/serverless.config.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/{date_numeric_types => float}/basic_license_essentials_tier/float.ts (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/float/basic_license_essentials_tier/index.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/integer/basic_license_essentials_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/integer/basic_license_essentials_tier/configs/serverless.config.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/{date_numeric_types => integer}/basic_license_essentials_tier/index.ts (67%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/{date_numeric_types => integer}/basic_license_essentials_tier/integer.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => }/README.md (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/eql/trial_license_complete_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/eql/trial_license_complete_tier/configs/serverless.config.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => eql/trial_license_complete_tier}/eql.ts (99%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => eql/trial_license_complete_tier}/eql_alert_suppression.ts (100%) rename x-pack/{test_serverless/api_integration/test_suites/observability/slos => test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/eql/trial_license_complete_tier}/index.ts (55%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/esql/trial_license_complete_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/esql/trial_license_complete_tier/configs/serverless.config.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => esql/trial_license_complete_tier}/esql.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => esql/trial_license_complete_tier}/esql_suppression.ts (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/esql/trial_license_complete_tier/index.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/configs/ess.config.ts (77%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/configs/serverless.config.ts (76%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/ignore_fields.ts (96%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/index.ts (75%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/keyword_family/README.md (100%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/keyword_family/const_keyword.ts (96%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/keyword_family/index.ts (88%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/keyword_family/keyword.ts (95%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/keyword_family/keyword_mixed_with_const.ts (96%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => general_logic/trial_license_complete_tier}/non_ecs_fields.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/runtime.ts (98%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => general_logic/trial_license_complete_tier}/synthetic_source.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{ => general_logic}/trial_license_complete_tier/timestamps.ts (98%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/indicator_match/trial_license_complete_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/indicator_match/trial_license_complete_tier/configs/serverless.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/indicator_match/trial_license_complete_tier/index.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => indicator_match/trial_license_complete_tier}/indicator_match.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => indicator_match/trial_license_complete_tier}/indicator_match_alert_suppression.ts (99%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/machine_learning/trial_license_complete_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/machine_learning/trial_license_complete_tier/configs/serverless.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/machine_learning/trial_license_complete_tier/index.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => machine_learning/trial_license_complete_tier}/machine_learning.ts (99%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => machine_learning/trial_license_complete_tier}/machine_learning_alert_suppression.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => machine_learning/trial_license_complete_tier}/machine_learning_manual_run.ts (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/new_terms/trial_license_complete_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/new_terms/trial_license_complete_tier/configs/serverless.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/new_terms/trial_license_complete_tier/index.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => new_terms/trial_license_complete_tier}/new_terms.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => new_terms/trial_license_complete_tier}/new_terms_alert_suppression.ts (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/query/trial_license_complete_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/query/trial_license_complete_tier/configs/serverless.config.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => query/trial_license_complete_tier}/custom_query.ts (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/query/trial_license_complete_tier/index.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => query/trial_license_complete_tier}/saved_query.ts (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/threshold/trial_license_complete_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/threshold/trial_license_complete_tier/configs/serverless.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/threshold/trial_license_complete_tier/index.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => threshold/trial_license_complete_tier}/threshold.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => threshold/trial_license_complete_tier}/threshold_alert_suppression.ts (100%) delete mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/index.ts rename x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/{trial_license_complete_tier/execution_logic => }/utils.ts (100%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/edr_workflows/policy/trial_license_complete_tier/configs/ess.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/edr_workflows/policy/trial_license_complete_tier/configs/serverless.config.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/edr_workflows/policy/trial_license_complete_tier/datastream_index_creation.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/edr_workflows/policy/trial_license_complete_tier/index.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/cases/get_all_comments.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/cases/get_all_user_actions.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/cases/get_status.ts delete mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/slos/create_slo.ts delete mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/slos/delete_slo.ts delete mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/slos/fetch_historical_summary.ts create mode 100644 x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_app_menu.ts diff --git a/.buildkite/ftr_oblt_stateful_configs.yml b/.buildkite/ftr_oblt_stateful_configs.yml index 6f0cb38be3a62..7655ce6de38cf 100644 --- a/.buildkite/ftr_oblt_stateful_configs.yml +++ b/.buildkite/ftr_oblt_stateful_configs.yml @@ -30,7 +30,6 @@ enabled: - x-pack/test/api_integration/apis/metrics_ui/config.ts - x-pack/test/api_integration/apis/osquery/config.ts - x-pack/test/api_integration/apis/synthetics/config.ts - - x-pack/test/api_integration/apis/slos/config.ts - x-pack/test/api_integration/apis/uptime/config.ts - x-pack/test/api_integration/apis/entity_manager/config.ts - x-pack/test/apm_api_integration/basic/config.ts diff --git a/.buildkite/ftr_security_serverless_configs.yml b/.buildkite/ftr_security_serverless_configs.yml index 22d1391034822..6b1c222382687 100644 --- a/.buildkite/ftr_security_serverless_configs.yml +++ b/.buildkite/ftr_security_serverless_configs.yml @@ -45,13 +45,23 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/actions/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/trial_license_complete_tier/configs/serverless.config.ts - - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/date_numeric_types/basic_license_essentials_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/date_types/basic_license_essentials_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/float/basic_license_essentials_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/integer/basic_license_essentials_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/double/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/ips/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/keyword/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/long/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/text/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/workflows/basic_license_essentials_tier/configs/serverless.config.ts - - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/eql/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/esql/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/general_logic/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/indicator_match/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/machine_learning/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/new_terms/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/query/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/threshold/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_creation/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_creation/trial_license_complete_tier/configs/serverless.config.ts @@ -96,6 +106,7 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/metadata/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/package/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/policy_response/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/policy/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/resolver/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/response_actions/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/spaces/trial_license_complete_tier/configs/serverless.config.ts diff --git a/.buildkite/ftr_security_stateful_configs.yml b/.buildkite/ftr_security_stateful_configs.yml index aa37c6f52fb8c..d3aadb1b7491d 100644 --- a/.buildkite/ftr_security_stateful_configs.yml +++ b/.buildkite/ftr_security_stateful_configs.yml @@ -30,13 +30,23 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/actions/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/trial_license_complete_tier/configs/ess.config.ts - - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/date_numeric_types/basic_license_essentials_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/date_types/basic_license_essentials_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/float/basic_license_essentials_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/integer/basic_license_essentials_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/double/basic_license_essentials_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/ips/basic_license_essentials_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/keyword/basic_license_essentials_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/long/basic_license_essentials_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/operators_data_types/text/basic_license_essentials_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/exceptions/workflows/basic_license_essentials_tier/configs/ess.config.ts - - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/eql/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/esql/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/general_logic/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/indicator_match/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/machine_learning/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/new_terms/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/query/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/threshold/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_creation/basic_license_essentials_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_creation/trial_license_complete_tier/configs/ess.config.ts @@ -83,6 +93,7 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/metadata/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/package/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/policy_response/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/policy/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/resolver/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/response_actions/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/spaces/trial_license_complete_tier/configs/ess.config.ts diff --git a/.buildkite/pipeline-resource-definitions/kibana-deploy-project.yml b/.buildkite/pipeline-resource-definitions/kibana-deploy-project.yml index 3c1bdc00ba371..490c9d9afc4e4 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-deploy-project.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-deploy-project.yml @@ -28,9 +28,11 @@ spec: pipeline_file: .buildkite/pipelines/serverless_deployment/project-build-and-deploy-pr.yml skip_intermediate_builds: true provider_settings: + build_pull_requests: true prefix_pull_request_fork_branch_names: false skip_pull_request_builds_for_existing_commits: true trigger_mode: none + cancel_intermediate_builds: true teams: kibana-operations: access_level: MANAGE_BUILD_AND_READ diff --git a/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml b/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml index 5a2521bb23026..b99fd82408b76 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml @@ -62,7 +62,7 @@ spec: message: Daily build branch: '8.15' Daily build (7.17): - cronline: 0 22 * * * America/New_York + cronline: 0 20 * * * America/New_York message: Daily build branch: '7.17' tags: diff --git a/.buildkite/pipeline-utils/github/github.ts b/.buildkite/pipeline-utils/github/github.ts index 0a7970d750598..eb9a240386bbc 100644 --- a/.buildkite/pipeline-utils/github/github.ts +++ b/.buildkite/pipeline-utils/github/github.ts @@ -93,6 +93,26 @@ export const doAnyChangesMatch = async ( return anyFilesMatchRequired; }; +export function addComment( + comment: string, + owner = process.env.GITHUB_PR_BASE_OWNER, + repo = process.env.GITHUB_PR_BASE_REPO, + prNumber: undefined | string | number = process.env.GITHUB_PR_NUMBER +) { + if (!owner || !repo || !prNumber) { + throw Error( + "Couldn't retrieve Github PR info from environment variables in order to add a comment" + ); + } + + return github.issues.createComment({ + owner, + repo, + issue_number: typeof prNumber === 'number' ? prNumber : parseInt(prNumber, 10), + body: comment, + }); +} + export function getGithubClient() { return github; } diff --git a/.buildkite/pipelines/on_merge.yml b/.buildkite/pipelines/on_merge.yml index 64067ec52a4d3..5518e1f8ed83c 100644 --- a/.buildkite/pipelines/on_merge.yml +++ b/.buildkite/pipelines/on_merge.yml @@ -39,7 +39,50 @@ steps: provider: gcp machineType: n2-highcpu-8 preemptible: true - key: quick_checks + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 + + - command: .buildkite/scripts/steps/lint.sh + label: 'Linting' + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-16 + preemptible: true + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 + + - command: .buildkite/scripts/steps/lint_with_types.sh + label: 'Linting (with types)' + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-32 + preemptible: true + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 + + - command: .buildkite/scripts/steps/check_types.sh + label: 'Check Types' + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: c4-standard-4 + diskType: 'hyperdisk-balanced' + preemptible: true + spotZones: us-central1-a,us-central1-b,us-central1-c timeout_in_minutes: 60 retry: automatic: @@ -106,9 +149,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 3 retry: @@ -124,9 +164,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 2 retry: @@ -142,9 +179,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 8 retry: @@ -160,9 +194,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 5 retry: @@ -178,9 +209,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 1 retry: @@ -196,9 +224,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 4 retry: @@ -214,9 +239,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 6 retry: @@ -232,9 +254,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 5 retry: @@ -250,9 +269,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 6 retry: @@ -268,9 +284,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 5 retry: @@ -286,9 +299,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 6 retry: @@ -304,9 +314,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 1 retry: @@ -322,9 +329,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 1 retry: @@ -340,9 +344,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 2 retry: @@ -358,9 +359,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 2 retry: @@ -376,9 +374,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 6 retry: @@ -394,9 +389,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 8 retry: @@ -412,9 +404,6 @@ steps: provider: gcp machineType: n2-standard-4 preemptible: true - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 8 retry: @@ -432,9 +421,6 @@ steps: localSsds: 1 localSsdInterface: nvme machineType: n2-standard-4 - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 20 retry: @@ -452,9 +438,6 @@ steps: localSsds: 1 localSsdInterface: nvme machineType: n2-standard-4 - depends_on: - - build - - quick_checks timeout_in_minutes: 60 parallelism: 14 retry: @@ -465,45 +448,12 @@ steps: - command: '.buildkite/scripts/steps/functional/on_merge_unsupported_ftrs.sh' label: Trigger unsupported ftr tests timeout_in_minutes: 10 - depends_on: - - build - - quick_checks agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod provider: gcp machineType: n2-standard-2 - - command: .buildkite/scripts/steps/lint.sh - label: 'Linting' - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-8 - preemptible: true - key: linting - timeout_in_minutes: 60 - retry: - automatic: - - exit_status: '-1' - limit: 3 - - - command: .buildkite/scripts/steps/lint_with_types.sh - label: 'Linting (with types)' - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-16 - preemptible: true - key: linting_with_types - timeout_in_minutes: 90 - retry: - automatic: - - exit_status: '-1' - limit: 3 - - command: .buildkite/scripts/steps/checks.sh label: 'Checks' agents: @@ -518,27 +468,13 @@ steps: - exit_status: '-1' limit: 3 - - command: .buildkite/scripts/steps/check_types.sh - label: 'Check Types' - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-4 - preemptible: true - timeout_in_minutes: 70 - retry: - automatic: - - exit_status: '-1' - limit: 3 - - command: .buildkite/scripts/steps/checks/capture_oas_snapshot.sh label: 'Check OAS Snapshot' agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod provider: gcp - machineType: n2-standard-2 + machineType: n2-standard-4 preemptible: true timeout_in_minutes: 60 retry: diff --git a/.buildkite/pipelines/pull_request/apm_cypress.yml b/.buildkite/pipelines/pull_request/apm_cypress.yml index 05194bae83e79..c0cb60dbc986b 100644 --- a/.buildkite/pipelines/pull_request/apm_cypress.yml +++ b/.buildkite/pipelines/pull_request/apm_cypress.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 120 parallelism: 1 # TODO: Set parallelism when apm_cypress handles it retry: diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index c60d68bd2e88b..fc3e2ce388bf5 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -32,6 +32,44 @@ steps: - exit_status: '-1' limit: 3 + - command: .buildkite/scripts/steps/lint.sh + label: 'Linting' + agents: + machineType: n2-standard-16 + preemptible: true + key: linting + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 + + - command: .buildkite/scripts/steps/lint_with_types.sh + label: 'Linting (with types)' + agents: + machineType: n2-standard-32 + preemptible: true + key: linting_with_types + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 + + - command: .buildkite/scripts/steps/check_types.sh + label: 'Check Types' + agents: + machineType: c4-standard-4 + diskType: 'hyperdisk-balanced' + preemptible: true + spotZones: us-central1-a,us-central1-b,us-central1-c + key: check_types + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 + - wait - command: .buildkite/scripts/steps/ci_stats_ready.sh @@ -61,42 +99,6 @@ steps: - exit_status: '*' limit: 1 - - command: .buildkite/scripts/steps/lint.sh - label: 'Linting' - agents: - machineType: n2-standard-8 - preemptible: true - key: linting - timeout_in_minutes: 60 - retry: - automatic: - - exit_status: '-1' - limit: 3 - - - command: .buildkite/scripts/steps/check_types.sh - label: 'Check Types' - agents: - machineType: n2-standard-4 - preemptible: true - key: check_types - timeout_in_minutes: 70 - retry: - automatic: - - exit_status: '-1' - limit: 3 - - - command: .buildkite/scripts/steps/lint_with_types.sh - label: 'Linting (with types)' - agents: - machineType: n2-standard-16 - preemptible: true - key: linting_with_types - timeout_in_minutes: 90 - retry: - automatic: - - exit_status: '-1' - limit: 3 - - command: .buildkite/scripts/steps/checks.sh label: 'Checks' key: checks @@ -112,7 +114,7 @@ steps: - command: .buildkite/scripts/steps/checks/capture_oas_snapshot.sh label: 'Check OAS Snapshot' agents: - machineType: n2-standard-2 + machineType: n2-standard-4 preemptible: true timeout_in_minutes: 60 retry: diff --git a/.buildkite/pipelines/pull_request/deploy_cloud.yml b/.buildkite/pipelines/pull_request/deploy_cloud.yml index d520822e54f7b..6b42037b95953 100644 --- a/.buildkite/pipelines/pull_request/deploy_cloud.yml +++ b/.buildkite/pipelines/pull_request/deploy_cloud.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 30 soft_fail: true retry: diff --git a/.buildkite/pipelines/pull_request/exploratory_view_plugin.yml b/.buildkite/pipelines/pull_request/exploratory_view_plugin.yml index 72a2ae8ab785b..c46edb528987a 100644 --- a/.buildkite/pipelines/pull_request/exploratory_view_plugin.yml +++ b/.buildkite/pipelines/pull_request/exploratory_view_plugin.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 artifact_paths: - 'x-pack/plugins/observability_solution/exploratory_view/e2e/.journeys/**/*' diff --git a/.buildkite/pipelines/pull_request/fips.yml b/.buildkite/pipelines/pull_request/fips.yml index a136b4f91a2c5..1a759e1288328 100644 --- a/.buildkite/pipelines/pull_request/fips.yml +++ b/.buildkite/pipelines/pull_request/fips.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 soft_fail: true retry: diff --git a/.buildkite/pipelines/pull_request/fleet_cypress.yml b/.buildkite/pipelines/pull_request/fleet_cypress.yml index 2e0365793afc0..d20591728b788 100644 --- a/.buildkite/pipelines/pull_request/fleet_cypress.yml +++ b/.buildkite/pipelines/pull_request/fleet_cypress.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 50 parallelism: 6 retry: diff --git a/.buildkite/pipelines/pull_request/inventory_cypress.yml b/.buildkite/pipelines/pull_request/inventory_cypress.yml index 371cd80b02cdf..7028b55808ca6 100644 --- a/.buildkite/pipelines/pull_request/inventory_cypress.yml +++ b/.buildkite/pipelines/pull_request/inventory_cypress.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 120 parallelism: 1 retry: diff --git a/.buildkite/pipelines/pull_request/kbn_handlebars.yml b/.buildkite/pipelines/pull_request/kbn_handlebars.yml index 5da18ce31919c..36901a5d5c552 100644 --- a/.buildkite/pipelines/pull_request/kbn_handlebars.yml +++ b/.buildkite/pipelines/pull_request/kbn_handlebars.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 5 retry: automatic: diff --git a/.buildkite/pipelines/pull_request/observability_onboarding_cypress.yml b/.buildkite/pipelines/pull_request/observability_onboarding_cypress.yml index b5831e7bb471d..8906cc72fa81f 100644 --- a/.buildkite/pipelines/pull_request/observability_onboarding_cypress.yml +++ b/.buildkite/pipelines/pull_request/observability_onboarding_cypress.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 120 retry: automatic: diff --git a/.buildkite/pipelines/pull_request/profiling_cypress.yml b/.buildkite/pipelines/pull_request/profiling_cypress.yml index d86fc5a167db6..100e42206b3a1 100644 --- a/.buildkite/pipelines/pull_request/profiling_cypress.yml +++ b/.buildkite/pipelines/pull_request/profiling_cypress.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 120 parallelism: 2 retry: diff --git a/.buildkite/pipelines/pull_request/response_ops.yml b/.buildkite/pipelines/pull_request/response_ops.yml index 60e2dc32476d5..f09beb168259f 100644 --- a/.buildkite/pipelines/pull_request/response_ops.yml +++ b/.buildkite/pipelines/pull_request/response_ops.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 120 parallelism: 9 retry: diff --git a/.buildkite/pipelines/pull_request/response_ops_cases.yml b/.buildkite/pipelines/pull_request/response_ops_cases.yml index 1e1510260436d..5382ab6017fa6 100644 --- a/.buildkite/pipelines/pull_request/response_ops_cases.yml +++ b/.buildkite/pipelines/pull_request/response_ops_cases.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 120 retry: automatic: diff --git a/.buildkite/pipelines/pull_request/security_solution/ai_assistant.yml b/.buildkite/pipelines/pull_request/security_solution/ai_assistant.yml index 252365ee7e4da..e8fa983f5ff63 100644 --- a/.buildkite/pipelines/pull_request/security_solution/ai_assistant.yml +++ b/.buildkite/pipelines/pull_request/security_solution/ai_assistant.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 1 retry: @@ -22,6 +25,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 1 retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/cloud_security_posture.yml b/.buildkite/pipelines/pull_request/security_solution/cloud_security_posture.yml index 7f5131b77f204..d2f1571f9d93f 100644 --- a/.buildkite/pipelines/pull_request/security_solution/cloud_security_posture.yml +++ b/.buildkite/pipelines/pull_request/security_solution/cloud_security_posture.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 1 retry: @@ -22,6 +25,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 1 retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/cypress_burn.yml b/.buildkite/pipelines/pull_request/security_solution/cypress_burn.yml index 6d69748c6d447..24c7fad53ddd2 100644 --- a/.buildkite/pipelines/pull_request/security_solution/cypress_burn.yml +++ b/.buildkite/pipelines/pull_request/security_solution/cypress_burn.yml @@ -9,6 +9,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 soft_fail: true parallelism: 1 @@ -25,6 +28,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 soft_fail: true parallelism: 1 @@ -39,6 +45,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 1 retry: @@ -53,6 +62,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 50 soft_fail: true retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/defend_workflows.yml b/.buildkite/pipelines/pull_request/security_solution/defend_workflows.yml index fc5e601adad61..ecb07ce4c22a1 100644 --- a/.buildkite/pipelines/pull_request/security_solution/defend_workflows.yml +++ b/.buildkite/pipelines/pull_request/security_solution/defend_workflows.yml @@ -9,6 +9,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 20 retry: @@ -26,6 +29,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 14 retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/detection_engine.yml b/.buildkite/pipelines/pull_request/security_solution/detection_engine.yml index 65a9dc832e1e6..ad3c4dd230cee 100644 --- a/.buildkite/pipelines/pull_request/security_solution/detection_engine.yml +++ b/.buildkite/pipelines/pull_request/security_solution/detection_engine.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 5 retry: @@ -22,6 +25,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 2 retry: @@ -37,6 +43,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 5 retry: @@ -52,6 +61,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 2 retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/entity_analytics.yml b/.buildkite/pipelines/pull_request/security_solution/entity_analytics.yml index 8883f1ab9c038..2f1d30ab97d07 100644 --- a/.buildkite/pipelines/pull_request/security_solution/entity_analytics.yml +++ b/.buildkite/pipelines/pull_request/security_solution/entity_analytics.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 3 retry: @@ -22,6 +25,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 2 retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/explore.yml b/.buildkite/pipelines/pull_request/security_solution/explore.yml index 239021affcf99..5fb3ed443e037 100644 --- a/.buildkite/pipelines/pull_request/security_solution/explore.yml +++ b/.buildkite/pipelines/pull_request/security_solution/explore.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 2 retry: @@ -22,6 +25,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 2 retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/investigations.yml b/.buildkite/pipelines/pull_request/security_solution/investigations.yml index ccd469aedbdbe..c238c8936ad7f 100644 --- a/.buildkite/pipelines/pull_request/security_solution/investigations.yml +++ b/.buildkite/pipelines/pull_request/security_solution/investigations.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 7 retry: @@ -22,6 +25,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 8 retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/osquery_cypress.yml b/.buildkite/pipelines/pull_request/security_solution/osquery_cypress.yml index 5fa8fe359ada6..790d28ff4c472 100644 --- a/.buildkite/pipelines/pull_request/security_solution/osquery_cypress.yml +++ b/.buildkite/pipelines/pull_request/security_solution/osquery_cypress.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 8 retry: @@ -22,6 +25,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 8 retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/playwright.yml b/.buildkite/pipelines/pull_request/security_solution/playwright.yml index 694a7ed588089..213021e02ca06 100644 --- a/.buildkite/pipelines/pull_request/security_solution/playwright.yml +++ b/.buildkite/pipelines/pull_request/security_solution/playwright.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 1 retry: @@ -22,6 +25,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 1 retry: diff --git a/.buildkite/pipelines/pull_request/security_solution/rule_management.yml b/.buildkite/pipelines/pull_request/security_solution/rule_management.yml index 30bd1bd1ff649..8e43f0f4530ef 100644 --- a/.buildkite/pipelines/pull_request/security_solution/rule_management.yml +++ b/.buildkite/pipelines/pull_request/security_solution/rule_management.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 5 retry: @@ -22,6 +25,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 1 retry: @@ -37,6 +43,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 4 retry: @@ -52,6 +61,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 parallelism: 2 retry: diff --git a/.buildkite/pipelines/pull_request/slo_plugin_e2e.yml b/.buildkite/pipelines/pull_request/slo_plugin_e2e.yml index 852ec2f9a0b16..3d1a4f9b46f41 100644 --- a/.buildkite/pipelines/pull_request/slo_plugin_e2e.yml +++ b/.buildkite/pipelines/pull_request/slo_plugin_e2e.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 30 artifact_paths: - 'x-pack/plugins/observability_solution/slo/e2e/.journeys/**/*' diff --git a/.buildkite/pipelines/pull_request/synthetics_plugin.yml b/.buildkite/pipelines/pull_request/synthetics_plugin.yml index 77f330b991ba8..f5d6b841a953d 100644 --- a/.buildkite/pipelines/pull_request/synthetics_plugin.yml +++ b/.buildkite/pipelines/pull_request/synthetics_plugin.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 artifact_paths: - 'x-pack/plugins/observability_solution/synthetics/e2e/.journeys/**/*' diff --git a/.buildkite/pipelines/pull_request/uptime_plugin.yml b/.buildkite/pipelines/pull_request/uptime_plugin.yml index 286c760336132..a03915ef77099 100644 --- a/.buildkite/pipelines/pull_request/uptime_plugin.yml +++ b/.buildkite/pipelines/pull_request/uptime_plugin.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 artifact_paths: - 'x-pack/plugins/observability_solution/synthetics/e2e/.journeys/**/*' diff --git a/.buildkite/pipelines/pull_request/ux_plugin_e2e.yml b/.buildkite/pipelines/pull_request/ux_plugin_e2e.yml index a11309cffb2c2..cd95f44fa2e86 100644 --- a/.buildkite/pipelines/pull_request/ux_plugin_e2e.yml +++ b/.buildkite/pipelines/pull_request/ux_plugin_e2e.yml @@ -7,6 +7,9 @@ steps: depends_on: - build - quick_checks + - linting + - linting_with_types + - check_types timeout_in_minutes: 60 artifact_paths: - 'x-pack/plugins/observability_solution/ux/e2e/.journeys/**/*' diff --git a/.buildkite/pipelines/security_solution_quality_gate/mki_periodic/mki_periodic_detection_engine.yml b/.buildkite/pipelines/security_solution_quality_gate/mki_periodic/mki_periodic_detection_engine.yml index e25c6dfef0e4b..56b1904925f04 100644 --- a/.buildkite/pipelines/security_solution_quality_gate/mki_periodic/mki_periodic_detection_engine.yml +++ b/.buildkite/pipelines/security_solution_quality_gate/mki_periodic/mki_periodic_detection_engine.yml @@ -1,12 +1,12 @@ steps: - - group: "Cypress MKI - Detection Engine" + - group: 'Cypress MKI - Detection Engine' key: cypress_test_detections_engine steps: - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:detection_engine - label: "Cypress MKI - Detection Engine" + label: 'Cypress MKI - Detection Engine' key: test_detection_engine env: - BK_TEST_SUITE_KEY: "serverless-cypress-detection-engine" + BK_TEST_SUITE_KEY: 'serverless-cypress-detection-engine' agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod @@ -18,10 +18,10 @@ steps: parallelism: 8 - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:detection_engine:exceptions - label: "Cypress MKI - Detection Engine - Exceptions" + label: 'Cypress MKI - Detection Engine - Exceptions' key: test_detection_engine_exceptions env: - BK_TEST_SUITE_KEY: "serverless-cypress-detection-engine" + BK_TEST_SUITE_KEY: 'serverless-cypress-detection-engine' agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod @@ -32,7 +32,7 @@ steps: timeout_in_minutes: 300 parallelism: 6 - - group: "API MKI - Detection Engine - " + - group: 'API MKI - Detection Engine - ' key: api_test_detections_engine steps: - label: Running exception_lists_items:qa:serverless @@ -47,7 +47,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running lists_items:qa:serverless @@ -62,7 +62,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running user_roles:qa:serverless @@ -77,7 +77,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running telemetry:qa:serverless @@ -92,7 +92,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running exception_workflows:essentials:qa:serverless @@ -107,12 +107,12 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - - label: Running exception_operators_date_numeric_types:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_date_numeric_types:essentials:qa:serverless - key: exception_operators_date_numeric_types:essentials:qa:serverless + - label: Running exception_operators_date_types:essentials:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_date_types:essentials:qa:serverless + key: exception_operators_date_types:essentials:qa:serverless agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod @@ -122,7 +122,52 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' + limit: 2 + + - label: Running exception_operators_double:essentials:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_double:essentials:qa:serverless + key: exception_operators_double:essentials:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running exception_operators_float:essentials:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_float:essentials:qa:serverless + key: exception_operators_float:essentials:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running exception_operators_integer:essentials:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_integer:essentials:qa:serverless + key: exception_operators_integer:essentials:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' limit: 2 - label: Running exception_operators_keyword:essentials:qa:serverless @@ -137,7 +182,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running exception_operators_ips:essentials:qa:serverless @@ -152,7 +197,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running exception_operators_long:essentials:qa:serverless @@ -167,7 +212,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running exception_operators_text:essentials:qa:serverless @@ -182,7 +227,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running actions:qa:serverless @@ -197,7 +242,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running alerts:qa:serverless @@ -212,7 +257,7 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 - label: Running alerts:essentials:qa:serverless @@ -227,12 +272,117 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' + limit: 2 + + - label: Running rule_execution_logic:eql:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:eql:qa:serverless + key: rule_execution_logic:eql:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_execution_logic:esql:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:esql:qa:serverless + key: rule_execution_logic:esql:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_execution_logic:general_logic:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:general_logic:qa:serverless + key: rule_execution_logic:general_logic:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_execution_logic:indicator_match:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:indicator_match:qa:serverless + key: rule_execution_logic:indicator_match:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_execution_logic:machine_learning:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:machine_learning:qa:serverless + key: rule_execution_logic:machine_learning:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_execution_logic:new_terms:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:new_terms:qa:serverless + key: rule_execution_logic:new_terms:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_execution_logic:query:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:query:qa:serverless + key: rule_execution_logic:query:qa:serverless + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' limit: 2 - - label: Running rule_execution_logic:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:qa:serverless - key: rule_execution_logic:qa:serverless + - label: Running rule_execution_logic:threshold:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:threshold:qa:serverless + key: rule_execution_logic:threshold:qa:serverless agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod @@ -242,5 +392,5 @@ steps: timeout_in_minutes: 120 retry: automatic: - - exit_status: "1" + - exit_status: '1' limit: 2 diff --git a/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_detection_engine.yml b/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_detection_engine.yml index 90c90ae8a3a36..023099dd99392 100644 --- a/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_detection_engine.yml +++ b/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_detection_engine.yml @@ -103,9 +103,51 @@ steps: - exit_status: "1" limit: 2 - - label: Running exception_operators_date_numeric_types:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_date_numeric_types:essentials:qa:serverless:release - key: exception_operators_date_numeric_types:essentials:qa:serverless:release + - label: Running exception_operators_date_types:essentials:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_date_types:essentials:qa:serverless:release + key: exception_operators_date_types:essentials:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running exception_operators_double:essentials:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_double:essentials:qa:serverless:release + key: exception_operators_double:essentials:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running exception_operators_float:essentials:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_float:essentials:qa:serverless:release + key: exception_operators_float:essentials:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running exception_operators_integer:essentials:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_integer:essentials:qa:serverless:release + key: exception_operators_integer:essentials:qa:serverless:release agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod @@ -215,9 +257,107 @@ steps: - exit_status: "1" limit: 2 - - label: Running rule_execution_logic:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:qa:serverless:release - key: rule_execution_logic:qa:serverless:release + - label: Running rule_execution_logic:eql:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:eql:qa:serverless:release + key: rule_execution_logic:eql:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running rule_execution_logic:esql:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:esql:qa:serverless:release + key: rule_execution_logic:esql:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running rule_execution_logic:general_logic:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:general_logic:qa:serverless:release + key: rule_execution_logic:general_logic:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running rule_execution_logic:indicator_match:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:indicator_match:qa:serverless:release + key: rule_execution_logic:indicator_match:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running rule_execution_logic:machine_learning:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:machine_learning:qa:serverless:release + key: rule_execution_logic:machine_learning:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running rule_execution_logic:new_terms:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:new_terms:qa:serverless:release + key: rule_execution_logic:new_terms:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running rule_execution_logic:query:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:query:qa:serverless:release + key: rule_execution_logic:query:qa:serverless:release + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: "1" + limit: 2 + + - label: Running rule_execution_logic:threshold:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:threshold:qa:serverless:release + key: rule_execution_logic:threshold:qa:serverless:release agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod diff --git a/.buildkite/pipelines/serverless_deployment/project-build-and-deploy-pr.yml b/.buildkite/pipelines/serverless_deployment/project-build-and-deploy-pr.yml index f7fc94ac444e1..04b738ff363e1 100644 --- a/.buildkite/pipelines/serverless_deployment/project-build-and-deploy-pr.yml +++ b/.buildkite/pipelines/serverless_deployment/project-build-and-deploy-pr.yml @@ -1,53 +1,72 @@ -agents: - provider: gcp - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod +env: + ELASTIC_PR_COMMENTS_ENABLED: 'true' + GITHUB_BUILD_COMMIT_STATUS_ENABLED: 'true' + GITHUB_BUILD_COMMIT_STATUS_CONTEXT: kibana-deploy-project-from-pr steps: - - command: .buildkite/scripts/lifecycle/pre_build.sh - label: Pre-Build - timeout_in_minutes: 10 - agents: - machineType: n2-standard-2 - retry: - automatic: - - exit_status: '*' - limit: 1 - - - wait: ~ - - - command: .buildkite/scripts/steps/build_kibana.sh - label: Build Kibana Distribution and Plugins - agents: - machineType: n2-standard-16 - preemptible: true - key: build - if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" - timeout_in_minutes: 90 - retry: - automatic: - - exit_status: '-1' - limit: 3 - - - wait: ~ - - - command: .buildkite/scripts/steps/artifacts/docker_image.sh - label: 'Build Project Image' - key: build_project_image - agents: - machineType: n2-standard-16 - preemptible: true - timeout_in_minutes: 60 - retry: - automatic: - - exit_status: '-1' - limit: 3 - - - wait: ~ - - - command: .buildkite/scripts/steps/serverless/deploy.sh - label: 'Deploy Project' - agents: - machineType: n2-standard-4 - preemptible: true - timeout_in_minutes: 10 + - group: 'Project Deployment' + if: "build.env('GITHUB_PR_LABELS') =~ /ci:project-deploy-(elasticsearch|observability|security)/" + + steps: + - command: .buildkite/scripts/lifecycle/pre_build.sh + label: Pre-Build + timeout_in_minutes: 10 + agents: + provider: gcp + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + machineType: n2-standard-2 + retry: + automatic: + - exit_status: '*' + limit: 1 + + - command: | + ts-node .buildkite/scripts/lifecycle/comment_on_pr.ts "PR Project deployment started at: $BUILDKITE_BUILD_URL" + label: Comment with job URL + agents: + provider: gcp + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + machineType: n2-standard-2 + timeout_in_minutes: 5 + + - wait: ~ + + - command: .buildkite/scripts/steps/artifacts/docker_image.sh + label: 'Build Project Image' + key: build_project_image + agents: + provider: gcp + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + machineType: n2-standard-16 + preemptible: true + timeout_in_minutes: 60 + retry: + automatic: + - exit_status: '-1' + limit: 3 + + - wait: ~ + - command: .buildkite/scripts/steps/serverless/deploy.sh + label: 'Deploy Project' + agents: + provider: gcp + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + machineType: n2-standard-4 + preemptible: true + timeout_in_minutes: 10 + + - wait: ~ + + - command: | + ts-node .buildkite/scripts/lifecycle/comment_on_pr.ts "Project deployed, see credentials at: $BUILDKITE_BUILD_URL" + label: Comment with job URL + agents: + provider: gcp + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + machineType: n2-standard-2 + timeout_in_minutes: 5 diff --git a/.buildkite/pull_requests.json b/.buildkite/pull_requests.json index 20785e92be1b5..cbc0e9df03dc8 100644 --- a/.buildkite/pull_requests.json +++ b/.buildkite/pull_requests.json @@ -49,14 +49,15 @@ "repoOwner": "elastic", "repoName": "kibana", "pipelineSlug": "kibana-deploy-project-from-pr", - + "skip_ci_labels": [], "enabled": true, "allow_org_users": true, "allowed_repo_permissions": ["admin", "write"], "allowed_list": ["elastic-vault-github-plugin-prod[bot]"], - "set_commit_status": false, + "set_commit_status": true, + "commit_status_context": "kibana-deploy-project-from-pr", "build_on_commit": false, - "build_on_comment": false, + "build_on_comment": true, "build_drafts": false, "trigger_comment_regex": "^(?:(?:buildkite\\W+)?(?:deploy)\\W+(?:project))$", "kibana_versions_check": true, diff --git a/.buildkite/scripts/lifecycle/comment_on_pr.ts b/.buildkite/scripts/lifecycle/comment_on_pr.ts new file mode 100644 index 0000000000000..39ebd511d8410 --- /dev/null +++ b/.buildkite/scripts/lifecycle/comment_on_pr.ts @@ -0,0 +1,64 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { addComment } from '#pipeline-utils'; + +const ALLOWED_ENV_VARS = [ + 'BUILDKITE_BRANCH', + 'BUILDKITE_BUILD_ID', + 'BUILDKITE_BUILD_NUMBER', + 'BUILDKITE_BUILD_URL', + 'BUILDKITE_COMMIT', + 'BUILDKITE_PIPELINE_NAME', + 'BUILDKITE_PIPELINE_SLUG', + 'GITHUB_PR_BASE_OWNER', + 'GITHUB_PR_BASE_REPO', + 'GITHUB_PR_BRANCH', + 'GITHUB_PR_HEAD_SHA', + 'GITHUB_PR_HEAD_USER', + 'GITHUB_PR_LABELS', + 'GITHUB_PR_NUMBER', + 'GITHUB_PR_OWNER', + 'GITHUB_PR_REPO', + 'GITHUB_PR_TARGET_BRANCH', + 'GITHUB_PR_TRIGGERED_SHA', + 'GITHUB_PR_TRIGGER_USER', + 'GITHUB_PR_USER', +]; +const DEFAULT_MESSAGE_TEMPLATE = + '🚀 Buildkite job started for PR #${GITHUB_PR_NUMBER}: ${BUILDKITE_BUILD_URL}'; + +export function commentOnPR() { + const messageTemplate = + process.argv.slice(2)?.join(' ') || + process.env.JOB_START_COMMENT_TEMPLATE || + DEFAULT_MESSAGE_TEMPLATE; + if (messageTemplate === DEFAULT_MESSAGE_TEMPLATE) { + console.log('No message template provided, using default message'); + } else { + console.log(`Using message template: ${messageTemplate}`); + } + + const message = messageTemplate.replace(/\${([^}]+)}/g, (_, envVar) => { + if (ALLOWED_ENV_VARS.includes(envVar)) { + return process.env[envVar] || ''; + } else { + return '${' + envVar + '}'; + } + }); + + return addComment(message); +} + +if (require.main === module) { + commentOnPR().catch((error) => { + console.error(error); + process.exit(1); + }); +} diff --git a/.buildkite/scripts/steps/checks.sh b/.buildkite/scripts/steps/checks.sh index 8d62a305dd535..ce7dec4f36e8d 100755 --- a/.buildkite/scripts/steps/checks.sh +++ b/.buildkite/scripts/steps/checks.sh @@ -4,6 +4,7 @@ set -euo pipefail export DISABLE_BOOTSTRAP_VALIDATION=false .buildkite/scripts/bootstrap.sh +.buildkite/scripts/copy_es_snapshot_cache.sh if [[ "${FTR_ENABLE_FIPS_AGENT:-}" == "true" ]]; then .buildkite/scripts/steps/checks/verify_fips_enabled.sh diff --git a/.buildkite/scripts/steps/checks/capture_oas_snapshot.sh b/.buildkite/scripts/steps/checks/capture_oas_snapshot.sh index 0c0f7ac996bba..e9f42d67008ea 100755 --- a/.buildkite/scripts/steps/checks/capture_oas_snapshot.sh +++ b/.buildkite/scripts/steps/checks/capture_oas_snapshot.sh @@ -2,10 +2,11 @@ set -euo pipefail -.buildkite/scripts/bootstrap.sh - source .buildkite/scripts/common/util.sh +.buildkite/scripts/bootstrap.sh +.buildkite/scripts/copy_es_snapshot_cache.sh + echo --- Capture OAS snapshot cmd="node scripts/capture_oas_snapshot --include-path /api/status --include-path /api/alerting/rule/ --include-path /api/alerting/rules --include-path /api/actions --include-path /api/security/role --include-path /api/spaces --include-path /api/fleet" if is_pr && ! is_auto_commit_disabled; then diff --git a/.buildkite/scripts/steps/checks/i18n.sh b/.buildkite/scripts/steps/checks/i18n.sh index 090512e391d7c..f23ed2d63759e 100755 --- a/.buildkite/scripts/steps/checks/i18n.sh +++ b/.buildkite/scripts/steps/checks/i18n.sh @@ -5,4 +5,4 @@ set -euo pipefail source .buildkite/scripts/common/util.sh echo --- Check i18n -node scripts/i18n_check +node scripts/i18n_check --quiet diff --git a/.buildkite/scripts/steps/checks/quick_checks.txt b/.buildkite/scripts/steps/checks/quick_checks.txt index e0196950b4a75..9bd9224673905 100644 --- a/.buildkite/scripts/steps/checks/quick_checks.txt +++ b/.buildkite/scripts/steps/checks/quick_checks.txt @@ -1,4 +1,3 @@ -.buildkite/scripts/steps/checks/precommit_hook.sh .buildkite/scripts/steps/checks/ts_projects.sh .buildkite/scripts/steps/checks/packages.sh .buildkite/scripts/steps/checks/bazel_packages.sh diff --git a/.buildkite/scripts/steps/cloud/build_and_deploy.sh b/.buildkite/scripts/steps/cloud/build_and_deploy.sh index 220ab497aaf7b..e2a55b03ebf64 100755 --- a/.buildkite/scripts/steps/cloud/build_and_deploy.sh +++ b/.buildkite/scripts/steps/cloud/build_and_deploy.sh @@ -19,7 +19,7 @@ download_artifact "kibana-$VERSION-linux-x86_64.tar.gz" ./target --build "${KIBA echo "--- Build Cloud Distribution" ELASTICSEARCH_MANIFEST_URL="https://storage.googleapis.com/kibana-ci-es-snapshots-daily/$(jq -r '.version' package.json)/manifest-latest-verified.json" ELASTICSEARCH_SHA=$(curl -s $ELASTICSEARCH_MANIFEST_URL | jq -r '.sha') -ELASTICSEARCH_CLOUD_IMAGE="docker.elastic.co/kibana-ci/elasticsearch-cloud:$VERSION-$ELASTICSEARCH_SHA" +ELASTICSEARCH_CLOUD_IMAGE="docker.elastic.co/kibana-ci/elasticsearch-cloud-ess:$VERSION-$ELASTICSEARCH_SHA" KIBANA_CLOUD_IMAGE="docker.elastic.co/kibana-ci/kibana-cloud:$VERSION-$GIT_COMMIT" CLOUD_DEPLOYMENT_NAME="kibana-pr-$BUILDKITE_PULL_REQUEST" diff --git a/.buildkite/scripts/steps/es_snapshots/build.sh b/.buildkite/scripts/steps/es_snapshots/build.sh index d9d685338250f..0485763b0e918 100755 --- a/.buildkite/scripts/steps/es_snapshots/build.sh +++ b/.buildkite/scripts/steps/es_snapshots/build.sh @@ -85,11 +85,11 @@ echo "--- Create kibana-ci docker cloud image archives" # When we bump versions, these dependencies may not exist yet, but we don't want to # block the rest of the snapshot promotion process set +e -./gradlew :distribution:docker:cloud-docker-export:assemble && { - ES_CLOUD_ID=$(docker images "docker.elastic.co/elasticsearch-ci/elasticsearch-cloud" --format "{{.ID}}") - ES_CLOUD_VERSION=$(docker images "docker.elastic.co/elasticsearch-ci/elasticsearch-cloud" --format "{{.Tag}}") +./gradlew :distribution:docker:cloud-ess-docker-export:assemble && { + ES_CLOUD_ID=$(docker images "docker.elastic.co/elasticsearch/elasticsearch-cloud-ess" --format "{{.ID}}") + ES_CLOUD_VERSION=$(docker images "docker.elastic.co/elasticsearch/elasticsearch-cloud-ess" --format "{{.Tag}}") KIBANA_ES_CLOUD_VERSION="$ES_CLOUD_VERSION-$ELASTICSEARCH_GIT_COMMIT" - KIBANA_ES_CLOUD_IMAGE="docker.elastic.co/kibana-ci/elasticsearch-cloud:$KIBANA_ES_CLOUD_VERSION" + KIBANA_ES_CLOUD_IMAGE="docker.elastic.co/kibana-ci/elasticsearch-cloud-ess:$KIBANA_ES_CLOUD_VERSION" echo $ES_CLOUD_ID $ES_CLOUD_VERSION $KIBANA_ES_CLOUD_VERSION $KIBANA_ES_CLOUD_IMAGE docker tag "$ES_CLOUD_ID" "$KIBANA_ES_CLOUD_IMAGE" diff --git a/.buildkite/scripts/steps/functional/apm_cypress.sh b/.buildkite/scripts/steps/functional/apm_cypress.sh index 976c551dfe19a..1fc10089e8eb4 100755 --- a/.buildkite/scripts/steps/functional/apm_cypress.sh +++ b/.buildkite/scripts/steps/functional/apm_cypress.sh @@ -8,6 +8,7 @@ APM_CYPRESS_RECORD_KEY="$(vault_get apm-cypress-dashboard-record-key CYPRESS_REC .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-apm-cypress IS_FLAKY_TEST_RUNNER=${CLI_COUNT:-0} diff --git a/.buildkite/scripts/steps/functional/defend_workflows_burn.sh b/.buildkite/scripts/steps/functional/defend_workflows_burn.sh index 643a8d9f4ec53..6a97ba4e82b33 100644 --- a/.buildkite/scripts/steps/functional/defend_workflows_burn.sh +++ b/.buildkite/scripts/steps/functional/defend_workflows_burn.sh @@ -5,6 +5,7 @@ set -euo pipefail source .buildkite/scripts/steps/functional/common.sh .buildkite/scripts/bootstrap.sh +.buildkite/scripts/copy_es_snapshot_cache.sh node scripts/build_kibana_platform_plugins.js export JOB=kibana-defend-workflows-cypress diff --git a/.buildkite/scripts/steps/functional/defend_workflows_serverless_burn.sh b/.buildkite/scripts/steps/functional/defend_workflows_serverless_burn.sh index 3f85a9b051845..4bebee15953e6 100644 --- a/.buildkite/scripts/steps/functional/defend_workflows_serverless_burn.sh +++ b/.buildkite/scripts/steps/functional/defend_workflows_serverless_burn.sh @@ -5,6 +5,7 @@ set -euo pipefail source .buildkite/scripts/steps/functional/common.sh .buildkite/scripts/bootstrap.sh +.buildkite/scripts/copy_es_snapshot_cache.sh node scripts/build_kibana_platform_plugins.js export JOB=kibana-defend-workflows-serverless-cypress diff --git a/.buildkite/scripts/steps/functional/exploratory_view_plugin.sh b/.buildkite/scripts/steps/functional/exploratory_view_plugin.sh index d14033883312f..adee8986bc746 100755 --- a/.buildkite/scripts/steps/functional/exploratory_view_plugin.sh +++ b/.buildkite/scripts/steps/functional/exploratory_view_plugin.sh @@ -6,6 +6,7 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-observability-plugin diff --git a/.buildkite/scripts/steps/functional/inventory_cypress.sh b/.buildkite/scripts/steps/functional/inventory_cypress.sh index b238b62c9c1fe..b45215ca86505 100644 --- a/.buildkite/scripts/steps/functional/inventory_cypress.sh +++ b/.buildkite/scripts/steps/functional/inventory_cypress.sh @@ -6,6 +6,7 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-inventory-onboarding-cypress diff --git a/.buildkite/scripts/steps/functional/observability_onboarding_cypress.sh b/.buildkite/scripts/steps/functional/observability_onboarding_cypress.sh index 095ef5c723392..802bb447f72d2 100644 --- a/.buildkite/scripts/steps/functional/observability_onboarding_cypress.sh +++ b/.buildkite/scripts/steps/functional/observability_onboarding_cypress.sh @@ -6,6 +6,7 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-observability-onboarding-cypress diff --git a/.buildkite/scripts/steps/functional/profiling_cypress.sh b/.buildkite/scripts/steps/functional/profiling_cypress.sh index daad169069ae3..4e5fb770a12b4 100644 --- a/.buildkite/scripts/steps/functional/profiling_cypress.sh +++ b/.buildkite/scripts/steps/functional/profiling_cypress.sh @@ -6,6 +6,7 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-profiling-cypress diff --git a/.buildkite/scripts/steps/functional/slo_plugin_e2e.sh b/.buildkite/scripts/steps/functional/slo_plugin_e2e.sh index 95007fbff85bf..0492e41ae7041 100755 --- a/.buildkite/scripts/steps/functional/slo_plugin_e2e.sh +++ b/.buildkite/scripts/steps/functional/slo_plugin_e2e.sh @@ -6,6 +6,7 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-ux-plugin-synthetics diff --git a/.buildkite/scripts/steps/functional/synthetics.sh b/.buildkite/scripts/steps/functional/synthetics.sh index 3d22131701762..aa388096fc404 100644 --- a/.buildkite/scripts/steps/functional/synthetics.sh +++ b/.buildkite/scripts/steps/functional/synthetics.sh @@ -6,6 +6,7 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-uptime-playwright diff --git a/.buildkite/scripts/steps/functional/synthetics_plugin.sh b/.buildkite/scripts/steps/functional/synthetics_plugin.sh index 5ad02174ccd26..3e31b92011ad2 100755 --- a/.buildkite/scripts/steps/functional/synthetics_plugin.sh +++ b/.buildkite/scripts/steps/functional/synthetics_plugin.sh @@ -6,6 +6,7 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-synthetics-plugin diff --git a/.buildkite/scripts/steps/functional/uptime_plugin.sh b/.buildkite/scripts/steps/functional/uptime_plugin.sh index 3122953862c73..b4cdd0fb5738a 100755 --- a/.buildkite/scripts/steps/functional/uptime_plugin.sh +++ b/.buildkite/scripts/steps/functional/uptime_plugin.sh @@ -6,6 +6,7 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-uptime-plugin diff --git a/.buildkite/scripts/steps/functional/ux_synthetics_e2e.sh b/.buildkite/scripts/steps/functional/ux_synthetics_e2e.sh index dbb3289f604e5..bcc5b71149607 100755 --- a/.buildkite/scripts/steps/functional/ux_synthetics_e2e.sh +++ b/.buildkite/scripts/steps/functional/ux_synthetics_e2e.sh @@ -6,6 +6,7 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh +.buildkite/scripts/copy_es_snapshot_cache.sh export JOB=kibana-ux-plugin-synthetics diff --git a/.buildkite/scripts/steps/lint.sh b/.buildkite/scripts/steps/lint.sh index 05eb3bb602d84..70ab323c9f731 100755 --- a/.buildkite/scripts/steps/lint.sh +++ b/.buildkite/scripts/steps/lint.sh @@ -15,9 +15,9 @@ echo '--- Lint: eslint' # after possibly commiting fixed files to the repo set +e; if is_pr && ! is_auto_commit_disabled; then - git ls-files | grep -E '\.(js|mjs|ts|tsx)$' | xargs -n 250 -P 4 node scripts/eslint --no-cache --fix + git ls-files | grep -E '\.(js|mjs|ts|tsx)$' | xargs -n 250 -P 8 node scripts/eslint --no-cache --fix else - git ls-files | grep -E '\.(js|mjs|ts|tsx)$' | xargs -n 250 -P 4 node scripts/eslint --no-cache + git ls-files | grep -E '\.(js|mjs|ts|tsx)$' | xargs -n 250 -P 8 node scripts/eslint --no-cache fi eslint_exit=$? diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 5f925468ac716..725570d958f0c 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,7 @@ FROM mcr.microsoft.com/devcontainers/base:ubuntu-22.04 +ARG KBN_DIR + ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8 ENV HOME=/home/vscode ENV NVM_DIR=${HOME}/nvm @@ -67,8 +69,8 @@ RUN mkdir -p $NVM_DIR && \ USER root # Reload the env everytime a new shell is opened incase the .env file changed. -RUN echo "source $KBN_DIR/.devcontainer/scripts/env.sh" >> ${HOME}/.bashrc && \ - echo "source $KBN_DIR/.devcontainer/scripts/env.sh" >> ${HOME}/.zshrc +RUN echo "source ${KBN_DIR}/.devcontainer/scripts/env.sh" >> ${HOME}/.bashrc && \ + echo "source ${KBN_DIR}/.devcontainer/scripts/env.sh" >> ${HOME}/.zshrc # This is for documentation. Ports are exposed via devcontainer.json EXPOSE 9200 5601 9229 9230 9231 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 932c16ddb293d..1b8f51120dae9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,7 +2,10 @@ "name": "Kibana", "build": { "dockerfile": "Dockerfile", - "context": ".." + "context": "..", + "args": { + "KBN_DIR": "${containerWorkspaceFolder}" + } }, "customizations": { "vscode": { diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 80d9c8b64e9e6..10250b18541c8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -525,6 +525,7 @@ x-pack/plugins/index_management @elastic/kibana-management x-pack/packages/index-management/index_management_shared_types @elastic/kibana-management test/plugin_functional/plugins/index_patterns @elastic/kibana-data-discovery x-pack/packages/ml/inference_integration_flyout @elastic/ml-ui +x-pack/packages/ai-infra/inference-common @elastic/appex-ai-infra x-pack/plugins/inference @elastic/appex-ai-infra x-pack/packages/kbn-infra-forge @elastic/obs-ux-management-team x-pack/plugins/observability_solution/infra @elastic/obs-ux-logs-team @elastic/obs-ux-infra_services-team @@ -1034,6 +1035,8 @@ x-pack/test_serverless/api_integration/test_suites/common/platform_security @ela /x-pack/test/api_integration/apis/entity_manager @elastic/obs-entities # Data Discovery +/test/plugin_functional/plugins/data_search @elastic/kibana-data-discovery +/test/plugin_functional/plugins/index_patterns @elastic/kibana-data-discovery /x-pack/test/api_integration/apis/kibana/kql_telemetry @elastic/kibana-data-discovery @elastic/kibana-visualizations /x-pack/test_serverless/functional/es_archives/pre_calculated_histogram @elastic/kibana-data-discovery /x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern @elastic/kibana-data-discovery @@ -1090,10 +1093,12 @@ src/plugins/discover/public/context_awareness/profile_providers/security @elasti # Platform Docs /x-pack/test_serverless/functional/test_suites/security/screenshot_creation/index.ts @elastic/platform-docs /x-pack/test_serverless/functional/test_suites/security/config.screenshots.ts @elastic/platform-docs +/x-pack/test/screenshot_creation @elastic/platform-docs # Visualizations /x-pack/test/accessibility/apps/group3/graph.ts @elastic/kibana-visualizations /x-pack/test/accessibility/apps/group2/lens.ts @elastic/kibana-visualizations +/x-pack/test/functional/apps/visualize @elastic/kibana-visualizations /src/plugins/visualize/ @elastic/kibana-visualizations /x-pack/test/functional/apps/lens @elastic/kibana-visualizations /x-pack/test/api_integration/apis/lens/ @elastic/kibana-visualizations @@ -1159,6 +1164,7 @@ x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai ## This should allow the infra team to work without dependencies on the @elastic/obs-ux-logs-team, which will maintain ownership of the Logs UI code only. ## infra/{common,docs,public,server}/{sub-folders}/ -> @elastic/obs-ux-infra_services-team +/test/common/plugins/otel_metrics @elastic/obs-ux-infra_services-team /x-pack/plugins/observability_solution/infra/common @elastic/obs-ux-infra_services-team /x-pack/plugins/observability_solution/infra/docs @elastic/obs-ux-infra_services-team /x-pack/plugins/observability_solution/infra/public/alerting @elastic/obs-ux-infra_services-team @@ -1224,6 +1230,7 @@ x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai /x-pack/test_serverless/**/test_suites/observability/infra/ @elastic/obs-ux-infra_services-team # Elastic Stack Monitoring +/x-pack/test/functional/services/monitoring @elastic/stack-monitoring /x-pack/test/functional/apps/monitoring @elastic/stack-monitoring /x-pack/test/api_integration/apis/monitoring @elastic/stack-monitoring /x-pack/test/api_integration/apis/monitoring_collection @elastic/stack-monitoring @@ -1231,6 +1238,7 @@ x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai /x-pack/test/accessibility/apps/group3/stack_monitoring.ts @elastic/stack-monitoring # Fleet +/x-pack/test/fleet_packages @elastic/fleet /x-pack/test/fleet_api_integration @elastic/fleet /x-pack/test/fleet_cypress @elastic/fleet /x-pack/test/fleet_functional @elastic/fleet @@ -1260,6 +1268,7 @@ x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai /x-pack/test_serverless/api_integration/test_suites/observability/synthetics @elastic/obs-ux-management-team # obs-ux-logs-team +/x-pack/test/observability_onboarding_api_integration @elastic/obs-ux-logs-team /x-pack/test_serverless/api_integration/test_suites/observability/index.feature_flags.ts @elastic/obs-ux-logs-team /x-pack/test/api_integration/apis/logs_ui @elastic/obs-ux-logs-team /x-pack/test/dataset_quality_api_integration @elastic/obs-ux-logs-team @@ -1313,12 +1322,17 @@ x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai /x-pack/test/screenshot_creation/services/ml_screenshots.ts @elastic/ml-ui /x-pack/test_serverless/**/test_suites/**/ml/ @elastic/ml-ui /x-pack/test_serverless/**/test_suites/common/management/transforms/ @elastic/ml-ui +/x-pack/test/api_integration/services/ml.ts @elastic/ml-ui # Additional plugins and packages maintained by the ML team. /x-pack/test/accessibility/apps/group2/transform.ts @elastic/ml-ui /x-pack/test/api_integration/apis/aiops/ @elastic/ml-ui /x-pack/test/api_integration/apis/transform/ @elastic/ml-ui +/x-pack/test/api_integration_basic/apis/aiops @elastic/ml-ui /x-pack/test/api_integration_basic/apis/transform/ @elastic/ml-ui +/x-pack/test/api_integration/services/aiops.ts @elastic/ml-ui +/x-pack/test/api_integration/services/transform.ts @elastic/ml-ui +/x-pack/test/functional/apps/aiops @elastic/ml-ui /x-pack/test/functional/apps/transform/ @elastic/ml-ui /x-pack/test/functional/services/transform/ @elastic/ml-ui /x-pack/test/functional_basic/apps/transform/ @elastic/ml-ui @@ -1360,6 +1374,8 @@ x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai /.eslintignore @elastic/kibana-operations # Appex QA +/x-pack/test/scalability @elastic/appex-qa +/src/dev/performance @elastic/appex-qa /x-pack/test/functional/config.*.* @elastic/appex-qa /x-pack/test/api_integration/ftr_provider_context.d.ts @elastic/appex-qa # Maybe this should be a glob? /x-pack/test/accessibility/services.ts @elastic/appex-qa @@ -1398,6 +1414,14 @@ x-pack/test/api_integration/deployment_agnostic/services/ @elastic/appex-qa x-pack/test/**/deployment_agnostic/ @elastic/appex-qa #temporarily to monitor tests migration # Core +/test/plugin_functional/plugins/rendering_plugin @elastic/kibana-core +/test/plugin_functional/plugins/session_notifications @elastic/kibana-core +/x-pack/test/cloud_integration/plugins/saml_provider @elastic/kibana-core +/x-pack/test/functional_embedded/plugins/iframe_embedded @elastic/kibana-core +/x-pack/test/functional/apps/saved_objects_management @elastic/kibana-core +/x-pack/test/usage_collection @elastic/kibana-core +/x-pack/test/licensing_plugin @elastic/kibana-core +/x-pack/test/functional_execution_context @elastic/kibana-core /x-pack/test/api_integration/apis/telemetry @elastic/kibana-core /x-pack/test/api_integration/apis/status @elastic/kibana-core /x-pack/test/api_integration/apis/stats @elastic/kibana-core @@ -1484,6 +1508,10 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib #CC# /x-pack/plugins/security/ @elastic/kibana-security # Response Ops team +/x-pack/test/examples/triggers_actions_ui_examples @elastic/response-ops +/x-pack/test/functional_with_es_ssl/plugins/cases @elastic/response-ops +/x-pack/test/screenshot_creation/apps/response_ops_docs @elastic/response-ops +/x-pack/test/rule_registry @elastic/response-ops @elastic/obs-ux-management-team /x-pack/test/accessibility/apps/group3/rules_connectors.ts @elastic/response-ops /x-pack/test/functional/es_archives/cases/default @elastic/response-ops /x-pack/test_serverless/api_integration/test_suites/observability/config.ts @elastic/response-ops @@ -1541,6 +1569,9 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints /x-pack/test/functional_search/ @elastic/search-kibana # Management Experience - Deployment Management +/x-pack/test/functional/apps/license_management @elastic/kibana-management +/x-pack/test/functional/apps/painless_lab @elastic/kibana-management +/x-pack/test/functional/apps/management @elastic/kibana-management /x-pack/test/api_integration/services/index_management.ts @elastic/kibana-management /x-pack/test/functional/services/grok_debugger.js @elastic/kibana-management /x-pack/test/functional/apps/grok_debugger @elastic/kibana-management @@ -1860,6 +1891,7 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/common/components/threat_match @elastic/security-detection-engine ## Security Solution sub teams - security-defend-workflows +/x-pack/test/defend_workflows_cypress @elastic/security-defend-workflows /x-pack/test/api_integration/apis/osquery @elastic/security-defend-workflows /x-pack/plugins/security_solution/public/management/ @elastic/security-defend-workflows /x-pack/plugins/security_solution/public/common/lib/endpoint/ @elastic/security-defend-workflows @@ -1915,6 +1947,7 @@ x-pack/plugins/osquery @elastic/security-defend-workflows # Cloud Security Posture x-pack/packages/kbn-cloud-security-posture @elastic/kibana-cloud-security-posture +/x-pack/test/kubernetes_security @elastic/kibana-cloud-security-posture /x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.* @elastic/kibana-cloud-security-posture /x-pack/plugins/security_solution/public/cloud_security_posture @elastic/kibana-cloud-security-posture /x-pack/test/api_integration/apis/cloud_security_posture/ @elastic/kibana-cloud-security-posture @@ -1961,6 +1994,7 @@ x-pack/plugins/security_solution/server/lib/security_integrations @elastic/secur # Logstash /x-pack/test/api_integration/apis/logstash @elastic/logstash +/x-pack/test/functional/apps/logstash @elastic/logstash #CC# /x-pack/plugins/logstash/ @elastic/logstash # EUI team @@ -1979,9 +2013,16 @@ x-pack/test/profiling_api_integration @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/observability_shared/public/components/profiling @elastic/obs-ux-infra_services-team # Shared UX -/x-pack/test/api_integration/apis/content_management @elastic/appex-sharedux -/x-pack/test/accessibility/apps/group3/tags.ts @elastic/appex-sharedux +/test/examples/content_management @elastic/appex-sharedux +/test/plugin_functional/plugins/kbn_sample_panel_action @elastic/appex-sharedux +/test/functional/apps/kibana_overview @elastic/appex-sharedux +/test/plugin_functional/plugins/eui_provider_dev_warning @elastic/appex-sharedux +/x-pack/test/banners_functional @elastic/appex-sharedux +/x-pack/test/custom_branding @elastic/appex-sharedux /x-pack/test/accessibility/apps/group3/snapshot_and_restore.ts @elastic/appex-sharedux +/x-pack/test/accessibility/apps/group3/tags.ts @elastic/appex-sharedux +/x-pack/test/api_integration/apis/content_management @elastic/appex-sharedux +/x-pack/test/functional_solution_sidenav @elastic/appex-sharedux /x-pack/test_serverless/functional/test_suites/common/spaces/spaces_selection.ts @elastic/appex-sharedux /x-pack/test_serverless/functional/test_suites/common/spaces/index.ts @elastic/appex-sharedux packages/react @elastic/appex-sharedux diff --git a/.github/workflows/updatecli-compose.yml b/.github/workflows/updatecli-compose.yml index cbab42d3a63b1..44a937db3fa6d 100644 --- a/.github/workflows/updatecli-compose.yml +++ b/.github/workflows/updatecli-compose.yml @@ -11,6 +11,7 @@ permissions: jobs: compose: + if: github.event.repository.fork == false runs-on: ubuntu-latest permissions: contents: write diff --git a/.gitignore b/.gitignore index 7e06f1e23f863..9bda927a92b6a 100644 --- a/.gitignore +++ b/.gitignore @@ -157,4 +157,5 @@ x-pack/test/security_solution_playwright/playwright-report/ x-pack/test/security_solution_playwright/blob-report/ x-pack/test/security_solution_playwright/playwright/.cache/ x-pack/test/security_solution_playwright/.auth/ -x-pack/test/security_solution_playwright/.env \ No newline at end of file +x-pack/test/security_solution_playwright/.env +.codeql diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 0e8f3acdf40b0..1db0e7083bdc4 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 502eaa848e05f..64b36694e13b6 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; -Contact [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) for questions regarding this plugin. +Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/ai_assistant_management_selection.mdx b/api_docs/ai_assistant_management_selection.mdx index 97bb4414983cf..33f787510f89a 100644 --- a/api_docs/ai_assistant_management_selection.mdx +++ b/api_docs/ai_assistant_management_selection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiAssistantManagementSelection title: "aiAssistantManagementSelection" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementSelection plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 2c71a66c0921b..ca23ed3fa827b 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index 298ef15ab0e39..e1d6edb818426 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -3302,7 +3302,7 @@ "label": "monitoring", "description": [], "signature": [ - "Readonly<{} & { run: Readonly<{} & { history: Readonly<{ outcome?: Readonly<{ warning?: \"execute\" | \"validate\" | \"unknown\" | \"license\" | \"ruleExecution\" | \"timeout\" | \"read\" | \"decrypt\" | \"disabled\" | \"maxExecutableActions\" | \"maxAlerts\" | \"maxQueuedActions\" | null | undefined; outcomeOrder?: number | undefined; outcomeMsg?: string[] | null | undefined; } & { outcome: \"warning\" | \"succeeded\" | \"failed\"; alertsCount: Readonly<{ recovered?: number | null | undefined; active?: number | null | undefined; new?: number | null | undefined; ignored?: number | null | undefined; } & {}>; }> | undefined; duration?: number | undefined; } & { timestamp: number; success: boolean; }>[]; calculated_metrics: Readonly<{ p50?: number | undefined; p95?: number | undefined; p99?: number | undefined; } & { success_ratio: number; }>; last_run: Readonly<{} & { timestamp: string; metrics: Readonly<{ duration?: number | undefined; total_search_duration_ms?: number | null | undefined; total_indexing_duration_ms?: number | null | undefined; total_alerts_detected?: number | null | undefined; total_alerts_created?: number | null | undefined; gap_duration_s?: number | null | undefined; } & {}>; }>; }>; }> | undefined" + "Readonly<{} & { run: Readonly<{} & { history: Readonly<{ outcome?: \"warning\" | \"succeeded\" | \"failed\" | undefined; duration?: number | undefined; } & { timestamp: number; success: boolean; }>[]; calculated_metrics: Readonly<{ p50?: number | undefined; p95?: number | undefined; p99?: number | undefined; } & { success_ratio: number; }>; last_run: Readonly<{} & { timestamp: string; metrics: Readonly<{ duration?: number | undefined; total_search_duration_ms?: number | null | undefined; total_indexing_duration_ms?: number | null | undefined; total_alerts_detected?: number | null | undefined; total_alerts_created?: number | null | undefined; gap_duration_s?: number | null | undefined; } & {}>; }>; }>; }> | undefined" ], "path": "x-pack/plugins/alerting/server/application/rule/types/rule.ts", "deprecated": false, @@ -3316,7 +3316,7 @@ "label": "snoozeSchedule", "description": [], "signature": [ - "Readonly<{ id?: string | undefined; skipRecurrences?: string[] | undefined; } & { duration: number; rRule: Readonly<{ count?: number | undefined; interval?: number | undefined; freq?: 0 | 2 | 1 | 6 | 5 | 4 | 3 | undefined; until?: string | undefined; byweekday?: (string | number)[] | undefined; bymonthday?: number[] | undefined; bymonth?: number[] | undefined; wkst?: \"MO\" | \"TU\" | \"WE\" | \"TH\" | \"FR\" | \"SA\" | \"SU\" | undefined; bysetpos?: number[] | undefined; byyearday?: number[] | undefined; byweekno?: number[] | undefined; byhour?: number[] | undefined; byminute?: number[] | undefined; bysecond?: number[] | undefined; } & { dtstart: string; tzid: string; }>; }>[] | undefined" + "Readonly<{ id?: string | undefined; skipRecurrences?: string[] | undefined; } & { duration: number; rRule: Readonly<{ count?: number | undefined; interval?: number | undefined; freq?: 0 | 2 | 1 | 6 | 5 | 4 | 3 | undefined; until?: string | undefined; byweekday?: (string | number)[] | null | undefined; bymonthday?: number[] | null | undefined; bymonth?: number[] | null | undefined; wkst?: \"MO\" | \"TU\" | \"WE\" | \"TH\" | \"FR\" | \"SA\" | \"SU\" | undefined; bysetpos?: number[] | null | undefined; byyearday?: number[] | null | undefined; byweekno?: number[] | null | undefined; byhour?: number[] | null | undefined; byminute?: number[] | null | undefined; bysecond?: number[] | null | undefined; } & { dtstart: string; tzid: string; }>; }>[] | undefined" ], "path": "x-pack/plugins/alerting/server/application/rule/types/rule.ts", "deprecated": false, @@ -3763,10 +3763,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "ruleRegistry", - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts" - }, { "plugin": "ruleRegistry", "path": "x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts" @@ -11436,7 +11432,7 @@ "signature": [ "Omit<", "Options", - ", \"dtstart\" | \"until\" | \"byweekday\" | \"wkst\"> & { dtstart: string; byweekday?: (string | number)[] | undefined; wkst?: ", + ", \"dtstart\" | \"until\" | \"byweekday\" | \"wkst\"> & { dtstart: string; byweekday?: (string | number)[] | null | undefined; wkst?: ", { "pluginId": "@kbn/rrule", "scope": "common", diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 29ec99ec3dc76..180086005cbaf 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 6d05f5f6c6b43..8f84dcb7295f9 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index f2b509a8adb9f..add4319eff127 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index e8a6e40a67d61..1b481bf5ac5c4 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 4482e8b00a06b..aab018f5b8aa9 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index 8de6048ddbe5c..80aa8f92736ab 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.devdocs.json b/api_docs/cases.devdocs.json index f52790e2615e0..a872c5d9426d7 100644 --- a/api_docs/cases.devdocs.json +++ b/api_docs/cases.devdocs.json @@ -365,7 +365,9 @@ "CustomFieldTypes", ".TOGGLE; value: boolean | null; } | { key: string; type: ", "CustomFieldTypes", - ".TEXT; value: string | null; })[] | undefined; }, \"title\" | \"description\"> | undefined; }" + ".TEXT; value: string | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[] | undefined; }, \"title\" | \"description\"> | undefined; }" ], "path": "x-pack/plugins/cases/public/client/ui/get_create_case_flyout.tsx", "deprecated": false, @@ -585,7 +587,9 @@ "CustomFieldTypes", ".TEXT; value: string | null; } | { key: string; type: ", "CustomFieldTypes", - ".TOGGLE; value: boolean | null; })[]; settings: { syncAlerts: boolean; }; status: ", + ".TOGGLE; value: boolean | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[]; settings: { syncAlerts: boolean; }; status: ", { "pluginId": "@kbn/cases-components", "scope": "common", @@ -1962,7 +1966,9 @@ "CustomFieldTypes", ".TEXT; value: string | null; } | { key: string; type: ", "CustomFieldTypes", - ".TOGGLE; value: boolean | null; })[]; settings: { syncAlerts: boolean; }; status: ", + ".TOGGLE; value: boolean | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[]; settings: { syncAlerts: boolean; }; status: ", { "pluginId": "@kbn/cases-components", "scope": "common", @@ -2164,7 +2170,9 @@ "CustomFieldTypes", ".TOGGLE; value: boolean | null; } | { key: string; type: ", "CustomFieldTypes", - ".TEXT; value: string | null; })[] | undefined; }" + ".TEXT; value: string | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[] | undefined; }" ], "path": "x-pack/plugins/cases/common/types/api/case/v1.ts", "deprecated": false, @@ -2255,7 +2263,9 @@ "CustomFieldTypes", ".TEXT; value: string | null; } | { key: string; type: ", "CustomFieldTypes", - ".TOGGLE; value: boolean | null; })[]; settings: { syncAlerts: boolean; }; status: ", + ".TOGGLE; value: boolean | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[]; settings: { syncAlerts: boolean; }; status: ", { "pluginId": "@kbn/cases-components", "scope": "common", @@ -2489,7 +2499,9 @@ "CustomFieldTypes", ".TEXT; value: string | null; } | { key: string; type: ", "CustomFieldTypes", - ".TOGGLE; value: boolean | null; })[]; settings: { syncAlerts: boolean; }; status: ", + ".TOGGLE; value: boolean | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[]; settings: { syncAlerts: boolean; }; status: ", { "pluginId": "@kbn/cases-components", "scope": "common", @@ -2676,7 +2688,9 @@ "CustomFieldTypes", ".TEXT; value: string | null; } | { key: string; type: ", "CustomFieldTypes", - ".TOGGLE; value: boolean | null; })[]; settings: { syncAlerts: boolean; }; status: ", + ".TOGGLE; value: boolean | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[]; settings: { syncAlerts: boolean; }; status: ", { "pluginId": "@kbn/cases-components", "scope": "common", @@ -2899,7 +2913,9 @@ "CustomFieldTypes", ".TEXT; value: string | null; } | { key: string; type: ", "CustomFieldTypes", - ".TOGGLE; value: boolean | null; })[]; settings: { syncAlerts: boolean; }; status: ", + ".TOGGLE; value: boolean | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[]; settings: { syncAlerts: boolean; }; status: ", { "pluginId": "@kbn/cases-components", "scope": "common", @@ -3304,7 +3320,9 @@ "CustomFieldTypes", ".TEXT; value: string | null; } | { key: string; type: ", "CustomFieldTypes", - ".TOGGLE; value: boolean | null; })[]; }; } | { type: \"comment\"; payload: { comment: { type: ", + ".TOGGLE; value: boolean | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[]; }; } | { type: \"comment\"; payload: { comment: { type: ", { "pluginId": "cases", "scope": "common", @@ -3460,7 +3478,9 @@ "CustomFieldTypes", ".TEXT; value: string | null; } | { key: string; type: ", "CustomFieldTypes", - ".TOGGLE; value: boolean | null; })[] | undefined; }; }) | { type: \"connector\"; payload: { connector: { id: string; } & (({ type: ", + ".TOGGLE; value: boolean | null; } | { key: string; type: ", + "CustomFieldTypes", + ".NUMBER; value: number | null; })[] | undefined; }; }) | { type: \"connector\"; payload: { connector: { id: string; } & (({ type: ", { "pluginId": "cases", "scope": "common", diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index ef50f06a0721b..d0ffc1b5d621c 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index a6e11745aa9a0..07363f30a419f 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.devdocs.json b/api_docs/cloud.devdocs.json index 08dbd1e77d8ef..354f3b99d8c05 100644 --- a/api_docs/cloud.devdocs.json +++ b/api_docs/cloud.devdocs.json @@ -893,11 +893,11 @@ "signature": [ "{ defaultSolution?: ", { - "pluginId": "cloud", - "scope": "common", - "docId": "kibCloudPluginApi", - "section": "def-common.OnBoardingDefaultSolution", - "text": "OnBoardingDefaultSolution" + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.SolutionId", + "text": "SolutionId" }, " | undefined; }" ], @@ -1212,11 +1212,11 @@ "signature": [ "{ defaultSolution?: ", { - "pluginId": "cloud", - "scope": "common", - "docId": "kibCloudPluginApi", - "section": "def-common.OnBoardingDefaultSolution", - "text": "OnBoardingDefaultSolution" + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.SolutionId", + "text": "SolutionId" }, " | undefined; }" ], @@ -1327,23 +1327,7 @@ "functions": [], "interfaces": [], "enums": [], - "misc": [ - { - "parentPluginId": "cloud", - "id": "def-common.OnBoardingDefaultSolution", - "type": "Type", - "tags": [], - "label": "OnBoardingDefaultSolution", - "description": [], - "signature": [ - "\"security\" | \"es\" | \"oblt\"" - ], - "path": "x-pack/plugins/cloud/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], + "misc": [], "objects": [] } } \ No newline at end of file diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index a5f6401ba0a5d..3fa2b6c3c3d56 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 84 | 0 | 21 | 1 | +| 83 | 0 | 20 | 1 | ## Client @@ -39,8 +39,3 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core ### Start -## Common - -### Consts, variables and types - - diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index 3a111a23fb7c0..12bdf56ea9f5e 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index d0cf6a71eb6b2..da9a113c4a0b8 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index f799cad3d0f95..265c84d0a7617 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index b94b5c9da2338..bb5583236e15e 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index e6245443103a4..0a804e983babd 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 790dbe005ee65..8cc7c190e1112 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index d19329fe3ea6b..cb150e23e1050 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index b954f6a417dc7..a7f2c975f0651 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index 7be289077d18a..4f6000f7c6244 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 3ee94254c413f..67e9142d639b1 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_quality.mdx b/api_docs/data_quality.mdx index 1fbb28b6097e0..ee9c08e61fec5 100644 --- a/api_docs/data_quality.mdx +++ b/api_docs/data_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataQuality title: "dataQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the dataQuality plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataQuality'] --- import dataQualityObj from './data_quality.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 439fed69df251..30c1bc88b582f 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 66a4195bfda18..69a1e798e385b 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_usage.mdx b/api_docs/data_usage.mdx index 7fd671e4fc336..e0baf2f27cfc4 100644 --- a/api_docs/data_usage.mdx +++ b/api_docs/data_usage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataUsage title: "dataUsage" image: https://source.unsplash.com/400x175/?github description: API docs for the dataUsage plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataUsage'] --- import dataUsageObj from './data_usage.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 33a037e036db4..076810b30bf83 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index d9c40b66b8ef7..5231994ca6426 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index cf4845bfe9615..73a866beac9f1 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 9e9d5a4d41216..9a87e1ee9a4d4 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index 2059562d37d7d..97230d1215956 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.devdocs.json b/api_docs/dataset_quality.devdocs.json index 6ab79f43aaa32..b0a5233462aef 100644 --- a/api_docs/dataset_quality.devdocs.json +++ b/api_docs/dataset_quality.devdocs.json @@ -247,6 +247,46 @@ "DatasetQualityRouteHandlerResources", ", { integrations: ({ name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; })[]; }, ", "DatasetQualityRouteCreateOptions", + ">; \"POST /internal/dataset_quality/data_streams/{dataStream}/rollover\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/dataset_quality/data_streams/{dataStream}/rollover\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ dataStream: ", + "StringC", + "; }>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { acknowledged: boolean; }, ", + "DatasetQualityRouteCreateOptions", + ">; \"PUT /internal/dataset_quality/data_streams/{dataStream}/update_field_limit\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"PUT /internal/dataset_quality/data_streams/{dataStream}/update_field_limit\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ dataStream: ", + "StringC", + "; }>; body: ", + "TypeC", + "<{ newFieldLimit: ", + "NumberC", + "; }>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { isComponentTemplateUpdated: boolean | undefined; isLatestBackingIndexUpdated: boolean | undefined; customComponentTemplateName: string; } & { error?: string | undefined; }, ", + "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/degraded_field/{degradedField}/analyze\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -269,7 +309,7 @@ "StringC", "; }>; }>, ", "DatasetQualityRouteHandlerResources", - ", { isFieldLimitIssue: boolean; fieldCount: number; totalFieldLimit: number; } & { ignoreMalformed?: boolean | undefined; nestedFieldLimit?: number | undefined; fieldMapping?: { type?: string | undefined; ignore_above?: number | undefined; } | undefined; }, ", + ", { isFieldLimitIssue: boolean; fieldCount: number; totalFieldLimit: number; } & { ignoreMalformed?: boolean | undefined; nestedFieldLimit?: number | undefined; fieldMapping?: { type?: string | undefined; ignore_above?: number | undefined; } | undefined; defaultPipeline?: string | undefined; }, ", "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\": ", { @@ -287,7 +327,7 @@ "StringC", "; }>; }>, ", "DatasetQualityRouteHandlerResources", - ", { lastBackingIndexName: string; } & { createdOn?: number | null | undefined; integration?: string | undefined; datasetUserPrivileges?: ({ canMonitor: boolean; } & { canRead: boolean; canViewIntegrations: boolean; }) | undefined; }, ", + ", { lastBackingIndexName?: string | undefined; indexTemplate?: string | undefined; createdOn?: number | null | undefined; integration?: string | undefined; datasetUserPrivileges?: ({ canMonitor: boolean; } & { canRead: boolean; canViewIntegrations: boolean; }) | undefined; }, ", "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/details\": ", { @@ -548,6 +588,46 @@ "DatasetQualityRouteHandlerResources", ", { integrations: ({ name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; })[]; }, ", "DatasetQualityRouteCreateOptions", + ">; \"POST /internal/dataset_quality/data_streams/{dataStream}/rollover\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/dataset_quality/data_streams/{dataStream}/rollover\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ dataStream: ", + "StringC", + "; }>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { acknowledged: boolean; }, ", + "DatasetQualityRouteCreateOptions", + ">; \"PUT /internal/dataset_quality/data_streams/{dataStream}/update_field_limit\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"PUT /internal/dataset_quality/data_streams/{dataStream}/update_field_limit\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ dataStream: ", + "StringC", + "; }>; body: ", + "TypeC", + "<{ newFieldLimit: ", + "NumberC", + "; }>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { isComponentTemplateUpdated: boolean | undefined; isLatestBackingIndexUpdated: boolean | undefined; customComponentTemplateName: string; } & { error?: string | undefined; }, ", + "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/degraded_field/{degradedField}/analyze\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -570,7 +650,7 @@ "StringC", "; }>; }>, ", "DatasetQualityRouteHandlerResources", - ", { isFieldLimitIssue: boolean; fieldCount: number; totalFieldLimit: number; } & { ignoreMalformed?: boolean | undefined; nestedFieldLimit?: number | undefined; fieldMapping?: { type?: string | undefined; ignore_above?: number | undefined; } | undefined; }, ", + ", { isFieldLimitIssue: boolean; fieldCount: number; totalFieldLimit: number; } & { ignoreMalformed?: boolean | undefined; nestedFieldLimit?: number | undefined; fieldMapping?: { type?: string | undefined; ignore_above?: number | undefined; } | undefined; defaultPipeline?: string | undefined; }, ", "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\": ", { @@ -588,7 +668,7 @@ "StringC", "; }>; }>, ", "DatasetQualityRouteHandlerResources", - ", { lastBackingIndexName: string; } & { createdOn?: number | null | undefined; integration?: string | undefined; datasetUserPrivileges?: ({ canMonitor: boolean; } & { canRead: boolean; canViewIntegrations: boolean; }) | undefined; }, ", + ", { lastBackingIndexName?: string | undefined; indexTemplate?: string | undefined; createdOn?: number | null | undefined; integration?: string | undefined; datasetUserPrivileges?: ({ canMonitor: boolean; } & { canRead: boolean; canViewIntegrations: boolean; }) | undefined; }, ", "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/details\": ", { diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 6db559a156159..3c0f9aae9b5b4 100644 --- a/api_docs/dataset_quality.mdx +++ b/api_docs/dataset_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/datasetQuality title: "datasetQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the datasetQuality plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'datasetQuality'] --- import datasetQualityObj from './dataset_quality.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 7c89950343798..b0fd973f96952 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -168,6 +168,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-plugins-server-internal | - | | | encryptedSavedObjects | - | | | @kbn/esql-validation-autocomplete | - | +| | @kbn/monaco | - | | | reporting | - | | | @kbn/reporting-export-types-csv, reporting | - | | | @kbn/reporting-export-types-csv, reporting | - | @@ -243,6 +244,7 @@ Safe to remove. | | taskManager | | | @kbn/core-saved-objects-api-browser | | | @kbn/core-saved-objects-api-browser | +| | @kbn/esql-validation-autocomplete | | | @kbn/storybook | | | @kbn/ui-theme | | | @kbn/ui-theme | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 6cd00c7d52e93..9a533304dcdae 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -389,6 +389,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| +| | [hover.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/hover/hover.ts#:~:text=modes) | - | | | [esql_theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/esql_theme.ts#:~:text=darkMode), [esql_theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/esql_theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode) | - | @@ -543,7 +544,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [rules_client_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client_factory.ts#:~:text=authc), [task.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/invalidate_pending_api_keys/task.ts#:~:text=authc), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=authc), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=authc), [rules_client_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client_factory.ts#:~:text=authc), [task.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/invalidate_pending_api_keys/task.ts#:~:text=authc), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=authc), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=authc) | - | | | [task.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/usage/task.ts#:~:text=index) | - | | | [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion) | - | -| | [rule.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/common/rule.ts#:~:text=SavedObjectAttributes), [rule.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/common/rule.ts#:~:text=SavedObjectAttributes), [rule_attributes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts#:~:text=SavedObjectAttributes), [rule_attributes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts#:~:text=SavedObjectAttributes), [rule_attributes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts#:~:text=SavedObjectAttributes), [rule_attributes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts#:~:text=SavedObjectAttributes), [rule_attributes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts#:~:text=SavedObjectAttributes), [inject_references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/common/inject_references.ts#:~:text=SavedObjectAttributes), [inject_references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/common/inject_references.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/types.ts#:~:text=SavedObjectAttributes)+ 36 more | - | +| | [rule.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/common/rule.ts#:~:text=SavedObjectAttributes), [rule.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/common/rule.ts#:~:text=SavedObjectAttributes), [inject_references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/common/inject_references.ts#:~:text=SavedObjectAttributes), [inject_references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/common/inject_references.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/types.ts#:~:text=SavedObjectAttributes), [migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/saved_objects/geo_containment/migrations.ts#:~:text=SavedObjectAttributes), [migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/saved_objects/geo_containment/migrations.ts#:~:text=SavedObjectAttributes), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/saved_objects/migrations/7.11/index.ts#:~:text=SavedObjectAttributes), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/saved_objects/migrations/7.11/index.ts#:~:text=SavedObjectAttributes)+ 14 more | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/saved_objects/index.ts#:~:text=migrations) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/saved_objects/index.ts#:~:text=convertToMultiNamespaceTypeVersion) | - | | | [rules_client_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client_factory.ts#:~:text=audit) | - | @@ -759,7 +760,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| | | [on_save_search.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx#:~:text=SavedObjectSaveModal), [on_save_search.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | -| | [get_top_nav_links.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx#:~:text=shareableUrlForSavedObject) | - | +| | [get_share.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_share.tsx#:~:text=shareableUrlForSavedObject) | - | | | [plugin.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/plugin.tsx#:~:text=executeTriggerActions) | - | | | [discover_state.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/state_management/discover_state.test.ts#:~:text=savedObjects) | - | | | [discover_state.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/state_management/discover_state.test.ts#:~:text=resolve) | - | @@ -1238,7 +1239,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [create_lifecycle_executor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts#:~:text=alertFactory), [create_persistence_rule_type_wrapper.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts#:~:text=alertFactory), [create_persistence_rule_type_wrapper.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts#:~:text=alertFactory), [rule_executor.test_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts#:~:text=alertFactory) | - | +| | [create_persistence_rule_type_wrapper.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts#:~:text=alertFactory), [create_persistence_rule_type_wrapper.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts#:~:text=alertFactory), [rule_executor.test_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts#:~:text=alertFactory) | - | | | [alerts_client_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts#:~:text=audit), [search_strategy.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts#:~:text=audit) | - | @@ -1371,7 +1372,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 7 more | 8.8.0 | | | [get_is_alert_suppression_active.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_is_alert_suppression_active.ts#:~:text=license%24), [create_threat_signals.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/create_threat_signals.ts#:~:text=license%24), [query.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts#:~:text=license%24), [threshold.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/threshold.ts#:~:text=license%24), [get_is_alert_suppression_active.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_is_alert_suppression_active.test.ts#:~:text=license%24), [get_is_alert_suppression_active.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_is_alert_suppression_active.test.ts#:~:text=license%24), [get_is_alert_suppression_active.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_is_alert_suppression_active.test.ts#:~:text=license%24) | 8.8.0 | | | [route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts#:~:text=authc) | - | -| | [suggest_user_profiles_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts#:~:text=userProfiles), [suggest_user_profiles_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts#:~:text=userProfiles) | - | +| | [suggest_user_profiles_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts#:~:text=userProfiles), [get_notes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts#:~:text=userProfiles), [suggest_user_profiles_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts#:~:text=userProfiles), [get_notes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts#:~:text=userProfiles) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedCellValueElementProps), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedCellValueElementProps) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedRowRenderer), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedRowRenderer) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 6b62d0edd3a04..bee5b436d4700 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index aeb50204b8302..43874a956324f 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.devdocs.json b/api_docs/discover.devdocs.json index daefbbeb4072f..2eb8c1f28f089 100644 --- a/api_docs/discover.devdocs.json +++ b/api_docs/discover.devdocs.json @@ -1807,24 +1807,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "discover", - "id": "def-public.TopNavCustomization.getMenuItems", - "type": "Function", - "tags": [], - "label": "getMenuItems", - "description": [], - "signature": [ - "(() => ", - "TopNavMenuItem", - "[]) | undefined" - ], - "path": "src/plugins/discover/public/customizations/customization_types/top_nav_customization.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, { "parentPluginId": "discover", "id": "def-public.TopNavCustomization.defaultBadges", @@ -1839,24 +1821,6 @@ "path": "src/plugins/discover/public/customizations/customization_types/top_nav_customization.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.TopNavCustomization.getBadges", - "type": "Function", - "tags": [], - "label": "getBadges", - "description": [], - "signature": [ - "(() => ", - "TopNavBadge", - "[]) | undefined" - ], - "path": "src/plugins/discover/public/customizations/customization_types/top_nav_customization.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index e25fe1fca4c00..29646ab3ac57d 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 150 | 0 | 102 | 26 | +| 148 | 0 | 100 | 24 | ## Client diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index a19a9d1d910cb..46b1d9f418733 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/discover_shared.mdx b/api_docs/discover_shared.mdx index 8cf6d5811c890..eaf809fb79199 100644 --- a/api_docs/discover_shared.mdx +++ b/api_docs/discover_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverShared title: "discoverShared" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverShared plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverShared'] --- import discoverSharedObj from './discover_shared.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index 22fc7f08a3c74..39fc99a0c53e3 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index 509f4864481db..b4dfe78e447e7 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.devdocs.json b/api_docs/embeddable.devdocs.json index 07af1a6da01b0..f462c063c1dfc 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -6106,6 +6106,198 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "embeddable", + "id": "def-public.Embeddable.hasLockedHoverActions$", + "type": "Object", + "tags": [], + "label": "hasLockedHoverActions$", + "description": [], + "signature": [ + "{ source: ", + "Observable", + " | undefined; readonly value: boolean; error: (err: any) => void; forEach: { (next: (value: boolean) => void): Promise; (next: (value: boolean) => void, promiseCtor: PromiseConstructorLike): Promise; }; complete: () => void; getValue: () => boolean; closed: boolean; pipe: { (): ", + "Observable", + "; (op1: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + ", op9: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + ", op9: ", + "OperatorFunction", + ", ...operations: ", + "OperatorFunction", + "[]): ", + "Observable", + "; }; operator: ", + "Operator", + " | undefined; lift: (operator: ", + "Operator", + ") => ", + "Observable", + "; subscribe: { (observerOrNext?: Partial<", + "Observer", + "> | ((value: boolean) => void) | undefined): ", + "Subscription", + "; (next?: ((value: boolean) => void) | null | undefined, error?: ((error: any) => void) | null | undefined, complete?: (() => void) | null | undefined): ", + "Subscription", + "; }; toPromise: { (): Promise; (PromiseCtor: PromiseConstructor): Promise; (PromiseCtor: PromiseConstructorLike): Promise; }; observers: ", + "Observer", + "[]; isStopped: boolean; hasError: boolean; thrownError: any; unsubscribe: () => void; readonly observed: boolean; asObservable: () => ", + "Observable", + "; }" + ], + "path": "src/plugins/embeddable/public/lib/embeddables/embeddable.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "embeddable", + "id": "def-public.Embeddable.lockHoverActions", + "type": "Function", + "tags": [], + "label": "lockHoverActions", + "description": [], + "signature": [ + "(lock: boolean) => void" + ], + "path": "src/plugins/embeddable/public/lib/embeddables/embeddable.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "embeddable", + "id": "def-public.Embeddable.lockHoverActions.$1", + "type": "boolean", + "tags": [], + "label": "lock", + "description": [], + "path": "packages/presentation/presentation_publishing/interfaces/can_lock_hover_actions.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, { "parentPluginId": "embeddable", "id": "def-public.Embeddable.getEditHref", diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 91996d48362d7..48ca1f3fb9e33 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 575 | 1 | 465 | 9 | +| 578 | 1 | 468 | 9 | ## Client diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index efccd7663a031..8fcfeb30f1194 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index 9aed88578c119..3a966f5a29051 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index bf3f296cc486d..83586cb49c06d 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/entities_data_access.mdx b/api_docs/entities_data_access.mdx index b02c7a918d491..d7d8523eebf99 100644 --- a/api_docs/entities_data_access.mdx +++ b/api_docs/entities_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entitiesDataAccess title: "entitiesDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the entitiesDataAccess plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entitiesDataAccess'] --- import entitiesDataAccessObj from './entities_data_access.devdocs.json'; diff --git a/api_docs/entity_manager.mdx b/api_docs/entity_manager.mdx index 39af0d3afddde..b0602651a1dee 100644 --- a/api_docs/entity_manager.mdx +++ b/api_docs/entity_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entityManager title: "entityManager" image: https://source.unsplash.com/400x175/?github description: API docs for the entityManager plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entityManager'] --- import entityManagerObj from './entity_manager.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index c3b53d34b2a8e..1a4a85d6b496d 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/esql.mdx b/api_docs/esql.mdx index 836841fabf53e..aca99ecafeff7 100644 --- a/api_docs/esql.mdx +++ b/api_docs/esql.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esql title: "esql" image: https://source.unsplash.com/400x175/?github description: API docs for the esql plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esql'] --- import esqlObj from './esql.devdocs.json'; diff --git a/api_docs/esql_data_grid.mdx b/api_docs/esql_data_grid.mdx index 2b2a7808e9152..c99e59106b690 100644 --- a/api_docs/esql_data_grid.mdx +++ b/api_docs/esql_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esqlDataGrid title: "esqlDataGrid" image: https://source.unsplash.com/400x175/?github description: API docs for the esqlDataGrid plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esqlDataGrid'] --- import esqlDataGridObj from './esql_data_grid.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index bc3bb187fd016..6af390ed57221 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index 8f6294f23a1c7..72d9cb9680699 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index e2ec68ef82e07..a83e8dd9d931b 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/exploratory_view.mdx b/api_docs/exploratory_view.mdx index 1a3d2a96b6669..109d3f6d0a98f 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'exploratoryView'] --- import exploratoryViewObj from './exploratory_view.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index af9e6ebeddb45..133565f8e879d 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index ae49b77013d00..46458d8213c6f 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index 8e32a8a630c47..ae37dea25da2f 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index ef905b8669834..c1059b39d5fee 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index 80f8f1d5b18a9..574acb6f47366 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index ac4d8b408de5d..42ddb71d2360f 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index eee54e1648ee7..fc7ecb4582c1c 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index bbfe62e67bb37..f5ec3bb6de32b 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index 012a05f5085da..2d1b50c7a0af7 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index aae29be9303ab..4e44b72cb8e23 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index 5a7ac495b4a3f..35fc3a0b7fae7 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index 038f9bf9dac65..01dd6b05c4275 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index f32b1411e2272..bef9018ce06f1 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index c1446d09c2d48..4bc9dd0984a5e 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index f13916cc4a223..5d199b694434e 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index a469fcd55f650..a55a7fcc5e9f0 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/fields_metadata.mdx b/api_docs/fields_metadata.mdx index a78dac4200a5f..935948319b021 100644 --- a/api_docs/fields_metadata.mdx +++ b/api_docs/fields_metadata.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldsMetadata title: "fieldsMetadata" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldsMetadata plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldsMetadata'] --- import fieldsMetadataObj from './fields_metadata.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 2c37d2e76dbec..c4738a05d8190 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index ad4882b5bbc90..346afab7c85b6 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index df2e6d24ea945..9101e26b9daed 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index a0ccb47e00b5e..7fee0ab161b3f 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -11646,41 +11646,9 @@ "label": "runExternalCallbacks", "description": [], "signature": [ - "(externalCallbackType: A, packagePolicy: A extends \"packagePolicyDelete\" ? ", - "DeletePackagePoliciesResponse", - " : A extends \"packagePolicyPostDelete\" ? ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.PostDeletePackagePoliciesResponse", - "text": "PostDeletePackagePoliciesResponse" - }, - " : A extends \"packagePolicyPostCreate\" ? ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.PackagePolicy", - "text": "PackagePolicy" - }, - " : A extends \"packagePolicyUpdate\" ? ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.UpdatePackagePolicy", - "text": "UpdatePackagePolicy" - }, - " : ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.NewPackagePolicy", - "text": "NewPackagePolicy" - }, - ", soClient: ", + "(externalCallbackType: A, packagePolicy: ", + "RunExternalCallbacksPackagePolicyArgument", + ", soClient: ", { "pluginId": "@kbn/core-saved-objects-api-server", "scope": "server", @@ -11712,31 +11680,9 @@ "section": "def-server.KibanaRequest", "text": "KibanaRequest" }, - " | undefined) => Promise" + " | undefined) => Promise<", + "RunExternalCallbacksPackagePolicyResponse", + ">" ], "path": "x-pack/plugins/fleet/server/services/package_policy_service.ts", "deprecated": false, @@ -11765,40 +11711,8 @@ "label": "packagePolicy", "description": [], "signature": [ - "A extends \"packagePolicyDelete\" ? ", - "DeletePackagePoliciesResponse", - " : A extends \"packagePolicyPostDelete\" ? ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.PostDeletePackagePoliciesResponse", - "text": "PostDeletePackagePoliciesResponse" - }, - " : A extends \"packagePolicyPostCreate\" ? ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.PackagePolicy", - "text": "PackagePolicy" - }, - " : A extends \"packagePolicyUpdate\" ? ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.UpdatePackagePolicy", - "text": "UpdatePackagePolicy" - }, - " : ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.NewPackagePolicy", - "text": "NewPackagePolicy" - } + "RunExternalCallbacksPackagePolicyArgument", + "" ], "path": "x-pack/plugins/fleet/server/services/package_policy_service.ts", "deprecated": false, @@ -12633,9 +12547,13 @@ " | ", "ExternalCallbackUpdate", " | ", + "ExternalCallbackPostUpdate", + " | ", "ExternalCallbackAgentPolicyCreate", " | ", - "ExternalCallbackAgentPolicyUpdate" + "ExternalCallbackAgentPolicyUpdate", + " | ", + "ExternalCallbackAgentPolicyPostUpdate" ], "path": "x-pack/plugins/fleet/server/types/extensions.ts", "deprecated": false, diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 1b9bed79143eb..9a10cd91f5ce2 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1426 | 5 | 1301 | 76 | +| 1426 | 5 | 1301 | 80 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 1b946c28aa6c1..7282d4ec6322d 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index f0cce41a5cf8a..244c4600c5783 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 65cc10185309d..bf19a7bbaa3e1 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index 2024262876c0a..203566a3f2915 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index b6b938d38fee8..081f291a70dad 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.devdocs.json b/api_docs/index_management.devdocs.json index 0b00cab28949e..d669189fc7e2a 100644 --- a/api_docs/index_management.devdocs.json +++ b/api_docs/index_management.devdocs.json @@ -347,65 +347,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "indexManagement", - "id": "def-public.IndexManagementLocatorParams", - "type": "Interface", - "tags": [], - "label": "IndexManagementLocatorParams", - "description": [], - "signature": [ - { - "pluginId": "@kbn/index-management-shared-types", - "scope": "common", - "docId": "kibKbnIndexManagementSharedTypesPluginApi", - "section": "def-common.IndexManagementLocatorParams", - "text": "IndexManagementLocatorParams" - }, - " extends ", - { - "pluginId": "@kbn/utility-types", - "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.SerializableRecord", - "text": "SerializableRecord" - } - ], - "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "indexManagement", - "id": "def-public.IndexManagementLocatorParams.page", - "type": "string", - "tags": [], - "label": "page", - "description": [], - "signature": [ - "\"data_streams_details\"" - ], - "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-public.IndexManagementLocatorParams.dataStreamName", - "type": "string", - "tags": [], - "label": "dataStreamName", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "indexManagement", "id": "def-public.IndexMappingProps", @@ -472,6 +413,28 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "indexManagement", + "id": "def-public.IndexManagementLocatorParams", + "type": "Type", + "tags": [], + "label": "IndexManagementLocatorParams", + "description": [], + "signature": [ + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.SerializableRecord", + "text": "SerializableRecord" + }, + " & ({ page: \"data_streams_details\"; dataStreamName?: string | undefined; } | { page: \"index_template\"; indexTemplate: string; } | { page: \"component_template\"; componentTemplate: string; })" + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [], @@ -2102,6 +2065,20 @@ "path": "x-pack/plugins/index_management/common/types/data_streams.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "indexManagement", + "id": "def-common.DataStream.indexMode", + "type": "CompoundType", + "tags": [], + "label": "indexMode", + "description": [], + "signature": [ + "\"standard\" | \"time_series\" | \"logsdb\"" + ], + "path": "x-pack/plugins/index_management/common/types/data_streams.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -2299,6 +2276,20 @@ "path": "x-pack/plugins/index_management/common/types/data_streams.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "indexManagement", + "id": "def-common.EnhancedDataStreamFromEs.index_mode", + "type": "CompoundType", + "tags": [], + "label": "index_mode", + "description": [], + "signature": [ + "string | null | undefined" + ], + "path": "x-pack/plugins/index_management/common/types/data_streams.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -2652,145 +2643,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule", - "type": "Interface", - "tags": [], - "label": "IndexModule", - "description": [], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.number_of_shards", - "type": "CompoundType", - "tags": [], - "label": "number_of_shards", - "description": [], - "signature": [ - "string | number" - ], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.codec", - "type": "string", - "tags": [], - "label": "codec", - "description": [], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.routing_partition_size", - "type": "number", - "tags": [], - "label": "routing_partition_size", - "description": [], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.refresh_interval", - "type": "string", - "tags": [], - "label": "refresh_interval", - "description": [], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.load_fixed_bitset_filters_eagerly", - "type": "boolean", - "tags": [], - "label": "load_fixed_bitset_filters_eagerly", - "description": [], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.shard", - "type": "Object", - "tags": [], - "label": "shard", - "description": [], - "signature": [ - "{ check_on_startup: boolean | \"checksum\"; }" - ], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.number_of_replicas", - "type": "number", - "tags": [], - "label": "number_of_replicas", - "description": [], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.auto_expand_replicas", - "type": "CompoundType", - "tags": [], - "label": "auto_expand_replicas", - "description": [], - "signature": [ - "string | false" - ], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.lifecycle", - "type": "Object", - "tags": [], - "label": "lifecycle", - "description": [], - "signature": [ - "LifecycleModule" - ], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "indexManagement", - "id": "def-common.IndexModule.routing", - "type": "Object", - "tags": [], - "label": "routing", - "description": [], - "signature": [ - "{ allocation: { enable: \"none\" | \"all\" | \"primaries\" | \"new_primaries\"; }; rebalance: { enable: \"none\" | \"all\" | \"primaries\" | \"replicas\"; }; }" - ], - "path": "x-pack/plugins/index_management/common/types/indices.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "indexManagement", "id": "def-common.IndexSettings", @@ -2810,15 +2662,8 @@ "label": "index", "description": [], "signature": [ - "Partial<", - { - "pluginId": "indexManagement", - "scope": "common", - "docId": "kibIndexManagementPluginApi", - "section": "def-common.IndexModule", - "text": "IndexModule" - }, - "> | undefined" + "IndicesIndexSettingsKeys", + " | undefined" ], "path": "x-pack/plugins/index_management/common/types/indices.ts", "deprecated": false, diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 365c1d0d4c5b9..e193809411717 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 252 | 0 | 247 | 1 | +| 241 | 0 | 236 | 1 | ## Client diff --git a/api_docs/inference.mdx b/api_docs/inference.mdx index dc6b9385358be..a1c0bd1661a3d 100644 --- a/api_docs/inference.mdx +++ b/api_docs/inference.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inference title: "inference" image: https://source.unsplash.com/400x175/?github description: API docs for the inference plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inference'] --- import inferenceObj from './inference.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 92065c50ce107..be7722b49842b 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/ingest_pipelines.mdx b/api_docs/ingest_pipelines.mdx index 3cb617fe3d3f9..4f358a796db47 100644 --- a/api_docs/ingest_pipelines.mdx +++ b/api_docs/ingest_pipelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ingestPipelines title: "ingestPipelines" image: https://source.unsplash.com/400x175/?github description: API docs for the ingestPipelines plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ingestPipelines'] --- import ingestPipelinesObj from './ingest_pipelines.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 0b9e3bc75240b..b5beb5df3b4a8 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/integration_assistant.mdx b/api_docs/integration_assistant.mdx index 2ed577c134c0a..0f758fdd05b97 100644 --- a/api_docs/integration_assistant.mdx +++ b/api_docs/integration_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/integrationAssistant title: "integrationAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the integrationAssistant plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'integrationAssistant'] --- import integrationAssistantObj from './integration_assistant.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 1585a7ece5051..5dbddb2150676 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/inventory.devdocs.json b/api_docs/inventory.devdocs.json index 061ad0b1ed5a3..acc804d848107 100644 --- a/api_docs/inventory.devdocs.json +++ b/api_docs/inventory.devdocs.json @@ -62,6 +62,36 @@ "InventoryRouteHandlerResources", ", { hasData: boolean; }, ", "InventoryRouteCreateOptions", + ">; \"GET /internal/inventory/entities/group_by/{field}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/inventory/entities/group_by/{field}\", ", + "IntersectionC", + "<[", + "TypeC", + "<{ path: ", + "TypeC", + "<{ field: ", + "LiteralC", + "<\"entity.type\">; }>; }>, ", + "PartialC", + "<{ query: ", + "PartialC", + "<{ kuery: ", + "StringC", + "; entityTypes: ", + "Type", + "; }>; }>]>, ", + "InventoryRouteHandlerResources", + ", { groupBy: \"entity.type\"; groups: ", + "EntityGroup", + "[]; entitiesCount: number; }, ", + "InventoryRouteCreateOptions", ">; \"GET /internal/inventory/entities/types\": ", { "pluginId": "@kbn/server-route-repository-utils", diff --git a/api_docs/inventory.mdx b/api_docs/inventory.mdx index 877c4fa6083ca..0082a4be032e0 100644 --- a/api_docs/inventory.mdx +++ b/api_docs/inventory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inventory title: "inventory" image: https://source.unsplash.com/400x175/?github description: API docs for the inventory plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inventory'] --- import inventoryObj from './inventory.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 5 | 0 | 5 | 3 | +| 5 | 0 | 5 | 4 | ## Client diff --git a/api_docs/investigate.mdx b/api_docs/investigate.mdx index aa0696f8de6dd..ac98731e7808d 100644 --- a/api_docs/investigate.mdx +++ b/api_docs/investigate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigate title: "investigate" image: https://source.unsplash.com/400x175/?github description: API docs for the investigate plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigate'] --- import investigateObj from './investigate.devdocs.json'; diff --git a/api_docs/investigate_app.mdx b/api_docs/investigate_app.mdx index 23f61a87f42a2..f02e921b8e25d 100644 --- a/api_docs/investigate_app.mdx +++ b/api_docs/investigate_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigateApp title: "investigateApp" image: https://source.unsplash.com/400x175/?github description: API docs for the investigateApp plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigateApp'] --- import investigateAppObj from './investigate_app.devdocs.json'; diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index f97fd9a1c7040..9c77e9ab9e8a7 100644 --- a/api_docs/kbn_actions_types.mdx +++ b/api_docs/kbn_actions_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-actions-types title: "@kbn/actions-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/actions-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; diff --git a/api_docs/kbn_ai_assistant.devdocs.json b/api_docs/kbn_ai_assistant.devdocs.json index 5940c3c6fe125..f80f569dd4300 100644 --- a/api_docs/kbn_ai_assistant.devdocs.json +++ b/api_docs/kbn_ai_assistant.devdocs.json @@ -55,7 +55,7 @@ "section": "def-public.FlyoutPositionMode", "text": "FlyoutPositionMode" }, - ") => void) | undefined; navigateToConversation: (conversationId?: string | undefined) => void; }) => React.JSX.Element" + ") => void) | undefined; navigateToConversation?: ((conversationId?: string | undefined) => void) | undefined; }) => React.JSX.Element" ], "path": "x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx", "deprecated": false, @@ -311,7 +311,7 @@ "label": "navigateToConversation", "description": [], "signature": [ - "(conversationId?: string | undefined) => void" + "((conversationId?: string | undefined) => void) | undefined" ], "path": "x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx", "deprecated": false, @@ -349,7 +349,7 @@ "label": "ChatFlyout", "description": [], "signature": [ - "({\n initialTitle,\n initialMessages,\n initialFlyoutPositionMode,\n isOpen,\n onClose,\n navigateToConversation,\n}: { initialTitle: string; initialMessages: ", + "({\n initialTitle,\n initialMessages,\n initialFlyoutPositionMode,\n isOpen,\n onClose,\n navigateToConversation,\n hideConversationList,\n}: { initialTitle: string; initialMessages: ", { "pluginId": "observabilityAIAssistant", "scope": "common", @@ -365,7 +365,7 @@ "section": "def-public.FlyoutPositionMode", "text": "FlyoutPositionMode" }, - " | undefined; isOpen: boolean; onClose: () => void; navigateToConversation(conversationId?: string | undefined): void; }) => React.JSX.Element | null" + " | undefined; isOpen: boolean; onClose: () => void; navigateToConversation?: ((conversationId?: string | undefined) => void) | undefined; hideConversationList?: boolean | undefined; }) => React.JSX.Element | null" ], "path": "x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx", "deprecated": false, @@ -376,7 +376,7 @@ "id": "def-public.ChatFlyout.$1", "type": "Object", "tags": [], - "label": "{\n initialTitle,\n initialMessages,\n initialFlyoutPositionMode,\n isOpen,\n onClose,\n navigateToConversation,\n}", + "label": "{\n initialTitle,\n initialMessages,\n initialFlyoutPositionMode,\n isOpen,\n onClose,\n navigateToConversation,\n hideConversationList,\n}", "description": [], "path": "x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx", "deprecated": false, @@ -470,7 +470,7 @@ "label": "navigateToConversation", "description": [], "signature": [ - "(conversationId?: string | undefined) => void" + "((conversationId?: string | undefined) => void) | undefined" ], "path": "x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx", "deprecated": false, @@ -493,6 +493,20 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/ai-assistant", + "id": "def-public.ChatFlyout.$1.hideConversationList", + "type": "CompoundType", + "tags": [], + "label": "hideConversationList", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx", + "deprecated": false, + "trackAdoption": false } ] } @@ -1085,7 +1099,7 @@ "label": "status", "description": [], "signature": [ - "State<{ ready: boolean; error?: any; deployment_state?: ", + "State<{ ready: boolean; enabled: boolean; error?: any; deployment_state?: ", "MlDeploymentState", " | undefined; allocation_state?: ", "MlDeploymentAllocationState", diff --git a/api_docs/kbn_ai_assistant.mdx b/api_docs/kbn_ai_assistant.mdx index 990d8bbd2d734..9f4aebd335fff 100644 --- a/api_docs/kbn_ai_assistant.mdx +++ b/api_docs/kbn_ai_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ai-assistant title: "@kbn/ai-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ai-assistant plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ai-assistant'] --- import kbnAiAssistantObj from './kbn_ai_assistant.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-ki | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 63 | 0 | 63 | 1 | +| 64 | 0 | 64 | 1 | ## Client diff --git a/api_docs/kbn_ai_assistant_common.mdx b/api_docs/kbn_ai_assistant_common.mdx index d197535e4585d..f55a0591246ee 100644 --- a/api_docs/kbn_ai_assistant_common.mdx +++ b/api_docs/kbn_ai_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ai-assistant-common title: "@kbn/ai-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ai-assistant-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ai-assistant-common'] --- import kbnAiAssistantCommonObj from './kbn_ai_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 14aa0e0c6122d..dd5caccabf8bc 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_pattern_analysis.mdx b/api_docs/kbn_aiops_log_pattern_analysis.mdx index b5da2892b2201..48a73e5acd0f6 100644 --- a/api_docs/kbn_aiops_log_pattern_analysis.mdx +++ b/api_docs/kbn_aiops_log_pattern_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-pattern-analysis title: "@kbn/aiops-log-pattern-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-pattern-analysis plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-pattern-analysis'] --- import kbnAiopsLogPatternAnalysisObj from './kbn_aiops_log_pattern_analysis.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_rate_analysis.mdx b/api_docs/kbn_aiops_log_rate_analysis.mdx index db58d88a6f245..daa437a07bd5f 100644 --- a/api_docs/kbn_aiops_log_rate_analysis.mdx +++ b/api_docs/kbn_aiops_log_rate_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-rate-analysis title: "@kbn/aiops-log-rate-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-rate-analysis plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-rate-analysis'] --- import kbnAiopsLogRateAnalysisObj from './kbn_aiops_log_rate_analysis.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index 34a948b5c2770..92c17eb6eacde 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_comparators.mdx b/api_docs/kbn_alerting_comparators.mdx index 683fee9922359..15ed3315d7b40 100644 --- a/api_docs/kbn_alerting_comparators.mdx +++ b/api_docs/kbn_alerting_comparators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-comparators title: "@kbn/alerting-comparators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-comparators plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-comparators'] --- import kbnAlertingComparatorsObj from './kbn_alerting_comparators.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index e01e82dca0d9b..a9f2ce380e071 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerting_types.devdocs.json b/api_docs/kbn_alerting_types.devdocs.json index ec2985ed5666a..830a829583ab9 100644 --- a/api_docs/kbn_alerting_types.devdocs.json +++ b/api_docs/kbn_alerting_types.devdocs.json @@ -3659,7 +3659,7 @@ "signature": [ "Omit<", "Options", - ", \"dtstart\" | \"until\" | \"byweekday\" | \"wkst\"> & { dtstart: string; byweekday?: (string | number)[] | undefined; wkst?: ", + ", \"dtstart\" | \"until\" | \"byweekday\" | \"wkst\"> & { dtstart: string; byweekday?: (string | number)[] | null | undefined; wkst?: ", { "pluginId": "@kbn/rrule", "scope": "common", diff --git a/api_docs/kbn_alerting_types.mdx b/api_docs/kbn_alerting_types.mdx index 912223f2c1421..3d19ac7b48650 100644 --- a/api_docs/kbn_alerting_types.mdx +++ b/api_docs/kbn_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-types title: "@kbn/alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-types'] --- import kbnAlertingTypesObj from './kbn_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 1276310af8c88..21e95086eb253 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_grouping.mdx b/api_docs/kbn_alerts_grouping.mdx index 7359a86a5d93d..f23736a4d367a 100644 --- a/api_docs/kbn_alerts_grouping.mdx +++ b/api_docs/kbn_alerts_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-grouping title: "@kbn/alerts-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-grouping plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-grouping'] --- import kbnAlertsGroupingObj from './kbn_alerts_grouping.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 441ababd03849..62bb549d68383 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index f2c3c9661fdbf..4be82fdf20524 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index df74108e64bd5..39ee997b1385e 100644 --- a/api_docs/kbn_analytics_collection_utils.mdx +++ b/api_docs/kbn_analytics_collection_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-collection-utils title: "@kbn/analytics-collection-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-collection-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 3be4e76bb84a4..8302ada28edd3 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_data_view.mdx b/api_docs/kbn_apm_data_view.mdx index 86b3747e7ed11..effc6193a456d 100644 --- a/api_docs/kbn_apm_data_view.mdx +++ b/api_docs/kbn_apm_data_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-data-view title: "@kbn/apm-data-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-data-view plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-data-view'] --- import kbnApmDataViewObj from './kbn_apm_data_view.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 939ebeba7f63c..67faa87a55c38 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index c3bf780aa4650..01c1ce40b1766 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_types.mdx b/api_docs/kbn_apm_types.mdx index a0718445b4fbc..adb6cb79aedd6 100644 --- a/api_docs/kbn_apm_types.mdx +++ b/api_docs/kbn_apm_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-types title: "@kbn/apm-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-types'] --- import kbnApmTypesObj from './kbn_apm_types.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 8abba56d800d2..ab776fead78c5 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_avc_banner.mdx b/api_docs/kbn_avc_banner.mdx index d34df87175eb0..174350a3f50a9 100644 --- a/api_docs/kbn_avc_banner.mdx +++ b/api_docs/kbn_avc_banner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-avc-banner title: "@kbn/avc-banner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/avc-banner plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/avc-banner'] --- import kbnAvcBannerObj from './kbn_avc_banner.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index d52483de527a8..2fa43e0e12409 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bfetch_error.mdx b/api_docs/kbn_bfetch_error.mdx index 0f1ef20d91ed0..f6c29c8fa8dd9 100644 --- a/api_docs/kbn_bfetch_error.mdx +++ b/api_docs/kbn_bfetch_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bfetch-error title: "@kbn/bfetch-error" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bfetch-error plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bfetch-error'] --- import kbnBfetchErrorObj from './kbn_bfetch_error.devdocs.json'; diff --git a/api_docs/kbn_calculate_auto.mdx b/api_docs/kbn_calculate_auto.mdx index df6624d352ca6..47d9f891e6dd1 100644 --- a/api_docs/kbn_calculate_auto.mdx +++ b/api_docs/kbn_calculate_auto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-auto title: "@kbn/calculate-auto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-auto plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-auto'] --- import kbnCalculateAutoObj from './kbn_calculate_auto.devdocs.json'; diff --git a/api_docs/kbn_calculate_width_from_char_count.mdx b/api_docs/kbn_calculate_width_from_char_count.mdx index ad5895edfb160..bd3e7bb4179c9 100644 --- a/api_docs/kbn_calculate_width_from_char_count.mdx +++ b/api_docs/kbn_calculate_width_from_char_count.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-width-from-char-count title: "@kbn/calculate-width-from-char-count" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-width-from-char-count plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-width-from-char-count'] --- import kbnCalculateWidthFromCharCountObj from './kbn_calculate_width_from_char_count.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index e1eefe8437602..e56c686c9de02 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cbor.mdx b/api_docs/kbn_cbor.mdx index ff0bcc82a7787..34f5f0f8f868b 100644 --- a/api_docs/kbn_cbor.mdx +++ b/api_docs/kbn_cbor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cbor title: "@kbn/cbor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cbor plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cbor'] --- import kbnCborObj from './kbn_cbor.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 4276312b74be8..06f6ec322a4e2 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index b5c8e7e6a4755..4dc5fa8a15ce3 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index 3da1f513352bf..cc871bd3657b1 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-icons'] --- import kbnChartIconsObj from './kbn_chart_icons.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 760cdc0103b9f..3ee9e2a79bcbc 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index 599f9afd8b4e5..92fecc6431205 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 1f386dd2fff21..ec170f08a0a12 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index 72ec880449783..fa68238f7d869 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_cloud_security_posture.devdocs.json b/api_docs/kbn_cloud_security_posture.devdocs.json index 89432b1285c4a..37cc79e0d28b8 100644 --- a/api_docs/kbn_cloud_security_posture.devdocs.json +++ b/api_docs/kbn_cloud_security_posture.devdocs.json @@ -1116,7 +1116,7 @@ "signature": [ "{ [x: string]: FilterValue; }" ], - "path": "x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_navigate_findings.ts", + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/utils/query_utils.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -1514,6 +1514,17 @@ "path": "x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture", + "id": "def-public.statusColors.unknown", + "type": "string", + "tags": [], + "label": "unknown", + "description": [], + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_cloud_security_posture.mdx b/api_docs/kbn_cloud_security_posture.mdx index 5c48a6e0999b9..c69aa9f74804e 100644 --- a/api_docs/kbn_cloud_security_posture.mdx +++ b/api_docs/kbn_cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture title: "@kbn/cloud-security-posture" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture'] --- import kbnCloudSecurityPostureObj from './kbn_cloud_security_posture.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 88 | 1 | 88 | 0 | +| 89 | 1 | 89 | 0 | ## Client diff --git a/api_docs/kbn_cloud_security_posture_common.mdx b/api_docs/kbn_cloud_security_posture_common.mdx index d2b770b7d4529..2ed3347b58bb7 100644 --- a/api_docs/kbn_cloud_security_posture_common.mdx +++ b/api_docs/kbn_cloud_security_posture_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture-common title: "@kbn/cloud-security-posture-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture-common'] --- import kbnCloudSecurityPostureCommonObj from './kbn_cloud_security_posture_common.devdocs.json'; diff --git a/api_docs/kbn_cloud_security_posture_graph.devdocs.json b/api_docs/kbn_cloud_security_posture_graph.devdocs.json new file mode 100644 index 0000000000000..18a9900639d04 --- /dev/null +++ b/api_docs/kbn_cloud_security_posture_graph.devdocs.json @@ -0,0 +1,449 @@ +{ + "id": "@kbn/cloud-security-posture-graph", + "client": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.Graph", + "type": "Function", + "tags": [ + "component" + ], + "label": "Graph", + "description": [ + "\nGraph component renders a graph visualization using ReactFlow.\nIt takes nodes and edges as input and provides interactive controls\nfor panning, zooming, and manipulating the graph.\n" + ], + "signature": [ + "({ nodes, edges, interactive, ...rest }: ", + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.GraphProps", + "text": "GraphProps" + }, + ") => React.JSX.Element" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/graph/graph.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.Graph.$1", + "type": "Object", + "tags": [], + "label": "{ nodes, edges, interactive, ...rest }", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.GraphProps", + "text": "GraphProps" + } + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/graph/graph.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "The rendered Graph component." + ], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.EdgeViewModel", + "type": "Interface", + "tags": [], + "label": "EdgeViewModel", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.EdgeViewModel", + "text": "EdgeViewModel" + }, + " extends Record,Readonly<{} & { source: string; id: string; color: \"warning\" | \"primary\" | \"danger\"; target: string; }>" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.EntityNodeViewModel", + "type": "Interface", + "tags": [], + "label": "EntityNodeViewModel", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.EntityNodeViewModel", + "text": "EntityNodeViewModel" + }, + " extends Record,Readonly<{ label?: string | undefined; icon?: string | undefined; } & { id: string; shape: \"ellipse\" | \"rectangle\" | \"hexagon\" | \"pentagon\" | \"diamond\"; color: \"warning\" | \"primary\" | \"danger\"; }>,BaseNodeDataViewModel" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.EntityNodeViewModel.expandButtonClick", + "type": "Function", + "tags": [], + "label": "expandButtonClick", + "description": [], + "signature": [ + "((e: React.MouseEvent, node: ", + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.NodeProps", + "text": "NodeProps" + }, + ") => void) | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.EntityNodeViewModel.expandButtonClick.$1", + "type": "Object", + "tags": [], + "label": "e", + "description": [], + "signature": [ + "React.MouseEvent" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.EntityNodeViewModel.expandButtonClick.$2", + "type": "CompoundType", + "tags": [], + "label": "node", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.NodeProps", + "text": "NodeProps" + } + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.GraphProps", + "type": "Interface", + "tags": [], + "label": "GraphProps", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.GraphProps", + "text": "GraphProps" + }, + " extends ", + "CommonProps" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/graph/graph.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.GraphProps.nodes", + "type": "Array", + "tags": [], + "label": "nodes", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.NodeViewModel", + "text": "NodeViewModel" + }, + "[]" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/graph/graph.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.GraphProps.edges", + "type": "Array", + "tags": [], + "label": "edges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.EdgeViewModel", + "text": "EdgeViewModel" + }, + "[]" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/graph/graph.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.GraphProps.interactive", + "type": "boolean", + "tags": [], + "label": "interactive", + "description": [], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/graph/graph.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.GroupNodeViewModel", + "type": "Interface", + "tags": [], + "label": "GroupNodeViewModel", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.GroupNodeViewModel", + "text": "GroupNodeViewModel" + }, + " extends Record,Readonly<{ label?: string | undefined; icon?: string | undefined; } & { id: string; shape: \"group\"; }>,BaseNodeDataViewModel" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.LabelNodeViewModel", + "type": "Interface", + "tags": [], + "label": "LabelNodeViewModel", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.LabelNodeViewModel", + "text": "LabelNodeViewModel" + }, + " extends Record,Readonly<{ label?: string | undefined; icon?: string | undefined; parentId?: string | undefined; } & { id: string; shape: \"label\"; color: \"warning\" | \"primary\" | \"danger\"; }>,BaseNodeDataViewModel" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.LabelNodeViewModel.expandButtonClick", + "type": "Function", + "tags": [], + "label": "expandButtonClick", + "description": [], + "signature": [ + "((e: React.MouseEvent, node: ", + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.NodeProps", + "text": "NodeProps" + }, + ") => void) | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.LabelNodeViewModel.expandButtonClick.$1", + "type": "Object", + "tags": [], + "label": "e", + "description": [], + "signature": [ + "React.MouseEvent" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.LabelNodeViewModel.expandButtonClick.$2", + "type": "CompoundType", + "tags": [], + "label": "node", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.NodeProps", + "text": "NodeProps" + } + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.NodeProps", + "type": "Type", + "tags": [], + "label": "NodeProps", + "description": [], + "signature": [ + "Pick<", + "Node", + "<", + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.NodeViewModel", + "text": "NodeViewModel" + }, + ", string>, \"id\" | \"draggable\" | \"data\" | \"width\" | \"height\" | \"selectable\" | \"selected\" | \"parentId\" | \"sourcePosition\" | \"targetPosition\" | \"dragHandle\" | \"deletable\"> & Required, \"type\" | \"zIndex\" | \"dragging\">> & { isConnectable: boolean; positionAbsoluteX: number; positionAbsoluteY: number; }" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-graph", + "id": "def-public.NodeViewModel", + "type": "Type", + "tags": [], + "label": "NodeViewModel", + "description": [], + "signature": [ + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.EntityNodeViewModel", + "text": "EntityNodeViewModel" + }, + " | ", + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.GroupNodeViewModel", + "text": "GroupNodeViewModel" + }, + " | ", + { + "pluginId": "@kbn/cloud-security-posture-graph", + "scope": "public", + "docId": "kibKbnCloudSecurityPostureGraphPluginApi", + "section": "def-public.LabelNodeViewModel", + "text": "LabelNodeViewModel" + } + ], + "path": "x-pack/packages/kbn-cloud-security-posture/graph/src/components/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_cloud_security_posture_graph.mdx b/api_docs/kbn_cloud_security_posture_graph.mdx new file mode 100644 index 0000000000000..d0b9c70ba5b76 --- /dev/null +++ b/api_docs/kbn_cloud_security_posture_graph.mdx @@ -0,0 +1,36 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCloudSecurityPostureGraphPluginApi +slug: /kibana-dev-docs/api/kbn-cloud-security-posture-graph +title: "@kbn/cloud-security-posture-graph" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/cloud-security-posture-graph plugin +date: 2024-11-01 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture-graph'] +--- +import kbnCloudSecurityPostureGraphObj from './kbn_cloud_security_posture_graph.devdocs.json'; + + + +Contact [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 18 | 0 | 17 | 0 | + +## Client + +### Functions + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index 908eb9080cd60..6213792bbe697 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mock.mdx b/api_docs/kbn_code_editor_mock.mdx index 09595244de2cb..7ba6695edffe4 100644 --- a/api_docs/kbn_code_editor_mock.mdx +++ b/api_docs/kbn_code_editor_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mock title: "@kbn/code-editor-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mock plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mock'] --- import kbnCodeEditorMockObj from './kbn_code_editor_mock.devdocs.json'; diff --git a/api_docs/kbn_code_owners.mdx b/api_docs/kbn_code_owners.mdx index 2e80806fadf0e..f736234760aa6 100644 --- a/api_docs/kbn_code_owners.mdx +++ b/api_docs/kbn_code_owners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-owners title: "@kbn/code-owners" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-owners plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-owners'] --- import kbnCodeOwnersObj from './kbn_code_owners.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index b70f71c8e4694..c78bba1b4b0f6 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 280ddbb9d3d77..ca819f5cd11e0 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index b4d34ee9d0884..6920ebca02423 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 53924f175150e..314e395ef9a60 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index e8bc80179f1a2..5093af3ad6894 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_public.mdx b/api_docs/kbn_content_management_content_insights_public.mdx index 16ba14cf1421c..ff9cf1d6cb6f1 100644 --- a/api_docs/kbn_content_management_content_insights_public.mdx +++ b/api_docs/kbn_content_management_content_insights_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-public title: "@kbn/content-management-content-insights-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-public plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-public'] --- import kbnContentManagementContentInsightsPublicObj from './kbn_content_management_content_insights_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_server.mdx b/api_docs/kbn_content_management_content_insights_server.mdx index c22e848ce98c9..c2fb3b38c69df 100644 --- a/api_docs/kbn_content_management_content_insights_server.mdx +++ b/api_docs/kbn_content_management_content_insights_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-server title: "@kbn/content-management-content-insights-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-server'] --- import kbnContentManagementContentInsightsServerObj from './kbn_content_management_content_insights_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_public.mdx b/api_docs/kbn_content_management_favorites_public.mdx index df010f9cf1c66..f839ff271bea5 100644 --- a/api_docs/kbn_content_management_favorites_public.mdx +++ b/api_docs/kbn_content_management_favorites_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-public title: "@kbn/content-management-favorites-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-public plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-public'] --- import kbnContentManagementFavoritesPublicObj from './kbn_content_management_favorites_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_server.mdx b/api_docs/kbn_content_management_favorites_server.mdx index 7437543f2f848..5db1bbe6c7c06 100644 --- a/api_docs/kbn_content_management_favorites_server.mdx +++ b/api_docs/kbn_content_management_favorites_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-server title: "@kbn/content-management-favorites-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-server'] --- import kbnContentManagementFavoritesServerObj from './kbn_content_management_favorites_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index 4b1db955ffae0..b386d3267d885 100644 --- a/api_docs/kbn_content_management_tabbed_table_list_view.mdx +++ b/api_docs/kbn_content_management_tabbed_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-tabbed-table-list-view title: "@kbn/content-management-tabbed-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-tabbed-table-list-view plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-tabbed-table-list-view'] --- import kbnContentManagementTabbedTableListViewObj from './kbn_content_management_tabbed_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view.mdx b/api_docs/kbn_content_management_table_list_view.mdx index d5305bd8deb84..9574aea73af9d 100644 --- a/api_docs/kbn_content_management_table_list_view.mdx +++ b/api_docs/kbn_content_management_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view title: "@kbn/content-management-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view'] --- import kbnContentManagementTableListViewObj from './kbn_content_management_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_common.mdx b/api_docs/kbn_content_management_table_list_view_common.mdx index 488e98e1a0788..8ffb60bc661b1 100644 --- a/api_docs/kbn_content_management_table_list_view_common.mdx +++ b/api_docs/kbn_content_management_table_list_view_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-common title: "@kbn/content-management-table-list-view-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-common'] --- import kbnContentManagementTableListViewCommonObj from './kbn_content_management_table_list_view_common.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index ba09425a77101..86bede673f7f7 100644 --- a/api_docs/kbn_content_management_table_list_view_table.mdx +++ b/api_docs/kbn_content_management_table_list_view_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-table title: "@kbn/content-management-table-list-view-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-table plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_user_profiles.mdx b/api_docs/kbn_content_management_user_profiles.mdx index 3f05cd4a2410c..08d0ca41a0ddf 100644 --- a/api_docs/kbn_content_management_user_profiles.mdx +++ b/api_docs/kbn_content_management_user_profiles.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-user-profiles title: "@kbn/content-management-user-profiles" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-user-profiles plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-user-profiles'] --- import kbnContentManagementUserProfilesObj from './kbn_content_management_user_profiles.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index c3951f0b13008..fead3a0c4219a 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.devdocs.json b/api_docs/kbn_core_analytics_browser.devdocs.json index d5dec8bb07c0a..288f48a4955a0 100644 --- a/api_docs/kbn_core_analytics_browser.devdocs.json +++ b/api_docs/kbn_core_analytics_browser.devdocs.json @@ -722,10 +722,6 @@ "plugin": "elasticAssistant", "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/post/helpers/handle_graph_error/index.tsx" }, - { - "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts" - }, { "plugin": "globalSearchBar", "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" @@ -782,6 +778,30 @@ "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" @@ -950,6 +970,22 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts" @@ -1010,6 +1046,22 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, { "plugin": "observabilityLogsExplorer", "path": "x-pack/plugins/observability_solution/observability_logs_explorer/public/state_machines/observability_logs_explorer/src/telemetry_events.ts" @@ -1402,6 +1454,70 @@ "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 38ff55655ec8e..6ea9a15b5a1ee 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index d847b170231e7..5da9894ceaaf4 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index a36c41c26390d..a6d457a2b1f0a 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.devdocs.json b/api_docs/kbn_core_analytics_server.devdocs.json index 8cf99c35166ab..c08c5dec164f0 100644 --- a/api_docs/kbn_core_analytics_server.devdocs.json +++ b/api_docs/kbn_core_analytics_server.devdocs.json @@ -730,10 +730,6 @@ "plugin": "elasticAssistant", "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/post/helpers/handle_graph_error/index.tsx" }, - { - "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts" - }, { "plugin": "globalSearchBar", "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" @@ -790,6 +786,30 @@ "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" @@ -958,6 +978,22 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts" @@ -1018,6 +1054,22 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, { "plugin": "observabilityLogsExplorer", "path": "x-pack/plugins/observability_solution/observability_logs_explorer/public/state_machines/observability_logs_explorer/src/telemetry_events.ts" @@ -1410,6 +1462,70 @@ "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 552b3c889df2e..0de038e5c0cc8 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index 57f1ebeee476f..fe2f352269943 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index 2be7ad246d6d2..1bb4be4940a06 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser.mdx b/api_docs/kbn_core_application_browser.mdx index 27e5355f0d380..22276eb1bc561 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser'] --- import kbnCoreApplicationBrowserObj from './kbn_core_application_browser.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_internal.mdx b/api_docs/kbn_core_application_browser_internal.mdx index 59a7c14a1183f..060e08e11932a 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-internal'] --- import kbnCoreApplicationBrowserInternalObj from './kbn_core_application_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_mocks.mdx b/api_docs/kbn_core_application_browser_mocks.mdx index 2aa4aeaeb0b6a..8e8e6e35f2ba6 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-mocks'] --- import kbnCoreApplicationBrowserMocksObj from './kbn_core_application_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_common.mdx b/api_docs/kbn_core_application_common.mdx index 651d0d1cf1be9..c633544970950 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-common'] --- import kbnCoreApplicationCommonObj from './kbn_core_application_common.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_internal.mdx b/api_docs/kbn_core_apps_browser_internal.mdx index 6fa3be391616f..272b0f57ca72d 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-internal'] --- import kbnCoreAppsBrowserInternalObj from './kbn_core_apps_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_mocks.mdx b/api_docs/kbn_core_apps_browser_mocks.mdx index 3af58c89ed8ac..309456742cc12 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index 5e7d22b0cda8e..36e7ffcc1fd45 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index de028b6a0a5cf..72ec2fbd89e87 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index 5e865fd249196..d36cd1ea19d8c 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 99dbc9056aaf6..3feb90f04c411 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index 5f6190b4bad24..a11caeccc157b 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_browser_mocks.mdx b/api_docs/kbn_core_capabilities_browser_mocks.mdx index 7115d3bb7d62c..376c9d2063a8f 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-browser-mocks'] --- import kbnCoreCapabilitiesBrowserMocksObj from './kbn_core_capabilities_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index a4cb7c5d24f54..4e77a01235170 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index d3472845a8b14..0b9e04fdd97b2 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 7b62e26f37d4c..33bfeec38de7a 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.devdocs.json b/api_docs/kbn_core_chrome_browser.devdocs.json index 9a5c873f29227..74cc5c0a5be1b 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -3259,6 +3259,20 @@ "deprecated": false, "trackAdoption": false, "children": [ + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-public.NavigationTreeDefinitionUI.id", + "type": "CompoundType", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "\"security\" | \"es\" | \"oblt\"" + ], + "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-chrome-browser", "id": "def-public.NavigationTreeDefinitionUI.body", @@ -3630,12 +3644,15 @@ { "parentPluginId": "@kbn/core-chrome-browser", "id": "def-public.SolutionNavigationDefinition.id", - "type": "string", + "type": "CompoundType", "tags": [], "label": "id", "description": [ "Unique id for the solution navigation." ], + "signature": [ + "\"security\" | \"es\" | \"oblt\"" + ], "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, "trackAdoption": false @@ -3736,50 +3753,6 @@ } ], "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/core-chrome-browser", - "id": "def-public.SolutionNavigationDefinitions", - "type": "Interface", - "tags": [], - "label": "SolutionNavigationDefinitions", - "description": [], - "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/core-chrome-browser", - "id": "def-public.SolutionNavigationDefinitions.Unnamed", - "type": "IndexSignature", - "tags": [], - "label": "[id: string]: SolutionNavigationDefinition", - "description": [], - "signature": [ - "[id: string]: ", - { - "pluginId": "@kbn/core-chrome-browser", - "scope": "public", - "docId": "kibKbnCoreChromeBrowserPluginApi", - "section": "def-public.SolutionNavigationDefinition", - "text": "SolutionNavigationDefinition" - }, - "<", - { - "pluginId": "@kbn/core-chrome-browser", - "scope": "public", - "docId": "kibKbnCoreChromeBrowserPluginApi", - "section": "def-public.AppDeepLinkId", - "text": "AppDeepLinkId" - }, - ">" - ], - "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false } ], "enums": [], @@ -3792,7 +3765,7 @@ "label": "AppDeepLinkId", "description": [], "signature": [ - "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" ], "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, @@ -4226,6 +4199,84 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-public.SolutionId", + "type": "Type", + "tags": [], + "label": "SolutionId", + "description": [], + "signature": [ + "\"security\" | \"es\" | \"oblt\"" + ], + "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-public.SolutionNavigationDefinitions", + "type": "Type", + "tags": [], + "label": "SolutionNavigationDefinitions", + "description": [], + "signature": [ + "{ security?: ", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.SolutionNavigationDefinition", + "text": "SolutionNavigationDefinition" + }, + "<", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.AppDeepLinkId", + "text": "AppDeepLinkId" + }, + "> | undefined; es?: ", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.SolutionNavigationDefinition", + "text": "SolutionNavigationDefinition" + }, + "<", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.AppDeepLinkId", + "text": "AppDeepLinkId" + }, + "> | undefined; oblt?: ", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.SolutionNavigationDefinition", + "text": "SolutionNavigationDefinition" + }, + "<", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.AppDeepLinkId", + "text": "AppDeepLinkId" + }, + "> | undefined; }" + ], + "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 748ba5e37febe..e5fcf858f4958 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 210 | 0 | 103 | 0 | +| 211 | 0 | 104 | 0 | ## Client diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index dc0178f1ca9c3..9e6570053f74b 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser-mocks'] --- import kbnCoreChromeBrowserMocksObj from './kbn_core_chrome_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 36582efd7b78f..36b8723c641ff 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index a918d027cb3d1..b4000b5997f13 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index 0b57551e3fb79..7450bcf7129c3 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index 85ff8336bbbeb..d48ce8fe7dc08 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index dc80d6c66be28..08a5b24fab14c 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index b11db6dc44dfc..aa860de0b7473 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index 2b6381208cc18..f6e33df5421c1 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index 41ba06074bfcc..0ad756867a747 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index a7c6e52fad558..f680d3d812f55 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index f855a29466080..8e4be1e6de60f 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index 2f0b975bbcbf6..b5f21b60a8f69 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index be72e4f6760ad..2cb12eac8efad 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server.mdx b/api_docs/kbn_core_deprecations_server.mdx index 392e440a5da95..072a6742bfd7e 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server'] --- import kbnCoreDeprecationsServerObj from './kbn_core_deprecations_server.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_internal.mdx b/api_docs/kbn_core_deprecations_server_internal.mdx index 9c2e69b287516..d27bf5dd3375d 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-internal'] --- import kbnCoreDeprecationsServerInternalObj from './kbn_core_deprecations_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_mocks.mdx b/api_docs/kbn_core_deprecations_server_mocks.mdx index 509956cfecce6..dd730b724cf71 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-mocks'] --- import kbnCoreDeprecationsServerMocksObj from './kbn_core_deprecations_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index c4081a26f43b1..dd8b108d9b70f 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index 1c29760a75995..4fa2a34b07f81 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 9f4b64a4b5e41..02dbf2f80f3df 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 4544289280c30..806f4c37c27a8 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index ce0a6c58bcee3..0c967f7f33e4f 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 385a3409631f9..ad224bb3244ac 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 0fb8dda03687d..f7d3f5abe448a 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 89a052cab3b34..9bc05a5fcffdb 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 4bc81fc43a17c..82fe06225c2a4 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index 59bee3352b8b2..e2b6219d0bf79 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index 7d0352b91db05..9d7bba4866ada 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index 2566cbfdabccc..03e1200905154 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 502276b9844e5..eea7b9c6a40ee 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index 82a11dcb24e59..afde840e9fb1d 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index 3b6407e6bfcec..c5d6c2604915f 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 33eed5a35b2d8..493a78f48f5ea 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index 98f1e4cf49391..1b52ccbfe62a9 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index 13a1a80f5d362..a9fa2eee4318b 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index 37c5284973860..28090e7cf59a4 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index 707bbde3cbcc4..de2cccb198719 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser.mdx b/api_docs/kbn_core_feature_flags_browser.mdx index 4867bd71d5011..943fda86e47ab 100644 --- a/api_docs/kbn_core_feature_flags_browser.mdx +++ b/api_docs/kbn_core_feature_flags_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser title: "@kbn/core-feature-flags-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser'] --- import kbnCoreFeatureFlagsBrowserObj from './kbn_core_feature_flags_browser.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser_internal.mdx b/api_docs/kbn_core_feature_flags_browser_internal.mdx index 1d66bf24d83e8..05be8f5d4dcd2 100644 --- a/api_docs/kbn_core_feature_flags_browser_internal.mdx +++ b/api_docs/kbn_core_feature_flags_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser-internal title: "@kbn/core-feature-flags-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser-internal'] --- import kbnCoreFeatureFlagsBrowserInternalObj from './kbn_core_feature_flags_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser_mocks.mdx b/api_docs/kbn_core_feature_flags_browser_mocks.mdx index 26c57eab529ef..b6a92c92da5b1 100644 --- a/api_docs/kbn_core_feature_flags_browser_mocks.mdx +++ b/api_docs/kbn_core_feature_flags_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser-mocks title: "@kbn/core-feature-flags-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser-mocks'] --- import kbnCoreFeatureFlagsBrowserMocksObj from './kbn_core_feature_flags_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server.mdx b/api_docs/kbn_core_feature_flags_server.mdx index c945e0897bd65..d99bc3d2c15a1 100644 --- a/api_docs/kbn_core_feature_flags_server.mdx +++ b/api_docs/kbn_core_feature_flags_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server title: "@kbn/core-feature-flags-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server'] --- import kbnCoreFeatureFlagsServerObj from './kbn_core_feature_flags_server.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server_internal.mdx b/api_docs/kbn_core_feature_flags_server_internal.mdx index 4bd0e16beb684..d1e046e60e94d 100644 --- a/api_docs/kbn_core_feature_flags_server_internal.mdx +++ b/api_docs/kbn_core_feature_flags_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server-internal title: "@kbn/core-feature-flags-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server-internal'] --- import kbnCoreFeatureFlagsServerInternalObj from './kbn_core_feature_flags_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server_mocks.mdx b/api_docs/kbn_core_feature_flags_server_mocks.mdx index 76ef53a8d04eb..45a311d4aabd1 100644 --- a/api_docs/kbn_core_feature_flags_server_mocks.mdx +++ b/api_docs/kbn_core_feature_flags_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server-mocks title: "@kbn/core-feature-flags-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server-mocks'] --- import kbnCoreFeatureFlagsServerMocksObj from './kbn_core_feature_flags_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index da77d27edace6..03132a3e4b157 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 4ff37c536625f..97d25aa89d1ec 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index e819399a30d90..bda77f088d868 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index b312d444c22d7..943f63f33b20b 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index a5afe9bc0f1de..b51310fcfb964 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index 82c3dacf2b394..15d2dabf3618e 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index 45c900eb34e0a..cc20016d62ddf 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index d0f55f2cc9fe9..b29be47eb284e 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index befb4ad6b3360..4b1b2d9be6fd7 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index 6afe3f87c6622..aa077e10fe7cf 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index cf4fe8373a025..ce98db595acc8 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index 35bd18cec9bde..fc742149a4495 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -3891,18 +3891,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/connector/get/get.ts" }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get_all.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/list_action_types.ts" - }, { "plugin": "share", "path": "src/plugins/share/server/url_service/http/short_urls/register_get_route.ts" @@ -5415,54 +5403,6 @@ "plugin": "triggersActionsUi", "path": "x-pack/plugins/triggers_actions_ui/server/routes/config.test.ts" }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get_all.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get_all.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get_all.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/get_all.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/list_action_types.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/list_action_types.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/list_action_types.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/list_action_types.test.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/find.test.ts" @@ -5783,6 +5723,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/maintenance_window/apis/get/get_maintenance_window_route.test.ts" @@ -6569,14 +6513,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/get_oauth_access_token.ts" }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/create.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/execute.ts" - }, { "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/get_global_execution_logs.ts" @@ -7869,46 +7805,6 @@ "plugin": "ruleRegistry", "path": "x-pack/plugins/rule_registry/server/routes/__mocks__/server.ts" }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/create.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/create.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/create.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/create.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/execute.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/execute.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/execute.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/execute.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/execute.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/execute.test.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/create.test.ts" @@ -8795,10 +8691,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/connector/update/update.ts" }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/update.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/update.ts" @@ -9179,26 +9071,6 @@ "plugin": "ruleRegistry", "path": "x-pack/plugins/rule_registry/server/routes/__mocks__/server.ts" }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/update.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/update.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/update.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/update.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/update.test.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/update.test.ts" @@ -9807,10 +9679,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/connector/delete/delete.ts" }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/delete.ts" - }, { "plugin": "share", "path": "src/plugins/share/server/url_service/http/short_urls/register_delete_route.ts" @@ -10095,22 +9963,6 @@ "plugin": "ruleRegistry", "path": "x-pack/plugins/rule_registry/server/routes/__mocks__/server.ts" }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/delete.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/delete.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/delete.test.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/legacy/delete.test.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/delete.test.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 0f129f549cabc..d66f291bb585d 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 2c9cda9b414f2..068f94bbe00ef 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index 9becf34cf3e54..ecc556517e2fc 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 91278abc3e334..283642f2f2b48 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index 4261103113312..164854b3360de 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index 9dda3a9665424..65aff06bba4e9 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index 7b7a83177657c..c156e63d9287b 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index 26208edaffe76..a248bd9aaa65c 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 5481756a5ffbe..b5dfa4950c432 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index e89d0730578a4..92b229df0dea5 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index 3a858d43adee3..0f786cc3de74f 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index 157680a23afea..28aaf9c010d4a 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index 7b4d793557a5f..098977edf8a45 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index 0a2fef2f2628f..62b17f1748670 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index b0f5a9b868d3a..6275fff69b2f4 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index 3958b5fb088f0..0548bd0822148 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index 40b54fb602ff3..2bcda4896adb1 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 39b07dcdb118f..d61fd8af32187 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 6a92a0d76e98f..64e8ff2644f02 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 7c880dcfefb89..b6b19d625b9aa 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 5328ee4e81fcf..c0343c3b6fba9 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 034f9c42a4dcf..ee592d1ea5aaf 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index 5e2430d3fc3d3..f2bb56ef54648 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 8084230e0aa7e..39e77c9e29435 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index e1d68dcacbc91..87e3cfe6c8c54 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 15e1b9336ac68..098e0c8ad5a1e 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 733fba5e1c7d9..ff21bdc820b1a 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index 27ac76878b35e..053a64bd6939a 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index e6866432f43de..10d22bfc2e6b4 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index 1d31ebf2ee934..484067d042827 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index 884d8a6f5ec44..2b03a50e949db 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index dcf26199c458a..26ee5cc8b67a1 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 974aa27ed52b2..7160b9f812de9 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index ce1c87b69ff8d..89fe125006fc0 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 520c29279e897..e6c53bc690cd3 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index 7440908693fac..fc4ca4542d35e 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index b9e327d31514d..46d6217ac9089 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index 09f6e57fa9405..27122580de4eb 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index 2ed82c4f2d80a..5011ebb96f585 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index ee98e78a69db8..1f5e143f6e1bd 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 506da2bee329e..4c78b095ec83a 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index 5b664c9fea407..e2bb1bf002b06 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index c024bfbeddc7c..b6d8f765bf1ab 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index 72b72f350f144..f7dbf554ad790 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index 224b3a0ec37c0..3715772deff10 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index 80d0828edc829..137eeaac82c12 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 47b59bc27bcc7..70ae3a6a47cad 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 053bc36ab2e89..2b339e4c44843 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.devdocs.json b/api_docs/kbn_core_saved_objects_api_server.devdocs.json index 78c5844109cd2..7b8b82e990599 100644 --- a/api_docs/kbn_core_saved_objects_api_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_server.devdocs.json @@ -2746,26 +2746,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/application/connector/methods/create/create.ts" }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/rules_client/common/inject_references.ts" @@ -2782,30 +2762,6 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/types.ts" }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/saved_objects/geo_containment/migrations.ts" diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index a7e9ace76cfc8..4f939a18dce96 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 74c8e94e01033..c31fffac3c926 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index cefd397c25f79..08e3a6feeb48c 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index d51a61c24e73d..62c25e8fb7f32 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index ccbf92cec3456..82099920bc4c9 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index beb66154c76e1..e1539e36e123f 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index bd11402aecbee..540e7067635b7 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index 412f66f224c67..957e8e68d5708 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index 631b31671f57a..2a49cf2566281 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index b5db588cea70c..4f9202273bca7 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index 1d81a105baaea..61fe57dbcd799 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index 06c42c5eef4b6..71d7d1cc58655 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.devdocs.json b/api_docs/kbn_core_saved_objects_server.devdocs.json index fecd38966f116..c34c701d22002 100644 --- a/api_docs/kbn_core_saved_objects_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_server.devdocs.json @@ -6237,26 +6237,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/application/connector/methods/create/create.ts" }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/rules_client/common/inject_references.ts" @@ -6273,30 +6253,6 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/types.ts" }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/types.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/saved_objects/geo_containment/migrations.ts" diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 690299c9f6169..86a4e387d702d 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index b53dcf86beecb..1923b7351f521 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index 342e63a245624..3e2491f52c291 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index 118101f884759..ace5594e319bb 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser.mdx b/api_docs/kbn_core_security_browser.mdx index 34a1beebd0f8b..0722fcdb1e641 100644 --- a/api_docs/kbn_core_security_browser.mdx +++ b/api_docs/kbn_core_security_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser title: "@kbn/core-security-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser'] --- import kbnCoreSecurityBrowserObj from './kbn_core_security_browser.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_internal.mdx b/api_docs/kbn_core_security_browser_internal.mdx index 4f2a74ca003e0..28a7796bf86a0 100644 --- a/api_docs/kbn_core_security_browser_internal.mdx +++ b/api_docs/kbn_core_security_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-internal title: "@kbn/core-security-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-internal'] --- import kbnCoreSecurityBrowserInternalObj from './kbn_core_security_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_mocks.mdx b/api_docs/kbn_core_security_browser_mocks.mdx index eb1e69eec1c5f..45f98c60ad917 100644 --- a/api_docs/kbn_core_security_browser_mocks.mdx +++ b/api_docs/kbn_core_security_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-mocks title: "@kbn/core-security-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-mocks'] --- import kbnCoreSecurityBrowserMocksObj from './kbn_core_security_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_security_common.mdx b/api_docs/kbn_core_security_common.mdx index 2d76be55d62ca..48a20821ec963 100644 --- a/api_docs/kbn_core_security_common.mdx +++ b/api_docs/kbn_core_security_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-common title: "@kbn/core-security-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-common'] --- import kbnCoreSecurityCommonObj from './kbn_core_security_common.devdocs.json'; diff --git a/api_docs/kbn_core_security_server.mdx b/api_docs/kbn_core_security_server.mdx index 0e592f11a44b7..b0b8721fcbbcc 100644 --- a/api_docs/kbn_core_security_server.mdx +++ b/api_docs/kbn_core_security_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server title: "@kbn/core-security-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server'] --- import kbnCoreSecurityServerObj from './kbn_core_security_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_internal.mdx b/api_docs/kbn_core_security_server_internal.mdx index 167fc0d4768a0..2b992a29cdb06 100644 --- a/api_docs/kbn_core_security_server_internal.mdx +++ b/api_docs/kbn_core_security_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-internal title: "@kbn/core-security-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-internal'] --- import kbnCoreSecurityServerInternalObj from './kbn_core_security_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_mocks.mdx b/api_docs/kbn_core_security_server_mocks.mdx index 64cf0f346da8c..8912f3027e1fc 100644 --- a/api_docs/kbn_core_security_server_mocks.mdx +++ b/api_docs/kbn_core_security_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-mocks title: "@kbn/core-security-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-mocks'] --- import kbnCoreSecurityServerMocksObj from './kbn_core_security_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index 293bad7ac9b40..019330ce8b4e2 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index 9043954847c3d..fd8118af20136 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index 86bd69b7bd616..b204af0082fa1 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index 3ed61484f2f7e..7164e942e4c1e 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index 31973ea45aa86..be061ce19255b 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index a6c1da6e38a94..3e9f82e1e9519 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index 1ab880f8f6a35..592ae6950991a 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index 9820ab3cb3165..04ab1b7b18ec5 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index af15198a4e010..f4ed2c8404b4e 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 61c3fb6ad11cb..8a54ec213d267 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index 808c35883891e..9d20649a27ed6 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 16d999498587d..89c8cf61efda4 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 5c81b517dd4bc..e3260e79a6ca2 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 117707111955e..c6cd54c6e6ebb 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 71522e93920ab..92c1ca6525a70 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index e47c382c2eded..cc55590ffedae 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index 2e1c8f89f8bcd..f2b79c56583dc 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index ad53f3bc01ce9..6d082b2682f93 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index 78a75d3e84cf1..b3ba2a52becac 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index eadd313d92375..a9fe942e27204 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index f4ac5dc3e9bf8..73f49ac82e5e1 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index c52e538d5fdb9..bff1e20b3b2c7 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index 42bd15e5a53cd..0a99a56360b49 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser.mdx b/api_docs/kbn_core_user_profile_browser.mdx index 20a020e788b7e..4b29672ce3507 100644 --- a/api_docs/kbn_core_user_profile_browser.mdx +++ b/api_docs/kbn_core_user_profile_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser title: "@kbn/core-user-profile-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser'] --- import kbnCoreUserProfileBrowserObj from './kbn_core_user_profile_browser.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_internal.mdx b/api_docs/kbn_core_user_profile_browser_internal.mdx index e1b87c3eb8e7f..9369a3205c419 100644 --- a/api_docs/kbn_core_user_profile_browser_internal.mdx +++ b/api_docs/kbn_core_user_profile_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-internal title: "@kbn/core-user-profile-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-internal'] --- import kbnCoreUserProfileBrowserInternalObj from './kbn_core_user_profile_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_mocks.mdx b/api_docs/kbn_core_user_profile_browser_mocks.mdx index eee10551db541..9fd50a9d48af0 100644 --- a/api_docs/kbn_core_user_profile_browser_mocks.mdx +++ b/api_docs/kbn_core_user_profile_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-mocks title: "@kbn/core-user-profile-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-mocks'] --- import kbnCoreUserProfileBrowserMocksObj from './kbn_core_user_profile_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_common.mdx b/api_docs/kbn_core_user_profile_common.mdx index bc9a34486f712..3bdb0b47cf9e7 100644 --- a/api_docs/kbn_core_user_profile_common.mdx +++ b/api_docs/kbn_core_user_profile_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-common title: "@kbn/core-user-profile-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-common'] --- import kbnCoreUserProfileCommonObj from './kbn_core_user_profile_common.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server.mdx b/api_docs/kbn_core_user_profile_server.mdx index 37676f3e30a09..9d6505a559bf7 100644 --- a/api_docs/kbn_core_user_profile_server.mdx +++ b/api_docs/kbn_core_user_profile_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server title: "@kbn/core-user-profile-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server'] --- import kbnCoreUserProfileServerObj from './kbn_core_user_profile_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_internal.mdx b/api_docs/kbn_core_user_profile_server_internal.mdx index fd33971ae59e7..ffcd6cfd2fab4 100644 --- a/api_docs/kbn_core_user_profile_server_internal.mdx +++ b/api_docs/kbn_core_user_profile_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-internal title: "@kbn/core-user-profile-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-internal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-internal'] --- import kbnCoreUserProfileServerInternalObj from './kbn_core_user_profile_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_mocks.mdx b/api_docs/kbn_core_user_profile_server_mocks.mdx index d02d813e6b893..6eca7a76b7261 100644 --- a/api_docs/kbn_core_user_profile_server_mocks.mdx +++ b/api_docs/kbn_core_user_profile_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-mocks title: "@kbn/core-user-profile-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-mocks'] --- import kbnCoreUserProfileServerMocksObj from './kbn_core_user_profile_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index cbbd484348bf3..312191eaae0b2 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index 3d9f24b401d27..ceb76aae74ec1 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index e08941938cfff..d36ff18b0bde5 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index 7821769fc9433..d7ab72aee0d1b 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_icons.mdx b/api_docs/kbn_custom_icons.mdx index b7559cadccfed..b7994dcc55b53 100644 --- a/api_docs/kbn_custom_icons.mdx +++ b/api_docs/kbn_custom_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-icons title: "@kbn/custom-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-icons plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-icons'] --- import kbnCustomIconsObj from './kbn_custom_icons.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index 566186b6a0add..d7764fc6ad71b 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index 5f7ccbb6cedb8..bd23f94d999ed 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_forge.mdx b/api_docs/kbn_data_forge.mdx index e55be5f3ce3e4..dcec7e4697df9 100644 --- a/api_docs/kbn_data_forge.mdx +++ b/api_docs/kbn_data_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-forge title: "@kbn/data-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-forge plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-forge'] --- import kbnDataForgeObj from './kbn_data_forge.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 61477da487d59..89b7eefc7d821 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_data_stream_adapter.devdocs.json b/api_docs/kbn_data_stream_adapter.devdocs.json index 0cd9d1c79b2f8..1893c1919bcbd 100644 --- a/api_docs/kbn_data_stream_adapter.devdocs.json +++ b/api_docs/kbn_data_stream_adapter.devdocs.json @@ -1109,7 +1109,7 @@ "section": "def-common.MultiField", "text": "MultiField" }, - "[] | undefined; index?: boolean | undefined; path?: string | undefined; scaling_factor?: number | undefined; dynamic?: boolean | \"strict\" | undefined; properties?: Record | undefined; }; }" + "[] | undefined; index?: boolean | undefined; path?: string | undefined; scaling_factor?: number | undefined; dynamic?: boolean | \"strict\" | undefined; properties?: Record | undefined; inference_id?: string | undefined; copy_to?: string | undefined; }; }" ], "path": "packages/kbn-data-stream-adapter/src/data_stream_adapter.ts", "deprecated": false, @@ -1248,7 +1248,7 @@ "section": "def-common.MultiField", "text": "MultiField" }, - "[] | undefined; index?: boolean | undefined; path?: string | undefined; scaling_factor?: number | undefined; dynamic?: boolean | \"strict\" | undefined; properties?: Record | undefined; }; }" + "[] | undefined; index?: boolean | undefined; path?: string | undefined; scaling_factor?: number | undefined; dynamic?: boolean | \"strict\" | undefined; properties?: Record | undefined; inference_id?: string | undefined; copy_to?: string | undefined; }; }" ], "path": "packages/kbn-data-stream-adapter/src/field_maps/ecs_field_map.ts", "deprecated": false, @@ -1271,7 +1271,7 @@ "section": "def-common.MultiField", "text": "MultiField" }, - "[] | undefined; index?: boolean | undefined; path?: string | undefined; scaling_factor?: number | undefined; dynamic?: boolean | \"strict\" | undefined; properties?: Record | undefined; }; }" + "[] | undefined; index?: boolean | undefined; path?: string | undefined; scaling_factor?: number | undefined; dynamic?: boolean | \"strict\" | undefined; properties?: Record | undefined; inference_id?: string | undefined; copy_to?: string | undefined; }; }" ], "path": "packages/kbn-data-stream-adapter/src/field_maps/types.ts", "deprecated": false, @@ -1319,7 +1319,7 @@ "section": "def-common.MultiField", "text": "MultiField" }, - "[] | undefined; index?: boolean | undefined; path?: string | undefined; scaling_factor?: number | undefined; dynamic?: boolean | \"strict\" | undefined; properties?: Record | undefined; }; }" + "[] | undefined; index?: boolean | undefined; path?: string | undefined; scaling_factor?: number | undefined; dynamic?: boolean | \"strict\" | undefined; properties?: Record | undefined; inference_id?: string | undefined; copy_to?: string | undefined; }; }" ], "path": "packages/kbn-data-stream-adapter/src/field_maps/ecs_field_map.ts", "deprecated": false, diff --git a/api_docs/kbn_data_stream_adapter.mdx b/api_docs/kbn_data_stream_adapter.mdx index 83ad4f7a30151..53bc517415b12 100644 --- a/api_docs/kbn_data_stream_adapter.mdx +++ b/api_docs/kbn_data_stream_adapter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-stream-adapter title: "@kbn/data-stream-adapter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-stream-adapter plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-stream-adapter'] --- import kbnDataStreamAdapterObj from './kbn_data_stream_adapter.devdocs.json'; diff --git a/api_docs/kbn_data_view_utils.mdx b/api_docs/kbn_data_view_utils.mdx index d5c26b7229efc..f0755cb6b1ba9 100644 --- a/api_docs/kbn_data_view_utils.mdx +++ b/api_docs/kbn_data_view_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-view-utils title: "@kbn/data-view-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-view-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-view-utils'] --- import kbnDataViewUtilsObj from './kbn_data_view_utils.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 53a8c087280b1..fca00527a69f3 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index 2eb233e083455..a344680bc8365 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index 58ec9fc9db98b..7b69bf1deebbc 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_fleet.mdx b/api_docs/kbn_deeplinks_fleet.mdx index d4e26ed2b3fd8..1edfd7222fefa 100644 --- a/api_docs/kbn_deeplinks_fleet.mdx +++ b/api_docs/kbn_deeplinks_fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-fleet title: "@kbn/deeplinks-fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-fleet plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-fleet'] --- import kbnDeeplinksFleetObj from './kbn_deeplinks_fleet.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index d7bbe21013ebf..c6dc83e676cfb 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index a6378a819d7c7..556124633ad3a 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index c5dfeb09e5b39..49f102e3d3fd0 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.devdocs.json b/api_docs/kbn_deeplinks_search.devdocs.json index 8376c52ebf1ea..d8cd4e993a4e4 100644 --- a/api_docs/kbn_deeplinks_search.devdocs.json +++ b/api_docs/kbn_deeplinks_search.devdocs.json @@ -30,7 +30,7 @@ "label": "DeepLinkId", "description": [], "signature": [ - "\"appSearch\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\"" + "\"appSearch\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\"" ], "path": "packages/deeplinks/search/deep_links.ts", "deprecated": false, @@ -232,6 +232,66 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/deeplinks-search", + "id": "def-common.SEARCH_AI_SEARCH", + "type": "string", + "tags": [], + "label": "SEARCH_AI_SEARCH", + "description": [], + "signature": [ + "\"enterpriseSearchAISearch\"" + ], + "path": "packages/deeplinks/search/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/deeplinks-search", + "id": "def-common.SEARCH_ELASTICSEARCH", + "type": "string", + "tags": [], + "label": "SEARCH_ELASTICSEARCH", + "description": [], + "signature": [ + "\"enterpriseSearchElasticsearch\"" + ], + "path": "packages/deeplinks/search/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/deeplinks-search", + "id": "def-common.SEARCH_SEMANTIC_SEARCH", + "type": "string", + "tags": [], + "label": "SEARCH_SEMANTIC_SEARCH", + "description": [], + "signature": [ + "\"enterpriseSearchSemanticSearch\"" + ], + "path": "packages/deeplinks/search/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/deeplinks-search", + "id": "def-common.SEARCH_VECTOR_SEARCH", + "type": "string", + "tags": [], + "label": "SEARCH_VECTOR_SEARCH", + "description": [], + "signature": [ + "\"enterpriseSearchVectorSearch\"" + ], + "path": "packages/deeplinks/search/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/deeplinks-search", "id": "def-common.SERVERLESS_ES_APP_ID", diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index d72d29877b369..4662c3e0fc212 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-ki | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 17 | 0 | 17 | 0 | +| 21 | 0 | 21 | 0 | ## Common diff --git a/api_docs/kbn_deeplinks_security.mdx b/api_docs/kbn_deeplinks_security.mdx index f5c99a50635bb..f5956cbe3a9da 100644 --- a/api_docs/kbn_deeplinks_security.mdx +++ b/api_docs/kbn_deeplinks_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-security title: "@kbn/deeplinks-security" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-security plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-security'] --- import kbnDeeplinksSecurityObj from './kbn_deeplinks_security.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_shared.mdx b/api_docs/kbn_deeplinks_shared.mdx index d84485e163776..4f502cc5a292d 100644 --- a/api_docs/kbn_deeplinks_shared.mdx +++ b/api_docs/kbn_deeplinks_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-shared title: "@kbn/deeplinks-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-shared plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-shared'] --- import kbnDeeplinksSharedObj from './kbn_deeplinks_shared.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index 3beda1c97aaba..d3e2983b1986f 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index 833402a621001..5efd56de2d99b 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index f7ffc888e932a..10fb9a69dd148 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index 8192bb865a9ed..5e90d50571f50 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 0be01879092b3..82961d44d2252 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 87cdfb552eaa6..d3a1af810206c 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index 57fc632d581e2..f34f24b583378 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 42783b7c5e50b..580681eed680d 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_contextual_components.mdx b/api_docs/kbn_discover_contextual_components.mdx index f871112fe2bb2..09a6450ebccdb 100644 --- a/api_docs/kbn_discover_contextual_components.mdx +++ b/api_docs/kbn_discover_contextual_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-contextual-components title: "@kbn/discover-contextual-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-contextual-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-contextual-components'] --- import kbnDiscoverContextualComponentsObj from './kbn_discover_contextual_components.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.devdocs.json b/api_docs/kbn_discover_utils.devdocs.json index 25a8aaaf454cb..96845d5017c89 100644 --- a/api_docs/kbn_discover_utils.devdocs.json +++ b/api_docs/kbn_discover_utils.devdocs.json @@ -17,7 +17,266 @@ "objects": [] }, "common": { - "classes": [], + "classes": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry", + "type": "Class", + "tags": [], + "label": "AppMenuRegistry", + "description": [], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.CUSTOM_ITEMS_LIMIT", + "type": "number", + "tags": [], + "label": "CUSTOM_ITEMS_LIMIT", + "description": [], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.Unnamed.$1", + "type": "Array", + "tags": [], + "label": "primaryAndSecondaryActions", + "description": [], + "signature": [ + "(", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionPrimary", + "text": "AppMenuActionPrimary" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuItemSecondary", + "text": "AppMenuItemSecondary" + }, + ")[]" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.isActionRegistered", + "type": "Function", + "tags": [], + "label": "isActionRegistered", + "description": [], + "signature": [ + "(appMenuItemId: string) => boolean" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.isActionRegistered.$1", + "type": "string", + "tags": [], + "label": "appMenuItemId", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.registerCustomAction", + "type": "Function", + "tags": [], + "label": "registerCustomAction", + "description": [ + "\nRegister a custom action to the app menu. It can be a simple action or a submenu with more actions and horizontal rules.\nNote: Only 2 top level custom actions are allowed to be rendered in the app menu. The rest will be ignored.\nA custom action can also open a flyout or a modal. For that, return your custom react node from action's `onClick` event and call `onFinishAction` when you're done." + ], + "signature": [ + "(appMenuItem: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuItemCustom", + "text": "AppMenuItemCustom" + }, + ") => void" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.registerCustomAction.$1", + "type": "CompoundType", + "tags": [], + "label": "appMenuItem", + "description": [], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuItemCustom", + "text": "AppMenuItemCustom" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.registerCustomActionUnderSubmenu", + "type": "Function", + "tags": [], + "label": "registerCustomActionUnderSubmenu", + "description": [ + "\nRegister a custom action under a submenu. It can be an action or a horizontal rule.\nAny number of submenu actions can be registered and rendered.\nYou can also extend an existing submenu with more actions. For example, AppMenuActionType.alerts.\n`order` property is optional and can be used to control the order of actions in the submenu." + ], + "signature": [ + "(submenuId: string, appMenuItem: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuActionCustom", + "text": "AppMenuSubmenuActionCustom" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuHorizontalRule", + "text": "AppMenuSubmenuHorizontalRule" + }, + ") => void" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.registerCustomActionUnderSubmenu.$1", + "type": "string", + "tags": [], + "label": "submenuId", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.registerCustomActionUnderSubmenu.$2", + "type": "CompoundType", + "tags": [], + "label": "appMenuItem", + "description": [], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuActionCustom", + "text": "AppMenuSubmenuActionCustom" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuHorizontalRule", + "text": "AppMenuSubmenuHorizontalRule" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuRegistry.getSortedItems", + "type": "Function", + "tags": [], + "label": "getSortedItems", + "description": [ + "\nGet the resulting app menu items sorted by type and order." + ], + "signature": [ + "() => ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuItem", + "text": "AppMenuItem" + }, + "[]" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], "functions": [ { "parentPluginId": "@kbn/discover-utils", @@ -2038,81 +2297,37 @@ "interfaces": [ { "parentPluginId": "@kbn/discover-utils", - "id": "def-common.DataTableRecord", + "id": "def-common.AppMenuActionBase", "type": "Interface", "tags": [], - "label": "DataTableRecord", - "description": [ - "\nThis is the record/row of data provided to our Data Table" - ], - "path": "packages/kbn-discover-utils/src/types.ts", + "label": "AppMenuActionBase", + "description": [], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/discover-utils", - "id": "def-common.DataTableRecord.id", + "id": "def-common.AppMenuActionBase.id", "type": "string", "tags": [], "label": "id", - "description": [ - "\nA unique id generated by index, id and routing of a record" - ], - "path": "packages/kbn-discover-utils/src/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/discover-utils", - "id": "def-common.DataTableRecord.raw", - "type": "Object", - "tags": [], - "label": "raw", - "description": [ - "\nThe document returned by Elasticsearch for search queries" - ], - "signature": [ - { - "pluginId": "@kbn/discover-utils", - "scope": "common", - "docId": "kibKbnDiscoverUtilsPluginApi", - "section": "def-common.EsHitRecord", - "text": "EsHitRecord" - } - ], - "path": "packages/kbn-discover-utils/src/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/discover-utils", - "id": "def-common.DataTableRecord.flattened", - "type": "Object", - "tags": [], - "label": "flattened", - "description": [ - "\nA flattened version of the ES doc or data provided by SQL, aggregations ..." - ], - "signature": [ - "{ [x: string]: unknown; }" - ], - "path": "packages/kbn-discover-utils/src/types.ts", + "description": [], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/discover-utils", - "id": "def-common.DataTableRecord.isAnchor", - "type": "CompoundType", + "id": "def-common.AppMenuActionBase.order", + "type": "number", "tags": [], - "label": "isAnchor", - "description": [ - "\nDetermines that the given doc is the anchor doc when rendering view surrounding docs" - ], + "label": "order", + "description": [], "signature": [ - "boolean | undefined" + "number | undefined" ], - "path": "packages/kbn-discover-utils/src/types.ts", + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", "deprecated": false, "trackAdoption": false } @@ -2121,20 +2336,807 @@ }, { "parentPluginId": "@kbn/discover-utils", - "id": "def-common.EsHitRecord", + "id": "def-common.AppMenuActionCustom", "type": "Interface", "tags": [], - "label": "EsHitRecord", - "description": [], + "label": "AppMenuActionCustom", + "description": [ + "\nA custom menu action" + ], "signature": [ { "pluginId": "@kbn/discover-utils", "scope": "common", "docId": "kibKbnDiscoverUtilsPluginApi", - "section": "def-common.EsHitRecord", - "text": "EsHitRecord" + "section": "def-common.AppMenuActionCustom", + "text": "AppMenuActionCustom" }, - " extends Omit" + " extends ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionBase", + "text": "AppMenuActionBase" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionCustom.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionType", + "text": "AppMenuActionType" + }, + ".custom" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionCustom.controlProps", + "type": "CompoundType", + "tags": [], + "label": "controlProps", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.TopNavMenuData", + "text": "TopNavMenuData" + }, + ", \"isLoading\" | \"description\" | \"label\" | \"href\" | \"tooltip\" | \"testId\" | \"disableButton\"> & { onClick: ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => Promise) | ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => void | React.ReactNode) | undefined; }" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionPrimary", + "type": "Interface", + "tags": [], + "label": "AppMenuActionPrimary", + "description": [ + "\nA primary menu action (with icon only)" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionPrimary", + "text": "AppMenuActionPrimary" + }, + " extends ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionBase", + "text": "AppMenuActionBase" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionPrimary.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionType", + "text": "AppMenuActionType" + }, + ".primary" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionPrimary.controlProps", + "type": "CompoundType", + "tags": [], + "label": "controlProps", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.TopNavMenuData", + "text": "TopNavMenuData" + }, + ", \"isLoading\" | \"description\" | \"label\" | \"href\" | \"tooltip\" | \"testId\" | \"disableButton\"> & { onClick: ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => Promise) | ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => void | React.ReactNode) | undefined; } & { iconType: \"string\" | \"number\" | \"function\" | \"key\" | \"namespace\" | \"error\" | \"filter\" | \"search\" | \"link\" | \"at\" | \"nested\" | \"ip\" | \"push\" | \"list\" | \"cluster\" | \"eql\" | \"index\" | \"unlink\" | \"alert\" | \"color\" | \"grid\" | \"aggregate\" | \"warning\" | \"annotation\" | \"memory\" | \"stop\" | \"stats\" | \"mobile\" | \"article\" | \"menu\" | \"image\" | \"download\" | \"document\" | \"email\" | \"copy\" | \"move\" | \"merge\" | \"partial\" | \"container\" | \"user\" | \"pause\" | \"share\" | \"home\" | \"spaces\" | \"package\" | \"tag\" | \"beta\" | \"users\" | \"brush\" | \"percent\" | \"temperature\" | \"accessibility\" | \"addDataApp\" | \"advancedSettingsApp\" | \"agentApp\" | \"analyzeEvent\" | \"anomalyChart\" | \"anomalySwimLane\" | \"apmApp\" | \"apmTrace\" | \"appSearchApp\" | \"apps\" | \"arrowDown\" | \"arrowLeft\" | \"arrowRight\" | \"arrowUp\" | \"arrowStart\" | \"arrowEnd\" | \"asterisk\" | \"auditbeatApp\" | \"beaker\" | \"bell\" | \"bellSlash\" | \"bolt\" | \"boxesHorizontal\" | \"boxesVertical\" | \"branch\" | \"branchUser\" | \"broom\" | \"bug\" | \"bullseye\" | \"calendar\" | \"canvasApp\" | \"casesApp\" | \"changePointDetection\" | \"check\" | \"checkInCircleFilled\" | \"cheer\" | \"classificationJob\" | \"clickLeft\" | \"clickRight\" | \"clock\" | \"clockCounter\" | \"cloudDrizzle\" | \"cloudStormy\" | \"cloudSunny\" | \"codeApp\" | \"compute\" | \"console\" | \"consoleApp\" | \"continuityAbove\" | \"continuityAboveBelow\" | \"continuityBelow\" | \"continuityWithin\" | \"controlsHorizontal\" | \"controlsVertical\" | \"copyClipboard\" | \"createAdvancedJob\" | \"createMultiMetricJob\" | \"createPopulationJob\" | \"createSingleMetricJob\" | \"cross\" | \"crossClusterReplicationApp\" | \"crossInCircle\" | \"crosshairs\" | \"currency\" | \"cut\" | \"dashboardApp\" | \"dataVisualizer\" | \"database\" | \"desktop\" | \"devToolsApp\" | \"diff\" | \"discoverApp\" | \"discuss\" | \"documentEdit\" | \"documentation\" | \"documents\" | \"dot\" | \"dotInCircle\" | \"doubleArrowLeft\" | \"doubleArrowRight\" | \"editorAlignCenter\" | \"editorAlignLeft\" | \"editorAlignRight\" | \"editorBold\" | \"editorChecklist\" | \"editorCodeBlock\" | \"editorComment\" | \"editorDistributeHorizontal\" | \"editorDistributeVertical\" | \"editorHeading\" | \"editorItalic\" | \"editorItemAlignBottom\" | \"editorItemAlignCenter\" | \"editorItemAlignLeft\" | \"editorItemAlignMiddle\" | \"editorItemAlignRight\" | \"editorItemAlignTop\" | \"editorLink\" | \"editorOrderedList\" | \"editorPositionBottomLeft\" | \"editorPositionBottomRight\" | \"editorPositionTopLeft\" | \"editorPositionTopRight\" | \"editorRedo\" | \"editorStrike\" | \"editorTable\" | \"editorUnderline\" | \"editorUndo\" | \"editorUnorderedList\" | \"empty\" | \"emsApp\" | \"endpoint\" | \"eraser\" | \"errorFilled\" | \"esqlVis\" | \"exit\" | \"expand\" | \"expandMini\" | \"exportAction\" | \"eye\" | \"eyeClosed\" | \"faceHappy\" | \"faceNeutral\" | \"faceSad\" | \"fieldStatistics\" | \"filebeatApp\" | \"filterExclude\" | \"filterIgnore\" | \"filterInclude\" | \"filterInCircle\" | \"flag\" | \"fleetApp\" | \"fold\" | \"folderCheck\" | \"folderClosed\" | \"folderExclamation\" | \"folderOpen\" | \"frameNext\" | \"framePrevious\" | \"fullScreen\" | \"fullScreenExit\" | \"gear\" | \"gisApp\" | \"glasses\" | \"globe\" | \"grab\" | \"grabHorizontal\" | \"grabOmnidirectional\" | \"gradient\" | \"graphApp\" | \"grokApp\" | \"heart\" | \"heartbeatApp\" | \"heatmap\" | \"help\" | \"iInCircle\" | \"importAction\" | \"indexClose\" | \"indexEdit\" | \"indexFlush\" | \"indexManagementApp\" | \"indexMapping\" | \"indexOpen\" | \"indexPatternApp\" | \"indexRollupApp\" | \"indexRuntime\" | \"indexSettings\" | \"indexTemporary\" | \"infinity\" | \"inputOutput\" | \"inspect\" | \"invert\" | \"keyboard\" | \"kqlField\" | \"kqlFunction\" | \"kqlOperand\" | \"kqlSelector\" | \"kqlValue\" | \"kubernetesNode\" | \"kubernetesPod\" | \"launch\" | \"layers\" | \"lensApp\" | \"lettering\" | \"lineDashed\" | \"lineDotted\" | \"lineSolid\" | \"listAdd\" | \"lock\" | \"lockOpen\" | \"logPatternAnalysis\" | \"logRateAnalysis\" | \"logoAWS\" | \"logoAWSMono\" | \"logoAerospike\" | \"logoApache\" | \"logoAppSearch\" | \"logoAzure\" | \"logoAzureMono\" | \"logoBeats\" | \"logoBusinessAnalytics\" | \"logoCeph\" | \"logoCloud\" | \"logoCloudEnterprise\" | \"logoCode\" | \"logoCodesandbox\" | \"logoCouchbase\" | \"logoDocker\" | \"logoDropwizard\" | \"logoElastic\" | \"logoElasticStack\" | \"logoElasticsearch\" | \"logoEnterpriseSearch\" | \"logoEtcd\" | \"logoGCP\" | \"logoGCPMono\" | \"logoGithub\" | \"logoGmail\" | \"logoGolang\" | \"logoGoogleG\" | \"logoHAproxy\" | \"logoIBM\" | \"logoIBMMono\" | \"logoKafka\" | \"logoKibana\" | \"logoKubernetes\" | \"logoLogging\" | \"logoLogstash\" | \"logoMaps\" | \"logoMemcached\" | \"logoMetrics\" | \"logoMongodb\" | \"logoMySQL\" | \"logoNginx\" | \"logoObservability\" | \"logoOsquery\" | \"logoPhp\" | \"logoPostgres\" | \"logoPrometheus\" | \"logoRabbitmq\" | \"logoRedis\" | \"logoSecurity\" | \"logoSiteSearch\" | \"logoSketch\" | \"logoSlack\" | \"logoUptime\" | \"logoVulnerabilityManagement\" | \"logoWebhook\" | \"logoWindows\" | \"logoWorkplaceSearch\" | \"logsApp\" | \"logstashFilter\" | \"logstashIf\" | \"logstashInput\" | \"logstashOutput\" | \"logstashQueue\" | \"machineLearningApp\" | \"magnet\" | \"magnifyWithExclamation\" | \"magnifyWithMinus\" | \"magnifyWithPlus\" | \"managementApp\" | \"mapMarker\" | \"menuDown\" | \"menuLeft\" | \"menuRight\" | \"menuUp\" | \"metricbeatApp\" | \"metricsApp\" | \"minimize\" | \"minus\" | \"minusInCircle\" | \"minusInCircleFilled\" | \"minusInSquare\" | \"monitoringApp\" | \"moon\" | \"newChat\" | \"node\" | \"notebookApp\" | \"offline\" | \"online\" | \"outlierDetectionJob\" | \"packetbeatApp\" | \"pageSelect\" | \"pagesSelect\" | \"palette\" | \"paperClip\" | \"payment\" | \"pencil\" | \"pin\" | \"pinFilled\" | \"pipeBreaks\" | \"pipelineApp\" | \"pipeNoBreaks\" | \"pivot\" | \"play\" | \"playFilled\" | \"plus\" | \"plusInCircle\" | \"plusInCircleFilled\" | \"plusInSquare\" | \"popout\" | \"questionInCircle\" | \"quote\" | \"recentlyViewedApp\" | \"refresh\" | \"regressionJob\" | \"reporter\" | \"reportingApp\" | \"returnKey\" | \"save\" | \"savedObjectsApp\" | \"scale\" | \"searchProfilerApp\" | \"securityAnalyticsApp\" | \"securityApp\" | \"securitySignal\" | \"securitySignalDetected\" | \"securitySignalResolved\" | \"sessionViewer\" | \"shard\" | \"singleMetricViewer\" | \"snowflake\" | \"sortAscending\" | \"sortDescending\" | \"sortDown\" | \"sortLeft\" | \"sortRight\" | \"sortUp\" | \"sortable\" | \"spacesApp\" | \"sparkles\" | \"sqlApp\" | \"starEmpty\" | \"starEmptySpace\" | \"starFilled\" | \"starFilledSpace\" | \"starMinusEmpty\" | \"starMinusFilled\" | \"starPlusEmpty\" | \"starPlusFilled\" | \"stopFilled\" | \"stopSlash\" | \"storage\" | \"submodule\" | \"sun\" | \"swatchInput\" | \"symlink\" | \"tableDensityCompact\" | \"tableDensityExpanded\" | \"tableDensityNormal\" | \"tableOfContents\" | \"tear\" | \"timeline\" | \"timelineWithArrow\" | \"timelionApp\" | \"timeRefresh\" | \"timeslider\" | \"training\" | \"transitionLeftIn\" | \"transitionLeftOut\" | \"transitionTopIn\" | \"transitionTopOut\" | \"trash\" | \"unfold\" | \"upgradeAssistantApp\" | \"uptimeApp\" | \"userAvatar\" | \"usersRolesApp\" | \"vector\" | \"videoPlayer\" | \"visArea\" | \"visAreaStacked\" | \"visBarHorizontal\" | \"visBarHorizontalStacked\" | \"visBarVertical\" | \"visBarVerticalStacked\" | \"visGauge\" | \"visGoal\" | \"visLine\" | \"visMapCoordinate\" | \"visMapRegion\" | \"visMetric\" | \"visPie\" | \"visTable\" | \"visTagCloud\" | \"visText\" | \"visTimelion\" | \"visVega\" | \"visVisualBuilder\" | \"visualizeApp\" | \"vulnerabilityManagementApp\" | \"warningFilled\" | \"watchesApp\" | \"wordWrap\" | \"wordWrapDisabled\" | \"workplaceSearchApp\" | \"wrench\" | \"tokenAlias\" | \"tokenAnnotation\" | \"tokenArray\" | \"tokenBinary\" | \"tokenBoolean\" | \"tokenClass\" | \"tokenCompletionSuggester\" | \"tokenConstant\" | \"tokenDate\" | \"tokenDimension\" | \"tokenElement\" | \"tokenEnum\" | \"tokenEnumMember\" | \"tokenEvent\" | \"tokenException\" | \"tokenField\" | \"tokenFile\" | \"tokenFlattened\" | \"tokenFunction\" | \"tokenGeo\" | \"tokenHistogram\" | \"tokenInterface\" | \"tokenIP\" | \"tokenJoin\" | \"tokenKey\" | \"tokenKeyword\" | \"tokenMethod\" | \"tokenMetricCounter\" | \"tokenMetricGauge\" | \"tokenModule\" | \"tokenNamespace\" | \"tokenNested\" | \"tokenNull\" | \"tokenNumber\" | \"tokenObject\" | \"tokenOperator\" | \"tokenPackage\" | \"tokenParameter\" | \"tokenPercolator\" | \"tokenProperty\" | \"tokenRange\" | \"tokenRankFeature\" | \"tokenRankFeatures\" | \"tokenRepo\" | \"tokenSearchType\" | \"tokenSemanticText\" | \"tokenShape\" | \"tokenString\" | \"tokenStruct\" | \"tokenSymbol\" | \"tokenTag\" | \"tokenText\" | \"tokenTokenCount\" | \"tokenVariable\" | \"tokenVectorDense\" | \"tokenDenseVector\" | \"tokenVectorSparse\"; }" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSecondary", + "type": "Interface", + "tags": [], + "label": "AppMenuActionSecondary", + "description": [ + "\nA secondary menu action" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSecondary", + "text": "AppMenuActionSecondary" + }, + " extends ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionBase", + "text": "AppMenuActionBase" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSecondary.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionType", + "text": "AppMenuActionType" + }, + ".secondary" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSecondary.controlProps", + "type": "CompoundType", + "tags": [], + "label": "controlProps", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.TopNavMenuData", + "text": "TopNavMenuData" + }, + ", \"isLoading\" | \"description\" | \"label\" | \"href\" | \"tooltip\" | \"testId\" | \"disableButton\"> & { onClick: ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => Promise) | ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => void | React.ReactNode) | undefined; }" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSubmenuBase", + "type": "Interface", + "tags": [], + "label": "AppMenuActionSubmenuBase", + "description": [ + "\nA menu action which opens a submenu with more actions" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSubmenuBase", + "text": "AppMenuActionSubmenuBase" + }, + " extends ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionBase", + "text": "AppMenuActionBase" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSubmenuBase.type", + "type": "Uncategorized", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "T extends ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSecondary", + "text": "AppMenuActionSecondary" + }, + " ? ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionType", + "text": "AppMenuActionType" + }, + ".secondary : ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionType", + "text": "AppMenuActionType" + }, + ".custom" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSubmenuBase.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSubmenuBase.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSubmenuBase.testId", + "type": "string", + "tags": [], + "label": "testId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSubmenuBase.actions", + "type": "Uncategorized", + "tags": [], + "label": "actions", + "description": [], + "signature": [ + "T extends ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSecondary", + "text": "AppMenuActionSecondary" + }, + " ? (", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuActionSecondary", + "text": "AppMenuSubmenuActionSecondary" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuActionCustom", + "text": "AppMenuSubmenuActionCustom" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuHorizontalRule", + "text": "AppMenuSubmenuHorizontalRule" + }, + ")[] : (", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuActionCustom", + "text": "AppMenuSubmenuActionCustom" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuHorizontalRule", + "text": "AppMenuSubmenuHorizontalRule" + }, + ")[]" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuControlOnClickParams", + "type": "Interface", + "tags": [], + "label": "AppMenuControlOnClickParams", + "description": [], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuControlOnClickParams.anchorElement", + "type": "Object", + "tags": [], + "label": "anchorElement", + "description": [], + "signature": [ + "HTMLElement" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuControlOnClickParams.onFinishAction", + "type": "Function", + "tags": [], + "label": "onFinishAction", + "description": [], + "signature": [ + "() => void" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuSubmenuActionCustom", + "type": "Interface", + "tags": [], + "label": "AppMenuSubmenuActionCustom", + "description": [ + "\nA custom submenu action" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuActionCustom", + "text": "AppMenuSubmenuActionCustom" + }, + " extends Omit<", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionCustom", + "text": "AppMenuActionCustom" + }, + ", \"controlProps\">" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuSubmenuActionCustom.controlProps", + "type": "CompoundType", + "tags": [], + "label": "controlProps", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.TopNavMenuData", + "text": "TopNavMenuData" + }, + ", \"isLoading\" | \"description\" | \"label\" | \"href\" | \"tooltip\" | \"testId\" | \"disableButton\"> & { onClick: ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => Promise) | ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => void | React.ReactNode) | undefined; } & ControlWithOptionalIcon" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuSubmenuActionSecondary", + "type": "Interface", + "tags": [], + "label": "AppMenuSubmenuActionSecondary", + "description": [ + "\nA secondary submenu action" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuActionSecondary", + "text": "AppMenuSubmenuActionSecondary" + }, + " extends Omit<", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSecondary", + "text": "AppMenuActionSecondary" + }, + ", \"controlProps\">" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuSubmenuActionSecondary.controlProps", + "type": "CompoundType", + "tags": [], + "label": "controlProps", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.TopNavMenuData", + "text": "TopNavMenuData" + }, + ", \"isLoading\" | \"description\" | \"label\" | \"href\" | \"tooltip\" | \"testId\" | \"disableButton\"> & { onClick: ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => Promise) | ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => void | React.ReactNode) | undefined; } & ControlWithOptionalIcon" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuSubmenuHorizontalRule", + "type": "Interface", + "tags": [], + "label": "AppMenuSubmenuHorizontalRule", + "description": [ + "\nA horizontal rule between menu items" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuSubmenuHorizontalRule", + "text": "AppMenuSubmenuHorizontalRule" + }, + " extends ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionBase", + "text": "AppMenuActionBase" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuSubmenuHorizontalRule.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionType", + "text": "AppMenuActionType" + }, + ".submenuHorizontalRule" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuSubmenuHorizontalRule.testId", + "type": "string", + "tags": [], + "label": "testId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.DataTableRecord", + "type": "Interface", + "tags": [], + "label": "DataTableRecord", + "description": [ + "\nThis is the record/row of data provided to our Data Table" + ], + "path": "packages/kbn-discover-utils/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.DataTableRecord.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nA unique id generated by index, id and routing of a record" + ], + "path": "packages/kbn-discover-utils/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.DataTableRecord.raw", + "type": "Object", + "tags": [], + "label": "raw", + "description": [ + "\nThe document returned by Elasticsearch for search queries" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.EsHitRecord", + "text": "EsHitRecord" + } + ], + "path": "packages/kbn-discover-utils/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.DataTableRecord.flattened", + "type": "Object", + "tags": [], + "label": "flattened", + "description": [ + "\nA flattened version of the ES doc or data provided by SQL, aggregations ..." + ], + "signature": [ + "{ [x: string]: unknown; }" + ], + "path": "packages/kbn-discover-utils/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.DataTableRecord.isAnchor", + "type": "CompoundType", + "tags": [], + "label": "isAnchor", + "description": [ + "\nDetermines that the given doc is the anchor doc when rendering view surrounding docs" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-discover-utils/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.EsHitRecord", + "type": "Interface", + "tags": [], + "label": "EsHitRecord", + "description": [], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.EsHitRecord", + "text": "EsHitRecord" + }, + " extends Omit" ], "path": "packages/kbn-discover-utils/src/types.ts", "deprecated": false, @@ -2987,6 +3989,30 @@ } ], "enums": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionId", + "type": "Enum", + "tags": [], + "label": "AppMenuActionId", + "description": [], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionType", + "type": "Enum", + "tags": [], + "label": "AppMenuActionType", + "description": [], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/discover-utils", "id": "def-common.DiscoverFlyouts", @@ -3055,6 +4081,272 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSubmenuCustom", + "type": "Type", + "tags": [], + "label": "AppMenuActionSubmenuCustom", + "description": [ + "\nA menu action which opens a submenu with more custom actions" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSubmenuBase", + "text": "AppMenuActionSubmenuBase" + }, + "<", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionCustom", + "text": "AppMenuActionCustom" + }, + ">" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuActionSubmenuSecondary", + "type": "Type", + "tags": [], + "label": "AppMenuActionSubmenuSecondary", + "description": [ + "\nA menu action which opens a submenu with more secondary actions" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSubmenuBase", + "text": "AppMenuActionSubmenuBase" + }, + "<", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSecondary", + "text": "AppMenuActionSecondary" + }, + ">" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuControlProps", + "type": "Type", + "tags": [], + "label": "AppMenuControlProps", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.TopNavMenuData", + "text": "TopNavMenuData" + }, + ", \"isLoading\" | \"description\" | \"label\" | \"href\" | \"tooltip\" | \"testId\" | \"disableButton\"> & { onClick: ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => Promise) | ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => void | React.ReactNode) | undefined; }" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuControlWithIconProps", + "type": "Type", + "tags": [], + "label": "AppMenuControlWithIconProps", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.TopNavMenuData", + "text": "TopNavMenuData" + }, + ", \"isLoading\" | \"description\" | \"label\" | \"href\" | \"tooltip\" | \"testId\" | \"disableButton\"> & { onClick: ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => Promise) | ((params: ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuControlOnClickParams", + "text": "AppMenuControlOnClickParams" + }, + ") => void | React.ReactNode) | undefined; } & { iconType: \"string\" | \"number\" | \"function\" | \"key\" | \"namespace\" | \"error\" | \"filter\" | \"search\" | \"link\" | \"at\" | \"nested\" | \"ip\" | \"push\" | \"list\" | \"cluster\" | \"eql\" | \"index\" | \"unlink\" | \"alert\" | \"color\" | \"grid\" | \"aggregate\" | \"warning\" | \"annotation\" | \"memory\" | \"stop\" | \"stats\" | \"mobile\" | \"article\" | \"menu\" | \"image\" | \"download\" | \"document\" | \"email\" | \"copy\" | \"move\" | \"merge\" | \"partial\" | \"container\" | \"user\" | \"pause\" | \"share\" | \"home\" | \"spaces\" | \"package\" | \"tag\" | \"beta\" | \"users\" | \"brush\" | \"percent\" | \"temperature\" | \"accessibility\" | \"addDataApp\" | \"advancedSettingsApp\" | \"agentApp\" | \"analyzeEvent\" | \"anomalyChart\" | \"anomalySwimLane\" | \"apmApp\" | \"apmTrace\" | \"appSearchApp\" | \"apps\" | \"arrowDown\" | \"arrowLeft\" | \"arrowRight\" | \"arrowUp\" | \"arrowStart\" | \"arrowEnd\" | \"asterisk\" | \"auditbeatApp\" | \"beaker\" | \"bell\" | \"bellSlash\" | \"bolt\" | \"boxesHorizontal\" | \"boxesVertical\" | \"branch\" | \"branchUser\" | \"broom\" | \"bug\" | \"bullseye\" | \"calendar\" | \"canvasApp\" | \"casesApp\" | \"changePointDetection\" | \"check\" | \"checkInCircleFilled\" | \"cheer\" | \"classificationJob\" | \"clickLeft\" | \"clickRight\" | \"clock\" | \"clockCounter\" | \"cloudDrizzle\" | \"cloudStormy\" | \"cloudSunny\" | \"codeApp\" | \"compute\" | \"console\" | \"consoleApp\" | \"continuityAbove\" | \"continuityAboveBelow\" | \"continuityBelow\" | \"continuityWithin\" | \"controlsHorizontal\" | \"controlsVertical\" | \"copyClipboard\" | \"createAdvancedJob\" | \"createMultiMetricJob\" | \"createPopulationJob\" | \"createSingleMetricJob\" | \"cross\" | \"crossClusterReplicationApp\" | \"crossInCircle\" | \"crosshairs\" | \"currency\" | \"cut\" | \"dashboardApp\" | \"dataVisualizer\" | \"database\" | \"desktop\" | \"devToolsApp\" | \"diff\" | \"discoverApp\" | \"discuss\" | \"documentEdit\" | \"documentation\" | \"documents\" | \"dot\" | \"dotInCircle\" | \"doubleArrowLeft\" | \"doubleArrowRight\" | \"editorAlignCenter\" | \"editorAlignLeft\" | \"editorAlignRight\" | \"editorBold\" | \"editorChecklist\" | \"editorCodeBlock\" | \"editorComment\" | \"editorDistributeHorizontal\" | \"editorDistributeVertical\" | \"editorHeading\" | \"editorItalic\" | \"editorItemAlignBottom\" | \"editorItemAlignCenter\" | \"editorItemAlignLeft\" | \"editorItemAlignMiddle\" | \"editorItemAlignRight\" | \"editorItemAlignTop\" | \"editorLink\" | \"editorOrderedList\" | \"editorPositionBottomLeft\" | \"editorPositionBottomRight\" | \"editorPositionTopLeft\" | \"editorPositionTopRight\" | \"editorRedo\" | \"editorStrike\" | \"editorTable\" | \"editorUnderline\" | \"editorUndo\" | \"editorUnorderedList\" | \"empty\" | \"emsApp\" | \"endpoint\" | \"eraser\" | \"errorFilled\" | \"esqlVis\" | \"exit\" | \"expand\" | \"expandMini\" | \"exportAction\" | \"eye\" | \"eyeClosed\" | \"faceHappy\" | \"faceNeutral\" | \"faceSad\" | \"fieldStatistics\" | \"filebeatApp\" | \"filterExclude\" | \"filterIgnore\" | \"filterInclude\" | \"filterInCircle\" | \"flag\" | \"fleetApp\" | \"fold\" | \"folderCheck\" | \"folderClosed\" | \"folderExclamation\" | \"folderOpen\" | \"frameNext\" | \"framePrevious\" | \"fullScreen\" | \"fullScreenExit\" | \"gear\" | \"gisApp\" | \"glasses\" | \"globe\" | \"grab\" | \"grabHorizontal\" | \"grabOmnidirectional\" | \"gradient\" | \"graphApp\" | \"grokApp\" | \"heart\" | \"heartbeatApp\" | \"heatmap\" | \"help\" | \"iInCircle\" | \"importAction\" | \"indexClose\" | \"indexEdit\" | \"indexFlush\" | \"indexManagementApp\" | \"indexMapping\" | \"indexOpen\" | \"indexPatternApp\" | \"indexRollupApp\" | \"indexRuntime\" | \"indexSettings\" | \"indexTemporary\" | \"infinity\" | \"inputOutput\" | \"inspect\" | \"invert\" | \"keyboard\" | \"kqlField\" | \"kqlFunction\" | \"kqlOperand\" | \"kqlSelector\" | \"kqlValue\" | \"kubernetesNode\" | \"kubernetesPod\" | \"launch\" | \"layers\" | \"lensApp\" | \"lettering\" | \"lineDashed\" | \"lineDotted\" | \"lineSolid\" | \"listAdd\" | \"lock\" | \"lockOpen\" | \"logPatternAnalysis\" | \"logRateAnalysis\" | \"logoAWS\" | \"logoAWSMono\" | \"logoAerospike\" | \"logoApache\" | \"logoAppSearch\" | \"logoAzure\" | \"logoAzureMono\" | \"logoBeats\" | \"logoBusinessAnalytics\" | \"logoCeph\" | \"logoCloud\" | \"logoCloudEnterprise\" | \"logoCode\" | \"logoCodesandbox\" | \"logoCouchbase\" | \"logoDocker\" | \"logoDropwizard\" | \"logoElastic\" | \"logoElasticStack\" | \"logoElasticsearch\" | \"logoEnterpriseSearch\" | \"logoEtcd\" | \"logoGCP\" | \"logoGCPMono\" | \"logoGithub\" | \"logoGmail\" | \"logoGolang\" | \"logoGoogleG\" | \"logoHAproxy\" | \"logoIBM\" | \"logoIBMMono\" | \"logoKafka\" | \"logoKibana\" | \"logoKubernetes\" | \"logoLogging\" | \"logoLogstash\" | \"logoMaps\" | \"logoMemcached\" | \"logoMetrics\" | \"logoMongodb\" | \"logoMySQL\" | \"logoNginx\" | \"logoObservability\" | \"logoOsquery\" | \"logoPhp\" | \"logoPostgres\" | \"logoPrometheus\" | \"logoRabbitmq\" | \"logoRedis\" | \"logoSecurity\" | \"logoSiteSearch\" | \"logoSketch\" | \"logoSlack\" | \"logoUptime\" | \"logoVulnerabilityManagement\" | \"logoWebhook\" | \"logoWindows\" | \"logoWorkplaceSearch\" | \"logsApp\" | \"logstashFilter\" | \"logstashIf\" | \"logstashInput\" | \"logstashOutput\" | \"logstashQueue\" | \"machineLearningApp\" | \"magnet\" | \"magnifyWithExclamation\" | \"magnifyWithMinus\" | \"magnifyWithPlus\" | \"managementApp\" | \"mapMarker\" | \"menuDown\" | \"menuLeft\" | \"menuRight\" | \"menuUp\" | \"metricbeatApp\" | \"metricsApp\" | \"minimize\" | \"minus\" | \"minusInCircle\" | \"minusInCircleFilled\" | \"minusInSquare\" | \"monitoringApp\" | \"moon\" | \"newChat\" | \"node\" | \"notebookApp\" | \"offline\" | \"online\" | \"outlierDetectionJob\" | \"packetbeatApp\" | \"pageSelect\" | \"pagesSelect\" | \"palette\" | \"paperClip\" | \"payment\" | \"pencil\" | \"pin\" | \"pinFilled\" | \"pipeBreaks\" | \"pipelineApp\" | \"pipeNoBreaks\" | \"pivot\" | \"play\" | \"playFilled\" | \"plus\" | \"plusInCircle\" | \"plusInCircleFilled\" | \"plusInSquare\" | \"popout\" | \"questionInCircle\" | \"quote\" | \"recentlyViewedApp\" | \"refresh\" | \"regressionJob\" | \"reporter\" | \"reportingApp\" | \"returnKey\" | \"save\" | \"savedObjectsApp\" | \"scale\" | \"searchProfilerApp\" | \"securityAnalyticsApp\" | \"securityApp\" | \"securitySignal\" | \"securitySignalDetected\" | \"securitySignalResolved\" | \"sessionViewer\" | \"shard\" | \"singleMetricViewer\" | \"snowflake\" | \"sortAscending\" | \"sortDescending\" | \"sortDown\" | \"sortLeft\" | \"sortRight\" | \"sortUp\" | \"sortable\" | \"spacesApp\" | \"sparkles\" | \"sqlApp\" | \"starEmpty\" | \"starEmptySpace\" | \"starFilled\" | \"starFilledSpace\" | \"starMinusEmpty\" | \"starMinusFilled\" | \"starPlusEmpty\" | \"starPlusFilled\" | \"stopFilled\" | \"stopSlash\" | \"storage\" | \"submodule\" | \"sun\" | \"swatchInput\" | \"symlink\" | \"tableDensityCompact\" | \"tableDensityExpanded\" | \"tableDensityNormal\" | \"tableOfContents\" | \"tear\" | \"timeline\" | \"timelineWithArrow\" | \"timelionApp\" | \"timeRefresh\" | \"timeslider\" | \"training\" | \"transitionLeftIn\" | \"transitionLeftOut\" | \"transitionTopIn\" | \"transitionTopOut\" | \"trash\" | \"unfold\" | \"upgradeAssistantApp\" | \"uptimeApp\" | \"userAvatar\" | \"usersRolesApp\" | \"vector\" | \"videoPlayer\" | \"visArea\" | \"visAreaStacked\" | \"visBarHorizontal\" | \"visBarHorizontalStacked\" | \"visBarVertical\" | \"visBarVerticalStacked\" | \"visGauge\" | \"visGoal\" | \"visLine\" | \"visMapCoordinate\" | \"visMapRegion\" | \"visMetric\" | \"visPie\" | \"visTable\" | \"visTagCloud\" | \"visText\" | \"visTimelion\" | \"visVega\" | \"visVisualBuilder\" | \"visualizeApp\" | \"vulnerabilityManagementApp\" | \"warningFilled\" | \"watchesApp\" | \"wordWrap\" | \"wordWrapDisabled\" | \"workplaceSearchApp\" | \"wrench\" | \"tokenAlias\" | \"tokenAnnotation\" | \"tokenArray\" | \"tokenBinary\" | \"tokenBoolean\" | \"tokenClass\" | \"tokenCompletionSuggester\" | \"tokenConstant\" | \"tokenDate\" | \"tokenDimension\" | \"tokenElement\" | \"tokenEnum\" | \"tokenEnumMember\" | \"tokenEvent\" | \"tokenException\" | \"tokenField\" | \"tokenFile\" | \"tokenFlattened\" | \"tokenFunction\" | \"tokenGeo\" | \"tokenHistogram\" | \"tokenInterface\" | \"tokenIP\" | \"tokenJoin\" | \"tokenKey\" | \"tokenKeyword\" | \"tokenMethod\" | \"tokenMetricCounter\" | \"tokenMetricGauge\" | \"tokenModule\" | \"tokenNamespace\" | \"tokenNested\" | \"tokenNull\" | \"tokenNumber\" | \"tokenObject\" | \"tokenOperator\" | \"tokenPackage\" | \"tokenParameter\" | \"tokenPercolator\" | \"tokenProperty\" | \"tokenRange\" | \"tokenRankFeature\" | \"tokenRankFeatures\" | \"tokenRepo\" | \"tokenSearchType\" | \"tokenSemanticText\" | \"tokenShape\" | \"tokenString\" | \"tokenStruct\" | \"tokenSymbol\" | \"tokenTag\" | \"tokenText\" | \"tokenTokenCount\" | \"tokenVariable\" | \"tokenVectorDense\" | \"tokenDenseVector\" | \"tokenVectorSparse\"; }" + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuItem", + "type": "Type", + "tags": [], + "label": "AppMenuItem", + "description": [ + "\nA menu item can be primary, secondary or custom" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionPrimary", + "text": "AppMenuActionPrimary" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuItemSecondary", + "text": "AppMenuItemSecondary" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuItemCustom", + "text": "AppMenuItemCustom" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuItemCustom", + "type": "Type", + "tags": [], + "label": "AppMenuItemCustom", + "description": [ + "\nA custom menu item can have only a label or a submenu" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionCustom", + "text": "AppMenuActionCustom" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSubmenuCustom", + "text": "AppMenuActionSubmenuCustom" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuItemPrimary", + "type": "Type", + "tags": [], + "label": "AppMenuItemPrimary", + "description": [ + "\nA primary menu item can only have an icon" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionPrimary", + "text": "AppMenuActionPrimary" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.AppMenuItemSecondary", + "type": "Type", + "tags": [], + "label": "AppMenuItemSecondary", + "description": [ + "\nA secondary menu item can have only a label or a submenu" + ], + "signature": [ + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSecondary", + "text": "AppMenuActionSecondary" + }, + " | ", + { + "pluginId": "@kbn/discover-utils", + "scope": "common", + "docId": "kibKbnDiscoverUtilsPluginApi", + "section": "def-common.AppMenuActionSubmenuSecondary", + "text": "AppMenuActionSubmenuSecondary" + } + ], + "path": "packages/kbn-discover-utils/src/components/app_menu/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/discover-utils", "id": "def-common.CLOUD_AVAILABILITY_ZONE_FIELD", diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 10ec6e859d318..e76ff611434e4 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 234 | 0 | 200 | 4 | +| 284 | 0 | 234 | 4 | ## Common @@ -31,6 +31,9 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k ### Functions +### Classes + + ### Interfaces diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 13e09364b3cd5..43b0a0bd2c15d 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 9b173b0d346eb..20e9fadae1598 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index 72ddaf0b2e5f3..70ea7afd79dfc 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index 782221793ba6f..5f2b72ef8a732 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index eb5ed51b104fb..b642bd3857f78 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_agent_utils.mdx b/api_docs/kbn_elastic_agent_utils.mdx index 42fbfb0bd0a17..f2ba7cee1b7c1 100644 --- a/api_docs/kbn_elastic_agent_utils.mdx +++ b/api_docs/kbn_elastic_agent_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-agent-utils title: "@kbn/elastic-agent-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-agent-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index fe27e860436a9..62c23704699a9 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant_common.devdocs.json b/api_docs/kbn_elastic_assistant_common.devdocs.json index d901a9c32b414..49dbaeea7049b 100644 --- a/api_docs/kbn_elastic_assistant_common.devdocs.json +++ b/api_docs/kbn_elastic_assistant_common.devdocs.json @@ -3613,7 +3613,7 @@ "label": "ReadKnowledgeBaseResponse", "description": [], "signature": [ - "{ elser_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; }" + "{ elser_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; user_data_exists?: boolean | undefined; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", "deprecated": false, @@ -4737,7 +4737,7 @@ "\nDefault features available to the elastic assistant" ], "signature": [ - "{ readonly assistantKnowledgeBaseByDefault: false; readonly assistantModelEvaluation: false; }" + "{ readonly assistantKnowledgeBaseByDefault: true; readonly assistantModelEvaluation: false; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts", "deprecated": false, @@ -5907,7 +5907,7 @@ "label": "ReadKnowledgeBaseResponse", "description": [], "signature": [ - "Zod.ZodObject<{ elser_exists: Zod.ZodOptional; index_exists: Zod.ZodOptional; is_setup_available: Zod.ZodOptional; is_setup_in_progress: Zod.ZodOptional; pipeline_exists: Zod.ZodOptional; security_labs_exists: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { elser_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; }, { elser_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; }>" + "Zod.ZodObject<{ elser_exists: Zod.ZodOptional; index_exists: Zod.ZodOptional; is_setup_available: Zod.ZodOptional; is_setup_in_progress: Zod.ZodOptional; pipeline_exists: Zod.ZodOptional; security_labs_exists: Zod.ZodOptional; user_data_exists: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { elser_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; user_data_exists?: boolean | undefined; }, { elser_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; user_data_exists?: boolean | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", "deprecated": false, diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index 1c61735c5d90c..15da08c21b752 100644 --- a/api_docs/kbn_elastic_assistant_common.mdx +++ b/api_docs/kbn_elastic_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant-common title: "@kbn/elastic-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_entities_schema.mdx b/api_docs/kbn_entities_schema.mdx index 421b1ed14a799..afb4339060938 100644 --- a/api_docs/kbn_entities_schema.mdx +++ b/api_docs/kbn_entities_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-entities-schema title: "@kbn/entities-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/entities-schema plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/entities-schema'] --- import kbnEntitiesSchemaObj from './kbn_entities_schema.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index ecd91a632b60f..4ee53b37bf35d 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index fe45478f29a0c..c9cf041c98512 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 3129cbb435063..38a21e4c0735a 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 4c257f0fbdf40..2b3247e44d808 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index ec6bbb652b0b1..0fa03e5594981 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index cc4f89070d784..1a4a9535f23d6 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_esql_ast.devdocs.json b/api_docs/kbn_esql_ast.devdocs.json index cac01fac9555d..94ef986f9809c 100644 --- a/api_docs/kbn_esql_ast.devdocs.json +++ b/api_docs/kbn_esql_ast.devdocs.json @@ -17949,6 +17949,31 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.ESQLFunction.operator", + "type": "CompoundType", + "tags": [], + "label": "operator", + "description": [ + "\nA node representing the function or operator being called." + ], + "signature": [ + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLParamLiteral", + "text": "ESQLParamLiteral" + }, + " | ", + "ESQLIdentifier", + " | undefined" + ], + "path": "packages/kbn-esql-ast/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/esql-ast", "id": "def-common.ESQLFunction.args", @@ -19533,6 +19558,8 @@ "text": "ESQLParamLiteral" }, " | ", + "ESQLIdentifier", + " | ", { "pluginId": "@kbn/esql-ast", "scope": "common", @@ -19668,6 +19695,8 @@ "text": "ESQLLiteral" }, " | ", + "ESQLIdentifier", + " | ", { "pluginId": "@kbn/esql-ast", "scope": "common", diff --git a/api_docs/kbn_esql_ast.mdx b/api_docs/kbn_esql_ast.mdx index 1b6b1edf1a988..22e579cc69e36 100644 --- a/api_docs/kbn_esql_ast.mdx +++ b/api_docs/kbn_esql_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-ast title: "@kbn/esql-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-ast plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-ast'] --- import kbnEsqlAstObj from './kbn_esql_ast.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 269 | 1 | 211 | 34 | +| 270 | 1 | 211 | 35 | ## Common diff --git a/api_docs/kbn_esql_editor.mdx b/api_docs/kbn_esql_editor.mdx index 1409e7d9da87f..584e650834c11 100644 --- a/api_docs/kbn_esql_editor.mdx +++ b/api_docs/kbn_esql_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-editor title: "@kbn/esql-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-editor plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-editor'] --- import kbnEsqlEditorObj from './kbn_esql_editor.devdocs.json'; diff --git a/api_docs/kbn_esql_utils.mdx b/api_docs/kbn_esql_utils.mdx index 7be3a7ab1705f..3c0ab467acce7 100644 --- a/api_docs/kbn_esql_utils.mdx +++ b/api_docs/kbn_esql_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-utils title: "@kbn/esql-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-utils'] --- import kbnEsqlUtilsObj from './kbn_esql_utils.devdocs.json'; diff --git a/api_docs/kbn_esql_validation_autocomplete.devdocs.json b/api_docs/kbn_esql_validation_autocomplete.devdocs.json index ffc4814f5708c..693c134947b52 100644 --- a/api_docs/kbn_esql_validation_autocomplete.devdocs.json +++ b/api_docs/kbn_esql_validation_autocomplete.devdocs.json @@ -400,7 +400,7 @@ "section": "def-common.CommandDefinition", "text": "CommandDefinition" }, - "[]" + "[]" ], "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", "deprecated": false, @@ -675,6 +675,8 @@ "text": "ESQLParamLiteral" }, " | ", + "ESQLIdentifier", + " | ", { "pluginId": "@kbn/esql-ast", "scope": "common", @@ -797,6 +799,8 @@ "text": "ESQLParamLiteral" }, " | ", + "ESQLIdentifier", + " | ", { "pluginId": "@kbn/esql-ast", "scope": "common", @@ -903,6 +907,8 @@ "text": "ESQLParamLiteral" }, " | ", + "ESQLIdentifier", + " | ", { "pluginId": "@kbn/esql-ast", "scope": "common", @@ -1017,6 +1023,8 @@ "text": "ESQLParamLiteral" }, " | ", + "ESQLIdentifier", + " | ", { "pluginId": "@kbn/esql-ast", "scope": "common", @@ -1206,7 +1214,8 @@ "docId": "kibKbnEsqlValidationAutocompletePluginApi", "section": "def-common.CommandDefinition", "text": "CommandDefinition" - } + }, + "" ], "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", "deprecated": false, @@ -1247,7 +1256,7 @@ "section": "def-common.CommandOptionsDefinition", "text": "CommandOptionsDefinition" }, - " | undefined" + " | undefined" ], "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", "deprecated": false, @@ -2705,34 +2714,14 @@ "section": "def-common.CommandDefinition", "text": "CommandDefinition" }, - " extends ", - "CommandBaseDefinition" + " extends ", + "CommandBaseDefinition", + "" ], "path": "packages/kbn-esql-validation-autocomplete/src/definitions/types.ts", "deprecated": false, "trackAdoption": false, "children": [ - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.CommandDefinition.options", - "type": "Array", - "tags": [], - "label": "options", - "description": [], - "signature": [ - { - "pluginId": "@kbn/esql-validation-autocomplete", - "scope": "common", - "docId": "kibKbnEsqlValidationAutocompletePluginApi", - "section": "def-common.CommandOptionsDefinition", - "text": "CommandOptionsDefinition" - }, - "[]" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/definitions/types.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.CommandDefinition.examples", @@ -2802,11 +2791,27 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.CommandDefinition.hasRecommendedQueries", + "type": "CompoundType", + "tags": [], + "label": "hasRecommendedQueries", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/definitions/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.CommandDefinition.modes", "type": "Array", - "tags": [], + "tags": [ + "deprecated" + ], "label": "modes", "description": [], "signature": [ @@ -2820,22 +2825,38 @@ "[]" ], "path": "packages/kbn-esql-validation-autocomplete/src/definitions/types.ts", - "deprecated": false, - "trackAdoption": false + "deprecated": true, + "trackAdoption": false, + "references": [ + { + "plugin": "@kbn/monaco", + "path": "packages/kbn-monaco/src/esql/lib/hover/hover.ts" + } + ] }, { "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.CommandDefinition.hasRecommendedQueries", - "type": "CompoundType", - "tags": [], - "label": "hasRecommendedQueries", + "id": "def-common.CommandDefinition.options", + "type": "Array", + "tags": [ + "deprecated" + ], + "label": "options", "description": [], "signature": [ - "boolean | undefined" + { + "pluginId": "@kbn/esql-validation-autocomplete", + "scope": "common", + "docId": "kibKbnEsqlValidationAutocompletePluginApi", + "section": "def-common.CommandOptionsDefinition", + "text": "CommandOptionsDefinition" + }, + "[]" ], "path": "packages/kbn-esql-validation-autocomplete/src/definitions/types.ts", - "deprecated": false, - "trackAdoption": false + "deprecated": true, + "trackAdoption": false, + "references": [] } ], "initialIsOpen": false @@ -2919,8 +2940,9 @@ "section": "def-common.CommandOptionsDefinition", "text": "CommandOptionsDefinition" }, - " extends ", - "CommandBaseDefinition" + " extends ", + "CommandBaseDefinition", + "" ], "path": "packages/kbn-esql-validation-autocomplete/src/definitions/types.ts", "deprecated": false, @@ -3096,10 +3118,10 @@ }, { "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.ESQLCallbacks.getFieldsFor", + "id": "def-common.ESQLCallbacks.getColumnsFor", "type": "Function", "tags": [], - "label": "getFieldsFor", + "label": "getColumnsFor", "description": [], "signature": [ "CallbackFn<{ query: string; }, ", diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index 8fad3f8784a8c..ec3660daab104 100644 --- a/api_docs/kbn_esql_validation_autocomplete.mdx +++ b/api_docs/kbn_esql_validation_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-validation-autocomplete title: "@kbn/esql-validation-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-validation-autocomplete plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-validation-autocomplete'] --- import kbnEsqlValidationAutocompleteObj from './kbn_esql_validation_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index b951b786d4521..7ebbd05bc7908 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index 11c650bcd9f43..061c2e18b4a65 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index f6d11d4461046..cefaf3f3c66a5 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index e902fa17bcedf..ab93d15585361 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index fc317182455ef..76f2aae7b8575 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 59e819b16728e..35d9e1d91a682 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_formatters.mdx b/api_docs/kbn_formatters.mdx index 4b8160ff489d0..88b91c720c5a2 100644 --- a/api_docs/kbn_formatters.mdx +++ b/api_docs/kbn_formatters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-formatters title: "@kbn/formatters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/formatters plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/formatters'] --- import kbnFormattersObj from './kbn_formatters.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.devdocs.json b/api_docs/kbn_ftr_common_functional_services.devdocs.json index 000ff1cb78701..da4cb9fdb2ab7 100644 --- a/api_docs/kbn_ftr_common_functional_services.devdocs.json +++ b/api_docs/kbn_ftr_common_functional_services.devdocs.json @@ -1901,7 +1901,7 @@ "label": "InternalRequestHeader", "description": [], "signature": [ - "{ 'kbn-xsrf': string; } | { 'x-elastic-internal-origin': string; 'kbn-xsrf': string; }" + "{ 'x-elastic-internal-origin': string; 'kbn-xsrf': string; } | { 'x-elastic-internal-origin': string; 'kbn-xsrf': string; }" ], "path": "packages/kbn-ftr-common-functional-services/services/saml_auth/default_request_headers.ts", "deprecated": false, diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 3046218767b28..6e57950109100 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_ui_services.devdocs.json b/api_docs/kbn_ftr_common_functional_ui_services.devdocs.json index 9dc0cc6adbf11..048e3d908e3f5 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.devdocs.json +++ b/api_docs/kbn_ftr_common_functional_ui_services.devdocs.json @@ -2885,7 +2885,7 @@ "\nMoves the remote environment’s mouse cursor to the current element with optional offset\nhttps://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html#move" ], "signature": [ - "(options?: { xOffset: number; yOffset: number; }) => Promise" + "({ xOffset, yOffset, topOffset }?: { xOffset?: number | undefined; yOffset?: number | undefined; topOffset?: number | undefined; }) => Promise" ], "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", "deprecated": false, @@ -2896,10 +2896,10 @@ "id": "def-common.WebElementWrapper.moveMouseTo.$1", "type": "Object", "tags": [], - "label": "options", + "label": "{ xOffset = 0, yOffset = 0, topOffset = 0 }", "description": [], "signature": [ - "{ xOffset: number; yOffset: number; }" + "{ xOffset?: number | undefined; yOffset?: number | undefined; topOffset?: number | undefined; }" ], "path": "packages/kbn-ftr-common-functional-ui-services/services/web_element_wrapper/web_element_wrapper.ts", "deprecated": false, diff --git a/api_docs/kbn_ftr_common_functional_ui_services.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index 581c52131c378..2219ad33b7597 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.mdx +++ b/api_docs/kbn_ftr_common_functional_ui_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-ui-services title: "@kbn/ftr-common-functional-ui-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-ui-services plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-ui-services'] --- import kbnFtrCommonFunctionalUiServicesObj from './kbn_ftr_common_functional_ui_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 7a2bad84b1315..bb47332c42b76 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index 374fe7901ed4c..22d09d4a376ec 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index f933a8338f91f..5c0f2927e1a1c 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grid_layout.mdx b/api_docs/kbn_grid_layout.mdx index adf471b5feef3..cf56d3bd6175f 100644 --- a/api_docs/kbn_grid_layout.mdx +++ b/api_docs/kbn_grid_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grid-layout title: "@kbn/grid-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grid-layout plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grid-layout'] --- import kbnGridLayoutObj from './kbn_grid_layout.devdocs.json'; diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index 5309134ccf8d0..ab9ea9acafd5e 100644 --- a/api_docs/kbn_grouping.mdx +++ b/api_docs/kbn_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grouping title: "@kbn/grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grouping plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grouping'] --- import kbnGroupingObj from './kbn_grouping.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 54ee126becf5b..fd3b9a840bc26 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 667b48db81445..9a51094601049 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index 45730b7212c56..5d95637087c79 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index 4dcb5020eb81b..7d634783fd184 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index f3d1028bee0d7..495f0ebe9a6d8 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index a307ee6e52d21..92fd02436cc53 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index 5bb93c3d44187..02b44ab6c789c 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index 8e465b481a286..ce71521dfa526 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 2a19c27cfdbba..13052b9a02512 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_index_management_shared_types.devdocs.json b/api_docs/kbn_index_management_shared_types.devdocs.json index 532c3a1bdcda9..34b0baa513dcf 100644 --- a/api_docs/kbn_index_management_shared_types.devdocs.json +++ b/api_docs/kbn_index_management_shared_types.devdocs.json @@ -1314,65 +1314,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/index-management-shared-types", - "id": "def-common.IndexManagementLocatorParams", - "type": "Interface", - "tags": [], - "label": "IndexManagementLocatorParams", - "description": [], - "signature": [ - { - "pluginId": "@kbn/index-management-shared-types", - "scope": "common", - "docId": "kibKbnIndexManagementSharedTypesPluginApi", - "section": "def-common.IndexManagementLocatorParams", - "text": "IndexManagementLocatorParams" - }, - " extends ", - { - "pluginId": "@kbn/utility-types", - "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.SerializableRecord", - "text": "SerializableRecord" - } - ], - "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/index-management-shared-types", - "id": "def-common.IndexManagementLocatorParams.page", - "type": "string", - "tags": [], - "label": "page", - "description": [], - "signature": [ - "\"data_streams_details\"" - ], - "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/index-management-shared-types", - "id": "def-common.IndexManagementLocatorParams.dataStreamName", - "type": "string", - "tags": [], - "label": "dataStreamName", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/index-management-shared-types", "id": "def-common.IndexManagementPluginSetup", @@ -2173,6 +2114,28 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-management-shared-types", + "id": "def-common.IndexManagementLocatorParams", + "type": "Type", + "tags": [], + "label": "IndexManagementLocatorParams", + "description": [], + "signature": [ + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.SerializableRecord", + "text": "SerializableRecord" + }, + " & ({ page: \"data_streams_details\"; dataStreamName?: string | undefined; } | { page: \"index_template\"; indexTemplate: string; } | { page: \"component_template\"; componentTemplate: string; })" + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/kbn_index_management_shared_types.mdx b/api_docs/kbn_index_management_shared_types.mdx index 9902a95586dea..b02cb8fe57f3e 100644 --- a/api_docs/kbn_index_management_shared_types.mdx +++ b/api_docs/kbn_index_management_shared_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-management-shared-types title: "@kbn/index-management-shared-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-management-shared-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-management-shared-types'] --- import kbnIndexManagementSharedTypesObj from './kbn_index_management_shared_types.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 126 | 3 | 126 | 0 | +| 124 | 3 | 124 | 0 | ## Common diff --git a/api_docs/kbn_inference_integration_flyout.mdx b/api_docs/kbn_inference_integration_flyout.mdx index 8e95c5959784c..b839f360785a0 100644 --- a/api_docs/kbn_inference_integration_flyout.mdx +++ b/api_docs/kbn_inference_integration_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-inference_integration_flyout title: "@kbn/inference_integration_flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/inference_integration_flyout plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/inference_integration_flyout'] --- import kbnInferenceIntegrationFlyoutObj from './kbn_inference_integration_flyout.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index 7decfdca2c478..fa25aca9f5b92 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 1dd2226abf4cb..f94cee5e9b4a2 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_investigation_shared.mdx b/api_docs/kbn_investigation_shared.mdx index c5bd54e8374b2..2f5d75ece7669 100644 --- a/api_docs/kbn_investigation_shared.mdx +++ b/api_docs/kbn_investigation_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-investigation-shared title: "@kbn/investigation-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/investigation-shared plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/investigation-shared'] --- import kbnInvestigationSharedObj from './kbn_investigation_shared.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index cf51181704dd9..ba55a2e8c9833 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_ipynb.mdx b/api_docs/kbn_ipynb.mdx index f89bc85826c7c..7528c44fc0b32 100644 --- a/api_docs/kbn_ipynb.mdx +++ b/api_docs/kbn_ipynb.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ipynb title: "@kbn/ipynb" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ipynb plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ipynb'] --- import kbnIpynbObj from './kbn_ipynb.devdocs.json'; diff --git a/api_docs/kbn_item_buffer.mdx b/api_docs/kbn_item_buffer.mdx index ed03e400a21b9..126fdda674f82 100644 --- a/api_docs/kbn_item_buffer.mdx +++ b/api_docs/kbn_item_buffer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-item-buffer title: "@kbn/item-buffer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/item-buffer plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/item-buffer'] --- import kbnItemBufferObj from './kbn_item_buffer.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 718fcf966ced6..6bf431ee1b359 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index 5cde98628f4fc..9e7e2face3c1a 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index eb061414a8b8d..6f3bc7e5e5459 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_json_schemas.mdx b/api_docs/kbn_json_schemas.mdx index 6128d220c1066..7b680e22999eb 100644 --- a/api_docs/kbn_json_schemas.mdx +++ b/api_docs/kbn_json_schemas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-schemas title: "@kbn/json-schemas" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-schemas plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-schemas'] --- import kbnJsonSchemasObj from './kbn_json_schemas.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 564d38cf64ba0..6c8cb0488dee6 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation.mdx b/api_docs/kbn_language_documentation.mdx index 40b2661ac1191..36a7a31bda78e 100644 --- a/api_docs/kbn_language_documentation.mdx +++ b/api_docs/kbn_language_documentation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation title: "@kbn/language-documentation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation'] --- import kbnLanguageDocumentationObj from './kbn_language_documentation.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index e9e7d4b8d37ea..72b4ad0c32564 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_lens_formula_docs.mdx b/api_docs/kbn_lens_formula_docs.mdx index e443971960cc6..1c7ca2be3adb2 100644 --- a/api_docs/kbn_lens_formula_docs.mdx +++ b/api_docs/kbn_lens_formula_docs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-formula-docs title: "@kbn/lens-formula-docs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-formula-docs plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-formula-docs'] --- import kbnLensFormulaDocsObj from './kbn_lens_formula_docs.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 18262df1c99f6..b085cd3d3942b 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index 87f81cfa1701c..9f5b42bf380e3 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_content_badge.mdx b/api_docs/kbn_managed_content_badge.mdx index 156a29789cf9f..d1cf37e1ffa3b 100644 --- a/api_docs/kbn_managed_content_badge.mdx +++ b/api_docs/kbn_managed_content_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-content-badge title: "@kbn/managed-content-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-content-badge plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-content-badge'] --- import kbnManagedContentBadgeObj from './kbn_managed_content_badge.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index 903c451d69cc1..2ff99e7fbe188 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index 24d3f45b0e09b..66e58b81926d7 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index d6217af2a9ce1..a05abbb712608 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index 0a8a72ec52299..993c8c6f663d5 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index 706a888e336d3..321d9f7a28684 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index f6df4194023b3..d123c98e8f2e6 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index 4b0a63da5cac4..9c09f6758f1c5 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index 9ceeb594828fc..b7a4c1c242868 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.devdocs.json b/api_docs/kbn_management_settings_ids.devdocs.json index 716f5512821b5..19accbeb0d254 100644 --- a/api_docs/kbn_management_settings_ids.devdocs.json +++ b/api_docs/kbn_management_settings_ids.devdocs.json @@ -532,21 +532,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/management-settings-ids", - "id": "def-common.DISCOVER_SHOW_LEGACY_FIELD_TOP_VALUES_ID", - "type": "string", - "tags": [], - "label": "DISCOVER_SHOW_LEGACY_FIELD_TOP_VALUES_ID", - "description": [], - "signature": [ - "\"discover:showLegacyFieldTopValues\"" - ], - "path": "packages/kbn-management/settings/setting_ids/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/management-settings-ids", "id": "def-common.DISCOVER_SHOW_MULTI_FIELDS_ID", @@ -1372,36 +1357,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/management-settings-ids", - "id": "def-common.OBSERVABILITY_ENABLE_INFRASTRUCTURE_CONTAINER_ASSET_VIEW_ID", - "type": "string", - "tags": [], - "label": "OBSERVABILITY_ENABLE_INFRASTRUCTURE_CONTAINER_ASSET_VIEW_ID", - "description": [], - "signature": [ - "\"observability:enableInfrastructureContainerAssetView\"" - ], - "path": "packages/kbn-management/settings/setting_ids/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/management-settings-ids", - "id": "def-common.OBSERVABILITY_ENABLE_INFRASTRUCTURE_HOSTS_VIEW_ID", - "type": "string", - "tags": [], - "label": "OBSERVABILITY_ENABLE_INFRASTRUCTURE_HOSTS_VIEW_ID", - "description": [], - "signature": [ - "\"observability:enableInfrastructureHostsView\"" - ], - "path": "packages/kbn-management/settings/setting_ids/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/management-settings-ids", "id": "def-common.OBSERVABILITY_ENABLE_INSPECT_ES_QUERIES_ID", diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index 9573d05bbd967..5b37ee9e959fc 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 143 | 0 | 142 | 0 | +| 140 | 0 | 139 | 0 | ## Common diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index 93344ca090a73..44a1164bfad14 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index 590c1c4615da8..ff08a4d685da8 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index 2286f1792e48f..72feb8ced8999 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index 5030148051d49..a3690d43d76eb 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_manifest.mdx b/api_docs/kbn_manifest.mdx index defcb3fb78c19..894bbbe1a2a0d 100644 --- a/api_docs/kbn_manifest.mdx +++ b/api_docs/kbn_manifest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-manifest title: "@kbn/manifest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/manifest plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/manifest'] --- import kbnManifestObj from './kbn_manifest.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index d76af270abf3e..48dba15929695 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index 77f8b5f688e22..6073fb1940e94 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 4052a7e5184f8..0618e910d7854 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index e28f1fc92c187..df9cc8d4aeee2 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_cancellable_search.mdx b/api_docs/kbn_ml_cancellable_search.mdx index 61f8a944c0892..8c72b28bcb81c 100644 --- a/api_docs/kbn_ml_cancellable_search.mdx +++ b/api_docs/kbn_ml_cancellable_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-cancellable-search title: "@kbn/ml-cancellable-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-cancellable-search plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-cancellable-search'] --- import kbnMlCancellableSearchObj from './kbn_ml_cancellable_search.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index 76e19d40a636e..bfb05eb817a0c 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index 5aa3570bcfae5..a048e34522a88 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index b4fcf7ab8f0c2..fe97a213a8aa2 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index b101733529e2e..9274edcd354b6 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 73c4fe3a72aa2..84975f5f168a4 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 45c95511f5090..edce31ff877c0 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index d383bd3b2df7a..478be1861d335 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_field_stats_flyout.mdx b/api_docs/kbn_ml_field_stats_flyout.mdx index c534ea37f9794..16486df8fd82f 100644 --- a/api_docs/kbn_ml_field_stats_flyout.mdx +++ b/api_docs/kbn_ml_field_stats_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-field-stats-flyout title: "@kbn/ml-field-stats-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-field-stats-flyout plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-field-stats-flyout'] --- import kbnMlFieldStatsFlyoutObj from './kbn_ml_field_stats_flyout.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index 17f3001836a0a..f1458af586f6b 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index 0b0a0d0a64fac..6f667a8e50bc9 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 6d94ff686a9ae..d2ce52623980a 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index b48fa9d764cdb..b5076a9d3effa 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index 636e25e819407..761543e00490e 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index e45673e76502a..b815853d09822 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index 345472ed17925..6d8a3984ddc05 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_parse_interval.mdx b/api_docs/kbn_ml_parse_interval.mdx index 5e839b98de318..5c8682910e5a5 100644 --- a/api_docs/kbn_ml_parse_interval.mdx +++ b/api_docs/kbn_ml_parse_interval.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-parse-interval title: "@kbn/ml-parse-interval" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-parse-interval plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-parse-interval'] --- import kbnMlParseIntervalObj from './kbn_ml_parse_interval.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index 0ee1aa66f6c0e..6c670234b48cf 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index 87f1f04b3af0e..46f69b352051f 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index 7b745db75a7c6..a3406b68d70fb 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index 67f62124cb887..c6d46329bc94f 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 6a5644d94fb88..cac3ea2f80482 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_time_buckets.mdx b/api_docs/kbn_ml_time_buckets.mdx index 718d146361bcf..711832559b365 100644 --- a/api_docs/kbn_ml_time_buckets.mdx +++ b/api_docs/kbn_ml_time_buckets.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-time-buckets title: "@kbn/ml-time-buckets" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-time-buckets plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-time-buckets'] --- import kbnMlTimeBucketsObj from './kbn_ml_time_buckets.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 8cfd0f206aad3..2ab3b3960dec3 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_ui_actions.mdx b/api_docs/kbn_ml_ui_actions.mdx index 2a8141166f14d..e04b931181df1 100644 --- a/api_docs/kbn_ml_ui_actions.mdx +++ b/api_docs/kbn_ml_ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-ui-actions title: "@kbn/ml-ui-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-ui-actions plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-ui-actions'] --- import kbnMlUiActionsObj from './kbn_ml_ui_actions.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index 76a494713f894..1954742fbf6a7 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_ml_validators.mdx b/api_docs/kbn_ml_validators.mdx index d0c0b165f58ad..f54e1217ff7e7 100644 --- a/api_docs/kbn_ml_validators.mdx +++ b/api_docs/kbn_ml_validators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-validators title: "@kbn/ml-validators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-validators plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-validators'] --- import kbnMlValidatorsObj from './kbn_ml_validators.devdocs.json'; diff --git a/api_docs/kbn_mock_idp_utils.mdx b/api_docs/kbn_mock_idp_utils.mdx index bb3ed1181d1a2..5e07ee7896f78 100644 --- a/api_docs/kbn_mock_idp_utils.mdx +++ b/api_docs/kbn_mock_idp_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mock-idp-utils title: "@kbn/mock-idp-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mock-idp-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mock-idp-utils'] --- import kbnMockIdpUtilsObj from './kbn_mock_idp_utils.devdocs.json'; diff --git a/api_docs/kbn_monaco.devdocs.json b/api_docs/kbn_monaco.devdocs.json index 4a460e13cec3c..fcb876065c8a2 100644 --- a/api_docs/kbn_monaco.devdocs.json +++ b/api_docs/kbn_monaco.devdocs.json @@ -509,10 +509,10 @@ }, { "parentPluginId": "@kbn/monaco", - "id": "def-common.ESQLCallbacks.getFieldsFor", + "id": "def-common.ESQLCallbacks.getColumnsFor", "type": "Function", "tags": [], - "label": "getFieldsFor", + "label": "getColumnsFor", "description": [], "signature": [ "CallbackFn<{ query: string; }, ", diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 1ed0a07d3fc0a..3f5038fa197e4 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index c22c7c8691581..97a226db0d6ea 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_object_versioning_utils.mdx b/api_docs/kbn_object_versioning_utils.mdx index 262d2dc8cc2f4..3585efc6ddd7f 100644 --- a/api_docs/kbn_object_versioning_utils.mdx +++ b/api_docs/kbn_object_versioning_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning-utils title: "@kbn/object-versioning-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning-utils'] --- import kbnObjectVersioningUtilsObj from './kbn_object_versioning_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index 5865ccb841455..90b09f178ab48 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_rule_utils.mdx b/api_docs/kbn_observability_alerting_rule_utils.mdx index 138124da68d34..40825dbebdc1f 100644 --- a/api_docs/kbn_observability_alerting_rule_utils.mdx +++ b/api_docs/kbn_observability_alerting_rule_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-rule-utils title: "@kbn/observability-alerting-rule-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-rule-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-rule-utils'] --- import kbnObservabilityAlertingRuleUtilsObj from './kbn_observability_alerting_rule_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 7b178f99c2fa2..82294bcd86e8b 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx index 19a62d9f06c06..531529dd6be3d 100644 --- a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-get-padded-alert-time-range-util title: "@kbn/observability-get-padded-alert-time-range-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-get-padded-alert-time-range-util plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-get-padded-alert-time-range-util'] --- import kbnObservabilityGetPaddedAlertTimeRangeUtilObj from './kbn_observability_get_padded_alert_time_range_util.devdocs.json'; diff --git a/api_docs/kbn_observability_logs_overview.mdx b/api_docs/kbn_observability_logs_overview.mdx index 5fe22eaae5415..c28edaeb707ee 100644 --- a/api_docs/kbn_observability_logs_overview.mdx +++ b/api_docs/kbn_observability_logs_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-logs-overview title: "@kbn/observability-logs-overview" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-logs-overview plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-logs-overview'] --- import kbnObservabilityLogsOverviewObj from './kbn_observability_logs_overview.devdocs.json'; diff --git a/api_docs/kbn_observability_synthetics_test_data.mdx b/api_docs/kbn_observability_synthetics_test_data.mdx index 9dd17bd7a5a88..ccd773d013b07 100644 --- a/api_docs/kbn_observability_synthetics_test_data.mdx +++ b/api_docs/kbn_observability_synthetics_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-synthetics-test-data title: "@kbn/observability-synthetics-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-synthetics-test-data plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-synthetics-test-data'] --- import kbnObservabilitySyntheticsTestDataObj from './kbn_observability_synthetics_test_data.devdocs.json'; diff --git a/api_docs/kbn_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx index daf8ee5ca9312..6d948dc92f6e3 100644 --- a/api_docs/kbn_openapi_bundler.mdx +++ b/api_docs/kbn_openapi_bundler.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-bundler title: "@kbn/openapi-bundler" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-bundler plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-bundler'] --- import kbnOpenapiBundlerObj from './kbn_openapi_bundler.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index 147dddf3bd965..6131bafc8283f 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index d48c9c1a3110f..e47aef25a65b8 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index 209b021bb6332..8d5afa2484e2b 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_osquery_io_ts_types.mdx b/api_docs/kbn_osquery_io_ts_types.mdx index 6ee8c445269e0..e06f3265e6f8a 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx index 64c8c19437ce1..3cdde73e4c3df 100644 --- a/api_docs/kbn_panel_loader.mdx +++ b/api_docs/kbn_panel_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-panel-loader title: "@kbn/panel-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/panel-loader plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/panel-loader'] --- import kbnPanelLoaderObj from './kbn_panel_loader.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 37548d98c61bc..c2c303725cdcb 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_check.mdx b/api_docs/kbn_plugin_check.mdx index b7f27290b864f..16d1c33731be3 100644 --- a/api_docs/kbn_plugin_check.mdx +++ b/api_docs/kbn_plugin_check.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-check title: "@kbn/plugin-check" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-check plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-check'] --- import kbnPluginCheckObj from './kbn_plugin_check.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 106022fe20fea..22e2b9471d8ab 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index 5ab0261f37aa3..6bf31a6dabbf1 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_presentation_containers.mdx b/api_docs/kbn_presentation_containers.mdx index 652d217f5d493..fb0b93d347916 100644 --- a/api_docs/kbn_presentation_containers.mdx +++ b/api_docs/kbn_presentation_containers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-containers title: "@kbn/presentation-containers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-containers plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; diff --git a/api_docs/kbn_presentation_publishing.devdocs.json b/api_docs/kbn_presentation_publishing.devdocs.json index 2d485ab66d69e..59b096c6077e7 100644 --- a/api_docs/kbn_presentation_publishing.devdocs.json +++ b/api_docs/kbn_presentation_publishing.devdocs.json @@ -45,6 +45,46 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.apiCanLockHoverActions", + "type": "Function", + "tags": [], + "label": "apiCanLockHoverActions", + "description": [], + "signature": [ + "(api: unknown) => api is ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.CanLockHoverActions", + "text": "CanLockHoverActions" + } + ], + "path": "packages/presentation/presentation_publishing/interfaces/can_lock_hover_actions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.apiCanLockHoverActions.$1", + "type": "Unknown", + "tags": [], + "label": "api", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/presentation/presentation_publishing/interfaces/can_lock_hover_actions.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-publishing", "id": "def-public.apiHasAppContext", @@ -2498,6 +2538,218 @@ } ], "interfaces": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.CanLockHoverActions", + "type": "Interface", + "tags": [], + "label": "CanLockHoverActions", + "description": [ + "\nThis API can lock hover actions" + ], + "path": "packages/presentation/presentation_publishing/interfaces/can_lock_hover_actions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.CanLockHoverActions.hasLockedHoverActions$", + "type": "Object", + "tags": [], + "label": "hasLockedHoverActions$", + "description": [], + "signature": [ + "{ source: ", + "Observable", + " | undefined; readonly value: boolean; error: (err: any) => void; forEach: { (next: (value: boolean) => void): Promise; (next: (value: boolean) => void, promiseCtor: PromiseConstructorLike): Promise; }; complete: () => void; getValue: () => boolean; closed: boolean; pipe: { (): ", + "Observable", + "; (op1: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + ", op9: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + ", op9: ", + "OperatorFunction", + ", ...operations: ", + "OperatorFunction", + "[]): ", + "Observable", + "; }; operator: ", + "Operator", + " | undefined; lift: (operator: ", + "Operator", + ") => ", + "Observable", + "; subscribe: { (observerOrNext?: Partial<", + "Observer", + "> | ((value: boolean) => void) | undefined): ", + "Subscription", + "; (next?: ((value: boolean) => void) | null | undefined, error?: ((error: any) => void) | null | undefined, complete?: (() => void) | null | undefined): ", + "Subscription", + "; }; toPromise: { (): Promise; (PromiseCtor: PromiseConstructor): Promise; (PromiseCtor: PromiseConstructorLike): Promise; }; observers: ", + "Observer", + "[]; isStopped: boolean; hasError: boolean; thrownError: any; unsubscribe: () => void; readonly observed: boolean; asObservable: () => ", + "Observable", + "; }" + ], + "path": "packages/presentation/presentation_publishing/interfaces/can_lock_hover_actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.CanLockHoverActions.lockHoverActions", + "type": "Function", + "tags": [], + "label": "lockHoverActions", + "description": [], + "signature": [ + "(lock: boolean) => void" + ], + "path": "packages/presentation/presentation_publishing/interfaces/can_lock_hover_actions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.CanLockHoverActions.lockHoverActions.$1", + "type": "boolean", + "tags": [], + "label": "lock", + "description": [], + "signature": [ + "boolean" + ], + "path": "packages/presentation/presentation_publishing/interfaces/can_lock_hover_actions.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-publishing", "id": "def-public.EmbeddableApiContext", diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index 5f6b2108f36da..085f99197db80 100644 --- a/api_docs/kbn_presentation_publishing.mdx +++ b/api_docs/kbn_presentation_publishing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-publishing title: "@kbn/presentation-publishing" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-publishing plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 218 | 0 | 183 | 6 | +| 224 | 0 | 188 | 6 | ## Client diff --git a/api_docs/kbn_product_doc_artifact_builder.mdx b/api_docs/kbn_product_doc_artifact_builder.mdx index 518e0604a0377..c6ff65cc0bdc9 100644 --- a/api_docs/kbn_product_doc_artifact_builder.mdx +++ b/api_docs/kbn_product_doc_artifact_builder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-product-doc-artifact-builder title: "@kbn/product-doc-artifact-builder" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/product-doc-artifact-builder plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/product-doc-artifact-builder'] --- import kbnProductDocArtifactBuilderObj from './kbn_product_doc_artifact_builder.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index ba3643b36fccc..0483e6e701ffd 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 179df1e7802f4..8c581345e99d3 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 52e5a8f8e42c3..529e9aa44c96f 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_hooks.mdx b/api_docs/kbn_react_hooks.mdx index eed47c302931c..a05902457fc03 100644 --- a/api_docs/kbn_react_hooks.mdx +++ b/api_docs/kbn_react_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-hooks title: "@kbn/react-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-hooks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-hooks'] --- import kbnReactHooksObj from './kbn_react_hooks.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index fc031d2c6dbb1..6797474980c88 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index 50c7b26242190..ffcad7ffcc68c 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index b699c7a5eacd2..d6c5c514c7986 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index 5fbe47b8ecc78..74ac20a794fef 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index 9fec1092fc09b..424ec359a3305 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index 26ea4ec39cc10..172bed73698bc 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_recently_accessed.mdx b/api_docs/kbn_recently_accessed.mdx index 5145ce0100674..9b886144c0613 100644 --- a/api_docs/kbn_recently_accessed.mdx +++ b/api_docs/kbn_recently_accessed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-recently-accessed title: "@kbn/recently-accessed" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/recently-accessed plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/recently-accessed'] --- import kbnRecentlyAccessedObj from './kbn_recently_accessed.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 777dc475f1316..2776dd3bfc4ea 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index 9f9d4402db837..949ff38cc2a9c 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index c3f5229d16b8b..bd8d93794c148 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 161eea6aa904d..db91a1d12be3d 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index b98e8752ba075..13aad08016a5f 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_csv_share_panel.mdx b/api_docs/kbn_reporting_csv_share_panel.mdx index d2ee5c2cf9775..5a6ec3367544a 100644 --- a/api_docs/kbn_reporting_csv_share_panel.mdx +++ b/api_docs/kbn_reporting_csv_share_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-csv-share-panel title: "@kbn/reporting-csv-share-panel" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-csv-share-panel plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-csv-share-panel'] --- import kbnReportingCsvSharePanelObj from './kbn_reporting_csv_share_panel.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index 98433d7ffc6a1..fd26d914e0cc5 100644 --- a/api_docs/kbn_reporting_export_types_csv.mdx +++ b/api_docs/kbn_reporting_export_types_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv title: "@kbn/reporting-export-types-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index a25391affc31f..56291c360a70c 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.mdx +++ b/api_docs/kbn_reporting_export_types_csv_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv-common title: "@kbn/reporting-export-types-csv-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index ee400bc3d1d15..d5cf270543a5a 100644 --- a/api_docs/kbn_reporting_export_types_pdf.mdx +++ b/api_docs/kbn_reporting_export_types_pdf.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf title: "@kbn/reporting-export-types-pdf" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf'] --- import kbnReportingExportTypesPdfObj from './kbn_reporting_export_types_pdf.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf_common.mdx b/api_docs/kbn_reporting_export_types_pdf_common.mdx index c387b153beef1..eadd6af46ed0a 100644 --- a/api_docs/kbn_reporting_export_types_pdf_common.mdx +++ b/api_docs/kbn_reporting_export_types_pdf_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf-common title: "@kbn/reporting-export-types-pdf-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf-common'] --- import kbnReportingExportTypesPdfCommonObj from './kbn_reporting_export_types_pdf_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png.mdx b/api_docs/kbn_reporting_export_types_png.mdx index d598f7aa96cc4..ec324e0ac1251 100644 --- a/api_docs/kbn_reporting_export_types_png.mdx +++ b/api_docs/kbn_reporting_export_types_png.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png title: "@kbn/reporting-export-types-png" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png'] --- import kbnReportingExportTypesPngObj from './kbn_reporting_export_types_png.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png_common.mdx b/api_docs/kbn_reporting_export_types_png_common.mdx index 4b4c80984dffd..32c6c8a6e3010 100644 --- a/api_docs/kbn_reporting_export_types_png_common.mdx +++ b/api_docs/kbn_reporting_export_types_png_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png-common title: "@kbn/reporting-export-types-png-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png-common'] --- import kbnReportingExportTypesPngCommonObj from './kbn_reporting_export_types_png_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_mocks_server.mdx b/api_docs/kbn_reporting_mocks_server.mdx index 531f5834c0502..980b11fe26182 100644 --- a/api_docs/kbn_reporting_mocks_server.mdx +++ b/api_docs/kbn_reporting_mocks_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-mocks-server title: "@kbn/reporting-mocks-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-mocks-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index 0a6870e601248..18029cba3725f 100644 --- a/api_docs/kbn_reporting_public.mdx +++ b/api_docs/kbn_reporting_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-public title: "@kbn/reporting-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-public plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index ae4e9007d5dca..f3ad45c695a8b 100644 --- a/api_docs/kbn_reporting_server.mdx +++ b/api_docs/kbn_reporting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-server title: "@kbn/reporting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index 7f50cea37fe5a..c31bc4392b78a 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_response_ops_feature_flag_service.mdx b/api_docs/kbn_response_ops_feature_flag_service.mdx index 70a1959803c8a..e7d2e5a426cd9 100644 --- a/api_docs/kbn_response_ops_feature_flag_service.mdx +++ b/api_docs/kbn_response_ops_feature_flag_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-feature-flag-service title: "@kbn/response-ops-feature-flag-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-feature-flag-service plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-feature-flag-service'] --- import kbnResponseOpsFeatureFlagServiceObj from './kbn_response_ops_feature_flag_service.devdocs.json'; diff --git a/api_docs/kbn_response_ops_rule_params.mdx b/api_docs/kbn_response_ops_rule_params.mdx index 9104bde74f7a4..feb2af634a15f 100644 --- a/api_docs/kbn_response_ops_rule_params.mdx +++ b/api_docs/kbn_response_ops_rule_params.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-rule-params title: "@kbn/response-ops-rule-params" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-rule-params plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-rule-params'] --- import kbnResponseOpsRuleParamsObj from './kbn_response_ops_rule_params.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index 354f825ba512e..816d0c143af6f 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rollup.mdx b/api_docs/kbn_rollup.mdx index 4fb97db26f75b..0289d4f21787a 100644 --- a/api_docs/kbn_rollup.mdx +++ b/api_docs/kbn_rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rollup title: "@kbn/rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rollup plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rollup'] --- import kbnRollupObj from './kbn_rollup.devdocs.json'; diff --git a/api_docs/kbn_router_to_openapispec.mdx b/api_docs/kbn_router_to_openapispec.mdx index a2c32e9592167..9e2961d6ead6b 100644 --- a/api_docs/kbn_router_to_openapispec.mdx +++ b/api_docs/kbn_router_to_openapispec.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-to-openapispec title: "@kbn/router-to-openapispec" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-to-openapispec plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-to-openapispec'] --- import kbnRouterToOpenapispecObj from './kbn_router_to_openapispec.devdocs.json'; diff --git a/api_docs/kbn_router_utils.mdx b/api_docs/kbn_router_utils.mdx index 825439d5afd8e..6aeb25da99a64 100644 --- a/api_docs/kbn_router_utils.mdx +++ b/api_docs/kbn_router_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-utils title: "@kbn/router-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-utils'] --- import kbnRouterUtilsObj from './kbn_router_utils.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index c2ab6baa4e106..4ef0f7307ca04 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 825f9480ae0c9..9072af5098a72 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index d9f78298097a2..3635d5b831270 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_screenshotting_server.mdx b/api_docs/kbn_screenshotting_server.mdx index 089926a228478..523f5ee048a6f 100644 --- a/api_docs/kbn_screenshotting_server.mdx +++ b/api_docs/kbn_screenshotting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-screenshotting-server title: "@kbn/screenshotting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/screenshotting-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/screenshotting-server'] --- import kbnScreenshottingServerObj from './kbn_screenshotting_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_keys_components.mdx b/api_docs/kbn_search_api_keys_components.mdx index 928a5315021db..e28cc7d83764d 100644 --- a/api_docs/kbn_search_api_keys_components.mdx +++ b/api_docs/kbn_search_api_keys_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-keys-components title: "@kbn/search-api-keys-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-keys-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-keys-components'] --- import kbnSearchApiKeysComponentsObj from './kbn_search_api_keys_components.devdocs.json'; diff --git a/api_docs/kbn_search_api_keys_server.mdx b/api_docs/kbn_search_api_keys_server.mdx index c5c33b39fbcab..6ad8fca7a460e 100644 --- a/api_docs/kbn_search_api_keys_server.mdx +++ b/api_docs/kbn_search_api_keys_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-keys-server title: "@kbn/search-api-keys-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-keys-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-keys-server'] --- import kbnSearchApiKeysServerObj from './kbn_search_api_keys_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index 38a2c78aadebb..abb550e5d1711 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index c4da56c56cb12..da7204a29cca2 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index ad21eef5ab11c..4924ee31ab124 100644 --- a/api_docs/kbn_search_errors.mdx +++ b/api_docs/kbn_search_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-errors title: "@kbn/search-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-errors plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-errors'] --- import kbnSearchErrorsObj from './kbn_search_errors.devdocs.json'; diff --git a/api_docs/kbn_search_index_documents.mdx b/api_docs/kbn_search_index_documents.mdx index bef1354fab895..cb7ad770a197d 100644 --- a/api_docs/kbn_search_index_documents.mdx +++ b/api_docs/kbn_search_index_documents.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-index-documents title: "@kbn/search-index-documents" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-index-documents plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-index-documents'] --- import kbnSearchIndexDocumentsObj from './kbn_search_index_documents.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 99097ebc6da24..c280e76cd7b13 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_search_shared_ui.mdx b/api_docs/kbn_search_shared_ui.mdx index 7cc87cdeb0226..f234bdafcb187 100644 --- a/api_docs/kbn_search_shared_ui.mdx +++ b/api_docs/kbn_search_shared_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-shared-ui title: "@kbn/search-shared-ui" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-shared-ui plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-shared-ui'] --- import kbnSearchSharedUiObj from './kbn_search_shared_ui.devdocs.json'; diff --git a/api_docs/kbn_search_types.mdx b/api_docs/kbn_search_types.mdx index 23094c67584bc..9c0ec3604042d 100644 --- a/api_docs/kbn_search_types.mdx +++ b/api_docs/kbn_search_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-types title: "@kbn/search-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_api_key_management.mdx b/api_docs/kbn_security_api_key_management.mdx index 24d77665f0b1a..cc69e96f4a303 100644 --- a/api_docs/kbn_security_api_key_management.mdx +++ b/api_docs/kbn_security_api_key_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-api-key-management title: "@kbn/security-api-key-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-api-key-management plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-api-key-management'] --- import kbnSecurityApiKeyManagementObj from './kbn_security_api_key_management.devdocs.json'; diff --git a/api_docs/kbn_security_authorization_core.mdx b/api_docs/kbn_security_authorization_core.mdx index 3966037b09c1d..0791f1f828995 100644 --- a/api_docs/kbn_security_authorization_core.mdx +++ b/api_docs/kbn_security_authorization_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-authorization-core title: "@kbn/security-authorization-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-authorization-core plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-authorization-core'] --- import kbnSecurityAuthorizationCoreObj from './kbn_security_authorization_core.devdocs.json'; diff --git a/api_docs/kbn_security_authorization_core_common.mdx b/api_docs/kbn_security_authorization_core_common.mdx index 4687d5ed6ebfc..de0d6177396a9 100644 --- a/api_docs/kbn_security_authorization_core_common.mdx +++ b/api_docs/kbn_security_authorization_core_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-authorization-core-common title: "@kbn/security-authorization-core-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-authorization-core-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-authorization-core-common'] --- import kbnSecurityAuthorizationCoreCommonObj from './kbn_security_authorization_core_common.devdocs.json'; diff --git a/api_docs/kbn_security_form_components.mdx b/api_docs/kbn_security_form_components.mdx index 9266b8dadce38..2171b7fd04847 100644 --- a/api_docs/kbn_security_form_components.mdx +++ b/api_docs/kbn_security_form_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-form-components title: "@kbn/security-form-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-form-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-form-components'] --- import kbnSecurityFormComponentsObj from './kbn_security_form_components.devdocs.json'; diff --git a/api_docs/kbn_security_hardening.mdx b/api_docs/kbn_security_hardening.mdx index 07620e7a90d21..8a8fbc46867bb 100644 --- a/api_docs/kbn_security_hardening.mdx +++ b/api_docs/kbn_security_hardening.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-hardening title: "@kbn/security-hardening" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-hardening plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-hardening'] --- import kbnSecurityHardeningObj from './kbn_security_hardening.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx index d89d0ebef21be..d314a73b2caee 100644 --- a/api_docs/kbn_security_plugin_types_common.mdx +++ b/api_docs/kbn_security_plugin_types_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-common title: "@kbn/security-plugin-types-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-common'] --- import kbnSecurityPluginTypesCommonObj from './kbn_security_plugin_types_common.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_public.mdx b/api_docs/kbn_security_plugin_types_public.mdx index 527ced0963d2c..007ed562d7000 100644 --- a/api_docs/kbn_security_plugin_types_public.mdx +++ b/api_docs/kbn_security_plugin_types_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-public title: "@kbn/security-plugin-types-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-public plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.devdocs.json b/api_docs/kbn_security_plugin_types_server.devdocs.json index 279dae1d55066..4f11b25ee54f1 100644 --- a/api_docs/kbn_security_plugin_types_server.devdocs.json +++ b/api_docs/kbn_security_plugin_types_server.devdocs.json @@ -5040,6 +5040,10 @@ { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts" } ] } diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index 729078564a46f..601b84564ea12 100644 --- a/api_docs/kbn_security_plugin_types_server.mdx +++ b/api_docs/kbn_security_plugin_types_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-server title: "@kbn/security-plugin-types-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] --- import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; diff --git a/api_docs/kbn_security_role_management_model.mdx b/api_docs/kbn_security_role_management_model.mdx index bb007a8bd2060..11f2e5902e207 100644 --- a/api_docs/kbn_security_role_management_model.mdx +++ b/api_docs/kbn_security_role_management_model.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-role-management-model title: "@kbn/security-role-management-model" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-role-management-model plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-role-management-model'] --- import kbnSecurityRoleManagementModelObj from './kbn_security_role_management_model.devdocs.json'; diff --git a/api_docs/kbn_security_solution_common.devdocs.json b/api_docs/kbn_security_solution_common.devdocs.json index ec70d3e9c476e..f8b99bbd6dd3d 100644 --- a/api_docs/kbn_security_solution_common.devdocs.json +++ b/api_docs/kbn_security_solution_common.devdocs.json @@ -277,7 +277,7 @@ "\nWrapper component that is composed of a header section and a content section.\nThe header can display an icon, a title (that can be a link), and an optional content section on the right.\nThe content section can display a loading spinner, an error message, or any other content.\nThe component can be expanded or collapsed by clicking on the chevron icon on the left of the title." ], "signature": [ - "{ ({ header: { title, link, iconType, headerContent }, content: { loading, error }, expand: { expandable, expandedOnFirstRender }, \"data-test-subj\": dataTestSubj, children, }: React.PropsWithChildren<", + "{ ({ header: { title, link, iconType, headerContent }, content: { loading, error, paddingSize: contentPaddingSize }, expand: { expandable, expandedOnFirstRender }, \"data-test-subj\": dataTestSubj, children, }: React.PropsWithChildren<", "ExpandablePanelPanelProps", ">): React.JSX.Element; displayName: string | undefined; }" ], @@ -290,7 +290,7 @@ "id": "def-public.ExpandablePanel.$1", "type": "CompoundType", "tags": [], - "label": "{\n header: { title, link, iconType, headerContent },\n content: { loading, error } = { loading: false, error: false },\n expand: { expandable, expandedOnFirstRender } = {\n expandable: false,\n expandedOnFirstRender: false,\n },\n 'data-test-subj': dataTestSubj,\n children,\n}", + "label": "{\n header: { title, link, iconType, headerContent },\n content: { loading, error, paddingSize: contentPaddingSize } = {\n loading: false,\n error: false,\n paddingSize: 'm',\n },\n expand: { expandable, expandedOnFirstRender } = {\n expandable: false,\n expandedOnFirstRender: false,\n },\n 'data-test-subj': dataTestSubj,\n children,\n}", "description": [], "signature": [ "React.PropsWithChildren<", diff --git a/api_docs/kbn_security_solution_common.mdx b/api_docs/kbn_security_solution_common.mdx index 77ba68e966f36..fc824e0022af7 100644 --- a/api_docs/kbn_security_solution_common.mdx +++ b/api_docs/kbn_security_solution_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-common title: "@kbn/security-solution-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-common plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-common'] --- import kbnSecuritySolutionCommonObj from './kbn_security_solution_common.devdocs.json'; diff --git a/api_docs/kbn_security_solution_distribution_bar.mdx b/api_docs/kbn_security_solution_distribution_bar.mdx index 07ded1ff38392..bf7082f370ba3 100644 --- a/api_docs/kbn_security_solution_distribution_bar.mdx +++ b/api_docs/kbn_security_solution_distribution_bar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-distribution-bar title: "@kbn/security-solution-distribution-bar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-distribution-bar plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-distribution-bar'] --- import kbnSecuritySolutionDistributionBarObj from './kbn_security_solution_distribution_bar.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index ecade49ff9859..91af6943af9b9 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index 34c5bca405704..21980402ee2b0 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index 2456edd014414..090eb92ac5e95 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-side-nav'] --- import kbnSecuritySolutionSideNavObj from './kbn_security_solution_side_nav.devdocs.json'; diff --git a/api_docs/kbn_security_solution_storybook_config.mdx b/api_docs/kbn_security_solution_storybook_config.mdx index f49e7390ab54d..07deee1fbe40d 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_security_ui_components.mdx b/api_docs/kbn_security_ui_components.mdx index ddd5969386c2c..0c0ba6eed7892 100644 --- a/api_docs/kbn_security_ui_components.mdx +++ b/api_docs/kbn_security_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-ui-components title: "@kbn/security-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-ui-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-ui-components'] --- import kbnSecurityUiComponentsObj from './kbn_security_ui_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 2f5e1d0eed4dc..a34cdae4cd97e 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index a4395ac31906c..688d50cef7ef6 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index 8f8ab6f2ba1f8..9e912e7b4ca1e 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 60d29238037d6..0506493c5671c 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index 83a63361ca5f4..eeb77f30fe24e 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 621319c46584a..93746138f79ce 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index b6c0ad0938187..9ed507bccbff8 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 5e339b3dff21f..9823ddedeec5a 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 00caf5c58b688..88e037ff0dfe3 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index 9fe5e2683256d..f030a806aad3e 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index cc89b5d37b8f8..e0d4291b9d358 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index 20f3ee19f391c..e8a4cd491a806 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index b157d31dfc713..c4f10307a4e33 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 9a24e42b4c094..131a46fd1e32e 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 026598b3bbd44..f1607b93950a6 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index 5e00aa68744b5..74a80665ed684 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 6c5ffd40097d2..a82d6f50a167e 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index 01bfe64008c4f..245a8bfead558 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 48c827079d4c9..4405956f486bd 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_client.mdx b/api_docs/kbn_server_route_repository_client.mdx index df3dd4e7ef1a6..1b33d0a5d620a 100644 --- a/api_docs/kbn_server_route_repository_client.mdx +++ b/api_docs/kbn_server_route_repository_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-client title: "@kbn/server-route-repository-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-client plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-client'] --- import kbnServerRouteRepositoryClientObj from './kbn_server_route_repository_client.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_utils.mdx b/api_docs/kbn_server_route_repository_utils.mdx index 219d20e06fdc1..9ed8b6776b8f8 100644 --- a/api_docs/kbn_server_route_repository_utils.mdx +++ b/api_docs/kbn_server_route_repository_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-utils title: "@kbn/server-route-repository-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-utils'] --- import kbnServerRouteRepositoryUtilsObj from './kbn_server_route_repository_utils.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index 6718c9fe68043..07516adc07f21 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index 8918e33e3072e..6e5fa8dafc28f 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index 2f5cd7f1ee59c..25501cf1d0f0a 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index fb0f2a164cc46..a87d84e1355da 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 0ba4832f8f822..661f41b13ea65 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index 475055266cfa3..7cc8d43a3f58a 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index fea2785a4e36e..4c5cded5d92cd 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index 0eb8e8b77c0d1..3e73d0fbed46d 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 776e90985f11d..cbf6ea28eab00 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 8d2f988acb993..a356bac755a7b 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index a457331f12046..8425949a390a4 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index d6a1185ac5cac..465e2f2aa97d0 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index 298906c5672b8..28d72aa35391e 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index 345cb99e8e3a4..16fe52f50c9d6 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 1d4da8757b09f..51f1f66418391 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index da5dbddd59a1c..2d9aacf8b6e8d 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index 8962455c1e734..54c201bd0ee91 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index fc971eb7e23ed..32a02ee12ef00 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index fe2af0946b720..1c6ac8dab7628 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index 5b704a756a9f0..f78223e9bbb9b 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index a01de092f0d27..ff06190ef3e26 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index 9013f3ff4680f..03c853a3fa229 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index 1cb1d6f05a3f5..86a9751d0892c 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index 7de1d9071c1b3..038c3b9b02fa8 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index b9709319635e1..48fe1aace774a 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index e0b04fd59253c..987b8a3ef6c0c 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 26947ab8a9807..71206803df2b4 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index ffeedb2f55028..e48c1dac9f021 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index 1893fbf6bfec4..4d154840f86c8 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index 44a27539fd84c..d58ebe6ccd271 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index 1882a3e06cf4e..e66ec22c16460 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index 094ac671bf5a0..138b4418bfec7 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index e56c3b05d3661..3fb5c2fb91fca 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index 1dd9923407c78..782dd0d9230d9 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index 58007fe4eda51..f05dcb7155712 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index c6c446c5078a7..9fa4b1da29dc8 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index 7a63b4c99cfbd..348bab44d9075 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index 1dac2749c63c8..75097100f2914 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index f9303ffe209eb..9507d6df6886b 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index 86bee58915a67..f775b22d60b20 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 501cf0f6df841..6991ee456815d 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index d880fada8f33f..4f71798957da0 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index 3d8b56b475ab1..ec4404508a9b6 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 3d758e4d42b7a..a88bf327d9255 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_tabbed_modal.mdx b/api_docs/kbn_shared_ux_tabbed_modal.mdx index 824750cd9eba8..7e74b886199c9 100644 --- a/api_docs/kbn_shared_ux_tabbed_modal.mdx +++ b/api_docs/kbn_shared_ux_tabbed_modal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-tabbed-modal title: "@kbn/shared-ux-tabbed-modal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-tabbed-modal plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-tabbed-modal'] --- import kbnSharedUxTabbedModalObj from './kbn_shared_ux_tabbed_modal.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_table_persist.mdx b/api_docs/kbn_shared_ux_table_persist.mdx index db003d9bc2e75..3ebc91a806e43 100644 --- a/api_docs/kbn_shared_ux_table_persist.mdx +++ b/api_docs/kbn_shared_ux_table_persist.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-table-persist title: "@kbn/shared-ux-table-persist" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-table-persist plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-table-persist'] --- import kbnSharedUxTablePersistObj from './kbn_shared_ux_table_persist.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 5592cedafe191..8b64311a3bc1c 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 459b672c7d901..287aa7feab0d7 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 5750ee5bad7f1..5cf3a0dd0bbfc 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_predicates.mdx b/api_docs/kbn_sort_predicates.mdx index c738658afabda..0f4411bc75653 100644 --- a/api_docs/kbn_sort_predicates.mdx +++ b/api_docs/kbn_sort_predicates.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-predicates title: "@kbn/sort-predicates" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-predicates plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-predicates'] --- import kbnSortPredicatesObj from './kbn_sort_predicates.devdocs.json'; diff --git a/api_docs/kbn_sse_utils.mdx b/api_docs/kbn_sse_utils.mdx index 92a6969399ccf..b0358835ed028 100644 --- a/api_docs/kbn_sse_utils.mdx +++ b/api_docs/kbn_sse_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils title: "@kbn/sse-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils'] --- import kbnSseUtilsObj from './kbn_sse_utils.devdocs.json'; diff --git a/api_docs/kbn_sse_utils_client.mdx b/api_docs/kbn_sse_utils_client.mdx index e60a4b03794e9..15db4cdbb294a 100644 --- a/api_docs/kbn_sse_utils_client.mdx +++ b/api_docs/kbn_sse_utils_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils-client title: "@kbn/sse-utils-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils-client plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils-client'] --- import kbnSseUtilsClientObj from './kbn_sse_utils_client.devdocs.json'; diff --git a/api_docs/kbn_sse_utils_server.mdx b/api_docs/kbn_sse_utils_server.mdx index d78aeb2afba50..fe9d93cd64885 100644 --- a/api_docs/kbn_sse_utils_server.mdx +++ b/api_docs/kbn_sse_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils-server title: "@kbn/sse-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils-server plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils-server'] --- import kbnSseUtilsServerObj from './kbn_sse_utils_server.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 1273349a1f7e8..50c821675c49f 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index dffda67527183..a5c2340a22af4 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index af78a4a8cc9f0..bde762c685b2a 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_synthetics_e2e.mdx b/api_docs/kbn_synthetics_e2e.mdx index 4f2b1ab687a51..19165ea9a7ed5 100644 --- a/api_docs/kbn_synthetics_e2e.mdx +++ b/api_docs/kbn_synthetics_e2e.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-e2e title: "@kbn/synthetics-e2e" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-e2e plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-e2e'] --- import kbnSyntheticsE2eObj from './kbn_synthetics_e2e.devdocs.json'; diff --git a/api_docs/kbn_synthetics_private_location.mdx b/api_docs/kbn_synthetics_private_location.mdx index f8f61aef9772d..b3f85536cd265 100644 --- a/api_docs/kbn_synthetics_private_location.mdx +++ b/api_docs/kbn_synthetics_private_location.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-private-location title: "@kbn/synthetics-private-location" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-private-location plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-private-location'] --- import kbnSyntheticsPrivateLocationObj from './kbn_synthetics_private_location.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 9c7c8fe29101e..60fe35e02977e 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 39410cab15250..ae0b8acfc0889 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index 142898e0e6c55..0eb79f1ee0123 100644 --- a/api_docs/kbn_test_eui_helpers.mdx +++ b/api_docs/kbn_test_eui_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-eui-helpers title: "@kbn/test-eui-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-eui-helpers plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-eui-helpers'] --- import kbnTestEuiHelpersObj from './kbn_test_eui_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 6914792e26917..fa270cd46b39f 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 306475a2fdefb..2ecff97eed975 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_timerange.mdx b/api_docs/kbn_timerange.mdx index 80c5a764632d7..c9a47be6f3ef5 100644 --- a/api_docs/kbn_timerange.mdx +++ b/api_docs/kbn_timerange.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-timerange title: "@kbn/timerange" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/timerange plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/timerange'] --- import kbnTimerangeObj from './kbn_timerange.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index e68a201d844ae..58ae0394ee43d 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_transpose_utils.mdx b/api_docs/kbn_transpose_utils.mdx index ee37aecc12c0a..aa14bce75a325 100644 --- a/api_docs/kbn_transpose_utils.mdx +++ b/api_docs/kbn_transpose_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-transpose-utils title: "@kbn/transpose-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/transpose-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/transpose-utils'] --- import kbnTransposeUtilsObj from './kbn_transpose_utils.devdocs.json'; diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index e6d094147a15e..4dfd7bb08056b 100644 --- a/api_docs/kbn_triggers_actions_ui_types.mdx +++ b/api_docs/kbn_triggers_actions_ui_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-triggers-actions-ui-types title: "@kbn/triggers-actions-ui-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/triggers-actions-ui-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; diff --git a/api_docs/kbn_try_in_console.mdx b/api_docs/kbn_try_in_console.mdx index 987f45ee38df4..fa8142acfb18e 100644 --- a/api_docs/kbn_try_in_console.mdx +++ b/api_docs/kbn_try_in_console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-try-in-console title: "@kbn/try-in-console" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/try-in-console plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/try-in-console'] --- import kbnTryInConsoleObj from './kbn_try_in_console.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index 5ec77e2a06e07..de8efb3ca7f1e 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 5a5289b6cb2ae..94384e0d70098 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index d71283b636a38..f8511aa29bfd2 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index 471dc6005706e..8886d93c6ed20 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 499acfa51ffcc..0f435fe4d51a1 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index dbde5de2a9249..b7aaf9fc5e5eb 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index 823164c970adb..0d1f5386f06c5 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index c8765f73d5594..15cb0a4bc20d7 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index 0ed9d524f0d19..b96e80c0095c8 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_prompt.mdx b/api_docs/kbn_unsaved_changes_prompt.mdx index c5d4a02e9ba62..ca11a0dc92703 100644 --- a/api_docs/kbn_unsaved_changes_prompt.mdx +++ b/api_docs/kbn_unsaved_changes_prompt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-prompt title: "@kbn/unsaved-changes-prompt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-prompt plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-prompt'] --- import kbnUnsavedChangesPromptObj from './kbn_unsaved_changes_prompt.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 29ed5875748a2..7a233cb2eea87 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index e968891699024..fd1313146d3f4 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index ebeaae075a431..21ed092c0d0e3 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index 9bb52295063b3..ff420a4bcffb8 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index c366526745baa..871a0bdfb5173 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index eb515ec4ae82c..4cdb4dcc48863 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_visualization_utils.mdx b/api_docs/kbn_visualization_utils.mdx index bc5e2f54a73d5..7797965497563 100644 --- a/api_docs/kbn_visualization_utils.mdx +++ b/api_docs/kbn_visualization_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-utils title: "@kbn/visualization-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-utils'] --- import kbnVisualizationUtilsObj from './kbn_visualization_utils.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index 840e46e49eabc..7bfa9363cc99f 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index d9545969d2fa0..aea98e2695c20 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod.mdx b/api_docs/kbn_zod.mdx index 16aff3c1e9584..407bf62f21eb3 100644 --- a/api_docs/kbn_zod.mdx +++ b/api_docs/kbn_zod.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod title: "@kbn/zod" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod'] --- import kbnZodObj from './kbn_zod.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index 0791b1759db0c..14bf0ef891707 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 4d71a4dc33e76..6010dc9d398a0 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 62b96df12b69f..8a155f12d0392 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index b2563e3613201..d67bcb357c42c 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 461b933e6dcf9..9cc9282807f58 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.devdocs.json b/api_docs/lens.devdocs.json index 27e7e0a324279..cb14f93bdc64d 100644 --- a/api_docs/lens.devdocs.json +++ b/api_docs/lens.devdocs.json @@ -764,19 +764,18 @@ }, { "parentPluginId": "lens", - "id": "def-public.Embeddable.canViewUnderlyingData", - "type": "Function", + "id": "def-public.Embeddable.canViewUnderlyingData$", + "type": "Object", "tags": [], - "label": "canViewUnderlyingData", + "label": "canViewUnderlyingData$", "description": [], "signature": [ - "() => Promise" + "BehaviorSubject", + "" ], "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "trackAdoption": false }, { "parentPluginId": "lens", @@ -11401,7 +11400,15 @@ "section": "def-public.LensSavedObjectAttributes", "text": "LensSavedObjectAttributes" }, - " | undefined>; canViewUnderlyingData: () => Promise; getViewUnderlyingDataArgs: () => ", + " | undefined>; canViewUnderlyingData$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; getViewUnderlyingDataArgs: () => ", "ViewUnderlyingDataArgs", "; getFullAttributes: () => ", { diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 7e00249d1c4a9..d9afd39cc35d7 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index 45ee50d90bb29..55a2c7e151a0a 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 35235fc313ec9..55ad5949cbf6b 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index c3e88c4f56aed..b9e997187a8dd 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index 6fcfed1836120..bfa7c5c972370 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 250c0e52f907e..f199d4d73841a 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/logs_data_access.mdx b/api_docs/logs_data_access.mdx index 893832d32b813..4368791d9fd22 100644 --- a/api_docs/logs_data_access.mdx +++ b/api_docs/logs_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsDataAccess title: "logsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the logsDataAccess plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsDataAccess'] --- import logsDataAccessObj from './logs_data_access.devdocs.json'; diff --git a/api_docs/logs_explorer.mdx b/api_docs/logs_explorer.mdx index 042b42f0acba1..bd25652090303 100644 --- a/api_docs/logs_explorer.mdx +++ b/api_docs/logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsExplorer title: "logsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logsExplorer plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsExplorer'] --- import logsExplorerObj from './logs_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 4eed158298bc5..708194db1ca72 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index dd7cdc255be61..12a4dfa78a216 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index 8fc61b422770a..753cc5b0e88dc 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 473061eb99571..830a2c19490ac 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index d88973d983599..c7df6cc036db2 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.devdocs.json b/api_docs/ml.devdocs.json index 8b9d3866bfad7..e6ce179e5ada1 100644 --- a/api_docs/ml.devdocs.json +++ b/api_docs/ml.devdocs.json @@ -1253,7 +1253,9 @@ "MlDetector", "; }): Promise; forecast({ jobId, duration, neverExpires, }: { jobId: string; duration?: string | undefined; neverExpires?: boolean | undefined; }): Promise; deleteForecast({ jobId, forecastId }: { jobId: string; forecastId: string; }): Promise<", "DeleteForecastResponse", - ">; overallBuckets({ jobId, topN, bucketSpan, start, end, overallScore, }: { jobId: string; topN: string; bucketSpan: string; start: number; end: number; overallScore?: number | undefined; }): Promise; hasPrivileges(obj: any): Promise<", + ">; overallBuckets({ jobId, topN, bucketSpan, start, end, overallScore, }: { jobId: string[]; topN: string; bucketSpan: string; start: number; end: number; overallScore?: number | undefined; }): Promise<", + "MlGetOverallBucketsResponse", + ">; hasPrivileges(obj: any): Promise<", "MlHasPrivilegesResponse", ">; checkMlCapabilities(): Promise<", "MlCapabilitiesResponse", diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 41fa17a04ef93..952102823a86d 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index b0ecd6defef27..43e9681c9472c 100644 --- a/api_docs/mock_idp_plugin.mdx +++ b/api_docs/mock_idp_plugin.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mockIdpPlugin title: "mockIdpPlugin" image: https://source.unsplash.com/400x175/?github description: API docs for the mockIdpPlugin plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] --- import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index f63f4ff6eff9d..bd52b69d93172 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index aac666ff72e30..a5fa365dac656 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.devdocs.json b/api_docs/navigation.devdocs.json index d1c3a65dac7cc..9e31f4d2ddd76 100644 --- a/api_docs/navigation.devdocs.json +++ b/api_docs/navigation.devdocs.json @@ -379,7 +379,7 @@ "id": "def-public.TopNavMenuItems.$1", "type": "Object", "tags": [], - "label": "{\n config,\n className,\n popoverBreakpoints,\n}", + "label": "{\n config,\n className,\n popoverBreakpoints = POPOVER_BREAKPOINTS,\n}", "description": [], "signature": [ "TopNavMenuItemsProps" @@ -780,6 +780,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "navigation", + "id": "def-public.TopNavMenuData.iconOnly", + "type": "CompoundType", + "tags": [], + "label": "iconOnly", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "navigation", "id": "def-public.TopNavMenuData.target", diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 0ecb0e676ad05..87c865d4bcc22 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 55 | 0 | 53 | 4 | +| 56 | 0 | 54 | 4 | ## Client diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index 9c73243df6850..30e0d47d55770 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index 8e09cfae38518..1d5d98c9f5b11 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index 65fdff4b1242b..db2df8ad452b6 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index 5c875c4abbd9a..6f87ad7be9bee 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -4547,36 +4547,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "observability", - "id": "def-public.enableInfrastructureContainerAssetView", - "type": "string", - "tags": [], - "label": "enableInfrastructureContainerAssetView", - "description": [], - "signature": [ - "\"observability:enableInfrastructureContainerAssetView\"" - ], - "path": "x-pack/plugins/observability_solution/observability/common/ui_settings_keys.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "observability", - "id": "def-public.enableInfrastructureHostsView", - "type": "string", - "tags": [], - "label": "enableInfrastructureHostsView", - "description": [], - "signature": [ - "\"observability:enableInfrastructureHostsView\"" - ], - "path": "x-pack/plugins/observability_solution/observability/common/ui_settings_keys.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "observability", "id": "def-public.enableInspectEsQueries", @@ -10244,174 +10214,6 @@ } ] }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureHostsView", - "type": "Object", - "tags": [], - "label": "[enableInfrastructureHostsView]", - "description": [], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureHostsView.category", - "type": "Array", - "tags": [], - "label": "category", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureHostsView.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureHostsView.value", - "type": "boolean", - "tags": [], - "label": "value", - "description": [], - "signature": [ - "true" - ], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureHostsView.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureHostsView.schema", - "type": "Object", - "tags": [], - "label": "schema", - "description": [], - "signature": [ - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" - }, - "" - ], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureContainerAssetView", - "type": "Object", - "tags": [], - "label": "[enableInfrastructureContainerAssetView]", - "description": [], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureContainerAssetView.category", - "type": "Array", - "tags": [], - "label": "category", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureContainerAssetView.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureContainerAssetView.value", - "type": "boolean", - "tags": [], - "label": "value", - "description": [], - "signature": [ - "true" - ], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureContainerAssetView.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "observability", - "id": "def-server.uiSettings.enableInfrastructureContainerAssetView.schema", - "type": "Object", - "tags": [], - "label": "schema", - "description": [], - "signature": [ - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" - }, - "" - ], - "path": "x-pack/plugins/observability_solution/observability/server/ui_settings.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, { "parentPluginId": "observability", "id": "def-server.uiSettings.enableInfrastructureProfilingIntegration", @@ -14532,36 +14334,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "observability", - "id": "def-common.enableInfrastructureContainerAssetView", - "type": "string", - "tags": [], - "label": "enableInfrastructureContainerAssetView", - "description": [], - "signature": [ - "\"observability:enableInfrastructureContainerAssetView\"" - ], - "path": "x-pack/plugins/observability_solution/observability/common/ui_settings_keys.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "observability", - "id": "def-common.enableInfrastructureHostsView", - "type": "string", - "tags": [], - "label": "enableInfrastructureHostsView", - "description": [], - "signature": [ - "\"observability:enableInfrastructureHostsView\"" - ], - "path": "x-pack/plugins/observability_solution/observability/common/ui_settings_keys.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "observability", "id": "def-common.enableInfrastructureProfilingIntegration", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 524e954236a24..5abbbd33852ee 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 710 | 2 | 702 | 23 | +| 694 | 2 | 686 | 23 | ## Client diff --git a/api_docs/observability_a_i_assistant.devdocs.json b/api_docs/observability_a_i_assistant.devdocs.json index 8515f9c86f398..fb3350bd038fd 100644 --- a/api_docs/observability_a_i_assistant.devdocs.json +++ b/api_docs/observability_a_i_assistant.devdocs.json @@ -2394,7 +2394,7 @@ }, "<\"GET /internal/observability_ai_assistant/kb/status\", undefined, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { ready: boolean; error?: any; deployment_state?: ", + ", { enabled: boolean; ready: boolean; error?: any; deployment_state?: ", "MlDeploymentState", " | undefined; allocation_state?: ", "MlDeploymentAllocationState", @@ -3256,7 +3256,7 @@ }, "<\"GET /internal/observability_ai_assistant/kb/status\", undefined, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { ready: boolean; error?: any; deployment_state?: ", + ", { enabled: boolean; ready: boolean; error?: any; deployment_state?: ", "MlDeploymentState", " | undefined; allocation_state?: ", "MlDeploymentAllocationState", @@ -4839,7 +4839,7 @@ }, "<\"GET /internal/observability_ai_assistant/kb/status\", undefined, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { ready: boolean; error?: any; deployment_state?: ", + ", { enabled: boolean; ready: boolean; error?: any; deployment_state?: ", "MlDeploymentState", " | undefined; allocation_state?: ", "MlDeploymentAllocationState", @@ -5944,7 +5944,7 @@ }, "<\"GET /internal/observability_ai_assistant/kb/status\", undefined, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { ready: boolean; error?: any; deployment_state?: ", + ", { enabled: boolean; ready: boolean; error?: any; deployment_state?: ", "MlDeploymentState", " | undefined; allocation_state?: ", "MlDeploymentAllocationState", @@ -6826,7 +6826,15 @@ "section": "def-common.Message", "text": "Message" }, - "; }" + " & { scopes: ", + { + "pluginId": "@kbn/ai-assistant-common", + "scope": "common", + "docId": "kibKbnAiAssistantCommonPluginApi", + "section": "def-common.AssistantScope", + "text": "AssistantScope" + }, + "[]; }; }" ], "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts", "deprecated": false, @@ -7566,7 +7574,7 @@ }, "<\"GET /internal/observability_ai_assistant/kb/status\", undefined, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { ready: boolean; error?: any; deployment_state?: ", + ", { enabled: boolean; ready: boolean; error?: any; deployment_state?: ", "MlDeploymentState", " | undefined; allocation_state?: ", "MlDeploymentAllocationState", diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index 1c4817a258856..cc426946e39fd 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index 92ef3362fae29..625f342af0ecf 100644 --- a/api_docs/observability_a_i_assistant_app.mdx +++ b/api_docs/observability_a_i_assistant_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistantApp title: "observabilityAIAssistantApp" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistantApp plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistantApp'] --- import observabilityAIAssistantAppObj from './observability_a_i_assistant_app.devdocs.json'; diff --git a/api_docs/observability_ai_assistant_management.mdx b/api_docs/observability_ai_assistant_management.mdx index 94db91d595d8e..ed97f6b915448 100644 --- a/api_docs/observability_ai_assistant_management.mdx +++ b/api_docs/observability_ai_assistant_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAiAssistantManagement title: "observabilityAiAssistantManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAiAssistantManagement plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAiAssistantManagement'] --- import observabilityAiAssistantManagementObj from './observability_ai_assistant_management.devdocs.json'; diff --git a/api_docs/observability_logs_explorer.mdx b/api_docs/observability_logs_explorer.mdx index 5bfb65e5dcdc3..4a19dd9d48be9 100644 --- a/api_docs/observability_logs_explorer.mdx +++ b/api_docs/observability_logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogsExplorer title: "observabilityLogsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogsExplorer plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogsExplorer'] --- import observabilityLogsExplorerObj from './observability_logs_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 4589bf3c678cc..2851d4e75a0bc 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.devdocs.json b/api_docs/observability_shared.devdocs.json index cbcd73348b303..4026f1325b638 100644 --- a/api_docs/observability_shared.devdocs.json +++ b/api_docs/observability_shared.devdocs.json @@ -1541,7 +1541,9 @@ "type": "Function", "tags": [], "label": "useBreadcrumbs", - "description": [], + "description": [ + "\n\nBy default the breadcrumbs will be passed to either serverless.setBreadcrumbs or chrome.setBreadcrumbs depending on the\nenvironment. The breadcrumbs will *also* be passed to the project style breadcrumbs for stateful project style. We will use \"project style\"\nhere to refer to serverless chrome and stateful project style chrome. Classic refers to stateful classic chrome.\n\nProject style breadcrumbs add a root crumb (\"deployment\" etc) and \"nav crumbs\" which are derived from the navigation structure. By default\nthe \"absolute\" mode is used which means the breadcrumbs passed here will omit the navigation derived \"nav crumbs\". You can pass\nabsoluteProjectStyleBreadcrumbs: false to include the 'smart' \"nav crumbs\".\n\nIn classic mode (not project style) the 'Observability' crumb is added.\n\nYou can also pass classicOnly to only set breadrumbs in the classic chrome context. This can be useful if your solution just wants to defer all project style crumbs to the \"nav crumbs\"." + ], "signature": [ "(extraCrumbs: ", { @@ -1567,7 +1569,7 @@ "section": "def-public.ServerlessPluginStart", "text": "ServerlessPluginStart" }, - " | undefined; } | undefined) => void" + " | undefined; absoluteProjectStyleBreadcrumbs?: boolean | undefined; classicOnly?: boolean | undefined; } | undefined) => void" ], "path": "x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.ts", "deprecated": false, @@ -1661,6 +1663,34 @@ "path": "x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.useBreadcrumbs.$2.absoluteProjectStyleBreadcrumbs", + "type": "CompoundType", + "tags": [], + "label": "absoluteProjectStyleBreadcrumbs", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.useBreadcrumbs.$2.classicOnly", + "type": "CompoundType", + "tags": [], + "label": "classicOnly", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.ts", + "deprecated": false, + "trackAdoption": false } ] } diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 8e364a4fde118..127911cbf86cf 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 505 | 1 | 500 | 19 | +| 507 | 1 | 501 | 19 | ## Client diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index d8ba4c4ac9964..e45d68e6d7ce2 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index 45487e50b6834..ca6f97230e12c 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 239a584a6473a..0873bb827ba5b 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,20 +15,20 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 878 | 750 | 45 | +| 878 | 751 | 45 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 54116 | 242 | 40691 | 2016 | +| 54098 | 242 | 40653 | 2018 | ## Plugin Directory | Plugin name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 322 | 0 | 316 | 37 | -| | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 2 | 0 | 2 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 4 | 0 | 4 | 1 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 72 | 0 | 8 | 2 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 880 | 1 | 848 | 50 | @@ -39,7 +39,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 115 | 0 | 95 | 28 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 268 | 2 | 253 | 10 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 84 | 0 | 21 | 1 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 83 | 0 | 20 | 1 | | cloudChat | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | Chat available on Elastic Cloud deployments for quicker assistance. | 0 | 0 | 0 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | Static migration page where self-managed users can see text/copy about migrating to Elastic Cloud | 8 | 0 | 8 | 1 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | Defend for containers (D4C) | 52 | 0 | 43 | 2 | @@ -65,12 +65,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 31 | 3 | 25 | 4 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin introduces the concept of data set quality, where users can easily get an overview on the data sets they have. | 14 | 0 | 14 | 8 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 15 | 0 | 9 | 2 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 150 | 0 | 102 | 26 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 148 | 0 | 100 | 24 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 35 | 0 | 33 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A stateful layer to register shared features and provide an access point to discover without a direct dependency | 16 | 0 | 15 | 2 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | Server APIs for the Elastic AI Assistant | 52 | 0 | 37 | 2 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 575 | 1 | 465 | 9 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 578 | 1 | 468 | 9 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Extends embeddable plugin with more functionality | 19 | 0 | 19 | 2 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides encryption and decryption utilities for saved objects containing sensitive information. | 53 | 0 | 46 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Adds dashboards for discovering and managing Enterprise Search products. | 5 | 0 | 5 | 0 | @@ -103,7 +103,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 89 | 0 | 89 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 240 | 0 | 24 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Simple UI for managing files in Kibana | 3 | 0 | 3 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1426 | 5 | 1301 | 76 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1426 | 5 | 1301 | 80 | | ftrApis | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 72 | 0 | 14 | 5 | | globalSearchBar | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | @@ -114,7 +114,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 149 | 0 | 111 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Image embeddable | 1 | 0 | 1 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | -| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 252 | 0 | 247 | 1 | +| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 241 | 0 | 236 | 1 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 49 | 0 | 44 | 15 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions | 24 | 0 | 24 | 5 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | @@ -122,7 +122,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 127 | 2 | 100 | 4 | | | [@elastic/security-scalability](https://github.com/orgs/elastic/teams/security-scalability) | Plugin implementing the Integration Assistant API and UI | 71 | 0 | 56 | 4 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides UI and APIs for the interactive setup mode. | 28 | 0 | 18 | 0 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 5 | 0 | 5 | 3 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 5 | 0 | 5 | 4 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 43 | 0 | 43 | 4 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 5 | 0 | 5 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 6 | 0 | 6 | 0 | @@ -148,17 +148,17 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 2 | 0 | 2 | 0 | | | [@elastic/stack-monitoring](https://github.com/orgs/elastic/teams/stack-monitoring) | - | 15 | 3 | 13 | 1 | | | [@elastic/stack-monitoring](https://github.com/orgs/elastic/teams/stack-monitoring) | - | 9 | 0 | 9 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 55 | 0 | 53 | 4 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 56 | 0 | 54 | 4 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | -| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 710 | 2 | 702 | 23 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 694 | 2 | 686 | 23 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 296 | 1 | 294 | 27 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 4 | 0 | 4 | 0 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin exposes and registers observability log consumption features. | 19 | 0 | 19 | 1 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 24 | 0 | 24 | 0 | -| | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 505 | 1 | 500 | 19 | +| | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 507 | 1 | 501 | 19 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 23 | 0 | 23 | 7 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds a standardized Presentation panel which allows any forward ref component to interface with various Kibana systems. | 11 | 0 | 11 | 4 | @@ -168,13 +168,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 23 | 0 | 23 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Reporting Services enables applications to feature reports that the user can automate with Watcher and download later. | 9 | 0 | 2 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 21 | 0 | 21 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 285 | 0 | 248 | 11 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 263 | 0 | 226 | 10 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 24 | 0 | 19 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 114 | 2 | 109 | 5 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 25 | 0 | 25 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 148 | 0 | 139 | 2 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 89 | 0 | 83 | 3 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 100 | 0 | 53 | 1 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 36 | 0 | 30 | 3 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 105 | 0 | 58 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the definition and helper methods around saved searches, used by discover and visualizations. | 61 | 0 | 60 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 32 | 0 | 13 | 0 | | | [@elastic/kibana-reporting-services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Kibana Screenshotting Plugin | 32 | 0 | 8 | 3 | @@ -201,7 +201,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 25 | 0 | 25 | 3 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 10 | 0 | 10 | 0 | | synthetics | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | This plugin visualizes data from Synthetics and Heartbeat, and integrates with other Observability solutions. | 0 | 0 | 0 | 1 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 109 | 0 | 65 | 7 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 108 | 0 | 64 | 7 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 45 | 0 | 1 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 31 | 0 | 26 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 1 | 0 | @@ -243,7 +243,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Package name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 14 | 0 | 14 | 0 | -| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 63 | 0 | 63 | 1 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 64 | 0 | 64 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3 | 0 | 3 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 36 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 0 | 0 | @@ -277,8 +277,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 62 | 0 | 17 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 2 | 0 | -| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 88 | 1 | 88 | 0 | +| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 89 | 1 | 89 | 0 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 109 | 0 | 107 | 1 | +| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 18 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 41 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) | - | 9 | 0 | 4 | 0 | @@ -318,7 +319,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 5 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 20 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 210 | 0 | 103 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 211 | 0 | 104 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 1 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 8 | 0 | @@ -491,7 +492,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 3 | 0 | 3 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 65 | 0 | 53 | 0 | -| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 17 | 0 | 17 | 0 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 21 | 0 | 21 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 5 | 0 | 5 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 8 | 0 | 8 | 0 | @@ -503,7 +504,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 15 | 0 | 9 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 38 | 2 | 33 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 37 | 0 | 34 | 2 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 234 | 0 | 200 | 4 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 284 | 0 | 234 | 4 | | | [@elastic/docs](https://github.com/orgs/elastic/teams/docs) | - | 79 | 0 | 79 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 5 | 0 | 5 | 1 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 57 | 0 | 30 | 6 | @@ -519,7 +520,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 271 | 1 | 210 | 14 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 29 | 0 | 29 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 269 | 1 | 211 | 34 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 270 | 1 | 211 | 35 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 29 | 0 | 12 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 79 | 0 | 71 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 202 | 0 | 190 | 12 | @@ -546,7 +547,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 37 | 0 | 27 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 36 | 0 | 7 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 47 | 0 | 40 | 0 | -| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 126 | 3 | 126 | 0 | +| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 124 | 3 | 124 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 7 | 1 | 7 | 1 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 9 | 0 | 9 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 12 | 43 | 0 | @@ -573,7 +574,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 23 | 0 | 7 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 8 | 0 | 2 | 3 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 45 | 0 | 0 | 0 | -| | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 143 | 0 | 142 | 0 | +| | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 140 | 0 | 139 | 0 | | | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 20 | 0 | 11 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 88 | 0 | 10 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 56 | 0 | 6 | 0 | @@ -631,7 +632,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 92 | 0 | 80 | 0 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 218 | 0 | 183 | 6 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 224 | 0 | 188 | 6 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 1 | 0 | 1 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 168 | 0 | 55 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 13 | 0 | 7 | 0 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index e36455c81e2d7..16b10e77fb4cc 100644 --- a/api_docs/presentation_panel.mdx +++ b/api_docs/presentation_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationPanel title: "presentationPanel" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationPanel plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationPanel'] --- import presentationPanelObj from './presentation_panel.devdocs.json'; diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index f6792abb29a74..ab8af618daa21 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index c579fdab20a42..3927cb35d6f28 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index 5857a7a734a83..5729edd18fa41 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index e9ad7e476da4f..f34d7a56edb57 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index e1e38ca53773e..b999656ed4763 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index 99651d71f063d..47570ddea95fb 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.devdocs.json b/api_docs/rule_registry.devdocs.json index d12d867f04393..17ebe064cea2a 100644 --- a/api_docs/rule_registry.devdocs.json +++ b/api_docs/rule_registry.devdocs.json @@ -1879,266 +1879,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.createLifecycleExecutor", - "type": "Function", - "tags": [], - "label": "createLifecycleExecutor", - "description": [], - "signature": [ - "(logger: ", - { - "pluginId": "@kbn/logging", - "scope": "common", - "docId": "kibKbnLoggingPluginApi", - "section": "def-common.Logger", - "text": "Logger" - }, - ", ruleDataClient: ", - { - "pluginId": "@kbn/utility-types", - "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.PublicContract", - "text": "PublicContract" - }, - "<", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.IRuleDataClient", - "text": "IRuleDataClient" - }, - ">) => = never, InstanceContext extends { [x: string]: unknown; } = never, ActionGroupIds extends string = never>(wrappedExecutor: ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.LifecycleRuleExecutor", - "text": "LifecycleRuleExecutor" - }, - ") => (options: ", - { - "pluginId": "alerting", - "scope": "server", - "docId": "kibAlertingPluginApi", - "section": "def-server.RuleExecutorOptions", - "text": "RuleExecutorOptions" - }, - ", InstanceState, InstanceContext, ActionGroupIds, never>) => Promise<{ state: ", - { - "pluginId": "@kbn/alerting-state-types", - "scope": "server", - "docId": "kibKbnAlertingStateTypesPluginApi", - "section": "def-server.WrappedLifecycleRuleState", - "text": "WrappedLifecycleRuleState" - }, - "; }>" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.createLifecycleExecutor.$1", - "type": "Object", - "tags": [], - "label": "logger", - "description": [], - "signature": [ - { - "pluginId": "@kbn/logging", - "scope": "common", - "docId": "kibKbnLoggingPluginApi", - "section": "def-common.Logger", - "text": "Logger" - } - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.createLifecycleExecutor.$2", - "type": "Object", - "tags": [], - "label": "ruleDataClient", - "description": [], - "signature": [ - { - "pluginId": "@kbn/utility-types", - "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.PublicContract", - "text": "PublicContract" - }, - "<", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.IRuleDataClient", - "text": "IRuleDataClient" - }, - ">" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.createLifecycleRuleTypeFactory", - "type": "Function", - "tags": [], - "label": "createLifecycleRuleTypeFactory", - "description": [], - "signature": [ - "({ logger, ruleDataClient }: { logger: ", - { - "pluginId": "@kbn/logging", - "scope": "common", - "docId": "kibKbnLoggingPluginApi", - "section": "def-common.Logger", - "text": "Logger" - }, - "; ruleDataClient: ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.IRuleDataClient", - "text": "IRuleDataClient" - }, - "; }) => , TAlertInstanceContext extends { [x: string]: unknown; }, TActionGroupIds extends string, TServices extends ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.LifecycleAlertServices", - "text": "LifecycleAlertServices" - }, - ">(type: ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.AlertTypeWithExecutor", - "text": "AlertTypeWithExecutor" - }, - ") => ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.AlertTypeWithExecutor", - "text": "AlertTypeWithExecutor" - }, - "" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type_factory.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.createLifecycleRuleTypeFactory.$1", - "type": "Object", - "tags": [], - "label": "{ logger, ruleDataClient }", - "description": [], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type_factory.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.createLifecycleRuleTypeFactory.$1.logger", - "type": "Object", - "tags": [], - "label": "logger", - "description": [], - "signature": [ - { - "pluginId": "@kbn/logging", - "scope": "common", - "docId": "kibKbnLoggingPluginApi", - "section": "def-common.Logger", - "text": "Logger" - } - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type_factory.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.createLifecycleRuleTypeFactory.$1.ruleDataClient", - "type": "Object", - "tags": [], - "label": "ruleDataClient", - "description": [], - "signature": [ - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.IRuleDataClient", - "text": "IRuleDataClient" - } - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type_factory.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "ruleRegistry", "id": "def-server.createPersistenceRuleTypeWrapper", @@ -3414,173 +3154,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertServices", - "type": "Interface", - "tags": [], - "label": "LifecycleAlertServices", - "description": [], - "signature": [ - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.LifecycleAlertServices", - "text": "LifecycleAlertServices" - }, - "" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertServices.alertWithLifecycle", - "type": "Function", - "tags": [], - "label": "alertWithLifecycle", - "description": [], - "signature": [ - "(alert: { id: string; fields: ExplicitAlertFields; }) => ", - { - "pluginId": "alerting", - "scope": "server", - "docId": "kibAlertingPluginApi", - "section": "def-server.PublicAlert", - "text": "PublicAlert" - }, - "" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertServices.alertWithLifecycle.$1", - "type": "Object", - "tags": [], - "label": "alert", - "description": [], - "signature": [ - "{ id: string; fields: ExplicitAlertFields; }" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertServices.getAlertStartedDate", - "type": "Function", - "tags": [], - "label": "getAlertStartedDate", - "description": [], - "signature": [ - "(alertInstanceId: string) => string | null" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertServices.getAlertStartedDate.$1", - "type": "string", - "tags": [], - "label": "alertInstanceId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertServices.getAlertUuid", - "type": "Function", - "tags": [], - "label": "getAlertUuid", - "description": [], - "signature": [ - "(alertInstanceId: string) => string" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertServices.getAlertUuid.$1", - "type": "string", - "tags": [], - "label": "alertInstanceId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertServices.getAlertByAlertUuid", - "type": "Function", - "tags": [], - "label": "getAlertByAlertUuid", - "description": [], - "signature": [ - "(alertUuid: string) => Promise> & OutputOf>> | null> | null" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertServices.getAlertByAlertUuid.$1", - "type": "string", - "tags": [], - "label": "alertUuid", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false - }, { "parentPluginId": "ruleRegistry", "id": "def-server.PersistenceAlertServiceResult", @@ -4265,120 +3838,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertService", - "type": "Type", - "tags": [], - "label": "LifecycleAlertService", - "description": [], - "signature": [ - "(alert: { id: string; fields: ExplicitAlertFields; }) => ", - { - "pluginId": "alerting", - "scope": "server", - "docId": "kibAlertingPluginApi", - "section": "def-server.PublicAlert", - "text": "PublicAlert" - }, - "" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleAlertService.$1", - "type": "Object", - "tags": [], - "label": "alert", - "description": [], - "signature": [ - "{ id: string; fields: ExplicitAlertFields; }" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleRuleExecutor", - "type": "Type", - "tags": [], - "label": "LifecycleRuleExecutor", - "description": [], - "signature": [ - "(options: ", - "AlertExecutorOptionsWithExtraServices", - ">) => Promise<{ state: State; }>" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.LifecycleRuleExecutor.$1", - "type": "CompoundType", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "Omit<", - { - "pluginId": "alerting", - "scope": "server", - "docId": "kibAlertingPluginApi", - "section": "def-server.RuleExecutorOptions", - "text": "RuleExecutorOptions" - }, - ", \"services\"> & { services: ", - { - "pluginId": "alerting", - "scope": "server", - "docId": "kibAlertingPluginApi", - "section": "def-server.RuleExecutorServices", - "text": "RuleExecutorServices" - }, - " & ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.LifecycleAlertServices", - "text": "LifecycleAlertServices" - }, - "; }" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "ruleRegistry", "id": "def-server.Mappings", @@ -4848,101 +4307,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.RuleRegistryPluginSetupContract.createLifecycleRuleTypeFactory", - "type": "Function", - "tags": [], - "label": "createLifecycleRuleTypeFactory", - "description": [], - "signature": [ - "({ logger, ruleDataClient }: { logger: ", - { - "pluginId": "@kbn/logging", - "scope": "common", - "docId": "kibKbnLoggingPluginApi", - "section": "def-common.Logger", - "text": "Logger" - }, - "; ruleDataClient: ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.IRuleDataClient", - "text": "IRuleDataClient" - }, - "; }) => , TAlertInstanceContext extends { [x: string]: unknown; }, TActionGroupIds extends string, TServices extends ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.LifecycleAlertServices", - "text": "LifecycleAlertServices" - }, - ">(type: ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.AlertTypeWithExecutor", - "text": "AlertTypeWithExecutor" - }, - ") => ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.AlertTypeWithExecutor", - "text": "AlertTypeWithExecutor" - }, - "" - ], - "path": "x-pack/plugins/rule_registry/server/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.RuleRegistryPluginSetupContract.createLifecycleRuleTypeFactory.$1", - "type": "Object", - "tags": [], - "label": "__0", - "description": [], - "signature": [ - "{ logger: ", - { - "pluginId": "@kbn/logging", - "scope": "common", - "docId": "kibKbnLoggingPluginApi", - "section": "def-common.Logger", - "text": "Logger" - }, - "; ruleDataClient: ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.IRuleDataClient", - "text": "IRuleDataClient" - }, - "; }" - ], - "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type_factory.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, { "parentPluginId": "ruleRegistry", "id": "def-server.RuleRegistryPluginSetupContract.dataset", diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 7bd0eb9e450c6..b3b59ac359137 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 285 | 0 | 248 | 11 | +| 263 | 0 | 226 | 10 | ## Server diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index b3b9f7810d7f1..4213d49a47d64 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 63902df405436..de70b1f69fdd0 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index 1e7492c993743..32565bccf0842 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 1fb8d2f192992..311f1fc210a9f 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.devdocs.json b/api_docs/saved_objects_tagging.devdocs.json index 13b28479824b2..a3672cfb898d8 100644 --- a/api_docs/saved_objects_tagging.devdocs.json +++ b/api_docs/saved_objects_tagging.devdocs.json @@ -3,77 +3,7 @@ "client": { "classes": [], "functions": [], - "interfaces": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-public.Tag", - "type": "Interface", - "tags": [], - "label": "Tag", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-public.Tag.id", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-public.Tag.managed", - "type": "boolean", - "tags": [], - "label": "managed", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-public.Tag.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-public.Tag.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-public.Tag.color", - "type": "string", - "tags": [], - "label": "color", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - } - ], + "interfaces": [], "enums": [], "misc": [], "objects": [], @@ -171,355 +101,6 @@ } ], "initialIsOpen": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient", - "type": "Interface", - "tags": [], - "label": "ITagsClient", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.create", - "type": "Function", - "tags": [], - "label": "create", - "description": [], - "signature": [ - "(attributes: ", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.TagAttributes", - "text": "TagAttributes" - }, - ", options?: ", - "CreateTagOptions", - " | undefined) => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - ">" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.create.$1", - "type": "Object", - "tags": [], - "label": "attributes", - "description": [], - "signature": [ - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.TagAttributes", - "text": "TagAttributes" - } - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.create.$2", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "CreateTagOptions", - " | undefined" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.get", - "type": "Function", - "tags": [], - "label": "get", - "description": [], - "signature": [ - "(id: string) => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - ">" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.get.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.getAll", - "type": "Function", - "tags": [], - "label": "getAll", - "description": [], - "signature": [ - "(options?: ", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.GetAllTagsOptions", - "text": "GetAllTagsOptions" - }, - " | undefined) => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - "[]>" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.getAll.$1", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.GetAllTagsOptions", - "text": "GetAllTagsOptions" - }, - " | undefined" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.findByName", - "type": "Function", - "tags": [], - "label": "findByName", - "description": [], - "signature": [ - "(name: string, options?: { exact?: boolean | undefined; } | undefined) => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - " | null>" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.findByName.$1", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.findByName.$2", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.findByName.$2.exact", - "type": "CompoundType", - "tags": [], - "label": "exact", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.delete", - "type": "Function", - "tags": [], - "label": "delete", - "description": [], - "signature": [ - "(id: string) => Promise" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.delete.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.update", - "type": "Function", - "tags": [], - "label": "update", - "description": [], - "signature": [ - "(id: string, attributes: ", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.TagAttributes", - "text": "TagAttributes" - }, - ") => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - ">" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.update.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-server.ITagsClient.update.$2", - "type": "Object", - "tags": [], - "label": "attributes", - "description": [], - "signature": [ - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.TagAttributes", - "text": "TagAttributes" - } - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false } ], "enums": [], @@ -831,471 +412,6 @@ } ], "interfaces": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient", - "type": "Interface", - "tags": [], - "label": "ITagsClient", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.create", - "type": "Function", - "tags": [], - "label": "create", - "description": [], - "signature": [ - "(attributes: ", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.TagAttributes", - "text": "TagAttributes" - }, - ", options?: ", - "CreateTagOptions", - " | undefined) => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - ">" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.create.$1", - "type": "Object", - "tags": [], - "label": "attributes", - "description": [], - "signature": [ - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.TagAttributes", - "text": "TagAttributes" - } - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.create.$2", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "CreateTagOptions", - " | undefined" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.get", - "type": "Function", - "tags": [], - "label": "get", - "description": [], - "signature": [ - "(id: string) => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - ">" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.get.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.getAll", - "type": "Function", - "tags": [], - "label": "getAll", - "description": [], - "signature": [ - "(options?: ", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.GetAllTagsOptions", - "text": "GetAllTagsOptions" - }, - " | undefined) => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - "[]>" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.getAll.$1", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.GetAllTagsOptions", - "text": "GetAllTagsOptions" - }, - " | undefined" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.findByName", - "type": "Function", - "tags": [], - "label": "findByName", - "description": [], - "signature": [ - "(name: string, options?: { exact?: boolean | undefined; } | undefined) => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - " | null>" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.findByName.$1", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.findByName.$2", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.findByName.$2.exact", - "type": "CompoundType", - "tags": [], - "label": "exact", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.delete", - "type": "Function", - "tags": [], - "label": "delete", - "description": [], - "signature": [ - "(id: string) => Promise" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.delete.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.update", - "type": "Function", - "tags": [], - "label": "update", - "description": [], - "signature": [ - "(id: string, attributes: ", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.TagAttributes", - "text": "TagAttributes" - }, - ") => Promise<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - ">" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.update.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.ITagsClient.update.$2", - "type": "Object", - "tags": [], - "label": "attributes", - "description": [], - "signature": [ - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.TagAttributes", - "text": "TagAttributes" - } - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.Tag", - "type": "Interface", - "tags": [], - "label": "Tag", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.Tag.id", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.Tag.managed", - "type": "boolean", - "tags": [], - "label": "managed", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.Tag.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.Tag.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.Tag.color", - "type": "string", - "tags": [], - "label": "color", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.TagAttributes", - "type": "Interface", - "tags": [], - "label": "TagAttributes", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.TagAttributes.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.TagAttributes.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.TagAttributes.color", - "type": "string", - "tags": [], - "label": "color", - "description": [], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "savedObjectsTagging", "id": "def-common.TagsCapabilities", @@ -1513,36 +629,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.TagSavedObject", - "type": "Type", - "tags": [], - "label": "TagSavedObject", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-saved-objects-common", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsCommonPluginApi", - "section": "def-common.SavedObject", - "text": "SavedObject" - }, - "<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.TagAttributes", - "text": "TagAttributes" - }, - ">" - ], - "path": "x-pack/plugins/saved_objects_tagging/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "savedObjectsTagging", "id": "def-common.tagSavedObjectTypeName", @@ -1559,51 +645,6 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.TagWithOptionalId", - "type": "Type", - "tags": [], - "label": "TagWithOptionalId", - "description": [], - "signature": [ - "Omit<", - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - ", \"id\"> & { id?: string | undefined; }" - ], - "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "savedObjectsTagging", - "id": "def-common.TagWithRelations", - "type": "Type", - "tags": [], - "label": "TagWithRelations", - "description": [], - "signature": [ - { - "pluginId": "savedObjectsTaggingOss", - "scope": "common", - "docId": "kibSavedObjectsTaggingOssPluginApi", - "section": "def-common.Tag", - "text": "Tag" - }, - " & { relationCount: number; }" - ], - "path": "x-pack/plugins/saved_objects_tagging/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index 0fb0e3ab4bfc5..c5da7879f7c2d 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; @@ -21,16 +21,13 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 89 | 0 | 83 | 3 | +| 36 | 0 | 30 | 3 | ## Client ### Start -### Interfaces - - ## Server ### Start diff --git a/api_docs/saved_objects_tagging_oss.devdocs.json b/api_docs/saved_objects_tagging_oss.devdocs.json index 0ee6e295f18b2..3b82d21a21b2c 100644 --- a/api_docs/saved_objects_tagging_oss.devdocs.json +++ b/api_docs/saved_objects_tagging_oss.devdocs.json @@ -1451,6 +1451,76 @@ "classes": [], "functions": [], "interfaces": [ + { + "parentPluginId": "savedObjectsTaggingOss", + "id": "def-common.CreateTagOptions", + "type": "Interface", + "tags": [], + "label": "CreateTagOptions", + "description": [], + "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedObjectsTaggingOss", + "id": "def-common.CreateTagOptions.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjectsTaggingOss", + "id": "def-common.CreateTagOptions.overwrite", + "type": "CompoundType", + "tags": [], + "label": "overwrite", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjectsTaggingOss", + "id": "def-common.CreateTagOptions.refresh", + "type": "CompoundType", + "tags": [], + "label": "refresh", + "description": [], + "signature": [ + "boolean | \"wait_for\" | undefined" + ], + "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjectsTaggingOss", + "id": "def-common.CreateTagOptions.managed", + "type": "CompoundType", + "tags": [], + "label": "managed", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "savedObjectsTaggingOss", "id": "def-common.GetAllTagsOptions", @@ -1507,7 +1577,13 @@ "text": "TagAttributes" }, ", options?: ", - "CreateTagOptions", + { + "pluginId": "savedObjectsTaggingOss", + "scope": "common", + "docId": "kibSavedObjectsTaggingOssPluginApi", + "section": "def-common.CreateTagOptions", + "text": "CreateTagOptions" + }, " | undefined) => Promise<", { "pluginId": "savedObjectsTaggingOss", @@ -1551,7 +1627,13 @@ "label": "options", "description": [], "signature": [ - "CreateTagOptions", + { + "pluginId": "savedObjectsTaggingOss", + "scope": "common", + "docId": "kibSavedObjectsTaggingOssPluginApi", + "section": "def-common.CreateTagOptions", + "text": "CreateTagOptions" + }, " | undefined" ], "path": "src/plugins/saved_objects_tagging_oss/common/types.ts", diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index e79c626159bca..6ac50d30fefa2 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 100 | 0 | 53 | 1 | +| 105 | 0 | 58 | 0 | ## Client diff --git a/api_docs/saved_search.mdx b/api_docs/saved_search.mdx index 0491dfa40fb07..0823713fa2f7a 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedSearch'] --- import savedSearchObj from './saved_search.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 3a6f46a1781f8..c79272bcab541 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index 6c32d66087e2a..c189de373b251 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/search_assistant.mdx b/api_docs/search_assistant.mdx index 344bcb84a50a5..09f5e8dbd2f98 100644 --- a/api_docs/search_assistant.mdx +++ b/api_docs/search_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchAssistant title: "searchAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the searchAssistant plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchAssistant'] --- import searchAssistantObj from './search_assistant.devdocs.json'; diff --git a/api_docs/search_connectors.mdx b/api_docs/search_connectors.mdx index 62bdb500e93c0..e9b0559250df3 100644 --- a/api_docs/search_connectors.mdx +++ b/api_docs/search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchConnectors title: "searchConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the searchConnectors plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './search_connectors.devdocs.json'; diff --git a/api_docs/search_homepage.mdx b/api_docs/search_homepage.mdx index ca3b5baf13216..ab6fb76c6ecf5 100644 --- a/api_docs/search_homepage.mdx +++ b/api_docs/search_homepage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchHomepage title: "searchHomepage" image: https://source.unsplash.com/400x175/?github description: API docs for the searchHomepage plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchHomepage'] --- import searchHomepageObj from './search_homepage.devdocs.json'; diff --git a/api_docs/search_indices.devdocs.json b/api_docs/search_indices.devdocs.json index a2fa441a9b27d..2a5d681533d15 100644 --- a/api_docs/search_indices.devdocs.json +++ b/api_docs/search_indices.devdocs.json @@ -85,7 +85,7 @@ "label": "startAppId", "description": [], "signature": [ - "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" ], "path": "x-pack/plugins/search_indices/public/types.ts", "deprecated": false, diff --git a/api_docs/search_indices.mdx b/api_docs/search_indices.mdx index a66160b5502f9..6c22ef39e3d9a 100644 --- a/api_docs/search_indices.mdx +++ b/api_docs/search_indices.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchIndices title: "searchIndices" image: https://source.unsplash.com/400x175/?github description: API docs for the searchIndices plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchIndices'] --- import searchIndicesObj from './search_indices.devdocs.json'; diff --git a/api_docs/search_inference_endpoints.mdx b/api_docs/search_inference_endpoints.mdx index b9328cdd4ffcc..ace1269008f04 100644 --- a/api_docs/search_inference_endpoints.mdx +++ b/api_docs/search_inference_endpoints.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchInferenceEndpoints title: "searchInferenceEndpoints" image: https://source.unsplash.com/400x175/?github description: API docs for the searchInferenceEndpoints plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchInferenceEndpoints'] --- import searchInferenceEndpointsObj from './search_inference_endpoints.devdocs.json'; diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index 93a3522cb9b8e..58f43079c034e 100644 --- a/api_docs/search_notebooks.mdx +++ b/api_docs/search_notebooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchNotebooks title: "searchNotebooks" image: https://source.unsplash.com/400x175/?github description: API docs for the searchNotebooks plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNotebooks'] --- import searchNotebooksObj from './search_notebooks.devdocs.json'; diff --git a/api_docs/search_playground.mdx b/api_docs/search_playground.mdx index 41e9088935d56..4be8fad3aa7e0 100644 --- a/api_docs/search_playground.mdx +++ b/api_docs/search_playground.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchPlayground title: "searchPlayground" image: https://source.unsplash.com/400x175/?github description: API docs for the searchPlayground plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.devdocs.json b/api_docs/security.devdocs.json index a641e9411e347..18274d63075c1 100644 --- a/api_docs/security.devdocs.json +++ b/api_docs/security.devdocs.json @@ -6644,6 +6644,10 @@ { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts" } ] } diff --git a/api_docs/security.mdx b/api_docs/security.mdx index bae120b81c5ef..2f3eec79dadc9 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index cfeb857bbb82a..5da27f3f14753 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -420,7 +420,7 @@ "\nExperimental flag needed to enable the link" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreDisabled\" | \"siemMigrationsEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesDisabled\" | \"entityAlertPreviewDisabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"graphVisualizationInFlyoutEnabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreDisabled\" | \"siemMigrationsEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -500,7 +500,7 @@ "\nExperimental flag needed to disable the link. Opposite of experimentalKey" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreDisabled\" | \"siemMigrationsEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesDisabled\" | \"entityAlertPreviewDisabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"graphVisualizationInFlyoutEnabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreDisabled\" | \"siemMigrationsEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -1791,7 +1791,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreDisabled: boolean; readonly siemMigrationsEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesDisabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly graphVisualizationInFlyoutEnabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreDisabled: boolean; readonly siemMigrationsEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -2918,7 +2918,7 @@ "label": "ConfigType", "description": [], "signature": [ - "Omit; entityAnalytics: Readonly<{} & { riskEngine: Readonly<{} & { alertSampleSizePerShard: number; }>; assetCriticality: Readonly<{} & { csvUpload: Readonly<{} & { errorRetries: number; maxBulkRequestBodySizeBytes: number; }>; }>; entityStore: Readonly<{} & { developer: Readonly<{} & { pipelineDebugMode: boolean; }>; }>; }>; }>, \"offeringSettings\"> & { experimentalFeatures: ", + "Omit; entityAnalytics: Readonly<{} & { riskEngine: Readonly<{} & { alertSampleSizePerShard: number; }>; assetCriticality: Readonly<{} & { csvUpload: Readonly<{} & { errorRetries: number; maxBulkRequestBodySizeBytes: number; }>; }>; entityStore: Readonly<{} & { frequency: moment.Duration; syncDelay: moment.Duration; developer: Readonly<{} & { pipelineDebugMode: boolean; }>; }>; }>; }>, \"offeringSettings\"> & { experimentalFeatures: ", { "pluginId": "securitySolution", "scope": "common", @@ -2993,7 +2993,7 @@ "\nThe security solution generic experimental features" ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreDisabled: boolean; readonly siemMigrationsEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesDisabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly graphVisualizationInFlyoutEnabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreDisabled: boolean; readonly siemMigrationsEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", "deprecated": false, @@ -3166,7 +3166,7 @@ "label": "ExperimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreDisabled: boolean; readonly siemMigrationsEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesDisabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly graphVisualizationInFlyoutEnabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreDisabled: boolean; readonly siemMigrationsEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3232,7 +3232,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly endpointManagementSpaceAwarenessEnabled: false; readonly securitySolutionNotesEnabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly responseActionsTelemetryEnabled: false; readonly jamfDataInAnalyzerEnabled: true; readonly timelineEsqlTabDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: false; readonly entityStoreDisabled: false; readonly siemMigrationsEnabled: false; }" + "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly endpointManagementSpaceAwarenessEnabled: false; readonly securitySolutionNotesDisabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: true; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly responseActionsTelemetryEnabled: false; readonly jamfDataInAnalyzerEnabled: true; readonly timelineEsqlTabDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly graphVisualizationInFlyoutEnabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: false; readonly entityStoreDisabled: false; readonly siemMigrationsEnabled: false; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 799d580bc92f1..586390523a44d 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index 3bb1db377d6bf..d009bb108a27b 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index e6d20157cffb8..e39fcaaa9f7d9 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.devdocs.json b/api_docs/serverless.devdocs.json index 110cf72e9d79e..5ff67d3104e84 100644 --- a/api_docs/serverless.devdocs.json +++ b/api_docs/serverless.devdocs.json @@ -166,7 +166,15 @@ "label": "initNavigation", "description": [], "signature": [ - "(id: string, navigationTree$: ", + "(id: ", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.SolutionId", + "text": "SolutionId" + }, + ", navigationTree$: ", "Observable", "<", { @@ -201,12 +209,18 @@ { "parentPluginId": "serverless", "id": "def-public.ServerlessPluginStart.initNavigation.$1", - "type": "string", + "type": "CompoundType", "tags": [], "label": "id", "description": [], "signature": [ - "string" + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.SolutionId", + "text": "SolutionId" + } ], "path": "x-pack/plugins/serverless/public/types.ts", "deprecated": false, diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index fb6ee25b16da9..418fcba2bb493 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index 0a39d56a088cf..207120e0af381 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index e8cc5b79f0430..1f369bc489146 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index e2503457d7cd6..6519f810a35f9 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.devdocs.json b/api_docs/share.devdocs.json index 779c2a12f4c64..f059f4827715a 100644 --- a/api_docs/share.devdocs.json +++ b/api_docs/share.devdocs.json @@ -905,7 +905,7 @@ }, { "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx" + "path": "src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_share.tsx" } ] }, diff --git a/api_docs/share.mdx b/api_docs/share.mdx index 5919a0988b784..f789f022797d4 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index 53dcaa9ccd441..60c86ac71416c 100644 --- a/api_docs/slo.mdx +++ b/api_docs/slo.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/slo title: "slo" image: https://source.unsplash.com/400x175/?github description: API docs for the slo plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'slo'] --- import sloObj from './slo.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 364543bcef3e6..4096f521d93bc 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.devdocs.json b/api_docs/spaces.devdocs.json index e87c7b38031a0..93ea371a06d61 100644 --- a/api_docs/spaces.devdocs.json +++ b/api_docs/spaces.devdocs.json @@ -5154,11 +5154,11 @@ "description": [], "signature": [ { - "pluginId": "cloud", - "scope": "common", - "docId": "kibCloudPluginApi", - "section": "def-common.OnBoardingDefaultSolution", - "text": "OnBoardingDefaultSolution" + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.SolutionId", + "text": "SolutionId" }, " | \"classic\"" ], diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 167bd4ba407d2..5a08504ed7e6d 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 4e6b8f6db5044..8269f73230ba0 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/stack_connectors.mdx b/api_docs/stack_connectors.mdx index ad230c18ae5c4..133ac743ba0eb 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.devdocs.json b/api_docs/task_manager.devdocs.json index 4eec18a6f47c0..88f728716be0e 100644 --- a/api_docs/task_manager.devdocs.json +++ b/api_docs/task_manager.devdocs.json @@ -134,15 +134,7 @@ "section": "def-server.TaskManagerStartContract", "text": "TaskManagerStartContract" }, - ", unknown>, plugins: { cloud?: ", - { - "pluginId": "cloud", - "scope": "server", - "docId": "kibCloudPluginApi", - "section": "def-server.CloudSetup", - "text": "CloudSetup" - }, - " | undefined; usageCollection?: ", + ", unknown>, plugins: { usageCollection?: ", { "pluginId": "usageCollection", "scope": "server", @@ -204,27 +196,6 @@ "deprecated": false, "trackAdoption": false, "children": [ - { - "parentPluginId": "taskManager", - "id": "def-server.TaskManagerPlugin.setup.$2.cloud", - "type": "Object", - "tags": [], - "label": "cloud", - "description": [], - "signature": [ - { - "pluginId": "cloud", - "scope": "server", - "docId": "kibCloudPluginApi", - "section": "def-server.CloudSetup", - "text": "CloudSetup" - }, - " | undefined" - ], - "path": "x-pack/plugins/task_manager/server/plugin.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "taskManager", "id": "def-server.TaskManagerPlugin.setup.$2.usageCollection", diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 5a5f0f87ca35f..18089bf93c662 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 109 | 0 | 65 | 7 | +| 108 | 0 | 64 | 7 | ## Server diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index f402acf45c06f..50d0b5f2333c8 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 611519f28dd38..fedfbf093a1cb 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index 08bcd82d4751c..e64f45318bbd8 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 578ede36f50fe..4c451d5da0555 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 16c8b51601af5..a23caf59f6ecb 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 63ef6479c8745..bf0519ab7d43e 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 70c2bb6e660e3..adf88eb9d5b29 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index a331cc99a2476..aae0a1a79d30c 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 3b6848a87016c..11c00bbe76910 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 280f694f36b66..255d8cad3796d 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index 3b782f0785a09..ff623718d6e77 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index b5a4445640eab..79b1306473caa 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 100b60e87605b..b7f2fec64c432 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 3fc6f67275a87..4ad7a531f0d51 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index 34573796bb3af..35f7eb900360e 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index b3329138f61a8..296a53bcaa6a7 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 7bc577aa729de..7d0944c690494 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index 9e3366bb305dc..61b4cb3fc2ad1 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index 2496dfbc96e48..c8a7afdac19f9 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 5264dea7092c5..2fa5b3b9853fc 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 5c10e69ade3c1..8f0e2e61162ca 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index 7f9475ba64793..0f2968fde504e 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index 876c30ba6d62f..23be7ae9f9991 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 6425e01e09e75..e5a5bcb4a4a2c 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index ff46daef026ad..0637b99db10e4 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index 03500f2fb8b8f..df3fe33873bad 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index cff1b9359f925..21327a8338052 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index 2305809f08236..7f41f4c97200a 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.devdocs.json b/api_docs/visualizations.devdocs.json index 4ffa3d6ca8856..b3a0a1f575137 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -6976,7 +6976,15 @@ "section": "def-public.PublishesViewMode", "text": "PublishesViewMode" }, - ">) | undefined; disableTriggers: boolean; timeRange$: ", + ">) | undefined; hasLockedHoverActions$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; lockHoverActions: (lock: boolean) => void; disableTriggers: boolean; timeRange$: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 5d8fbb1f4fa01..c85b2fe1f41bf 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2024-10-25 +date: 2024-11-01 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/config/kibana.yml b/config/kibana.yml index 6c4fb774eb37c..c816337f881d4 100644 --- a/config/kibana.yml +++ b/config/kibana.yml @@ -181,8 +181,3 @@ # Maximum number of documents loaded by each shard to generate autocomplete suggestions. # This value must be a whole number greater than zero. Defaults to 100_000 #unifiedSearch.autocomplete.valueSuggestions.terminateAfter: 100000 - -# Must be removed before v9 release -# Requires all registry packages to add v9 as a compatible semver range -# https://github.com/elastic/kibana/issues/192624 -xpack.fleet.internal.registry.kibanaVersionCheckEnabled: false diff --git a/dev_docs/key_concepts/api_authorization.mdx b/dev_docs/key_concepts/api_authorization.mdx index b781808757c9a..cda6ad5de21ce 100644 --- a/dev_docs/key_concepts/api_authorization.mdx +++ b/dev_docs/key_concepts/api_authorization.mdx @@ -313,6 +313,23 @@ Routes without a compelling reason to opt-out of authorization should plan to in MIGRATE_DISABLED_AUTHZ=true MIGRATE_ENABLED_AUTHZ=true npx eslint --ext .ts --fix path/to/your/folder ``` +**How to migrate if you have an utility function for route creation?** +If you have utility function that creates routes, i.e `createApmServerRoute` or `createObservabilityOnboardingServerRoute`, you can easily modify the eslint rule to handle your case. +For example, you register the route with `access` tags in your utility function: +```ts +createApmServerRoute({ + endpoint: 'GET /your/route/path', + options: { tags: ['access:apm'] }, + handler: async (resources): => { + // your handler logic + }, +}) +``` +You can modify [the rule](https://github.com/elastic/kibana/blob/6a50066e00ae38a64c5365fd66b4dc32857ba1fc/packages/kbn-eslint-plugin-eslint/rules/no_deprecated_authz_config.js#L312-#L315) to handle your case by adding the following code: +```ts +callee.type === 'Identifier' && callee.name === 'createApmServerRoute' +``` + ## Questions? If you have any questions or need help with API authorization, please reach out to the `@elastic/kibana-security` team. diff --git a/dev_docs/nav-kibana-dev.docnav.json b/dev_docs/nav-kibana-dev.docnav.json index 6dd2ca052b7bd..289593aaf159c 100644 --- a/dev_docs/nav-kibana-dev.docnav.json +++ b/dev_docs/nav-kibana-dev.docnav.json @@ -183,8 +183,13 @@ "label": "data.search" }, { - "id": "kibDevTutorialFileService", - "label": "File service" + "id": "kibDevTutorialScreenshotting", + "label": "Screenshotting", + "items": [ + { + "id": "kibDevDocsUpdatingPuppeteerAndChromium" + } + ] }, { "id": "kibDevTutorialDataViews" @@ -266,10 +271,6 @@ } ] }, - { - "id": "kibDevTutorialScreenshotting", - "label": "Screenshotting" - }, { "id": "kibDevTutorialAdvancedSettings", "label": "Advanced Settings" diff --git a/dev_docs/shared_ux/shared_ux_landing.mdx b/dev_docs/shared_ux/shared_ux_landing.mdx index 6093b1c5c943f..d5cebf7b76b1f 100644 --- a/dev_docs/shared_ux/shared_ux_landing.mdx +++ b/dev_docs/shared_ux/shared_ux_landing.mdx @@ -46,16 +46,6 @@ layout: landing pageId: 'kibContentManagement', description: 'Learn about the content management system in Kibana', }, - { - pageId: 'kibDevTutorialScreenshotting', - title: 'Reporting / Screenshotting', - description: 'Learn how to integrate your plugin with reporting', - }, - { - pageId: 'kibDevDocsUpdatingPuppeteerAndChromium', - title: 'Reporting / Updating Puppeteer and Chromium', - description: 'Learn how to update the Puppeteer node module and build headless Chromium', - }, { pageId: 'kibDevTutorialAdvancedSettings', title: 'Advanced Settings (uiSettings)', diff --git a/dev_docs/shared_ux/browser_snapshots_filter1.png b/dev_docs/tutorials/screenshotting/browser_snapshots_filter1.png similarity index 100% rename from dev_docs/shared_ux/browser_snapshots_filter1.png rename to dev_docs/tutorials/screenshotting/browser_snapshots_filter1.png diff --git a/dev_docs/shared_ux/browser_snapshots_filter2.png b/dev_docs/tutorials/screenshotting/browser_snapshots_filter2.png similarity index 100% rename from dev_docs/shared_ux/browser_snapshots_filter2.png rename to dev_docs/tutorials/screenshotting/browser_snapshots_filter2.png diff --git a/dev_docs/shared_ux/browser_snapshots_listing.png b/dev_docs/tutorials/screenshotting/browser_snapshots_listing.png similarity index 100% rename from dev_docs/shared_ux/browser_snapshots_listing.png rename to dev_docs/tutorials/screenshotting/browser_snapshots_listing.png diff --git a/dev_docs/shared_ux/chromium_version_command.png b/dev_docs/tutorials/screenshotting/chromium_version_command.png similarity index 100% rename from dev_docs/shared_ux/chromium_version_command.png rename to dev_docs/tutorials/screenshotting/chromium_version_command.png diff --git a/dev_docs/tutorials/screenshotting.mdx b/dev_docs/tutorials/screenshotting/screenshotting.mdx similarity index 100% rename from dev_docs/tutorials/screenshotting.mdx rename to dev_docs/tutorials/screenshotting/screenshotting.mdx diff --git a/dev_docs/shared_ux/updating_puppeteer_and_chromium.mdx b/dev_docs/tutorials/screenshotting/screenshotting_updating_puppeteer_and_chromium.mdx similarity index 100% rename from dev_docs/shared_ux/updating_puppeteer_and_chromium.mdx rename to dev_docs/tutorials/screenshotting/screenshotting_updating_puppeteer_and_chromium.mdx diff --git a/docs/api/role-management.asciidoc b/docs/api/role-management.asciidoc index 7fbded3e57dd3..837e63bff74f0 100644 --- a/docs/api/role-management.asciidoc +++ b/docs/api/role-management.asciidoc @@ -1,4 +1,3 @@ -[role="xpack"] [[role-management-api]] == {kib} role management APIs @@ -6,19 +5,4 @@ Manage the roles that grant <>. WARNING: Do not use the {ref}/security-api.html#security-role-apis[{es} role management APIs] to manage {kib} roles. -The following {kib} role management APIs are available: - -* <> to create a new {kib} role, or update the attributes of an existing role -* <> to create a new {kib} roles, or update the attributes of existing roles - -* <> to retrieve all {kib} roles - -* <> to retrieve a specific role - -* <> to delete a {kib} role - -include::role-management/put.asciidoc[] -include::role-management/get.asciidoc[] -include::role-management/get-all.asciidoc[] -include::role-management/delete.asciidoc[] -include::role-management/put-bulk.asciidoc[] +For the latest API details, refer to {api-kibana}/group/endpoint-roles[role APIs]. diff --git a/docs/api/role-management/delete.asciidoc b/docs/api/role-management/delete.asciidoc deleted file mode 100644 index 530e1e252ef8f..0000000000000 --- a/docs/api/role-management/delete.asciidoc +++ /dev/null @@ -1,26 +0,0 @@ -[[role-management-api-delete]] -=== Delete role API -++++ -Delete role -++++ - -experimental[] Delete a {kib} role. - -[[role-management-api-delete-prereqs]] -==== Prerequisite - -To use the delete role API, you must have the `manage_security` cluster privilege. - -[[role-management-api-delete-request-body]] -==== Request - -`DELETE :/api/security/role/my_admin_role` - -[[role-management-api-delete-response-codes]] -==== Response codes - -`204`:: - Indicates a successful call. - -`404`:: - Indicates an unsuccessful call. diff --git a/docs/api/role-management/get-all.asciidoc b/docs/api/role-management/get-all.asciidoc deleted file mode 100644 index 56c8b2c78859b..0000000000000 --- a/docs/api/role-management/get-all.asciidoc +++ /dev/null @@ -1,80 +0,0 @@ -[[role-management-api-get]] -=== Get all {kib} roles API -++++ -Get all roles -++++ - -experimental[] Retrieve all {kib} roles. - -[[role-management-api-get-prereqs]] -==== Prerequisite - -To use the get role API, you must have the `manage_security` cluster privilege. - -[[role-management-api-retrieve-all-request-body]] -==== Request - -`GET :/api/security/role` - -[[role-management-api-retrieve-all-response-codes]] -==== Response code - -`200`:: - Indicates a successful call. - -[[role-management-api-retrieve-all-example]] -==== Example - -The API returns the following: - -[source,sh] --------------------------------------------------- -[ - { - "name": "my_kibana_role", - "description": "My kibana role description", - "metadata" : { - "version" : 1 - }, - "transient_metadata": { - "enabled": true - }, - "elasticsearch": { - "indices": [ ], - "cluster": [ ], - "run_as": [ ] - }, - "kibana": [{ - "base": [ - "all" - ], - "feature": {}, - "spaces": [ - "*" - ] - }] - }, - { - "name": "my_admin_role", - "description": "My admin role description", - "metadata" : { - "version" : 1 - }, - "transient_metadata": { - "enabled": true - }, - "elasticsearch": { - "cluster" : [ "all" ], - "indices" : [ { - "names" : [ "index1", "index2" ], - "privileges" : [ "all" ], - "field_security" : { - "grant" : [ "title", "body" ] - }, - "query" : "{\"match\": {\"title\": \"foo\"}}" - } ], - }, - "kibana": [ ] - } -] --------------------------------------------------- diff --git a/docs/api/role-management/get.asciidoc b/docs/api/role-management/get.asciidoc deleted file mode 100644 index 95f944a56e150..0000000000000 --- a/docs/api/role-management/get.asciidoc +++ /dev/null @@ -1,106 +0,0 @@ -[[role-management-specific-api-get]] -=== Get specific role API -++++ -Get specific role -++++ - -experimental[] Retrieve a specific role. - -[[role-management-specific-api-get-prereqs]] -==== Prerequisite - -To use the get specific role API, you must have the `manage_security` cluster privilege. - -[[role-management-specific-api-retrieve-all-request-body]] -===== Request - -`GET :/api/security/role/my_restricted_kibana_role` - -[[role-management-specific-api-retrieve-all-response-codes]] -==== Response code - -`200`:: - Indicates a successful call. - -[[role-management-specific-api-retrieve-all-example]] -===== Example - -The API returns the following: - -[source,sh] --------------------------------------------------- -{ - "name": "my_restricted_kibana_role", - "description": "My restricted kibana role description", - "metadata" : { - "version" : 1 - }, - "transient_metadata": { - "enabled": true - }, - "elasticsearch": { - "cluster": [ ], - "indices": [ ], - "run_as": [ ] - }, - "kibana": [ - { - "base": [ - "read" - ], - "feature": {}, - "spaces": [ - "marketing" - ] - }, - { - "base": [], - "feature": { - "discover": [ - "all" - ], - "visualize": [ - "all" - ], - "dashboard": [ - "all" - ], - "dev_tools": [ - "read" - ], - "advancedSettings": [ - "read" - ], - "indexPatterns": [ - "read" - ], - "graph": [ - "all" - ], - "apm": [ - "read" - ], - "maps": [ - "read" - ], - "canvas": [ - "read" - ], - "infrastructure": [ - "all" - ], - "logs": [ - "all" - ], - "uptime": [ - "all" - ] - }, - "spaces": [ - "sales", - "default" - ] - } - ] -} --------------------------------------------------- diff --git a/docs/api/role-management/put-bulk.asciidoc b/docs/api/role-management/put-bulk.asciidoc deleted file mode 100644 index a11de47167e05..0000000000000 --- a/docs/api/role-management/put-bulk.asciidoc +++ /dev/null @@ -1,377 +0,0 @@ -[[role-management-api-put-bulk]] -=== Bulk create or update roles API -++++ -Bulk create or update roles API -++++ - -preview::["This functionality is in technical preview, and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features."] - -experimental[] Create new {kib} roles, or update the attributes of an existing roles. {kib} roles are stored in the -{es} native realm. - -[[role-management-api-put-bulk-request]] -==== Request - -`POST :/api/security/roles` - -[[role-management-api-put-bulk-prereqs]] -==== Prerequisite - -To use the bulk create or update roles API, you must have the `manage_security` cluster privilege. - -[role="child_attributes"] -[[role-management-api-bulk-response-body]] -==== Request body - -`roles`:: - (object) Object that specifies the roles to add as a role name to role map. -`` (required):: (string) The role name. -`description`:: - (Optional, string) Description for the role. - -`metadata`:: - (Optional, object) In the `metadata` object, keys that begin with `_` are reserved for system usage. - -`elasticsearch`:: - (Optional, object) {es} cluster and index privileges. Valid keys include - `cluster`, `indices`, `remote_indices`, `remote_cluster`, and `run_as`. For more information, see - {ref}/defining-roles.html[Defining roles]. - -`kibana`:: - (list) Objects that specify the <> for the role. -+ -.Properties of `kibana` -[%collapsible%open] -===== -`base` ::: - (Optional, list) A base privilege. When specified, the base must be `["all"]` or `["read"]`. - When the `base` privilege is specified, you are unable to use the `feature` section. - "all" grants read/write access to all {kib} features for the specified spaces. - "read" grants read-only access to all {kib} features for the specified spaces. - -`feature` ::: - (object) Contains privileges for specific features. - When the `feature` privileges are specified, you are unable to use the `base` section. - To retrieve a list of available features, use the <>. - -`spaces` ::: - (list) The spaces to apply the privileges to. - To grant access to all spaces, set to `["*"]`, or omit the value. -===== - -[[role-management-api-bulk-put-response-codes]] -==== Response code - -`200`:: - Indicates a successful call. - -==== Examples - -Grant access to various features in all spaces: - -[source,sh] --------------------------------------------------- -$ curl -X POST api/security/roles -{ - "roles": { - "my_kibana_role_1": { - "description": "my_kibana_role_1_description", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [], - "indices": [] - }, - "kibana": [ - { - "base": [], - "feature": { - "discover": ["all"], - "visualize": ["all"], - "dashboard": ["all"], - "dev_tools": ["read"], - "advancedSettings": ["read"], - "indexPatterns": ["read"], - "graph": ["all"], - "apm": ["read"], - "maps": ["read"], - "canvas": ["read"], - "infrastructure": ["all"], - "logs": ["all"], - "uptime": ["all"] - }, - "spaces": ["*"] - } - ] - }, - "my_kibana_role_2": { - "description": "my_kibana_role_2_description", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [], - "indices": [] - }, - "kibana": [ - { - "base": [], - "feature": { - "discover": ["all"], - "visualize": ["all"], - "dashboard": ["all"], - "dev_tools": ["read"], - "logs": ["all"], - "uptime": ["all"] - }, - "spaces": ["*"] - } - ] - } - } -} --------------------------------------------------- -// KIBANA - -Grant dashboard-only access to only the Marketing space for `my_kibana_role_1` and dashboard-only access to only Sales space for `my_kibana_role_2`: - -[source,sh] --------------------------------------------------- -$ curl -X POST api/security/roles -{ - "roles": { - "my_kibana_role_1": { - "description": "Grants dashboard-only access to only the Marketing space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [], - "indices": [] - }, - "kibana": [ - { - "base": [], - "feature": { - "dashboard": ["read"] - }, - "spaces": ["marketing"] - } - ] - }, - "my_kibana_role_2": { - "description": "Grants dashboard-only access to only the Sales space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [], - "indices": [] - }, - "kibana": [ - { - "base": [], - "feature": { - "dashboard": ["read"] - }, - "spaces": ["sales"] - } - ] - } - } -} - --------------------------------------------------- -// KIBANA - -Grant full access to all features in the Default space for `my_kibana_role_1` and `my_kibana_role_2`: - -[source,sh] --------------------------------------------------- -$ curl -X POST api/security/roles -{ - "roles": { - "my_kibana_role_1": { - "description": "Grants full access to all features in the Default space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [], - "indices": [] - }, - "kibana": [ - { - "base": ["all"], - "feature": {}, - "spaces": ["default"] - } - ] - }, - "my_kibana_role_2": { - "description": "Grants full access to all features in the Default space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [], - "indices": [] - }, - "kibana": [ - { - "base": ["all"], - "feature": {}, - "spaces": ["default"] - } - ] - } - } -} - --------------------------------------------------- -// KIBANA - -Grant different access to different spaces: - -[source,sh] --------------------------------------------------- -$ curl -X POST api/security/roles -{ - "roles": { - "my_kibana_role_1": { - "description": "Grants full access to discover and dashboard features in the default space. Grants read access in the marketing, and sales spaces.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [], - "indices": [] - }, - "kibana": [ - { - "base": [], - "feature": { - "discover": ["all"], - "dashboard": ["all"] - }, - "spaces": ["default"] - }, - { - "base": ["read"], - "spaces": ["marketing", "sales"] - } - ] - }, - "my_kibana_role_2": { - "description": "Grants full access to discover and dashboard features in the default space. Grants read access in the marketing space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [], - "indices": [] - }, - "kibana": [ - { - "base": [], - "feature": { - "discover": ["all"], - "dashboard": ["all"] - }, - "spaces": ["default"] - }, - { - "base": ["read"], - "spaces": ["marketing"] - } - ] - } - } -} - --------------------------------------------------- -// KIBANA - -Grant access to {kib} and {es}: - -[source,sh] --------------------------------------------------- -$ curl -X POST api/security/roles -{ - "roles": { - "my_kibana_role_1": { - "description": "Grants all cluster privileges and full access to index1 and index2. Grants full access to remote_index1 and remote_index2, and the monitor_enrich cluster privilege on remote_cluster1. Grants all Kibana privileges in the default space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": ["all"], - "indices": [ - { - "names": ["index1", "index2"], - "privileges": ["all"] - } - ], - "remote_indices": [ - { - "clusters": ["remote_cluster1"], - "names": ["remote_index1", "remote_index2"], - "privileges": ["all"] - } - ], - "remote_cluster": [ - { - "clusters": ["remote_cluster1"], - "privileges": ["monitor_enrich"] - } - ] - }, - "kibana": [ - { - "base": ["all"], - "feature": {}, - "spaces": ["default"] - } - ] - }, - "my_kibana_role_2": { - "description": "Grants all cluster privileges and full access to index1. Grants full access to remote_index1, and the monitor_enrich cluster privilege on remote_cluster1. Grants all Kibana privileges in the default space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": ["all"], - "indices": [ - { - "names": ["index1"], - "privileges": ["all"] - } - ], - "remote_indices": [ - { - "clusters": ["remote_cluster1"], - "names": ["remote_index1"], - "privileges": ["all"] - } - ], - "remote_cluster": [ - { - "clusters": ["remote_cluster1"], - "privileges": ["monitor_enrich"] - } - ] - }, - "kibana": [ - { - "base": ["all"], - "feature": {}, - "spaces": ["default"] - } - ] - } - } -} - --------------------------------------------------- -// KIBANA diff --git a/docs/api/role-management/put.asciidoc b/docs/api/role-management/put.asciidoc deleted file mode 100644 index d68f3928a4063..0000000000000 --- a/docs/api/role-management/put.asciidoc +++ /dev/null @@ -1,238 +0,0 @@ -[[role-management-api-put]] -=== Create or update role API -++++ -Create or update role -++++ - -experimental[] Create a new {kib} role, or update the attributes of an existing role. {kib} roles are stored in the -{es} native realm. - -[[role-management-api-put-request]] -==== Request - -`PUT :/api/security/role/my_kibana_role` - -[[role-management-api-put-prereqs]] -==== Prerequisite - -To use the create or update role API, you must have the `manage_security` cluster privilege. - -[role="child_attributes"] -[[role-management-api-response-body]] -==== Request body - -`description`:: - (Optional, string) Description for the role. - -`metadata`:: - (Optional, object) In the `metadata` object, keys that begin with `_` are reserved for system usage. - -`elasticsearch`:: - (Optional, object) {es} cluster and index privileges. Valid keys include - `cluster`, `indices`, `remote_indices`, `remote_cluster`, and `run_as`. For more information, see - {ref}/defining-roles.html[Defining roles]. - -`kibana`:: - (list) Objects that specify the <> for the role. -+ -.Properties of `kibana` -[%collapsible%open] -===== -`base` ::: - (Optional, list) A base privilege. When specified, the base must be `["all"]` or `["read"]`. - When the `base` privilege is specified, you are unable to use the `feature` section. - "all" grants read/write access to all {kib} features for the specified spaces. - "read" grants read-only access to all {kib} features for the specified spaces. - -`feature` ::: - (object) Contains privileges for specific features. - When the `feature` privileges are specified, you are unable to use the `base` section. - To retrieve a list of available features, use the <>. - -`spaces` ::: - (list) The spaces to apply the privileges to. - To grant access to all spaces, set to `["*"]`, or omit the value. -===== - -[[role-management-api-put-query-params]] -==== Query parameters - -`createOnly`:: - (Optional, boolean) When `true`, will prevent overwriting the role if it already exists. - -[[role-management-api-put-response-codes]] -==== Response code - -`204`:: - Indicates a successful call. - -`409`:: - When `createOnly` is true, indicates a conflict with an existing role. - -==== Examples - -Grant access to various features in all spaces: - -[source,sh] --------------------------------------------------- -$ curl -X PUT api/security/role/my_kibana_role -{ - "description": "my_kibana_role_description", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [ ], - "indices": [ ] - }, - "kibana": [ - { - "base": [ ], - "feature": { - "discover": [ "all" ], - "visualize": [ "all" ], - "dashboard": [ "all" ], - "dev_tools": [ "read" ], - "advancedSettings": [ "read" ], - "indexPatterns": [ "read" ], - "graph": [ "all" ], - "apm": [ "read" ], - "maps": [ "read" ], - "canvas": [ "read" ], - "infrastructure": [ "all" ], - "logs": [ "all" ], - "uptime": [ "all" ] - }, - "spaces": [ "*" ] - } - ] -} --------------------------------------------------- -// KIBANA - -Grant dashboard-only access to only the Marketing space: - -[source,sh] --------------------------------------------------- -$ curl -X PUT api/security/role/my_kibana_role -{ - "description": "Grants dashboard-only access to only the Marketing space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [ ], - "indices": [ ] - }, - "kibana": [ - { - "base": [ ], - "feature": { - "dashboard": [ "read" ] - }, - "spaces": [ "marketing" ] - } - ] -} --------------------------------------------------- -// KIBANA - -Grant full access to all features in the Default space: - -[source,sh] --------------------------------------------------- -$ curl -X PUT api/security/role/my_kibana_role -{ - "description": "Grants full access to all features in the Default space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [ ], - "indices": [ ] - }, - "kibana": [ - { - "base": [ "all" ], - "feature": { }, - "spaces": [ "default" ] - } - ] -} --------------------------------------------------- -// KIBANA - -Grant different access to different spaces: - -[source,sh] --------------------------------------------------- -$ curl -X PUT api/security/role/my_kibana_role -{ - "description": "Grants full access to discover and dashboard features in the default space. Grants read access in the marketing, and sales spaces.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [ ], - "indices": [ ] - }, - "kibana": [ - { - "base": [ ], - "feature": { - "discover": [ "all" ], - "dashboard": [ "all" ] - }, - "spaces": [ "default" ] - }, - { - "base": [ "read"] , - "spaces": [ "marketing", "sales" ] - } - ] -} --------------------------------------------------- -// KIBANA - -Grant access to {kib} and {es}: - -[source,sh] --------------------------------------------------- -$ curl -X PUT api/security/role/my_kibana_role -{ - "description": "Grants all cluster privileges and full access to index1 and index2. Grants full access to remote_index1 and remote_index2, and the monitor_enrich cluster privilege on remote_cluster1. Grants all Kibana privileges in the default space.", - "metadata": { - "version": 1 - }, - "elasticsearch": { - "cluster": [ "all" ], - "indices": [ - { - "names": [ "index1", "index2" ], - "privileges": [ "all" ] - } - ], - "remote_indices": [ - { - "clusters": [ "remote_cluster1" ], - "names": [ "remote_index1", "remote_index2" ], - "privileges": [ "all" ] - } - ], - "remote_cluster": [ - { - "clusters": [ "remote_cluster1" ], - "privileges": [ "monitor_enrich" ] - } - ] - }, - "kibana": [ - { - "base": [ "all" ], - "feature": { }, - "spaces": [ "default" ] - } - ] -} --------------------------------------------------- -// KIBANA diff --git a/docs/developer/architecture/security/rbac.asciidoc b/docs/developer/architecture/security/rbac.asciidoc index bf75ec1715de0..11896da243f2d 100644 --- a/docs/developer/architecture/security/rbac.asciidoc +++ b/docs/developer/architecture/security/rbac.asciidoc @@ -77,7 +77,7 @@ The application is created by concatenating the prefix of `kibana-` with the val } ---------------------------------- -Roles that grant <> should be managed using the <> or the *Management -> Security -> Roles* page, not directly using the {es} {ref}/security-api.html#security-role-apis[role management API]. This role can then be assigned to users using the {es} +Roles that grant <> should be managed using the {api-kibana}/group/endpoint-roles[role APIs] or the *Management -> Security -> Roles* page, not directly using the {es} {ref}/security-api.html#security-role-apis[role management API]. This role can then be assigned to users using the {es} {ref}/security-api.html#security-user-apis[user management APIs]. [[development-rbac-authorization]] diff --git a/docs/management/action-types.asciidoc b/docs/management/action-types.asciidoc index 361892e430afd..1357af980d278 100644 --- a/docs/management/action-types.asciidoc +++ b/docs/management/action-types.asciidoc @@ -28,9 +28,9 @@ a| <> | Send a request to {gemini}. -a| <> +a| <> -| Send a request to {inference}. +| Send a request to {infer}. a| <> diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index cda03f91dfc17..d6ae2aecaf276 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -330,9 +330,6 @@ the minimum and maximum values of a numeric field or a map of a geo field. [[discover:showMultiFields]]`discover:showMultiFields`:: Controls the display of multi-fields in the expanded document view. -[[discover:showLegacyFieldTopValues]]`discover:showLegacyFieldTopValues`:: -To calculate the top values for a field in the sidebar using 500 instead of 5,000 records per shard, turn on this option. - [[discover-sort-defaultorder]]`discover:sort:defaultOrder`:: The default sort direction for time-based data views. diff --git a/docs/management/connectors/action-types/inference.asciidoc b/docs/management/connectors/action-types/inference.asciidoc index 8c7f2840f9c5c..ea8a0be675e18 100644 --- a/docs/management/connectors/action-types/inference.asciidoc +++ b/docs/management/connectors/action-types/inference.asciidoc @@ -1,7 +1,7 @@ [[inference-action-type]] == {infer-cap} connector and action ++++ -{inference} +{infer-cap} ++++ :frontmatter-description: Add a connector that can send requests to {inference}. :frontmatter-tags-products: [kibana] @@ -9,7 +9,8 @@ :frontmatter-tags-user-goals: [configure] -The {infer} connector uses the {es} client to send requests to an {infer} service. The connector uses the <> to send the request. +The {infer} connector uses the {es} client to send requests to an {infer} service. +The connector uses the <> to send the request. [float] [[define-inference-ui]] @@ -19,7 +20,7 @@ You can create connectors in *{stack-manage-app} > {connectors-ui}*. For example [role="screenshot"] image::management/connectors/images/inference-connector.png[{inference} connector] -// NOTE: This is an autogenerated screenshot. Do not edit it directly. + [float] [[inference-connector-configuration]] @@ -44,7 +45,8 @@ while creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/inference-completion-params.png[{infer} params test] -// NOTE: This is an autogenerated screenshot. Do not edit it directly. + + [float] [[inference-connector-actions]] === {infer-cap} connector actions @@ -56,14 +58,17 @@ The {infer} actions have the following configuration properties. Properties depe ==== Completion The following example performs a completion task on the example question. + Input:: The text on which you want to perform the {infer} task. For example: + -[source,text] -- +[source,text] +------------------------------------------------------------ { input: 'What is Elastic?' } +------------------------------------------------------------ -- [float] @@ -71,18 +76,22 @@ The text on which you want to perform the {infer} task. For example: ==== Text embedding The following example performs a text embedding task. + Input:: The text on which you want to perform the {infer} task. For example: + -[source,text] -- +[source,text] +------------------------------------------------------------ { input: 'The sky above the port was the color of television tuned to a dead channel.', task_settings: { input_type: 'ingest' } } +------------------------------------------------------------ -- + Input type:: An optional string that overwrites the connector's default model. @@ -91,16 +100,20 @@ An optional string that overwrites the connector's default model. ==== Reranking The following example performs a reranking task on the example input. + Input:: The text on which you want to perform the {infer} task. Should be a string array. For example: + -[source,text] -- +[source,text] +------------------------------------------------------------ { input: ['luke', 'like', 'leia', 'chewy', 'r2d2', 'star', 'wars'], query: 'star wars main character' } +------------------------------------------------------------ -- + Query:: The search query text. @@ -109,14 +122,17 @@ The search query text. ==== Sparse embedding The following example performs a sparse embedding task on the example sentence. + Input:: The text on which you want to perform the {infer} task. For example: + -[source,text] -- +[source,text] +------------------------------------------------------------ { input: 'The sky above the port was the color of television tuned to a dead channel.' } +------------------------------------------------------------ -- [float] diff --git a/docs/management/watcher-ui/index.asciidoc b/docs/management/watcher-ui/index.asciidoc index 96ad0d3acc287..2e941cb86ca0b 100644 --- a/docs/management/watcher-ui/index.asciidoc +++ b/docs/management/watcher-ui/index.asciidoc @@ -39,9 +39,8 @@ and either of these Watcher roles: * `watcher_admin`. You can perform all Watcher actions, including create and edit watches. * `watcher_user`. You can view watches, but not create or edit them. -To manage roles, open the main menu, then click *Stack Management > Roles*, or use the -<>. Watches are shared between -all users with the same role. +To manage roles, open the main menu, then click *Stack Management > Roles*, or use the {api-kibana}/group/endpoint-roles[role APIs]. +Watches are shared between all users with the same role. NOTE: If you are creating a threshold watch, you must also have the `view_index_metadata` index privilege. See {ref}/index-mgmt.html[Index management] for detailed information. diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index 1fa61881eca92..84cf809c66667 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -1196,4 +1196,28 @@ Refer to {api-kibana}/group/endpoint-spaces[spaces APIs]. [role="exclude",id="spaces-api-update-objects-spaces"] == Update saved objects spaces API -Refer to {api-kibana}/group/endpoint-spaces[spaces APIs]. \ No newline at end of file +Refer to {api-kibana}/group/endpoint-spaces[spaces APIs]. +[role="exclude",id="role-management-api-delete] +== Delete role API + +Refer to {api-kibana}/group/endpoint-roles[role APIs]. + +[role="exclude",id="role-management-api-get"] +== Get all {kib} roles API + +Refer to {api-kibana}/group/endpoint-roles[role APIs]. + +[role="exclude",id="role-management-specific-api-get"] +== Get specific role API + +Refer to {api-kibana}/group/endpoint-roles[role APIs]. + +[role="exclude",id="role-management-api-put-bulk"] +== Bulk create or update roles API + +Refer to {api-kibana}/group/endpoint-roles[role APIs]. + +[role="exclude",id="role-management-api-put"] +== Create or update role API + +Refer to {api-kibana}/group/endpoint-roles[role APIs]. diff --git a/docs/settings/security-settings.asciidoc b/docs/settings/security-settings.asciidoc index 94c21486fe9cb..ad413ecbb7ce6 100644 --- a/docs/settings/security-settings.asciidoc +++ b/docs/settings/security-settings.asciidoc @@ -201,7 +201,7 @@ NOTE: Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d [[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. +recommended. You can also specify this setting for <>. By default, this value is 30 days for on-prem installations, and 24 hours for Elastic Cloud installations. + TIP: Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). diff --git a/docs/setup/configuring-reporting.asciidoc b/docs/setup/configuring-reporting.asciidoc index a1b2f7e9af583..4213cf38b6398 100644 --- a/docs/setup/configuring-reporting.asciidoc +++ b/docs/setup/configuring-reporting.asciidoc @@ -99,9 +99,10 @@ Granting the privilege to generate reports also grants the user the privilege to [float] [[reporting-roles-user-api]] ==== Grant access with the role API -With <> enabled in Reporting, you can also use the {ref}/security-api-put-role.html[role API] to grant access to the {report-features}, using *All* privileges, or sub-feature privileges. +With <> enabled in Reporting, you can also use the {api-kibana}/group/endpoint-roles[role APIs] to grant access to the {report-features}, using *All* privileges, or sub-feature privileges. + +NOTE: This API request needs to be run against the <>. -NOTE: This link:https://www.elastic.co/guide/en/kibana/current/role-management-api-put.html[API request] needs to be executed against the link:https://www.elastic.co/guide/en/kibana/current/api.html[Kibana API endpoint]. [source, sh] --------------------------------------------------------------- PUT :/api/security/role/custom_reporting_user diff --git a/docs/user/dashboard/create-dashboards.asciidoc b/docs/user/dashboard/create-dashboards.asciidoc index b07b4e88a684a..8b0d5e5f524fd 100644 --- a/docs/user/dashboard/create-dashboards.asciidoc +++ b/docs/user/dashboard/create-dashboards.asciidoc @@ -83,6 +83,7 @@ image::https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltf75cdb828 [[save-dashboards]] . **Save** the dashboard. You can then leave the **Edit** mode and *Switch to view mode*. +NOTE: Managed dashboards can't be edited directly, but you can <> them and edit these duplicates. [[reset-the-dashboard]] === Reset dashboard changes @@ -155,6 +156,24 @@ Copy panels from one dashboard to another dashboard. [role="screenshot"] image:https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt64206db263cf5514/66f49286833cffb09bebd18d/copy-to-dashboard-8.15.0.gif[Copy a panel to another dashboard, width 30%] +[[duplicate-dashboards]] +== Duplicate dashboards + +. Open the dashboard you want to duplicate. + +. In *View* mode, click *Duplicate* in the toolbar. + +. In the *Duplicate dashboard* window, enter a title and optional description and tags. + +. Click *Save*. + +You will be redirected to the duplicated dashboard. + +To duplicate a managed dashboard, follow the instructions above or click the *Managed* badge in the toolbar. Then click *Duplicate* in the dialogue that appears. + +[role="screenshot"] +image::images/managed-dashboard-popover-8.16.0.png[Managed badge dialog with Duplicate button, width=40%] + == Import dashboards You can import dashboards from the **Saved Objects** page under **Stack Management**. Refer to <>. diff --git a/docs/user/dashboard/dashboard.asciidoc b/docs/user/dashboard/dashboard.asciidoc index 5ca198c9831af..2bc6738516f15 100644 --- a/docs/user/dashboard/dashboard.asciidoc +++ b/docs/user/dashboard/dashboard.asciidoc @@ -17,7 +17,7 @@ There are several <> in {kib} that let you create // add link to sharing section At any time, you can <> you've created with your team, in {kib} or outside. -Some dashboards are created and managed by the system, and are identified as `managed` in your list of of dashboards. This generally happens when you set up an integration to add data. You can't edit managed dashboards directly, but you can duplicate them and edit these duplicates. +Some dashboards are created and managed by the system, and are identified as `managed` in your list of dashboards. This generally happens when you set up an integration to add data. You can't edit managed dashboards directly, but you can <> them and edit these duplicates. -- diff --git a/docs/user/dashboard/drilldowns.asciidoc b/docs/user/dashboard/drilldowns.asciidoc index 6b3a6d80ecdda..cb568d97e69ee 100644 --- a/docs/user/dashboard/drilldowns.asciidoc +++ b/docs/user/dashboard/drilldowns.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[drilldowns]] -=== Drilldowns +=== Add drilldowns Panels have built-in interactive capabilities that apply filters to the dashboard data. For example, when you drag a time range or click a pie slice, a filter for the time range or pie slice is applied. Drilldowns let you customize the interactive behavior while keeping the context of the interaction. diff --git a/docs/user/dashboard/images/managed-dashboard-popover-8.16.0.png b/docs/user/dashboard/images/managed-dashboard-popover-8.16.0.png new file mode 100644 index 0000000000000000000000000000000000000000..b1cd0562a42c70821db421af6b2989e653b17f9c GIT binary patch literal 34533 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%0A+redoSXCiH82cCJeuA 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 Ir18i92L_HOTmS$7 literal 0 HcmV?d00001 diff --git a/docs/user/introduction.asciidoc b/docs/user/introduction.asciidoc index f3281b9bed175..48c9dfd91c9c6 100644 --- a/docs/user/introduction.asciidoc +++ b/docs/user/introduction.asciidoc @@ -193,8 +193,8 @@ or even give users their very own private space. For example, power users might have privileges to create and edit visualizations and dashboards, while analysts or executives might have *Dashboard* and *Canvas* with read-only privileges. -{kib}’s role management interface allows you to describe these various access -levels, or you can automate role creation via our <>. +The {kib} role management interface allows you to describe these various access +levels, or you can automate role creation by using {api-kibana}/group/endpoint-roles[role APIs]. [role="screenshot"] image::spaces/images/spaces-roles.png[{kib privileges}] diff --git a/docs/user/security/api-keys/index.asciidoc b/docs/user/security/api-keys/index.asciidoc index 5b3dd206b5408..2f9a0d337e3b9 100644 --- a/docs/user/security/api-keys/index.asciidoc +++ b/docs/user/security/api-keys/index.asciidoc @@ -28,7 +28,7 @@ image:images/api-keys.png["API Keys UI"] * To create or update a *cross-cluster API key*, you must have the `manage_security` privilege and an Enterprise license. * To have a read-only view on the API keys, you must have access to the page and the `read_security` cluster privilege. -To manage roles, open the main menu, then click *Stack Management > Security > Roles*, or use the <>. +To manage roles, open the main menu, then click *Stack Management > Security > Roles*, or use the {api-kibana}/group/endpoint-roles[role APIs]. [float] [[create-api-key]] diff --git a/docs/user/security/authorization/kibana-privileges.asciidoc b/docs/user/security/authorization/kibana-privileges.asciidoc index 581210bb9d393..6c9a94a354fb3 100644 --- a/docs/user/security/authorization/kibana-privileges.asciidoc +++ b/docs/user/security/authorization/kibana-privileges.asciidoc @@ -1,22 +1,21 @@ -[role="xpack"] [[kibana-privileges]] -=== {kib} privileges += {kib} privileges {kib} privileges grant users access to features within {kib}. Roles have privileges to determine whether users have write or read access. -==== Base privileges +== Base privileges Assigning a base privilege grants access to all {kib} features, such as *Discover*, *Dashboard*, *Visualize Library*, and *Canvas*. [[kibana-privileges-all]] `all`:: Grants full read-write access. `read`:: Grants read-only access. -===== Assigning base privileges +=== Assigning base privileges From the role management screen: [role="screenshot"] image::security/images/assign-base-privilege.png[Assign base privilege] -From the <>: +Using the {api-kibana}/group/endpoint-roles[role APIs]: [source,js] -------------------------------------------------- PUT /api/security/role/my_kibana_role @@ -37,23 +36,23 @@ PUT /api/security/role/my_kibana_role [[kibana-feature-privileges]] -==== Feature privileges +== Feature privileges Assigning a feature privilege grants access to a specific feature. `all`:: Grants full read-write access. `read`:: Grants read-only access. -===== Sub-feature privileges +=== Sub-feature privileges Some features allow for finer access control than the `all` and `read` privileges. -This additional level of control is a https://www.elastic.co/subscriptions[subscription feature]. +This additional level of control is a {subscriptions}[subscription feature]. -===== Assigning feature privileges +=== Assigning feature privileges From the role management screen: [role="screenshot"] image::security/images/assign-subfeature-privilege.png[Assign feature privilege] -From the <>: +Using the {api-kibana}/group/endpoint-roles[role APIs]: [source,js] -------------------------------------------------- PUT /api/security/role/my_kibana_role diff --git a/docs/user/security/index.asciidoc b/docs/user/security/index.asciidoc index 906aee3d76d5a..44d7c41391c35 100644 --- a/docs/user/security/index.asciidoc +++ b/docs/user/security/index.asciidoc @@ -30,7 +30,7 @@ authentication and built-in users, see === Roles To manage roles, open the main menu, then click *Stack Management > Roles*, or use -the <>. For more information on configuring roles for {kib}, see <>. +the {api-kibana}/group/endpoint-roles[role APIs]. For more information on configuring roles for {kib}, see <>. For a more holistic overview of configuring roles for the entire stack, see {ref}/authorization.html[User authorization]. @@ -43,7 +43,7 @@ cause Kibana's authorization to behave unexpectedly. ============================================================================ include::authorization/index.asciidoc[] -include::authorization/kibana-privileges.asciidoc[] +include::authorization/kibana-privileges.asciidoc[leveloffset=+2] include::api-keys/index.asciidoc[] include::role-mappings/index.asciidoc[] include::fips-140-2.asciidoc[] diff --git a/examples/discover_customization_examples/public/plugin.tsx b/examples/discover_customization_examples/public/plugin.tsx index 7c35287b843ba..6dc6e8f48da58 100644 --- a/examples/discover_customization_examples/public/plugin.tsx +++ b/examples/discover_customization_examples/public/plugin.tsx @@ -7,17 +7,9 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { - EuiButton, - EuiContextMenu, - EuiFlexItem, - EuiPopover, - EuiWrappingPopover, - IconType, -} from '@elastic/eui'; +import { EuiButton, EuiContextMenu, EuiFlexItem, EuiPopover, IconType } from '@elastic/eui'; import { CoreSetup, CoreStart, Plugin, SimpleSavedObject } from '@kbn/core/public'; import type { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; -import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import type { CustomizationCallback, DiscoverSetup, @@ -102,112 +94,14 @@ export class DiscoverCustomizationExamplesPlugin implements Plugin { } start(core: CoreStart, plugins: DiscoverCustomizationExamplesStartPlugins) { - const { discover } = plugins; - - let isOptionsOpen = false; - const optionsContainer = document.createElement('div'); - const closeOptionsPopover = () => { - ReactDOM.unmountComponentAtNode(optionsContainer); - document.body.removeChild(optionsContainer); - isOptionsOpen = false; - }; - this.customizationCallback = ({ customizations, stateContainer }) => { customizations.set({ id: 'top_nav', defaultMenu: { newItem: { disabled: true }, openItem: { disabled: true }, - shareItem: { order: 200 }, alertsItem: { disabled: true }, inspectItem: { disabled: true }, - saveItem: { order: 400 }, - }, - getMenuItems: () => [ - { - data: { - id: 'options', - label: 'Options', - iconType: 'arrowDown', - iconSide: 'right', - testId: 'customOptionsButton', - run: (anchorElement: HTMLElement) => { - if (isOptionsOpen) { - closeOptionsPopover(); - return; - } - - isOptionsOpen = true; - document.body.appendChild(optionsContainer); - - const element = ( - - - alert('Create new clicked'), - }, - { - name: 'Make a copy', - icon: 'copy', - onClick: () => alert('Make a copy clicked'), - }, - { - name: 'Manage saved searches', - icon: 'gear', - onClick: () => alert('Manage saved searches clicked'), - }, - ], - }, - ]} - data-test-subj="customOptionsPopover" - /> - - - ); - - ReactDOM.render(element, optionsContainer); - }, - }, - order: 100, - }, - { - data: { - id: 'documentExplorer', - label: 'Document explorer', - iconType: 'discoverApp', - testId: 'documentExplorerButton', - run: () => { - discover.locator?.navigate({}); - }, - }, - order: 300, - }, - ], - getBadges: () => { - return [ - { - data: { - badgeText: 'Example badge', - color: 'warning', - }, - order: 10, - }, - ]; }, }); diff --git a/examples/discover_customization_examples/tsconfig.json b/examples/discover_customization_examples/tsconfig.json index 776153f943fac..30ff666575f1d 100644 --- a/examples/discover_customization_examples/tsconfig.json +++ b/examples/discover_customization_examples/tsconfig.json @@ -13,7 +13,6 @@ "@kbn/i18n-react", "@kbn/react-kibana-context-theme", "@kbn/data-plugin", - "@kbn/react-kibana-context-render", ], "exclude": ["target/**/*"] } diff --git a/examples/esql_ast_inspector/public/components/esql_inspector/helpers.tsx b/examples/esql_ast_inspector/public/components/esql_inspector/helpers.tsx index a117062f7efa9..19a0c54a722c6 100644 --- a/examples/esql_ast_inspector/public/components/esql_inspector/helpers.tsx +++ b/examples/esql_ast_inspector/public/components/esql_inspector/helpers.tsx @@ -82,6 +82,8 @@ export const highlight = (query: EsqlQuery): Annotation[] => { }); Walker.visitComments(query.ast, (comment) => { + if (!comment.location) return; + annotations.push([ comment.location.min, comment.location.max, diff --git a/oas_docs/bundle.json b/oas_docs/bundle.json index 6bca9024e77ea..fd2a7bbe22de0 100644 --- a/oas_docs/bundle.json +++ b/oas_docs/bundle.json @@ -344,10 +344,10 @@ }, "openapi": "3.0.0", "paths": { - "/api/actions": { - "get": { - "deprecated": true, - "operationId": "%2Fapi%2Factions#0", + "/api/actions/connector/{id}": { + "delete": { + "description": "WARNING: When you delete a connector, it cannot be recovered.", + "operationId": "delete-actions-connector-id", "parameters": [ { "description": "The version of the API to use", @@ -360,19 +360,39 @@ ], "type": "string" } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "description": "An identifier for the connector.", + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } } ], - "responses": {}, - "summary": "Get all connectors", + "responses": { + "204": { + "description": "Indicates a successful call." + } + }, + "summary": "Delete a connector", "tags": [ "connectors" ] - } - }, - "/api/actions/action": { - "post": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Faction#0", + }, + "get": { + "operationId": "get-actions-connector-id", "parameters": [ { "description": "The version of the API to use", @@ -387,50 +407,15 @@ } }, { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", + "description": "An identifier for the connector.", + "in": "path", + "name": "id", "required": true, "schema": { - "example": "true", "type": "string" } } ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "actionTypeId": { - "description": "The connector type identifier.", - "type": "string" - }, - "config": { - "additionalProperties": {}, - "default": {}, - "type": "object" - }, - "name": { - "description": "The display name for the connector.", - "type": "string" - }, - "secrets": { - "additionalProperties": {}, - "default": {}, - "type": "object" - } - }, - "required": [ - "name", - "actionTypeId" - ], - "type": "object" - } - } - } - }, "responses": { "200": { "content": { @@ -486,17 +471,13 @@ "description": "Indicates a successful call." } }, - "summary": "Create a connector", + "summary": "Get connector information", "tags": [ "connectors" ] - } - }, - "/api/actions/action/{id}": { - "delete": { - "deprecated": true, - "description": "WARNING: When you delete a connector, it cannot be recovered.", - "operationId": "%2Fapi%2Factions%2Faction%2F%7Bid%7D#0", + }, + "post": { + "operationId": "post-actions-connector-id", "parameters": [ { "description": "The version of the API to use", @@ -524,48 +505,46 @@ "description": "An identifier for the connector.", "in": "path", "name": "id", - "required": true, + "required": false, "schema": { "type": "string" } } ], - "responses": { - "204": { - "description": "Indicates a successful call." - } - }, - "summary": "Delete a connector", - "tags": [ - "connectors" - ] - }, - "get": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Faction%2F%7Bid%7D#1", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, - "schema": { - "type": "string" + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "config": { + "additionalProperties": {}, + "default": {}, + "type": "object" + }, + "connector_type_id": { + "description": "The type of connector.", + "type": "string" + }, + "name": { + "description": "The display name for the connector.", + "type": "string" + }, + "secrets": { + "additionalProperties": {}, + "default": {}, + "type": "object" + } + }, + "required": [ + "name", + "connector_type_id" + ], + "type": "object" + } } } - ], + }, "responses": { "200": { "content": { @@ -621,14 +600,13 @@ "description": "Indicates a successful call." } }, - "summary": "Get connector information", + "summary": "Create a connector", "tags": [ "connectors" ] }, "put": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Faction%2F%7Bid%7D#2", + "operationId": "put-actions-connector-id", "parameters": [ { "description": "The version of the API to use", @@ -674,6 +652,7 @@ "type": "object" }, "name": { + "description": "The display name for the connector.", "type": "string" }, "secrets": { @@ -751,10 +730,10 @@ ] } }, - "/api/actions/action/{id}/_execute": { + "/api/actions/connector/{id}/_execute": { "post": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Faction%2F%7Bid%7D%2F_execute#0", + "description": "You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems.", + "operationId": "post-actions-connector-id-execute", "parameters": [ { "description": "The version of the API to use", @@ -868,10 +847,10 @@ ] } }, - "/api/actions/connector/{id}": { - "delete": { - "description": "WARNING: When you delete a connector, it cannot be recovered.", - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#0", + "/api/actions/connector_types": { + "get": { + "description": "You do not need any Kibana feature privileges to run this API.", + "operationId": "get-actions-connector-types", "parameters": [ { "description": "The version of the API to use", @@ -886,37 +865,25 @@ } }, { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, + "description": "A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases).", + "in": "query", + "name": "feature_id", + "required": false, "schema": { "type": "string" } } ], - "responses": { - "204": { - "description": "Indicates a successful call." - } - }, - "summary": "Delete a connector", + "responses": {}, + "summary": "Get connector types", "tags": [ "connectors" ] - }, + } + }, + "/api/actions/connectors": { "get": { - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#1", + "operationId": "get-actions-connectors", "parameters": [ { "description": "The version of the API to use", @@ -929,534 +896,18 @@ ], "type": "string" } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, - "schema": { - "type": "string" - } } ], - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The connector type identifier.", - "type": "string" - }, - "id": { - "description": "The identifier for the connector.", - "type": "string" - }, - "is_deprecated": { - "description": "Indicates whether the connector is deprecated.", - "type": "boolean" - }, - "is_missing_secrets": { - "description": "Indicates whether the connector is missing secrets.", - "type": "boolean" - }, - "is_preconfigured": { - "description": "Indicates whether the connector is preconfigured. If true, the `config` and `is_missing_secrets` properties are omitted from the response. ", - "type": "boolean" - }, - "is_system_action": { - "description": "Indicates whether the connector is used for system actions.", - "type": "boolean" - }, - "name": { - "description": " The name of the rule.", - "type": "string" - } - }, - "required": [ - "id", - "name", - "connector_type_id", - "is_preconfigured", - "is_deprecated", - "is_system_action" - ], - "type": "object" - } - } - }, - "description": "Indicates a successful call." - } - }, - "summary": "Get connector information", + "responses": {}, + "summary": "Get all connectors", "tags": [ "connectors" ] - }, - "post": { - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%3F%7D#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": false, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "default": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The type of connector.", - "type": "string" - }, - "name": { - "description": "The display name for the connector.", - "type": "string" - }, - "secrets": { - "additionalProperties": {}, - "default": {}, - "type": "object" - } - }, - "required": [ - "name", - "connector_type_id" - ], - "type": "object" - } - } - } - }, - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The connector type identifier.", - "type": "string" - }, - "id": { - "description": "The identifier for the connector.", - "type": "string" - }, - "is_deprecated": { - "description": "Indicates whether the connector is deprecated.", - "type": "boolean" - }, - "is_missing_secrets": { - "description": "Indicates whether the connector is missing secrets.", - "type": "boolean" - }, - "is_preconfigured": { - "description": "Indicates whether the connector is preconfigured. If true, the `config` and `is_missing_secrets` properties are omitted from the response. ", - "type": "boolean" - }, - "is_system_action": { - "description": "Indicates whether the connector is used for system actions.", - "type": "boolean" - }, - "name": { - "description": " The name of the rule.", - "type": "string" - } - }, - "required": [ - "id", - "name", - "connector_type_id", - "is_preconfigured", - "is_deprecated", - "is_system_action" - ], - "type": "object" - } - } - }, - "description": "Indicates a successful call." - } - }, - "summary": "Create a connector", - "tags": [ - "connectors" - ] - }, - "put": { - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#2", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "default": {}, - "type": "object" - }, - "name": { - "description": "The display name for the connector.", - "type": "string" - }, - "secrets": { - "additionalProperties": {}, - "default": {}, - "type": "object" - } - }, - "required": [ - "name" - ], - "type": "object" - } - } - } - }, - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The connector type identifier.", - "type": "string" - }, - "id": { - "description": "The identifier for the connector.", - "type": "string" - }, - "is_deprecated": { - "description": "Indicates whether the connector is deprecated.", - "type": "boolean" - }, - "is_missing_secrets": { - "description": "Indicates whether the connector is missing secrets.", - "type": "boolean" - }, - "is_preconfigured": { - "description": "Indicates whether the connector is preconfigured. If true, the `config` and `is_missing_secrets` properties are omitted from the response. ", - "type": "boolean" - }, - "is_system_action": { - "description": "Indicates whether the connector is used for system actions.", - "type": "boolean" - }, - "name": { - "description": " The name of the rule.", - "type": "string" - } - }, - "required": [ - "id", - "name", - "connector_type_id", - "is_preconfigured", - "is_deprecated", - "is_system_action" - ], - "type": "object" - } - } - }, - "description": "Indicates a successful call." - } - }, - "summary": "Update a connector", - "tags": [ - "connectors" - ] - } - }, - "/api/actions/connector/{id}/_execute": { - "post": { - "description": "You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems.", - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%7D%2F_execute#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "params": { - "additionalProperties": {}, - "type": "object" - } - }, - "required": [ - "params" - ], - "type": "object" - } - } - } - }, - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The connector type identifier.", - "type": "string" - }, - "id": { - "description": "The identifier for the connector.", - "type": "string" - }, - "is_deprecated": { - "description": "Indicates whether the connector is deprecated.", - "type": "boolean" - }, - "is_missing_secrets": { - "description": "Indicates whether the connector is missing secrets.", - "type": "boolean" - }, - "is_preconfigured": { - "description": "Indicates whether the connector is preconfigured. If true, the `config` and `is_missing_secrets` properties are omitted from the response. ", - "type": "boolean" - }, - "is_system_action": { - "description": "Indicates whether the connector is used for system actions.", - "type": "boolean" - }, - "name": { - "description": " The name of the rule.", - "type": "string" - } - }, - "required": [ - "id", - "name", - "connector_type_id", - "is_preconfigured", - "is_deprecated", - "is_system_action" - ], - "type": "object" - } - } - }, - "description": "Indicates a successful call." - } - }, - "summary": "Run a connector", - "tags": [ - "connectors" - ] - } - }, - "/api/actions/connector_types": { - "get": { - "description": "You do not need any Kibana feature privileges to run this API.", - "operationId": "%2Fapi%2Factions%2Fconnector_types#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases).", - "in": "query", - "name": "feature_id", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": {}, - "summary": "Get connector types", - "tags": [ - "connectors" - ] - } - }, - "/api/actions/connectors": { - "get": { - "operationId": "%2Fapi%2Factions%2Fconnectors#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - } - ], - "responses": {}, - "summary": "Get all connectors", - "tags": [ - "connectors" - ] - } - }, - "/api/actions/list_action_types": { - "get": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Flist_action_types#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - } - ], - "responses": {}, - "summary": "Get connector types", - "tags": [ - "connectors" - ] - } - }, - "/api/alerting/rule/{id}": { - "delete": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D#2", + } + }, + "/api/alerting/rule/{id}": { + "delete": { + "operationId": "delete-alerting-rule-id", "parameters": [ { "description": "The version of the API to use", @@ -1510,7 +961,7 @@ ] }, "get": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D#0", + "operationId": "get-alerting-rule-id", "parameters": [ { "description": "The version of the API to use", @@ -2002,80 +1453,13 @@ "type": "number" }, "outcome": { - "additionalProperties": false, - "properties": { - "alerts_count": { - "additionalProperties": false, - "properties": { - "active": { - "description": "Number of active alerts during last run.", - "nullable": true, - "type": "number" - }, - "ignored": { - "description": "Number of ignored alerts during last run.", - "nullable": true, - "type": "number" - }, - "new": { - "description": "Number of new alerts during last run.", - "nullable": true, - "type": "number" - }, - "recovered": { - "description": "Number of recovered alerts during last run.", - "nullable": true, - "type": "number" - } - }, - "type": "object" - }, - "outcome": { - "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", - "enum": [ - "succeeded", - "warning", - "failed" - ], - "type": "string" - }, - "outcome_msg": { - "items": { - "description": "Outcome message generated during last rule run.", - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "outcome_order": { - "description": "Order of the outcome.", - "type": "number" - }, - "warning": { - "description": "Warning of last rule execution.", - "enum": [ - "read", - "decrypt", - "execute", - "unknown", - "license", - "timeout", - "disabled", - "validate", - "maxExecutableActions", - "maxAlerts", - "maxQueuedActions", - "ruleExecution" - ], - "nullable": true, - "type": "string" - } - }, - "required": [ - "outcome", - "alerts_count" + "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", + "enum": [ + "succeeded", + "warning", + "failed" ], - "type": "object" + "type": "string" }, "success": { "description": "Indicates whether the rule run was successful.", @@ -2242,6 +1626,7 @@ "description": "Indicates hours of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byminute": { @@ -2249,6 +1634,7 @@ "description": "Indicates minutes of the hour to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonth": { @@ -2256,6 +1642,7 @@ "description": "Indicates months of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonthday": { @@ -2263,6 +1650,7 @@ "description": "Indicates the days of the month to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysecond": { @@ -2270,6 +1658,7 @@ "description": "Indicates seconds of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysetpos": { @@ -2277,6 +1666,7 @@ "description": "A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.", "type": "number" }, + "nullable": true, "type": "array" }, "byweekday": { @@ -2291,6 +1681,7 @@ ], "description": "Indicates the days of the week to recur or else nth-day-of-month strings. For example, \"+2TU\" second Tuesday of month, \"-1FR\" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination." }, + "nullable": true, "type": "array" }, "byweekno": { @@ -2298,6 +1689,7 @@ "description": "Indicates number of the week hours to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byyearday": { @@ -2305,6 +1697,7 @@ "description": "Indicates the days of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "count": { @@ -2446,7 +1839,7 @@ ] }, "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%3F%7D#0", + "operationId": "post-alerting-rule-id", "parameters": [ { "description": "The version of the API to use", @@ -3240,80 +2633,13 @@ "type": "number" }, "outcome": { - "additionalProperties": false, - "properties": { - "alerts_count": { - "additionalProperties": false, - "properties": { - "active": { - "description": "Number of active alerts during last run.", - "nullable": true, - "type": "number" - }, - "ignored": { - "description": "Number of ignored alerts during last run.", - "nullable": true, - "type": "number" - }, - "new": { - "description": "Number of new alerts during last run.", - "nullable": true, - "type": "number" - }, - "recovered": { - "description": "Number of recovered alerts during last run.", - "nullable": true, - "type": "number" - } - }, - "type": "object" - }, - "outcome": { - "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", - "enum": [ - "succeeded", - "warning", - "failed" - ], - "type": "string" - }, - "outcome_msg": { - "items": { - "description": "Outcome message generated during last rule run.", - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "outcome_order": { - "description": "Order of the outcome.", - "type": "number" - }, - "warning": { - "description": "Warning of last rule execution.", - "enum": [ - "read", - "decrypt", - "execute", - "unknown", - "license", - "timeout", - "disabled", - "validate", - "maxExecutableActions", - "maxAlerts", - "maxQueuedActions", - "ruleExecution" - ], - "nullable": true, - "type": "string" - } - }, - "required": [ - "outcome", - "alerts_count" + "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", + "enum": [ + "succeeded", + "warning", + "failed" ], - "type": "object" + "type": "string" }, "success": { "description": "Indicates whether the rule run was successful.", @@ -3480,6 +2806,7 @@ "description": "Indicates hours of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byminute": { @@ -3487,6 +2814,7 @@ "description": "Indicates minutes of the hour to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonth": { @@ -3494,6 +2822,7 @@ "description": "Indicates months of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonthday": { @@ -3501,6 +2830,7 @@ "description": "Indicates the days of the month to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysecond": { @@ -3508,6 +2838,7 @@ "description": "Indicates seconds of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysetpos": { @@ -3515,6 +2846,7 @@ "description": "A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.", "type": "number" }, + "nullable": true, "type": "array" }, "byweekday": { @@ -3529,6 +2861,7 @@ ], "description": "Indicates the days of the week to recur or else nth-day-of-month strings. For example, \"+2TU\" second Tuesday of month, \"-1FR\" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination." }, + "nullable": true, "type": "array" }, "byweekno": { @@ -3536,6 +2869,7 @@ "description": "Indicates number of the week hours to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byyearday": { @@ -3543,6 +2877,7 @@ "description": "Indicates the days of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "count": { @@ -3684,7 +3019,7 @@ ] }, "put": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D#1", + "operationId": "put-alerting-rule-id", "parameters": [ { "description": "The version of the API to use", @@ -4461,80 +3796,13 @@ "type": "number" }, "outcome": { - "additionalProperties": false, - "properties": { - "alerts_count": { - "additionalProperties": false, - "properties": { - "active": { - "description": "Number of active alerts during last run.", - "nullable": true, - "type": "number" - }, - "ignored": { - "description": "Number of ignored alerts during last run.", - "nullable": true, - "type": "number" - }, - "new": { - "description": "Number of new alerts during last run.", - "nullable": true, - "type": "number" - }, - "recovered": { - "description": "Number of recovered alerts during last run.", - "nullable": true, - "type": "number" - } - }, - "type": "object" - }, - "outcome": { - "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", - "enum": [ - "succeeded", - "warning", - "failed" - ], - "type": "string" - }, - "outcome_msg": { - "items": { - "description": "Outcome message generated during last rule run.", - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "outcome_order": { - "description": "Order of the outcome.", - "type": "number" - }, - "warning": { - "description": "Warning of last rule execution.", - "enum": [ - "read", - "decrypt", - "execute", - "unknown", - "license", - "timeout", - "disabled", - "validate", - "maxExecutableActions", - "maxAlerts", - "maxQueuedActions", - "ruleExecution" - ], - "nullable": true, - "type": "string" - } - }, - "required": [ - "outcome", - "alerts_count" + "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", + "enum": [ + "succeeded", + "warning", + "failed" ], - "type": "object" + "type": "string" }, "success": { "description": "Indicates whether the rule run was successful.", @@ -4701,6 +3969,7 @@ "description": "Indicates hours of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byminute": { @@ -4708,6 +3977,7 @@ "description": "Indicates minutes of the hour to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonth": { @@ -4715,6 +3985,7 @@ "description": "Indicates months of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonthday": { @@ -4722,6 +3993,7 @@ "description": "Indicates the days of the month to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysecond": { @@ -4729,6 +4001,7 @@ "description": "Indicates seconds of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysetpos": { @@ -4736,6 +4009,7 @@ "description": "A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.", "type": "number" }, + "nullable": true, "type": "array" }, "byweekday": { @@ -4750,6 +4024,7 @@ ], "description": "Indicates the days of the week to recur or else nth-day-of-month strings. For example, \"+2TU\" second Tuesday of month, \"-1FR\" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination." }, + "nullable": true, "type": "array" }, "byweekno": { @@ -4757,6 +4032,7 @@ "description": "Indicates number of the week hours to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byyearday": { @@ -4764,6 +4040,7 @@ "description": "Indicates the days of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "count": { @@ -4910,7 +4187,7 @@ }, "/api/alerting/rule/{id}/_disable": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_disable#0", + "operationId": "post-alerting-rule-id-disable", "parameters": [ { "description": "The version of the API to use", @@ -4984,7 +4261,7 @@ }, "/api/alerting/rule/{id}/_enable": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_enable#0", + "operationId": "post-alerting-rule-id-enable", "parameters": [ { "description": "The version of the API to use", @@ -5040,7 +4317,7 @@ }, "/api/alerting/rule/{id}/_mute_all": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_mute_all#0", + "operationId": "post-alerting-rule-id-mute-all", "parameters": [ { "description": "The version of the API to use", @@ -5096,7 +4373,7 @@ }, "/api/alerting/rule/{id}/_unmute_all": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_unmute_all#0", + "operationId": "post-alerting-rule-id-unmute-all", "parameters": [ { "description": "The version of the API to use", @@ -5152,7 +4429,7 @@ }, "/api/alerting/rule/{id}/_update_api_key": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_update_api_key#0", + "operationId": "post-alerting-rule-id-update-api-key", "parameters": [ { "description": "The version of the API to use", @@ -5211,7 +4488,7 @@ }, "/api/alerting/rule/{rule_id}/alert/{alert_id}/_mute": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Brule_id%7D%2Falert%2F%7Balert_id%7D%2F_mute#0", + "operationId": "post-alerting-rule-rule-id-alert-alert-id-mute", "parameters": [ { "description": "The version of the API to use", @@ -5276,7 +4553,7 @@ }, "/api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Brule_id%7D%2Falert%2F%7Balert_id%7D%2F_unmute#0", + "operationId": "post-alerting-rule-rule-id-alert-alert-id-unmute", "parameters": [ { "description": "The version of the API to use", @@ -5341,7 +4618,7 @@ }, "/api/alerting/rules/_find": { "get": { - "operationId": "%2Fapi%2Falerting%2Frules%2F_find#0", + "operationId": "get-alerting-rules-find", "parameters": [ { "description": "The version of the API to use", @@ -5966,80 +5243,13 @@ "type": "number" }, "outcome": { - "additionalProperties": false, - "properties": { - "alerts_count": { - "additionalProperties": false, - "properties": { - "active": { - "description": "Number of active alerts during last run.", - "nullable": true, - "type": "number" - }, - "ignored": { - "description": "Number of ignored alerts during last run.", - "nullable": true, - "type": "number" - }, - "new": { - "description": "Number of new alerts during last run.", - "nullable": true, - "type": "number" - }, - "recovered": { - "description": "Number of recovered alerts during last run.", - "nullable": true, - "type": "number" - } - }, - "type": "object" - }, - "outcome": { - "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", - "enum": [ - "succeeded", - "warning", - "failed" - ], - "type": "string" - }, - "outcome_msg": { - "items": { - "description": "Outcome message generated during last rule run.", - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "outcome_order": { - "description": "Order of the outcome.", - "type": "number" - }, - "warning": { - "description": "Warning of last rule execution.", - "enum": [ - "read", - "decrypt", - "execute", - "unknown", - "license", - "timeout", - "disabled", - "validate", - "maxExecutableActions", - "maxAlerts", - "maxQueuedActions", - "ruleExecution" - ], - "nullable": true, - "type": "string" - } - }, - "required": [ - "outcome", - "alerts_count" + "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", + "enum": [ + "succeeded", + "warning", + "failed" ], - "type": "object" + "type": "string" }, "success": { "description": "Indicates whether the rule run was successful.", @@ -6206,6 +5416,7 @@ "description": "Indicates hours of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byminute": { @@ -6213,6 +5424,7 @@ "description": "Indicates minutes of the hour to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonth": { @@ -6220,6 +5432,7 @@ "description": "Indicates months of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonthday": { @@ -6227,6 +5440,7 @@ "description": "Indicates the days of the month to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysecond": { @@ -6234,6 +5448,7 @@ "description": "Indicates seconds of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysetpos": { @@ -6241,6 +5456,7 @@ "description": "A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.", "type": "number" }, + "nullable": true, "type": "array" }, "byweekday": { @@ -6255,6 +5471,7 @@ ], "description": "Indicates the days of the week to recur or else nth-day-of-month strings. For example, \"+2TU\" second Tuesday of month, \"-1FR\" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination." }, + "nullable": true, "type": "array" }, "byweekno": { @@ -6262,6 +5479,7 @@ "description": "Indicates number of the week hours to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byyearday": { @@ -6269,6 +5487,7 @@ "description": "Indicates the days of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "count": { @@ -6407,67 +5626,10 @@ ] } }, - "/api/fleet/agent-status": { - "get": { - "operationId": "%2Fapi%2Ffleet%2Fagent-status#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "in": "query", - "name": "policyId", - "required": false, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "policyIds", - "required": false, - "schema": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ] - } - }, - { - "in": "query", - "name": "kuery", - "required": false, - "schema": { - "deprecated": true, - "type": "string" - } - } - ], - "responses": {}, - "summary": "", - "tags": [] - } - }, "/api/fleet/agent_download_sources": { "get": { "description": "List agent binary download sources", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources#0", + "operationId": "get-fleet-agent-download-sources", "parameters": [ { "description": "The version of the API to use", @@ -6576,7 +5738,7 @@ }, "post": { "description": "Create agent binary download source", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources#1", + "operationId": "post-fleet-agent-download-sources", "parameters": [ { "description": "The version of the API to use", @@ -6717,7 +5879,7 @@ "/api/fleet/agent_download_sources/{sourceId}": { "delete": { "description": "Delete agent binary download source by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#2", + "operationId": "delete-fleet-agent-download-sources-sourceid", "parameters": [ { "description": "The version of the API to use", @@ -6802,7 +5964,7 @@ }, "get": { "description": "Get agent binary download source by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#0", + "operationId": "get-fleet-agent-download-sources-sourceid", "parameters": [ { "description": "The version of the API to use", @@ -6904,7 +6066,7 @@ }, "put": { "description": "Update agent binary download source by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#1", + "operationId": "put-fleet-agent-download-sources-sourceid", "parameters": [ { "description": "The version of the API to use", @@ -7053,7 +6215,7 @@ "/api/fleet/agent_policies": { "get": { "description": "List agent policies", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies#0", + "operationId": "get-fleet-agent-policies", "parameters": [ { "description": "The version of the API to use", @@ -7891,7 +7053,7 @@ }, "post": { "description": "Create an agent policy", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies#1", + "operationId": "post-fleet-agent-policies", "parameters": [ { "description": "The version of the API to use", @@ -8886,7 +8048,7 @@ "/api/fleet/agent_policies/_bulk_get": { "post": { "description": "Bulk get agent policies", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F_bulk_get#0", + "operationId": "post-fleet-agent-policies-bulk-get", "parameters": [ { "description": "The version of the API to use", @@ -9673,7 +8835,7 @@ "/api/fleet/agent_policies/delete": { "post": { "description": "Delete agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2Fdelete#0", + "operationId": "post-fleet-agent-policies-delete", "parameters": [ { "description": "The version of the API to use", @@ -9778,7 +8940,7 @@ "/api/fleet/agent_policies/outputs": { "post": { "description": "Get list of outputs associated with agent policies", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2Foutputs#0", + "operationId": "post-fleet-agent-policies-outputs", "parameters": [ { "description": "The version of the API to use", @@ -9963,7 +9125,7 @@ "/api/fleet/agent_policies/{agentPolicyId}": { "get": { "description": "Get an agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D#0", + "operationId": "get-fleet-agent-policies-agentpolicyid", "parameters": [ { "description": "The version of the API to use", @@ -10714,7 +9876,7 @@ }, "put": { "description": "Update an agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D#1", + "operationId": "put-fleet-agent-policies-agentpolicyid", "parameters": [ { "description": "The version of the API to use", @@ -11721,7 +10883,7 @@ "/api/fleet/agent_policies/{agentPolicyId}/copy": { "post": { "description": "Copy an agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Fcopy#0", + "operationId": "post-fleet-agent-policies-agentpolicyid-copy", "parameters": [ { "description": "The version of the API to use", @@ -12506,7 +11668,7 @@ "/api/fleet/agent_policies/{agentPolicyId}/download": { "get": { "description": "Download an agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Fdownload#0", + "operationId": "get-fleet-agent-policies-agentpolicyid-download", "parameters": [ { "description": "The version of the API to use", @@ -12623,7 +11785,7 @@ "/api/fleet/agent_policies/{agentPolicyId}/full": { "get": { "description": "Get a full agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Ffull#0", + "operationId": "get-fleet-agent-policies-agentpolicyid-full", "parameters": [ { "description": "The version of the API to use", @@ -13125,7 +12287,7 @@ "/api/fleet/agent_policies/{agentPolicyId}/outputs": { "get": { "description": "Get list of outputs associated with agent policy by policy id", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Foutputs#0", + "operationId": "get-fleet-agent-policies-agentpolicyid-outputs", "parameters": [ { "description": "The version of the API to use", @@ -13283,7 +12445,7 @@ "/api/fleet/agent_status": { "get": { "description": "Get agent status summary", - "operationId": "%2Fapi%2Ffleet%2Fagent_status#0", + "operationId": "get-fleet-agent-status", "parameters": [ { "description": "The version of the API to use", @@ -13328,7 +12490,6 @@ "name": "kuery", "required": false, "schema": { - "deprecated": true, "type": "string" } } @@ -13367,10 +12528,6 @@ "other": { "type": "number" }, - "total": { - "deprecated": true, - "type": "number" - }, "unenrolled": { "type": "number" }, @@ -13380,7 +12537,6 @@ }, "required": [ "events", - "total", "online", "error", "offline", @@ -13437,7 +12593,7 @@ "/api/fleet/agent_status/data": { "get": { "description": "Get incoming agent data", - "operationId": "%2Fapi%2Ffleet%2Fagent_status%2Fdata#0", + "operationId": "get-fleet-agent-status-data", "parameters": [ { "description": "The version of the API to use", @@ -13553,7 +12709,7 @@ "/api/fleet/agents": { "get": { "description": "List agents", - "operationId": "%2Fapi%2Ffleet%2Fagents#0", + "operationId": "get-fleet-agents", "parameters": [ { "description": "The version of the API to use", @@ -14044,394 +13200,6 @@ }, "type": "array" }, - "list": { - "deprecated": true, - "items": { - "additionalProperties": false, - "properties": { - "access_api_key": { - "type": "string" - }, - "access_api_key_id": { - "type": "string" - }, - "active": { - "type": "boolean" - }, - "agent": { - "additionalProperties": true, - "properties": { - "id": { - "type": "string" - }, - "version": { - "type": "string" - } - }, - "required": [ - "id", - "version" - ], - "type": "object" - }, - "components": { - "items": { - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - }, - "message": { - "type": "string" - }, - "status": { - "enum": [ - "STARTING", - "CONFIGURING", - "HEALTHY", - "DEGRADED", - "FAILED", - "STOPPING", - "STOPPED" - ], - "type": "string" - }, - "type": { - "type": "string" - }, - "units": { - "items": { - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - }, - "message": { - "type": "string" - }, - "payload": { - "additionalProperties": {}, - "type": "object" - }, - "status": { - "enum": [ - "STARTING", - "CONFIGURING", - "HEALTHY", - "DEGRADED", - "FAILED", - "STOPPING", - "STOPPED" - ], - "type": "string" - }, - "type": { - "enum": [ - "input", - "output" - ], - "type": "string" - } - }, - "required": [ - "id", - "type", - "status", - "message" - ], - "type": "object" - }, - "type": "array" - } - }, - "required": [ - "id", - "type", - "status", - "message" - ], - "type": "object" - }, - "type": "array" - }, - "default_api_key": { - "type": "string" - }, - "default_api_key_history": { - "items": { - "additionalProperties": false, - "deprecated": true, - "properties": { - "id": { - "type": "string" - }, - "retired_at": { - "type": "string" - } - }, - "required": [ - "id", - "retired_at" - ], - "type": "object" - }, - "type": "array" - }, - "default_api_key_id": { - "type": "string" - }, - "enrolled_at": { - "type": "string" - }, - "id": { - "type": "string" - }, - "last_checkin": { - "type": "string" - }, - "last_checkin_message": { - "type": "string" - }, - "last_checkin_status": { - "enum": [ - "error", - "online", - "degraded", - "updating", - "starting" - ], - "type": "string" - }, - "local_metadata": { - "additionalProperties": {}, - "type": "object" - }, - "metrics": { - "additionalProperties": false, - "properties": { - "cpu_avg": { - "type": "number" - }, - "memory_size_byte_avg": { - "type": "number" - } - }, - "type": "object" - }, - "namespaces": { - "items": { - "type": "string" - }, - "type": "array" - }, - "outputs": { - "additionalProperties": { - "additionalProperties": false, - "properties": { - "api_key_id": { - "type": "string" - }, - "to_retire_api_key_ids": { - "items": { - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - }, - "retired_at": { - "type": "string" - } - }, - "required": [ - "id", - "retired_at" - ], - "type": "object" - }, - "type": "array" - }, - "type": { - "type": "string" - } - }, - "required": [ - "api_key_id", - "type" - ], - "type": "object" - }, - "type": "object" - }, - "packages": { - "items": { - "type": "string" - }, - "type": "array" - }, - "policy_id": { - "type": "string" - }, - "policy_revision": { - "nullable": true, - "type": "number" - }, - "sort": { - "items": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - }, - { - "enum": [], - "nullable": true - } - ] - }, - "type": "array" - }, - "status": { - "enum": [ - "offline", - "error", - "online", - "inactive", - "enrolling", - "unenrolling", - "unenrolled", - "updating", - "degraded" - ], - "type": "string" - }, - "tags": { - "items": { - "type": "string" - }, - "type": "array" - }, - "type": { - "enum": [ - "PERMANENT", - "EPHEMERAL", - "TEMPORARY" - ], - "type": "string" - }, - "unenrolled_at": { - "type": "string" - }, - "unenrollment_started_at": { - "type": "string" - }, - "unhealthy_reason": { - "items": { - "enum": [ - "input", - "output", - "other" - ], - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "upgrade_details": { - "additionalProperties": false, - "properties": { - "action_id": { - "type": "string" - }, - "metadata": { - "additionalProperties": false, - "properties": { - "download_percent": { - "type": "number" - }, - "download_rate": { - "type": "number" - }, - "error_msg": { - "type": "string" - }, - "failed_state": { - "enum": [ - "UPG_REQUESTED", - "UPG_SCHEDULED", - "UPG_DOWNLOADING", - "UPG_EXTRACTING", - "UPG_REPLACING", - "UPG_RESTARTING", - "UPG_FAILED", - "UPG_WATCHING", - "UPG_ROLLBACK" - ], - "type": "string" - }, - "retry_error_msg": { - "type": "string" - }, - "retry_until": { - "type": "string" - }, - "scheduled_at": { - "type": "string" - } - }, - "type": "object" - }, - "state": { - "enum": [ - "UPG_REQUESTED", - "UPG_SCHEDULED", - "UPG_DOWNLOADING", - "UPG_EXTRACTING", - "UPG_REPLACING", - "UPG_RESTARTING", - "UPG_FAILED", - "UPG_WATCHING", - "UPG_ROLLBACK" - ], - "type": "string" - }, - "target_version": { - "type": "string" - } - }, - "required": [ - "target_version", - "action_id", - "state" - ], - "type": "object" - }, - "upgrade_started_at": { - "nullable": true, - "type": "string" - }, - "upgraded_at": { - "nullable": true, - "type": "string" - }, - "user_provided_metadata": { - "additionalProperties": {}, - "type": "object" - } - }, - "required": [ - "id", - "packages", - "type", - "active", - "enrolled_at", - "local_metadata" - ], - "type": "object" - }, - "type": "array" - }, "page": { "type": "number" }, @@ -14492,7 +13260,7 @@ }, "post": { "description": "List agents by action ids", - "operationId": "%2Fapi%2Ffleet%2Fagents#1", + "operationId": "post-fleet-agents", "parameters": [ { "description": "The version of the API to use", @@ -14595,7 +13363,7 @@ "/api/fleet/agents/action_status": { "get": { "description": "Get agent action status", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Faction_status#0", + "operationId": "get-fleet-agents-action-status", "parameters": [ { "description": "The version of the API to use", @@ -14831,7 +13599,7 @@ "/api/fleet/agents/actions/{actionId}/cancel": { "post": { "description": "Cancel agent action", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Factions%2F%7BactionId%7D%2Fcancel#0", + "operationId": "post-fleet-agents-actions-actionid-cancel", "parameters": [ { "description": "The version of the API to use", @@ -14973,7 +13741,7 @@ "/api/fleet/agents/available_versions": { "get": { "description": "Get available agent versions", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Favailable_versions#0", + "operationId": "get-fleet-agents-available-versions", "parameters": [ { "description": "The version of the API to use", @@ -15045,7 +13813,7 @@ "/api/fleet/agents/bulk_reassign": { "post": { "description": "Bulk reassign agents", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_reassign#0", + "operationId": "post-fleet-agents-bulk-reassign", "parameters": [ { "description": "The version of the API to use", @@ -15163,7 +13931,7 @@ "/api/fleet/agents/bulk_request_diagnostics": { "post": { "description": "Bulk request diagnostics from agents", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_request_diagnostics#0", + "operationId": "post-fleet-agents-bulk-request-diagnostics", "parameters": [ { "description": "The version of the API to use", @@ -15282,7 +14050,7 @@ "/api/fleet/agents/bulk_unenroll": { "post": { "description": "Bulk unenroll agents", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_unenroll#0", + "operationId": "post-fleet-agents-bulk-unenroll", "parameters": [ { "description": "The version of the API to use", @@ -15406,7 +14174,7 @@ "/api/fleet/agents/bulk_update_agent_tags": { "post": { "description": "Bulk update agent tags", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_update_agent_tags#0", + "operationId": "post-fleet-agents-bulk-update-agent-tags", "parameters": [ { "description": "The version of the API to use", @@ -15532,7 +14300,7 @@ "/api/fleet/agents/bulk_upgrade": { "post": { "description": "Bulk upgrade agents", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_upgrade#0", + "operationId": "post-fleet-agents-bulk-upgrade", "parameters": [ { "description": "The version of the API to use", @@ -15666,7 +14434,7 @@ "/api/fleet/agents/files/{fileId}": { "delete": { "description": "Delete file uploaded by agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Ffiles%2F%7BfileId%7D#0", + "operationId": "delete-fleet-agents-files-fileid", "parameters": [ { "description": "The version of the API to use", @@ -15757,7 +14525,7 @@ "/api/fleet/agents/files/{fileId}/{fileName}": { "get": { "description": "Get file uploaded by agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Ffiles%2F%7BfileId%7D%2F%7BfileName%7D#0", + "operationId": "get-fleet-agents-files-fileid-filename", "parameters": [ { "description": "The version of the API to use", @@ -15833,7 +14601,7 @@ "/api/fleet/agents/setup": { "get": { "description": "Get agent setup info", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fsetup#0", + "operationId": "get-fleet-agents-setup", "parameters": [ { "description": "The version of the API to use", @@ -15934,7 +14702,7 @@ }, "post": { "description": "Initiate agent setup", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fsetup#1", + "operationId": "post-fleet-agents-setup", "parameters": [ { "description": "The version of the API to use", @@ -16034,7 +14802,7 @@ "/api/fleet/agents/tags": { "get": { "description": "List agent tags", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Ftags#0", + "operationId": "get-fleet-agents-tags", "parameters": [ { "description": "The version of the API to use", @@ -16123,7 +14891,7 @@ "/api/fleet/agents/{agentId}": { "delete": { "description": "Delete agent by ID", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#2", + "operationId": "delete-fleet-agents-agentid", "parameters": [ { "description": "The version of the API to use", @@ -16211,7 +14979,7 @@ }, "get": { "description": "Get agent by ID", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#0", + "operationId": "get-fleet-agents-agentid", "parameters": [ { "description": "The version of the API to use", @@ -16676,7 +15444,7 @@ }, "put": { "description": "Update agent by ID", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#1", + "operationId": "put-fleet-agents-agentid", "parameters": [ { "description": "The version of the API to use", @@ -17166,7 +15934,7 @@ "/api/fleet/agents/{agentId}/actions": { "post": { "description": "Create agent action", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Factions#0", + "operationId": "post-fleet-agents-agentid-actions", "parameters": [ { "description": "The version of the API to use", @@ -17383,7 +16151,7 @@ "/api/fleet/agents/{agentId}/reassign": { "post": { "description": "Reassign agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Freassign#1", + "operationId": "post-fleet-agents-agentid-reassign", "parameters": [ { "description": "The version of the API to use", @@ -17476,68 +16244,12 @@ "tags": [ "Elastic Agent actions" ] - }, - "put": { - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Freassign#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "in": "path", - "name": "agentId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "policy_id": { - "type": "string" - } - }, - "required": [ - "policy_id" - ], - "type": "object" - } - } - } - }, - "responses": {}, - "summary": "", - "tags": [] } }, "/api/fleet/agents/{agentId}/request_diagnostics": { "post": { "description": "Request agent diagnostics", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Frequest_diagnostics#0", + "operationId": "post-fleet-agents-agentid-request-diagnostics", "parameters": [ { "description": "The version of the API to use", @@ -17646,7 +16358,7 @@ "/api/fleet/agents/{agentId}/unenroll": { "post": { "description": "Unenroll agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Funenroll#0", + "operationId": "post-fleet-agents-agentid-unenroll", "parameters": [ { "description": "The version of the API to use", @@ -17708,7 +16420,7 @@ "/api/fleet/agents/{agentId}/upgrade": { "post": { "description": "Upgrade agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Fupgrade#0", + "operationId": "post-fleet-agents-agentid-upgrade", "parameters": [ { "description": "The version of the API to use", @@ -17815,7 +16527,7 @@ "/api/fleet/agents/{agentId}/uploads": { "get": { "description": "List agent uploads", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Fuploads#0", + "operationId": "get-fleet-agents-agentid-uploads", "parameters": [ { "description": "The version of the API to use", @@ -17935,7 +16647,7 @@ "/api/fleet/check-permissions": { "get": { "description": "Check permissions", - "operationId": "%2Fapi%2Ffleet%2Fcheck-permissions#0", + "operationId": "get-fleet-check-permissions", "parameters": [ { "description": "The version of the API to use", @@ -18020,7 +16732,7 @@ "/api/fleet/data_streams": { "get": { "description": "List data streams", - "operationId": "%2Fapi%2Ffleet%2Fdata_streams#0", + "operationId": "get-fleet-data-streams", "parameters": [ { "description": "The version of the API to use", @@ -18177,7 +16889,7 @@ }, "/api/fleet/enrollment-api-keys": { "get": { - "operationId": "%2Fapi%2Ffleet%2Fenrollment-api-keys#0", + "operationId": "get-fleet-enrollment-api-keys-2", "parameters": [ { "description": "The version of the API to use", @@ -18223,7 +16935,7 @@ "tags": [] }, "post": { - "operationId": "%2Fapi%2Ffleet%2Fenrollment-api-keys#1", + "operationId": "post-fleet-enrollment-api-keys-2", "parameters": [ { "description": "The version of the API to use", @@ -18279,7 +16991,7 @@ }, "/api/fleet/enrollment-api-keys/{keyId}": { "delete": { - "operationId": "%2Fapi%2Ffleet%2Fenrollment-api-keys%2F%7BkeyId%7D#1", + "operationId": "delete-fleet-enrollment-api-keys-keyid-2", "parameters": [ { "description": "The version of the API to use", @@ -18317,7 +17029,7 @@ "tags": [] }, "get": { - "operationId": "%2Fapi%2Ffleet%2Fenrollment-api-keys%2F%7BkeyId%7D#0", + "operationId": "get-fleet-enrollment-api-keys-keyid-2", "parameters": [ { "description": "The version of the API to use", @@ -18348,7 +17060,7 @@ "/api/fleet/enrollment_api_keys": { "get": { "description": "List enrollment API keys", - "operationId": "%2Fapi%2Ffleet%2Fenrollment_api_keys#0", + "operationId": "get-fleet-enrollment-api-keys", "parameters": [ { "description": "The version of the API to use", @@ -18536,7 +17248,7 @@ }, "post": { "description": "Create enrollment API key", - "operationId": "%2Fapi%2Ffleet%2Fenrollment_api_keys#1", + "operationId": "post-fleet-enrollment-api-keys", "parameters": [ { "description": "The version of the API to use", @@ -18682,7 +17394,7 @@ "/api/fleet/enrollment_api_keys/{keyId}": { "delete": { "description": "Revoke enrollment API key by ID by marking it as inactive", - "operationId": "%2Fapi%2Ffleet%2Fenrollment_api_keys%2F%7BkeyId%7D#1", + "operationId": "delete-fleet-enrollment-api-keys-keyid", "parameters": [ { "description": "The version of the API to use", @@ -18770,7 +17482,7 @@ }, "get": { "description": "Get enrollment API key by ID", - "operationId": "%2Fapi%2Ffleet%2Fenrollment_api_keys%2F%7BkeyId%7D#0", + "operationId": "get-fleet-enrollment-api-keys-keyid", "parameters": [ { "description": "The version of the API to use", @@ -18883,7 +17595,7 @@ "/api/fleet/epm/bulk_assets": { "post": { "description": "Bulk get assets", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fbulk_assets#0", + "operationId": "post-fleet-epm-bulk-assets", "parameters": [ { "description": "The version of the API to use", @@ -19034,7 +17746,7 @@ "/api/fleet/epm/categories": { "get": { "description": "List package categories", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fcategories#0", + "operationId": "get-fleet-epm-categories", "parameters": [ { "description": "The version of the API to use", @@ -19183,7 +17895,7 @@ "/api/fleet/epm/custom_integrations": { "post": { "description": "Create custom integration", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fcustom_integrations#0", + "operationId": "post-fleet-epm-custom-integrations", "parameters": [ { "description": "The version of the API to use", @@ -19465,7 +18177,7 @@ "/api/fleet/epm/data_streams": { "get": { "description": "List data streams", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fdata_streams#0", + "operationId": "get-fleet-epm-data-streams", "parameters": [ { "description": "The version of the API to use", @@ -19591,7 +18303,7 @@ "/api/fleet/epm/packages": { "get": { "description": "List packages", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages#0", + "operationId": "get-fleet-epm-packages", "parameters": [ { "description": "The version of the API to use", @@ -20660,7 +19372,7 @@ }, "post": { "description": "Install package by upload", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages#1", + "operationId": "post-fleet-epm-packages", "parameters": [ { "description": "The version of the API to use", @@ -20922,7 +19634,7 @@ "/api/fleet/epm/packages/_bulk": { "post": { "description": "Bulk install packages", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F_bulk#0", + "operationId": "post-fleet-epm-packages-bulk", "parameters": [ { "description": "The version of the API to use", @@ -21346,7 +20058,7 @@ "/api/fleet/epm/packages/installed": { "get": { "description": "Get installed packages", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2Finstalled#0", + "operationId": "get-fleet-epm-packages-installed", "parameters": [ { "description": "The version of the API to use", @@ -21587,7 +20299,7 @@ "/api/fleet/epm/packages/limited": { "get": { "description": "Get limited package list", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2Flimited#0", + "operationId": "get-fleet-epm-packages-limited", "parameters": [ { "description": "The version of the API to use", @@ -21666,7 +20378,7 @@ "/api/fleet/epm/packages/{pkgName}/stats": { "get": { "description": "Get package stats", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2Fstats#0", + "operationId": "get-fleet-epm-packages-pkgname-stats", "parameters": [ { "description": "The version of the API to use", @@ -21752,7 +20464,7 @@ "/api/fleet/epm/packages/{pkgName}/{pkgVersion}": { "delete": { "description": "Delete package", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#3", + "operationId": "delete-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { "description": "The version of the API to use", @@ -22014,7 +20726,7 @@ }, "get": { "description": "Get package", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#0", + "operationId": "get-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { "description": "The version of the API to use", @@ -23278,7 +21990,7 @@ }, "post": { "description": "Install package from registry", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#2", + "operationId": "post-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { "description": "The version of the API to use", @@ -23573,7 +22285,7 @@ }, "put": { "description": "Update package settings", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#1", + "operationId": "put-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { "description": "The version of the API to use", @@ -24822,7 +23534,7 @@ "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/transforms/authorize": { "post": { "description": "Authorize transforms", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2Ftransforms%2Fauthorize#0", + "operationId": "post-fleet-epm-packages-pkgname-pkgversion-transforms-authorize", "parameters": [ { "description": "The version of the API to use", @@ -24966,7 +23678,7 @@ "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/{filePath*}": { "get": { "description": "Get package file", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2F%7BfilePath*%7D#0", + "operationId": "get-fleet-epm-packages-pkgname-pkgversion-filepath", "parameters": [ { "description": "The version of the API to use", @@ -25047,7 +23759,7 @@ }, "/api/fleet/epm/packages/{pkgkey}": { "delete": { - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#3", + "operationId": "delete-fleet-epm-packages-pkgkey", "parameters": [ { "description": "The version of the API to use", @@ -25104,7 +23816,7 @@ "tags": [] }, "get": { - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#0", + "operationId": "get-fleet-epm-packages-pkgkey", "parameters": [ { "description": "The version of the API to use", @@ -25165,7 +23877,7 @@ "tags": [] }, "post": { - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#2", + "operationId": "post-fleet-epm-packages-pkgkey", "parameters": [ { "description": "The version of the API to use", @@ -25248,7 +23960,7 @@ "tags": [] }, "put": { - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#1", + "operationId": "put-fleet-epm-packages-pkgkey", "parameters": [ { "description": "The version of the API to use", @@ -25307,7 +24019,7 @@ "/api/fleet/epm/templates/{pkgName}/{pkgVersion}/inputs": { "get": { "description": "Get inputs template", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Ftemplates%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2Finputs#0", + "operationId": "get-fleet-epm-templates-pkgname-pkgversion-inputs", "parameters": [ { "description": "The version of the API to use", @@ -25476,7 +24188,7 @@ "/api/fleet/epm/verification_key_id": { "get": { "description": "Get a package signature verification key ID", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fverification_key_id#0", + "operationId": "get-fleet-epm-verification-key-id", "parameters": [ { "description": "The version of the API to use", @@ -25546,7 +24258,7 @@ "/api/fleet/fleet_server_hosts": { "get": { "description": "List Fleet Server hosts", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts#0", + "operationId": "get-fleet-fleet-server-hosts", "parameters": [ { "description": "The version of the API to use", @@ -25664,7 +24376,7 @@ }, "post": { "description": "Create Fleet Server host", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts#1", + "operationId": "post-fleet-fleet-server-hosts", "parameters": [ { "description": "The version of the API to use", @@ -25823,7 +24535,7 @@ "/api/fleet/fleet_server_hosts/{itemId}": { "delete": { "description": "Delete Fleet Server host by ID", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#1", + "operationId": "delete-fleet-fleet-server-hosts-itemid", "parameters": [ { "description": "The version of the API to use", @@ -25908,7 +24620,7 @@ }, "get": { "description": "Get Fleet Server host by ID", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#0", + "operationId": "get-fleet-fleet-server-hosts-itemid", "parameters": [ { "description": "The version of the API to use", @@ -26019,7 +24731,7 @@ }, "put": { "description": "Update Fleet Server host by ID", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#2", + "operationId": "put-fleet-fleet-server-hosts-itemid", "parameters": [ { "description": "The version of the API to use", @@ -26177,7 +24889,7 @@ "/api/fleet/health_check": { "post": { "description": "Check Fleet Server health", - "operationId": "%2Fapi%2Ffleet%2Fhealth_check#0", + "operationId": "post-fleet-health-check", "parameters": [ { "description": "The version of the API to use", @@ -26313,7 +25025,7 @@ "/api/fleet/kubernetes": { "get": { "description": "Get full K8s agent manifest", - "operationId": "%2Fapi%2Ffleet%2Fkubernetes#0", + "operationId": "get-fleet-kubernetes", "parameters": [ { "description": "The version of the API to use", @@ -26405,7 +25117,7 @@ }, "/api/fleet/kubernetes/download": { "get": { - "operationId": "%2Fapi%2Ffleet%2Fkubernetes%2Fdownload#0", + "operationId": "get-fleet-kubernetes-download", "parameters": [ { "description": "The version of the API to use", @@ -26514,7 +25226,7 @@ "/api/fleet/logstash_api_keys": { "post": { "description": "Generate Logstash API key", - "operationId": "%2Fapi%2Ffleet%2Flogstash_api_keys#0", + "operationId": "post-fleet-logstash-api-keys", "parameters": [ { "description": "The version of the API to use", @@ -26593,7 +25305,7 @@ "/api/fleet/message_signing_service/rotate_key_pair": { "post": { "description": "Rotate fleet message signing key pair", - "operationId": "%2Fapi%2Ffleet%2Fmessage_signing_service%2Frotate_key_pair#0", + "operationId": "post-fleet-message-signing-service-rotate-key-pair", "parameters": [ { "description": "The version of the API to use", @@ -26706,7 +25418,7 @@ "/api/fleet/outputs": { "get": { "description": "List outputs", - "operationId": "%2Fapi%2Ffleet%2Foutputs#0", + "operationId": "get-fleet-outputs", "parameters": [ { "description": "The version of the API to use", @@ -27836,7 +26548,7 @@ }, "post": { "description": "Create output", - "operationId": "%2Fapi%2Ffleet%2Foutputs#1", + "operationId": "post-fleet-outputs", "parameters": [ { "description": "The version of the API to use", @@ -30020,7 +28732,7 @@ "/api/fleet/outputs/{outputId}": { "delete": { "description": "Delete output by ID", - "operationId": "%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#2", + "operationId": "delete-fleet-outputs-outputid", "parameters": [ { "description": "The version of the API to use", @@ -30130,7 +28842,7 @@ }, "get": { "description": "Get output by ID", - "operationId": "%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#0", + "operationId": "get-fleet-outputs-outputid", "parameters": [ { "description": "The version of the API to use", @@ -31253,7 +29965,7 @@ }, "put": { "description": "Update output by ID", - "operationId": "%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#1", + "operationId": "put-fleet-outputs-outputid", "parameters": [ { "description": "The version of the API to use", @@ -33421,7 +32133,7 @@ "/api/fleet/outputs/{outputId}/health": { "get": { "description": "Get latest output health", - "operationId": "%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D%2Fhealth#0", + "operationId": "get-fleet-outputs-outputid-health", "parameters": [ { "description": "The version of the API to use", @@ -33509,7 +32221,7 @@ "/api/fleet/package_policies": { "get": { "description": "List package policies", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies#0", + "operationId": "get-fleet-package-policies", "parameters": [ { "description": "The version of the API to use", @@ -34224,7 +32936,7 @@ }, "post": { "description": "Create package policy", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies#1", + "operationId": "post-fleet-package-policies", "parameters": [ { "description": "The version of the API to use", @@ -35498,7 +34210,7 @@ "/api/fleet/package_policies/_bulk_get": { "post": { "description": "Bulk get package policies", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2F_bulk_get#0", + "operationId": "post-fleet-package-policies-bulk-get", "parameters": [ { "description": "The version of the API to use", @@ -36196,7 +34908,7 @@ "/api/fleet/package_policies/delete": { "post": { "description": "Bulk delete package policies", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2Fdelete#0", + "operationId": "post-fleet-package-policies-delete", "parameters": [ { "description": "The version of the API to use", @@ -36400,7 +35112,7 @@ "/api/fleet/package_policies/upgrade": { "post": { "description": "Upgrade package policy to a newer package version", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2Fupgrade#0", + "operationId": "post-fleet-package-policies-upgrade", "parameters": [ { "description": "The version of the API to use", @@ -36525,7 +35237,7 @@ "/api/fleet/package_policies/upgrade/dryrun": { "post": { "description": "Dry run package policy upgrade", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2Fupgrade%2Fdryrun#0", + "operationId": "post-fleet-package-policies-upgrade-dryrun", "parameters": [ { "description": "The version of the API to use", @@ -37711,7 +36423,7 @@ "/api/fleet/package_policies/{packagePolicyId}": { "delete": { "description": "Delete package policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#2", + "operationId": "delete-fleet-package-policies-packagepolicyid", "parameters": [ { "description": "The version of the API to use", @@ -37804,7 +36516,7 @@ }, "get": { "description": "Get package policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#0", + "operationId": "get-fleet-package-policies-packagepolicyid", "parameters": [ { "description": "The version of the API to use", @@ -38470,7 +37182,7 @@ }, "put": { "description": "Update package policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#1", + "operationId": "put-fleet-package-policies-packagepolicyid", "parameters": [ { "description": "The version of the API to use", @@ -39744,7 +38456,7 @@ "/api/fleet/proxies": { "get": { "description": "List proxies", - "operationId": "%2Fapi%2Ffleet%2Fproxies#0", + "operationId": "get-fleet-proxies", "parameters": [ { "description": "The version of the API to use", @@ -39876,7 +38588,7 @@ }, "post": { "description": "Create proxy", - "operationId": "%2Fapi%2Ffleet%2Fproxies#1", + "operationId": "post-fleet-proxies", "parameters": [ { "description": "The version of the API to use", @@ -40060,410 +38772,10 @@ ] } }, - "/api/fleet/proxies/{itemId}": { - "delete": { - "description": "Delete proxy by ID", - "operationId": "%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#2", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "in": "path", - "name": "itemId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - } - } - } - }, - "400": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "description": "Generic Error", - "properties": { - "error": { - "type": "string" - }, - "message": { - "type": "string" - }, - "statusCode": { - "type": "number" - } - }, - "required": [ - "message" - ], - "type": "object" - } - } - } - } - }, - "summary": "", - "tags": [ - "Fleet proxies" - ] - }, - "get": { - "description": "Get proxy by ID", - "operationId": "%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#1", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "in": "path", - "name": "itemId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "item": { - "additionalProperties": false, - "properties": { - "certificate": { - "nullable": true, - "type": "string" - }, - "certificate_authorities": { - "nullable": true, - "type": "string" - }, - "certificate_key": { - "nullable": true, - "type": "string" - }, - "id": { - "type": "string" - }, - "is_preconfigured": { - "default": false, - "type": "boolean" - }, - "name": { - "type": "string" - }, - "proxy_headers": { - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - }, - { - "type": "number" - } - ] - }, - "nullable": true, - "type": "object" - }, - "url": { - "type": "string" - } - }, - "required": [ - "id", - "url", - "name" - ], - "type": "object" - } - }, - "required": [ - "item" - ], - "type": "object" - } - } - } - }, - "400": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "description": "Generic Error", - "properties": { - "error": { - "type": "string" - }, - "message": { - "type": "string" - }, - "statusCode": { - "type": "number" - } - }, - "required": [ - "message" - ], - "type": "object" - } - } - } - } - }, - "summary": "", - "tags": [ - "Fleet proxies" - ] - }, - "put": { - "description": "Update proxy by ID", - "operationId": "%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "in": "path", - "name": "itemId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "certificate": { - "nullable": true, - "type": "string" - }, - "certificate_authorities": { - "nullable": true, - "type": "string" - }, - "certificate_key": { - "nullable": true, - "type": "string" - }, - "name": { - "type": "string" - }, - "proxy_headers": { - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - }, - { - "type": "number" - } - ] - }, - "nullable": true, - "type": "object" - }, - "url": { - "type": "string" - } - }, - "required": [ - "proxy_headers", - "certificate_authorities", - "certificate", - "certificate_key" - ], - "type": "object" - } - } - } - }, - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "item": { - "additionalProperties": false, - "properties": { - "certificate": { - "nullable": true, - "type": "string" - }, - "certificate_authorities": { - "nullable": true, - "type": "string" - }, - "certificate_key": { - "nullable": true, - "type": "string" - }, - "id": { - "type": "string" - }, - "is_preconfigured": { - "default": false, - "type": "boolean" - }, - "name": { - "type": "string" - }, - "proxy_headers": { - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - }, - { - "type": "number" - } - ] - }, - "nullable": true, - "type": "object" - }, - "url": { - "type": "string" - } - }, - "required": [ - "id", - "url", - "name" - ], - "type": "object" - } - }, - "required": [ - "item" - ], - "type": "object" - } - } - } - }, - "400": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "description": "Generic Error", - "properties": { - "error": { - "type": "string" - }, - "message": { - "type": "string" - }, - "statusCode": { - "type": "number" - } - }, - "required": [ - "message" - ], - "type": "object" - } - } - } - } - }, - "summary": "", - "tags": [ - "Fleet proxies" - ] - } - }, - "/api/fleet/service-tokens": { - "post": { - "description": "Create a service token", - "operationId": "%2Fapi%2Ffleet%2Fservice-tokens#0", + "/api/fleet/proxies/{itemId}": { + "delete": { + "description": "Delete proxy by ID", + "operationId": "delete-fleet-proxies-itemid", "parameters": [ { "description": "The version of the API to use", @@ -40486,17 +38798,384 @@ "example": "true", "type": "string" } + }, + { + "in": "path", + "name": "itemId", + "required": true, + "schema": { + "type": "string" + } } ], - "responses": {}, + "responses": { + "200": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + } + } + }, + "400": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "description": "Generic Error", + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "statusCode": { + "type": "number" + } + }, + "required": [ + "message" + ], + "type": "object" + } + } + } + } + }, "summary": "", - "tags": [] + "tags": [ + "Fleet proxies" + ] + }, + "get": { + "description": "Get proxy by ID", + "operationId": "get-fleet-proxies-itemid", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "in": "path", + "name": "itemId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "item": { + "additionalProperties": false, + "properties": { + "certificate": { + "nullable": true, + "type": "string" + }, + "certificate_authorities": { + "nullable": true, + "type": "string" + }, + "certificate_key": { + "nullable": true, + "type": "string" + }, + "id": { + "type": "string" + }, + "is_preconfigured": { + "default": false, + "type": "boolean" + }, + "name": { + "type": "string" + }, + "proxy_headers": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + } + ] + }, + "nullable": true, + "type": "object" + }, + "url": { + "type": "string" + } + }, + "required": [ + "id", + "url", + "name" + ], + "type": "object" + } + }, + "required": [ + "item" + ], + "type": "object" + } + } + } + }, + "400": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "description": "Generic Error", + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "statusCode": { + "type": "number" + } + }, + "required": [ + "message" + ], + "type": "object" + } + } + } + } + }, + "summary": "", + "tags": [ + "Fleet proxies" + ] + }, + "put": { + "description": "Update proxy by ID", + "operationId": "put-fleet-proxies-itemid", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "in": "path", + "name": "itemId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "certificate": { + "nullable": true, + "type": "string" + }, + "certificate_authorities": { + "nullable": true, + "type": "string" + }, + "certificate_key": { + "nullable": true, + "type": "string" + }, + "name": { + "type": "string" + }, + "proxy_headers": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + } + ] + }, + "nullable": true, + "type": "object" + }, + "url": { + "type": "string" + } + }, + "required": [ + "proxy_headers", + "certificate_authorities", + "certificate", + "certificate_key" + ], + "type": "object" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "item": { + "additionalProperties": false, + "properties": { + "certificate": { + "nullable": true, + "type": "string" + }, + "certificate_authorities": { + "nullable": true, + "type": "string" + }, + "certificate_key": { + "nullable": true, + "type": "string" + }, + "id": { + "type": "string" + }, + "is_preconfigured": { + "default": false, + "type": "boolean" + }, + "name": { + "type": "string" + }, + "proxy_headers": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + } + ] + }, + "nullable": true, + "type": "object" + }, + "url": { + "type": "string" + } + }, + "required": [ + "id", + "url", + "name" + ], + "type": "object" + } + }, + "required": [ + "item" + ], + "type": "object" + } + } + } + }, + "400": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "description": "Generic Error", + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "statusCode": { + "type": "number" + } + }, + "required": [ + "message" + ], + "type": "object" + } + } + } + } + }, + "summary": "", + "tags": [ + "Fleet proxies" + ] } }, "/api/fleet/service_tokens": { "post": { "description": "Create a service token", - "operationId": "%2Fapi%2Ffleet%2Fservice_tokens#0", + "operationId": "post-fleet-service-tokens", "parameters": [ { "description": "The version of the API to use", @@ -40596,7 +39275,7 @@ "/api/fleet/settings": { "get": { "description": "Get settings", - "operationId": "%2Fapi%2Ffleet%2Fsettings#0", + "operationId": "get-fleet-settings", "parameters": [ { "description": "The version of the API to use", @@ -40747,7 +39426,7 @@ }, "put": { "description": "Update settings", - "operationId": "%2Fapi%2Ffleet%2Fsettings#1", + "operationId": "put-fleet-settings", "parameters": [ { "description": "The version of the API to use", @@ -40964,7 +39643,7 @@ "/api/fleet/setup": { "post": { "description": "Initiate Fleet setup", - "operationId": "%2Fapi%2Ffleet%2Fsetup#0", + "operationId": "post-fleet-setup", "parameters": [ { "description": "The version of the API to use", @@ -41083,7 +39762,7 @@ "/api/fleet/uninstall_tokens": { "get": { "description": "List metadata for latest uninstall tokens per agent policy", - "operationId": "%2Fapi%2Ffleet%2Funinstall_tokens#0", + "operationId": "get-fleet-uninstall-tokens", "parameters": [ { "description": "The version of the API to use", @@ -41232,7 +39911,7 @@ "/api/fleet/uninstall_tokens/{uninstallTokenId}": { "get": { "description": "Get one decrypted uninstall token by its ID", - "operationId": "%2Fapi%2Ffleet%2Funinstall_tokens%2F%7BuninstallTokenId%7D#0", + "operationId": "get-fleet-uninstall-tokens-uninstalltokenid", "parameters": [ { "description": "The version of the API to use", @@ -41339,7 +40018,7 @@ }, "/api/security/role": { "get": { - "operationId": "%2Fapi%2Fsecurity%2Frole#0", + "operationId": "get-security-role", "parameters": [ { "description": "The version of the API to use", @@ -41354,6 +40033,7 @@ } }, { + "description": "If `true` and the response contains any privileges that are associated with deprecated features, they are omitted in favor of details about the appropriate replacement feature privileges.", "in": "query", "name": "replaceDeprecatedPrivileges", "required": false, @@ -41362,7 +40042,11 @@ } } ], - "responses": {}, + "responses": { + "200": { + "description": "Indicates a successful call." + } + }, "summary": "Get all roles", "tags": [ "roles" @@ -41371,7 +40055,7 @@ }, "/api/security/role/{name}": { "delete": { - "operationId": "%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#1", + "operationId": "delete-security-role-name", "parameters": [ { "description": "The version of the API to use", @@ -41405,14 +40089,18 @@ } } ], - "responses": {}, + "responses": { + "204": { + "description": "Indicates a successful call." + } + }, "summary": "Delete a role", "tags": [ "roles" ] }, "get": { - "operationId": "%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#0", + "operationId": "get-security-role-name", "parameters": [ { "description": "The version of the API to use", @@ -41427,6 +40115,7 @@ } }, { + "description": "The role name.", "in": "path", "name": "name", "required": true, @@ -41436,6 +40125,7 @@ } }, { + "description": "If `true` and the response contains any privileges that are associated with deprecated features, they are omitted in favor of details about the appropriate replacement feature privileges.", "in": "query", "name": "replaceDeprecatedPrivileges", "required": false, @@ -41444,14 +40134,19 @@ } } ], - "responses": {}, + "responses": { + "200": { + "description": "Indicates a successful call." + } + }, "summary": "Get a role", "tags": [ "roles" ] }, "put": { - "operationId": "%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#2", + "description": "Create a new Kibana role or update the attributes of an existing role. Kibana roles are stored in the Elasticsearch native realm.", + "operationId": "put-security-role-name", "parameters": [ { "description": "The version of the API to use", @@ -41476,6 +40171,7 @@ } }, { + "description": "The role name.", "in": "path", "name": "name", "required": true, @@ -41486,6 +40182,7 @@ } }, { + "description": "When true, a role is not overwritten if it already exists.", "in": "query", "name": "createOnly", "required": false, @@ -41502,6 +40199,7 @@ "additionalProperties": false, "properties": { "description": { + "description": "A description for the role.", "maxLength": 2048, "type": "string" }, @@ -41510,6 +40208,7 @@ "properties": { "cluster": { "items": { + "description": "Cluster privileges that define the cluster level actions that users can perform.", "type": "string" }, "type": "array" @@ -41519,11 +40218,13 @@ "additionalProperties": false, "properties": { "allow_restricted_indices": { + "description": "Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field covers the restricted indices too.", "type": "boolean" }, "field_security": { "additionalProperties": { "items": { + "description": "The document fields that the role members have read access to.", "type": "string" }, "type": "array" @@ -41532,6 +40233,7 @@ }, "names": { "items": { + "description": "The data streams, indices, and aliases to which the permissions in this entry apply. It supports wildcards (*).", "type": "string" }, "minItems": 1, @@ -41539,12 +40241,14 @@ }, "privileges": { "items": { + "description": "The index level privileges that the role members have for the data streams and indices.", "type": "string" }, "minItems": 1, "type": "array" }, "query": { + "description": "A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members.", "type": "string" } }, @@ -41562,6 +40266,7 @@ "properties": { "clusters": { "items": { + "description": "A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.", "type": "string" }, "minItems": 1, @@ -41569,6 +40274,7 @@ }, "privileges": { "items": { + "description": "The cluster level privileges for the remote cluster. The allowed values are a subset of the cluster privileges.", "type": "string" }, "minItems": 1, @@ -41588,10 +40294,12 @@ "additionalProperties": false, "properties": { "allow_restricted_indices": { + "description": "Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field will cover the restricted indices too.", "type": "boolean" }, "clusters": { "items": { + "description": "A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.", "type": "string" }, "minItems": 1, @@ -41600,6 +40308,7 @@ "field_security": { "additionalProperties": { "items": { + "description": "The document fields that the role members have read access to.", "type": "string" }, "type": "array" @@ -41608,6 +40317,7 @@ }, "names": { "items": { + "description": "A list of remote aliases, data streams, or indices to which the permissions apply. It supports wildcards (*).", "type": "string" }, "minItems": 1, @@ -41615,12 +40325,14 @@ }, "privileges": { "items": { + "description": "The index level privileges that role members have for the specified indices.", "type": "string" }, "minItems": 1, "type": "array" }, "query": { + "description": "A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members. ", "type": "string" } }, @@ -41635,6 +40347,7 @@ }, "run_as": { "items": { + "description": "A user name that the role member can impersonate.", "type": "string" }, "type": "array" @@ -41669,12 +40382,14 @@ "oneOf": [ { "items": { + "description": "A base privilege that grants applies to all spaces.", "type": "string" }, "type": "array" }, { "items": { + "description": "A base privilege that applies to specific spaces.", "type": "string" }, "type": "array" @@ -41684,6 +40399,7 @@ "feature": { "additionalProperties": { "items": { + "description": "The privileges that the role member has for the feature.", "type": "string" }, "type": "array" @@ -41705,6 +40421,7 @@ }, { "items": { + "description": "A space that the privilege applies to.", "type": "string" }, "type": "array" @@ -41735,7 +40452,11 @@ } } }, - "responses": {}, + "responses": { + "204": { + "description": "Indicates a successful call." + } + }, "summary": "Create or update a role", "tags": [ "roles" @@ -41744,7 +40465,7 @@ }, "/api/security/roles": { "post": { - "operationId": "%2Fapi%2Fsecurity%2Froles#0", + "operationId": "post-security-roles", "parameters": [ { "description": "The version of the API to use", @@ -41780,6 +40501,7 @@ "additionalProperties": false, "properties": { "description": { + "description": "A description for the role.", "maxLength": 2048, "type": "string" }, @@ -41788,6 +40510,7 @@ "properties": { "cluster": { "items": { + "description": "Cluster privileges that define the cluster level actions that users can perform.", "type": "string" }, "type": "array" @@ -41797,11 +40520,13 @@ "additionalProperties": false, "properties": { "allow_restricted_indices": { + "description": "Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field covers the restricted indices too.", "type": "boolean" }, "field_security": { "additionalProperties": { "items": { + "description": "The document fields that the role members have read access to.", "type": "string" }, "type": "array" @@ -41810,6 +40535,7 @@ }, "names": { "items": { + "description": "The data streams, indices, and aliases to which the permissions in this entry apply. It supports wildcards (*).", "type": "string" }, "minItems": 1, @@ -41817,12 +40543,14 @@ }, "privileges": { "items": { + "description": "The index level privileges that the role members have for the data streams and indices.", "type": "string" }, "minItems": 1, "type": "array" }, "query": { + "description": "A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members.", "type": "string" } }, @@ -41840,6 +40568,7 @@ "properties": { "clusters": { "items": { + "description": "A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.", "type": "string" }, "minItems": 1, @@ -41847,6 +40576,7 @@ }, "privileges": { "items": { + "description": "The cluster level privileges for the remote cluster. The allowed values are a subset of the cluster privileges.", "type": "string" }, "minItems": 1, @@ -41866,10 +40596,12 @@ "additionalProperties": false, "properties": { "allow_restricted_indices": { + "description": "Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field will cover the restricted indices too.", "type": "boolean" }, "clusters": { "items": { + "description": "A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.", "type": "string" }, "minItems": 1, @@ -41878,6 +40610,7 @@ "field_security": { "additionalProperties": { "items": { + "description": "The document fields that the role members have read access to.", "type": "string" }, "type": "array" @@ -41886,6 +40619,7 @@ }, "names": { "items": { + "description": "A list of remote aliases, data streams, or indices to which the permissions apply. It supports wildcards (*).", "type": "string" }, "minItems": 1, @@ -41893,12 +40627,14 @@ }, "privileges": { "items": { + "description": "The index level privileges that role members have for the specified indices.", "type": "string" }, "minItems": 1, "type": "array" }, "query": { + "description": "A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members. ", "type": "string" } }, @@ -41913,6 +40649,7 @@ }, "run_as": { "items": { + "description": "A user name that the role member can impersonate.", "type": "string" }, "type": "array" @@ -41947,12 +40684,14 @@ "oneOf": [ { "items": { + "description": "A base privilege that grants applies to all spaces.", "type": "string" }, "type": "array" }, { "items": { + "description": "A base privilege that applies to specific spaces.", "type": "string" }, "type": "array" @@ -41962,6 +40701,7 @@ "feature": { "additionalProperties": { "items": { + "description": "The privileges that the role member has for the feature.", "type": "string" }, "type": "array" @@ -41983,6 +40723,7 @@ }, { "items": { + "description": "A space that the privilege applies to.", "type": "string" }, "type": "array" @@ -42021,7 +40762,11 @@ } } }, - "responses": {}, + "responses": { + "200": { + "description": "Indicates a successful call." + } + }, "summary": "Create or update roles", "tags": [ "roles" @@ -42031,7 +40776,7 @@ "/api/spaces/_copy_saved_objects": { "post": { "description": "It also allows you to automatically copy related objects, so when you copy a dashboard, this can automatically copy over the associated visualizations, data views, and saved searches, as required. You can request to overwrite any objects that already exist in the target space if they share an identifier or you can use the resolve copy saved objects conflicts API to do this on a per-object basis.", - "operationId": "%2Fapi%2Fspaces%2F_copy_saved_objects#0", + "operationId": "post-spaces-copy-saved-objects", "parameters": [ { "description": "The version of the API to use", @@ -42129,7 +40874,7 @@ }, "/api/spaces/_disable_legacy_url_aliases": { "post": { - "operationId": "%2Fapi%2Fspaces%2F_disable_legacy_url_aliases#0", + "operationId": "post-spaces-disable-legacy-url-aliases", "parameters": [ { "description": "The version of the API to use", @@ -42205,7 +40950,7 @@ "/api/spaces/_get_shareable_references": { "post": { "description": "Collect references and space contexts for saved objects.", - "operationId": "%2Fapi%2Fspaces%2F_get_shareable_references#0", + "operationId": "post-spaces-get-shareable-references", "parameters": [ { "description": "The version of the API to use", @@ -42274,7 +41019,7 @@ "/api/spaces/_resolve_copy_saved_objects_errors": { "post": { "description": "Overwrite saved objects that are returned as errors from the copy saved objects to space API.", - "operationId": "%2Fapi%2Fspaces%2F_resolve_copy_saved_objects_errors#0", + "operationId": "post-spaces-resolve-copy-saved-objects-errors", "parameters": [ { "description": "The version of the API to use", @@ -42395,7 +41140,7 @@ "/api/spaces/_update_objects_spaces": { "post": { "description": "Update one or more saved objects to add or remove them from some spaces.", - "operationId": "%2Fapi%2Fspaces%2F_update_objects_spaces#0", + "operationId": "post-spaces-update-objects-spaces", "parameters": [ { "description": "The version of the API to use", @@ -42481,7 +41226,7 @@ }, "/api/spaces/space": { "get": { - "operationId": "%2Fapi%2Fspaces%2Fspace#0", + "operationId": "get-spaces-space", "parameters": [ { "description": "The version of the API to use", @@ -42561,7 +41306,7 @@ ] }, "post": { - "operationId": "%2Fapi%2Fspaces%2Fspace#1", + "operationId": "post-spaces-space", "parameters": [ { "description": "The version of the API to use", @@ -42662,7 +41407,7 @@ "/api/spaces/space/{id}": { "delete": { "description": "When you delete a space, all saved objects that belong to the space are automatically deleted, which is permanent and cannot be undone.", - "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2", + "operationId": "delete-spaces-space-id", "parameters": [ { "description": "The version of the API to use", @@ -42710,7 +41455,7 @@ ] }, "get": { - "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0", + "operationId": "get-spaces-space-id", "parameters": [ { "description": "The version of the API to use", @@ -42745,7 +41490,7 @@ ] }, "put": { - "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1", + "operationId": "put-spaces-space-id", "parameters": [ { "description": "The version of the API to use", @@ -42854,7 +41599,7 @@ }, "/api/status": { "get": { - "operationId": "%2Fapi%2Fstatus#0", + "operationId": "get-status", "parameters": [ { "description": "The version of the API to use", diff --git a/oas_docs/bundle.serverless.json b/oas_docs/bundle.serverless.json index a8d428d5404fc..f171dadde991a 100644 --- a/oas_docs/bundle.serverless.json +++ b/oas_docs/bundle.serverless.json @@ -344,10 +344,10 @@ }, "openapi": "3.0.0", "paths": { - "/api/actions": { - "get": { - "deprecated": true, - "operationId": "%2Fapi%2Factions#0", + "/api/actions/connector/{id}": { + "delete": { + "description": "WARNING: When you delete a connector, it cannot be recovered.", + "operationId": "delete-actions-connector-id", "parameters": [ { "description": "The version of the API to use", @@ -360,19 +360,39 @@ ], "type": "string" } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "description": "An identifier for the connector.", + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } } ], - "responses": {}, - "summary": "Get all connectors", + "responses": { + "204": { + "description": "Indicates a successful call." + } + }, + "summary": "Delete a connector", "tags": [ "connectors" ] - } - }, - "/api/actions/action": { - "post": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Faction#0", + }, + "get": { + "operationId": "get-actions-connector-id", "parameters": [ { "description": "The version of the API to use", @@ -387,50 +407,15 @@ } }, { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", + "description": "An identifier for the connector.", + "in": "path", + "name": "id", "required": true, "schema": { - "example": "true", "type": "string" } } ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "actionTypeId": { - "description": "The connector type identifier.", - "type": "string" - }, - "config": { - "additionalProperties": {}, - "default": {}, - "type": "object" - }, - "name": { - "description": "The display name for the connector.", - "type": "string" - }, - "secrets": { - "additionalProperties": {}, - "default": {}, - "type": "object" - } - }, - "required": [ - "name", - "actionTypeId" - ], - "type": "object" - } - } - } - }, "responses": { "200": { "content": { @@ -486,17 +471,13 @@ "description": "Indicates a successful call." } }, - "summary": "Create a connector", + "summary": "Get connector information", "tags": [ "connectors" ] - } - }, - "/api/actions/action/{id}": { - "delete": { - "deprecated": true, - "description": "WARNING: When you delete a connector, it cannot be recovered.", - "operationId": "%2Fapi%2Factions%2Faction%2F%7Bid%7D#0", + }, + "post": { + "operationId": "post-actions-connector-id", "parameters": [ { "description": "The version of the API to use", @@ -524,48 +505,46 @@ "description": "An identifier for the connector.", "in": "path", "name": "id", - "required": true, + "required": false, "schema": { "type": "string" } } ], - "responses": { - "204": { - "description": "Indicates a successful call." - } - }, - "summary": "Delete a connector", - "tags": [ - "connectors" - ] - }, - "get": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Faction%2F%7Bid%7D#1", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, - "schema": { - "type": "string" + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "config": { + "additionalProperties": {}, + "default": {}, + "type": "object" + }, + "connector_type_id": { + "description": "The type of connector.", + "type": "string" + }, + "name": { + "description": "The display name for the connector.", + "type": "string" + }, + "secrets": { + "additionalProperties": {}, + "default": {}, + "type": "object" + } + }, + "required": [ + "name", + "connector_type_id" + ], + "type": "object" + } } } - ], + }, "responses": { "200": { "content": { @@ -621,14 +600,13 @@ "description": "Indicates a successful call." } }, - "summary": "Get connector information", + "summary": "Create a connector", "tags": [ "connectors" ] }, "put": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Faction%2F%7Bid%7D#2", + "operationId": "put-actions-connector-id", "parameters": [ { "description": "The version of the API to use", @@ -674,6 +652,7 @@ "type": "object" }, "name": { + "description": "The display name for the connector.", "type": "string" }, "secrets": { @@ -751,10 +730,10 @@ ] } }, - "/api/actions/action/{id}/_execute": { + "/api/actions/connector/{id}/_execute": { "post": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Faction%2F%7Bid%7D%2F_execute#0", + "description": "You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems.", + "operationId": "post-actions-connector-id-execute", "parameters": [ { "description": "The version of the API to use", @@ -868,10 +847,10 @@ ] } }, - "/api/actions/connector/{id}": { - "delete": { - "description": "WARNING: When you delete a connector, it cannot be recovered.", - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#0", + "/api/actions/connector_types": { + "get": { + "description": "You do not need any Kibana feature privileges to run this API.", + "operationId": "get-actions-connector-types", "parameters": [ { "description": "The version of the API to use", @@ -886,37 +865,25 @@ } }, { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, + "description": "A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases).", + "in": "query", + "name": "feature_id", + "required": false, "schema": { "type": "string" } } ], - "responses": { - "204": { - "description": "Indicates a successful call." - } - }, - "summary": "Delete a connector", + "responses": {}, + "summary": "Get connector types", "tags": [ "connectors" ] - }, + } + }, + "/api/actions/connectors": { "get": { - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#1", + "operationId": "get-actions-connectors", "parameters": [ { "description": "The version of the API to use", @@ -929,534 +896,18 @@ ], "type": "string" } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, - "schema": { - "type": "string" - } } ], - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The connector type identifier.", - "type": "string" - }, - "id": { - "description": "The identifier for the connector.", - "type": "string" - }, - "is_deprecated": { - "description": "Indicates whether the connector is deprecated.", - "type": "boolean" - }, - "is_missing_secrets": { - "description": "Indicates whether the connector is missing secrets.", - "type": "boolean" - }, - "is_preconfigured": { - "description": "Indicates whether the connector is preconfigured. If true, the `config` and `is_missing_secrets` properties are omitted from the response. ", - "type": "boolean" - }, - "is_system_action": { - "description": "Indicates whether the connector is used for system actions.", - "type": "boolean" - }, - "name": { - "description": " The name of the rule.", - "type": "string" - } - }, - "required": [ - "id", - "name", - "connector_type_id", - "is_preconfigured", - "is_deprecated", - "is_system_action" - ], - "type": "object" - } - } - }, - "description": "Indicates a successful call." - } - }, - "summary": "Get connector information", + "responses": {}, + "summary": "Get all connectors", "tags": [ "connectors" ] - }, - "post": { - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%3F%7D#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": false, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "default": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The type of connector.", - "type": "string" - }, - "name": { - "description": "The display name for the connector.", - "type": "string" - }, - "secrets": { - "additionalProperties": {}, - "default": {}, - "type": "object" - } - }, - "required": [ - "name", - "connector_type_id" - ], - "type": "object" - } - } - } - }, - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The connector type identifier.", - "type": "string" - }, - "id": { - "description": "The identifier for the connector.", - "type": "string" - }, - "is_deprecated": { - "description": "Indicates whether the connector is deprecated.", - "type": "boolean" - }, - "is_missing_secrets": { - "description": "Indicates whether the connector is missing secrets.", - "type": "boolean" - }, - "is_preconfigured": { - "description": "Indicates whether the connector is preconfigured. If true, the `config` and `is_missing_secrets` properties are omitted from the response. ", - "type": "boolean" - }, - "is_system_action": { - "description": "Indicates whether the connector is used for system actions.", - "type": "boolean" - }, - "name": { - "description": " The name of the rule.", - "type": "string" - } - }, - "required": [ - "id", - "name", - "connector_type_id", - "is_preconfigured", - "is_deprecated", - "is_system_action" - ], - "type": "object" - } - } - }, - "description": "Indicates a successful call." - } - }, - "summary": "Create a connector", - "tags": [ - "connectors" - ] - }, - "put": { - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#2", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "default": {}, - "type": "object" - }, - "name": { - "description": "The display name for the connector.", - "type": "string" - }, - "secrets": { - "additionalProperties": {}, - "default": {}, - "type": "object" - } - }, - "required": [ - "name" - ], - "type": "object" - } - } - } - }, - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The connector type identifier.", - "type": "string" - }, - "id": { - "description": "The identifier for the connector.", - "type": "string" - }, - "is_deprecated": { - "description": "Indicates whether the connector is deprecated.", - "type": "boolean" - }, - "is_missing_secrets": { - "description": "Indicates whether the connector is missing secrets.", - "type": "boolean" - }, - "is_preconfigured": { - "description": "Indicates whether the connector is preconfigured. If true, the `config` and `is_missing_secrets` properties are omitted from the response. ", - "type": "boolean" - }, - "is_system_action": { - "description": "Indicates whether the connector is used for system actions.", - "type": "boolean" - }, - "name": { - "description": " The name of the rule.", - "type": "string" - } - }, - "required": [ - "id", - "name", - "connector_type_id", - "is_preconfigured", - "is_deprecated", - "is_system_action" - ], - "type": "object" - } - } - }, - "description": "Indicates a successful call." - } - }, - "summary": "Update a connector", - "tags": [ - "connectors" - ] - } - }, - "/api/actions/connector/{id}/_execute": { - "post": { - "description": "You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems.", - "operationId": "%2Fapi%2Factions%2Fconnector%2F%7Bid%7D%2F_execute#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "description": "An identifier for the connector.", - "in": "path", - "name": "id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "params": { - "additionalProperties": {}, - "type": "object" - } - }, - "required": [ - "params" - ], - "type": "object" - } - } - } - }, - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": {}, - "type": "object" - }, - "connector_type_id": { - "description": "The connector type identifier.", - "type": "string" - }, - "id": { - "description": "The identifier for the connector.", - "type": "string" - }, - "is_deprecated": { - "description": "Indicates whether the connector is deprecated.", - "type": "boolean" - }, - "is_missing_secrets": { - "description": "Indicates whether the connector is missing secrets.", - "type": "boolean" - }, - "is_preconfigured": { - "description": "Indicates whether the connector is preconfigured. If true, the `config` and `is_missing_secrets` properties are omitted from the response. ", - "type": "boolean" - }, - "is_system_action": { - "description": "Indicates whether the connector is used for system actions.", - "type": "boolean" - }, - "name": { - "description": " The name of the rule.", - "type": "string" - } - }, - "required": [ - "id", - "name", - "connector_type_id", - "is_preconfigured", - "is_deprecated", - "is_system_action" - ], - "type": "object" - } - } - }, - "description": "Indicates a successful call." - } - }, - "summary": "Run a connector", - "tags": [ - "connectors" - ] - } - }, - "/api/actions/connector_types": { - "get": { - "description": "You do not need any Kibana feature privileges to run this API.", - "operationId": "%2Fapi%2Factions%2Fconnector_types#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases).", - "in": "query", - "name": "feature_id", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": {}, - "summary": "Get connector types", - "tags": [ - "connectors" - ] - } - }, - "/api/actions/connectors": { - "get": { - "operationId": "%2Fapi%2Factions%2Fconnectors#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - } - ], - "responses": {}, - "summary": "Get all connectors", - "tags": [ - "connectors" - ] - } - }, - "/api/actions/list_action_types": { - "get": { - "deprecated": true, - "operationId": "%2Fapi%2Factions%2Flist_action_types#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - } - ], - "responses": {}, - "summary": "Get connector types", - "tags": [ - "connectors" - ] - } - }, - "/api/alerting/rule/{id}": { - "delete": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D#2", + } + }, + "/api/alerting/rule/{id}": { + "delete": { + "operationId": "delete-alerting-rule-id", "parameters": [ { "description": "The version of the API to use", @@ -1510,7 +961,7 @@ ] }, "get": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D#0", + "operationId": "get-alerting-rule-id", "parameters": [ { "description": "The version of the API to use", @@ -2002,80 +1453,13 @@ "type": "number" }, "outcome": { - "additionalProperties": false, - "properties": { - "alerts_count": { - "additionalProperties": false, - "properties": { - "active": { - "description": "Number of active alerts during last run.", - "nullable": true, - "type": "number" - }, - "ignored": { - "description": "Number of ignored alerts during last run.", - "nullable": true, - "type": "number" - }, - "new": { - "description": "Number of new alerts during last run.", - "nullable": true, - "type": "number" - }, - "recovered": { - "description": "Number of recovered alerts during last run.", - "nullable": true, - "type": "number" - } - }, - "type": "object" - }, - "outcome": { - "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", - "enum": [ - "succeeded", - "warning", - "failed" - ], - "type": "string" - }, - "outcome_msg": { - "items": { - "description": "Outcome message generated during last rule run.", - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "outcome_order": { - "description": "Order of the outcome.", - "type": "number" - }, - "warning": { - "description": "Warning of last rule execution.", - "enum": [ - "read", - "decrypt", - "execute", - "unknown", - "license", - "timeout", - "disabled", - "validate", - "maxExecutableActions", - "maxAlerts", - "maxQueuedActions", - "ruleExecution" - ], - "nullable": true, - "type": "string" - } - }, - "required": [ - "outcome", - "alerts_count" + "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", + "enum": [ + "succeeded", + "warning", + "failed" ], - "type": "object" + "type": "string" }, "success": { "description": "Indicates whether the rule run was successful.", @@ -2242,6 +1626,7 @@ "description": "Indicates hours of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byminute": { @@ -2249,6 +1634,7 @@ "description": "Indicates minutes of the hour to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonth": { @@ -2256,6 +1642,7 @@ "description": "Indicates months of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonthday": { @@ -2263,6 +1650,7 @@ "description": "Indicates the days of the month to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysecond": { @@ -2270,6 +1658,7 @@ "description": "Indicates seconds of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysetpos": { @@ -2277,6 +1666,7 @@ "description": "A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.", "type": "number" }, + "nullable": true, "type": "array" }, "byweekday": { @@ -2291,6 +1681,7 @@ ], "description": "Indicates the days of the week to recur or else nth-day-of-month strings. For example, \"+2TU\" second Tuesday of month, \"-1FR\" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination." }, + "nullable": true, "type": "array" }, "byweekno": { @@ -2298,6 +1689,7 @@ "description": "Indicates number of the week hours to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byyearday": { @@ -2305,6 +1697,7 @@ "description": "Indicates the days of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "count": { @@ -2446,7 +1839,7 @@ ] }, "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%3F%7D#0", + "operationId": "post-alerting-rule-id", "parameters": [ { "description": "The version of the API to use", @@ -3240,80 +2633,13 @@ "type": "number" }, "outcome": { - "additionalProperties": false, - "properties": { - "alerts_count": { - "additionalProperties": false, - "properties": { - "active": { - "description": "Number of active alerts during last run.", - "nullable": true, - "type": "number" - }, - "ignored": { - "description": "Number of ignored alerts during last run.", - "nullable": true, - "type": "number" - }, - "new": { - "description": "Number of new alerts during last run.", - "nullable": true, - "type": "number" - }, - "recovered": { - "description": "Number of recovered alerts during last run.", - "nullable": true, - "type": "number" - } - }, - "type": "object" - }, - "outcome": { - "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", - "enum": [ - "succeeded", - "warning", - "failed" - ], - "type": "string" - }, - "outcome_msg": { - "items": { - "description": "Outcome message generated during last rule run.", - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "outcome_order": { - "description": "Order of the outcome.", - "type": "number" - }, - "warning": { - "description": "Warning of last rule execution.", - "enum": [ - "read", - "decrypt", - "execute", - "unknown", - "license", - "timeout", - "disabled", - "validate", - "maxExecutableActions", - "maxAlerts", - "maxQueuedActions", - "ruleExecution" - ], - "nullable": true, - "type": "string" - } - }, - "required": [ - "outcome", - "alerts_count" + "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", + "enum": [ + "succeeded", + "warning", + "failed" ], - "type": "object" + "type": "string" }, "success": { "description": "Indicates whether the rule run was successful.", @@ -3480,6 +2806,7 @@ "description": "Indicates hours of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byminute": { @@ -3487,6 +2814,7 @@ "description": "Indicates minutes of the hour to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonth": { @@ -3494,6 +2822,7 @@ "description": "Indicates months of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonthday": { @@ -3501,6 +2830,7 @@ "description": "Indicates the days of the month to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysecond": { @@ -3508,6 +2838,7 @@ "description": "Indicates seconds of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysetpos": { @@ -3515,6 +2846,7 @@ "description": "A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.", "type": "number" }, + "nullable": true, "type": "array" }, "byweekday": { @@ -3529,6 +2861,7 @@ ], "description": "Indicates the days of the week to recur or else nth-day-of-month strings. For example, \"+2TU\" second Tuesday of month, \"-1FR\" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination." }, + "nullable": true, "type": "array" }, "byweekno": { @@ -3536,6 +2869,7 @@ "description": "Indicates number of the week hours to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byyearday": { @@ -3543,6 +2877,7 @@ "description": "Indicates the days of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "count": { @@ -3684,7 +3019,7 @@ ] }, "put": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D#1", + "operationId": "put-alerting-rule-id", "parameters": [ { "description": "The version of the API to use", @@ -4461,80 +3796,13 @@ "type": "number" }, "outcome": { - "additionalProperties": false, - "properties": { - "alerts_count": { - "additionalProperties": false, - "properties": { - "active": { - "description": "Number of active alerts during last run.", - "nullable": true, - "type": "number" - }, - "ignored": { - "description": "Number of ignored alerts during last run.", - "nullable": true, - "type": "number" - }, - "new": { - "description": "Number of new alerts during last run.", - "nullable": true, - "type": "number" - }, - "recovered": { - "description": "Number of recovered alerts during last run.", - "nullable": true, - "type": "number" - } - }, - "type": "object" - }, - "outcome": { - "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", - "enum": [ - "succeeded", - "warning", - "failed" - ], - "type": "string" - }, - "outcome_msg": { - "items": { - "description": "Outcome message generated during last rule run.", - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "outcome_order": { - "description": "Order of the outcome.", - "type": "number" - }, - "warning": { - "description": "Warning of last rule execution.", - "enum": [ - "read", - "decrypt", - "execute", - "unknown", - "license", - "timeout", - "disabled", - "validate", - "maxExecutableActions", - "maxAlerts", - "maxQueuedActions", - "ruleExecution" - ], - "nullable": true, - "type": "string" - } - }, - "required": [ - "outcome", - "alerts_count" + "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", + "enum": [ + "succeeded", + "warning", + "failed" ], - "type": "object" + "type": "string" }, "success": { "description": "Indicates whether the rule run was successful.", @@ -4701,6 +3969,7 @@ "description": "Indicates hours of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byminute": { @@ -4708,6 +3977,7 @@ "description": "Indicates minutes of the hour to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonth": { @@ -4715,6 +3985,7 @@ "description": "Indicates months of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonthday": { @@ -4722,6 +3993,7 @@ "description": "Indicates the days of the month to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysecond": { @@ -4729,6 +4001,7 @@ "description": "Indicates seconds of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysetpos": { @@ -4736,6 +4009,7 @@ "description": "A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.", "type": "number" }, + "nullable": true, "type": "array" }, "byweekday": { @@ -4750,6 +4024,7 @@ ], "description": "Indicates the days of the week to recur or else nth-day-of-month strings. For example, \"+2TU\" second Tuesday of month, \"-1FR\" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination." }, + "nullable": true, "type": "array" }, "byweekno": { @@ -4757,6 +4032,7 @@ "description": "Indicates number of the week hours to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byyearday": { @@ -4764,6 +4040,7 @@ "description": "Indicates the days of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "count": { @@ -4910,7 +4187,7 @@ }, "/api/alerting/rule/{id}/_disable": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_disable#0", + "operationId": "post-alerting-rule-id-disable", "parameters": [ { "description": "The version of the API to use", @@ -4984,7 +4261,7 @@ }, "/api/alerting/rule/{id}/_enable": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_enable#0", + "operationId": "post-alerting-rule-id-enable", "parameters": [ { "description": "The version of the API to use", @@ -5040,7 +4317,7 @@ }, "/api/alerting/rule/{id}/_mute_all": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_mute_all#0", + "operationId": "post-alerting-rule-id-mute-all", "parameters": [ { "description": "The version of the API to use", @@ -5096,7 +4373,7 @@ }, "/api/alerting/rule/{id}/_unmute_all": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_unmute_all#0", + "operationId": "post-alerting-rule-id-unmute-all", "parameters": [ { "description": "The version of the API to use", @@ -5152,7 +4429,7 @@ }, "/api/alerting/rule/{id}/_update_api_key": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_update_api_key#0", + "operationId": "post-alerting-rule-id-update-api-key", "parameters": [ { "description": "The version of the API to use", @@ -5211,7 +4488,7 @@ }, "/api/alerting/rule/{rule_id}/alert/{alert_id}/_mute": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Brule_id%7D%2Falert%2F%7Balert_id%7D%2F_mute#0", + "operationId": "post-alerting-rule-rule-id-alert-alert-id-mute", "parameters": [ { "description": "The version of the API to use", @@ -5276,7 +4553,7 @@ }, "/api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute": { "post": { - "operationId": "%2Fapi%2Falerting%2Frule%2F%7Brule_id%7D%2Falert%2F%7Balert_id%7D%2F_unmute#0", + "operationId": "post-alerting-rule-rule-id-alert-alert-id-unmute", "parameters": [ { "description": "The version of the API to use", @@ -5341,7 +4618,7 @@ }, "/api/alerting/rules/_find": { "get": { - "operationId": "%2Fapi%2Falerting%2Frules%2F_find#0", + "operationId": "get-alerting-rules-find", "parameters": [ { "description": "The version of the API to use", @@ -5966,80 +5243,13 @@ "type": "number" }, "outcome": { - "additionalProperties": false, - "properties": { - "alerts_count": { - "additionalProperties": false, - "properties": { - "active": { - "description": "Number of active alerts during last run.", - "nullable": true, - "type": "number" - }, - "ignored": { - "description": "Number of ignored alerts during last run.", - "nullable": true, - "type": "number" - }, - "new": { - "description": "Number of new alerts during last run.", - "nullable": true, - "type": "number" - }, - "recovered": { - "description": "Number of recovered alerts during last run.", - "nullable": true, - "type": "number" - } - }, - "type": "object" - }, - "outcome": { - "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", - "enum": [ - "succeeded", - "warning", - "failed" - ], - "type": "string" - }, - "outcome_msg": { - "items": { - "description": "Outcome message generated during last rule run.", - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "outcome_order": { - "description": "Order of the outcome.", - "type": "number" - }, - "warning": { - "description": "Warning of last rule execution.", - "enum": [ - "read", - "decrypt", - "execute", - "unknown", - "license", - "timeout", - "disabled", - "validate", - "maxExecutableActions", - "maxAlerts", - "maxQueuedActions", - "ruleExecution" - ], - "nullable": true, - "type": "string" - } - }, - "required": [ - "outcome", - "alerts_count" + "description": "Outcome of last run of the rule. Value could be succeeded, warning or failed.", + "enum": [ + "succeeded", + "warning", + "failed" ], - "type": "object" + "type": "string" }, "success": { "description": "Indicates whether the rule run was successful.", @@ -6206,6 +5416,7 @@ "description": "Indicates hours of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byminute": { @@ -6213,6 +5424,7 @@ "description": "Indicates minutes of the hour to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonth": { @@ -6220,6 +5432,7 @@ "description": "Indicates months of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bymonthday": { @@ -6227,6 +5440,7 @@ "description": "Indicates the days of the month to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysecond": { @@ -6234,6 +5448,7 @@ "description": "Indicates seconds of the day to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "bysetpos": { @@ -6241,6 +5456,7 @@ "description": "A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.", "type": "number" }, + "nullable": true, "type": "array" }, "byweekday": { @@ -6255,6 +5471,7 @@ ], "description": "Indicates the days of the week to recur or else nth-day-of-month strings. For example, \"+2TU\" second Tuesday of month, \"-1FR\" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination." }, + "nullable": true, "type": "array" }, "byweekno": { @@ -6262,6 +5479,7 @@ "description": "Indicates number of the week hours to recur.", "type": "number" }, + "nullable": true, "type": "array" }, "byyearday": { @@ -6269,6 +5487,7 @@ "description": "Indicates the days of the year that this rule should recur.", "type": "number" }, + "nullable": true, "type": "array" }, "count": { @@ -6407,67 +5626,10 @@ ] } }, - "/api/fleet/agent-status": { - "get": { - "operationId": "%2Fapi%2Ffleet%2Fagent-status#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "in": "query", - "name": "policyId", - "required": false, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "policyIds", - "required": false, - "schema": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ] - } - }, - { - "in": "query", - "name": "kuery", - "required": false, - "schema": { - "deprecated": true, - "type": "string" - } - } - ], - "responses": {}, - "summary": "", - "tags": [] - } - }, "/api/fleet/agent_download_sources": { "get": { "description": "List agent binary download sources", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources#0", + "operationId": "get-fleet-agent-download-sources", "parameters": [ { "description": "The version of the API to use", @@ -6576,7 +5738,7 @@ }, "post": { "description": "Create agent binary download source", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources#1", + "operationId": "post-fleet-agent-download-sources", "parameters": [ { "description": "The version of the API to use", @@ -6717,7 +5879,7 @@ "/api/fleet/agent_download_sources/{sourceId}": { "delete": { "description": "Delete agent binary download source by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#2", + "operationId": "delete-fleet-agent-download-sources-sourceid", "parameters": [ { "description": "The version of the API to use", @@ -6802,7 +5964,7 @@ }, "get": { "description": "Get agent binary download source by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#0", + "operationId": "get-fleet-agent-download-sources-sourceid", "parameters": [ { "description": "The version of the API to use", @@ -6904,7 +6066,7 @@ }, "put": { "description": "Update agent binary download source by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#1", + "operationId": "put-fleet-agent-download-sources-sourceid", "parameters": [ { "description": "The version of the API to use", @@ -7053,7 +6215,7 @@ "/api/fleet/agent_policies": { "get": { "description": "List agent policies", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies#0", + "operationId": "get-fleet-agent-policies", "parameters": [ { "description": "The version of the API to use", @@ -7891,7 +7053,7 @@ }, "post": { "description": "Create an agent policy", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies#1", + "operationId": "post-fleet-agent-policies", "parameters": [ { "description": "The version of the API to use", @@ -8886,7 +8048,7 @@ "/api/fleet/agent_policies/_bulk_get": { "post": { "description": "Bulk get agent policies", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F_bulk_get#0", + "operationId": "post-fleet-agent-policies-bulk-get", "parameters": [ { "description": "The version of the API to use", @@ -9673,7 +8835,7 @@ "/api/fleet/agent_policies/delete": { "post": { "description": "Delete agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2Fdelete#0", + "operationId": "post-fleet-agent-policies-delete", "parameters": [ { "description": "The version of the API to use", @@ -9778,7 +8940,7 @@ "/api/fleet/agent_policies/outputs": { "post": { "description": "Get list of outputs associated with agent policies", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2Foutputs#0", + "operationId": "post-fleet-agent-policies-outputs", "parameters": [ { "description": "The version of the API to use", @@ -9963,7 +9125,7 @@ "/api/fleet/agent_policies/{agentPolicyId}": { "get": { "description": "Get an agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D#0", + "operationId": "get-fleet-agent-policies-agentpolicyid", "parameters": [ { "description": "The version of the API to use", @@ -10714,7 +9876,7 @@ }, "put": { "description": "Update an agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D#1", + "operationId": "put-fleet-agent-policies-agentpolicyid", "parameters": [ { "description": "The version of the API to use", @@ -11721,7 +10883,7 @@ "/api/fleet/agent_policies/{agentPolicyId}/copy": { "post": { "description": "Copy an agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Fcopy#0", + "operationId": "post-fleet-agent-policies-agentpolicyid-copy", "parameters": [ { "description": "The version of the API to use", @@ -12506,7 +11668,7 @@ "/api/fleet/agent_policies/{agentPolicyId}/download": { "get": { "description": "Download an agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Fdownload#0", + "operationId": "get-fleet-agent-policies-agentpolicyid-download", "parameters": [ { "description": "The version of the API to use", @@ -12623,7 +11785,7 @@ "/api/fleet/agent_policies/{agentPolicyId}/full": { "get": { "description": "Get a full agent policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Ffull#0", + "operationId": "get-fleet-agent-policies-agentpolicyid-full", "parameters": [ { "description": "The version of the API to use", @@ -13125,7 +12287,7 @@ "/api/fleet/agent_policies/{agentPolicyId}/outputs": { "get": { "description": "Get list of outputs associated with agent policy by policy id", - "operationId": "%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Foutputs#0", + "operationId": "get-fleet-agent-policies-agentpolicyid-outputs", "parameters": [ { "description": "The version of the API to use", @@ -13283,7 +12445,7 @@ "/api/fleet/agent_status": { "get": { "description": "Get agent status summary", - "operationId": "%2Fapi%2Ffleet%2Fagent_status#0", + "operationId": "get-fleet-agent-status", "parameters": [ { "description": "The version of the API to use", @@ -13328,7 +12490,6 @@ "name": "kuery", "required": false, "schema": { - "deprecated": true, "type": "string" } } @@ -13367,10 +12528,6 @@ "other": { "type": "number" }, - "total": { - "deprecated": true, - "type": "number" - }, "unenrolled": { "type": "number" }, @@ -13380,7 +12537,6 @@ }, "required": [ "events", - "total", "online", "error", "offline", @@ -13437,7 +12593,7 @@ "/api/fleet/agent_status/data": { "get": { "description": "Get incoming agent data", - "operationId": "%2Fapi%2Ffleet%2Fagent_status%2Fdata#0", + "operationId": "get-fleet-agent-status-data", "parameters": [ { "description": "The version of the API to use", @@ -13553,7 +12709,7 @@ "/api/fleet/agents": { "get": { "description": "List agents", - "operationId": "%2Fapi%2Ffleet%2Fagents#0", + "operationId": "get-fleet-agents", "parameters": [ { "description": "The version of the API to use", @@ -14044,394 +13200,6 @@ }, "type": "array" }, - "list": { - "deprecated": true, - "items": { - "additionalProperties": false, - "properties": { - "access_api_key": { - "type": "string" - }, - "access_api_key_id": { - "type": "string" - }, - "active": { - "type": "boolean" - }, - "agent": { - "additionalProperties": true, - "properties": { - "id": { - "type": "string" - }, - "version": { - "type": "string" - } - }, - "required": [ - "id", - "version" - ], - "type": "object" - }, - "components": { - "items": { - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - }, - "message": { - "type": "string" - }, - "status": { - "enum": [ - "STARTING", - "CONFIGURING", - "HEALTHY", - "DEGRADED", - "FAILED", - "STOPPING", - "STOPPED" - ], - "type": "string" - }, - "type": { - "type": "string" - }, - "units": { - "items": { - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - }, - "message": { - "type": "string" - }, - "payload": { - "additionalProperties": {}, - "type": "object" - }, - "status": { - "enum": [ - "STARTING", - "CONFIGURING", - "HEALTHY", - "DEGRADED", - "FAILED", - "STOPPING", - "STOPPED" - ], - "type": "string" - }, - "type": { - "enum": [ - "input", - "output" - ], - "type": "string" - } - }, - "required": [ - "id", - "type", - "status", - "message" - ], - "type": "object" - }, - "type": "array" - } - }, - "required": [ - "id", - "type", - "status", - "message" - ], - "type": "object" - }, - "type": "array" - }, - "default_api_key": { - "type": "string" - }, - "default_api_key_history": { - "items": { - "additionalProperties": false, - "deprecated": true, - "properties": { - "id": { - "type": "string" - }, - "retired_at": { - "type": "string" - } - }, - "required": [ - "id", - "retired_at" - ], - "type": "object" - }, - "type": "array" - }, - "default_api_key_id": { - "type": "string" - }, - "enrolled_at": { - "type": "string" - }, - "id": { - "type": "string" - }, - "last_checkin": { - "type": "string" - }, - "last_checkin_message": { - "type": "string" - }, - "last_checkin_status": { - "enum": [ - "error", - "online", - "degraded", - "updating", - "starting" - ], - "type": "string" - }, - "local_metadata": { - "additionalProperties": {}, - "type": "object" - }, - "metrics": { - "additionalProperties": false, - "properties": { - "cpu_avg": { - "type": "number" - }, - "memory_size_byte_avg": { - "type": "number" - } - }, - "type": "object" - }, - "namespaces": { - "items": { - "type": "string" - }, - "type": "array" - }, - "outputs": { - "additionalProperties": { - "additionalProperties": false, - "properties": { - "api_key_id": { - "type": "string" - }, - "to_retire_api_key_ids": { - "items": { - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - }, - "retired_at": { - "type": "string" - } - }, - "required": [ - "id", - "retired_at" - ], - "type": "object" - }, - "type": "array" - }, - "type": { - "type": "string" - } - }, - "required": [ - "api_key_id", - "type" - ], - "type": "object" - }, - "type": "object" - }, - "packages": { - "items": { - "type": "string" - }, - "type": "array" - }, - "policy_id": { - "type": "string" - }, - "policy_revision": { - "nullable": true, - "type": "number" - }, - "sort": { - "items": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - }, - { - "enum": [], - "nullable": true - } - ] - }, - "type": "array" - }, - "status": { - "enum": [ - "offline", - "error", - "online", - "inactive", - "enrolling", - "unenrolling", - "unenrolled", - "updating", - "degraded" - ], - "type": "string" - }, - "tags": { - "items": { - "type": "string" - }, - "type": "array" - }, - "type": { - "enum": [ - "PERMANENT", - "EPHEMERAL", - "TEMPORARY" - ], - "type": "string" - }, - "unenrolled_at": { - "type": "string" - }, - "unenrollment_started_at": { - "type": "string" - }, - "unhealthy_reason": { - "items": { - "enum": [ - "input", - "output", - "other" - ], - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "upgrade_details": { - "additionalProperties": false, - "properties": { - "action_id": { - "type": "string" - }, - "metadata": { - "additionalProperties": false, - "properties": { - "download_percent": { - "type": "number" - }, - "download_rate": { - "type": "number" - }, - "error_msg": { - "type": "string" - }, - "failed_state": { - "enum": [ - "UPG_REQUESTED", - "UPG_SCHEDULED", - "UPG_DOWNLOADING", - "UPG_EXTRACTING", - "UPG_REPLACING", - "UPG_RESTARTING", - "UPG_FAILED", - "UPG_WATCHING", - "UPG_ROLLBACK" - ], - "type": "string" - }, - "retry_error_msg": { - "type": "string" - }, - "retry_until": { - "type": "string" - }, - "scheduled_at": { - "type": "string" - } - }, - "type": "object" - }, - "state": { - "enum": [ - "UPG_REQUESTED", - "UPG_SCHEDULED", - "UPG_DOWNLOADING", - "UPG_EXTRACTING", - "UPG_REPLACING", - "UPG_RESTARTING", - "UPG_FAILED", - "UPG_WATCHING", - "UPG_ROLLBACK" - ], - "type": "string" - }, - "target_version": { - "type": "string" - } - }, - "required": [ - "target_version", - "action_id", - "state" - ], - "type": "object" - }, - "upgrade_started_at": { - "nullable": true, - "type": "string" - }, - "upgraded_at": { - "nullable": true, - "type": "string" - }, - "user_provided_metadata": { - "additionalProperties": {}, - "type": "object" - } - }, - "required": [ - "id", - "packages", - "type", - "active", - "enrolled_at", - "local_metadata" - ], - "type": "object" - }, - "type": "array" - }, "page": { "type": "number" }, @@ -14492,7 +13260,7 @@ }, "post": { "description": "List agents by action ids", - "operationId": "%2Fapi%2Ffleet%2Fagents#1", + "operationId": "post-fleet-agents", "parameters": [ { "description": "The version of the API to use", @@ -14595,7 +13363,7 @@ "/api/fleet/agents/action_status": { "get": { "description": "Get agent action status", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Faction_status#0", + "operationId": "get-fleet-agents-action-status", "parameters": [ { "description": "The version of the API to use", @@ -14831,7 +13599,7 @@ "/api/fleet/agents/actions/{actionId}/cancel": { "post": { "description": "Cancel agent action", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Factions%2F%7BactionId%7D%2Fcancel#0", + "operationId": "post-fleet-agents-actions-actionid-cancel", "parameters": [ { "description": "The version of the API to use", @@ -14973,7 +13741,7 @@ "/api/fleet/agents/available_versions": { "get": { "description": "Get available agent versions", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Favailable_versions#0", + "operationId": "get-fleet-agents-available-versions", "parameters": [ { "description": "The version of the API to use", @@ -15045,7 +13813,7 @@ "/api/fleet/agents/bulk_reassign": { "post": { "description": "Bulk reassign agents", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_reassign#0", + "operationId": "post-fleet-agents-bulk-reassign", "parameters": [ { "description": "The version of the API to use", @@ -15163,7 +13931,7 @@ "/api/fleet/agents/bulk_request_diagnostics": { "post": { "description": "Bulk request diagnostics from agents", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_request_diagnostics#0", + "operationId": "post-fleet-agents-bulk-request-diagnostics", "parameters": [ { "description": "The version of the API to use", @@ -15282,7 +14050,7 @@ "/api/fleet/agents/bulk_unenroll": { "post": { "description": "Bulk unenroll agents", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_unenroll#0", + "operationId": "post-fleet-agents-bulk-unenroll", "parameters": [ { "description": "The version of the API to use", @@ -15406,7 +14174,7 @@ "/api/fleet/agents/bulk_update_agent_tags": { "post": { "description": "Bulk update agent tags", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_update_agent_tags#0", + "operationId": "post-fleet-agents-bulk-update-agent-tags", "parameters": [ { "description": "The version of the API to use", @@ -15532,7 +14300,7 @@ "/api/fleet/agents/bulk_upgrade": { "post": { "description": "Bulk upgrade agents", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fbulk_upgrade#0", + "operationId": "post-fleet-agents-bulk-upgrade", "parameters": [ { "description": "The version of the API to use", @@ -15666,7 +14434,7 @@ "/api/fleet/agents/files/{fileId}": { "delete": { "description": "Delete file uploaded by agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Ffiles%2F%7BfileId%7D#0", + "operationId": "delete-fleet-agents-files-fileid", "parameters": [ { "description": "The version of the API to use", @@ -15757,7 +14525,7 @@ "/api/fleet/agents/files/{fileId}/{fileName}": { "get": { "description": "Get file uploaded by agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Ffiles%2F%7BfileId%7D%2F%7BfileName%7D#0", + "operationId": "get-fleet-agents-files-fileid-filename", "parameters": [ { "description": "The version of the API to use", @@ -15833,7 +14601,7 @@ "/api/fleet/agents/setup": { "get": { "description": "Get agent setup info", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fsetup#0", + "operationId": "get-fleet-agents-setup", "parameters": [ { "description": "The version of the API to use", @@ -15934,7 +14702,7 @@ }, "post": { "description": "Initiate agent setup", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Fsetup#1", + "operationId": "post-fleet-agents-setup", "parameters": [ { "description": "The version of the API to use", @@ -16034,7 +14802,7 @@ "/api/fleet/agents/tags": { "get": { "description": "List agent tags", - "operationId": "%2Fapi%2Ffleet%2Fagents%2Ftags#0", + "operationId": "get-fleet-agents-tags", "parameters": [ { "description": "The version of the API to use", @@ -16123,7 +14891,7 @@ "/api/fleet/agents/{agentId}": { "delete": { "description": "Delete agent by ID", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#2", + "operationId": "delete-fleet-agents-agentid", "parameters": [ { "description": "The version of the API to use", @@ -16211,7 +14979,7 @@ }, "get": { "description": "Get agent by ID", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#0", + "operationId": "get-fleet-agents-agentid", "parameters": [ { "description": "The version of the API to use", @@ -16676,7 +15444,7 @@ }, "put": { "description": "Update agent by ID", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#1", + "operationId": "put-fleet-agents-agentid", "parameters": [ { "description": "The version of the API to use", @@ -17166,7 +15934,7 @@ "/api/fleet/agents/{agentId}/actions": { "post": { "description": "Create agent action", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Factions#0", + "operationId": "post-fleet-agents-agentid-actions", "parameters": [ { "description": "The version of the API to use", @@ -17383,7 +16151,7 @@ "/api/fleet/agents/{agentId}/reassign": { "post": { "description": "Reassign agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Freassign#1", + "operationId": "post-fleet-agents-agentid-reassign", "parameters": [ { "description": "The version of the API to use", @@ -17476,68 +16244,12 @@ "tags": [ "Elastic Agent actions" ] - }, - "put": { - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Freassign#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "in": "path", - "name": "agentId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "policy_id": { - "type": "string" - } - }, - "required": [ - "policy_id" - ], - "type": "object" - } - } - } - }, - "responses": {}, - "summary": "", - "tags": [] } }, "/api/fleet/agents/{agentId}/request_diagnostics": { "post": { "description": "Request agent diagnostics", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Frequest_diagnostics#0", + "operationId": "post-fleet-agents-agentid-request-diagnostics", "parameters": [ { "description": "The version of the API to use", @@ -17646,7 +16358,7 @@ "/api/fleet/agents/{agentId}/unenroll": { "post": { "description": "Unenroll agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Funenroll#0", + "operationId": "post-fleet-agents-agentid-unenroll", "parameters": [ { "description": "The version of the API to use", @@ -17708,7 +16420,7 @@ "/api/fleet/agents/{agentId}/upgrade": { "post": { "description": "Upgrade agent", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Fupgrade#0", + "operationId": "post-fleet-agents-agentid-upgrade", "parameters": [ { "description": "The version of the API to use", @@ -17815,7 +16527,7 @@ "/api/fleet/agents/{agentId}/uploads": { "get": { "description": "List agent uploads", - "operationId": "%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Fuploads#0", + "operationId": "get-fleet-agents-agentid-uploads", "parameters": [ { "description": "The version of the API to use", @@ -17935,7 +16647,7 @@ "/api/fleet/check-permissions": { "get": { "description": "Check permissions", - "operationId": "%2Fapi%2Ffleet%2Fcheck-permissions#0", + "operationId": "get-fleet-check-permissions", "parameters": [ { "description": "The version of the API to use", @@ -18020,7 +16732,7 @@ "/api/fleet/data_streams": { "get": { "description": "List data streams", - "operationId": "%2Fapi%2Ffleet%2Fdata_streams#0", + "operationId": "get-fleet-data-streams", "parameters": [ { "description": "The version of the API to use", @@ -18177,7 +16889,7 @@ }, "/api/fleet/enrollment-api-keys": { "get": { - "operationId": "%2Fapi%2Ffleet%2Fenrollment-api-keys#0", + "operationId": "get-fleet-enrollment-api-keys-2", "parameters": [ { "description": "The version of the API to use", @@ -18223,7 +16935,7 @@ "tags": [] }, "post": { - "operationId": "%2Fapi%2Ffleet%2Fenrollment-api-keys#1", + "operationId": "post-fleet-enrollment-api-keys-2", "parameters": [ { "description": "The version of the API to use", @@ -18279,7 +16991,7 @@ }, "/api/fleet/enrollment-api-keys/{keyId}": { "delete": { - "operationId": "%2Fapi%2Ffleet%2Fenrollment-api-keys%2F%7BkeyId%7D#1", + "operationId": "delete-fleet-enrollment-api-keys-keyid-2", "parameters": [ { "description": "The version of the API to use", @@ -18317,7 +17029,7 @@ "tags": [] }, "get": { - "operationId": "%2Fapi%2Ffleet%2Fenrollment-api-keys%2F%7BkeyId%7D#0", + "operationId": "get-fleet-enrollment-api-keys-keyid-2", "parameters": [ { "description": "The version of the API to use", @@ -18348,7 +17060,7 @@ "/api/fleet/enrollment_api_keys": { "get": { "description": "List enrollment API keys", - "operationId": "%2Fapi%2Ffleet%2Fenrollment_api_keys#0", + "operationId": "get-fleet-enrollment-api-keys", "parameters": [ { "description": "The version of the API to use", @@ -18536,7 +17248,7 @@ }, "post": { "description": "Create enrollment API key", - "operationId": "%2Fapi%2Ffleet%2Fenrollment_api_keys#1", + "operationId": "post-fleet-enrollment-api-keys", "parameters": [ { "description": "The version of the API to use", @@ -18682,7 +17394,7 @@ "/api/fleet/enrollment_api_keys/{keyId}": { "delete": { "description": "Revoke enrollment API key by ID by marking it as inactive", - "operationId": "%2Fapi%2Ffleet%2Fenrollment_api_keys%2F%7BkeyId%7D#1", + "operationId": "delete-fleet-enrollment-api-keys-keyid", "parameters": [ { "description": "The version of the API to use", @@ -18770,7 +17482,7 @@ }, "get": { "description": "Get enrollment API key by ID", - "operationId": "%2Fapi%2Ffleet%2Fenrollment_api_keys%2F%7BkeyId%7D#0", + "operationId": "get-fleet-enrollment-api-keys-keyid", "parameters": [ { "description": "The version of the API to use", @@ -18883,7 +17595,7 @@ "/api/fleet/epm/bulk_assets": { "post": { "description": "Bulk get assets", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fbulk_assets#0", + "operationId": "post-fleet-epm-bulk-assets", "parameters": [ { "description": "The version of the API to use", @@ -19034,7 +17746,7 @@ "/api/fleet/epm/categories": { "get": { "description": "List package categories", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fcategories#0", + "operationId": "get-fleet-epm-categories", "parameters": [ { "description": "The version of the API to use", @@ -19183,7 +17895,7 @@ "/api/fleet/epm/custom_integrations": { "post": { "description": "Create custom integration", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fcustom_integrations#0", + "operationId": "post-fleet-epm-custom-integrations", "parameters": [ { "description": "The version of the API to use", @@ -19465,7 +18177,7 @@ "/api/fleet/epm/data_streams": { "get": { "description": "List data streams", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fdata_streams#0", + "operationId": "get-fleet-epm-data-streams", "parameters": [ { "description": "The version of the API to use", @@ -19591,7 +18303,7 @@ "/api/fleet/epm/packages": { "get": { "description": "List packages", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages#0", + "operationId": "get-fleet-epm-packages", "parameters": [ { "description": "The version of the API to use", @@ -20660,7 +19372,7 @@ }, "post": { "description": "Install package by upload", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages#1", + "operationId": "post-fleet-epm-packages", "parameters": [ { "description": "The version of the API to use", @@ -20922,7 +19634,7 @@ "/api/fleet/epm/packages/_bulk": { "post": { "description": "Bulk install packages", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F_bulk#0", + "operationId": "post-fleet-epm-packages-bulk", "parameters": [ { "description": "The version of the API to use", @@ -21346,7 +20058,7 @@ "/api/fleet/epm/packages/installed": { "get": { "description": "Get installed packages", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2Finstalled#0", + "operationId": "get-fleet-epm-packages-installed", "parameters": [ { "description": "The version of the API to use", @@ -21587,7 +20299,7 @@ "/api/fleet/epm/packages/limited": { "get": { "description": "Get limited package list", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2Flimited#0", + "operationId": "get-fleet-epm-packages-limited", "parameters": [ { "description": "The version of the API to use", @@ -21666,7 +20378,7 @@ "/api/fleet/epm/packages/{pkgName}/stats": { "get": { "description": "Get package stats", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2Fstats#0", + "operationId": "get-fleet-epm-packages-pkgname-stats", "parameters": [ { "description": "The version of the API to use", @@ -21752,7 +20464,7 @@ "/api/fleet/epm/packages/{pkgName}/{pkgVersion}": { "delete": { "description": "Delete package", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#3", + "operationId": "delete-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { "description": "The version of the API to use", @@ -22014,7 +20726,7 @@ }, "get": { "description": "Get package", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#0", + "operationId": "get-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { "description": "The version of the API to use", @@ -23278,7 +21990,7 @@ }, "post": { "description": "Install package from registry", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#2", + "operationId": "post-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { "description": "The version of the API to use", @@ -23573,7 +22285,7 @@ }, "put": { "description": "Update package settings", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#1", + "operationId": "put-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { "description": "The version of the API to use", @@ -24822,7 +23534,7 @@ "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/transforms/authorize": { "post": { "description": "Authorize transforms", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2Ftransforms%2Fauthorize#0", + "operationId": "post-fleet-epm-packages-pkgname-pkgversion-transforms-authorize", "parameters": [ { "description": "The version of the API to use", @@ -24966,7 +23678,7 @@ "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/{filePath*}": { "get": { "description": "Get package file", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2F%7BfilePath*%7D#0", + "operationId": "get-fleet-epm-packages-pkgname-pkgversion-filepath", "parameters": [ { "description": "The version of the API to use", @@ -25047,7 +23759,7 @@ }, "/api/fleet/epm/packages/{pkgkey}": { "delete": { - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#3", + "operationId": "delete-fleet-epm-packages-pkgkey", "parameters": [ { "description": "The version of the API to use", @@ -25104,7 +23816,7 @@ "tags": [] }, "get": { - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#0", + "operationId": "get-fleet-epm-packages-pkgkey", "parameters": [ { "description": "The version of the API to use", @@ -25165,7 +23877,7 @@ "tags": [] }, "post": { - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#2", + "operationId": "post-fleet-epm-packages-pkgkey", "parameters": [ { "description": "The version of the API to use", @@ -25248,7 +23960,7 @@ "tags": [] }, "put": { - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#1", + "operationId": "put-fleet-epm-packages-pkgkey", "parameters": [ { "description": "The version of the API to use", @@ -25307,7 +24019,7 @@ "/api/fleet/epm/templates/{pkgName}/{pkgVersion}/inputs": { "get": { "description": "Get inputs template", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Ftemplates%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2Finputs#0", + "operationId": "get-fleet-epm-templates-pkgname-pkgversion-inputs", "parameters": [ { "description": "The version of the API to use", @@ -25476,7 +24188,7 @@ "/api/fleet/epm/verification_key_id": { "get": { "description": "Get a package signature verification key ID", - "operationId": "%2Fapi%2Ffleet%2Fepm%2Fverification_key_id#0", + "operationId": "get-fleet-epm-verification-key-id", "parameters": [ { "description": "The version of the API to use", @@ -25546,7 +24258,7 @@ "/api/fleet/fleet_server_hosts": { "get": { "description": "List Fleet Server hosts", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts#0", + "operationId": "get-fleet-fleet-server-hosts", "parameters": [ { "description": "The version of the API to use", @@ -25664,7 +24376,7 @@ }, "post": { "description": "Create Fleet Server host", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts#1", + "operationId": "post-fleet-fleet-server-hosts", "parameters": [ { "description": "The version of the API to use", @@ -25823,7 +24535,7 @@ "/api/fleet/fleet_server_hosts/{itemId}": { "delete": { "description": "Delete Fleet Server host by ID", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#1", + "operationId": "delete-fleet-fleet-server-hosts-itemid", "parameters": [ { "description": "The version of the API to use", @@ -25908,7 +24620,7 @@ }, "get": { "description": "Get Fleet Server host by ID", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#0", + "operationId": "get-fleet-fleet-server-hosts-itemid", "parameters": [ { "description": "The version of the API to use", @@ -26019,7 +24731,7 @@ }, "put": { "description": "Update Fleet Server host by ID", - "operationId": "%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#2", + "operationId": "put-fleet-fleet-server-hosts-itemid", "parameters": [ { "description": "The version of the API to use", @@ -26177,7 +24889,7 @@ "/api/fleet/health_check": { "post": { "description": "Check Fleet Server health", - "operationId": "%2Fapi%2Ffleet%2Fhealth_check#0", + "operationId": "post-fleet-health-check", "parameters": [ { "description": "The version of the API to use", @@ -26313,7 +25025,7 @@ "/api/fleet/kubernetes": { "get": { "description": "Get full K8s agent manifest", - "operationId": "%2Fapi%2Ffleet%2Fkubernetes#0", + "operationId": "get-fleet-kubernetes", "parameters": [ { "description": "The version of the API to use", @@ -26405,7 +25117,7 @@ }, "/api/fleet/kubernetes/download": { "get": { - "operationId": "%2Fapi%2Ffleet%2Fkubernetes%2Fdownload#0", + "operationId": "get-fleet-kubernetes-download", "parameters": [ { "description": "The version of the API to use", @@ -26514,7 +25226,7 @@ "/api/fleet/logstash_api_keys": { "post": { "description": "Generate Logstash API key", - "operationId": "%2Fapi%2Ffleet%2Flogstash_api_keys#0", + "operationId": "post-fleet-logstash-api-keys", "parameters": [ { "description": "The version of the API to use", @@ -26593,7 +25305,7 @@ "/api/fleet/message_signing_service/rotate_key_pair": { "post": { "description": "Rotate fleet message signing key pair", - "operationId": "%2Fapi%2Ffleet%2Fmessage_signing_service%2Frotate_key_pair#0", + "operationId": "post-fleet-message-signing-service-rotate-key-pair", "parameters": [ { "description": "The version of the API to use", @@ -26706,7 +25418,7 @@ "/api/fleet/outputs": { "get": { "description": "List outputs", - "operationId": "%2Fapi%2Ffleet%2Foutputs#0", + "operationId": "get-fleet-outputs", "parameters": [ { "description": "The version of the API to use", @@ -27836,7 +26548,7 @@ }, "post": { "description": "Create output", - "operationId": "%2Fapi%2Ffleet%2Foutputs#1", + "operationId": "post-fleet-outputs", "parameters": [ { "description": "The version of the API to use", @@ -30020,7 +28732,7 @@ "/api/fleet/outputs/{outputId}": { "delete": { "description": "Delete output by ID", - "operationId": "%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#2", + "operationId": "delete-fleet-outputs-outputid", "parameters": [ { "description": "The version of the API to use", @@ -30130,7 +28842,7 @@ }, "get": { "description": "Get output by ID", - "operationId": "%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#0", + "operationId": "get-fleet-outputs-outputid", "parameters": [ { "description": "The version of the API to use", @@ -31253,7 +29965,7 @@ }, "put": { "description": "Update output by ID", - "operationId": "%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#1", + "operationId": "put-fleet-outputs-outputid", "parameters": [ { "description": "The version of the API to use", @@ -33421,7 +32133,7 @@ "/api/fleet/outputs/{outputId}/health": { "get": { "description": "Get latest output health", - "operationId": "%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D%2Fhealth#0", + "operationId": "get-fleet-outputs-outputid-health", "parameters": [ { "description": "The version of the API to use", @@ -33509,7 +32221,7 @@ "/api/fleet/package_policies": { "get": { "description": "List package policies", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies#0", + "operationId": "get-fleet-package-policies", "parameters": [ { "description": "The version of the API to use", @@ -34224,7 +32936,7 @@ }, "post": { "description": "Create package policy", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies#1", + "operationId": "post-fleet-package-policies", "parameters": [ { "description": "The version of the API to use", @@ -35498,7 +34210,7 @@ "/api/fleet/package_policies/_bulk_get": { "post": { "description": "Bulk get package policies", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2F_bulk_get#0", + "operationId": "post-fleet-package-policies-bulk-get", "parameters": [ { "description": "The version of the API to use", @@ -36196,7 +34908,7 @@ "/api/fleet/package_policies/delete": { "post": { "description": "Bulk delete package policies", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2Fdelete#0", + "operationId": "post-fleet-package-policies-delete", "parameters": [ { "description": "The version of the API to use", @@ -36400,7 +35112,7 @@ "/api/fleet/package_policies/upgrade": { "post": { "description": "Upgrade package policy to a newer package version", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2Fupgrade#0", + "operationId": "post-fleet-package-policies-upgrade", "parameters": [ { "description": "The version of the API to use", @@ -36525,7 +35237,7 @@ "/api/fleet/package_policies/upgrade/dryrun": { "post": { "description": "Dry run package policy upgrade", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2Fupgrade%2Fdryrun#0", + "operationId": "post-fleet-package-policies-upgrade-dryrun", "parameters": [ { "description": "The version of the API to use", @@ -37711,7 +36423,7 @@ "/api/fleet/package_policies/{packagePolicyId}": { "delete": { "description": "Delete package policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#2", + "operationId": "delete-fleet-package-policies-packagepolicyid", "parameters": [ { "description": "The version of the API to use", @@ -37804,7 +36516,7 @@ }, "get": { "description": "Get package policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#0", + "operationId": "get-fleet-package-policies-packagepolicyid", "parameters": [ { "description": "The version of the API to use", @@ -38470,7 +37182,7 @@ }, "put": { "description": "Update package policy by ID", - "operationId": "%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#1", + "operationId": "put-fleet-package-policies-packagepolicyid", "parameters": [ { "description": "The version of the API to use", @@ -39744,7 +38456,7 @@ "/api/fleet/proxies": { "get": { "description": "List proxies", - "operationId": "%2Fapi%2Ffleet%2Fproxies#0", + "operationId": "get-fleet-proxies", "parameters": [ { "description": "The version of the API to use", @@ -39876,7 +38588,7 @@ }, "post": { "description": "Create proxy", - "operationId": "%2Fapi%2Ffleet%2Fproxies#1", + "operationId": "post-fleet-proxies", "parameters": [ { "description": "The version of the API to use", @@ -40060,410 +38772,10 @@ ] } }, - "/api/fleet/proxies/{itemId}": { - "delete": { - "description": "Delete proxy by ID", - "operationId": "%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#2", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "in": "path", - "name": "itemId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - } - } - } - }, - "400": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "description": "Generic Error", - "properties": { - "error": { - "type": "string" - }, - "message": { - "type": "string" - }, - "statusCode": { - "type": "number" - } - }, - "required": [ - "message" - ], - "type": "object" - } - } - } - } - }, - "summary": "", - "tags": [ - "Fleet proxies" - ] - }, - "get": { - "description": "Get proxy by ID", - "operationId": "%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#1", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "in": "path", - "name": "itemId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "item": { - "additionalProperties": false, - "properties": { - "certificate": { - "nullable": true, - "type": "string" - }, - "certificate_authorities": { - "nullable": true, - "type": "string" - }, - "certificate_key": { - "nullable": true, - "type": "string" - }, - "id": { - "type": "string" - }, - "is_preconfigured": { - "default": false, - "type": "boolean" - }, - "name": { - "type": "string" - }, - "proxy_headers": { - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - }, - { - "type": "number" - } - ] - }, - "nullable": true, - "type": "object" - }, - "url": { - "type": "string" - } - }, - "required": [ - "id", - "url", - "name" - ], - "type": "object" - } - }, - "required": [ - "item" - ], - "type": "object" - } - } - } - }, - "400": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "description": "Generic Error", - "properties": { - "error": { - "type": "string" - }, - "message": { - "type": "string" - }, - "statusCode": { - "type": "number" - } - }, - "required": [ - "message" - ], - "type": "object" - } - } - } - } - }, - "summary": "", - "tags": [ - "Fleet proxies" - ] - }, - "put": { - "description": "Update proxy by ID", - "operationId": "%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#0", - "parameters": [ - { - "description": "The version of the API to use", - "in": "header", - "name": "elastic-api-version", - "schema": { - "default": "2023-10-31", - "enum": [ - "2023-10-31" - ], - "type": "string" - } - }, - { - "description": "A required header to protect against CSRF attacks", - "in": "header", - "name": "kbn-xsrf", - "required": true, - "schema": { - "example": "true", - "type": "string" - } - }, - { - "in": "path", - "name": "itemId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "certificate": { - "nullable": true, - "type": "string" - }, - "certificate_authorities": { - "nullable": true, - "type": "string" - }, - "certificate_key": { - "nullable": true, - "type": "string" - }, - "name": { - "type": "string" - }, - "proxy_headers": { - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - }, - { - "type": "number" - } - ] - }, - "nullable": true, - "type": "object" - }, - "url": { - "type": "string" - } - }, - "required": [ - "proxy_headers", - "certificate_authorities", - "certificate", - "certificate_key" - ], - "type": "object" - } - } - } - }, - "responses": { - "200": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "properties": { - "item": { - "additionalProperties": false, - "properties": { - "certificate": { - "nullable": true, - "type": "string" - }, - "certificate_authorities": { - "nullable": true, - "type": "string" - }, - "certificate_key": { - "nullable": true, - "type": "string" - }, - "id": { - "type": "string" - }, - "is_preconfigured": { - "default": false, - "type": "boolean" - }, - "name": { - "type": "string" - }, - "proxy_headers": { - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - }, - { - "type": "number" - } - ] - }, - "nullable": true, - "type": "object" - }, - "url": { - "type": "string" - } - }, - "required": [ - "id", - "url", - "name" - ], - "type": "object" - } - }, - "required": [ - "item" - ], - "type": "object" - } - } - } - }, - "400": { - "content": { - "application/json; Elastic-Api-Version=2023-10-31": { - "schema": { - "additionalProperties": false, - "description": "Generic Error", - "properties": { - "error": { - "type": "string" - }, - "message": { - "type": "string" - }, - "statusCode": { - "type": "number" - } - }, - "required": [ - "message" - ], - "type": "object" - } - } - } - } - }, - "summary": "", - "tags": [ - "Fleet proxies" - ] - } - }, - "/api/fleet/service-tokens": { - "post": { - "description": "Create a service token", - "operationId": "%2Fapi%2Ffleet%2Fservice-tokens#0", + "/api/fleet/proxies/{itemId}": { + "delete": { + "description": "Delete proxy by ID", + "operationId": "delete-fleet-proxies-itemid", "parameters": [ { "description": "The version of the API to use", @@ -40486,17 +38798,384 @@ "example": "true", "type": "string" } + }, + { + "in": "path", + "name": "itemId", + "required": true, + "schema": { + "type": "string" + } } ], - "responses": {}, + "responses": { + "200": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + } + } + }, + "400": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "description": "Generic Error", + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "statusCode": { + "type": "number" + } + }, + "required": [ + "message" + ], + "type": "object" + } + } + } + } + }, "summary": "", - "tags": [] + "tags": [ + "Fleet proxies" + ] + }, + "get": { + "description": "Get proxy by ID", + "operationId": "get-fleet-proxies-itemid", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "in": "path", + "name": "itemId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "item": { + "additionalProperties": false, + "properties": { + "certificate": { + "nullable": true, + "type": "string" + }, + "certificate_authorities": { + "nullable": true, + "type": "string" + }, + "certificate_key": { + "nullable": true, + "type": "string" + }, + "id": { + "type": "string" + }, + "is_preconfigured": { + "default": false, + "type": "boolean" + }, + "name": { + "type": "string" + }, + "proxy_headers": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + } + ] + }, + "nullable": true, + "type": "object" + }, + "url": { + "type": "string" + } + }, + "required": [ + "id", + "url", + "name" + ], + "type": "object" + } + }, + "required": [ + "item" + ], + "type": "object" + } + } + } + }, + "400": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "description": "Generic Error", + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "statusCode": { + "type": "number" + } + }, + "required": [ + "message" + ], + "type": "object" + } + } + } + } + }, + "summary": "", + "tags": [ + "Fleet proxies" + ] + }, + "put": { + "description": "Update proxy by ID", + "operationId": "put-fleet-proxies-itemid", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "in": "path", + "name": "itemId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "certificate": { + "nullable": true, + "type": "string" + }, + "certificate_authorities": { + "nullable": true, + "type": "string" + }, + "certificate_key": { + "nullable": true, + "type": "string" + }, + "name": { + "type": "string" + }, + "proxy_headers": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + } + ] + }, + "nullable": true, + "type": "object" + }, + "url": { + "type": "string" + } + }, + "required": [ + "proxy_headers", + "certificate_authorities", + "certificate", + "certificate_key" + ], + "type": "object" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "item": { + "additionalProperties": false, + "properties": { + "certificate": { + "nullable": true, + "type": "string" + }, + "certificate_authorities": { + "nullable": true, + "type": "string" + }, + "certificate_key": { + "nullable": true, + "type": "string" + }, + "id": { + "type": "string" + }, + "is_preconfigured": { + "default": false, + "type": "boolean" + }, + "name": { + "type": "string" + }, + "proxy_headers": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + } + ] + }, + "nullable": true, + "type": "object" + }, + "url": { + "type": "string" + } + }, + "required": [ + "id", + "url", + "name" + ], + "type": "object" + } + }, + "required": [ + "item" + ], + "type": "object" + } + } + } + }, + "400": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "description": "Generic Error", + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "statusCode": { + "type": "number" + } + }, + "required": [ + "message" + ], + "type": "object" + } + } + } + } + }, + "summary": "", + "tags": [ + "Fleet proxies" + ] } }, "/api/fleet/service_tokens": { "post": { "description": "Create a service token", - "operationId": "%2Fapi%2Ffleet%2Fservice_tokens#0", + "operationId": "post-fleet-service-tokens", "parameters": [ { "description": "The version of the API to use", @@ -40596,7 +39275,7 @@ "/api/fleet/settings": { "get": { "description": "Get settings", - "operationId": "%2Fapi%2Ffleet%2Fsettings#0", + "operationId": "get-fleet-settings", "parameters": [ { "description": "The version of the API to use", @@ -40747,7 +39426,7 @@ }, "put": { "description": "Update settings", - "operationId": "%2Fapi%2Ffleet%2Fsettings#1", + "operationId": "put-fleet-settings", "parameters": [ { "description": "The version of the API to use", @@ -40964,7 +39643,7 @@ "/api/fleet/setup": { "post": { "description": "Initiate Fleet setup", - "operationId": "%2Fapi%2Ffleet%2Fsetup#0", + "operationId": "post-fleet-setup", "parameters": [ { "description": "The version of the API to use", @@ -41083,7 +39762,7 @@ "/api/fleet/uninstall_tokens": { "get": { "description": "List metadata for latest uninstall tokens per agent policy", - "operationId": "%2Fapi%2Ffleet%2Funinstall_tokens#0", + "operationId": "get-fleet-uninstall-tokens", "parameters": [ { "description": "The version of the API to use", @@ -41232,7 +39911,7 @@ "/api/fleet/uninstall_tokens/{uninstallTokenId}": { "get": { "description": "Get one decrypted uninstall token by its ID", - "operationId": "%2Fapi%2Ffleet%2Funinstall_tokens%2F%7BuninstallTokenId%7D#0", + "operationId": "get-fleet-uninstall-tokens-uninstalltokenid", "parameters": [ { "description": "The version of the API to use", @@ -41339,7 +40018,7 @@ }, "/api/security/role": { "get": { - "operationId": "%2Fapi%2Fsecurity%2Frole#0", + "operationId": "get-security-role", "parameters": [ { "description": "The version of the API to use", @@ -41354,6 +40033,7 @@ } }, { + "description": "If `true` and the response contains any privileges that are associated with deprecated features, they are omitted in favor of details about the appropriate replacement feature privileges.", "in": "query", "name": "replaceDeprecatedPrivileges", "required": false, @@ -41362,7 +40042,11 @@ } } ], - "responses": {}, + "responses": { + "200": { + "description": "Indicates a successful call." + } + }, "summary": "Get all roles", "tags": [ "roles" @@ -41371,7 +40055,7 @@ }, "/api/security/role/{name}": { "delete": { - "operationId": "%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#1", + "operationId": "delete-security-role-name", "parameters": [ { "description": "The version of the API to use", @@ -41405,14 +40089,18 @@ } } ], - "responses": {}, + "responses": { + "204": { + "description": "Indicates a successful call." + } + }, "summary": "Delete a role", "tags": [ "roles" ] }, "get": { - "operationId": "%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#0", + "operationId": "get-security-role-name", "parameters": [ { "description": "The version of the API to use", @@ -41427,6 +40115,7 @@ } }, { + "description": "The role name.", "in": "path", "name": "name", "required": true, @@ -41436,6 +40125,7 @@ } }, { + "description": "If `true` and the response contains any privileges that are associated with deprecated features, they are omitted in favor of details about the appropriate replacement feature privileges.", "in": "query", "name": "replaceDeprecatedPrivileges", "required": false, @@ -41444,14 +40134,19 @@ } } ], - "responses": {}, + "responses": { + "200": { + "description": "Indicates a successful call." + } + }, "summary": "Get a role", "tags": [ "roles" ] }, "put": { - "operationId": "%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#2", + "description": "Create a new Kibana role or update the attributes of an existing role. Kibana roles are stored in the Elasticsearch native realm.", + "operationId": "put-security-role-name", "parameters": [ { "description": "The version of the API to use", @@ -41476,6 +40171,7 @@ } }, { + "description": "The role name.", "in": "path", "name": "name", "required": true, @@ -41486,6 +40182,7 @@ } }, { + "description": "When true, a role is not overwritten if it already exists.", "in": "query", "name": "createOnly", "required": false, @@ -41502,6 +40199,7 @@ "additionalProperties": false, "properties": { "description": { + "description": "A description for the role.", "maxLength": 2048, "type": "string" }, @@ -41510,6 +40208,7 @@ "properties": { "cluster": { "items": { + "description": "Cluster privileges that define the cluster level actions that users can perform.", "type": "string" }, "type": "array" @@ -41519,11 +40218,13 @@ "additionalProperties": false, "properties": { "allow_restricted_indices": { + "description": "Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field covers the restricted indices too.", "type": "boolean" }, "field_security": { "additionalProperties": { "items": { + "description": "The document fields that the role members have read access to.", "type": "string" }, "type": "array" @@ -41532,6 +40233,7 @@ }, "names": { "items": { + "description": "The data streams, indices, and aliases to which the permissions in this entry apply. It supports wildcards (*).", "type": "string" }, "minItems": 1, @@ -41539,12 +40241,14 @@ }, "privileges": { "items": { + "description": "The index level privileges that the role members have for the data streams and indices.", "type": "string" }, "minItems": 1, "type": "array" }, "query": { + "description": "A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members.", "type": "string" } }, @@ -41562,6 +40266,7 @@ "properties": { "clusters": { "items": { + "description": "A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.", "type": "string" }, "minItems": 1, @@ -41569,6 +40274,7 @@ }, "privileges": { "items": { + "description": "The cluster level privileges for the remote cluster. The allowed values are a subset of the cluster privileges.", "type": "string" }, "minItems": 1, @@ -41588,10 +40294,12 @@ "additionalProperties": false, "properties": { "allow_restricted_indices": { + "description": "Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field will cover the restricted indices too.", "type": "boolean" }, "clusters": { "items": { + "description": "A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.", "type": "string" }, "minItems": 1, @@ -41600,6 +40308,7 @@ "field_security": { "additionalProperties": { "items": { + "description": "The document fields that the role members have read access to.", "type": "string" }, "type": "array" @@ -41608,6 +40317,7 @@ }, "names": { "items": { + "description": "A list of remote aliases, data streams, or indices to which the permissions apply. It supports wildcards (*).", "type": "string" }, "minItems": 1, @@ -41615,12 +40325,14 @@ }, "privileges": { "items": { + "description": "The index level privileges that role members have for the specified indices.", "type": "string" }, "minItems": 1, "type": "array" }, "query": { + "description": "A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members. ", "type": "string" } }, @@ -41635,6 +40347,7 @@ }, "run_as": { "items": { + "description": "A user name that the role member can impersonate.", "type": "string" }, "type": "array" @@ -41669,12 +40382,14 @@ "oneOf": [ { "items": { + "description": "A base privilege that grants applies to all spaces.", "type": "string" }, "type": "array" }, { "items": { + "description": "A base privilege that applies to specific spaces.", "type": "string" }, "type": "array" @@ -41684,6 +40399,7 @@ "feature": { "additionalProperties": { "items": { + "description": "The privileges that the role member has for the feature.", "type": "string" }, "type": "array" @@ -41705,6 +40421,7 @@ }, { "items": { + "description": "A space that the privilege applies to.", "type": "string" }, "type": "array" @@ -41735,7 +40452,11 @@ } } }, - "responses": {}, + "responses": { + "204": { + "description": "Indicates a successful call." + } + }, "summary": "Create or update a role", "tags": [ "roles" @@ -41744,7 +40465,7 @@ }, "/api/security/roles": { "post": { - "operationId": "%2Fapi%2Fsecurity%2Froles#0", + "operationId": "post-security-roles", "parameters": [ { "description": "The version of the API to use", @@ -41780,6 +40501,7 @@ "additionalProperties": false, "properties": { "description": { + "description": "A description for the role.", "maxLength": 2048, "type": "string" }, @@ -41788,6 +40510,7 @@ "properties": { "cluster": { "items": { + "description": "Cluster privileges that define the cluster level actions that users can perform.", "type": "string" }, "type": "array" @@ -41797,11 +40520,13 @@ "additionalProperties": false, "properties": { "allow_restricted_indices": { + "description": "Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field covers the restricted indices too.", "type": "boolean" }, "field_security": { "additionalProperties": { "items": { + "description": "The document fields that the role members have read access to.", "type": "string" }, "type": "array" @@ -41810,6 +40535,7 @@ }, "names": { "items": { + "description": "The data streams, indices, and aliases to which the permissions in this entry apply. It supports wildcards (*).", "type": "string" }, "minItems": 1, @@ -41817,12 +40543,14 @@ }, "privileges": { "items": { + "description": "The index level privileges that the role members have for the data streams and indices.", "type": "string" }, "minItems": 1, "type": "array" }, "query": { + "description": "A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members.", "type": "string" } }, @@ -41840,6 +40568,7 @@ "properties": { "clusters": { "items": { + "description": "A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.", "type": "string" }, "minItems": 1, @@ -41847,6 +40576,7 @@ }, "privileges": { "items": { + "description": "The cluster level privileges for the remote cluster. The allowed values are a subset of the cluster privileges.", "type": "string" }, "minItems": 1, @@ -41866,10 +40596,12 @@ "additionalProperties": false, "properties": { "allow_restricted_indices": { + "description": "Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field will cover the restricted indices too.", "type": "boolean" }, "clusters": { "items": { + "description": "A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.", "type": "string" }, "minItems": 1, @@ -41878,6 +40610,7 @@ "field_security": { "additionalProperties": { "items": { + "description": "The document fields that the role members have read access to.", "type": "string" }, "type": "array" @@ -41886,6 +40619,7 @@ }, "names": { "items": { + "description": "A list of remote aliases, data streams, or indices to which the permissions apply. It supports wildcards (*).", "type": "string" }, "minItems": 1, @@ -41893,12 +40627,14 @@ }, "privileges": { "items": { + "description": "The index level privileges that role members have for the specified indices.", "type": "string" }, "minItems": 1, "type": "array" }, "query": { + "description": "A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members. ", "type": "string" } }, @@ -41913,6 +40649,7 @@ }, "run_as": { "items": { + "description": "A user name that the role member can impersonate.", "type": "string" }, "type": "array" @@ -41947,12 +40684,14 @@ "oneOf": [ { "items": { + "description": "A base privilege that grants applies to all spaces.", "type": "string" }, "type": "array" }, { "items": { + "description": "A base privilege that applies to specific spaces.", "type": "string" }, "type": "array" @@ -41962,6 +40701,7 @@ "feature": { "additionalProperties": { "items": { + "description": "The privileges that the role member has for the feature.", "type": "string" }, "type": "array" @@ -41983,6 +40723,7 @@ }, { "items": { + "description": "A space that the privilege applies to.", "type": "string" }, "type": "array" @@ -42021,7 +40762,11 @@ } } }, - "responses": {}, + "responses": { + "200": { + "description": "Indicates a successful call." + } + }, "summary": "Create or update roles", "tags": [ "roles" @@ -42030,7 +40775,7 @@ }, "/api/spaces/space": { "get": { - "operationId": "%2Fapi%2Fspaces%2Fspace#0", + "operationId": "get-spaces-space", "parameters": [ { "description": "The version of the API to use", @@ -42110,7 +40855,7 @@ ] }, "post": { - "operationId": "%2Fapi%2Fspaces%2Fspace#1", + "operationId": "post-spaces-space", "parameters": [ { "description": "The version of the API to use", @@ -42202,7 +40947,7 @@ "/api/spaces/space/{id}": { "delete": { "description": "When you delete a space, all saved objects that belong to the space are automatically deleted, which is permanent and cannot be undone.", - "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2", + "operationId": "delete-spaces-space-id", "parameters": [ { "description": "The version of the API to use", @@ -42250,7 +40995,7 @@ ] }, "get": { - "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0", + "operationId": "get-spaces-space-id", "parameters": [ { "description": "The version of the API to use", @@ -42285,7 +41030,7 @@ ] }, "put": { - "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1", + "operationId": "put-spaces-space-id", "parameters": [ { "description": "The version of the API to use", @@ -42385,7 +41130,7 @@ }, "/api/status": { "get": { - "operationId": "%2Fapi%2Fstatus#0", + "operationId": "get-status", "parameters": [ { "description": "The version of the API to use", diff --git a/oas_docs/examples/create_role_request1.yaml b/oas_docs/examples/create_role_request1.yaml new file mode 100644 index 0000000000000..1d041005f30de --- /dev/null +++ b/oas_docs/examples/create_role_request1.yaml @@ -0,0 +1,23 @@ +summary: Feature privileges in multiple spaces +description: Grant access to various features in some spaces. +value: + description: Grant full access to discover and dashboard features in the default space. Grant read access in the marketing, and sales spaces. + metadata: + version: 1 + elasticsearch: + cluster: [] + indices: [] + kibana: + - base: [] + feature: + discover: + - all + dashboard: + - all + spaces: + - default + - base: + - read + spaces: + - marketing + - sales diff --git a/oas_docs/examples/create_role_request2.yaml b/oas_docs/examples/create_role_request2.yaml new file mode 100644 index 0000000000000..d36d7e2330f3c --- /dev/null +++ b/oas_docs/examples/create_role_request2.yaml @@ -0,0 +1,16 @@ +summary: Dashboard privileges in a space +description: Grant access to dashboard features in a Marketing space. +value: + description: Grant dashboard access in the Marketing space. + metadata: + version: 1 + elasticsearch: + cluster: [] + indices: [] + kibana: + - base: [] + feature: + dashboard: + - read + spaces: + - marketing \ No newline at end of file diff --git a/oas_docs/examples/create_role_request3.yaml b/oas_docs/examples/create_role_request3.yaml new file mode 100644 index 0000000000000..55b4cb0834b9f --- /dev/null +++ b/oas_docs/examples/create_role_request3.yaml @@ -0,0 +1,14 @@ +summary: Feature privileges in a space +description: Grant full access to all features in the default space. +value: + metadata: + version: 1 + elasticsearch: + cluster: [] + indices: [] + kibana: + - base: + - all + feature: { } + spaces: + - default \ No newline at end of file diff --git a/oas_docs/examples/create_role_request4.yaml b/oas_docs/examples/create_role_request4.yaml new file mode 100644 index 0000000000000..f2332e2e934dc --- /dev/null +++ b/oas_docs/examples/create_role_request4.yaml @@ -0,0 +1,34 @@ +summary: Elasticsearch and Kibana feature privileges +description: Grant Elasticsearch and Kibana feature privileges. +value: + description: Grant all cluster privileges and full access to index1 and index2. Grant full access to remote_index1 and remote_index2, and the monitor_enrich cluster privilege on remote_cluster1. Grant all Kibana privileges in the default space. + metadata: + version: 1 + elasticsearch: + cluster: + - all + indices: + - names: + - index1 + - index2 + privileges: + - all + remote_indices: + - clusters: + - remote_cluster1 + names: + - remote_index1 + - remote_index2 + privileges: + - all + remote_cluster: + - clusters: + - remote_cluster1 + privileges: + - monitor_enrich + kibana: + - base: + - all + feature: { } + spaces: + - default \ No newline at end of file diff --git a/oas_docs/examples/get_role_response1.yaml b/oas_docs/examples/get_role_response1.yaml new file mode 100644 index 0000000000000..5e44481afa8ce --- /dev/null +++ b/oas_docs/examples/get_role_response1.yaml @@ -0,0 +1,41 @@ +summary: Get role details +value: + name: my_kibana_role + description: Grants all cluster privileges and full access to index1 and index2. Grants full access to remote_index1 and remote_index2, and the monitor_enrich cluster privilege on remote_cluster1. Grants all Kibana privileges in the default space. + metadata: + version: 1 + transient_metadata: + enabled: true + elasticsearch: + cluster: + - all + remote_cluster: + - privileges: + - monitor_enrich + clusters: + - remote_cluster1 + indices: + - names: + - index1 + - index2 + privileges: + - all + allow_restricted_indices: false + remote_indices: + - names: + - remote_index1 + - remote_index2 + privileges: + - all + allow_restricted_indices: false + clusters: + - remote_cluster1 + run_as: [] + kibana: + - base: + - all + feature: {} + spaces: + - default + _transform_error: [] + _unrecognized_applications: [] diff --git a/oas_docs/examples/get_roles_response1.yaml b/oas_docs/examples/get_roles_response1.yaml new file mode 100644 index 0000000000000..9c3a45163ace1 --- /dev/null +++ b/oas_docs/examples/get_roles_response1.yaml @@ -0,0 +1,39 @@ +summary: Get all role details +value: + - name: my_kibana_role + description: My kibana role description + metadata: + version: 1 + transient_metadata: + enabled: true + elasticsearch: + indices: [] + cluster: [] + run_as: [] + kibana: + - base: + - all + feature: {} + spaces: + - "*" + - name: my_admin_role + description: My admin role description + metadata: + version: 1 + transient_metadata: + enabled: true + elasticsearch: + cluster: + - all + indices: + - names: + - index1 + - index2 + privileges: + - all + field_security: + grant: + - title + - body + query: '{\"match\": {\"title\": \"foo\"}}' + kibana: [] \ No newline at end of file diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index 05f614ede3df7..afb7d8bbd5f4d 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -82,396 +82,10 @@ servers: - description: local url: http://localhost:5601 paths: - /api/actions: - get: - deprecated: true - operationId: '%2Fapi%2Factions#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - responses: {} - summary: Get all connectors - tags: - - connectors - /api/actions/action: - post: - deprecated: true - operationId: '%2Fapi%2Factions%2Faction#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - requestBody: - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - actionTypeId: - description: The connector type identifier. - type: string - config: - additionalProperties: {} - default: {} - type: object - name: - description: The display name for the connector. - type: string - secrets: - additionalProperties: {} - default: {} - type: object - required: - - name - - actionTypeId - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - type: object - connector_type_id: - description: The connector type identifier. - type: string - id: - description: The identifier for the connector. - type: string - is_deprecated: - description: Indicates whether the connector is deprecated. - type: boolean - is_missing_secrets: - description: Indicates whether the connector is missing secrets. - type: boolean - is_preconfigured: - description: >- - Indicates whether the connector is preconfigured. If true, - the `config` and `is_missing_secrets` properties are - omitted from the response. - type: boolean - is_system_action: - description: >- - Indicates whether the connector is used for system - actions. - type: boolean - name: - description: ' The name of the rule.' - type: string - required: - - id - - name - - connector_type_id - - is_preconfigured - - is_deprecated - - is_system_action - description: Indicates a successful call. - summary: Create a connector - tags: - - connectors - /api/actions/action/{id}: - delete: - deprecated: true - description: 'WARNING: When you delete a connector, it cannot be recovered.' - operationId: '%2Fapi%2Factions%2Faction%2F%7Bid%7D#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - - description: An identifier for the connector. - in: path - name: id - required: true - schema: - type: string - responses: - '204': - description: Indicates a successful call. - summary: Delete a connector - tags: - - connectors - get: - deprecated: true - operationId: '%2Fapi%2Factions%2Faction%2F%7Bid%7D#1' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: An identifier for the connector. - in: path - name: id - required: true - schema: - type: string - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - type: object - connector_type_id: - description: The connector type identifier. - type: string - id: - description: The identifier for the connector. - type: string - is_deprecated: - description: Indicates whether the connector is deprecated. - type: boolean - is_missing_secrets: - description: Indicates whether the connector is missing secrets. - type: boolean - is_preconfigured: - description: >- - Indicates whether the connector is preconfigured. If true, - the `config` and `is_missing_secrets` properties are - omitted from the response. - type: boolean - is_system_action: - description: >- - Indicates whether the connector is used for system - actions. - type: boolean - name: - description: ' The name of the rule.' - type: string - required: - - id - - name - - connector_type_id - - is_preconfigured - - is_deprecated - - is_system_action - description: Indicates a successful call. - summary: Get connector information - tags: - - connectors - put: - deprecated: true - operationId: '%2Fapi%2Factions%2Faction%2F%7Bid%7D#2' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - - description: An identifier for the connector. - in: path - name: id - required: true - schema: - type: string - requestBody: - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - default: {} - type: object - name: - type: string - secrets: - additionalProperties: {} - default: {} - type: object - required: - - name - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - type: object - connector_type_id: - description: The connector type identifier. - type: string - id: - description: The identifier for the connector. - type: string - is_deprecated: - description: Indicates whether the connector is deprecated. - type: boolean - is_missing_secrets: - description: Indicates whether the connector is missing secrets. - type: boolean - is_preconfigured: - description: >- - Indicates whether the connector is preconfigured. If true, - the `config` and `is_missing_secrets` properties are - omitted from the response. - type: boolean - is_system_action: - description: >- - Indicates whether the connector is used for system - actions. - type: boolean - name: - description: ' The name of the rule.' - type: string - required: - - id - - name - - connector_type_id - - is_preconfigured - - is_deprecated - - is_system_action - description: Indicates a successful call. - summary: Update a connector - tags: - - connectors - /api/actions/action/{id}/_execute: - post: - deprecated: true - operationId: '%2Fapi%2Factions%2Faction%2F%7Bid%7D%2F_execute#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - - description: An identifier for the connector. - in: path - name: id - required: true - schema: - type: string - requestBody: - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - params: - additionalProperties: {} - type: object - required: - - params - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - type: object - connector_type_id: - description: The connector type identifier. - type: string - id: - description: The identifier for the connector. - type: string - is_deprecated: - description: Indicates whether the connector is deprecated. - type: boolean - is_missing_secrets: - description: Indicates whether the connector is missing secrets. - type: boolean - is_preconfigured: - description: >- - Indicates whether the connector is preconfigured. If true, - the `config` and `is_missing_secrets` properties are - omitted from the response. - type: boolean - is_system_action: - description: >- - Indicates whether the connector is used for system - actions. - type: boolean - name: - description: ' The name of the rule.' - type: string - required: - - id - - name - - connector_type_id - - is_preconfigured - - is_deprecated - - is_system_action - description: Indicates a successful call. - summary: Run a connector - tags: - - connectors /api/actions/connector_types: get: description: You do not need any Kibana feature privileges to run this API. - operationId: '%2Fapi%2Factions%2Fconnector_types#0' + operationId: get-actions-connector-types parameters: - description: The version of the API to use in: header @@ -496,7 +110,7 @@ paths: /api/actions/connector/{id}: delete: description: 'WARNING: When you delete a connector, it cannot be recovered.' - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#0' + operationId: delete-actions-connector-id parameters: - description: The version of the API to use in: header @@ -526,7 +140,7 @@ paths: tags: - connectors get: - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#1' + operationId: get-actions-connector-id parameters: - description: The version of the API to use in: header @@ -591,7 +205,7 @@ paths: tags: - connectors post: - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%3F%7D#0' + operationId: post-actions-connector-id parameters: - description: The version of the API to use in: header @@ -687,7 +301,7 @@ paths: tags: - connectors put: - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#2' + operationId: put-actions-connector-id parameters: - description: The version of the API to use in: header @@ -783,7 +397,7 @@ paths: description: >- You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%7D%2F_execute#0' + operationId: post-actions-connector-id-execute parameters: - description: The version of the API to use in: header @@ -868,7 +482,7 @@ paths: - connectors /api/actions/connectors: get: - operationId: '%2Fapi%2Factions%2Fconnectors#0' + operationId: get-actions-connectors parameters: - description: The version of the API to use in: header @@ -882,26 +496,9 @@ paths: summary: Get all connectors tags: - connectors - /api/actions/list_action_types: - get: - deprecated: true - operationId: '%2Fapi%2Factions%2Flist_action_types#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - responses: {} - summary: Get connector types - tags: - - connectors /api/alerting/rule/{id}: delete: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D#2' + operationId: delete-alerting-rule-id parameters: - description: The version of the API to use in: header @@ -937,7 +534,7 @@ paths: tags: - alerting get: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D#0' + operationId: get-alerting-rule-id parameters: - description: The version of the API to use in: header @@ -1395,73 +992,14 @@ paths: description: Duration of the rule run. type: number outcome: - additionalProperties: false - type: object - properties: - alerts_count: - additionalProperties: false - type: object - properties: - active: - description: Number of active alerts during last run. - nullable: true - type: number - ignored: - description: >- - Number of ignored alerts during last - run. - nullable: true - type: number - new: - description: Number of new alerts during last run. - nullable: true - type: number - recovered: - description: >- - Number of recovered alerts during last - run. - nullable: true - type: number - outcome: - description: >- - Outcome of last run of the rule. Value - could be succeeded, warning or failed. - enum: - - succeeded - - warning - - failed - type: string - outcome_msg: - items: - description: >- - Outcome message generated during last - rule run. - type: string - nullable: true - type: array - outcome_order: - description: Order of the outcome. - type: number - warning: - description: Warning of last rule execution. - enum: - - read - - decrypt - - execute - - unknown - - license - - timeout - - disabled - - validate - - maxExecutableActions - - maxAlerts - - maxQueuedActions - - ruleExecution - nullable: true - type: string - required: - - outcome - - alerts_count + description: >- + Outcome of last run of the rule. Value could + be succeeded, warning or failed. + enum: + - succeeded + - warning + - failed + type: string success: description: >- Indicates whether the rule run was @@ -1609,11 +1147,13 @@ paths: items: description: Indicates hours of the day to recur. type: number + nullable: true type: array byminute: items: description: Indicates minutes of the hour to recur. type: number + nullable: true type: array bymonth: items: @@ -1621,16 +1161,19 @@ paths: Indicates months of the year that this rule should recur. type: number + nullable: true type: array bymonthday: items: description: Indicates the days of the month to recur. type: number + nullable: true type: array bysecond: items: description: Indicates seconds of the day to recur. type: number + nullable: true type: array bysetpos: items: @@ -1641,6 +1184,7 @@ paths: of the month. It is recommended to not set this manually and just use `byweekday`. type: number + nullable: true type: array byweekday: items: @@ -1654,11 +1198,13 @@ paths: Friday of the month, which are internally converted to a `byweekday/bysetpos` combination. + nullable: true type: array byweekno: items: description: Indicates number of the week hours to recur. type: number + nullable: true type: array byyearday: items: @@ -1666,6 +1212,7 @@ paths: Indicates the days of the year that this rule should recur. type: number + nullable: true type: array count: description: >- @@ -1785,7 +1332,7 @@ paths: tags: - alerting post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%3F%7D#0' + operationId: post-alerting-rule-id parameters: - description: The version of the API to use in: header @@ -2568,73 +2115,14 @@ paths: description: Duration of the rule run. type: number outcome: - additionalProperties: false - type: object - properties: - alerts_count: - additionalProperties: false - type: object - properties: - active: - description: Number of active alerts during last run. - nullable: true - type: number - ignored: - description: >- - Number of ignored alerts during last - run. - nullable: true - type: number - new: - description: Number of new alerts during last run. - nullable: true - type: number - recovered: - description: >- - Number of recovered alerts during last - run. - nullable: true - type: number - outcome: - description: >- - Outcome of last run of the rule. Value - could be succeeded, warning or failed. - enum: - - succeeded - - warning - - failed - type: string - outcome_msg: - items: - description: >- - Outcome message generated during last - rule run. - type: string - nullable: true - type: array - outcome_order: - description: Order of the outcome. - type: number - warning: - description: Warning of last rule execution. - enum: - - read - - decrypt - - execute - - unknown - - license - - timeout - - disabled - - validate - - maxExecutableActions - - maxAlerts - - maxQueuedActions - - ruleExecution - nullable: true - type: string - required: - - outcome - - alerts_count + description: >- + Outcome of last run of the rule. Value could + be succeeded, warning or failed. + enum: + - succeeded + - warning + - failed + type: string success: description: >- Indicates whether the rule run was @@ -2782,11 +2270,13 @@ paths: items: description: Indicates hours of the day to recur. type: number + nullable: true type: array byminute: items: description: Indicates minutes of the hour to recur. type: number + nullable: true type: array bymonth: items: @@ -2794,16 +2284,19 @@ paths: Indicates months of the year that this rule should recur. type: number + nullable: true type: array bymonthday: items: description: Indicates the days of the month to recur. type: number + nullable: true type: array bysecond: items: description: Indicates seconds of the day to recur. type: number + nullable: true type: array bysetpos: items: @@ -2814,6 +2307,7 @@ paths: of the month. It is recommended to not set this manually and just use `byweekday`. type: number + nullable: true type: array byweekday: items: @@ -2827,11 +2321,13 @@ paths: Friday of the month, which are internally converted to a `byweekday/bysetpos` combination. + nullable: true type: array byweekno: items: description: Indicates number of the week hours to recur. type: number + nullable: true type: array byyearday: items: @@ -2839,6 +2335,7 @@ paths: Indicates the days of the year that this rule should recur. type: number + nullable: true type: array count: description: >- @@ -2958,7 +2455,7 @@ paths: tags: - alerting put: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D#1' + operationId: put-alerting-rule-id parameters: - description: The version of the API to use in: header @@ -3712,73 +3209,14 @@ paths: description: Duration of the rule run. type: number outcome: - additionalProperties: false - type: object - properties: - alerts_count: - additionalProperties: false - type: object - properties: - active: - description: Number of active alerts during last run. - nullable: true - type: number - ignored: - description: >- - Number of ignored alerts during last - run. - nullable: true - type: number - new: - description: Number of new alerts during last run. - nullable: true - type: number - recovered: - description: >- - Number of recovered alerts during last - run. - nullable: true - type: number - outcome: - description: >- - Outcome of last run of the rule. Value - could be succeeded, warning or failed. - enum: - - succeeded - - warning - - failed - type: string - outcome_msg: - items: - description: >- - Outcome message generated during last - rule run. - type: string - nullable: true - type: array - outcome_order: - description: Order of the outcome. - type: number - warning: - description: Warning of last rule execution. - enum: - - read - - decrypt - - execute - - unknown - - license - - timeout - - disabled - - validate - - maxExecutableActions - - maxAlerts - - maxQueuedActions - - ruleExecution - nullable: true - type: string - required: - - outcome - - alerts_count + description: >- + Outcome of last run of the rule. Value could + be succeeded, warning or failed. + enum: + - succeeded + - warning + - failed + type: string success: description: >- Indicates whether the rule run was @@ -3926,11 +3364,13 @@ paths: items: description: Indicates hours of the day to recur. type: number + nullable: true type: array byminute: items: description: Indicates minutes of the hour to recur. type: number + nullable: true type: array bymonth: items: @@ -3938,16 +3378,19 @@ paths: Indicates months of the year that this rule should recur. type: number + nullable: true type: array bymonthday: items: description: Indicates the days of the month to recur. type: number + nullable: true type: array bysecond: items: description: Indicates seconds of the day to recur. type: number + nullable: true type: array bysetpos: items: @@ -3958,6 +3401,7 @@ paths: of the month. It is recommended to not set this manually and just use `byweekday`. type: number + nullable: true type: array byweekday: items: @@ -3971,11 +3415,13 @@ paths: Friday of the month, which are internally converted to a `byweekday/bysetpos` combination. + nullable: true type: array byweekno: items: description: Indicates number of the week hours to recur. type: number + nullable: true type: array byyearday: items: @@ -3983,6 +3429,7 @@ paths: Indicates the days of the year that this rule should recur. type: number + nullable: true type: array count: description: >- @@ -4105,7 +3552,7 @@ paths: - alerting /api/alerting/rule/{id}/_disable: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_disable#0' + operationId: post-alerting-rule-id-disable parameters: - description: The version of the API to use in: header @@ -4154,7 +3601,7 @@ paths: - alerting /api/alerting/rule/{id}/_enable: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_enable#0' + operationId: post-alerting-rule-id-enable parameters: - description: The version of the API to use in: header @@ -4191,7 +3638,7 @@ paths: - alerting /api/alerting/rule/{id}/_mute_all: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_mute_all#0' + operationId: post-alerting-rule-id-mute-all parameters: - description: The version of the API to use in: header @@ -4228,7 +3675,7 @@ paths: - alerting /api/alerting/rule/{id}/_unmute_all: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_unmute_all#0' + operationId: post-alerting-rule-id-unmute-all parameters: - description: The version of the API to use in: header @@ -4265,7 +3712,7 @@ paths: - alerting /api/alerting/rule/{id}/_update_api_key: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_update_api_key#0' + operationId: post-alerting-rule-id-update-api-key parameters: - description: The version of the API to use in: header @@ -4304,8 +3751,7 @@ paths: - alerting /api/alerting/rule/{rule_id}/alert/{alert_id}/_mute: post: - operationId: >- - %2Fapi%2Falerting%2Frule%2F%7Brule_id%7D%2Falert%2F%7Balert_id%7D%2F_mute#0 + operationId: post-alerting-rule-rule-id-alert-alert-id-mute parameters: - description: The version of the API to use in: header @@ -4348,8 +3794,7 @@ paths: - alerting /api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute: post: - operationId: >- - %2Fapi%2Falerting%2Frule%2F%7Brule_id%7D%2Falert%2F%7Balert_id%7D%2F_unmute#0 + operationId: post-alerting-rule-rule-id-alert-alert-id-unmute parameters: - description: The version of the API to use in: header @@ -4392,7 +3837,7 @@ paths: - alerting /api/alerting/rules/_find: get: - operationId: '%2Fapi%2Falerting%2Frules%2F_find#0' + operationId: get-alerting-rules-find parameters: - description: The version of the API to use in: header @@ -4950,73 +4395,14 @@ paths: description: Duration of the rule run. type: number outcome: - additionalProperties: false - type: object - properties: - alerts_count: - additionalProperties: false - type: object - properties: - active: - description: Number of active alerts during last run. - nullable: true - type: number - ignored: - description: >- - Number of ignored alerts during last - run. - nullable: true - type: number - new: - description: Number of new alerts during last run. - nullable: true - type: number - recovered: - description: >- - Number of recovered alerts during last - run. - nullable: true - type: number - outcome: - description: >- - Outcome of last run of the rule. Value - could be succeeded, warning or failed. - enum: - - succeeded - - warning - - failed - type: string - outcome_msg: - items: - description: >- - Outcome message generated during last - rule run. - type: string - nullable: true - type: array - outcome_order: - description: Order of the outcome. - type: number - warning: - description: Warning of last rule execution. - enum: - - read - - decrypt - - execute - - unknown - - license - - timeout - - disabled - - validate - - maxExecutableActions - - maxAlerts - - maxQueuedActions - - ruleExecution - nullable: true - type: string - required: - - outcome - - alerts_count + description: >- + Outcome of last run of the rule. Value could + be succeeded, warning or failed. + enum: + - succeeded + - warning + - failed + type: string success: description: >- Indicates whether the rule run was @@ -5164,11 +4550,13 @@ paths: items: description: Indicates hours of the day to recur. type: number + nullable: true type: array byminute: items: description: Indicates minutes of the hour to recur. type: number + nullable: true type: array bymonth: items: @@ -5176,16 +4564,19 @@ paths: Indicates months of the year that this rule should recur. type: number + nullable: true type: array bymonthday: items: description: Indicates the days of the month to recur. type: number + nullable: true type: array bysecond: items: description: Indicates seconds of the day to recur. type: number + nullable: true type: array bysetpos: items: @@ -5196,6 +4587,7 @@ paths: of the month. It is recommended to not set this manually and just use `byweekday`. type: number + nullable: true type: array byweekday: items: @@ -5209,11 +4601,13 @@ paths: Friday of the month, which are internally converted to a `byweekday/bysetpos` combination. + nullable: true type: array byweekno: items: description: Indicates number of the week hours to recur. type: number + nullable: true type: array byyearday: items: @@ -5221,6 +4615,7 @@ paths: Indicates the days of the year that this rule should recur. type: number + nullable: true type: array count: description: >- @@ -5341,49 +4736,110 @@ paths: post: description: Create a new agent key for APM. operationId: createAgentKey + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' requestBody: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - name: - type: string - privileges: - items: - enum: - - event:write - - config_agent:read - type: string - type: array + $ref: '#/components/schemas/APM_UI_agent_keys_object' required: true responses: '200': content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - api_key: - type: string - encoded: - type: string - expiration: - format: int64 - type: integer - id: - type: string - name: - type: string + $ref: '#/components/schemas/APM_UI_agent_keys_response' description: Agent key created successfully + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response summary: Create an APM agent key tags: - APM agent keys + /api/apm/fleet/apm_server_schema: + post: + operationId: saveApmServerSchema + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + type: object + properties: + schema: + additionalProperties: true + description: Schema object + example: + foo: bar + type: object + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Save APM server schema + tags: + - APM server schema /api/apm/services/{serviceName}/annotation: post: description: Create a new annotation for a specific service. operationId: createAnnotation parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' - description: The name of the service in: path name: serviceName @@ -5394,63 +4850,39 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - '@timestamp': - type: string - message: - type: string - service: - type: object - properties: - environment: - type: string - version: - type: string - tags: - items: - type: string - type: array + $ref: '#/components/schemas/APM_UI_create_annotation_object' required: true responses: '200': content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - _id: - type: string - _index: - type: string - _source: - type: object - properties: - '@timestamp': - type: string - annotation: - type: string - event: - type: object - properties: - created: - type: string - message: - type: string - service: - type: object - properties: - environment: - type: string - name: - type: string - version: - type: string - tags: - items: - type: string - type: array + $ref: '#/components/schemas/APM_UI_create_annotation_response' description: Annotation created successfully + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response summary: Create a service annotation tags: - APM annotations @@ -5459,6 +4891,7 @@ paths: description: Search for annotations related to a specific service. operationId: getAnnotation parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' - description: The name of the service in: path name: serviceName @@ -5488,27 +4921,484 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - annotations: - items: - type: object - properties: - '@timestamp': - type: number - id: - type: string - text: - type: string - type: - enum: - - version - type: string - type: array + $ref: '#/components/schemas/APM_UI_annotation_search_response' description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response summary: Search for annotations tags: - APM annotations + /api/apm/settings/agent-configuration: + delete: + operationId: deleteAgentConfiguration + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_service_object' + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: >- + #/components/schemas/APM_UI_delete_agent_configurations_response + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Delete agent configuration + tags: + - APM agent configuration + get: + operationId: getAgentConfigurations + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_agent_configurations_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Get a list of agent configurations + tags: + - APM agent configuration + put: + operationId: createUpdateAgentConfiguration + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + - description: If the config exists ?overwrite=true is required + in: query + name: overwrite + schema: + type: boolean + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_agent_configuration_intake_object' + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Create or update agent configuration + tags: + - APM agent configuration + /api/apm/settings/agent-configuration/agent_name: + get: + description: Retrieve `agentName` for a service. + operationId: getAgentNameForService + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - description: The name of the service + example: node + in: query + name: serviceName + required: true + schema: + type: string + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_service_agent_name_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Get agent name for service + tags: + - APM agent configuration + /api/apm/settings/agent-configuration/environments: + get: + operationId: getEnvironmentsForService + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - description: The name of the service + in: query + name: serviceName + schema: + type: string + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_service_environments_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Get environments for service + tags: + - APM agent configuration + /api/apm/settings/agent-configuration/search: + post: + description: > + This endpoint allows to search for single agent configuration and update + 'applied_by_agent' field. + operationId: searchSingleConfiguration + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_search_agent_configuration_object' + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: >- + #/components/schemas/APM_UI_search_agent_configuration_response + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Lookup single agent configuration + tags: + - APM agent configuration + /api/apm/settings/agent-configuration/view: + get: + operationId: getSingleAgentConfiguration + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - description: Service name + example: node + in: query + name: name + schema: + type: string + - description: Service environment + example: prod + in: query + name: environment + schema: + type: string + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: >- + #/components/schemas/APM_UI_single_agent_configuration_response + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Get single agent configuration + tags: + - APM agent configuration + /api/apm/sourcemaps: + get: + description: Returns an array of Fleet artifacts, including source map uploads. + operationId: getSourceMaps + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - description: Page number + in: query + name: page + schema: + type: number + - description: Number of records per page + in: query + name: perPage + schema: + type: number + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_source_maps_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response + '501': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_501_response' + description: Not Implemented response + summary: Get source maps + tags: + - APM sourcemaps + post: + description: Upload a source map for a specific service and version. + operationId: uploadSourceMap + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + requestBody: + content: + multipart/form-data; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_upload_source_map_object' + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_upload_source_maps_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response + '501': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_501_response' + description: Not Implemented response + summary: Upload source map + tags: + - APM sourcemaps + /api/apm/sourcemaps/{id}: + delete: + description: Delete a previously uploaded source map. + operationId: deleteSourceMap + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + - description: Source map identifier + in: path + name: id + required: true + schema: + type: string + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response + '501': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_501_response' + description: Not Implemented response + summary: Delete source map + tags: + - APM sourcemaps /api/asset_criticality: delete: description: Delete the asset criticality record for a specific entity. @@ -9981,7 +9871,7 @@ paths: /api/fleet/agent_download_sources: get: description: List agent binary download sources - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources#0' + operationId: get-fleet-agent-download-sources parameters: - description: The version of the API to use in: header @@ -10057,7 +9947,7 @@ paths: - Elastic Agent binary download sources post: description: Create agent binary download source - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources#1' + operationId: post-fleet-agent-download-sources parameters: - description: The version of the API to use in: header @@ -10156,7 +10046,7 @@ paths: /api/fleet/agent_download_sources/{sourceId}: delete: description: Delete agent binary download source by ID - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#2' + operationId: delete-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use in: header @@ -10211,7 +10101,7 @@ paths: - Elastic Agent binary download sources get: description: Get agent binary download source by ID - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#0' + operationId: get-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use in: header @@ -10281,7 +10171,7 @@ paths: - Elastic Agent binary download sources put: description: Update agent binary download source by ID - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#1' + operationId: put-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use in: header @@ -10385,7 +10275,7 @@ paths: /api/fleet/agent_policies: get: description: List agent policies - operationId: '%2Fapi%2Ffleet%2Fagent_policies#0' + operationId: get-fleet-agent-policies parameters: - description: The version of the API to use in: header @@ -10999,7 +10889,7 @@ paths: - Elastic Agent policies post: description: Create an agent policy - operationId: '%2Fapi%2Ffleet%2Fagent_policies#1' + operationId: post-fleet-agent-policies parameters: - description: The version of the API to use in: header @@ -11734,7 +11624,7 @@ paths: /api/fleet/agent_policies/_bulk_get: post: description: Bulk get agent policies - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F_bulk_get#0' + operationId: post-fleet-agent-policies-bulk-get parameters: - description: The version of the API to use in: header @@ -12314,7 +12204,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}: get: description: Get an agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D#0' + operationId: get-fleet-agent-policies-agentpolicyid parameters: - description: The version of the API to use in: header @@ -12870,7 +12760,7 @@ paths: - Elastic Agent policies put: description: Update an agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D#1' + operationId: put-fleet-agent-policies-agentpolicyid parameters: - description: The version of the API to use in: header @@ -13613,7 +13503,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}/copy: post: description: Copy an agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Fcopy#0' + operationId: post-fleet-agent-policies-agentpolicyid-copy parameters: - description: The version of the API to use in: header @@ -14191,7 +14081,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}/download: get: description: Download an agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Fdownload#0' + operationId: get-fleet-agent-policies-agentpolicyid-download parameters: - description: The version of the API to use in: header @@ -14265,7 +14155,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}/full: get: description: Get a full agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Ffull#0' + operationId: get-fleet-agent-policies-agentpolicyid-full parameters: - description: The version of the API to use in: header @@ -14597,7 +14487,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}/outputs: get: description: Get list of outputs associated with agent policy by policy id - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Foutputs#0' + operationId: get-fleet-agent-policies-agentpolicyid-outputs parameters: - description: The version of the API to use in: header @@ -14701,7 +14591,7 @@ paths: /api/fleet/agent_policies/delete: post: description: Delete agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2Fdelete#0' + operationId: post-fleet-agent-policies-delete parameters: - description: The version of the API to use in: header @@ -14771,7 +14661,7 @@ paths: /api/fleet/agent_policies/outputs: post: description: Get list of outputs associated with agent policies - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2Foutputs#0' + operationId: post-fleet-agent-policies-outputs parameters: - description: The version of the API to use in: header @@ -14893,7 +14783,7 @@ paths: /api/fleet/agent_status: get: description: Get agent status summary - operationId: '%2Fapi%2Ffleet%2Fagent_status#0' + operationId: get-fleet-agent-status parameters: - description: The version of the API to use in: header @@ -14921,7 +14811,6 @@ paths: name: kuery required: false schema: - deprecated: true type: string responses: '200': @@ -14951,16 +14840,12 @@ paths: type: number other: type: number - total: - deprecated: true - type: number unenrolled: type: number updating: type: number required: - events - - total - online - error - offline @@ -14994,7 +14879,7 @@ paths: /api/fleet/agent_status/data: get: description: Get incoming agent data - operationId: '%2Fapi%2Ffleet%2Fagent_status%2Fdata#0' + operationId: get-fleet-agent-status-data parameters: - description: The version of the API to use in: header @@ -15064,45 +14949,10 @@ paths: summary: '' tags: - Elastic Agents - /api/fleet/agent-status: - get: - operationId: '%2Fapi%2Ffleet%2Fagent-status#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - in: query - name: policyId - required: false - schema: - type: string - - in: query - name: policyIds - required: false - schema: - anyOf: - - items: - type: string - type: array - - type: string - - in: query - name: kuery - required: false - schema: - deprecated: true - type: string - responses: {} - summary: '' - tags: [] /api/fleet/agents: get: description: List agents - operationId: '%2Fapi%2Ffleet%2Fagents#0' + operationId: get-fleet-agents parameters: - description: The version of the API to use in: header @@ -15452,285 +15302,6 @@ paths: - enrolled_at - local_metadata type: array - list: - deprecated: true - items: - additionalProperties: false - type: object - properties: - access_api_key: - type: string - access_api_key_id: - type: string - active: - type: boolean - agent: - additionalProperties: true - type: object - properties: - id: - type: string - version: - type: string - required: - - id - - version - components: - items: - additionalProperties: false - type: object - properties: - id: - type: string - message: - type: string - status: - enum: - - STARTING - - CONFIGURING - - HEALTHY - - DEGRADED - - FAILED - - STOPPING - - STOPPED - type: string - type: - type: string - units: - items: - additionalProperties: false - type: object - properties: - id: - type: string - message: - type: string - payload: - additionalProperties: {} - type: object - status: - enum: - - STARTING - - CONFIGURING - - HEALTHY - - DEGRADED - - FAILED - - STOPPING - - STOPPED - type: string - type: - enum: - - input - - output - type: string - required: - - id - - type - - status - - message - type: array - required: - - id - - type - - status - - message - type: array - default_api_key: - type: string - default_api_key_history: - items: - additionalProperties: false - deprecated: true - type: object - properties: - id: - type: string - retired_at: - type: string - required: - - id - - retired_at - type: array - default_api_key_id: - type: string - enrolled_at: - type: string - id: - type: string - last_checkin: - type: string - last_checkin_message: - type: string - last_checkin_status: - enum: - - error - - online - - degraded - - updating - - starting - type: string - local_metadata: - additionalProperties: {} - type: object - metrics: - additionalProperties: false - type: object - properties: - cpu_avg: - type: number - memory_size_byte_avg: - type: number - namespaces: - items: - type: string - type: array - outputs: - additionalProperties: - additionalProperties: false - type: object - properties: - api_key_id: - type: string - to_retire_api_key_ids: - items: - additionalProperties: false - type: object - properties: - id: - type: string - retired_at: - type: string - required: - - id - - retired_at - type: array - type: - type: string - required: - - api_key_id - - type - type: object - packages: - items: - type: string - type: array - policy_id: - type: string - policy_revision: - nullable: true - type: number - sort: - items: - anyOf: - - type: number - - type: string - - enum: [] - nullable: true - type: array - status: - enum: - - offline - - error - - online - - inactive - - enrolling - - unenrolling - - unenrolled - - updating - - degraded - type: string - tags: - items: - type: string - type: array - type: - enum: - - PERMANENT - - EPHEMERAL - - TEMPORARY - type: string - unenrolled_at: - type: string - unenrollment_started_at: - type: string - unhealthy_reason: - items: - enum: - - input - - output - - other - type: string - nullable: true - type: array - upgrade_details: - additionalProperties: false - type: object - properties: - action_id: - type: string - metadata: - additionalProperties: false - type: object - properties: - download_percent: - type: number - download_rate: - type: number - error_msg: - type: string - failed_state: - enum: - - UPG_REQUESTED - - UPG_SCHEDULED - - UPG_DOWNLOADING - - UPG_EXTRACTING - - UPG_REPLACING - - UPG_RESTARTING - - UPG_FAILED - - UPG_WATCHING - - UPG_ROLLBACK - type: string - retry_error_msg: - type: string - retry_until: - type: string - scheduled_at: - type: string - state: - enum: - - UPG_REQUESTED - - UPG_SCHEDULED - - UPG_DOWNLOADING - - UPG_EXTRACTING - - UPG_REPLACING - - UPG_RESTARTING - - UPG_FAILED - - UPG_WATCHING - - UPG_ROLLBACK - type: string - target_version: - type: string - required: - - target_version - - action_id - - state - upgrade_started_at: - nullable: true - type: string - upgraded_at: - nullable: true - type: string - user_provided_metadata: - additionalProperties: {} - type: object - required: - - id - - packages - - type - - active - - enrolled_at - - local_metadata - type: array page: type: number perPage: @@ -15767,7 +15338,7 @@ paths: - Elastic Agents post: description: List agents by action ids - operationId: '%2Fapi%2Ffleet%2Fagents#1' + operationId: post-fleet-agents parameters: - description: The version of the API to use in: header @@ -15833,7 +15404,7 @@ paths: /api/fleet/agents/{agentId}: delete: description: Delete agent by ID - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#2' + operationId: delete-fleet-agents-agentid parameters: - description: The version of the API to use in: header @@ -15890,7 +15461,7 @@ paths: - Elastic Agents get: description: Get agent by ID - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#0' + operationId: get-fleet-agents-agentid parameters: - description: The version of the API to use in: header @@ -16218,7 +15789,7 @@ paths: - Elastic Agents put: description: Update agent by ID - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#1' + operationId: put-fleet-agents-agentid parameters: - description: The version of the API to use in: header @@ -16562,7 +16133,7 @@ paths: /api/fleet/agents/{agentId}/actions: post: description: Create agent action - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Factions#0' + operationId: post-fleet-agents-agentid-actions parameters: - description: The version of the API to use in: header @@ -16707,7 +16278,7 @@ paths: /api/fleet/agents/{agentId}/reassign: post: description: Reassign agent - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Freassign#1' + operationId: post-fleet-agents-agentid-reassign parameters: - description: The version of the API to use in: header @@ -16767,47 +16338,10 @@ paths: summary: '' tags: - Elastic Agent actions - put: - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Freassign#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - - in: path - name: agentId - required: true - schema: - type: string - requestBody: - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - policy_id: - type: string - required: - - policy_id - responses: {} - summary: '' - tags: [] /api/fleet/agents/{agentId}/request_diagnostics: post: description: Request agent diagnostics - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Frequest_diagnostics#0' + operationId: post-fleet-agents-agentid-request-diagnostics parameters: - description: The version of the API to use in: header @@ -16877,7 +16411,7 @@ paths: /api/fleet/agents/{agentId}/unenroll: post: description: Unenroll agent - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Funenroll#0' + operationId: post-fleet-agents-agentid-unenroll parameters: - description: The version of the API to use in: header @@ -16918,7 +16452,7 @@ paths: /api/fleet/agents/{agentId}/upgrade: post: description: Upgrade agent - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Fupgrade#0' + operationId: post-fleet-agents-agentid-upgrade parameters: - description: The version of the API to use in: header @@ -16987,7 +16521,7 @@ paths: /api/fleet/agents/{agentId}/uploads: get: description: List agent uploads - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Fuploads#0' + operationId: get-fleet-agents-agentid-uploads parameters: - description: The version of the API to use in: header @@ -17068,7 +16602,7 @@ paths: /api/fleet/agents/action_status: get: description: Get agent action status - operationId: '%2Fapi%2Ffleet%2Fagents%2Faction_status#0' + operationId: get-fleet-agents-action-status parameters: - description: The version of the API to use in: header @@ -17236,7 +16770,7 @@ paths: /api/fleet/agents/actions/{actionId}/cancel: post: description: Cancel agent action - operationId: '%2Fapi%2Ffleet%2Fagents%2Factions%2F%7BactionId%7D%2Fcancel#0' + operationId: post-fleet-agents-actions-actionid-cancel parameters: - description: The version of the API to use in: header @@ -17331,7 +16865,7 @@ paths: /api/fleet/agents/available_versions: get: description: Get available agent versions - operationId: '%2Fapi%2Ffleet%2Fagents%2Favailable_versions#0' + operationId: get-fleet-agents-available-versions parameters: - description: The version of the API to use in: header @@ -17377,7 +16911,7 @@ paths: /api/fleet/agents/bulk_reassign: post: description: Bulk reassign agents - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_reassign#0' + operationId: post-fleet-agents-bulk-reassign parameters: - description: The version of the API to use in: header @@ -17451,7 +16985,7 @@ paths: /api/fleet/agents/bulk_request_diagnostics: post: description: Bulk request diagnostics from agents - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_request_diagnostics#0' + operationId: post-fleet-agents-bulk-request-diagnostics parameters: - description: The version of the API to use in: header @@ -17525,7 +17059,7 @@ paths: /api/fleet/agents/bulk_unenroll: post: description: Bulk unenroll agents - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_unenroll#0' + operationId: post-fleet-agents-bulk-unenroll parameters: - description: The version of the API to use in: header @@ -17606,7 +17140,7 @@ paths: /api/fleet/agents/bulk_update_agent_tags: post: description: Bulk update agent tags - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_update_agent_tags#0' + operationId: post-fleet-agents-bulk-update-agent-tags parameters: - description: The version of the API to use in: header @@ -17685,7 +17219,7 @@ paths: /api/fleet/agents/bulk_upgrade: post: description: Bulk upgrade agents - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_upgrade#0' + operationId: post-fleet-agents-bulk-upgrade parameters: - description: The version of the API to use in: header @@ -17770,7 +17304,7 @@ paths: /api/fleet/agents/files/{fileId}: delete: description: Delete file uploaded by agent - operationId: '%2Fapi%2Ffleet%2Fagents%2Ffiles%2F%7BfileId%7D#0' + operationId: delete-fleet-agents-files-fileid parameters: - description: The version of the API to use in: header @@ -17829,7 +17363,7 @@ paths: /api/fleet/agents/files/{fileId}/{fileName}: get: description: Get file uploaded by agent - operationId: '%2Fapi%2Ffleet%2Fagents%2Ffiles%2F%7BfileId%7D%2F%7BfileName%7D#0' + operationId: get-fleet-agents-files-fileid-filename parameters: - description: The version of the API to use in: header @@ -17877,7 +17411,7 @@ paths: /api/fleet/agents/setup: get: description: Get agent setup info - operationId: '%2Fapi%2Ffleet%2Fagents%2Fsetup#0' + operationId: get-fleet-agents-setup parameters: - description: The version of the API to use in: header @@ -17948,7 +17482,7 @@ paths: - Elastic Agents post: description: Initiate agent setup - operationId: '%2Fapi%2Ffleet%2Fagents%2Fsetup#1' + operationId: post-fleet-agents-setup parameters: - description: The version of the API to use in: header @@ -18018,7 +17552,7 @@ paths: /api/fleet/agents/tags: get: description: List agent tags - operationId: '%2Fapi%2Ffleet%2Fagents%2Ftags#0' + operationId: get-fleet-agents-tags parameters: - description: The version of the API to use in: header @@ -18075,7 +17609,7 @@ paths: /api/fleet/check-permissions: get: description: Check permissions - operationId: '%2Fapi%2Ffleet%2Fcheck-permissions#0' + operationId: get-fleet-check-permissions parameters: - description: The version of the API to use in: header @@ -18130,7 +17664,7 @@ paths: /api/fleet/data_streams: get: description: List data streams - operationId: '%2Fapi%2Ffleet%2Fdata_streams#0' + operationId: get-fleet-data-streams parameters: - description: The version of the API to use in: header @@ -18235,7 +17769,7 @@ paths: /api/fleet/enrollment_api_keys: get: description: List enrollment API keys - operationId: '%2Fapi%2Ffleet%2Fenrollment_api_keys#0' + operationId: get-fleet-enrollment-api-keys parameters: - description: The version of the API to use in: header @@ -18378,7 +17912,7 @@ paths: - Fleet enrollment API keys post: description: Create enrollment API key - operationId: '%2Fapi%2Ffleet%2Fenrollment_api_keys#1' + operationId: post-fleet-enrollment-api-keys parameters: - description: The version of the API to use in: header @@ -18482,7 +18016,7 @@ paths: /api/fleet/enrollment_api_keys/{keyId}: delete: description: Revoke enrollment API key by ID by marking it as inactive - operationId: '%2Fapi%2Ffleet%2Fenrollment_api_keys%2F%7BkeyId%7D#1' + operationId: delete-fleet-enrollment-api-keys-keyid parameters: - description: The version of the API to use in: header @@ -18539,7 +18073,7 @@ paths: - Fleet enrollment API keys get: description: Get enrollment API key by ID - operationId: '%2Fapi%2Ffleet%2Fenrollment_api_keys%2F%7BkeyId%7D#0' + operationId: get-fleet-enrollment-api-keys-keyid parameters: - description: The version of the API to use in: header @@ -18620,7 +18154,7 @@ paths: - Fleet enrollment API keys /api/fleet/enrollment-api-keys: get: - operationId: '%2Fapi%2Ffleet%2Fenrollment-api-keys#0' + operationId: get-fleet-enrollment-api-keys-2 parameters: - description: The version of the API to use in: header @@ -18651,7 +18185,7 @@ paths: summary: '' tags: [] post: - operationId: '%2Fapi%2Ffleet%2Fenrollment-api-keys#1' + operationId: post-fleet-enrollment-api-keys-2 parameters: - description: The version of the API to use in: header @@ -18688,7 +18222,7 @@ paths: tags: [] /api/fleet/enrollment-api-keys/{keyId}: delete: - operationId: '%2Fapi%2Ffleet%2Fenrollment-api-keys%2F%7BkeyId%7D#1' + operationId: delete-fleet-enrollment-api-keys-keyid-2 parameters: - description: The version of the API to use in: header @@ -18714,7 +18248,7 @@ paths: summary: '' tags: [] get: - operationId: '%2Fapi%2Ffleet%2Fenrollment-api-keys%2F%7BkeyId%7D#0' + operationId: get-fleet-enrollment-api-keys-keyid-2 parameters: - description: The version of the API to use in: header @@ -18735,7 +18269,7 @@ paths: /api/fleet/epm/bulk_assets: post: description: Bulk get assets - operationId: '%2Fapi%2Ffleet%2Fepm%2Fbulk_assets#0' + operationId: post-fleet-epm-bulk-assets parameters: - description: The version of the API to use in: header @@ -18834,7 +18368,7 @@ paths: /api/fleet/epm/categories: get: description: List package categories - operationId: '%2Fapi%2Ffleet%2Fepm%2Fcategories#0' + operationId: get-fleet-epm-categories parameters: - description: The version of the API to use in: header @@ -18932,7 +18466,7 @@ paths: /api/fleet/epm/custom_integrations: post: description: Create custom integration - operationId: '%2Fapi%2Ffleet%2Fepm%2Fcustom_integrations#0' + operationId: post-fleet-epm-custom-integrations parameters: - description: The version of the API to use in: header @@ -19128,7 +18662,7 @@ paths: /api/fleet/epm/data_streams: get: description: List data streams - operationId: '%2Fapi%2Ffleet%2Fepm%2Fdata_streams#0' + operationId: get-fleet-epm-data-streams parameters: - description: The version of the API to use in: header @@ -19211,7 +18745,7 @@ paths: /api/fleet/epm/packages: get: description: List packages - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages#0' + operationId: get-fleet-epm-packages parameters: - description: The version of the API to use in: header @@ -19965,7 +19499,7 @@ paths: - Elastic Package Manager (EPM) post: description: Install package by upload - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages#1' + operationId: post-fleet-epm-packages parameters: - description: The version of the API to use in: header @@ -20146,7 +19680,7 @@ paths: /api/fleet/epm/packages/_bulk: post: description: Bulk install packages - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F_bulk#0' + operationId: post-fleet-epm-packages-bulk parameters: - description: The version of the API to use in: header @@ -20428,7 +19962,7 @@ paths: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgkey}: delete: - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#3' + operationId: delete-fleet-epm-packages-pkgkey parameters: - description: The version of the API to use in: header @@ -20466,7 +20000,7 @@ paths: summary: '' tags: [] get: - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#0' + operationId: get-fleet-epm-packages-pkgkey parameters: - description: The version of the API to use in: header @@ -20506,7 +20040,7 @@ paths: summary: '' tags: [] post: - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#2' + operationId: post-fleet-epm-packages-pkgkey parameters: - description: The version of the API to use in: header @@ -20561,7 +20095,7 @@ paths: summary: '' tags: [] put: - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#1' + operationId: put-fleet-epm-packages-pkgkey parameters: - description: The version of the API to use in: header @@ -20600,7 +20134,7 @@ paths: /api/fleet/epm/packages/{pkgName}/{pkgVersion}: delete: description: Delete package - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#3' + operationId: delete-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use in: header @@ -20780,7 +20314,7 @@ paths: - Elastic Package Manager (EPM) get: description: Get package - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#0' + operationId: get-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use in: header @@ -21665,7 +21199,7 @@ paths: - Elastic Package Manager (EPM) post: description: Install package from registry - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#2' + operationId: post-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use in: header @@ -21868,7 +21402,7 @@ paths: - Elastic Package Manager (EPM) put: description: Update package settings - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#1' + operationId: put-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use in: header @@ -22743,8 +22277,7 @@ paths: /api/fleet/epm/packages/{pkgName}/{pkgVersion}/{filePath*}: get: description: Get package file - operationId: >- - %2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2F%7BfilePath*%7D#0 + operationId: get-fleet-epm-packages-pkgname-pkgversion-filepath parameters: - description: The version of the API to use in: header @@ -22796,8 +22329,7 @@ paths: /api/fleet/epm/packages/{pkgName}/{pkgVersion}/transforms/authorize: post: description: Authorize transforms - operationId: >- - %2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2Ftransforms%2Fauthorize#0 + operationId: post-fleet-epm-packages-pkgname-pkgversion-transforms-authorize parameters: - description: The version of the API to use in: header @@ -22890,7 +22422,7 @@ paths: /api/fleet/epm/packages/{pkgName}/stats: get: description: Get package stats - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2Fstats#0' + operationId: get-fleet-epm-packages-pkgname-stats parameters: - description: The version of the API to use in: header @@ -22945,7 +22477,7 @@ paths: /api/fleet/epm/packages/installed: get: description: Get installed packages - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2Finstalled#0' + operationId: get-fleet-epm-packages-installed parameters: - description: The version of the API to use in: header @@ -23099,7 +22631,7 @@ paths: /api/fleet/epm/packages/limited: get: description: Get limited package list - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2Flimited#0' + operationId: get-fleet-epm-packages-limited parameters: - description: The version of the API to use in: header @@ -23150,8 +22682,7 @@ paths: /api/fleet/epm/templates/{pkgName}/{pkgVersion}/inputs: get: description: Get inputs template - operationId: >- - %2Fapi%2Ffleet%2Fepm%2Ftemplates%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2Finputs#0 + operationId: get-fleet-epm-templates-pkgname-pkgversion-inputs parameters: - description: The version of the API to use in: header @@ -23259,7 +22790,7 @@ paths: /api/fleet/epm/verification_key_id: get: description: Get a package signature verification key ID - operationId: '%2Fapi%2Ffleet%2Fepm%2Fverification_key_id#0' + operationId: get-fleet-epm-verification-key-id parameters: - description: The version of the API to use in: header @@ -23304,7 +22835,7 @@ paths: /api/fleet/fleet_server_hosts: get: description: List Fleet Server hosts - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts#0' + operationId: get-fleet-fleet-server-hosts parameters: - description: The version of the API to use in: header @@ -23384,7 +22915,7 @@ paths: - Fleet Server hosts post: description: Create Fleet Server host - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts#1' + operationId: post-fleet-fleet-server-hosts parameters: - description: The version of the API to use in: header @@ -23491,7 +23022,7 @@ paths: /api/fleet/fleet_server_hosts/{itemId}: delete: description: Delete Fleet Server host by ID - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#1' + operationId: delete-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use in: header @@ -23546,7 +23077,7 @@ paths: - Fleet Server hosts get: description: Get Fleet Server host by ID - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#0' + operationId: get-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use in: header @@ -23620,7 +23151,7 @@ paths: - Fleet Server hosts put: description: Update Fleet Server host by ID - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#2' + operationId: put-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use in: header @@ -23725,7 +23256,7 @@ paths: /api/fleet/health_check: post: description: Check Fleet Server health - operationId: '%2Fapi%2Ffleet%2Fhealth_check#0' + operationId: post-fleet-health-check parameters: - description: The version of the API to use in: header @@ -23813,7 +23344,7 @@ paths: /api/fleet/kubernetes: get: description: Get full K8s agent manifest - operationId: '%2Fapi%2Ffleet%2Fkubernetes#0' + operationId: get-fleet-kubernetes parameters: - description: The version of the API to use in: header @@ -23871,7 +23402,7 @@ paths: - Elastic Agent policies /api/fleet/kubernetes/download: get: - operationId: '%2Fapi%2Ffleet%2Fkubernetes%2Fdownload#0' + operationId: get-fleet-kubernetes-download parameters: - description: The version of the API to use in: header @@ -23940,7 +23471,7 @@ paths: /api/fleet/logstash_api_keys: post: description: Generate Logstash API key - operationId: '%2Fapi%2Ffleet%2Flogstash_api_keys#0' + operationId: post-fleet-logstash-api-keys parameters: - description: The version of the API to use in: header @@ -23991,7 +23522,7 @@ paths: /api/fleet/message_signing_service/rotate_key_pair: post: description: Rotate fleet message signing key pair - operationId: '%2Fapi%2Ffleet%2Fmessage_signing_service%2Frotate_key_pair#0' + operationId: post-fleet-message-signing-service-rotate-key-pair parameters: - description: The version of the API to use in: header @@ -24064,7 +23595,7 @@ paths: /api/fleet/outputs: get: description: List outputs - operationId: '%2Fapi%2Ffleet%2Foutputs#0' + operationId: get-fleet-outputs parameters: - description: The version of the API to use in: header @@ -24820,7 +24351,7 @@ paths: - Fleet outputs post: description: Create output - operationId: '%2Fapi%2Ffleet%2Foutputs#1' + operationId: post-fleet-outputs parameters: - description: The version of the API to use in: header @@ -26280,7 +25811,7 @@ paths: /api/fleet/outputs/{outputId}: delete: description: Delete output by ID - operationId: '%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#2' + operationId: delete-fleet-outputs-outputid parameters: - description: The version of the API to use in: header @@ -26351,7 +25882,7 @@ paths: - Fleet outputs get: description: Get output by ID - operationId: '%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#0' + operationId: get-fleet-outputs-outputid parameters: - description: The version of the API to use in: header @@ -27101,7 +26632,7 @@ paths: - Fleet outputs put: description: Update output by ID - operationId: '%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#1' + operationId: put-fleet-outputs-outputid parameters: - description: The version of the API to use in: header @@ -28545,7 +28076,7 @@ paths: /api/fleet/outputs/{outputId}/health: get: description: Get latest output health - operationId: '%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D%2Fhealth#0' + operationId: get-fleet-outputs-outputid-health parameters: - description: The version of the API to use in: header @@ -28603,7 +28134,7 @@ paths: /api/fleet/package_policies: get: description: List package policies - operationId: '%2Fapi%2Ffleet%2Fpackage_policies#0' + operationId: get-fleet-package-policies parameters: - description: The version of the API to use in: header @@ -29108,7 +28639,7 @@ paths: - Fleet package policies post: description: Create package policy - operationId: '%2Fapi%2Ffleet%2Fpackage_policies#1' + operationId: post-fleet-package-policies parameters: - description: The version of the API to use in: header @@ -30011,7 +29542,7 @@ paths: /api/fleet/package_policies/_bulk_get: post: description: Bulk get package policies - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2F_bulk_get#0' + operationId: post-fleet-package-policies-bulk-get parameters: - description: The version of the API to use in: header @@ -30504,7 +30035,7 @@ paths: /api/fleet/package_policies/{packagePolicyId}: delete: description: Delete package policy by ID - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#2' + operationId: delete-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use in: header @@ -30564,7 +30095,7 @@ paths: - Fleet package policies get: description: Get package policy by ID - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#0' + operationId: get-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use in: header @@ -31033,7 +30564,7 @@ paths: - Fleet package policies put: description: Update package policy by ID - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#1' + operationId: put-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use in: header @@ -31930,7 +31461,7 @@ paths: /api/fleet/package_policies/delete: post: description: Bulk delete package policies - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2Fdelete#0' + operationId: post-fleet-package-policies-delete parameters: - description: The version of the API to use in: header @@ -32067,7 +31598,7 @@ paths: /api/fleet/package_policies/upgrade: post: description: Upgrade package policy to a newer package version - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2Fupgrade#0' + operationId: post-fleet-package-policies-upgrade parameters: - description: The version of the API to use in: header @@ -32148,7 +31679,7 @@ paths: /api/fleet/package_policies/upgrade/dryrun: post: description: Dry run package policy upgrade - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2Fupgrade%2Fdryrun#0' + operationId: post-fleet-package-policies-upgrade-dryrun parameters: - description: The version of the API to use in: header @@ -32998,7 +32529,7 @@ paths: /api/fleet/proxies: get: description: List proxies - operationId: '%2Fapi%2Ffleet%2Fproxies#0' + operationId: get-fleet-proxies parameters: - description: The version of the API to use in: header @@ -33084,7 +32615,7 @@ paths: - Fleet proxies post: description: Create proxy - operationId: '%2Fapi%2Ffleet%2Fproxies#1' + operationId: post-fleet-proxies parameters: - description: The version of the API to use in: header @@ -33203,7 +32734,7 @@ paths: /api/fleet/proxies/{itemId}: delete: description: Delete proxy by ID - operationId: '%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#2' + operationId: delete-fleet-proxies-itemid parameters: - description: The version of the API to use in: header @@ -33258,7 +32789,7 @@ paths: - Fleet proxies get: description: Get proxy by ID - operationId: '%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#1' + operationId: get-fleet-proxies-itemid parameters: - description: The version of the API to use in: header @@ -33338,7 +32869,7 @@ paths: - Fleet proxies put: description: Update proxy by ID - operationId: '%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#0' + operationId: put-fleet-proxies-itemid parameters: - description: The version of the API to use in: header @@ -33459,7 +32990,7 @@ paths: /api/fleet/service_tokens: post: description: Create a service token - operationId: '%2Fapi%2Ffleet%2Fservice_tokens#0' + operationId: post-fleet-service-tokens parameters: - description: The version of the API to use in: header @@ -33521,33 +33052,10 @@ paths: summary: '' tags: - Fleet service tokens - /api/fleet/service-tokens: - post: - description: Create a service token - operationId: '%2Fapi%2Ffleet%2Fservice-tokens#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - responses: {} - summary: '' - tags: [] /api/fleet/settings: get: description: Get settings - operationId: '%2Fapi%2Ffleet%2Fsettings#0' + operationId: get-fleet-settings parameters: - description: The version of the API to use in: header @@ -33646,7 +33154,7 @@ paths: - Fleet internals put: description: Update settings - operationId: '%2Fapi%2Ffleet%2Fsettings#1' + operationId: put-fleet-settings parameters: - description: The version of the API to use in: header @@ -33789,7 +33297,7 @@ paths: /api/fleet/setup: post: description: Initiate Fleet setup - operationId: '%2Fapi%2Ffleet%2Fsetup#0' + operationId: post-fleet-setup parameters: - description: The version of the API to use in: header @@ -33871,7 +33379,7 @@ paths: /api/fleet/uninstall_tokens: get: description: List metadata for latest uninstall tokens per agent policy - operationId: '%2Fapi%2Ffleet%2Funinstall_tokens#0' + operationId: get-fleet-uninstall-tokens parameters: - description: The version of the API to use in: header @@ -33971,7 +33479,7 @@ paths: /api/fleet/uninstall_tokens/{uninstallTokenId}: get: description: Get one decrypted uninstall token by its ID - operationId: '%2Fapi%2Ffleet%2Funinstall_tokens%2F%7BuninstallTokenId%7D#0' + operationId: get-fleet-uninstall-tokens-uninstalltokenid parameters: - description: The version of the API to use in: header @@ -35486,7 +34994,7 @@ paths: nullable: true type: string - in: query - name: userFilter + name: createdByFilter schema: nullable: true type: string @@ -36782,7 +36290,7 @@ paths: - Prompts API /api/security/role: get: - operationId: '%2Fapi%2Fsecurity%2Frole#0' + operationId: get-security-role parameters: - description: The version of the API to use in: header @@ -36792,18 +36300,24 @@ paths: enum: - '2023-10-31' type: string - - in: query + - description: >- + If `true` and the response contains any privileges that are + associated with deprecated features, they are omitted in favor of + details about the appropriate replacement feature privileges. + in: query name: replaceDeprecatedPrivileges required: false schema: type: boolean - responses: {} + responses: + '200': + description: Indicates a successful call. summary: Get all roles tags: - roles /api/security/role/{name}: delete: - operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#1' + operationId: delete-security-role-name parameters: - description: The version of the API to use in: header @@ -36826,12 +36340,14 @@ paths: schema: minLength: 1 type: string - responses: {} + responses: + '204': + description: Indicates a successful call. summary: Delete a role tags: - roles get: - operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#0' + operationId: get-security-role-name parameters: - description: The version of the API to use in: header @@ -36841,23 +36357,33 @@ paths: enum: - '2023-10-31' type: string - - in: path + - description: The role name. + in: path name: name required: true schema: minLength: 1 type: string - - in: query + - description: >- + If `true` and the response contains any privileges that are + associated with deprecated features, they are omitted in favor of + details about the appropriate replacement feature privileges. + in: query name: replaceDeprecatedPrivileges required: false schema: type: boolean - responses: {} + responses: + '200': + description: Indicates a successful call. summary: Get a role tags: - roles put: - operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#2' + description: >- + Create a new Kibana role or update the attributes of an existing role. + Kibana roles are stored in the Elasticsearch native realm. + operationId: put-security-role-name parameters: - description: The version of the API to use in: header @@ -36874,14 +36400,16 @@ paths: schema: example: 'true' type: string - - in: path + - description: The role name. + in: path name: name required: true schema: maxLength: 1024 minLength: 1 type: string - - in: query + - description: When true, a role is not overwritten if it already exists. + in: query name: createOnly required: false schema: @@ -36895,6 +36423,7 @@ paths: type: object properties: description: + description: A description for the role. maxLength: 2048 type: string elasticsearch: @@ -36903,6 +36432,9 @@ paths: properties: cluster: items: + description: >- + Cluster privileges that define the cluster level + actions that users can perform. type: string type: array indices: @@ -36911,24 +36443,55 @@ paths: type: object properties: allow_restricted_indices: + description: >- + Restricted indices are a special category of + indices that are used internally to store + configuration data and should not be directly + accessed. Only internal system roles should + normally grant privileges over the restricted + indices. Toggling this flag is very strongly + discouraged because it could effectively grant + unrestricted operations on critical data, making + the entire system unstable or leaking sensitive + information. If for administrative purposes you + need to create a role with privileges covering + restricted indices, however, you can set this + property to true. In that case, the names field + covers the restricted indices too. type: boolean field_security: additionalProperties: items: + description: >- + The document fields that the role members have + read access to. type: string type: array type: object names: items: + description: >- + The data streams, indices, and aliases to which + the permissions in this entry apply. It supports + wildcards (*). type: string minItems: 1 type: array privileges: items: + description: >- + The index level privileges that the role members + have for the data streams and indices. type: string minItems: 1 type: array query: + description: >- + A search query that defines the documents the role + members have read access to. A document within the + specified data streams and indices must match this + query in order for it to be accessible by the role + members. type: string required: - names @@ -36941,11 +36504,19 @@ paths: properties: clusters: items: + description: >- + A list of remote cluster aliases. It supports + literal strings as well as wildcards and regular + expressions. type: string minItems: 1 type: array privileges: items: + description: >- + The cluster level privileges for the remote + cluster. The allowed values are a subset of the + cluster privileges. type: string minItems: 1 type: array @@ -36959,29 +36530,64 @@ paths: type: object properties: allow_restricted_indices: + description: >- + Restricted indices are a special category of + indices that are used internally to store + configuration data and should not be directly + accessed. Only internal system roles should + normally grant privileges over the restricted + indices. Toggling this flag is very strongly + discouraged because it could effectively grant + unrestricted operations on critical data, making + the entire system unstable or leaking sensitive + information. If for administrative purposes you + need to create a role with privileges covering + restricted indices, however, you can set this + property to true. In that case, the names field + will cover the restricted indices too. type: boolean clusters: items: + description: >- + A list of remote cluster aliases. It supports + literal strings as well as wildcards and regular + expressions. type: string minItems: 1 type: array field_security: additionalProperties: items: + description: >- + The document fields that the role members have + read access to. type: string type: array type: object names: items: + description: >- + A list of remote aliases, data streams, or + indices to which the permissions apply. It + supports wildcards (*). type: string minItems: 1 type: array privileges: items: + description: >- + The index level privileges that role members + have for the specified indices. type: string minItems: 1 type: array query: + description: >- + A search query that defines the documents the role + members have read access to. A document within the + specified data streams and indices must match this + query in order for it to be accessible by the role + members. type: string required: - clusters @@ -36990,6 +36596,7 @@ paths: type: array run_as: items: + description: A user name that the role member can impersonate. type: string type: array kibana: @@ -37008,14 +36615,23 @@ paths: nullable: true oneOf: - items: + description: >- + A base privilege that grants applies to all + spaces. type: string type: array - items: + description: >- + A base privilege that applies to specific + spaces. type: string type: array feature: additionalProperties: items: + description: >- + The privileges that the role member has for the + feature. type: string type: array type: object @@ -37029,6 +36645,7 @@ paths: minItems: 1 type: array - items: + description: A space that the privilege applies to. type: string type: array default: @@ -37041,13 +36658,15 @@ paths: type: object required: - elasticsearch - responses: {} + responses: + '204': + description: Indicates a successful call. summary: Create or update a role tags: - roles /api/security/roles: post: - operationId: '%2Fapi%2Fsecurity%2Froles#0' + operationId: post-security-roles parameters: - description: The version of the API to use in: header @@ -37077,6 +36696,7 @@ paths: type: object properties: description: + description: A description for the role. maxLength: 2048 type: string elasticsearch: @@ -37085,6 +36705,9 @@ paths: properties: cluster: items: + description: >- + Cluster privileges that define the cluster level + actions that users can perform. type: string type: array indices: @@ -37093,24 +36716,58 @@ paths: type: object properties: allow_restricted_indices: + description: >- + Restricted indices are a special category of + indices that are used internally to store + configuration data and should not be + directly accessed. Only internal system + roles should normally grant privileges over + the restricted indices. Toggling this flag + is very strongly discouraged because it + could effectively grant unrestricted + operations on critical data, making the + entire system unstable or leaking sensitive + information. If for administrative purposes + you need to create a role with privileges + covering restricted indices, however, you + can set this property to true. In that case, + the names field covers the restricted + indices too. type: boolean field_security: additionalProperties: items: + description: >- + The document fields that the role + members have read access to. type: string type: array type: object names: items: + description: >- + The data streams, indices, and aliases to + which the permissions in this entry apply. + It supports wildcards (*). type: string minItems: 1 type: array privileges: items: + description: >- + The index level privileges that the role + members have for the data streams and + indices. type: string minItems: 1 type: array query: + description: >- + A search query that defines the documents + the role members have read access to. A + document within the specified data streams + and indices must match this query in order + for it to be accessible by the role members. type: string required: - names @@ -37123,11 +36780,19 @@ paths: properties: clusters: items: + description: >- + A list of remote cluster aliases. It + supports literal strings as well as + wildcards and regular expressions. type: string minItems: 1 type: array privileges: items: + description: >- + The cluster level privileges for the + remote cluster. The allowed values are a + subset of the cluster privileges. type: string minItems: 1 type: array @@ -37141,29 +36806,67 @@ paths: type: object properties: allow_restricted_indices: + description: >- + Restricted indices are a special category of + indices that are used internally to store + configuration data and should not be + directly accessed. Only internal system + roles should normally grant privileges over + the restricted indices. Toggling this flag + is very strongly discouraged because it + could effectively grant unrestricted + operations on critical data, making the + entire system unstable or leaking sensitive + information. If for administrative purposes + you need to create a role with privileges + covering restricted indices, however, you + can set this property to true. In that case, + the names field will cover the restricted + indices too. type: boolean clusters: items: + description: >- + A list of remote cluster aliases. It + supports literal strings as well as + wildcards and regular expressions. type: string minItems: 1 type: array field_security: additionalProperties: items: + description: >- + The document fields that the role + members have read access to. type: string type: array type: object names: items: + description: >- + A list of remote aliases, data streams, or + indices to which the permissions apply. It + supports wildcards (*). type: string minItems: 1 type: array privileges: items: + description: >- + The index level privileges that role + members have for the specified indices. type: string minItems: 1 type: array query: + description: >- + A search query that defines the documents + the role members have read access to. A + document within the specified data streams + and indices must match this query in order + for it to be accessible by the role + members. type: string required: - clusters @@ -37172,6 +36875,9 @@ paths: type: array run_as: items: + description: >- + A user name that the role member can + impersonate. type: string type: array kibana: @@ -37190,14 +36896,23 @@ paths: nullable: true oneOf: - items: + description: >- + A base privilege that grants applies to + all spaces. type: string type: array - items: + description: >- + A base privilege that applies to specific + spaces. type: string type: array feature: additionalProperties: items: + description: >- + The privileges that the role member has for + the feature. type: string type: array type: object @@ -37211,6 +36926,7 @@ paths: minItems: 1 type: array - items: + description: A space that the privilege applies to. type: string type: array default: @@ -37226,13 +36942,15 @@ paths: type: object required: - roles - responses: {} + responses: + '200': + description: Indicates a successful call. summary: Create or update roles tags: - roles /api/spaces/space: get: - operationId: '%2Fapi%2Fspaces%2Fspace#0' + operationId: get-spaces-space parameters: - description: The version of the API to use in: header @@ -37288,7 +37006,7 @@ paths: tags: - spaces post: - operationId: '%2Fapi%2Fspaces%2Fspace#1' + operationId: post-spaces-space parameters: - description: The version of the API to use in: header @@ -37370,7 +37088,7 @@ paths: description: >- When you delete a space, all saved objects that belong to the space are automatically deleted, which is permanent and cannot be undone. - operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2' + operationId: delete-spaces-space-id parameters: - description: The version of the API to use in: header @@ -37402,7 +37120,7 @@ paths: tags: - spaces get: - operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0' + operationId: get-spaces-space-id parameters: - description: The version of the API to use in: header @@ -37425,7 +37143,7 @@ paths: tags: - spaces put: - operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1' + operationId: put-spaces-space-id parameters: - description: The version of the API to use in: header @@ -37512,7 +37230,7 @@ paths: - spaces /api/status: get: - operationId: '%2Fapi%2Fstatus#0' + operationId: get-status parameters: - description: The version of the API to use in: header @@ -40329,6 +40047,24 @@ components: title: Kibana Sample Data Logs type: index-pattern parameters: + APM_UI_elastic_api_version: + description: The version of the API to use + in: header + name: elastic-api-version + required: true + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + APM_UI_kbn_xsrf: + description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string Data_views_field_name: description: The name of the runtime field. in: path @@ -40395,6 +40131,471 @@ components: example: default type: string schemas: + APM_UI_400_response: + type: object + properties: + error: + description: Error type + example: Not Found + type: string + message: + description: Error message + example: Not Found + type: string + statusCode: + description: Error status code + example: 400 + type: number + APM_UI_401_response: + type: object + properties: + error: + description: Error type + example: Unauthorized + type: string + message: + description: Error message + type: string + statusCode: + description: Error status code + example: 401 + type: number + APM_UI_403_response: + type: object + properties: + error: + description: Error type + example: Forbidden + type: string + message: + description: Error message + type: string + statusCode: + description: Error status code + example: 403 + type: number + APM_UI_404_response: + type: object + properties: + error: + description: Error type + example: Not Found + type: string + message: + description: Error message + example: Not Found + type: string + statusCode: + description: Error status code + example: 404 + type: number + APM_UI_500_response: + type: object + properties: + error: + description: Error type + example: Internal Server Error + type: string + message: + description: Error message + type: string + statusCode: + description: Error status code + example: 500 + type: number + APM_UI_501_response: + type: object + properties: + error: + description: Error type + example: Not Implemented + type: string + message: + description: Error message + example: Not Implemented + type: string + statusCode: + description: Error status code + example: 501 + type: number + APM_UI_agent_configuration_intake_object: + type: object + properties: + agent_name: + description: Agent name + type: string + service: + $ref: '#/components/schemas/APM_UI_service_object' + settings: + $ref: '#/components/schemas/APM_UI_settings_object' + required: + - service + - settings + APM_UI_agent_configuration_object: + description: Agent configuration + type: object + properties: + '@timestamp': + description: Timestamp + example: 1730194190636 + type: number + agent_name: + description: Agent name + type: string + applied_by_agent: + description: Applied by agent + example: true + type: boolean + etag: + description: Etag + example: 0bc3b5ebf18fba8163fe4c96f491e3767a358f85 + type: string + service: + $ref: '#/components/schemas/APM_UI_service_object' + settings: + $ref: '#/components/schemas/APM_UI_settings_object' + required: + - service + - settings + - '@timestamp' + - etag + APM_UI_agent_configurations_response: + type: object + properties: + configurations: + description: Agent configuration + items: + $ref: '#/components/schemas/APM_UI_agent_configuration_object' + type: array + APM_UI_agent_keys_object: + type: object + properties: + name: + description: Agent name + type: string + privileges: + description: Privileges configuration + items: + enum: + - event:write + - config_agent:read + type: string + type: array + required: + - name + - privileges + APM_UI_agent_keys_response: + type: object + properties: + agentKey: + description: Agent key + type: object + properties: + api_key: + type: string + encoded: + type: string + expiration: + format: int64 + type: integer + id: + type: string + name: + type: string + required: + - id + - name + - api_key + - encoded + APM_UI_annotation_search_response: + type: object + properties: + annotations: + description: Annotations + items: + type: object + properties: + '@timestamp': + type: number + id: + type: string + text: + type: string + type: + enum: + - version + type: string + type: array + APM_UI_base_source_map_object: + type: object + properties: + compressionAlgorithm: + description: Compression Algorithm + type: string + created: + description: Created date + type: string + decodedSha256: + description: Decoded SHA-256 + type: string + decodedSize: + description: Decoded size + type: number + encodedSha256: + description: Encoded SHA-256 + type: string + encodedSize: + description: Encoded size + type: number + encryptionAlgorithm: + description: Encryption Algorithm + type: string + id: + description: Identifier + type: string + identifier: + description: Identifier + type: string + packageName: + description: Package name + type: string + relative_url: + description: Relative URL + type: string + type: + description: Type + type: string + APM_UI_create_annotation_object: + type: object + properties: + '@timestamp': + description: Timestamp + type: string + message: + description: Message + type: string + service: + description: Service + type: object + properties: + environment: + type: string + version: + type: string + required: + - version + tags: + description: Tags + items: + type: string + type: array + required: + - '@timestamp' + - service + APM_UI_create_annotation_response: + type: object + properties: + _id: + description: Identifier + type: string + _index: + description: Index + type: string + _source: + description: Response + type: object + properties: + '@timestamp': + type: string + annotation: + type: object + properties: + title: + type: string + type: + type: string + event: + type: object + properties: + created: + type: string + message: + type: string + service: + type: object + properties: + environment: + type: string + name: + type: string + version: + type: string + tags: + items: + type: string + type: array + APM_UI_delete_agent_configurations_response: + type: object + properties: + result: + description: Result + type: string + APM_UI_search_agent_configuration_object: + type: object + properties: + etag: + description: If etags match then `applied_by_agent` field will be set to `true` + example: 0bc3b5ebf18fba8163fe4c96f491e3767a358f85 + type: string + mark_as_applied_by_agent: + description: > + `markAsAppliedByAgent=true` means "force setting it to true + regardless of etag". + + This is needed for Jaeger agent that doesn't have etags + type: boolean + service: + $ref: '#/components/schemas/APM_UI_service_object' + required: + - service + APM_UI_search_agent_configuration_response: + type: object + properties: + _id: + description: Identifier + type: string + _index: + description: Index + type: string + _score: + description: Score + type: number + _source: + $ref: '#/components/schemas/APM_UI_agent_configuration_object' + APM_UI_service_agent_name_response: + type: object + properties: + agentName: + description: Agent name + example: nodejs + type: string + APM_UI_service_environment_object: + type: object + properties: + alreadyConfigured: + description: Already configured + type: boolean + name: + description: Service environment name + example: ALL_OPTION_VALUE + type: string + APM_UI_service_environments_response: + type: object + properties: + environments: + description: Service environment list + items: + $ref: '#/components/schemas/APM_UI_service_environment_object' + type: array + APM_UI_service_object: + description: Service + type: object + properties: + environment: + description: Environment + example: prod + type: string + name: + description: Name + example: node + type: string + APM_UI_settings_object: + additionalProperties: + type: string + description: Agent configuration settings + type: object + APM_UI_single_agent_configuration_response: + allOf: + - type: object + properties: + id: + type: string + required: + - id + - $ref: '#/components/schemas/APM_UI_agent_configuration_object' + APM_UI_source_maps_response: + type: object + properties: + artifacts: + description: Artifacts + items: + allOf: + - type: object + properties: + body: + type: object + properties: + bundleFilepath: + type: string + serviceName: + type: string + serviceVersion: + type: string + sourceMap: + type: object + properties: + file: + type: string + mappings: + type: string + sourceRoot: + type: string + sources: + items: + type: string + type: array + sourcesContent: + items: + type: string + type: array + version: + type: number + - $ref: '#/components/schemas/APM_UI_base_source_map_object' + type: array + APM_UI_upload_source_map_object: + type: object + properties: + bundle_filepath: + description: >- + The absolute path of the final bundle as used in the web + application. + type: string + service_name: + description: The name of the service that the service map should apply to. + type: string + service_version: + description: The version of the service that the service map should apply to. + type: string + sourcemap: + description: > + The source map. String or file upload. It must follow the + + [source map revision 3 + proposal](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k). + format: binary + type: string + required: + - service_name + - service_version + - bundle_filepath + - sourcemap + APM_UI_upload_source_maps_response: + allOf: + - type: object + properties: + body: + type: string + - $ref: '#/components/schemas/APM_UI_base_source_map_object' Data_views_400_response: title: Bad request type: object @@ -48743,6 +48944,8 @@ components: Security_Entity_Analytics_API_EngineDescriptor: type: object properties: + error: + type: object fieldHistoryLength: type: integer filter: @@ -52142,6 +52345,9 @@ security: - apiKeyAuth: [] tags: - name: alerting + - description: | + Adjust APM agent configuration without need to redeploy your application. + name: APM agent configuration - description: > Configure APM agent keys to authorize requests from APM agents to the APM Server. @@ -52151,6 +52357,10 @@ tags: Annotations enable you to easily see how events are impacting the performance of your applications. name: APM annotations + - description: Create APM fleet server schema. + name: APM server schema + - description: Configure APM source maps. + name: APM sourcemaps - name: connectors - name: Data streams - description: >- diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index 044914ccc5758..5bbc65ad80bc4 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -79,396 +79,10 @@ servers: kibana_url: default: localhost:5601 paths: - /api/actions: - get: - deprecated: true - operationId: '%2Fapi%2Factions#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - responses: {} - summary: Get all connectors - tags: - - connectors - /api/actions/action: - post: - deprecated: true - operationId: '%2Fapi%2Factions%2Faction#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - requestBody: - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - actionTypeId: - description: The connector type identifier. - type: string - config: - additionalProperties: {} - default: {} - type: object - name: - description: The display name for the connector. - type: string - secrets: - additionalProperties: {} - default: {} - type: object - required: - - name - - actionTypeId - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - type: object - connector_type_id: - description: The connector type identifier. - type: string - id: - description: The identifier for the connector. - type: string - is_deprecated: - description: Indicates whether the connector is deprecated. - type: boolean - is_missing_secrets: - description: Indicates whether the connector is missing secrets. - type: boolean - is_preconfigured: - description: >- - Indicates whether the connector is preconfigured. If true, - the `config` and `is_missing_secrets` properties are - omitted from the response. - type: boolean - is_system_action: - description: >- - Indicates whether the connector is used for system - actions. - type: boolean - name: - description: ' The name of the rule.' - type: string - required: - - id - - name - - connector_type_id - - is_preconfigured - - is_deprecated - - is_system_action - description: Indicates a successful call. - summary: Create a connector - tags: - - connectors - /api/actions/action/{id}: - delete: - deprecated: true - description: 'WARNING: When you delete a connector, it cannot be recovered.' - operationId: '%2Fapi%2Factions%2Faction%2F%7Bid%7D#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - - description: An identifier for the connector. - in: path - name: id - required: true - schema: - type: string - responses: - '204': - description: Indicates a successful call. - summary: Delete a connector - tags: - - connectors - get: - deprecated: true - operationId: '%2Fapi%2Factions%2Faction%2F%7Bid%7D#1' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: An identifier for the connector. - in: path - name: id - required: true - schema: - type: string - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - type: object - connector_type_id: - description: The connector type identifier. - type: string - id: - description: The identifier for the connector. - type: string - is_deprecated: - description: Indicates whether the connector is deprecated. - type: boolean - is_missing_secrets: - description: Indicates whether the connector is missing secrets. - type: boolean - is_preconfigured: - description: >- - Indicates whether the connector is preconfigured. If true, - the `config` and `is_missing_secrets` properties are - omitted from the response. - type: boolean - is_system_action: - description: >- - Indicates whether the connector is used for system - actions. - type: boolean - name: - description: ' The name of the rule.' - type: string - required: - - id - - name - - connector_type_id - - is_preconfigured - - is_deprecated - - is_system_action - description: Indicates a successful call. - summary: Get connector information - tags: - - connectors - put: - deprecated: true - operationId: '%2Fapi%2Factions%2Faction%2F%7Bid%7D#2' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - - description: An identifier for the connector. - in: path - name: id - required: true - schema: - type: string - requestBody: - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - default: {} - type: object - name: - type: string - secrets: - additionalProperties: {} - default: {} - type: object - required: - - name - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - type: object - connector_type_id: - description: The connector type identifier. - type: string - id: - description: The identifier for the connector. - type: string - is_deprecated: - description: Indicates whether the connector is deprecated. - type: boolean - is_missing_secrets: - description: Indicates whether the connector is missing secrets. - type: boolean - is_preconfigured: - description: >- - Indicates whether the connector is preconfigured. If true, - the `config` and `is_missing_secrets` properties are - omitted from the response. - type: boolean - is_system_action: - description: >- - Indicates whether the connector is used for system - actions. - type: boolean - name: - description: ' The name of the rule.' - type: string - required: - - id - - name - - connector_type_id - - is_preconfigured - - is_deprecated - - is_system_action - description: Indicates a successful call. - summary: Update a connector - tags: - - connectors - /api/actions/action/{id}/_execute: - post: - deprecated: true - operationId: '%2Fapi%2Factions%2Faction%2F%7Bid%7D%2F_execute#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - - description: An identifier for the connector. - in: path - name: id - required: true - schema: - type: string - requestBody: - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - params: - additionalProperties: {} - type: object - required: - - params - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - config: - additionalProperties: {} - type: object - connector_type_id: - description: The connector type identifier. - type: string - id: - description: The identifier for the connector. - type: string - is_deprecated: - description: Indicates whether the connector is deprecated. - type: boolean - is_missing_secrets: - description: Indicates whether the connector is missing secrets. - type: boolean - is_preconfigured: - description: >- - Indicates whether the connector is preconfigured. If true, - the `config` and `is_missing_secrets` properties are - omitted from the response. - type: boolean - is_system_action: - description: >- - Indicates whether the connector is used for system - actions. - type: boolean - name: - description: ' The name of the rule.' - type: string - required: - - id - - name - - connector_type_id - - is_preconfigured - - is_deprecated - - is_system_action - description: Indicates a successful call. - summary: Run a connector - tags: - - connectors /api/actions/connector_types: get: description: You do not need any Kibana feature privileges to run this API. - operationId: '%2Fapi%2Factions%2Fconnector_types#0' + operationId: get-actions-connector-types parameters: - description: The version of the API to use in: header @@ -493,7 +107,7 @@ paths: /api/actions/connector/{id}: delete: description: 'WARNING: When you delete a connector, it cannot be recovered.' - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#0' + operationId: delete-actions-connector-id parameters: - description: The version of the API to use in: header @@ -523,7 +137,7 @@ paths: tags: - connectors get: - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#1' + operationId: get-actions-connector-id parameters: - description: The version of the API to use in: header @@ -588,7 +202,7 @@ paths: tags: - connectors post: - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%3F%7D#0' + operationId: post-actions-connector-id parameters: - description: The version of the API to use in: header @@ -684,7 +298,7 @@ paths: tags: - connectors put: - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%7D#2' + operationId: put-actions-connector-id parameters: - description: The version of the API to use in: header @@ -780,7 +394,7 @@ paths: description: >- You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. - operationId: '%2Fapi%2Factions%2Fconnector%2F%7Bid%7D%2F_execute#0' + operationId: post-actions-connector-id-execute parameters: - description: The version of the API to use in: header @@ -865,7 +479,7 @@ paths: - connectors /api/actions/connectors: get: - operationId: '%2Fapi%2Factions%2Fconnectors#0' + operationId: get-actions-connectors parameters: - description: The version of the API to use in: header @@ -879,23 +493,6 @@ paths: summary: Get all connectors tags: - connectors - /api/actions/list_action_types: - get: - deprecated: true - operationId: '%2Fapi%2Factions%2Flist_action_types#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - responses: {} - summary: Get connector types - tags: - - connectors /api/alerting/_health: get: description: > @@ -1286,7 +883,7 @@ paths: - alerting /api/alerting/rule/{id}: delete: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D#2' + operationId: delete-alerting-rule-id parameters: - description: The version of the API to use in: header @@ -1322,7 +919,7 @@ paths: tags: - alerting get: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D#0' + operationId: get-alerting-rule-id parameters: - description: The version of the API to use in: header @@ -1780,73 +1377,14 @@ paths: description: Duration of the rule run. type: number outcome: - additionalProperties: false - type: object - properties: - alerts_count: - additionalProperties: false - type: object - properties: - active: - description: Number of active alerts during last run. - nullable: true - type: number - ignored: - description: >- - Number of ignored alerts during last - run. - nullable: true - type: number - new: - description: Number of new alerts during last run. - nullable: true - type: number - recovered: - description: >- - Number of recovered alerts during last - run. - nullable: true - type: number - outcome: - description: >- - Outcome of last run of the rule. Value - could be succeeded, warning or failed. - enum: - - succeeded - - warning - - failed - type: string - outcome_msg: - items: - description: >- - Outcome message generated during last - rule run. - type: string - nullable: true - type: array - outcome_order: - description: Order of the outcome. - type: number - warning: - description: Warning of last rule execution. - enum: - - read - - decrypt - - execute - - unknown - - license - - timeout - - disabled - - validate - - maxExecutableActions - - maxAlerts - - maxQueuedActions - - ruleExecution - nullable: true - type: string - required: - - outcome - - alerts_count + description: >- + Outcome of last run of the rule. Value could + be succeeded, warning or failed. + enum: + - succeeded + - warning + - failed + type: string success: description: >- Indicates whether the rule run was @@ -1994,11 +1532,13 @@ paths: items: description: Indicates hours of the day to recur. type: number + nullable: true type: array byminute: items: description: Indicates minutes of the hour to recur. type: number + nullable: true type: array bymonth: items: @@ -2006,16 +1546,19 @@ paths: Indicates months of the year that this rule should recur. type: number + nullable: true type: array bymonthday: items: description: Indicates the days of the month to recur. type: number + nullable: true type: array bysecond: items: description: Indicates seconds of the day to recur. type: number + nullable: true type: array bysetpos: items: @@ -2026,6 +1569,7 @@ paths: of the month. It is recommended to not set this manually and just use `byweekday`. type: number + nullable: true type: array byweekday: items: @@ -2039,11 +1583,13 @@ paths: Friday of the month, which are internally converted to a `byweekday/bysetpos` combination. + nullable: true type: array byweekno: items: description: Indicates number of the week hours to recur. type: number + nullable: true type: array byyearday: items: @@ -2051,6 +1597,7 @@ paths: Indicates the days of the year that this rule should recur. type: number + nullable: true type: array count: description: >- @@ -2170,7 +1717,7 @@ paths: tags: - alerting post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%3F%7D#0' + operationId: post-alerting-rule-id parameters: - description: The version of the API to use in: header @@ -2953,73 +2500,14 @@ paths: description: Duration of the rule run. type: number outcome: - additionalProperties: false - type: object - properties: - alerts_count: - additionalProperties: false - type: object - properties: - active: - description: Number of active alerts during last run. - nullable: true - type: number - ignored: - description: >- - Number of ignored alerts during last - run. - nullable: true - type: number - new: - description: Number of new alerts during last run. - nullable: true - type: number - recovered: - description: >- - Number of recovered alerts during last - run. - nullable: true - type: number - outcome: - description: >- - Outcome of last run of the rule. Value - could be succeeded, warning or failed. - enum: - - succeeded - - warning - - failed - type: string - outcome_msg: - items: - description: >- - Outcome message generated during last - rule run. - type: string - nullable: true - type: array - outcome_order: - description: Order of the outcome. - type: number - warning: - description: Warning of last rule execution. - enum: - - read - - decrypt - - execute - - unknown - - license - - timeout - - disabled - - validate - - maxExecutableActions - - maxAlerts - - maxQueuedActions - - ruleExecution - nullable: true - type: string - required: - - outcome - - alerts_count + description: >- + Outcome of last run of the rule. Value could + be succeeded, warning or failed. + enum: + - succeeded + - warning + - failed + type: string success: description: >- Indicates whether the rule run was @@ -3167,11 +2655,13 @@ paths: items: description: Indicates hours of the day to recur. type: number + nullable: true type: array byminute: items: description: Indicates minutes of the hour to recur. type: number + nullable: true type: array bymonth: items: @@ -3179,16 +2669,19 @@ paths: Indicates months of the year that this rule should recur. type: number + nullable: true type: array bymonthday: items: description: Indicates the days of the month to recur. type: number + nullable: true type: array bysecond: items: description: Indicates seconds of the day to recur. type: number + nullable: true type: array bysetpos: items: @@ -3199,6 +2692,7 @@ paths: of the month. It is recommended to not set this manually and just use `byweekday`. type: number + nullable: true type: array byweekday: items: @@ -3212,11 +2706,13 @@ paths: Friday of the month, which are internally converted to a `byweekday/bysetpos` combination. + nullable: true type: array byweekno: items: description: Indicates number of the week hours to recur. type: number + nullable: true type: array byyearday: items: @@ -3224,6 +2720,7 @@ paths: Indicates the days of the year that this rule should recur. type: number + nullable: true type: array count: description: >- @@ -3343,7 +2840,7 @@ paths: tags: - alerting put: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D#1' + operationId: put-alerting-rule-id parameters: - description: The version of the API to use in: header @@ -4097,73 +3594,14 @@ paths: description: Duration of the rule run. type: number outcome: - additionalProperties: false - type: object - properties: - alerts_count: - additionalProperties: false - type: object - properties: - active: - description: Number of active alerts during last run. - nullable: true - type: number - ignored: - description: >- - Number of ignored alerts during last - run. - nullable: true - type: number - new: - description: Number of new alerts during last run. - nullable: true - type: number - recovered: - description: >- - Number of recovered alerts during last - run. - nullable: true - type: number - outcome: - description: >- - Outcome of last run of the rule. Value - could be succeeded, warning or failed. - enum: - - succeeded - - warning - - failed - type: string - outcome_msg: - items: - description: >- - Outcome message generated during last - rule run. - type: string - nullable: true - type: array - outcome_order: - description: Order of the outcome. - type: number - warning: - description: Warning of last rule execution. - enum: - - read - - decrypt - - execute - - unknown - - license - - timeout - - disabled - - validate - - maxExecutableActions - - maxAlerts - - maxQueuedActions - - ruleExecution - nullable: true - type: string - required: - - outcome - - alerts_count + description: >- + Outcome of last run of the rule. Value could + be succeeded, warning or failed. + enum: + - succeeded + - warning + - failed + type: string success: description: >- Indicates whether the rule run was @@ -4311,11 +3749,13 @@ paths: items: description: Indicates hours of the day to recur. type: number + nullable: true type: array byminute: items: description: Indicates minutes of the hour to recur. type: number + nullable: true type: array bymonth: items: @@ -4323,16 +3763,19 @@ paths: Indicates months of the year that this rule should recur. type: number + nullable: true type: array bymonthday: items: description: Indicates the days of the month to recur. type: number + nullable: true type: array bysecond: items: description: Indicates seconds of the day to recur. type: number + nullable: true type: array bysetpos: items: @@ -4343,6 +3786,7 @@ paths: of the month. It is recommended to not set this manually and just use `byweekday`. type: number + nullable: true type: array byweekday: items: @@ -4356,11 +3800,13 @@ paths: Friday of the month, which are internally converted to a `byweekday/bysetpos` combination. + nullable: true type: array byweekno: items: description: Indicates number of the week hours to recur. type: number + nullable: true type: array byyearday: items: @@ -4368,6 +3814,7 @@ paths: Indicates the days of the year that this rule should recur. type: number + nullable: true type: array count: description: >- @@ -4490,7 +3937,7 @@ paths: - alerting /api/alerting/rule/{id}/_disable: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_disable#0' + operationId: post-alerting-rule-id-disable parameters: - description: The version of the API to use in: header @@ -4539,7 +3986,7 @@ paths: - alerting /api/alerting/rule/{id}/_enable: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_enable#0' + operationId: post-alerting-rule-id-enable parameters: - description: The version of the API to use in: header @@ -4576,7 +4023,7 @@ paths: - alerting /api/alerting/rule/{id}/_mute_all: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_mute_all#0' + operationId: post-alerting-rule-id-mute-all parameters: - description: The version of the API to use in: header @@ -4613,7 +4060,7 @@ paths: - alerting /api/alerting/rule/{id}/_unmute_all: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_unmute_all#0' + operationId: post-alerting-rule-id-unmute-all parameters: - description: The version of the API to use in: header @@ -4650,7 +4097,7 @@ paths: - alerting /api/alerting/rule/{id}/_update_api_key: post: - operationId: '%2Fapi%2Falerting%2Frule%2F%7Bid%7D%2F_update_api_key#0' + operationId: post-alerting-rule-id-update-api-key parameters: - description: The version of the API to use in: header @@ -4689,8 +4136,7 @@ paths: - alerting /api/alerting/rule/{rule_id}/alert/{alert_id}/_mute: post: - operationId: >- - %2Fapi%2Falerting%2Frule%2F%7Brule_id%7D%2Falert%2F%7Balert_id%7D%2F_mute#0 + operationId: post-alerting-rule-rule-id-alert-alert-id-mute parameters: - description: The version of the API to use in: header @@ -4733,8 +4179,7 @@ paths: - alerting /api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute: post: - operationId: >- - %2Fapi%2Falerting%2Frule%2F%7Brule_id%7D%2Falert%2F%7Balert_id%7D%2F_unmute#0 + operationId: post-alerting-rule-rule-id-alert-alert-id-unmute parameters: - description: The version of the API to use in: header @@ -4777,7 +4222,7 @@ paths: - alerting /api/alerting/rules/_find: get: - operationId: '%2Fapi%2Falerting%2Frules%2F_find#0' + operationId: get-alerting-rules-find parameters: - description: The version of the API to use in: header @@ -5335,73 +4780,14 @@ paths: description: Duration of the rule run. type: number outcome: - additionalProperties: false - type: object - properties: - alerts_count: - additionalProperties: false - type: object - properties: - active: - description: Number of active alerts during last run. - nullable: true - type: number - ignored: - description: >- - Number of ignored alerts during last - run. - nullable: true - type: number - new: - description: Number of new alerts during last run. - nullable: true - type: number - recovered: - description: >- - Number of recovered alerts during last - run. - nullable: true - type: number - outcome: - description: >- - Outcome of last run of the rule. Value - could be succeeded, warning or failed. - enum: - - succeeded - - warning - - failed - type: string - outcome_msg: - items: - description: >- - Outcome message generated during last - rule run. - type: string - nullable: true - type: array - outcome_order: - description: Order of the outcome. - type: number - warning: - description: Warning of last rule execution. - enum: - - read - - decrypt - - execute - - unknown - - license - - timeout - - disabled - - validate - - maxExecutableActions - - maxAlerts - - maxQueuedActions - - ruleExecution - nullable: true - type: string - required: - - outcome - - alerts_count + description: >- + Outcome of last run of the rule. Value could + be succeeded, warning or failed. + enum: + - succeeded + - warning + - failed + type: string success: description: >- Indicates whether the rule run was @@ -5549,11 +4935,13 @@ paths: items: description: Indicates hours of the day to recur. type: number + nullable: true type: array byminute: items: description: Indicates minutes of the hour to recur. type: number + nullable: true type: array bymonth: items: @@ -5561,16 +4949,19 @@ paths: Indicates months of the year that this rule should recur. type: number + nullable: true type: array bymonthday: items: description: Indicates the days of the month to recur. type: number + nullable: true type: array bysecond: items: description: Indicates seconds of the day to recur. type: number + nullable: true type: array bysetpos: items: @@ -5581,6 +4972,7 @@ paths: of the month. It is recommended to not set this manually and just use `byweekday`. type: number + nullable: true type: array byweekday: items: @@ -5594,11 +4986,13 @@ paths: Friday of the month, which are internally converted to a `byweekday/bysetpos` combination. + nullable: true type: array byweekno: items: description: Indicates number of the week hours to recur. type: number + nullable: true type: array byyearday: items: @@ -5606,6 +5000,7 @@ paths: Indicates the days of the year that this rule should recur. type: number + nullable: true type: array count: description: >- @@ -6522,49 +5917,110 @@ paths: post: description: Create a new agent key for APM. operationId: createAgentKey + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' requestBody: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - name: - type: string - privileges: - items: - enum: - - event:write - - config_agent:read - type: string - type: array + $ref: '#/components/schemas/APM_UI_agent_keys_object' required: true responses: '200': content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - api_key: - type: string - encoded: - type: string - expiration: - format: int64 - type: integer - id: - type: string - name: - type: string + $ref: '#/components/schemas/APM_UI_agent_keys_response' description: Agent key created successfully + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response summary: Create an APM agent key tags: - APM agent keys + /api/apm/fleet/apm_server_schema: + post: + operationId: saveApmServerSchema + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + type: object + properties: + schema: + additionalProperties: true + description: Schema object + example: + foo: bar + type: object + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Save APM server schema + tags: + - APM server schema /api/apm/services/{serviceName}/annotation: post: description: Create a new annotation for a specific service. operationId: createAnnotation parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' - description: The name of the service in: path name: serviceName @@ -6575,63 +6031,39 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - '@timestamp': - type: string - message: - type: string - service: - type: object - properties: - environment: - type: string - version: - type: string - tags: - items: - type: string - type: array + $ref: '#/components/schemas/APM_UI_create_annotation_object' required: true responses: '200': content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - _id: - type: string - _index: - type: string - _source: - type: object - properties: - '@timestamp': - type: string - annotation: - type: string - event: - type: object - properties: - created: - type: string - message: - type: string - service: - type: object - properties: - environment: - type: string - name: - type: string - version: - type: string - tags: - items: - type: string - type: array + $ref: '#/components/schemas/APM_UI_create_annotation_response' description: Annotation created successfully + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response summary: Create a service annotation tags: - APM annotations @@ -6640,6 +6072,7 @@ paths: description: Search for annotations related to a specific service. operationId: getAnnotation parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' - description: The name of the service in: path name: serviceName @@ -6669,27 +6102,484 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - annotations: - items: - type: object - properties: - '@timestamp': - type: number - id: - type: string - text: - type: string - type: - enum: - - version - type: string - type: array + $ref: '#/components/schemas/APM_UI_annotation_search_response' description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response summary: Search for annotations tags: - APM annotations + /api/apm/settings/agent-configuration: + delete: + operationId: deleteAgentConfiguration + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_service_object' + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: >- + #/components/schemas/APM_UI_delete_agent_configurations_response + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Delete agent configuration + tags: + - APM agent configuration + get: + operationId: getAgentConfigurations + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_agent_configurations_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Get a list of agent configurations + tags: + - APM agent configuration + put: + operationId: createUpdateAgentConfiguration + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + - description: If the config exists ?overwrite=true is required + in: query + name: overwrite + schema: + type: boolean + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_agent_configuration_intake_object' + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Create or update agent configuration + tags: + - APM agent configuration + /api/apm/settings/agent-configuration/agent_name: + get: + description: Retrieve `agentName` for a service. + operationId: getAgentNameForService + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - description: The name of the service + example: node + in: query + name: serviceName + required: true + schema: + type: string + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_service_agent_name_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Get agent name for service + tags: + - APM agent configuration + /api/apm/settings/agent-configuration/environments: + get: + operationId: getEnvironmentsForService + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - description: The name of the service + in: query + name: serviceName + schema: + type: string + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_service_environments_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Get environments for service + tags: + - APM agent configuration + /api/apm/settings/agent-configuration/search: + post: + description: > + This endpoint allows to search for single agent configuration and update + 'applied_by_agent' field. + operationId: searchSingleConfiguration + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_search_agent_configuration_object' + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: >- + #/components/schemas/APM_UI_search_agent_configuration_response + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Lookup single agent configuration + tags: + - APM agent configuration + /api/apm/settings/agent-configuration/view: + get: + operationId: getSingleAgentConfiguration + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - description: Service name + example: node + in: query + name: name + schema: + type: string + - description: Service environment + example: prod + in: query + name: environment + schema: + type: string + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: >- + #/components/schemas/APM_UI_single_agent_configuration_response + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '404': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_404_response' + description: Not found response + summary: Get single agent configuration + tags: + - APM agent configuration + /api/apm/sourcemaps: + get: + description: Returns an array of Fleet artifacts, including source map uploads. + operationId: getSourceMaps + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - description: Page number + in: query + name: page + schema: + type: number + - description: Number of records per page + in: query + name: perPage + schema: + type: number + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_source_maps_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response + '501': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_501_response' + description: Not Implemented response + summary: Get source maps + tags: + - APM sourcemaps + post: + description: Upload a source map for a specific service and version. + operationId: uploadSourceMap + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + requestBody: + content: + multipart/form-data; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_upload_source_map_object' + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_upload_source_maps_response' + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response + '501': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_501_response' + description: Not Implemented response + summary: Upload source map + tags: + - APM sourcemaps + /api/apm/sourcemaps/{id}: + delete: + description: Delete a previously uploaded source map. + operationId: deleteSourceMap + parameters: + - $ref: '#/components/parameters/APM_UI_elastic_api_version' + - $ref: '#/components/parameters/APM_UI_kbn_xsrf' + - description: Source map identifier + in: path + name: id + required: true + schema: + type: string + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + description: Successful response + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_400_response' + description: Bad Request response + '401': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_401_response' + description: Unauthorized response + '403': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_403_response' + description: Forbidden response + '500': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_500_response' + description: Internal Server Error response + '501': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + $ref: '#/components/schemas/APM_UI_501_response' + description: Not Implemented response + summary: Delete source map + tags: + - APM sourcemaps /api/asset_criticality: delete: description: Delete the asset criticality record for a specific entity. @@ -13414,7 +13304,7 @@ paths: /api/fleet/agent_download_sources: get: description: List agent binary download sources - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources#0' + operationId: get-fleet-agent-download-sources parameters: - description: The version of the API to use in: header @@ -13490,7 +13380,7 @@ paths: - Elastic Agent binary download sources post: description: Create agent binary download source - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources#1' + operationId: post-fleet-agent-download-sources parameters: - description: The version of the API to use in: header @@ -13589,7 +13479,7 @@ paths: /api/fleet/agent_download_sources/{sourceId}: delete: description: Delete agent binary download source by ID - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#2' + operationId: delete-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use in: header @@ -13644,7 +13534,7 @@ paths: - Elastic Agent binary download sources get: description: Get agent binary download source by ID - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#0' + operationId: get-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use in: header @@ -13714,7 +13604,7 @@ paths: - Elastic Agent binary download sources put: description: Update agent binary download source by ID - operationId: '%2Fapi%2Ffleet%2Fagent_download_sources%2F%7BsourceId%7D#1' + operationId: put-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use in: header @@ -13818,7 +13708,7 @@ paths: /api/fleet/agent_policies: get: description: List agent policies - operationId: '%2Fapi%2Ffleet%2Fagent_policies#0' + operationId: get-fleet-agent-policies parameters: - description: The version of the API to use in: header @@ -14432,7 +14322,7 @@ paths: - Elastic Agent policies post: description: Create an agent policy - operationId: '%2Fapi%2Ffleet%2Fagent_policies#1' + operationId: post-fleet-agent-policies parameters: - description: The version of the API to use in: header @@ -15167,7 +15057,7 @@ paths: /api/fleet/agent_policies/_bulk_get: post: description: Bulk get agent policies - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F_bulk_get#0' + operationId: post-fleet-agent-policies-bulk-get parameters: - description: The version of the API to use in: header @@ -15747,7 +15637,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}: get: description: Get an agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D#0' + operationId: get-fleet-agent-policies-agentpolicyid parameters: - description: The version of the API to use in: header @@ -16303,7 +16193,7 @@ paths: - Elastic Agent policies put: description: Update an agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D#1' + operationId: put-fleet-agent-policies-agentpolicyid parameters: - description: The version of the API to use in: header @@ -17046,7 +16936,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}/copy: post: description: Copy an agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Fcopy#0' + operationId: post-fleet-agent-policies-agentpolicyid-copy parameters: - description: The version of the API to use in: header @@ -17624,7 +17514,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}/download: get: description: Download an agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Fdownload#0' + operationId: get-fleet-agent-policies-agentpolicyid-download parameters: - description: The version of the API to use in: header @@ -17698,7 +17588,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}/full: get: description: Get a full agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Ffull#0' + operationId: get-fleet-agent-policies-agentpolicyid-full parameters: - description: The version of the API to use in: header @@ -18030,7 +17920,7 @@ paths: /api/fleet/agent_policies/{agentPolicyId}/outputs: get: description: Get list of outputs associated with agent policy by policy id - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2F%7BagentPolicyId%7D%2Foutputs#0' + operationId: get-fleet-agent-policies-agentpolicyid-outputs parameters: - description: The version of the API to use in: header @@ -18134,7 +18024,7 @@ paths: /api/fleet/agent_policies/delete: post: description: Delete agent policy by ID - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2Fdelete#0' + operationId: post-fleet-agent-policies-delete parameters: - description: The version of the API to use in: header @@ -18204,7 +18094,7 @@ paths: /api/fleet/agent_policies/outputs: post: description: Get list of outputs associated with agent policies - operationId: '%2Fapi%2Ffleet%2Fagent_policies%2Foutputs#0' + operationId: post-fleet-agent-policies-outputs parameters: - description: The version of the API to use in: header @@ -18326,7 +18216,7 @@ paths: /api/fleet/agent_status: get: description: Get agent status summary - operationId: '%2Fapi%2Ffleet%2Fagent_status#0' + operationId: get-fleet-agent-status parameters: - description: The version of the API to use in: header @@ -18354,7 +18244,6 @@ paths: name: kuery required: false schema: - deprecated: true type: string responses: '200': @@ -18384,16 +18273,12 @@ paths: type: number other: type: number - total: - deprecated: true - type: number unenrolled: type: number updating: type: number required: - events - - total - online - error - offline @@ -18427,7 +18312,7 @@ paths: /api/fleet/agent_status/data: get: description: Get incoming agent data - operationId: '%2Fapi%2Ffleet%2Fagent_status%2Fdata#0' + operationId: get-fleet-agent-status-data parameters: - description: The version of the API to use in: header @@ -18497,45 +18382,10 @@ paths: summary: '' tags: - Elastic Agents - /api/fleet/agent-status: - get: - operationId: '%2Fapi%2Ffleet%2Fagent-status#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - in: query - name: policyId - required: false - schema: - type: string - - in: query - name: policyIds - required: false - schema: - anyOf: - - items: - type: string - type: array - - type: string - - in: query - name: kuery - required: false - schema: - deprecated: true - type: string - responses: {} - summary: '' - tags: [] /api/fleet/agents: get: description: List agents - operationId: '%2Fapi%2Ffleet%2Fagents#0' + operationId: get-fleet-agents parameters: - description: The version of the API to use in: header @@ -18885,285 +18735,6 @@ paths: - enrolled_at - local_metadata type: array - list: - deprecated: true - items: - additionalProperties: false - type: object - properties: - access_api_key: - type: string - access_api_key_id: - type: string - active: - type: boolean - agent: - additionalProperties: true - type: object - properties: - id: - type: string - version: - type: string - required: - - id - - version - components: - items: - additionalProperties: false - type: object - properties: - id: - type: string - message: - type: string - status: - enum: - - STARTING - - CONFIGURING - - HEALTHY - - DEGRADED - - FAILED - - STOPPING - - STOPPED - type: string - type: - type: string - units: - items: - additionalProperties: false - type: object - properties: - id: - type: string - message: - type: string - payload: - additionalProperties: {} - type: object - status: - enum: - - STARTING - - CONFIGURING - - HEALTHY - - DEGRADED - - FAILED - - STOPPING - - STOPPED - type: string - type: - enum: - - input - - output - type: string - required: - - id - - type - - status - - message - type: array - required: - - id - - type - - status - - message - type: array - default_api_key: - type: string - default_api_key_history: - items: - additionalProperties: false - deprecated: true - type: object - properties: - id: - type: string - retired_at: - type: string - required: - - id - - retired_at - type: array - default_api_key_id: - type: string - enrolled_at: - type: string - id: - type: string - last_checkin: - type: string - last_checkin_message: - type: string - last_checkin_status: - enum: - - error - - online - - degraded - - updating - - starting - type: string - local_metadata: - additionalProperties: {} - type: object - metrics: - additionalProperties: false - type: object - properties: - cpu_avg: - type: number - memory_size_byte_avg: - type: number - namespaces: - items: - type: string - type: array - outputs: - additionalProperties: - additionalProperties: false - type: object - properties: - api_key_id: - type: string - to_retire_api_key_ids: - items: - additionalProperties: false - type: object - properties: - id: - type: string - retired_at: - type: string - required: - - id - - retired_at - type: array - type: - type: string - required: - - api_key_id - - type - type: object - packages: - items: - type: string - type: array - policy_id: - type: string - policy_revision: - nullable: true - type: number - sort: - items: - anyOf: - - type: number - - type: string - - enum: [] - nullable: true - type: array - status: - enum: - - offline - - error - - online - - inactive - - enrolling - - unenrolling - - unenrolled - - updating - - degraded - type: string - tags: - items: - type: string - type: array - type: - enum: - - PERMANENT - - EPHEMERAL - - TEMPORARY - type: string - unenrolled_at: - type: string - unenrollment_started_at: - type: string - unhealthy_reason: - items: - enum: - - input - - output - - other - type: string - nullable: true - type: array - upgrade_details: - additionalProperties: false - type: object - properties: - action_id: - type: string - metadata: - additionalProperties: false - type: object - properties: - download_percent: - type: number - download_rate: - type: number - error_msg: - type: string - failed_state: - enum: - - UPG_REQUESTED - - UPG_SCHEDULED - - UPG_DOWNLOADING - - UPG_EXTRACTING - - UPG_REPLACING - - UPG_RESTARTING - - UPG_FAILED - - UPG_WATCHING - - UPG_ROLLBACK - type: string - retry_error_msg: - type: string - retry_until: - type: string - scheduled_at: - type: string - state: - enum: - - UPG_REQUESTED - - UPG_SCHEDULED - - UPG_DOWNLOADING - - UPG_EXTRACTING - - UPG_REPLACING - - UPG_RESTARTING - - UPG_FAILED - - UPG_WATCHING - - UPG_ROLLBACK - type: string - target_version: - type: string - required: - - target_version - - action_id - - state - upgrade_started_at: - nullable: true - type: string - upgraded_at: - nullable: true - type: string - user_provided_metadata: - additionalProperties: {} - type: object - required: - - id - - packages - - type - - active - - enrolled_at - - local_metadata - type: array page: type: number perPage: @@ -19200,7 +18771,7 @@ paths: - Elastic Agents post: description: List agents by action ids - operationId: '%2Fapi%2Ffleet%2Fagents#1' + operationId: post-fleet-agents parameters: - description: The version of the API to use in: header @@ -19266,7 +18837,7 @@ paths: /api/fleet/agents/{agentId}: delete: description: Delete agent by ID - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#2' + operationId: delete-fleet-agents-agentid parameters: - description: The version of the API to use in: header @@ -19323,7 +18894,7 @@ paths: - Elastic Agents get: description: Get agent by ID - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#0' + operationId: get-fleet-agents-agentid parameters: - description: The version of the API to use in: header @@ -19651,7 +19222,7 @@ paths: - Elastic Agents put: description: Update agent by ID - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D#1' + operationId: put-fleet-agents-agentid parameters: - description: The version of the API to use in: header @@ -19995,213 +19566,152 @@ paths: /api/fleet/agents/{agentId}/actions: post: description: Create agent action - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Factions#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - - in: path - name: agentId - required: true - schema: - type: string - requestBody: - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - action: - anyOf: - - additionalProperties: false - type: object - properties: - ack_data: {} - data: {} - type: - enum: - - UNENROLL - - UPGRADE - - POLICY_REASSIGN - type: string - required: - - type - - data - - ack_data - - additionalProperties: false - type: object - properties: - data: - additionalProperties: false - type: object - properties: - log_level: - enum: - - debug - - info - - warning - - error - nullable: true - type: string - required: - - log_level - type: - enum: - - SETTINGS - type: string - required: - - type - - data - required: - - action - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - item: - additionalProperties: false - type: object - properties: - ack_data: {} - agents: - items: - type: string - type: array - created_at: - type: string - data: {} - expiration: - type: string - id: - type: string - minimum_execution_duration: - type: number - namespaces: - items: - type: string - type: array - rollout_duration_seconds: - type: number - sent_at: - type: string - source_uri: - type: string - start_time: - type: string - total: - type: number - type: - type: string - required: - - id - - type - - data - - created_at - - ack_data - - agents - required: - - item - '400': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - description: Generic Error - type: object - properties: - error: - type: string - message: - type: string - statusCode: - type: number - required: - - message - summary: '' - tags: - - Elastic Agent actions - /api/fleet/agents/{agentId}/reassign: - post: - description: Reassign agent - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Freassign#1' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - - in: path - name: agentId - required: true - schema: - type: string - requestBody: - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: - policy_id: - type: string - required: - - policy_id - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - type: object - properties: {} - '400': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - additionalProperties: false - description: Generic Error - type: object - properties: - error: - type: string - message: - type: string - statusCode: - type: number - required: - - message - summary: '' - tags: - - Elastic Agent actions - put: - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Freassign#0' + operationId: post-fleet-agents-agentid-actions + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: agentId + required: true + schema: + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + action: + anyOf: + - additionalProperties: false + type: object + properties: + ack_data: {} + data: {} + type: + enum: + - UNENROLL + - UPGRADE + - POLICY_REASSIGN + type: string + required: + - type + - data + - ack_data + - additionalProperties: false + type: object + properties: + data: + additionalProperties: false + type: object + properties: + log_level: + enum: + - debug + - info + - warning + - error + nullable: true + type: string + required: + - log_level + type: + enum: + - SETTINGS + type: string + required: + - type + - data + required: + - action + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + item: + additionalProperties: false + type: object + properties: + ack_data: {} + agents: + items: + type: string + type: array + created_at: + type: string + data: {} + expiration: + type: string + id: + type: string + minimum_execution_duration: + type: number + namespaces: + items: + type: string + type: array + rollout_duration_seconds: + type: number + sent_at: + type: string + source_uri: + type: string + start_time: + type: string + total: + type: number + type: + type: string + required: + - id + - type + - data + - created_at + - ack_data + - agents + required: + - item + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + description: Generic Error + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: number + required: + - message + summary: '' + tags: + - Elastic Agent actions + /api/fleet/agents/{agentId}/reassign: + post: + description: Reassign agent + operationId: post-fleet-agents-agentid-reassign parameters: - description: The version of the API to use in: header @@ -20234,13 +19744,37 @@ paths: type: string required: - policy_id - responses: {} + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: {} + '400': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + description: Generic Error + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: number + required: + - message summary: '' - tags: [] + tags: + - Elastic Agent actions /api/fleet/agents/{agentId}/request_diagnostics: post: description: Request agent diagnostics - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Frequest_diagnostics#0' + operationId: post-fleet-agents-agentid-request-diagnostics parameters: - description: The version of the API to use in: header @@ -20310,7 +19844,7 @@ paths: /api/fleet/agents/{agentId}/unenroll: post: description: Unenroll agent - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Funenroll#0' + operationId: post-fleet-agents-agentid-unenroll parameters: - description: The version of the API to use in: header @@ -20351,7 +19885,7 @@ paths: /api/fleet/agents/{agentId}/upgrade: post: description: Upgrade agent - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Fupgrade#0' + operationId: post-fleet-agents-agentid-upgrade parameters: - description: The version of the API to use in: header @@ -20420,7 +19954,7 @@ paths: /api/fleet/agents/{agentId}/uploads: get: description: List agent uploads - operationId: '%2Fapi%2Ffleet%2Fagents%2F%7BagentId%7D%2Fuploads#0' + operationId: get-fleet-agents-agentid-uploads parameters: - description: The version of the API to use in: header @@ -20501,7 +20035,7 @@ paths: /api/fleet/agents/action_status: get: description: Get agent action status - operationId: '%2Fapi%2Ffleet%2Fagents%2Faction_status#0' + operationId: get-fleet-agents-action-status parameters: - description: The version of the API to use in: header @@ -20669,7 +20203,7 @@ paths: /api/fleet/agents/actions/{actionId}/cancel: post: description: Cancel agent action - operationId: '%2Fapi%2Ffleet%2Fagents%2Factions%2F%7BactionId%7D%2Fcancel#0' + operationId: post-fleet-agents-actions-actionid-cancel parameters: - description: The version of the API to use in: header @@ -20764,7 +20298,7 @@ paths: /api/fleet/agents/available_versions: get: description: Get available agent versions - operationId: '%2Fapi%2Ffleet%2Fagents%2Favailable_versions#0' + operationId: get-fleet-agents-available-versions parameters: - description: The version of the API to use in: header @@ -20810,7 +20344,7 @@ paths: /api/fleet/agents/bulk_reassign: post: description: Bulk reassign agents - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_reassign#0' + operationId: post-fleet-agents-bulk-reassign parameters: - description: The version of the API to use in: header @@ -20884,7 +20418,7 @@ paths: /api/fleet/agents/bulk_request_diagnostics: post: description: Bulk request diagnostics from agents - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_request_diagnostics#0' + operationId: post-fleet-agents-bulk-request-diagnostics parameters: - description: The version of the API to use in: header @@ -20958,7 +20492,7 @@ paths: /api/fleet/agents/bulk_unenroll: post: description: Bulk unenroll agents - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_unenroll#0' + operationId: post-fleet-agents-bulk-unenroll parameters: - description: The version of the API to use in: header @@ -21039,7 +20573,7 @@ paths: /api/fleet/agents/bulk_update_agent_tags: post: description: Bulk update agent tags - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_update_agent_tags#0' + operationId: post-fleet-agents-bulk-update-agent-tags parameters: - description: The version of the API to use in: header @@ -21118,7 +20652,7 @@ paths: /api/fleet/agents/bulk_upgrade: post: description: Bulk upgrade agents - operationId: '%2Fapi%2Ffleet%2Fagents%2Fbulk_upgrade#0' + operationId: post-fleet-agents-bulk-upgrade parameters: - description: The version of the API to use in: header @@ -21203,7 +20737,7 @@ paths: /api/fleet/agents/files/{fileId}: delete: description: Delete file uploaded by agent - operationId: '%2Fapi%2Ffleet%2Fagents%2Ffiles%2F%7BfileId%7D#0' + operationId: delete-fleet-agents-files-fileid parameters: - description: The version of the API to use in: header @@ -21262,7 +20796,7 @@ paths: /api/fleet/agents/files/{fileId}/{fileName}: get: description: Get file uploaded by agent - operationId: '%2Fapi%2Ffleet%2Fagents%2Ffiles%2F%7BfileId%7D%2F%7BfileName%7D#0' + operationId: get-fleet-agents-files-fileid-filename parameters: - description: The version of the API to use in: header @@ -21310,7 +20844,7 @@ paths: /api/fleet/agents/setup: get: description: Get agent setup info - operationId: '%2Fapi%2Ffleet%2Fagents%2Fsetup#0' + operationId: get-fleet-agents-setup parameters: - description: The version of the API to use in: header @@ -21381,7 +20915,7 @@ paths: - Elastic Agents post: description: Initiate agent setup - operationId: '%2Fapi%2Ffleet%2Fagents%2Fsetup#1' + operationId: post-fleet-agents-setup parameters: - description: The version of the API to use in: header @@ -21451,7 +20985,7 @@ paths: /api/fleet/agents/tags: get: description: List agent tags - operationId: '%2Fapi%2Ffleet%2Fagents%2Ftags#0' + operationId: get-fleet-agents-tags parameters: - description: The version of the API to use in: header @@ -21508,7 +21042,7 @@ paths: /api/fleet/check-permissions: get: description: Check permissions - operationId: '%2Fapi%2Ffleet%2Fcheck-permissions#0' + operationId: get-fleet-check-permissions parameters: - description: The version of the API to use in: header @@ -21563,7 +21097,7 @@ paths: /api/fleet/data_streams: get: description: List data streams - operationId: '%2Fapi%2Ffleet%2Fdata_streams#0' + operationId: get-fleet-data-streams parameters: - description: The version of the API to use in: header @@ -21668,7 +21202,7 @@ paths: /api/fleet/enrollment_api_keys: get: description: List enrollment API keys - operationId: '%2Fapi%2Ffleet%2Fenrollment_api_keys#0' + operationId: get-fleet-enrollment-api-keys parameters: - description: The version of the API to use in: header @@ -21811,7 +21345,7 @@ paths: - Fleet enrollment API keys post: description: Create enrollment API key - operationId: '%2Fapi%2Ffleet%2Fenrollment_api_keys#1' + operationId: post-fleet-enrollment-api-keys parameters: - description: The version of the API to use in: header @@ -21915,7 +21449,7 @@ paths: /api/fleet/enrollment_api_keys/{keyId}: delete: description: Revoke enrollment API key by ID by marking it as inactive - operationId: '%2Fapi%2Ffleet%2Fenrollment_api_keys%2F%7BkeyId%7D#1' + operationId: delete-fleet-enrollment-api-keys-keyid parameters: - description: The version of the API to use in: header @@ -21972,7 +21506,7 @@ paths: - Fleet enrollment API keys get: description: Get enrollment API key by ID - operationId: '%2Fapi%2Ffleet%2Fenrollment_api_keys%2F%7BkeyId%7D#0' + operationId: get-fleet-enrollment-api-keys-keyid parameters: - description: The version of the API to use in: header @@ -22053,7 +21587,7 @@ paths: - Fleet enrollment API keys /api/fleet/enrollment-api-keys: get: - operationId: '%2Fapi%2Ffleet%2Fenrollment-api-keys#0' + operationId: get-fleet-enrollment-api-keys-2 parameters: - description: The version of the API to use in: header @@ -22084,7 +21618,7 @@ paths: summary: '' tags: [] post: - operationId: '%2Fapi%2Ffleet%2Fenrollment-api-keys#1' + operationId: post-fleet-enrollment-api-keys-2 parameters: - description: The version of the API to use in: header @@ -22121,7 +21655,7 @@ paths: tags: [] /api/fleet/enrollment-api-keys/{keyId}: delete: - operationId: '%2Fapi%2Ffleet%2Fenrollment-api-keys%2F%7BkeyId%7D#1' + operationId: delete-fleet-enrollment-api-keys-keyid-2 parameters: - description: The version of the API to use in: header @@ -22147,7 +21681,7 @@ paths: summary: '' tags: [] get: - operationId: '%2Fapi%2Ffleet%2Fenrollment-api-keys%2F%7BkeyId%7D#0' + operationId: get-fleet-enrollment-api-keys-keyid-2 parameters: - description: The version of the API to use in: header @@ -22168,7 +21702,7 @@ paths: /api/fleet/epm/bulk_assets: post: description: Bulk get assets - operationId: '%2Fapi%2Ffleet%2Fepm%2Fbulk_assets#0' + operationId: post-fleet-epm-bulk-assets parameters: - description: The version of the API to use in: header @@ -22267,7 +21801,7 @@ paths: /api/fleet/epm/categories: get: description: List package categories - operationId: '%2Fapi%2Ffleet%2Fepm%2Fcategories#0' + operationId: get-fleet-epm-categories parameters: - description: The version of the API to use in: header @@ -22365,7 +21899,7 @@ paths: /api/fleet/epm/custom_integrations: post: description: Create custom integration - operationId: '%2Fapi%2Ffleet%2Fepm%2Fcustom_integrations#0' + operationId: post-fleet-epm-custom-integrations parameters: - description: The version of the API to use in: header @@ -22561,7 +22095,7 @@ paths: /api/fleet/epm/data_streams: get: description: List data streams - operationId: '%2Fapi%2Ffleet%2Fepm%2Fdata_streams#0' + operationId: get-fleet-epm-data-streams parameters: - description: The version of the API to use in: header @@ -22644,7 +22178,7 @@ paths: /api/fleet/epm/packages: get: description: List packages - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages#0' + operationId: get-fleet-epm-packages parameters: - description: The version of the API to use in: header @@ -23398,7 +22932,7 @@ paths: - Elastic Package Manager (EPM) post: description: Install package by upload - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages#1' + operationId: post-fleet-epm-packages parameters: - description: The version of the API to use in: header @@ -23579,7 +23113,7 @@ paths: /api/fleet/epm/packages/_bulk: post: description: Bulk install packages - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F_bulk#0' + operationId: post-fleet-epm-packages-bulk parameters: - description: The version of the API to use in: header @@ -23861,7 +23395,7 @@ paths: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgkey}: delete: - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#3' + operationId: delete-fleet-epm-packages-pkgkey parameters: - description: The version of the API to use in: header @@ -23899,7 +23433,7 @@ paths: summary: '' tags: [] get: - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#0' + operationId: get-fleet-epm-packages-pkgkey parameters: - description: The version of the API to use in: header @@ -23939,7 +23473,7 @@ paths: summary: '' tags: [] post: - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#2' + operationId: post-fleet-epm-packages-pkgkey parameters: - description: The version of the API to use in: header @@ -23994,7 +23528,7 @@ paths: summary: '' tags: [] put: - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7Bpkgkey%7D#1' + operationId: put-fleet-epm-packages-pkgkey parameters: - description: The version of the API to use in: header @@ -24033,7 +23567,7 @@ paths: /api/fleet/epm/packages/{pkgName}/{pkgVersion}: delete: description: Delete package - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#3' + operationId: delete-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use in: header @@ -24213,7 +23747,7 @@ paths: - Elastic Package Manager (EPM) get: description: Get package - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#0' + operationId: get-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use in: header @@ -25098,7 +24632,7 @@ paths: - Elastic Package Manager (EPM) post: description: Install package from registry - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#2' + operationId: post-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use in: header @@ -25301,7 +24835,7 @@ paths: - Elastic Package Manager (EPM) put: description: Update package settings - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D#1' + operationId: put-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use in: header @@ -26176,8 +25710,7 @@ paths: /api/fleet/epm/packages/{pkgName}/{pkgVersion}/{filePath*}: get: description: Get package file - operationId: >- - %2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2F%7BfilePath*%7D#0 + operationId: get-fleet-epm-packages-pkgname-pkgversion-filepath parameters: - description: The version of the API to use in: header @@ -26229,8 +25762,7 @@ paths: /api/fleet/epm/packages/{pkgName}/{pkgVersion}/transforms/authorize: post: description: Authorize transforms - operationId: >- - %2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2Ftransforms%2Fauthorize#0 + operationId: post-fleet-epm-packages-pkgname-pkgversion-transforms-authorize parameters: - description: The version of the API to use in: header @@ -26323,7 +25855,7 @@ paths: /api/fleet/epm/packages/{pkgName}/stats: get: description: Get package stats - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2F%7BpkgName%7D%2Fstats#0' + operationId: get-fleet-epm-packages-pkgname-stats parameters: - description: The version of the API to use in: header @@ -26378,7 +25910,7 @@ paths: /api/fleet/epm/packages/installed: get: description: Get installed packages - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2Finstalled#0' + operationId: get-fleet-epm-packages-installed parameters: - description: The version of the API to use in: header @@ -26532,7 +26064,7 @@ paths: /api/fleet/epm/packages/limited: get: description: Get limited package list - operationId: '%2Fapi%2Ffleet%2Fepm%2Fpackages%2Flimited#0' + operationId: get-fleet-epm-packages-limited parameters: - description: The version of the API to use in: header @@ -26583,8 +26115,7 @@ paths: /api/fleet/epm/templates/{pkgName}/{pkgVersion}/inputs: get: description: Get inputs template - operationId: >- - %2Fapi%2Ffleet%2Fepm%2Ftemplates%2F%7BpkgName%7D%2F%7BpkgVersion%7D%2Finputs#0 + operationId: get-fleet-epm-templates-pkgname-pkgversion-inputs parameters: - description: The version of the API to use in: header @@ -26692,7 +26223,7 @@ paths: /api/fleet/epm/verification_key_id: get: description: Get a package signature verification key ID - operationId: '%2Fapi%2Ffleet%2Fepm%2Fverification_key_id#0' + operationId: get-fleet-epm-verification-key-id parameters: - description: The version of the API to use in: header @@ -26737,7 +26268,7 @@ paths: /api/fleet/fleet_server_hosts: get: description: List Fleet Server hosts - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts#0' + operationId: get-fleet-fleet-server-hosts parameters: - description: The version of the API to use in: header @@ -26817,7 +26348,7 @@ paths: - Fleet Server hosts post: description: Create Fleet Server host - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts#1' + operationId: post-fleet-fleet-server-hosts parameters: - description: The version of the API to use in: header @@ -26924,7 +26455,7 @@ paths: /api/fleet/fleet_server_hosts/{itemId}: delete: description: Delete Fleet Server host by ID - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#1' + operationId: delete-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use in: header @@ -26979,7 +26510,7 @@ paths: - Fleet Server hosts get: description: Get Fleet Server host by ID - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#0' + operationId: get-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use in: header @@ -27053,7 +26584,7 @@ paths: - Fleet Server hosts put: description: Update Fleet Server host by ID - operationId: '%2Fapi%2Ffleet%2Ffleet_server_hosts%2F%7BitemId%7D#2' + operationId: put-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use in: header @@ -27158,7 +26689,7 @@ paths: /api/fleet/health_check: post: description: Check Fleet Server health - operationId: '%2Fapi%2Ffleet%2Fhealth_check#0' + operationId: post-fleet-health-check parameters: - description: The version of the API to use in: header @@ -27246,7 +26777,7 @@ paths: /api/fleet/kubernetes: get: description: Get full K8s agent manifest - operationId: '%2Fapi%2Ffleet%2Fkubernetes#0' + operationId: get-fleet-kubernetes parameters: - description: The version of the API to use in: header @@ -27304,7 +26835,7 @@ paths: - Elastic Agent policies /api/fleet/kubernetes/download: get: - operationId: '%2Fapi%2Ffleet%2Fkubernetes%2Fdownload#0' + operationId: get-fleet-kubernetes-download parameters: - description: The version of the API to use in: header @@ -27373,7 +26904,7 @@ paths: /api/fleet/logstash_api_keys: post: description: Generate Logstash API key - operationId: '%2Fapi%2Ffleet%2Flogstash_api_keys#0' + operationId: post-fleet-logstash-api-keys parameters: - description: The version of the API to use in: header @@ -27424,7 +26955,7 @@ paths: /api/fleet/message_signing_service/rotate_key_pair: post: description: Rotate fleet message signing key pair - operationId: '%2Fapi%2Ffleet%2Fmessage_signing_service%2Frotate_key_pair#0' + operationId: post-fleet-message-signing-service-rotate-key-pair parameters: - description: The version of the API to use in: header @@ -27497,7 +27028,7 @@ paths: /api/fleet/outputs: get: description: List outputs - operationId: '%2Fapi%2Ffleet%2Foutputs#0' + operationId: get-fleet-outputs parameters: - description: The version of the API to use in: header @@ -28253,7 +27784,7 @@ paths: - Fleet outputs post: description: Create output - operationId: '%2Fapi%2Ffleet%2Foutputs#1' + operationId: post-fleet-outputs parameters: - description: The version of the API to use in: header @@ -29713,7 +29244,7 @@ paths: /api/fleet/outputs/{outputId}: delete: description: Delete output by ID - operationId: '%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#2' + operationId: delete-fleet-outputs-outputid parameters: - description: The version of the API to use in: header @@ -29784,7 +29315,7 @@ paths: - Fleet outputs get: description: Get output by ID - operationId: '%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#0' + operationId: get-fleet-outputs-outputid parameters: - description: The version of the API to use in: header @@ -30534,7 +30065,7 @@ paths: - Fleet outputs put: description: Update output by ID - operationId: '%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D#1' + operationId: put-fleet-outputs-outputid parameters: - description: The version of the API to use in: header @@ -31978,7 +31509,7 @@ paths: /api/fleet/outputs/{outputId}/health: get: description: Get latest output health - operationId: '%2Fapi%2Ffleet%2Foutputs%2F%7BoutputId%7D%2Fhealth#0' + operationId: get-fleet-outputs-outputid-health parameters: - description: The version of the API to use in: header @@ -32036,7 +31567,7 @@ paths: /api/fleet/package_policies: get: description: List package policies - operationId: '%2Fapi%2Ffleet%2Fpackage_policies#0' + operationId: get-fleet-package-policies parameters: - description: The version of the API to use in: header @@ -32541,7 +32072,7 @@ paths: - Fleet package policies post: description: Create package policy - operationId: '%2Fapi%2Ffleet%2Fpackage_policies#1' + operationId: post-fleet-package-policies parameters: - description: The version of the API to use in: header @@ -33444,7 +32975,7 @@ paths: /api/fleet/package_policies/_bulk_get: post: description: Bulk get package policies - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2F_bulk_get#0' + operationId: post-fleet-package-policies-bulk-get parameters: - description: The version of the API to use in: header @@ -33937,7 +33468,7 @@ paths: /api/fleet/package_policies/{packagePolicyId}: delete: description: Delete package policy by ID - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#2' + operationId: delete-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use in: header @@ -33997,7 +33528,7 @@ paths: - Fleet package policies get: description: Get package policy by ID - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#0' + operationId: get-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use in: header @@ -34466,7 +33997,7 @@ paths: - Fleet package policies put: description: Update package policy by ID - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2F%7BpackagePolicyId%7D#1' + operationId: put-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use in: header @@ -35363,7 +34894,7 @@ paths: /api/fleet/package_policies/delete: post: description: Bulk delete package policies - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2Fdelete#0' + operationId: post-fleet-package-policies-delete parameters: - description: The version of the API to use in: header @@ -35500,7 +35031,7 @@ paths: /api/fleet/package_policies/upgrade: post: description: Upgrade package policy to a newer package version - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2Fupgrade#0' + operationId: post-fleet-package-policies-upgrade parameters: - description: The version of the API to use in: header @@ -35581,7 +35112,7 @@ paths: /api/fleet/package_policies/upgrade/dryrun: post: description: Dry run package policy upgrade - operationId: '%2Fapi%2Ffleet%2Fpackage_policies%2Fupgrade%2Fdryrun#0' + operationId: post-fleet-package-policies-upgrade-dryrun parameters: - description: The version of the API to use in: header @@ -36431,7 +35962,7 @@ paths: /api/fleet/proxies: get: description: List proxies - operationId: '%2Fapi%2Ffleet%2Fproxies#0' + operationId: get-fleet-proxies parameters: - description: The version of the API to use in: header @@ -36517,7 +36048,7 @@ paths: - Fleet proxies post: description: Create proxy - operationId: '%2Fapi%2Ffleet%2Fproxies#1' + operationId: post-fleet-proxies parameters: - description: The version of the API to use in: header @@ -36636,7 +36167,7 @@ paths: /api/fleet/proxies/{itemId}: delete: description: Delete proxy by ID - operationId: '%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#2' + operationId: delete-fleet-proxies-itemid parameters: - description: The version of the API to use in: header @@ -36691,7 +36222,7 @@ paths: - Fleet proxies get: description: Get proxy by ID - operationId: '%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#1' + operationId: get-fleet-proxies-itemid parameters: - description: The version of the API to use in: header @@ -36771,7 +36302,7 @@ paths: - Fleet proxies put: description: Update proxy by ID - operationId: '%2Fapi%2Ffleet%2Fproxies%2F%7BitemId%7D#0' + operationId: put-fleet-proxies-itemid parameters: - description: The version of the API to use in: header @@ -36892,7 +36423,7 @@ paths: /api/fleet/service_tokens: post: description: Create a service token - operationId: '%2Fapi%2Ffleet%2Fservice_tokens#0' + operationId: post-fleet-service-tokens parameters: - description: The version of the API to use in: header @@ -36954,33 +36485,10 @@ paths: summary: '' tags: - Fleet service tokens - /api/fleet/service-tokens: - post: - description: Create a service token - operationId: '%2Fapi%2Ffleet%2Fservice-tokens#0' - parameters: - - description: The version of the API to use - in: header - name: elastic-api-version - schema: - default: '2023-10-31' - enum: - - '2023-10-31' - type: string - - description: A required header to protect against CSRF attacks - in: header - name: kbn-xsrf - required: true - schema: - example: 'true' - type: string - responses: {} - summary: '' - tags: [] /api/fleet/settings: get: description: Get settings - operationId: '%2Fapi%2Ffleet%2Fsettings#0' + operationId: get-fleet-settings parameters: - description: The version of the API to use in: header @@ -37079,7 +36587,7 @@ paths: - Fleet internals put: description: Update settings - operationId: '%2Fapi%2Ffleet%2Fsettings#1' + operationId: put-fleet-settings parameters: - description: The version of the API to use in: header @@ -37222,7 +36730,7 @@ paths: /api/fleet/setup: post: description: Initiate Fleet setup - operationId: '%2Fapi%2Ffleet%2Fsetup#0' + operationId: post-fleet-setup parameters: - description: The version of the API to use in: header @@ -37304,7 +36812,7 @@ paths: /api/fleet/uninstall_tokens: get: description: List metadata for latest uninstall tokens per agent policy - operationId: '%2Fapi%2Ffleet%2Funinstall_tokens#0' + operationId: get-fleet-uninstall-tokens parameters: - description: The version of the API to use in: header @@ -37404,7 +36912,7 @@ paths: /api/fleet/uninstall_tokens/{uninstallTokenId}: get: description: Get one decrypted uninstall token by its ID - operationId: '%2Fapi%2Ffleet%2Funinstall_tokens%2F%7BuninstallTokenId%7D#0' + operationId: get-fleet-uninstall-tokens-uninstalltokenid parameters: - description: The version of the API to use in: header @@ -38921,7 +38429,7 @@ paths: nullable: true type: string - in: query - name: userFilter + name: createdByFilter schema: nullable: true type: string @@ -40876,7 +40384,7 @@ paths: - Prompts API /api/security/role: get: - operationId: '%2Fapi%2Fsecurity%2Frole#0' + operationId: get-security-role parameters: - description: The version of the API to use in: header @@ -40886,18 +40394,24 @@ paths: enum: - '2023-10-31' type: string - - in: query + - description: >- + If `true` and the response contains any privileges that are + associated with deprecated features, they are omitted in favor of + details about the appropriate replacement feature privileges. + in: query name: replaceDeprecatedPrivileges required: false schema: type: boolean - responses: {} + responses: + '200': + description: Indicates a successful call. summary: Get all roles tags: - roles /api/security/role/{name}: delete: - operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#1' + operationId: delete-security-role-name parameters: - description: The version of the API to use in: header @@ -40920,12 +40434,14 @@ paths: schema: minLength: 1 type: string - responses: {} + responses: + '204': + description: Indicates a successful call. summary: Delete a role tags: - roles get: - operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#0' + operationId: get-security-role-name parameters: - description: The version of the API to use in: header @@ -40935,23 +40451,33 @@ paths: enum: - '2023-10-31' type: string - - in: path + - description: The role name. + in: path name: name required: true schema: minLength: 1 type: string - - in: query + - description: >- + If `true` and the response contains any privileges that are + associated with deprecated features, they are omitted in favor of + details about the appropriate replacement feature privileges. + in: query name: replaceDeprecatedPrivileges required: false schema: type: boolean - responses: {} + responses: + '200': + description: Indicates a successful call. summary: Get a role tags: - roles put: - operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#2' + description: >- + Create a new Kibana role or update the attributes of an existing role. + Kibana roles are stored in the Elasticsearch native realm. + operationId: put-security-role-name parameters: - description: The version of the API to use in: header @@ -40968,14 +40494,16 @@ paths: schema: example: 'true' type: string - - in: path + - description: The role name. + in: path name: name required: true schema: maxLength: 1024 minLength: 1 type: string - - in: query + - description: When true, a role is not overwritten if it already exists. + in: query name: createOnly required: false schema: @@ -40989,6 +40517,7 @@ paths: type: object properties: description: + description: A description for the role. maxLength: 2048 type: string elasticsearch: @@ -40997,6 +40526,9 @@ paths: properties: cluster: items: + description: >- + Cluster privileges that define the cluster level + actions that users can perform. type: string type: array indices: @@ -41005,24 +40537,55 @@ paths: type: object properties: allow_restricted_indices: + description: >- + Restricted indices are a special category of + indices that are used internally to store + configuration data and should not be directly + accessed. Only internal system roles should + normally grant privileges over the restricted + indices. Toggling this flag is very strongly + discouraged because it could effectively grant + unrestricted operations on critical data, making + the entire system unstable or leaking sensitive + information. If for administrative purposes you + need to create a role with privileges covering + restricted indices, however, you can set this + property to true. In that case, the names field + covers the restricted indices too. type: boolean field_security: additionalProperties: items: + description: >- + The document fields that the role members have + read access to. type: string type: array type: object names: items: + description: >- + The data streams, indices, and aliases to which + the permissions in this entry apply. It supports + wildcards (*). type: string minItems: 1 type: array privileges: items: + description: >- + The index level privileges that the role members + have for the data streams and indices. type: string minItems: 1 type: array query: + description: >- + A search query that defines the documents the role + members have read access to. A document within the + specified data streams and indices must match this + query in order for it to be accessible by the role + members. type: string required: - names @@ -41035,11 +40598,19 @@ paths: properties: clusters: items: + description: >- + A list of remote cluster aliases. It supports + literal strings as well as wildcards and regular + expressions. type: string minItems: 1 type: array privileges: items: + description: >- + The cluster level privileges for the remote + cluster. The allowed values are a subset of the + cluster privileges. type: string minItems: 1 type: array @@ -41053,29 +40624,64 @@ paths: type: object properties: allow_restricted_indices: + description: >- + Restricted indices are a special category of + indices that are used internally to store + configuration data and should not be directly + accessed. Only internal system roles should + normally grant privileges over the restricted + indices. Toggling this flag is very strongly + discouraged because it could effectively grant + unrestricted operations on critical data, making + the entire system unstable or leaking sensitive + information. If for administrative purposes you + need to create a role with privileges covering + restricted indices, however, you can set this + property to true. In that case, the names field + will cover the restricted indices too. type: boolean clusters: items: + description: >- + A list of remote cluster aliases. It supports + literal strings as well as wildcards and regular + expressions. type: string minItems: 1 type: array field_security: additionalProperties: items: + description: >- + The document fields that the role members have + read access to. type: string type: array type: object names: items: + description: >- + A list of remote aliases, data streams, or + indices to which the permissions apply. It + supports wildcards (*). type: string minItems: 1 type: array privileges: items: + description: >- + The index level privileges that role members + have for the specified indices. type: string minItems: 1 type: array query: + description: >- + A search query that defines the documents the role + members have read access to. A document within the + specified data streams and indices must match this + query in order for it to be accessible by the role + members. type: string required: - clusters @@ -41084,6 +40690,7 @@ paths: type: array run_as: items: + description: A user name that the role member can impersonate. type: string type: array kibana: @@ -41102,14 +40709,23 @@ paths: nullable: true oneOf: - items: + description: >- + A base privilege that grants applies to all + spaces. type: string type: array - items: + description: >- + A base privilege that applies to specific + spaces. type: string type: array feature: additionalProperties: items: + description: >- + The privileges that the role member has for the + feature. type: string type: array type: object @@ -41123,6 +40739,7 @@ paths: minItems: 1 type: array - items: + description: A space that the privilege applies to. type: string type: array default: @@ -41135,13 +40752,15 @@ paths: type: object required: - elasticsearch - responses: {} + responses: + '204': + description: Indicates a successful call. summary: Create or update a role tags: - roles /api/security/roles: post: - operationId: '%2Fapi%2Fsecurity%2Froles#0' + operationId: post-security-roles parameters: - description: The version of the API to use in: header @@ -41171,6 +40790,7 @@ paths: type: object properties: description: + description: A description for the role. maxLength: 2048 type: string elasticsearch: @@ -41179,6 +40799,9 @@ paths: properties: cluster: items: + description: >- + Cluster privileges that define the cluster level + actions that users can perform. type: string type: array indices: @@ -41187,24 +40810,58 @@ paths: type: object properties: allow_restricted_indices: + description: >- + Restricted indices are a special category of + indices that are used internally to store + configuration data and should not be + directly accessed. Only internal system + roles should normally grant privileges over + the restricted indices. Toggling this flag + is very strongly discouraged because it + could effectively grant unrestricted + operations on critical data, making the + entire system unstable or leaking sensitive + information. If for administrative purposes + you need to create a role with privileges + covering restricted indices, however, you + can set this property to true. In that case, + the names field covers the restricted + indices too. type: boolean field_security: additionalProperties: items: + description: >- + The document fields that the role + members have read access to. type: string type: array type: object names: items: + description: >- + The data streams, indices, and aliases to + which the permissions in this entry apply. + It supports wildcards (*). type: string minItems: 1 type: array privileges: items: + description: >- + The index level privileges that the role + members have for the data streams and + indices. type: string minItems: 1 type: array query: + description: >- + A search query that defines the documents + the role members have read access to. A + document within the specified data streams + and indices must match this query in order + for it to be accessible by the role members. type: string required: - names @@ -41217,11 +40874,19 @@ paths: properties: clusters: items: + description: >- + A list of remote cluster aliases. It + supports literal strings as well as + wildcards and regular expressions. type: string minItems: 1 type: array privileges: items: + description: >- + The cluster level privileges for the + remote cluster. The allowed values are a + subset of the cluster privileges. type: string minItems: 1 type: array @@ -41235,29 +40900,67 @@ paths: type: object properties: allow_restricted_indices: + description: >- + Restricted indices are a special category of + indices that are used internally to store + configuration data and should not be + directly accessed. Only internal system + roles should normally grant privileges over + the restricted indices. Toggling this flag + is very strongly discouraged because it + could effectively grant unrestricted + operations on critical data, making the + entire system unstable or leaking sensitive + information. If for administrative purposes + you need to create a role with privileges + covering restricted indices, however, you + can set this property to true. In that case, + the names field will cover the restricted + indices too. type: boolean clusters: items: + description: >- + A list of remote cluster aliases. It + supports literal strings as well as + wildcards and regular expressions. type: string minItems: 1 type: array field_security: additionalProperties: items: + description: >- + The document fields that the role + members have read access to. type: string type: array type: object names: items: + description: >- + A list of remote aliases, data streams, or + indices to which the permissions apply. It + supports wildcards (*). type: string minItems: 1 type: array privileges: items: + description: >- + The index level privileges that role + members have for the specified indices. type: string minItems: 1 type: array query: + description: >- + A search query that defines the documents + the role members have read access to. A + document within the specified data streams + and indices must match this query in order + for it to be accessible by the role + members. type: string required: - clusters @@ -41266,6 +40969,9 @@ paths: type: array run_as: items: + description: >- + A user name that the role member can + impersonate. type: string type: array kibana: @@ -41284,14 +40990,23 @@ paths: nullable: true oneOf: - items: + description: >- + A base privilege that grants applies to + all spaces. type: string type: array - items: + description: >- + A base privilege that applies to specific + spaces. type: string type: array feature: additionalProperties: items: + description: >- + The privileges that the role member has for + the feature. type: string type: array type: object @@ -41305,6 +41020,7 @@ paths: minItems: 1 type: array - items: + description: A space that the privilege applies to. type: string type: array default: @@ -41320,7 +41036,9 @@ paths: type: object required: - roles - responses: {} + responses: + '200': + description: Indicates a successful call. summary: Create or update roles tags: - roles @@ -41333,7 +41051,7 @@ paths: request to overwrite any objects that already exist in the target space if they share an identifier or you can use the resolve copy saved objects conflicts API to do this on a per-object basis. - operationId: '%2Fapi%2Fspaces%2F_copy_saved_objects#0' + operationId: post-spaces-copy-saved-objects parameters: - description: The version of the API to use in: header @@ -41420,7 +41138,7 @@ paths: - spaces /api/spaces/_disable_legacy_url_aliases: post: - operationId: '%2Fapi%2Fspaces%2F_disable_legacy_url_aliases#0' + operationId: post-spaces-disable-legacy-url-aliases parameters: - description: The version of the API to use in: header @@ -41474,7 +41192,7 @@ paths: /api/spaces/_get_shareable_references: post: description: Collect references and space contexts for saved objects. - operationId: '%2Fapi%2Fspaces%2F_get_shareable_references#0' + operationId: post-spaces-get-shareable-references parameters: - description: The version of the API to use in: header @@ -41522,7 +41240,7 @@ paths: description: >- Overwrite saved objects that are returned as errors from the copy saved objects to space API. - operationId: '%2Fapi%2Fspaces%2F_resolve_copy_saved_objects_errors#0' + operationId: post-spaces-resolve-copy-saved-objects-errors parameters: - description: The version of the API to use in: header @@ -41617,7 +41335,7 @@ paths: /api/spaces/_update_objects_spaces: post: description: Update one or more saved objects to add or remove them from some spaces. - operationId: '%2Fapi%2Fspaces%2F_update_objects_spaces#0' + operationId: post-spaces-update-objects-spaces parameters: - description: The version of the API to use in: header @@ -41680,7 +41398,7 @@ paths: - spaces /api/spaces/space: get: - operationId: '%2Fapi%2Fspaces%2Fspace#0' + operationId: get-spaces-space parameters: - description: The version of the API to use in: header @@ -41736,7 +41454,7 @@ paths: tags: - spaces post: - operationId: '%2Fapi%2Fspaces%2Fspace#1' + operationId: post-spaces-space parameters: - description: The version of the API to use in: header @@ -41825,7 +41543,7 @@ paths: description: >- When you delete a space, all saved objects that belong to the space are automatically deleted, which is permanent and cannot be undone. - operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2' + operationId: delete-spaces-space-id parameters: - description: The version of the API to use in: header @@ -41857,7 +41575,7 @@ paths: tags: - spaces get: - operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0' + operationId: get-spaces-space-id parameters: - description: The version of the API to use in: header @@ -41880,7 +41598,7 @@ paths: tags: - spaces put: - operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1' + operationId: put-spaces-space-id parameters: - description: The version of the API to use in: header @@ -41974,7 +41692,7 @@ paths: - spaces /api/status: get: - operationId: '%2Fapi%2Fstatus#0' + operationId: get-status parameters: - description: The version of the API to use in: header @@ -45966,6 +45684,24 @@ components: required: true schema: type: string + APM_UI_elastic_api_version: + description: The version of the API to use + in: header + name: elastic-api-version + required: true + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + APM_UI_kbn_xsrf: + description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string Cases_alert_id: description: An identifier for the alert. in: path @@ -46457,6 +46193,471 @@ components: description: Specifies the data type for the field. example: scaled_float type: string + APM_UI_400_response: + type: object + properties: + error: + description: Error type + example: Not Found + type: string + message: + description: Error message + example: Not Found + type: string + statusCode: + description: Error status code + example: 400 + type: number + APM_UI_401_response: + type: object + properties: + error: + description: Error type + example: Unauthorized + type: string + message: + description: Error message + type: string + statusCode: + description: Error status code + example: 401 + type: number + APM_UI_403_response: + type: object + properties: + error: + description: Error type + example: Forbidden + type: string + message: + description: Error message + type: string + statusCode: + description: Error status code + example: 403 + type: number + APM_UI_404_response: + type: object + properties: + error: + description: Error type + example: Not Found + type: string + message: + description: Error message + example: Not Found + type: string + statusCode: + description: Error status code + example: 404 + type: number + APM_UI_500_response: + type: object + properties: + error: + description: Error type + example: Internal Server Error + type: string + message: + description: Error message + type: string + statusCode: + description: Error status code + example: 500 + type: number + APM_UI_501_response: + type: object + properties: + error: + description: Error type + example: Not Implemented + type: string + message: + description: Error message + example: Not Implemented + type: string + statusCode: + description: Error status code + example: 501 + type: number + APM_UI_agent_configuration_intake_object: + type: object + properties: + agent_name: + description: Agent name + type: string + service: + $ref: '#/components/schemas/APM_UI_service_object' + settings: + $ref: '#/components/schemas/APM_UI_settings_object' + required: + - service + - settings + APM_UI_agent_configuration_object: + description: Agent configuration + type: object + properties: + '@timestamp': + description: Timestamp + example: 1730194190636 + type: number + agent_name: + description: Agent name + type: string + applied_by_agent: + description: Applied by agent + example: true + type: boolean + etag: + description: Etag + example: 0bc3b5ebf18fba8163fe4c96f491e3767a358f85 + type: string + service: + $ref: '#/components/schemas/APM_UI_service_object' + settings: + $ref: '#/components/schemas/APM_UI_settings_object' + required: + - service + - settings + - '@timestamp' + - etag + APM_UI_agent_configurations_response: + type: object + properties: + configurations: + description: Agent configuration + items: + $ref: '#/components/schemas/APM_UI_agent_configuration_object' + type: array + APM_UI_agent_keys_object: + type: object + properties: + name: + description: Agent name + type: string + privileges: + description: Privileges configuration + items: + enum: + - event:write + - config_agent:read + type: string + type: array + required: + - name + - privileges + APM_UI_agent_keys_response: + type: object + properties: + agentKey: + description: Agent key + type: object + properties: + api_key: + type: string + encoded: + type: string + expiration: + format: int64 + type: integer + id: + type: string + name: + type: string + required: + - id + - name + - api_key + - encoded + APM_UI_annotation_search_response: + type: object + properties: + annotations: + description: Annotations + items: + type: object + properties: + '@timestamp': + type: number + id: + type: string + text: + type: string + type: + enum: + - version + type: string + type: array + APM_UI_base_source_map_object: + type: object + properties: + compressionAlgorithm: + description: Compression Algorithm + type: string + created: + description: Created date + type: string + decodedSha256: + description: Decoded SHA-256 + type: string + decodedSize: + description: Decoded size + type: number + encodedSha256: + description: Encoded SHA-256 + type: string + encodedSize: + description: Encoded size + type: number + encryptionAlgorithm: + description: Encryption Algorithm + type: string + id: + description: Identifier + type: string + identifier: + description: Identifier + type: string + packageName: + description: Package name + type: string + relative_url: + description: Relative URL + type: string + type: + description: Type + type: string + APM_UI_create_annotation_object: + type: object + properties: + '@timestamp': + description: Timestamp + type: string + message: + description: Message + type: string + service: + description: Service + type: object + properties: + environment: + type: string + version: + type: string + required: + - version + tags: + description: Tags + items: + type: string + type: array + required: + - '@timestamp' + - service + APM_UI_create_annotation_response: + type: object + properties: + _id: + description: Identifier + type: string + _index: + description: Index + type: string + _source: + description: Response + type: object + properties: + '@timestamp': + type: string + annotation: + type: object + properties: + title: + type: string + type: + type: string + event: + type: object + properties: + created: + type: string + message: + type: string + service: + type: object + properties: + environment: + type: string + name: + type: string + version: + type: string + tags: + items: + type: string + type: array + APM_UI_delete_agent_configurations_response: + type: object + properties: + result: + description: Result + type: string + APM_UI_search_agent_configuration_object: + type: object + properties: + etag: + description: If etags match then `applied_by_agent` field will be set to `true` + example: 0bc3b5ebf18fba8163fe4c96f491e3767a358f85 + type: string + mark_as_applied_by_agent: + description: > + `markAsAppliedByAgent=true` means "force setting it to true + regardless of etag". + + This is needed for Jaeger agent that doesn't have etags + type: boolean + service: + $ref: '#/components/schemas/APM_UI_service_object' + required: + - service + APM_UI_search_agent_configuration_response: + type: object + properties: + _id: + description: Identifier + type: string + _index: + description: Index + type: string + _score: + description: Score + type: number + _source: + $ref: '#/components/schemas/APM_UI_agent_configuration_object' + APM_UI_service_agent_name_response: + type: object + properties: + agentName: + description: Agent name + example: nodejs + type: string + APM_UI_service_environment_object: + type: object + properties: + alreadyConfigured: + description: Already configured + type: boolean + name: + description: Service environment name + example: ALL_OPTION_VALUE + type: string + APM_UI_service_environments_response: + type: object + properties: + environments: + description: Service environment list + items: + $ref: '#/components/schemas/APM_UI_service_environment_object' + type: array + APM_UI_service_object: + description: Service + type: object + properties: + environment: + description: Environment + example: prod + type: string + name: + description: Name + example: node + type: string + APM_UI_settings_object: + additionalProperties: + type: string + description: Agent configuration settings + type: object + APM_UI_single_agent_configuration_response: + allOf: + - type: object + properties: + id: + type: string + required: + - id + - $ref: '#/components/schemas/APM_UI_agent_configuration_object' + APM_UI_source_maps_response: + type: object + properties: + artifacts: + description: Artifacts + items: + allOf: + - type: object + properties: + body: + type: object + properties: + bundleFilepath: + type: string + serviceName: + type: string + serviceVersion: + type: string + sourceMap: + type: object + properties: + file: + type: string + mappings: + type: string + sourceRoot: + type: string + sources: + items: + type: string + type: array + sourcesContent: + items: + type: string + type: array + version: + type: number + - $ref: '#/components/schemas/APM_UI_base_source_map_object' + type: array + APM_UI_upload_source_map_object: + type: object + properties: + bundle_filepath: + description: >- + The absolute path of the final bundle as used in the web + application. + type: string + service_name: + description: The name of the service that the service map should apply to. + type: string + service_version: + description: The version of the service that the service map should apply to. + type: string + sourcemap: + description: > + The source map. String or file upload. It must follow the + + [source map revision 3 + proposal](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k). + format: binary + type: string + required: + - service_name + - service_version + - bundle_filepath + - sourcemap + APM_UI_upload_source_maps_response: + allOf: + - type: object + properties: + body: + type: string + - $ref: '#/components/schemas/APM_UI_base_source_map_object' Cases_4xx_response: properties: error: @@ -57128,6 +57329,8 @@ components: Security_Entity_Analytics_API_EngineDescriptor: type: object properties: + error: + type: object fieldHistoryLength: type: integer filter: @@ -60513,6 +60716,9 @@ security: - basicAuth: [] tags: - name: alerting + - description: | + Adjust APM agent configuration without need to redeploy your application. + name: APM agent configuration - description: > Configure APM agent keys to authorize requests from APM agents to the APM Server. @@ -60522,6 +60728,10 @@ tags: Annotations enable you to easily see how events are impacting the performance of your applications. name: APM annotations + - description: Create APM fleet server schema. + name: APM server schema + - description: Configure APM source maps. + name: APM sourcemaps - description: Case APIs enable you to open and track issues. name: cases - name: connectors diff --git a/oas_docs/overlays/kibana.overlays.yaml b/oas_docs/overlays/kibana.overlays.yaml index 4a21c029ef80a..ed41f56088bf8 100644 --- a/oas_docs/overlays/kibana.overlays.yaml +++ b/oas_docs/overlays/kibana.overlays.yaml @@ -164,4 +164,39 @@ actions: application/json; Elastic-Api-Version=2023-10-31: examples: updateObjectSpacesResponseExample1: - $ref: "../examples/update_saved_objects_spaces_response1.yaml" \ No newline at end of file + $ref: "../examples/update_saved_objects_spaces_response1.yaml" + - target: "$.paths['/api/security/role/{name}']['put']" + description: "Add examples to create role API" + update: + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + examples: + createRoleRequest1: + $ref: "../examples/create_role_request1.yaml" + createRoleRequest2: + $ref: "../examples/create_role_request2.yaml" + createRoleRequest3: + $ref: "../examples/create_role_request3.yaml" + createRoleRequest4: + $ref: "../examples/create_role_request4.yaml" + - target: "$.paths['/api/security/role/{name}']['get']" + description: "Add example to get role API" + update: + responses: + 200: + content: + application/json; Elastic-Api-Version=2023-10-31: + examples: + getRoleResponse1: + $ref: '../examples/get_role_response1.yaml' + - target: "$.paths['/api/security/role']['get']" + description: "Add example to get roles API" + update: + responses: + 200: + content: + application/json; Elastic-Api-Version=2023-10-31: + examples: + getRolesResponse1: + $ref: '../examples/get_roles_response1.yaml' diff --git a/oas_docs/scripts/merge_ess_oas.js b/oas_docs/scripts/merge_ess_oas.js index 218e8dfa5b803..d8bc45e64c2f2 100644 --- a/oas_docs/scripts/merge_ess_oas.js +++ b/oas_docs/scripts/merge_ess_oas.js @@ -22,7 +22,7 @@ const { REPO_ROOT } = require('@kbn/repo-info'); `${REPO_ROOT}/packages/core/saved-objects/docs/openapi/bundled.yaml`, // Observability Solution - `${REPO_ROOT}/x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml`, + `${REPO_ROOT}/x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.yaml`, `${REPO_ROOT}/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml`, // Security solution diff --git a/oas_docs/scripts/merge_serverless_oas.js b/oas_docs/scripts/merge_serverless_oas.js index c66187dea8d8d..63d2df0f32d3f 100644 --- a/oas_docs/scripts/merge_serverless_oas.js +++ b/oas_docs/scripts/merge_serverless_oas.js @@ -20,7 +20,7 @@ const { REPO_ROOT } = require('@kbn/repo-info'); `${REPO_ROOT}/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml`, // Observability Solution - `${REPO_ROOT}/x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml`, + `${REPO_ROOT}/x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.yaml`, `${REPO_ROOT}/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml`, // Security solution diff --git a/package.json b/package.json index 0205652b04a20..4a91266058ccb 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "@elastic/ecs": "^8.11.1", "@elastic/elasticsearch": "^8.15.0", "@elastic/ems-client": "8.5.3", - "@elastic/eui": "97.2.0", + "@elastic/eui": "97.3.0", "@elastic/filesaver": "1.1.2", "@elastic/node-crypto": "^1.2.3", "@elastic/numeral": "^2.5.1", @@ -571,6 +571,7 @@ "@kbn/index-management-plugin": "link:x-pack/plugins/index_management", "@kbn/index-management-shared-types": "link:x-pack/packages/index-management/index_management_shared_types", "@kbn/index-patterns-test-plugin": "link:test/plugin_functional/plugins/index_patterns", + "@kbn/inference-common": "link:x-pack/packages/ai-infra/inference-common", "@kbn/inference-plugin": "link:x-pack/plugins/inference", "@kbn/inference_integration_flyout": "link:x-pack/packages/ml/inference_integration_flyout", "@kbn/infra-forge": "link:x-pack/packages/kbn-infra-forge", @@ -1017,7 +1018,7 @@ "@langchain/langgraph": "0.0.34", "@langchain/openai": "^0.1.3", "@langtrase/trace-attributes": "^3.0.8", - "@launchdarkly/node-server-sdk": "^9.6.0", + "@launchdarkly/node-server-sdk": "^9.7.0", "@launchdarkly/openfeature-node-server": "^1.0.0", "@loaders.gl/core": "^3.4.7", "@loaders.gl/json": "^3.4.7", @@ -1160,7 +1161,7 @@ "kea": "^2.6.0", "langchain": "^0.2.11", "langsmith": "^0.1.55", - "launchdarkly-js-client-sdk": "^3.4.0", + "launchdarkly-js-client-sdk": "^3.5.0", "load-json-file": "^6.2.0", "lodash": "^4.17.21", "lru-cache": "^4.1.5", @@ -1579,7 +1580,7 @@ "@types/jsonwebtoken": "^9.0.0", "@types/license-checker": "15.0.0", "@types/loader-utils": "^2.0.3", - "@types/lodash": "^4.17.12", + "@types/lodash": "^4.17.13", "@types/lru-cache": "^5.1.0", "@types/lz-string": "^1.3.34", "@types/mapbox__vector-tile": "1.3.0", @@ -1675,7 +1676,7 @@ "buildkite-test-collector": "^1.7.0", "callsites": "^3.1.0", "chance": "1.0.18", - "chromedriver": "^129.0.0", + "chromedriver": "^130.0.1", "clarify": "^2.2.0", "clean-webpack-plugin": "^3.0.0", "cli-progress": "^3.12.0", @@ -1724,7 +1725,7 @@ "file-loader": "^4.2.0", "find-cypress-specs": "^1.41.4", "form-data": "^4.0.0", - "geckodriver": "^4.4.4", + "geckodriver": "^4.5.1", "gulp-brotli": "^3.0.0", "gulp-postcss": "^9.0.1", "gulp-terser": "^2.1.0", @@ -1765,7 +1766,7 @@ "mochawesome-merge": "^4.3.0", "mock-fs": "^5.1.2", "ms-chromium-edge-driver": "^0.5.1", - "msw": "^2.4.11", + "msw": "^2.4.12", "multistream": "^4.1.0", "mutation-observer": "^1.0.3", "native-hdr-histogram": "^1.0.0", diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx index 5d86209ec8800..434639b07efdf 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx @@ -36,6 +36,7 @@ import type { ChromeSetProjectBreadcrumbsParams, NavigationTreeDefinition, AppDeepLinkId, + SolutionId, } from '@kbn/core-chrome-browser'; import type { CustomBrandingStart } from '@kbn/core-custom-branding-browser'; import type { @@ -343,7 +344,10 @@ export class ChromeService { LinkId extends AppDeepLinkId = AppDeepLinkId, Id extends string = string, ChildrenId extends string = Id - >(id: string, navigationTree$: Observable>) { + >( + id: SolutionId, + navigationTree$: Observable> + ) { validateChromeStyle(); projectNavigation.initNavigation(id, navigationTree$); } diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts index d1be94aad246a..124b44e80e30f 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts @@ -110,7 +110,7 @@ describe('initNavigation()', () => { beforeAll(() => { projectNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -185,7 +185,7 @@ describe('initNavigation()', () => { const { projectNavigation: projNavigation, getNavigationTree: getNavTree } = setupInitNavigation(); projNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -210,7 +210,7 @@ describe('initNavigation()', () => { const { projectNavigation: projNavigation } = setupInitNavigation(); projNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -399,7 +399,7 @@ describe('initNavigation()', () => { // 2. initNavigation() is called projectNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -427,7 +427,7 @@ describe('initNavigation()', () => { }); projectNavigation.initNavigation( - 'foo', + 'es', // @ts-expect-error - We pass a non valid cloudLink that is not TS valid of({ body: [ @@ -533,7 +533,7 @@ describe('breadcrumbs', () => { const obs = subj.asObservable(); if (initiateNavigation) { - projectNavigation.initNavigation('foo', obs); + projectNavigation.initNavigation('es', obs); } return { @@ -740,7 +740,7 @@ describe('breadcrumbs', () => { { text: 'custom1', href: '/custom1' }, { text: 'custom2', href: '/custom1/custom2' }, ]); - projectNavigation.initNavigation('foo', of(mockNavigation)); // init navigation + projectNavigation.initNavigation('es', of(mockNavigation)); // init navigation const breadcrumbs = await firstValueFrom(projectNavigation.getProjectBreadcrumbs$()); expect(breadcrumbs).toHaveLength(4); @@ -779,7 +779,7 @@ describe('getActiveNodes$()', () => { expect(activeNodes).toEqual([]); projectNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -835,7 +835,7 @@ describe('getActiveNodes$()', () => { expect(activeNodes).toEqual([]); projectNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -889,7 +889,7 @@ describe('getActiveNodes$()', () => { describe('solution navigations', () => { const solution1: SolutionNavigationDefinition = { - id: 'solution1', + id: 'es', title: 'Solution 1', icon: 'logoSolution1', homePage: 'discover', @@ -897,7 +897,7 @@ describe('solution navigations', () => { }; const solution2: SolutionNavigationDefinition = { - id: 'solution2', + id: 'oblt', title: 'Solution 2', icon: 'logoSolution2', homePage: 'app2', @@ -906,7 +906,7 @@ describe('solution navigations', () => { }; const solution3: SolutionNavigationDefinition = { - id: 'solution3', + id: 'security', title: 'Solution 3', icon: 'logoSolution3', homePage: 'discover', @@ -943,30 +943,30 @@ describe('solution navigations', () => { } { - projectNavigation.updateSolutionNavigations({ 1: solution1, 2: solution2 }); + projectNavigation.updateSolutionNavigations({ es: solution1, oblt: solution2 }); const solutionNavs = await lastValueFrom( projectNavigation.getSolutionsNavDefinitions$().pipe(take(1)) ); - expect(solutionNavs).toEqual({ 1: solution1, 2: solution2 }); + expect(solutionNavs).toEqual({ es: solution1, oblt: solution2 }); } { // Test partial update - projectNavigation.updateSolutionNavigations({ 3: solution3 }, false); + projectNavigation.updateSolutionNavigations({ security: solution3 }, false); const solutionNavs = await lastValueFrom( projectNavigation.getSolutionsNavDefinitions$().pipe(take(1)) ); - expect(solutionNavs).toEqual({ 1: solution1, 2: solution2, 3: solution3 }); + expect(solutionNavs).toEqual({ es: solution1, oblt: solution2, security: solution3 }); } { // Test full replacement - projectNavigation.updateSolutionNavigations({ 4: solution3 }, true); + projectNavigation.updateSolutionNavigations({ security: solution3 }, true); const solutionNavs = await lastValueFrom( projectNavigation.getSolutionsNavDefinitions$().pipe(take(1)) ); - expect(solutionNavs).toEqual({ 4: solution3 }); + expect(solutionNavs).toEqual({ security: solution3 }); } }); @@ -980,8 +980,8 @@ describe('solution navigations', () => { expect(activeSolution).toBeNull(); } - projectNavigation.changeActiveSolutionNavigation('2'); // Set **before** the navs are registered - projectNavigation.updateSolutionNavigations({ 1: solution1, 2: solution2 }); + projectNavigation.changeActiveSolutionNavigation('oblt'); // Set **before** the navs are registered + projectNavigation.updateSolutionNavigations({ es: solution1, oblt: solution2 }); { const activeSolution = await lastValueFrom( @@ -994,7 +994,7 @@ describe('solution navigations', () => { expect(activeSolution).toEqual(rest); } - projectNavigation.changeActiveSolutionNavigation('1'); // Set **after** the navs are registered + projectNavigation.changeActiveSolutionNavigation('es'); // Set **after** the navs are registered { const activeSolution = await lastValueFrom( @@ -1027,7 +1027,7 @@ describe('solution navigations', () => { { const fooSolution: SolutionNavigationDefinition = { - id: 'fooSolution', + id: 'es', title: 'Foo solution', icon: 'logoSolution', homePage: 'discover', @@ -1053,8 +1053,8 @@ describe('solution navigations', () => { }), }; - projectNavigation.changeActiveSolutionNavigation('foo'); - projectNavigation.updateSolutionNavigations({ foo: fooSolution }); + projectNavigation.changeActiveSolutionNavigation('es'); + projectNavigation.updateSolutionNavigations({ es: fooSolution }); projectNavigation.setPanelSelectedNode('link2'); // Set the selected node using its id diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts index 85c3fd1905adb..7960d9f710c90 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts @@ -17,6 +17,7 @@ import type { NavigationTreeDefinition, SolutionNavigationDefinitions, CloudLinks, + SolutionId, } from '@kbn/core-chrome-browser'; import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import { @@ -86,9 +87,9 @@ export class ProjectNavigationService { private readonly solutionNavDefinitions$ = new BehaviorSubject({}); // As the active definition **id** and the definitions are set independently, one before the other without // any guarantee of order, we need to store the next active definition id in a separate BehaviorSubject - private readonly nextSolutionNavDefinitionId$ = new BehaviorSubject(null); + private readonly nextSolutionNavDefinitionId$ = new BehaviorSubject(null); // The active solution navigation definition id that has been initiated and is currently active - private readonly activeSolutionNavDefinitionId$ = new BehaviorSubject(null); + private readonly activeSolutionNavDefinitionId$ = new BehaviorSubject(null); private readonly location$ = new BehaviorSubject(createLocation('/')); private deepLinksMap$: Observable> = of({}); private cloudLinks$ = new BehaviorSubject({}); @@ -138,7 +139,7 @@ export class ProjectNavigationService { return this.projectName$.asObservable(); }, initNavigation: ( - id: string, + id: SolutionId, navTreeDefinition$: Observable> ) => { this.initNavigation(id, navTreeDefinition$); @@ -202,7 +203,7 @@ export class ProjectNavigationService { * @param id Id for the navigation tree definition * @param navTreeDefinition$ The navigation tree definition */ - private initNavigation(id: string, navTreeDefinition$: Observable) { + private initNavigation(id: SolutionId, navTreeDefinition$: Observable) { if (this.activeSolutionNavDefinitionId$.getValue() === id) return; if (this.navigationChangeSubscription) { @@ -220,7 +221,7 @@ export class ProjectNavigationService { .pipe( takeUntil(this.stop$), map(([def, deepLinksMap, cloudLinks]) => { - return parseNavigationTree(def, { + return parseNavigationTree(id, def, { deepLinks: deepLinksMap, cloudLinks, }); @@ -382,7 +383,7 @@ export class ProjectNavigationService { this.projectHome$.next(homeHref); } - private changeActiveSolutionNavigation(id: string | null) { + private changeActiveSolutionNavigation(id: SolutionId | null) { if (this.nextSolutionNavDefinitionId$.getValue() === id) return; this.nextSolutionNavDefinitionId$.next(id); } @@ -400,7 +401,7 @@ export class ProjectNavigationService { if (!definitions[id]) return null; // We strip out the sideNavComponent from the definition as it should only be used internally - const { sideNavComponent, ...definition } = definitions[id]; + const { sideNavComponent, ...definition } = definitions[id]!; return definition; }) ); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts index 9a45290c95389..bdf3929c464dc 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts @@ -22,6 +22,7 @@ import type { CloudLinkId, CloudLinks, ItemDefinition, + SolutionId, } from '@kbn/core-chrome-browser/src'; import type { Location } from 'history'; import type { MouseEventHandler } from 'react'; @@ -364,6 +365,7 @@ const isRecentlyAccessedDefinition = ( }; export const parseNavigationTree = ( + id: SolutionId, navigationTreeDef: NavigationTreeDefinition, { deepLinks, cloudLinks }: { deepLinks: Record; cloudLinks: CloudLinks } ): { @@ -376,7 +378,7 @@ export const parseNavigationTree = ( const navigationTree: ChromeProjectNavigationNode[] = []; // Contains UI layout information (body, footer) and render "special" blocks like recently accessed. - const navigationTreeUI: NavigationTreeDefinitionUI = { body: [] }; + const navigationTreeUI: NavigationTreeDefinitionUI = { id, body: [] }; const initNodeAndChildren = ( node: GroupDefinition | ItemDefinition | NodeDefinition, diff --git a/packages/core/chrome/core-chrome-browser-internal/src/types.ts b/packages/core/chrome/core-chrome-browser-internal/src/types.ts index 0e6bec4d2678c..36a247e22f847 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/types.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/types.ts @@ -18,6 +18,7 @@ import type { NavigationTreeDefinitionUI, CloudURLs, SolutionNavigationDefinitions, + SolutionId, } from '@kbn/core-chrome-browser'; import type { Observable } from 'rxjs'; @@ -66,7 +67,7 @@ export interface InternalChromeStart extends ChromeStart { Id extends string = string, ChildrenId extends string = Id >( - id: string, + id: SolutionId, navigationTree$: Observable> ): void; @@ -117,6 +118,6 @@ export interface InternalChromeStart extends ChromeStart { * @param id The id of the active solution navigation. If `null` is provided, the solution navigation * will be replaced with the legacy Kibana navigation. */ - changeActiveSolutionNavigation(id: string | null): void; + changeActiveSolutionNavigation(id: SolutionId | null): void; }; } diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/loading_indicator.scss b/packages/core/chrome/core-chrome-browser-internal/src/ui/loading_indicator.scss index ccf1ecc873fc5..d12331d9c042d 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/loading_indicator.scss +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/loading_indicator.scss @@ -2,3 +2,8 @@ visibility: hidden; animation-play-state: paused; } + +.euiHeaderSectionItem .euiButtonEmpty__text { + // stop global header buttons from jumping during loading state + display: flex; +} \ No newline at end of file diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx index 1f282db34a0f5..e63a27c1d44ed 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx @@ -306,7 +306,11 @@ export const ProjectHeader = ({ /> - + diff --git a/packages/core/chrome/core-chrome-browser/index.ts b/packages/core/chrome/core-chrome-browser/index.ts index afb2050d12e80..7b8658791340f 100644 --- a/packages/core/chrome/core-chrome-browser/index.ts +++ b/packages/core/chrome/core-chrome-browser/index.ts @@ -60,4 +60,5 @@ export type { SolutionNavigationDefinitions, EuiSideNavItemTypeEnhanced, RenderAs, + SolutionId, } from './src'; diff --git a/packages/core/chrome/core-chrome-browser/src/index.ts b/packages/core/chrome/core-chrome-browser/src/index.ts index efc2fb5636d84..efc709ff512da 100644 --- a/packages/core/chrome/core-chrome-browser/src/index.ts +++ b/packages/core/chrome/core-chrome-browser/src/index.ts @@ -38,6 +38,7 @@ export type { PanelSelectedNode, AppDeepLinkId, AppId, + SolutionId, CloudLinkId, CloudLink, CloudLinks, diff --git a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts index 3e6afeb8f6117..f4a5af26c4176 100644 --- a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts +++ b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts @@ -42,6 +42,8 @@ import type { AppId as SharedApp, DeepLinkId as SharedLink } from '@kbn/deeplink import type { ChromeNavLink } from './nav_links'; import type { ChromeRecentlyAccessedHistoryItem } from './recently_accessed'; +export type SolutionId = 'es' | 'oblt' | 'security'; + /** @public */ export type AppId = | DevToolsApp @@ -414,6 +416,7 @@ export interface NavigationTreeDefinition< * with their corresponding "deepLink"...) */ export interface NavigationTreeDefinitionUI { + id: SolutionId; body: Array; footer?: Array; } @@ -429,7 +432,7 @@ export interface NavigationTreeDefinitionUI { export interface SolutionNavigationDefinition { /** Unique id for the solution navigation. */ - id: string; + id: SolutionId; /** Title for the solution navigation. */ title: string; /** The navigation tree definition */ @@ -442,9 +445,9 @@ export interface SolutionNavigationDefinition [!IMPORTANT] -> At the moment, we follow a manual process to manage our feature flags. Refer to [this repo](https://github.com/elastic/kibana-feature-flags) to learn more about our current internal process. -> Our goal is to achieve the _gitops_ approach detailed below. But, at the moment, it's not available, and you can skip it if you want. +### Feature Flag -Kibana follows a _gitops_ approach when managing feature flags. To declare a feature flag, add your flags definitions in -your plugin's `server/index.ts` file: +A config key that defines a set of [variations](#variations) that will be resolved at runtime when the app calls [the evaluation APIs](https://docs.elastic.dev/kibana-dev-docs/tutorials/feature-flags-service#evaluating-feature-flags). The variation is decided at runtime based on static binary state (ON -> `variationA` vs. OFF -> `variationB`), or via [evaluation/segmentation rules](#evaluationsegmentation-rules). -```typescript -// /server/index.ts -import type { FeatureFlagDefinitions } from '@kbn/core-feature-flags-server'; -import type { PluginInitializerContext } from '@kbn/core-plugins-server'; - -export const featureFlags: FeatureFlagDefinitions = [ - { - key: 'myPlugin.myCoolFeature', - name: 'My cool feature', - description: 'Enables the cool feature to auto-hide the navigation bar', - tags: ['my-plugin', 'my-service', 'ui'], - variationType: 'boolean', - variations: [ - { - name: 'On', - description: 'Auto-hides the bar', - value: true, - }, - { - name: 'Off', - description: 'Static always-on', - value: false, - }, - ], - }, - {...}, -]; - -export async function plugin(initializerContext: PluginInitializerContext) { - const { FeatureFlagsExamplePlugin } = await import('./plugin'); - return new FeatureFlagsExamplePlugin(initializerContext); -} -``` +### Variations + +All the potential values that a feature flag can return based on the [evaluation rules](#evaluationsegmentation-rules). A feature flag should define at least 2 variations: the ON and the OFF states. The typical use case sets the OFF state to match the `fallback` value provided to [the evaluation APIs](https://docs.elastic.dev/kibana-dev-docs/tutorials/feature-flags-service#evaluating-feature-flags), although it's not a hard requirement and Kibana contributors might require special configurations. + +### Evaluation/Segmentation rules + +Set of rules used to evaluate the variation to resolve, based on the [evaluation context](#evaluation-context) provided by the app. + +The rules can vary from a percentage rollout per evaluation context, or more complex IF...THEN filters and clauses. + +Refer to the [Evaluation Context guide's examples](https://github.com/elastic/kibana-feature-flags/blob/main/docs/evaluation-context.md#examples) for some typical scenarios. + +### Evaluation Context + +Kibana reports a set of properties specific to each ECH deployment/Serverless project to help define the [segmentation rules](#evaluationsegmentation-rules). A list of the currently reported context properties can be found in the [Evaluation Context guide](https://github.com/elastic/kibana-feature-flags/blob/main/docs/evaluation-context.md). + +### Feature Flag Code References + +In the Kibana repo we run a [GH Action](https://github.com/elastic/kibana/actions/workflows/launchdarkly-code-references.yml) that links existing Feature Flags to their code references. This helps us figure out which flags have been removed from the code and, which ones are still being used. + +> :information_source: New flags might take a few moments to be updated with their code references. +> The job runs on every commit to the `main` branch of the [Kibana repository](https://github.com/elastic/kibana), so the wait can take from a few minutes to a few hours, depending on the Kibana repo's activity. + +## Registering a feature flag -After merging your PR, the CI will create/update the flags in our third-party feature flags provider. +At the moment, we follow a manual process to manage our feature flags. Refer to [this repo](https://github.com/elastic/kibana-feature-flags) to learn more about our current internal process. +Our goal is to achieve a _gitops_ approach eventually. But, at the moment, it's not available. ### Deprecation/removal strategy -When your code doesn't use the feature flag anymore, it is recommended to clean up the feature flags when possible. +When your code doesn't use the feature flag anymore, it is recommended to clean up the feature flags. There are a few considerations to take into account when performing this clean-up: 1. Always deprecate first, remove after diff --git a/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap b/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap index bd50f4ffe0e44..9fd84ce731847 100644 --- a/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap +++ b/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap @@ -129,15 +129,14 @@ exports[`#start() returns \`Context\` component 1`] = ` "euiDatePopoverContent.startDateLabel": "Start date", "euiDisplaySelector.buttonText": "Display options", "euiDisplaySelector.densityLabel": "Density", - "euiDisplaySelector.labelAuto": "Auto fit", + "euiDisplaySelector.labelAuto": "Auto", "euiDisplaySelector.labelCompact": "Compact", - "euiDisplaySelector.labelCustom": "Custom", "euiDisplaySelector.labelExpanded": "Expanded", + "euiDisplaySelector.labelMax": "Max", "euiDisplaySelector.labelNormal": "Normal", - "euiDisplaySelector.labelSingle": "Single", - "euiDisplaySelector.lineCountLabel": "Lines per row", + "euiDisplaySelector.labelStatic": "Static", "euiDisplaySelector.resetButtonText": "Reset to default", - "euiDisplaySelector.rowHeightLabel": "Row height", + "euiDisplaySelector.rowHeightLabel": "Lines per row", "euiDualRange.sliderScreenReaderInstructions": "You are in a custom range slider. Use the Up and Down arrow keys to change the minimum value. Press Tab to interact with the maximum value.", "euiErrorBoundary.error": "Error", "euiExternalLinkIcon.externalTarget.screenReaderOnlyText": "(external)", diff --git a/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx index ad1ba505dc6f2..732c43a0593c7 100644 --- a/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx +++ b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx @@ -724,19 +724,16 @@ export const getEuiContextMapping = (): EuiTokensObject => { 'euiDisplaySelector.labelExpanded': i18n.translate('core.euiDisplaySelector.labelExpanded', { defaultMessage: 'Expanded', }), - 'euiDisplaySelector.labelSingle': i18n.translate('core.euiDisplaySelector.labelSingle', { - defaultMessage: 'Single', - }), 'euiDisplaySelector.labelAuto': i18n.translate('core.euiDisplaySelector.labelAuto', { - defaultMessage: 'Auto fit', + defaultMessage: 'Auto', }), - 'euiDisplaySelector.labelCustom': i18n.translate('core.euiDisplaySelector.labelCustom', { - defaultMessage: 'Custom', + 'euiDisplaySelector.labelStatic': i18n.translate('core.euiDisplaySelector.labelStatic', { + defaultMessage: 'Static', }), - 'euiDisplaySelector.rowHeightLabel': i18n.translate('core.euiDisplaySelector.rowHeightLabel', { - defaultMessage: 'Row height', + 'euiDisplaySelector.labelMax': i18n.translate('core.euiDisplaySelector.labelMax', { + defaultMessage: 'Max', }), - 'euiDisplaySelector.lineCountLabel': i18n.translate('core.euiDisplaySelector.lineCountLabel', { + 'euiDisplaySelector.rowHeightLabel': i18n.translate('core.euiDisplaySelector.rowHeightLabel', { defaultMessage: 'Lines per row', }), 'euiFieldPassword.showPassword': i18n.translate('core.euiFieldPassword.showPassword', { diff --git a/packages/core/root/core-root-browser-internal/src/kbn_bootstrap.ts b/packages/core/root/core-root-browser-internal/src/kbn_bootstrap.ts index 80020b79427f5..a06abd107fd06 100644 --- a/packages/core/root/core-root-browser-internal/src/kbn_bootstrap.ts +++ b/packages/core/root/core-root-browser-internal/src/kbn_bootstrap.ts @@ -39,6 +39,76 @@ export async function __kbnBootstrap__() { }), ]); + const isDomStorageDisabled = () => { + try { + const key = 'kbn_bootstrap_domStorageEnabled'; + sessionStorage.setItem(key, 'true'); + sessionStorage.removeItem(key); + localStorage.setItem(key, 'true'); + localStorage.removeItem(key); + return false; + } catch (e) { + return true; + } + }; + + if (isDomStorageDisabled()) { + const defaultErrorTitle = `Couldn't load the page`; + const defaultErrorText = `Update your browser's settings to allow storage of cookies and site data, and reload the page.`; + const defaultErrorReload = 'Reload'; + + const errorTitle = i18nError + ? defaultErrorTitle + : i18n.translate('core.ui.welcomeErrorCouldNotLoadPage', { + defaultMessage: defaultErrorTitle, + }); + + const errorText = i18nError + ? defaultErrorText + : i18n.translate('core.ui.welcomeErrorDomStorageDisabled', { + defaultMessage: defaultErrorText, + }); + + const errorReload = i18nError + ? defaultErrorReload + : i18n.translate('core.ui.welcomeErrorReloadButton', { + defaultMessage: defaultErrorReload, + }); + + const err = document.createElement('div'); + err.style.textAlign = 'center'; + err.style.padding = '120px 20px'; + err.style.fontFamily = 'Inter, BlinkMacSystemFont, Helvetica, Arial, sans-serif'; + + const errorTitleEl = document.createElement('h1'); + errorTitleEl.innerText = errorTitle; + errorTitleEl.style.margin = '20px'; + errorTitleEl.style.color = '#1a1c21'; + + const errorTextEl = document.createElement('p'); + errorTextEl.innerText = errorText; + errorTextEl.style.margin = '20px'; + errorTextEl.style.color = '#343741'; + + const errorReloadEl = document.createElement('button'); + errorReloadEl.innerText = errorReload; + errorReloadEl.onclick = function () { + location.reload(); + }; + errorReloadEl.setAttribute( + 'style', + 'cursor: pointer; padding-inline: 12px; block-size: 40px; font-size: 1rem; line-height: 1.4286rem; border-radius: 6px; min-inline-size: 112px; color: rgb(255, 255, 255); background-color: rgb(0, 119, 204); outline-color: rgb(0, 0, 0); border:none' + ); + + err.appendChild(errorTitleEl); + err.appendChild(errorTextEl); + err.appendChild(errorReloadEl); + + document.body.innerHTML = ''; + document.body.appendChild(err); + return; + } + const coreSystem = new CoreSystem({ injectedMetadata, rootDomElement: document.body, diff --git a/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/import_saved_objects.test.ts b/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/import_saved_objects.test.ts index d8c2b0b25874f..06c8e351bc445 100644 --- a/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/import_saved_objects.test.ts +++ b/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/import_saved_objects.test.ts @@ -19,6 +19,7 @@ import { } from './import_saved_objects.test.mock'; import { Readable } from 'stream'; +import { loggerMock, type MockedLogger } from '@kbn/logging-mocks'; import { v4 as uuidv4 } from 'uuid'; import type { SavedObjectsImportFailure, @@ -40,8 +41,10 @@ import { import type { ImportStateMap } from './lib'; describe('#importSavedObjectsFromStream', () => { + let logger: MockedLogger; beforeEach(() => { jest.clearAllMocks(); + logger = loggerMock.create(); // mock empty output of each of these mocked modules so the import doesn't throw an error mockCollectSavedObjects.mockResolvedValue({ errors: [], @@ -72,7 +75,6 @@ describe('#importSavedObjectsFromStream', () => { let savedObjectsClient: jest.Mocked; let typeRegistry: jest.Mocked; const namespace = 'some-namespace'; - const setupOptions = ({ createNewCopies = false, getTypeImpl = (type: string) => @@ -102,6 +104,7 @@ describe('#importSavedObjectsFromStream', () => { createNewCopies, importHooks, managed, + log: logger, }; }; const createObject = ({ diff --git a/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/import_saved_objects.ts b/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/import_saved_objects.ts index 4182daa610b37..7d6bf9668286a 100644 --- a/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/import_saved_objects.ts +++ b/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/import_saved_objects.ts @@ -17,6 +17,7 @@ import type { ISavedObjectTypeRegistry, SavedObjectsImportHook, } from '@kbn/core-saved-objects-server'; +import type { Logger } from '@kbn/logging'; import { checkReferenceOrigins, validateReferences, @@ -59,6 +60,7 @@ export interface ImportSavedObjectsOptions { * If provided, Kibana will apply the given option to the `managed` property. */ managed?: boolean; + log: Logger; } /** @@ -79,7 +81,11 @@ export async function importSavedObjectsFromStream({ refresh, compatibilityMode, managed, + log, }: ImportSavedObjectsOptions): Promise { + log.debug( + `Importing with overwrite ${overwrite ? 'enabled' : 'disabled'} and size limit ${objectLimit}` + ); let errorAccumulator: SavedObjectsImportFailure[] = []; const supportedTypes = typeRegistry.getImportableAndExportableTypes().map((type) => type.name); @@ -90,6 +96,11 @@ export async function importSavedObjectsFromStream({ supportedTypes, managed, }); + log.debug( + `Importing types: ${[ + ...new Set(collectSavedObjectsResult.collectedObjects.map((obj) => obj.type)), + ].join(', ')}` + ); errorAccumulator = [...errorAccumulator, ...collectSavedObjectsResult.errors]; // Map of all IDs for objects that we are attempting to import, and any references that are not included in the read stream; // each value is empty by default @@ -197,7 +208,17 @@ export async function importSavedObjectsFromStream({ objects: createSavedObjectsResult.createdObjects, importHooks, }); - + if (errorAccumulator.length > 0) { + log.error( + `Failed to import saved objects. ${errorAccumulator.length} errors: ${JSON.stringify( + errorAccumulator + )}` + ); + } else { + log.info( + `Successfully imported ${createSavedObjectsResult.createdObjects.length} saved objects.` + ); + } return { successCount: createSavedObjectsResult.createdObjects.length, success: errorAccumulator.length === 0, diff --git a/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/saved_objects_importer.ts b/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/saved_objects_importer.ts index f990eb13c435b..e8c13180bbdaf 100644 --- a/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/saved_objects_importer.ts +++ b/packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/saved_objects_importer.ts @@ -62,7 +62,6 @@ export class SavedObjectsImporter implements ISavedObjectsImporter { compatibilityMode, managed, }: SavedObjectsImportOptions): Promise { - this.#log.debug('Starting the import process'); return importSavedObjectsFromStream({ readStream, createNewCopies, @@ -75,6 +74,7 @@ export class SavedObjectsImporter implements ISavedObjectsImporter { typeRegistry: this.#typeRegistry, importHooks: this.#importHooks, managed, + log: this.#log, }); } diff --git a/packages/deeplinks/search/constants.ts b/packages/deeplinks/search/constants.ts index a2a17b20efba8..9848bb0c3d42e 100644 --- a/packages/deeplinks/search/constants.ts +++ b/packages/deeplinks/search/constants.ts @@ -21,3 +21,7 @@ export const SERVERLESS_ES_SEARCH_INFERENCE_ENDPOINTS_ID = 'searchInferenceEndpo export const SEARCH_HOMEPAGE = 'searchHomepage'; export const SEARCH_INDICES_START = 'elasticsearchStart'; export const SEARCH_INDICES = 'elasticsearchIndices'; +export const SEARCH_ELASTICSEARCH = 'enterpriseSearchElasticsearch'; +export const SEARCH_VECTOR_SEARCH = 'enterpriseSearchVectorSearch'; +export const SEARCH_SEMANTIC_SEARCH = 'enterpriseSearchSemanticSearch'; +export const SEARCH_AI_SEARCH = 'enterpriseSearchAISearch'; diff --git a/packages/deeplinks/search/deep_links.ts b/packages/deeplinks/search/deep_links.ts index 98703f18ac3fb..22dfb91bdff33 100644 --- a/packages/deeplinks/search/deep_links.ts +++ b/packages/deeplinks/search/deep_links.ts @@ -22,6 +22,10 @@ import { SEARCH_HOMEPAGE, SEARCH_INDICES_START, SEARCH_INDICES, + SEARCH_ELASTICSEARCH, + SEARCH_VECTOR_SEARCH, + SEARCH_SEMANTIC_SEARCH, + SEARCH_AI_SEARCH, } from './constants'; export type EnterpriseSearchApp = typeof ENTERPRISE_SEARCH_APP_ID; @@ -38,6 +42,10 @@ export type SearchInferenceEndpointsId = typeof SERVERLESS_ES_SEARCH_INFERENCE_E export type SearchHomepage = typeof SEARCH_HOMEPAGE; export type SearchStart = typeof SEARCH_INDICES_START; export type SearchIndices = typeof SEARCH_INDICES; +export type SearchElasticsearch = typeof SEARCH_ELASTICSEARCH; +export type SearchVectorSearch = typeof SEARCH_VECTOR_SEARCH; +export type SearchSemanticSearch = typeof SEARCH_SEMANTIC_SEARCH; +export type SearchAISearch = typeof SEARCH_AI_SEARCH; export type ContentLinkId = 'searchIndices' | 'connectors' | 'webCrawlers'; @@ -65,4 +73,8 @@ export type DeepLinkId = | `${EnterpriseSearchAppsearchApp}:${AppsearchLinkId}` | `${EnterpriseSearchRelevanceApp}:${RelevanceLinkId}` | SearchStart - | SearchIndices; + | SearchIndices + | SearchElasticsearch + | SearchVectorSearch + | SearchSemanticSearch + | SearchAISearch; diff --git a/packages/deeplinks/search/index.ts b/packages/deeplinks/search/index.ts index 250dfeed299e6..7c78d64081133 100644 --- a/packages/deeplinks/search/index.ts +++ b/packages/deeplinks/search/index.ts @@ -17,6 +17,10 @@ export { ENTERPRISE_SEARCH_WORKPLACESEARCH_APP_ID, SERVERLESS_ES_APP_ID, SERVERLESS_ES_CONNECTORS_ID, + SEARCH_ELASTICSEARCH, + SEARCH_VECTOR_SEARCH, + SEARCH_SEMANTIC_SEARCH, + SEARCH_AI_SEARCH, } from './constants'; export type { diff --git a/packages/kbn-alerting-types/r_rule_types.ts b/packages/kbn-alerting-types/r_rule_types.ts index 25d1b9a5a30a7..a51b5939fe514 100644 --- a/packages/kbn-alerting-types/r_rule_types.ts +++ b/packages/kbn-alerting-types/r_rule_types.ts @@ -14,7 +14,7 @@ export type RRuleParams = Partial & Pick & { dtstart: string; - byweekday?: Array; + byweekday?: Array | null; wkst?: WeekdayStr; until?: string; }; diff --git a/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_uptime_schema.ts b/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_uptime_schema.ts index 8770b70402d08..bf37ffc1ddb9c 100644 --- a/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_uptime_schema.ts +++ b/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_uptime_schema.ts @@ -77,6 +77,7 @@ const ObservabilityUptimeAlertOptional = rt.partial({ 'anomaly.start': schemaDate, configId: schemaString, 'error.message': schemaString, + 'error.stack_trace': schemaString, 'host.name': schemaString, 'kibana.alert.context': schemaUnknown, 'kibana.alert.evaluation.threshold': schemaStringOrNumber, diff --git a/packages/kbn-apm-synthtrace-client/src/lib/entities/kubernetes/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/entities/kubernetes/index.ts index 36d7f8caf9601..db95dcf4155bc 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/entities/kubernetes/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/entities/kubernetes/index.ts @@ -55,9 +55,9 @@ export class K8sEntity extends Serializable { super({ ...fields, 'entity.type': entityTypeWithSchema, - 'entity.definitionId': `builtin_${entityTypeWithSchema}`, - 'entity.identityFields': identityFields, - 'entity.displayName': getDisplayName({ identityFields, fields }), + 'entity.definition_id': `builtin_${entityTypeWithSchema}`, + 'entity.identity_fields': identityFields, + 'entity.display_name': getDisplayName({ identityFields, fields }), }); } } diff --git a/packages/kbn-cell-actions/src/actions/copy_to_clipboard/copy_to_clipboard.ts b/packages/kbn-cell-actions/src/actions/copy_to_clipboard/copy_to_clipboard.ts index 850a534278fbe..90e93923fa360 100644 --- a/packages/kbn-cell-actions/src/actions/copy_to_clipboard/copy_to_clipboard.ts +++ b/packages/kbn-cell-actions/src/actions/copy_to_clipboard/copy_to_clipboard.ts @@ -33,7 +33,7 @@ const COPY_TO_CLIPBOARD_SUCCESS = i18n.translate( } ); -const escapeValue = (value: string) => value.replace(/"/g, '\\"'); +const escapeValue = (value: string) => value.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); export const createCopyToClipboardActionFactory = createCellActionFactory( ({ notifications }: { notifications: NotificationsStart }) => ({ diff --git a/packages/kbn-data-stream-adapter/src/field_maps/types.ts b/packages/kbn-data-stream-adapter/src/field_maps/types.ts index 62f4c7c600036..1cdafc7c61809 100644 --- a/packages/kbn-data-stream-adapter/src/field_maps/types.ts +++ b/packages/kbn-data-stream-adapter/src/field_maps/types.ts @@ -54,6 +54,8 @@ export type FieldMap = Record< scaling_factor?: number; dynamic?: boolean | 'strict'; properties?: Record; + inference_id?: string; + copy_to?: string; } >; diff --git a/packages/kbn-discover-utils/index.ts b/packages/kbn-discover-utils/index.ts index 7234944783037..4345c0f8fc6c4 100644 --- a/packages/kbn-discover-utils/index.ts +++ b/packages/kbn-discover-utils/index.ts @@ -56,6 +56,7 @@ export { getVisibleColumns, canPrependTimeFieldColumn, DiscoverFlyouts, + AppMenuRegistry, dismissAllFlyoutsExceptFor, dismissFlyouts, LogLevelBadge, diff --git a/packages/kbn-discover-utils/src/components/app_menu/__snapshots__/app_menu_registry.test.ts.snap b/packages/kbn-discover-utils/src/components/app_menu/__snapshots__/app_menu_registry.test.ts.snap new file mode 100644 index 0000000000000..88ee3c6f55a76 --- /dev/null +++ b/packages/kbn-discover-utils/src/components/app_menu/__snapshots__/app_menu_registry.test.ts.snap @@ -0,0 +1,184 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AppMenuRegistry should allow to override actions under submenu 1`] = ` +Array [ + Object { + "controlProps": Object { + "label": "Action 2", + "onClick": [MockFunction], + }, + "id": "action-2", + "order": 200, + "type": "secondary", + }, + Object { + "actions": Array [ + Object { + "controlProps": Object { + "label": "Action 3.2", + "onClick": [MockFunction], + }, + "id": "action-3-2", + "order": 200, + "type": "secondary", + }, + Object { + "controlProps": Object { + "label": "Action Custom", + "onClick": [MockFunction], + }, + "id": "action-3-1", + "type": "custom", + }, + ], + "id": "action-3", + "label": "Action 3", + "order": 300, + "type": "secondary", + }, + Object { + "controlProps": Object { + "iconType": "bell", + "label": "Action 1", + "onClick": [MockFunction], + }, + "id": "action-1", + "order": 100, + "type": "primary", + }, +] +`; + +exports[`AppMenuRegistry should allow to register custom actions 1`] = ` +Array [ + Object { + "controlProps": Object { + "label": "Action Custom", + "onClick": [MockFunction], + }, + "id": "action-custom", + "type": "custom", + }, + Object { + "actions": Array [ + Object { + "controlProps": Object { + "label": "Action Custom Submenu 1", + "onClick": [MockFunction], + }, + "id": "action-custom-submenu-1", + "type": "custom", + }, + ], + "id": "action-custom-submenu", + "label": "Action Custom Submenu", + "type": "custom", + }, + Object { + "controlProps": Object { + "label": "Action 2", + "onClick": [MockFunction], + }, + "id": "action-2", + "order": 200, + "type": "secondary", + }, + Object { + "actions": Array [ + Object { + "controlProps": Object { + "iconType": "heart", + "label": "Action 3.1", + "onClick": [MockFunction], + }, + "id": "action-3-1", + "order": 100, + "type": "secondary", + }, + Object { + "controlProps": Object { + "label": "Action 3.2", + "onClick": [MockFunction], + }, + "id": "action-3-2", + "order": 200, + "type": "secondary", + }, + ], + "id": "action-3", + "label": "Action 3", + "order": 300, + "type": "secondary", + }, + Object { + "controlProps": Object { + "iconType": "bell", + "label": "Action 1", + "onClick": [MockFunction], + }, + "id": "action-1", + "order": 100, + "type": "primary", + }, +] +`; + +exports[`AppMenuRegistry should allow to register custom actions under submenu 1`] = ` +Array [ + Object { + "controlProps": Object { + "label": "Action 2", + "onClick": [MockFunction], + }, + "id": "action-2", + "order": 200, + "type": "secondary", + }, + Object { + "actions": Array [ + Object { + "controlProps": Object { + "iconType": "heart", + "label": "Action 3.1", + "onClick": [MockFunction], + }, + "id": "action-3-1", + "order": 100, + "type": "secondary", + }, + Object { + "controlProps": Object { + "label": "Action Custom", + "onClick": [MockFunction], + }, + "id": "action-custom", + "order": 101, + "type": "custom", + }, + Object { + "controlProps": Object { + "label": "Action 3.2", + "onClick": [MockFunction], + }, + "id": "action-3-2", + "order": 200, + "type": "secondary", + }, + ], + "id": "action-3", + "label": "Action 3", + "order": 300, + "type": "secondary", + }, + Object { + "controlProps": Object { + "iconType": "bell", + "label": "Action 1", + "onClick": [MockFunction], + }, + "id": "action-1", + "order": 100, + "type": "primary", + }, +] +`; diff --git a/packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.test.ts b/packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.test.ts new file mode 100644 index 0000000000000..46b565c490b0e --- /dev/null +++ b/packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.test.ts @@ -0,0 +1,188 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { AppMenuRegistry } from './app_menu_registry'; +import { + AppMenuActionSubmenuSecondary, + AppMenuActionType, + AppMenuSubmenuActionCustom, +} from './types'; + +describe('AppMenuRegistry', () => { + it('should initialize correctly', () => { + const appMenuRegistry = initializeAppMenuRegistry(); + expect(appMenuRegistry.isActionRegistered('action-1')).toBe(true); + expect(appMenuRegistry.isActionRegistered('action-2')).toBe(true); + expect(appMenuRegistry.isActionRegistered('action-3')).toBe(true); + expect(appMenuRegistry.isActionRegistered('action-3-1')).toBe(true); + expect(appMenuRegistry.isActionRegistered('action-3-2')).toBe(true); + expect(appMenuRegistry.isActionRegistered('action-n')).toBe(false); + expect(appMenuRegistry.getSortedItems()).toHaveLength(3); + }); + + it('should allow to register custom actions', () => { + const appMenuRegistry = initializeAppMenuRegistry(); + expect(appMenuRegistry.isActionRegistered('action-custom')).toBe(false); + + appMenuRegistry.registerCustomAction({ + id: 'action-custom', + type: AppMenuActionType.custom, + controlProps: { + label: 'Action Custom', + onClick: jest.fn(), + }, + }); + + appMenuRegistry.registerCustomAction({ + id: 'action-custom-submenu', + type: AppMenuActionType.custom, + label: 'Action Custom Submenu', + actions: [ + { + id: 'action-custom-submenu-1', + type: AppMenuActionType.custom, + controlProps: { + label: 'Action Custom Submenu 1', + onClick: jest.fn(), + }, + }, + ], + }); + + expect(appMenuRegistry.isActionRegistered('action-custom')).toBe(true); + expect(appMenuRegistry.isActionRegistered('action-custom-submenu')).toBe(true); + expect(appMenuRegistry.getSortedItems()).toHaveLength(5); + + appMenuRegistry.registerCustomAction({ + id: 'action-custom-extra', + type: AppMenuActionType.custom, + controlProps: { + label: 'Action Custom Extra', + onClick: jest.fn(), + }, + }); + + // should limit the number of custom items + const items = appMenuRegistry.getSortedItems(); + expect(items).toHaveLength(5); + expect(items).toMatchSnapshot(); + }); + + it('should allow to register custom actions under submenu', () => { + const appMenuRegistry = initializeAppMenuRegistry(); + expect(appMenuRegistry.isActionRegistered('action-custom')).toBe(false); + + let items = appMenuRegistry.getSortedItems(); + let submenuItem = items.find((item) => item.id === 'action-3') as AppMenuActionSubmenuSecondary; + expect(items).toHaveLength(3); + expect(submenuItem.actions).toHaveLength(2); + + appMenuRegistry.registerCustomActionUnderSubmenu('action-3', { + id: 'action-custom', + type: AppMenuActionType.custom, + order: 101, + controlProps: { + label: 'Action Custom', + onClick: jest.fn(), + }, + }); + + expect(appMenuRegistry.isActionRegistered('action-custom')).toBe(true); + + items = appMenuRegistry.getSortedItems(); + expect(items).toHaveLength(3); + + // calling it again should not add a duplicate + items = appMenuRegistry.getSortedItems(); + expect(items).toHaveLength(3); + + submenuItem = items.find((item) => item.id === 'action-3') as AppMenuActionSubmenuSecondary; + expect(submenuItem.actions).toHaveLength(3); + expect(items).toMatchSnapshot(); + }); + + it('should allow to override actions under submenu', () => { + const appMenuRegistry = initializeAppMenuRegistry(); + + let items = appMenuRegistry.getSortedItems(); + expect(items).toHaveLength(3); + + let submenuItem = items.find((item) => item.id === 'action-3') as AppMenuActionSubmenuSecondary; + const existingSecondaryActionId = submenuItem.actions[0].id; + expect(submenuItem.actions).toHaveLength(2); + + expect(appMenuRegistry.isActionRegistered(existingSecondaryActionId)).toBe(true); + + const customAction: AppMenuSubmenuActionCustom = { + id: existingSecondaryActionId, // using the same id to override the action with a custom one + type: AppMenuActionType.custom, + controlProps: { + label: 'Action Custom', + onClick: jest.fn(), + }, + }; + appMenuRegistry.registerCustomActionUnderSubmenu('action-3', customAction); + + expect(appMenuRegistry.isActionRegistered(existingSecondaryActionId)).toBe(true); + + items = appMenuRegistry.getSortedItems(); + submenuItem = items.find((item) => item.id === 'action-3') as AppMenuActionSubmenuSecondary; + expect(submenuItem.actions).toHaveLength(2); + expect(submenuItem.actions.find((item) => item.id === existingSecondaryActionId)).toBe( + customAction + ); + expect(items).toMatchSnapshot(); + }); +}); + +function initializeAppMenuRegistry() { + return new AppMenuRegistry([ + { + id: 'action-1', + type: AppMenuActionType.primary, + controlProps: { + label: 'Action 1', + iconType: 'bell', + onClick: jest.fn(), + }, + }, + { + id: 'action-2', + type: AppMenuActionType.secondary, + controlProps: { + label: 'Action 2', + onClick: jest.fn(), + }, + }, + { + id: 'action-3', + type: AppMenuActionType.secondary, + label: 'Action 3', + actions: [ + { + id: 'action-3-1', + type: AppMenuActionType.secondary, + controlProps: { + label: 'Action 3.1', + iconType: 'heart', + onClick: jest.fn(), + }, + }, + { + id: 'action-3-2', + type: AppMenuActionType.secondary, + controlProps: { + label: 'Action 3.2', + onClick: jest.fn(), + }, + }, + ], + }, + ]); +} diff --git a/packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts b/packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts new file mode 100644 index 0000000000000..65145c7de6751 --- /dev/null +++ b/packages/kbn-discover-utils/src/components/app_menu/app_menu_registry.ts @@ -0,0 +1,214 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { + AppMenuActionBase, + AppMenuActionSubmenuBase, + AppMenuActionSubmenuCustom, + AppMenuSubmenuHorizontalRule, + AppMenuActionSubmenuSecondary, + AppMenuActionType, + AppMenuItem, + AppMenuItemCustom, + AppMenuItemPrimary, + AppMenuItemSecondary, + AppMenuSubmenuActionCustom, +} from './types'; + +export class AppMenuRegistry { + static CUSTOM_ITEMS_LIMIT = 2; + + private appMenuItems: AppMenuItem[]; + /** + * As custom actions can be registered under a submenu from both root and data source profiles, we need to keep track of them separately. + * Otherwise, it would be less predictable. For example, we would override/reset the actions from the data source profile with the ones from the root profile. + * @private + */ + private customSubmenuItemsBySubmenuId: Map< + string, + Array + >; + + constructor(primaryAndSecondaryActions: Array) { + this.appMenuItems = assignOrderToActions(primaryAndSecondaryActions); + this.customSubmenuItemsBySubmenuId = new Map(); + } + + public isActionRegistered(appMenuItemId: string) { + return ( + this.appMenuItems.some((item) => { + if (item.id === appMenuItemId) { + return true; + } + if (isAppMenuActionSubmenu(item)) { + return item.actions.some((submenuItem) => submenuItem.id === appMenuItemId); + } + return false; + }) || + [...this.customSubmenuItemsBySubmenuId.values()].some((submenuItems) => + submenuItems.some((item) => item.id === appMenuItemId) + ) + ); + } + + /** + * Register a custom action to the app menu. It can be a simple action or a submenu with more actions and horizontal rules. + * Note: Only 2 top level custom actions are allowed to be rendered in the app menu. The rest will be ignored. + * A custom action can also open a flyout or a modal. For that, return your custom react node from action's `onClick` event and call `onFinishAction` when you're done. + * @param appMenuItem + */ + public registerCustomAction(appMenuItem: AppMenuItemCustom) { + this.appMenuItems = [ + ...this.appMenuItems.filter( + // prevent duplicates + (item) => !(item.id === appMenuItem.id && item.type === AppMenuActionType.custom) + ), + appMenuItem, + ]; + } + + /** + * Register a custom action under a submenu. It can be an action or a horizontal rule. + * Any number of submenu actions can be registered and rendered. + * You can also extend an existing submenu with more actions. For example, AppMenuActionType.alerts. + * `order` property is optional and can be used to control the order of actions in the submenu. + * @param submenuId + * @param appMenuItem + */ + public registerCustomActionUnderSubmenu( + submenuId: string, + appMenuItem: AppMenuSubmenuActionCustom | AppMenuSubmenuHorizontalRule + ) { + this.customSubmenuItemsBySubmenuId.set(submenuId, [ + ...(this.customSubmenuItemsBySubmenuId.get(submenuId) ?? []).filter( + // prevent duplicates and allow overrides + (item) => item.id !== appMenuItem.id + ), + appMenuItem, + ]); + } + + private getSortedItemsForType(type: AppMenuActionType) { + let actions = this.appMenuItems.filter((item) => item.type === type); + + if (type === AppMenuActionType.custom && actions.length > AppMenuRegistry.CUSTOM_ITEMS_LIMIT) { + // apply the limitation on how many custom items can be shown + actions = actions.slice(0, AppMenuRegistry.CUSTOM_ITEMS_LIMIT); + } + + // enrich submenus with custom actions + if (type === AppMenuActionType.secondary || type === AppMenuActionType.custom) { + [...this.customSubmenuItemsBySubmenuId.entries()].forEach(([submenuId, customActions]) => { + actions = actions.map((item) => { + if (item.id === submenuId && isAppMenuActionSubmenu(item)) { + return extendSubmenuWithCustomActions(item, customActions); + } + return item; + }); + }); + } + + return sortAppMenuItemsByOrder(actions); + } + + /** + * Get the resulting app menu items sorted by type and order. + */ + public getSortedItems() { + const primaryItems = this.getSortedItemsForType(AppMenuActionType.primary); + const secondaryItems = this.getSortedItemsForType(AppMenuActionType.secondary); + const customItems = this.getSortedItemsForType(AppMenuActionType.custom); + + return [...customItems, ...secondaryItems, ...primaryItems]; + } +} + +function isAppMenuActionSubmenu( + appMenuItem: AppMenuItem +): appMenuItem is AppMenuActionSubmenuSecondary | AppMenuActionSubmenuCustom { + return 'actions' in appMenuItem && Array.isArray(appMenuItem.actions); +} + +const FALLBACK_ORDER = Number.MAX_SAFE_INTEGER; + +function sortByOrder(a: T, b: T): number { + return (a.order ?? FALLBACK_ORDER) - (b.order ?? FALLBACK_ORDER); +} + +function getAppMenuSubmenuWithSortedItemsByOrder< + T extends AppMenuActionSubmenuBase = AppMenuActionSubmenuSecondary | AppMenuActionSubmenuCustom +>(appMenuItem: T): T { + return { + ...appMenuItem, + actions: [...appMenuItem.actions].sort(sortByOrder), + }; +} + +function sortAppMenuItemsByOrder(appMenuItems: AppMenuItem[]): AppMenuItem[] { + const sortedAppMenuItems = [...appMenuItems].sort(sortByOrder); + return sortedAppMenuItems.map((appMenuItem) => { + if (isAppMenuActionSubmenu(appMenuItem)) { + return getAppMenuSubmenuWithSortedItemsByOrder(appMenuItem); + } + return appMenuItem; + }); +} + +function getAppMenuSubmenuWithAssignedOrder< + T extends AppMenuActionSubmenuBase = AppMenuActionSubmenuSecondary | AppMenuActionSubmenuCustom +>(appMenuItem: T, order: number): T { + let orderInSubmenu = 0; + const actionsWithOrder = appMenuItem.actions.map((action) => { + orderInSubmenu = orderInSubmenu + 100; + return { + ...action, + order: action.order ?? orderInSubmenu, + }; + }); + return { + ...appMenuItem, + order: appMenuItem.order ?? order, + actions: actionsWithOrder, + }; +} + +function extendSubmenuWithCustomActions< + T extends AppMenuActionSubmenuBase = AppMenuActionSubmenuSecondary | AppMenuActionSubmenuCustom +>( + appMenuItem: T, + customActions: Array +): T { + const customActionsIds = new Set(customActions.map((action) => action.id)); + return { + ...appMenuItem, + actions: [ + ...appMenuItem.actions.filter((item) => !customActionsIds.has(item.id)), // allow to override secondary actions with custom ones + ...customActions, + ], + }; +} + +/** + * All primary and secondary actions by default get order 100, 200, 300,... assigned to them. + * Same for actions under a submenu. + * @param appMenuItems + */ +function assignOrderToActions(appMenuItems: AppMenuItem[]): AppMenuItem[] { + let order = 0; + return appMenuItems.map((appMenuItem) => { + order = order + 100; + if (isAppMenuActionSubmenu(appMenuItem)) { + return getAppMenuSubmenuWithAssignedOrder(appMenuItem, order); + } + return { + ...appMenuItem, + order: appMenuItem.order ?? order, + }; + }); +} diff --git a/packages/kbn-discover-utils/src/components/app_menu/types.ts b/packages/kbn-discover-utils/src/components/app_menu/types.ts new file mode 100644 index 0000000000000..d5cd1bde16be7 --- /dev/null +++ b/packages/kbn-discover-utils/src/components/app_menu/types.ts @@ -0,0 +1,148 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React from 'react'; +import type { TopNavMenuData } from '@kbn/navigation-plugin/public'; +import type { EuiIconType } from '@elastic/eui/src/components/icon/icon'; + +export interface AppMenuControlOnClickParams { + anchorElement: HTMLElement; + onFinishAction: () => void; +} + +export type AppMenuControlProps = Pick< + TopNavMenuData, + 'testId' | 'isLoading' | 'label' | 'description' | 'disableButton' | 'href' | 'tooltip' +> & { + onClick: + | ((params: AppMenuControlOnClickParams) => Promise) + | ((params: AppMenuControlOnClickParams) => React.ReactNode | void) + | undefined; +}; + +export type AppMenuControlWithIconProps = AppMenuControlProps & { + iconType: EuiIconType; +}; + +interface ControlWithOptionalIcon { + iconType?: EuiIconType; +} + +export enum AppMenuActionId { + new = 'new', + open = 'open', + share = 'share', + alerts = 'alerts', + inspect = 'inspect', + createRule = 'createRule', + manageRulesAndConnectors = 'manageRulesAndConnectors', +} + +export enum AppMenuActionType { + primary = 'primary', + secondary = 'secondary', + custom = 'custom', + submenuHorizontalRule = 'submenuHorizontalRule', +} + +export interface AppMenuActionBase { + readonly id: AppMenuActionId | string; + readonly order?: number | undefined; +} + +/** + * A secondary menu action + */ +export interface AppMenuActionSecondary extends AppMenuActionBase { + readonly type: AppMenuActionType.secondary; + readonly controlProps: AppMenuControlProps; +} + +/** + * A secondary submenu action + */ +export interface AppMenuSubmenuActionSecondary + extends Omit { + readonly controlProps: AppMenuControlProps & ControlWithOptionalIcon; +} + +/** + * A custom menu action + */ +export interface AppMenuActionCustom extends AppMenuActionBase { + readonly type: AppMenuActionType.custom; + readonly controlProps: AppMenuControlProps; +} + +/** + * A custom submenu action + */ +export interface AppMenuSubmenuActionCustom extends Omit { + readonly controlProps: AppMenuControlProps & ControlWithOptionalIcon; +} + +/** + * A primary menu action (with icon only) + */ +export interface AppMenuActionPrimary extends AppMenuActionBase { + readonly type: AppMenuActionType.primary; + readonly controlProps: AppMenuControlWithIconProps; +} + +/** + * A horizontal rule between menu items + */ +export interface AppMenuSubmenuHorizontalRule extends AppMenuActionBase { + readonly type: AppMenuActionType.submenuHorizontalRule; + readonly testId?: TopNavMenuData['testId']; +} + +/** + * A menu action which opens a submenu with more actions + */ +export interface AppMenuActionSubmenuBase + extends AppMenuActionBase { + readonly type: T extends AppMenuActionSecondary + ? AppMenuActionType.secondary + : AppMenuActionType.custom; + readonly label: TopNavMenuData['label']; + readonly description?: TopNavMenuData['description']; + readonly testId?: TopNavMenuData['testId']; + readonly actions: T extends AppMenuActionSecondary + ? Array< + AppMenuSubmenuActionSecondary | AppMenuSubmenuActionCustom | AppMenuSubmenuHorizontalRule + > + : Array; +} + +/** + * A menu action which opens a submenu with more secondary actions + */ +export type AppMenuActionSubmenuSecondary = AppMenuActionSubmenuBase; +/** + * A menu action which opens a submenu with more custom actions + */ +export type AppMenuActionSubmenuCustom = AppMenuActionSubmenuBase; + +/** + * A primary menu item can only have an icon + */ +export type AppMenuItemPrimary = AppMenuActionPrimary; +/** + * A secondary menu item can have only a label or a submenu + */ +export type AppMenuItemSecondary = AppMenuActionSecondary | AppMenuActionSubmenuSecondary; +/** + * A custom menu item can have only a label or a submenu + */ +export type AppMenuItemCustom = AppMenuActionCustom | AppMenuActionSubmenuCustom; +/** + * A menu item can be primary, secondary or custom + */ +export type AppMenuItem = AppMenuItemPrimary | AppMenuItemSecondary | AppMenuItemCustom; diff --git a/packages/kbn-discover-utils/src/index.ts b/packages/kbn-discover-utils/src/index.ts index 8fe9a9418c9fe..243dd05774448 100644 --- a/packages/kbn-discover-utils/src/index.ts +++ b/packages/kbn-discover-utils/src/index.ts @@ -14,3 +14,4 @@ export * from './utils'; export * from './data_types'; export * from './components/custom_control_columns'; +export { AppMenuRegistry } from './components/app_menu/app_menu_registry'; diff --git a/packages/kbn-discover-utils/src/types.ts b/packages/kbn-discover-utils/src/types.ts index 63297edfe7643..2c298da999490 100644 --- a/packages/kbn-discover-utils/src/types.ts +++ b/packages/kbn-discover-utils/src/types.ts @@ -17,6 +17,8 @@ export type { RowControlProps, RowControlRowProps, } from './components/custom_control_columns/types'; +export type * from './components/app_menu/types'; +export { AppMenuActionId, AppMenuActionType } from './components/app_menu/types'; type DiscoverSearchHit = SearchHit>; diff --git a/packages/kbn-discover-utils/tsconfig.json b/packages/kbn-discover-utils/tsconfig.json index 865603e379eca..c26624d139dec 100644 --- a/packages/kbn-discover-utils/tsconfig.json +++ b/packages/kbn-discover-utils/tsconfig.json @@ -27,7 +27,8 @@ "@kbn/core-ui-settings-browser", "@kbn/expressions-plugin", "@kbn/logs-data-access-plugin", - "@kbn/ui-theme", - "@kbn/i18n-react" + "@kbn/i18n-react", + "@kbn/navigation-plugin", + "@kbn/ui-theme" ] } diff --git a/packages/kbn-es-types/src/search.ts b/packages/kbn-es-types/src/search.ts index 4c780fb2a2986..87f9dd15517c9 100644 --- a/packages/kbn-es-types/src/search.ts +++ b/packages/kbn-es-types/src/search.ts @@ -682,6 +682,7 @@ export interface ESQLSearchResponse { all_columns?: ESQLColumn[]; values: ESQLRow[]; took?: number; + _clusters?: estypes.ClusterStatistics; } export interface ESQLSearchParams { diff --git a/packages/kbn-eslint-plugin-eslint/rules/no_deprecated_authz_config.js b/packages/kbn-eslint-plugin-eslint/rules/no_deprecated_authz_config.js index 0f0b8759b4a82..8661c5e1c52d6 100644 --- a/packages/kbn-eslint-plugin-eslint/rules/no_deprecated_authz_config.js +++ b/packages/kbn-eslint-plugin-eslint/rules/no_deprecated_authz_config.js @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -const routeMethods = ['get', 'put', 'delete', 'post']; +const routeMethods = ['get', 'put', 'delete', 'post', 'patch']; const ACCESS_TAG_PREFIX = 'access:'; const isStringLiteral = (el) => el.type === 'Literal' && typeof el.value === 'string'; diff --git a/packages/kbn-esql-ast/src/builder/builder.ts b/packages/kbn-esql-ast/src/builder/builder.ts index 26b64a6312ee4..894ab99e5b3e8 100644 --- a/packages/kbn-esql-ast/src/builder/builder.ts +++ b/packages/kbn-esql-ast/src/builder/builder.ts @@ -11,15 +11,22 @@ import { ESQLAstComment, + ESQLAstCommentMultiLine, + ESQLAstCommentSingleLine, ESQLAstQueryExpression, ESQLColumn, ESQLCommand, ESQLCommandOption, ESQLDecimalLiteral, + ESQLIdentifier, ESQLInlineCast, ESQLIntegerLiteral, ESQLList, ESQLLocation, + ESQLNamedParamLiteral, + ESQLParam, + ESQLPositionalParamLiteral, + ESQLOrderExpression, ESQLSource, } from '../types'; import { AstNodeParserFields, AstNodeTemplate, PartialFields } from './types'; @@ -63,17 +70,17 @@ export namespace Builder { }; }; - export const comment = ( - subtype: ESQLAstComment['subtype'], + export const comment = ( + subtype: S, text: string, - location: ESQLLocation - ): ESQLAstComment => { + location?: ESQLLocation + ): S extends 'multi-line' ? ESQLAstCommentMultiLine : ESQLAstCommentSingleLine => { return { type: 'comment', subtype, text, location, - }; + } as S extends 'multi-line' ? ESQLAstCommentMultiLine : ESQLAstCommentSingleLine; }; export namespace expression { @@ -130,6 +137,20 @@ export namespace Builder { }; }; + export const order = ( + operand: ESQLColumn, + template: Omit, 'name' | 'args'>, + fromParser?: Partial + ): ESQLOrderExpression => { + return { + ...template, + ...Builder.parserFields(fromParser), + name: '', + args: [operand], + type: 'order', + }; + }; + export const inlineCast = ( template: Omit, 'name'>, fromParser?: Partial @@ -173,4 +194,65 @@ export namespace Builder { }; } } + + export const identifier = ( + template: AstNodeTemplate, + fromParser?: Partial + ): ESQLIdentifier => { + return { + ...template, + ...Builder.parserFields(fromParser), + type: 'identifier', + }; + }; + + export namespace param { + export const unnamed = (fromParser?: Partial): ESQLParam => { + const node = { + ...Builder.parserFields(fromParser), + name: '', + value: '', + paramType: 'unnamed', + type: 'literal', + literalType: 'param', + }; + + return node as ESQLParam; + }; + + export const named = ( + template: Omit, 'name' | 'literalType' | 'paramType'>, + fromParser?: Partial + ): ESQLNamedParamLiteral => { + const node: ESQLNamedParamLiteral = { + ...template, + ...Builder.parserFields(fromParser), + name: '', + type: 'literal', + literalType: 'param', + paramType: 'named', + }; + + return node; + }; + + export const positional = ( + template: Omit< + AstNodeTemplate, + 'name' | 'literalType' | 'paramType' + >, + fromParser?: Partial + ): ESQLPositionalParamLiteral => { + const node: ESQLPositionalParamLiteral = { + ...template, + ...Builder.parserFields(fromParser), + name: '', + type: 'literal', + literalType: 'param', + paramType: 'positional', + }; + + return node; + }; + } } diff --git a/packages/kbn-esql-ast/src/mutate/commands/from/metadata.ts b/packages/kbn-esql-ast/src/mutate/commands/from/metadata.ts index 7f08fa2a5e946..5160ab65954cb 100644 --- a/packages/kbn-esql-ast/src/mutate/commands/from/metadata.ts +++ b/packages/kbn-esql-ast/src/mutate/commands/from/metadata.ts @@ -106,7 +106,7 @@ export const removeByPredicate = ( option.args.splice(index, 1); if (option.args.length === 0) { - generic.removeCommandOption(ast, option); + generic.commands.options.remove(ast, option); } return tuple; @@ -148,16 +148,16 @@ export const insert = ( fieldName: string | string[], index: number = -1 ): [column: ESQLColumn, option: ESQLCommandOption] | undefined => { - let option = generic.findCommandOptionByName(ast, 'from', 'metadata'); + let option = generic.commands.options.findByName(ast, 'from', 'metadata'); if (!option) { - const command = generic.findCommandByName(ast, 'from'); + const command = generic.commands.findByName(ast, 'from'); if (!command) { return; } - option = generic.appendCommandOption(command, 'metadata'); + option = generic.commands.options.append(command, 'metadata'); } const parts: string[] = typeof fieldName === 'string' ? [fieldName] : fieldName; @@ -189,7 +189,7 @@ export const upsert = ( fieldName: string | string[], index: number = -1 ): [column: ESQLColumn, option: ESQLCommandOption] | undefined => { - const option = generic.findCommandOptionByName(ast, 'from', 'metadata'); + const option = generic.commands.options.findByName(ast, 'from', 'metadata'); if (option) { const parts = Array.isArray(fieldName) ? fieldName : [fieldName]; diff --git a/packages/kbn-esql-ast/src/mutate/commands/from/sources.ts b/packages/kbn-esql-ast/src/mutate/commands/from/sources.ts index da67500b5b0bd..c10096cec38d9 100644 --- a/packages/kbn-esql-ast/src/mutate/commands/from/sources.ts +++ b/packages/kbn-esql-ast/src/mutate/commands/from/sources.ts @@ -67,7 +67,7 @@ export const remove = ( return undefined; } - const success = generic.removeCommandArgument(ast, node); + const success = generic.commands.args.remove(ast, node); return success ? node : undefined; }; @@ -78,7 +78,7 @@ export const insert = ( clusterName?: string, index: number = -1 ): ESQLSource | undefined => { - const command = generic.findCommandByName(ast, 'from'); + const command = generic.commands.findByName(ast, 'from'); if (!command) { return; @@ -87,7 +87,7 @@ export const insert = ( const source = Builder.expression.indexSource(indexName, clusterName); if (index === -1) { - generic.appendCommandArgument(command, source); + generic.commands.args.append(command, source); } else { command.args.splice(index, 0, source); } diff --git a/packages/kbn-esql-ast/src/mutate/commands/index.ts b/packages/kbn-esql-ast/src/mutate/commands/index.ts index 0a779292e6eca..9e2599c493459 100644 --- a/packages/kbn-esql-ast/src/mutate/commands/index.ts +++ b/packages/kbn-esql-ast/src/mutate/commands/index.ts @@ -9,5 +9,6 @@ import * as from from './from'; import * as limit from './limit'; +import * as sort from './sort'; -export { from, limit }; +export { from, limit, sort }; diff --git a/packages/kbn-esql-ast/src/mutate/commands/limit/index.ts b/packages/kbn-esql-ast/src/mutate/commands/limit/index.ts index 937538e848328..f181a1d5f0cd4 100644 --- a/packages/kbn-esql-ast/src/mutate/commands/limit/index.ts +++ b/packages/kbn-esql-ast/src/mutate/commands/limit/index.ts @@ -19,7 +19,7 @@ import { Predicate } from '../../types'; * @returns A collection of "LIMIT" commands. */ export const list = (ast: ESQLAstQueryExpression): IterableIterator => { - return generic.listCommands(ast, (cmd) => cmd.name === 'limit'); + return generic.commands.list(ast, (cmd) => cmd.name === 'limit'); }; /** @@ -55,13 +55,13 @@ export const find = ( * @returns The removed "LIMIT" command, if any. */ export const remove = (ast: ESQLAstQueryExpression, index: number = 0): ESQLCommand | undefined => { - const command = generic.findCommandByName(ast, 'limit', index); + const command = generic.commands.findByName(ast, 'limit', index); if (!command) { return; } - const success = generic.removeCommand(ast, command); + const success = !!generic.commands.remove(ast, command); if (!success) { return; @@ -128,7 +128,7 @@ export const upsert = ( args: [literal], }); - generic.appendCommand(ast, command); + generic.commands.append(ast, command); return command; }; diff --git a/packages/kbn-esql-ast/src/mutate/commands/sort/index.test.ts b/packages/kbn-esql-ast/src/mutate/commands/sort/index.test.ts new file mode 100644 index 0000000000000..d04f79b96541a --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/commands/sort/index.test.ts @@ -0,0 +1,527 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { parse } from '../../../parser'; +import * as commands from '..'; +import { BasicPrettyPrinter } from '../../../pretty_print'; +import { Builder } from '../../../builder'; + +describe('commands.sort', () => { + describe('.listCommands()', () => { + it('returns empty array, if there are no sort commands', () => { + const src = 'FROM index METADATA a'; + const { root } = parse(src); + const list = [...commands.sort.listCommands(root)]; + + expect(list.length).toBe(0); + }); + + it('returns all sort commands', () => { + const src = + 'FROM index | SORT a ASC, b DESC, c | LIMIT 123 | SORT d | EVAL 1 | SORT e NULLS FIRST, f NULLS LAST'; + const { root } = parse(src); + const list = [...commands.sort.listCommands(root)]; + + expect(list.length).toBe(3); + }); + + it('can skip given number of sort commands', () => { + const src = + 'FROM index | SORT a ASC, b DESC, c | LIMIT 123 | SORT d | EVAL 1 | SORT e NULLS FIRST, f NULLS LAST'; + const { root } = parse(src); + const list1 = [...commands.sort.listCommands(root, 1)]; + const list2 = [...commands.sort.listCommands(root, 2)]; + const list3 = [...commands.sort.listCommands(root, 3)]; + const list4 = [...commands.sort.listCommands(root, 111)]; + + expect(list1.length).toBe(2); + expect(list2.length).toBe(1); + expect(list3.length).toBe(0); + expect(list4.length).toBe(0); + }); + }); + + describe('.list()', () => { + it('returns empty array, if there are no sort commands', () => { + const src = 'FROM index METADATA a'; + const { root } = parse(src); + const list = [...commands.sort.list(root)]; + + expect(list.length).toBe(0); + }); + + it('returns a single column expression', () => { + const src = 'FROM index | SORT a'; + const { root } = parse(src); + const list = [...commands.sort.list(root)].map(([node]) => node); + + expect(list.length).toBe(1); + expect(list[0]).toMatchObject({ + type: 'column', + name: 'a', + }); + }); + + it('returns a single order expression', () => { + const src = 'FROM index | SORT a ASC'; + const { root } = parse(src); + const list = [...commands.sort.list(root)].map(([node]) => node); + + expect(list.length).toBe(1); + expect(list[0]).toMatchObject({ + type: 'order', + args: [ + { + type: 'column', + name: 'a', + }, + ], + }); + }); + + it('returns all sort command expressions', () => { + const src = + 'FROM index | SORT a ASC, b DESC, c | LIMIT 123 | SORT d | EVAL 1 | SORT e NULLS FIRST, f NULLS LAST'; + const { root } = parse(src); + const list = [...commands.sort.list(root)].map(([node]) => node); + + expect(list).toMatchObject([ + { + type: 'order', + args: [ + { + type: 'column', + name: 'a', + }, + ], + }, + { + type: 'order', + args: [ + { + type: 'column', + name: 'b', + }, + ], + }, + { + type: 'column', + name: 'c', + }, + { + type: 'column', + name: 'd', + }, + { + type: 'order', + args: [ + { + type: 'column', + name: 'e', + }, + ], + }, + { + type: 'order', + args: [ + { + type: 'column', + name: 'f', + }, + ], + }, + ]); + }); + + it('can skip one order expression', () => { + const src = 'FROM index | SORT b DESC, a ASC'; + const { root } = parse(src); + const list = [...commands.sort.list(root, 1)].map(([node]) => node); + + expect(list.length).toBe(1); + expect(list[0]).toMatchObject({ + type: 'order', + args: [ + { + type: 'column', + name: 'a', + }, + ], + }); + }); + }); + + describe('.find()', () => { + it('returns undefined if sort expression is not found', () => { + const src = 'FROM index | WHERE a = b | LIMIT 123'; + const { root } = parse(src); + const node = commands.sort.find(root, 'abc'); + + expect(node).toBe(undefined); + }); + + it('can find a single sort expression', () => { + const src = 'FROM index | SORT a'; + const { root } = parse(src); + const [node] = commands.sort.find(root, 'a')!; + + expect(node).toMatchObject({ + type: 'column', + name: 'a', + }); + }); + + it('can find a single sort (order) expression', () => { + const src = 'FROM index | SORT b ASC'; + const { root } = parse(src); + const [node] = commands.sort.find(root, 'b')!; + + expect(node).toMatchObject({ + type: 'order', + args: [ + { + type: 'column', + name: 'b', + }, + ], + }); + }); + + it('can find a column and specific order expressions among other such expressions', () => { + const src = + 'FROM index | SORT a, b ASC | STATS agg() | SORT c DESC, d, e NULLS FIRST | LIMIT 10'; + const { root } = parse(src); + const [node1] = commands.sort.find(root, 'b')!; + const [node2] = commands.sort.find(root, 'd')!; + + expect(node1).toMatchObject({ + type: 'order', + args: [ + { + type: 'column', + name: 'b', + }, + ], + }); + expect(node2).toMatchObject({ + type: 'column', + name: 'd', + }); + }); + + it('can select second order expression with the same name', () => { + const src = 'FROM index | SORT b ASC | STATS agg() | SORT b DESC'; + const { root } = parse(src); + const [node] = commands.sort.find(root, 'b', 1)!; + + expect(node).toMatchObject({ + type: 'order', + order: 'DESC', + args: [ + { + type: 'column', + name: 'b', + }, + ], + }); + }); + + it('can find multipart columns', () => { + const src = 'FROM index | SORT hello, b.a ASC, a.b, c, c.d | STATS agg() | SORT b DESC'; + const { root } = parse(src); + const [node1] = commands.sort.find(root, ['b', 'a'])!; + const [node2] = commands.sort.find(root, ['a', 'b'])!; + + expect(node1).toMatchObject({ + type: 'order', + order: 'ASC', + args: [ + { + type: 'column', + parts: ['b', 'a'], + }, + ], + }); + expect(node2).toMatchObject({ + type: 'column', + parts: ['a', 'b'], + }); + }); + + it('returns the parent sort command of the found order expression', () => { + const src = 'FROM index | SORT hello, b.a ASC, a.b, c, c.d | STATS agg() | SORT b DESC'; + const { root } = parse(src); + const [node1, command1] = commands.sort.find(root, ['b', 'a'])!; + const [node2, command2] = commands.sort.find(root, ['a', 'b'])!; + + expect(command1).toBe(command2); + expect(!!command1.args.find((arg) => arg === node1)).toBe(true); + expect(!!command2.args.find((arg) => arg === node2)).toBe(true); + }); + }); + + describe('.remove()', () => { + it('can remove a column from a list', () => { + const src1 = 'FROM a, b, c | SORT a, b, c'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT a, b, c'); + + commands.sort.remove(root, 'b'); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT a, c'); + }); + + it('can remove an order expression from a list', () => { + const src1 = 'FROM a, b, c | SORT a, b ASC, c'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT a, b ASC, c'); + + commands.sort.remove(root, 'b'); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT a, c'); + }); + + it('does nothing if column does not exist', () => { + const src1 = 'FROM a, b, c | SORT a, c'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT a, c'); + + commands.sort.remove(root, 'b'); + commands.sort.remove(root, 'd'); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT a, c'); + }); + + it('can remove the sort expression at specific index', () => { + const src1 = 'FROM index | SORT a, b, c | LIMIT 1 | SORT a, b, c | LIMIT 2 | SORT a, b, c'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe( + 'FROM index | SORT a, b, c | LIMIT 1 | SORT a, b, c | LIMIT 2 | SORT a, b, c' + ); + + commands.sort.remove(root, 'a', 1); + commands.sort.remove(root, 'c', 1); + commands.sort.remove(root, 'b', 2); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM index | SORT a, b, c | LIMIT 1 | SORT b | LIMIT 2 | SORT a, c'); + }); + + it('removes SORT command, if it is left empty', () => { + const src1 = 'FROM index | SORT a, b, c | LIMIT 1 | SORT a, b, c | LIMIT 2 | SORT a, b, c'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe( + 'FROM index | SORT a, b, c | LIMIT 1 | SORT a, b, c | LIMIT 2 | SORT a, b, c' + ); + + commands.sort.remove(root, 'c', 1); + commands.sort.remove(root, 'b', 1); + commands.sort.remove(root, 'a', 1); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM index | SORT a, b, c | LIMIT 1 | LIMIT 2 | SORT a, b, c'); + }); + + it('can remove by matching parts', () => { + const src1 = 'FROM a, b, c | SORT a, b.c, d.e NULLS FIRST, e'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT a, b.c, d.e NULLS FIRST, e'); + + commands.sort.remove(root, ['b', 'c']); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT a, d.e NULLS FIRST, e'); + + commands.sort.remove(root, ['d', 'e']); + + const src4 = BasicPrettyPrinter.print(root); + + expect(src4).toBe('FROM a, b, c | SORT a, e'); + }); + }); + + describe('.insertIntoCommand()', () => { + it('can insert a sorting condition into the first existing SORT command', () => { + const src1 = 'FROM a, b, c | SORT s1, s2'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT s1, s2'); + + const command = commands.sort.getCommand(root)!; + commands.sort.insertIntoCommand(command, 's3'); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT s1, s2, s3'); + }); + + it('can prepend a sorting condition with options into the first existing SORT command', () => { + const src1 = 'FROM a, b, c | SORT s1, s2'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT s1, s2'); + + const command = commands.sort.getCommand(root)!; + commands.sort.insertIntoCommand( + command, + { parts: ['address', 'street🙃'], order: 'ASC', nulls: 'NULLS FIRST' }, + 0 + ); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT address.`street🙃` ASC NULLS FIRST, s1, s2'); + }); + + it('can insert a sorting condition into specific sorting command into specific position', () => { + const src1 = 'FROM a, b, c | SORT a1, a2 | SORT b1, /* HERE */ b3 | SORT c1, c2'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT a1, a2 | SORT b1, b3 | SORT c1, c2'); + + const command = commands.sort.getCommand(root, 1)!; + commands.sort.insertIntoCommand(command, 'b2', 1); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT a1, a2 | SORT b1, b2, b3 | SORT c1, c2'); + }); + }); + + describe('.insertExpression()', () => { + it('can insert a sorting condition into the first existing SORT command', () => { + const src1 = 'FROM a, b, c | SORT s1, s2'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT s1, s2'); + + commands.sort.insertExpression(root, 's3'); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT s1, s2, s3'); + }); + + it('can insert a sorting condition into specific sorting command into specific position', () => { + const src1 = 'FROM a, b, c | SORT a1, a2 | SORT b1, /* HERE */ b3 | SORT c1, c2'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT a1, a2 | SORT b1, b3 | SORT c1, c2'); + + commands.sort.insertExpression(root, 'b2', 1, 1); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT a1, a2 | SORT b1, b2, b3 | SORT c1, c2'); + }); + + it('when no positional arguments are provided append the column to the first SORT command', () => { + const src1 = 'FROM a, b, c | SORT a1, a2 | SORT b1, b2 | SORT c1, c2'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT a1, a2 | SORT b1, b2 | SORT c1, c2'); + + commands.sort.insertExpression(root, 'a3'); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT a1, a2, a3 | SORT b1, b2 | SORT c1, c2'); + }); + + it('when no SORT command found, inserts a new SORT command', () => { + const src1 = 'FROM a, b, c | LIMIT 10'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | LIMIT 10'); + + commands.sort.insertExpression(root, ['i18n', 'language', 'locale']); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | LIMIT 10 | SORT i18n.language.locale'); + }); + + it('can change the sorting order', () => { + const src1 = 'FROM a, b, c | SORT a ASC'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT a ASC'); + + commands.sort.insertExpression(root, { parts: 'a', order: 'DESC' }); + commands.sort.remove(root, 'a', 0); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT a DESC'); + }); + }); + + describe('.insertCommand()', () => { + it('can append a new SORT command', () => { + const src1 = 'FROM a, b, c | SORT s1, s2'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | SORT s1, s2'); + + commands.sort.insertCommand(root, 's3'); + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT s1, s2 | SORT s3'); + }); + + it('can insert a SORT command before a LIMIT command (and add a comment)', () => { + const src1 = 'FROM a, b, c | LIMIT 10'; + const { root } = parse(src1); + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM a, b, c | LIMIT 10'); + + const [_, column] = commands.sort.insertCommand(root, 'b', 1); + + column.formatting = { + right: [Builder.comment('multi-line', ' we sort by "b" ')], + }; + + const src3 = BasicPrettyPrinter.print(root); + + expect(src3).toBe('FROM a, b, c | SORT b /* we sort by "b" */ | LIMIT 10'); + }); + }); +}); diff --git a/packages/kbn-esql-ast/src/mutate/commands/sort/index.ts b/packages/kbn-esql-ast/src/mutate/commands/sort/index.ts new file mode 100644 index 0000000000000..d2b2c7cd5f3d4 --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/commands/sort/index.ts @@ -0,0 +1,313 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { Builder } from '../../../builder'; +import { + ESQLAstQueryExpression, + ESQLColumn, + ESQLCommand, + ESQLOrderExpression, +} from '../../../types'; +import { Visitor } from '../../../visitor'; +import { Predicate } from '../../types'; +import * as util from '../../util'; +import * as generic from '../../generic'; + +export type SortExpression = ESQLOrderExpression | ESQLColumn; + +/** + * This "template" allows the developer to easily specify a new sort expression + * AST node, for example: + * + * ```ts + * // as a simple string + * 'column_name' + * + * // column with nested fields + * ['column_name', 'nested_field'] + * + * // as an object with additional options + * { parts: 'column_name', order: 'ASC', nulls: 'NULLS FIRST' } + * { parts: ['column_name', 'nested_field'], order: 'DESC', nulls: 'NULLS LAST' } + * ``` + */ +export type NewSortExpressionTemplate = + | string + | string[] + | { + parts: string | string[]; + order?: ESQLOrderExpression['order']; + nulls?: ESQLOrderExpression['nulls']; + }; + +const createSortExpression = ( + template: string | string[] | NewSortExpressionTemplate +): SortExpression => { + const column = Builder.expression.column({ + parts: + typeof template === 'string' + ? [template] + : Array.isArray(template) + ? template + : typeof template.parts === 'string' + ? [template.parts] + : template.parts, + }); + + if (typeof template === 'string' || Array.isArray(template)) { + return column; + } + + const order = Builder.expression.order(column, { + order: template.order ?? '', + nulls: template.nulls ?? '', + }); + + return order; +}; + +/** + * Iterates through all sort commands starting from the beginning of the query. + * You can specify the `skip` parameter to skip a given number of sort commands. + * + * @param ast The root of the AST. + * @param skip Number of sort commands to skip. + * @returns Iterator through all sort commands. + */ +export const listCommands = ( + ast: ESQLAstQueryExpression, + skip: number = 0 +): IterableIterator => { + return new Visitor() + .on('visitSortCommand', function* (ctx): IterableIterator { + if (skip) { + skip--; + } else { + yield ctx.node; + } + }) + .on('visitCommand', function* (): IterableIterator {}) + .on('visitQuery', function* (ctx): IterableIterator { + for (const command of ctx.visitCommands()) { + yield* command; + } + }) + .visitQuery(ast); +}; + +/** + * Returns the Nth SORT command found in the query. + * + * @param ast The root of the AST. + * @param index The index (N) of the sort command to return. + * @returns The sort command found in the AST, if any. + */ +export const getCommand = ( + ast: ESQLAstQueryExpression, + index: number = 0 +): ESQLCommand | undefined => { + for (const command of listCommands(ast, index)) { + return command; + } +}; + +/** + * Returns an iterator for all sort expressions (columns and order expressions) + * in the query. You can specify the `skip` parameter to skip a given number of + * expressions. + * + * @param ast The root of the AST. + * @param skip Number of sort expressions to skip. + * @returns Iterator through sort expressions (columns and order expressions). + */ +export const list = ( + ast: ESQLAstQueryExpression, + skip: number = 0 +): IterableIterator<[sortExpression: SortExpression, sortCommand: ESQLCommand]> => { + return new Visitor() + .on('visitSortCommand', function* (ctx): IterableIterator<[SortExpression, ESQLCommand]> { + for (const argument of ctx.arguments()) { + if (argument.type === 'order' || argument.type === 'column') { + if (skip) { + skip--; + } else { + yield [argument, ctx.node]; + } + } + } + }) + .on('visitCommand', function* (): IterableIterator<[SortExpression, ESQLCommand]> {}) + .on('visitQuery', function* (ctx): IterableIterator<[SortExpression, ESQLCommand]> { + for (const command of ctx.visitCommands()) { + yield* command; + } + }) + .visitQuery(ast); +}; + +/** + * Finds the Nts sort expression that matches the predicate. + * + * @param ast The root of the AST. + * @param predicate A function that returns true if the sort expression matches + * the predicate. + * @param index The index of the sort expression to return. If not specified, + * the first sort expression that matches the predicate will be returned. + * @returns The sort expressions and sort command 2-tuple that matches the + * predicate, if any. + */ +export const findByPredicate = ( + ast: ESQLAstQueryExpression, + predicate: Predicate<[sortExpression: SortExpression, sortCommand: ESQLCommand]>, + index?: number +): [sortExpression: SortExpression, sortCommand: ESQLCommand] | undefined => { + return util.findByPredicate(list(ast, index), predicate); +}; + +/** + * Finds the Nth sort expression that matches the sort expression by column + * name. The `parts` argument allows to specify an array of nested field names. + * + * @param ast The root of the AST. + * @param parts A string or an array of strings representing the column name. + * @returns The sort expressions and sort command 2-tuple that matches the + * predicate, if any. + */ +export const find = ( + ast: ESQLAstQueryExpression, + parts: string | string[], + index: number = 0 +): [sortExpression: SortExpression, sortCommand: ESQLCommand] | undefined => { + const arrParts = typeof parts === 'string' ? [parts] : parts; + + return findByPredicate(ast, ([node]) => { + let isMatch = false; + if (node.type === 'column') { + isMatch = util.cmpArr(node.parts, arrParts); + } else if (node.type === 'order') { + const columnParts = (node.args[0] as ESQLColumn)?.parts; + + if (Array.isArray(columnParts)) { + isMatch = util.cmpArr(columnParts, arrParts); + } + } + + if (isMatch) { + index--; + if (index < 0) { + return true; + } + } + + return false; + }); +}; + +/** + * Removes the Nth sort expression that matches the sort expression by column + * name. The `parts` argument allows to specify an array of nested field names. + * + * @param ast The root of the AST. + * @param parts A string or an array of strings representing the column name. + * @param index The index of the sort expression to remove. + * @returns The sort expressions and sort command 2-tuple that was removed, if any. + */ +export const remove = ( + ast: ESQLAstQueryExpression, + parts: string | string[], + index?: number +): [sortExpression: SortExpression, sortCommand: ESQLCommand] | undefined => { + const tuple = find(ast, parts, index); + + if (!tuple) { + return undefined; + } + + const [node] = tuple; + const cmd = generic.commands.args.remove(ast, node); + + if (cmd) { + if (!cmd.args.length) { + generic.commands.remove(ast, cmd); + } + } + + return cmd ? tuple : undefined; +}; + +/** + * Inserts a new sort expression into the specified SORT command at the + * specified argument position. + * + * @param sortCommand The SORT command to insert the new sort expression into. + * @param template The sort expression template. + * @param index Argument position in the command argument list. + * @returns The inserted sort expression. + */ +export const insertIntoCommand = ( + sortCommand: ESQLCommand, + template: NewSortExpressionTemplate, + index?: number +): SortExpression => { + const expression = createSortExpression(template); + + generic.commands.args.insert(sortCommand, expression, index); + + return expression; +}; + +/** + * Creates a new sort expression node and inserts it into the specified SORT + * command at the specified argument position. If not sort command is found, a + * new one is created and appended to the end of the query. + * + * @param ast The root AST node. + * @param parts ES|QL column name parts. + * @param index The new column name position in command argument list. + * @param sortCommandIndex The index of the SORT command in the AST. E.g. 0 is the + * first SORT command in the AST. + * @returns The inserted column AST node. + */ +export const insertExpression = ( + ast: ESQLAstQueryExpression, + template: NewSortExpressionTemplate, + index: number = -1, + sortCommandIndex: number = 0 +): SortExpression => { + let command: ESQLCommand | undefined = getCommand(ast, sortCommandIndex); + + if (!command) { + command = Builder.command({ name: 'sort' }); + generic.commands.append(ast, command); + } + + return insertIntoCommand(command, template, index); +}; + +/** + * Inserts a new SORT command with a single sort expression as its sole argument. + * You can specify the position to insert the command at. + * + * @param ast The root of the AST. + * @param template The sort expression template. + * @param index The position to insert the sort expression at. + * @returns The inserted sort expression and the command it was inserted into. + */ +export const insertCommand = ( + ast: ESQLAstQueryExpression, + template: NewSortExpressionTemplate, + index: number = -1 +): [ESQLCommand, SortExpression] => { + const expression = createSortExpression(template); + const command = Builder.command({ name: 'sort', args: [expression] }); + + generic.commands.insert(ast, command, index); + + return [command, expression]; +}; diff --git a/packages/kbn-esql-ast/src/mutate/generic.ts b/packages/kbn-esql-ast/src/mutate/generic.ts deleted file mode 100644 index f27b0e2ae399f..0000000000000 --- a/packages/kbn-esql-ast/src/mutate/generic.ts +++ /dev/null @@ -1,287 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { isOptionNode } from '../ast/util'; -import { Builder } from '../builder'; -import { - ESQLAstQueryExpression, - ESQLCommand, - ESQLCommandOption, - ESQLProperNode, - ESQLSingleAstItem, -} from '../types'; -import { Visitor } from '../visitor'; -import { Predicate } from './types'; - -/** - * Returns an iterator for all command AST nodes in the query. If a predicate is - * provided, only commands that satisfy the predicate will be returned. - * - * @param ast Root AST node to search for commands. - * @param predicate Optional predicate to filter commands. - * @returns A list of commands found in the AST. - */ -export const listCommands = ( - ast: ESQLAstQueryExpression, - predicate?: Predicate -): IterableIterator => { - return new Visitor() - .on('visitQuery', function* (ctx): IterableIterator { - for (const cmd of ctx.commands()) { - if (!predicate || predicate(cmd)) { - yield cmd; - } - } - }) - .visitQuery(ast); -}; - -/** - * Returns the first command AST node at a given index in the query that - * satisfies the predicate. If no index is provided, the first command found - * will be returned. - * - * @param ast Root AST node to search for commands. - * @param predicate Optional predicate to filter commands. - * @param index The index of the command to return. - * @returns The command found in the AST, if any. - */ -export const findCommand = ( - ast: ESQLAstQueryExpression, - predicate?: Predicate, - index: number = 0 -): ESQLCommand | undefined => { - for (const cmd of listCommands(ast, predicate)) { - if (!index) { - return cmd; - } - - index--; - } - - return undefined; -}; - -/** - * Returns the first command option AST node that satisfies the predicate. - * - * @param command The command AST node to search for options. - * @param predicate The predicate to filter options. - * @returns The option found in the command, if any. - */ -export const findCommandOption = ( - command: ESQLCommand, - predicate: Predicate -): ESQLCommandOption | undefined => { - return new Visitor() - .on('visitCommand', (ctx): ESQLCommandOption | undefined => { - for (const opt of ctx.options()) { - if (predicate(opt)) { - return opt; - } - } - - return undefined; - }) - .visitCommand(command); -}; - -/** - * Returns the first command AST node at a given index with a given name in the - * query. If no index is provided, the first command found will be returned. - * - * @param ast Root AST node to search for commands. - * @param commandName The name of the command to find. - * @param index The index of the command to return. - * @returns The command found in the AST, if any. - */ -export const findCommandByName = ( - ast: ESQLAstQueryExpression, - commandName: string, - index: number = 0 -): ESQLCommand | undefined => { - return findCommand(ast, (cmd) => cmd.name === commandName, index); -}; - -/** - * Returns the first command option AST node with a given name in the query. - * - * @param ast The root AST node to search for command options. - * @param commandName Command name to search for. - * @param optionName Option name to search for. - * @returns The option found in the command, if any. - */ -export const findCommandOptionByName = ( - ast: ESQLAstQueryExpression, - commandName: string, - optionName: string -): ESQLCommandOption | undefined => { - const command = findCommand(ast, (cmd) => cmd.name === commandName); - - if (!command) { - return undefined; - } - - return findCommandOption(command, (opt) => opt.name === optionName); -}; - -/** - * Adds a new command to the query AST node. - * - * @param ast The root AST node to append the command to. - * @param command The command AST node to append. - */ -export const appendCommand = (ast: ESQLAstQueryExpression, command: ESQLCommand): void => { - ast.commands.push(command); -}; - -/** - * Inserts a command option into the command's arguments list. The option can - * be specified as a string or an AST node. - * - * @param command The command AST node to insert the option into. - * @param option The option to insert. - * @returns The inserted option. - */ -export const appendCommandOption = ( - command: ESQLCommand, - option: string | ESQLCommandOption -): ESQLCommandOption => { - if (typeof option === 'string') { - option = Builder.option({ name: option }); - } - - command.args.push(option); - - return option; -}; - -export const appendCommandArgument = ( - command: ESQLCommand, - expression: ESQLSingleAstItem -): number => { - if (expression.type === 'option') { - command.args.push(expression); - return command.args.length - 1; - } - - const index = command.args.findIndex((arg) => isOptionNode(arg)); - - if (index > -1) { - command.args.splice(index, 0, expression); - return index; - } - - command.args.push(expression); - return command.args.length - 1; -}; - -export const removeCommand = (ast: ESQLAstQueryExpression, command: ESQLCommand): boolean => { - const cmds = ast.commands; - const length = cmds.length; - - for (let i = 0; i < length; i++) { - if (cmds[i] === command) { - cmds.splice(i, 1); - return true; - } - } - - return false; -}; - -/** - * Removes the first command option from the command's arguments list that - * satisfies the predicate. - * - * @param command The command AST node to remove the option from. - * @param predicate The predicate to filter options. - * @returns The removed option, if any. - */ -export const removeCommandOption = ( - ast: ESQLAstQueryExpression, - option: ESQLCommandOption -): boolean => { - return new Visitor() - .on('visitCommandOption', (ctx): boolean => { - return ctx.node === option; - }) - .on('visitCommand', (ctx): boolean => { - let target: undefined | ESQLCommandOption; - - for (const opt of ctx.options()) { - if (opt === option) { - target = opt; - break; - } - } - - if (!target) { - return false; - } - - const index = ctx.node.args.indexOf(target); - - if (index === -1) { - return false; - } - - ctx.node.args.splice(index, 1); - - return true; - }) - .on('visitQuery', (ctx): boolean => { - for (const success of ctx.visitCommands()) { - if (success) { - return true; - } - } - - return false; - }) - .visitQuery(ast); -}; - -/** - * Searches all command arguments in the query AST node and removes the node - * from the command's arguments list. - * - * @param ast The root AST node to search for command arguments. - * @param node The argument AST node to remove. - * @returns Returns true if the argument was removed, false otherwise. - */ -export const removeCommandArgument = ( - ast: ESQLAstQueryExpression, - node: ESQLProperNode -): boolean => { - return new Visitor() - .on('visitCommand', (ctx): boolean => { - const args = ctx.node.args; - const length = args.length; - - for (let i = 0; i < length; i++) { - if (args[i] === node) { - args.splice(i, 1); - return true; - } - } - - return false; - }) - .on('visitQuery', (ctx): boolean => { - for (const success of ctx.visitCommands()) { - if (success) { - return true; - } - } - - return false; - }) - .visitQuery(ast); -}; diff --git a/packages/kbn-esql-ast/src/mutate/generic/commands/args/index.test.ts b/packages/kbn-esql-ast/src/mutate/generic/commands/args/index.test.ts new file mode 100644 index 0000000000000..e687c4528dd7d --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/generic/commands/args/index.test.ts @@ -0,0 +1,132 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { Builder } from '../../../../builder'; +import { parse } from '../../../../parser'; +import { BasicPrettyPrinter } from '../../../../pretty_print'; +import * as generic from '../..'; + +describe('generic.commands.args', () => { + describe('.insert()', () => { + it('can insert at the end of the list', () => { + const src = 'FROM index | LIMIT 10'; + const { root } = parse(src); + const command = generic.commands.findByName(root, 'from', 0); + + generic.commands.args.insert( + command!, + Builder.expression.source({ name: 'test', sourceType: 'index' }), + 123 + ); + + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM index, test | LIMIT 10'); + }); + + it('can insert at the beginning of the list', () => { + const src = 'FROM index | LIMIT 10'; + const { root } = parse(src); + const command = generic.commands.findByName(root, 'from', 0); + + generic.commands.args.insert( + command!, + Builder.expression.source({ name: 'test', sourceType: 'index' }), + 0 + ); + + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM test, index | LIMIT 10'); + }); + + it('can insert in the middle of the list', () => { + const src = 'FROM index1, index2 | LIMIT 10'; + const { root } = parse(src); + const command = generic.commands.findByName(root, 'from', 0); + + generic.commands.args.insert( + command!, + Builder.expression.source({ name: 'test', sourceType: 'index' }), + 1 + ); + + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM index1, test, index2 | LIMIT 10'); + }); + + describe('with option present', () => { + it('can insert at the end of the list', () => { + const src = 'FROM index METADATA _id | LIMIT 10'; + const { root } = parse(src); + const command = generic.commands.findByName(root, 'from', 0); + + generic.commands.args.insert( + command!, + Builder.expression.source({ name: 'test', sourceType: 'index' }), + 123 + ); + + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM index, test METADATA _id | LIMIT 10'); + }); + + it('can insert at the beginning of the list', () => { + const src = 'FROM index METADATA _id | LIMIT 10'; + const { root } = parse(src); + const command = generic.commands.findByName(root, 'from', 0); + + generic.commands.args.insert( + command!, + Builder.expression.source({ name: 'test', sourceType: 'index' }), + 0 + ); + + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM test, index METADATA _id | LIMIT 10'); + }); + + it('can insert in the middle of the list', () => { + const src = 'FROM index1, index2 METADATA _id | LIMIT 10'; + const { root } = parse(src); + const command = generic.commands.findByName(root, 'from', 0); + + generic.commands.args.insert( + command!, + Builder.expression.source({ name: 'test', sourceType: 'index' }), + 1 + ); + + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM index1, test, index2 METADATA _id | LIMIT 10'); + }); + }); + }); + + describe('.append()', () => { + it('can append and argument', () => { + const src = 'FROM index METADATA _id | LIMIT 10'; + const { root } = parse(src); + const command = generic.commands.findByName(root, 'from', 0); + + generic.commands.args.append( + command!, + Builder.expression.source({ name: 'test', sourceType: 'index' }) + ); + + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM index, test METADATA _id | LIMIT 10'); + }); + }); +}); diff --git a/packages/kbn-esql-ast/src/mutate/generic/commands/args/index.ts b/packages/kbn-esql-ast/src/mutate/generic/commands/args/index.ts new file mode 100644 index 0000000000000..7072c38a5f1a8 --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/generic/commands/args/index.ts @@ -0,0 +1,86 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { isOptionNode } from '../../../../ast/util'; +import { + ESQLAstQueryExpression, + ESQLCommand, + ESQLProperNode, + ESQLSingleAstItem, +} from '../../../../types'; +import { Visitor } from '../../../../visitor'; + +export const insert = ( + command: ESQLCommand, + expression: ESQLSingleAstItem, + index: number = -1 +): number => { + if (expression.type === 'option') { + command.args.push(expression); + return command.args.length - 1; + } + + let mainArgumentCount = command.args.findIndex((arg) => isOptionNode(arg)); + + if (mainArgumentCount < 0) { + mainArgumentCount = command.args.length; + } + if (index === -1) { + index = mainArgumentCount; + } + if (index > mainArgumentCount) { + index = mainArgumentCount; + } + + command.args.splice(index, 0, expression); + + return mainArgumentCount + 1; +}; + +export const append = (command: ESQLCommand, expression: ESQLSingleAstItem): number => { + return insert(command, expression, -1); +}; + +/** + * Searches all command arguments in the query AST node and removes the node + * from the command's arguments list. + * + * @param ast The root AST node to search for command arguments. + * @param node The argument AST node to remove. + * @returns Returns the command that the argument was removed from, if any. + */ +export const remove = ( + ast: ESQLAstQueryExpression, + node: ESQLProperNode +): ESQLCommand | undefined => { + return new Visitor() + .on('visitCommand', (ctx): ESQLCommand | undefined => { + const args = ctx.node.args; + const length = args.length; + + for (let i = 0; i < length; i++) { + if (args[i] === node) { + args.splice(i, 1); + return ctx.node; + } + } + + return undefined; + }) + .on('visitQuery', (ctx): ESQLCommand | undefined => { + for (const cmd of ctx.visitCommands()) { + if (cmd) { + return cmd; + } + } + + return undefined; + }) + .visitQuery(ast); +}; diff --git a/packages/kbn-esql-ast/src/mutate/generic.test.ts b/packages/kbn-esql-ast/src/mutate/generic/commands/index.test.ts similarity index 54% rename from packages/kbn-esql-ast/src/mutate/generic.test.ts rename to packages/kbn-esql-ast/src/mutate/generic/commands/index.test.ts index 0109ff838ffda..b35d0b6415247 100644 --- a/packages/kbn-esql-ast/src/mutate/generic.test.ts +++ b/packages/kbn-esql-ast/src/mutate/generic/commands/index.test.ts @@ -7,26 +7,26 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { parse } from '../parser'; -import { BasicPrettyPrinter } from '../pretty_print'; -import * as generic from './generic'; +import { parse } from '../../../parser'; +import { BasicPrettyPrinter } from '../../../pretty_print'; +import * as generic from '..'; -describe('generic', () => { - describe('.listCommands()', () => { +describe('generic.commands', () => { + describe('.list()', () => { it('lists all commands', () => { const src = 'FROM index | WHERE a == b | LIMIT 123'; const { root } = parse(src); - const commands = [...generic.listCommands(root)].map((cmd) => cmd.name); + const commands = [...generic.commands.list(root)].map((cmd) => cmd.name); expect(commands).toEqual(['from', 'where', 'limit']); }); }); - describe('.findCommand()', () => { + describe('.find()', () => { it('can the first command', () => { const src = 'FROM index | WHERE a == b | LIMIT 123'; const { root } = parse(src); - const command = generic.findCommand(root, (cmd) => cmd.name === 'from'); + const command = generic.commands.find(root, (cmd) => cmd.name === 'from'); expect(command).toMatchObject({ type: 'command', @@ -42,7 +42,7 @@ describe('generic', () => { it('can the last command', () => { const src = 'FROM index | WHERE a == b | LIMIT 123'; const { root } = parse(src); - const command = generic.findCommand(root, (cmd) => cmd.name === 'limit'); + const command = generic.commands.find(root, (cmd) => cmd.name === 'limit'); expect(command).toMatchObject({ type: 'command', @@ -58,7 +58,7 @@ describe('generic', () => { it('find the specific of multiple commands', () => { const src = 'FROM index | WHERE a == b | LIMIT 1 | LIMIT 2 | LIMIT 3'; const { root } = parse(src); - const command = generic.findCommand( + const command = generic.commands.find( root, (cmd) => cmd.name === 'limit' && (cmd.args?.[0] as any).value === 2 ); @@ -76,34 +76,13 @@ describe('generic', () => { }); }); - describe('.findCommandOptionByName()', () => { - it('can the find a command option', () => { - const src = 'FROM index METADATA _score'; - const { root } = parse(src); - const option = generic.findCommandOptionByName(root, 'from', 'metadata'); - - expect(option).toMatchObject({ - type: 'option', - name: 'metadata', - }); - }); - - it('returns undefined if there is no option', () => { - const src = 'FROM index'; - const { root } = parse(src); - const option = generic.findCommandOptionByName(root, 'from', 'metadata'); - - expect(option).toBe(undefined); - }); - }); - - describe('.removeCommand()', () => { + describe('.remove()', () => { it('can remove the last command', () => { const src = 'FROM index | LIMIT 10'; const { root } = parse(src); - const command = generic.findCommandByName(root, 'limit', 0); + const command = generic.commands.findByName(root, 'limit', 0); - generic.removeCommand(root, command!); + generic.commands.remove(root, command!); const src2 = BasicPrettyPrinter.print(root); @@ -113,9 +92,9 @@ describe('generic', () => { it('can remove the second command out of 3 with the same name', () => { const src = 'FROM index | LIMIT 1 | LIMIT 2 | LIMIT 3'; const { root } = parse(src); - const command = generic.findCommandByName(root, 'limit', 1); + const command = generic.commands.findByName(root, 'limit', 1); - generic.removeCommand(root, command!); + generic.commands.remove(root, command!); const src2 = BasicPrettyPrinter.print(root); @@ -125,29 +104,15 @@ describe('generic', () => { it('can remove all commands', () => { const src = 'FROM index | WHERE a == b | LIMIT 123'; const { root } = parse(src); - const cmd1 = generic.findCommandByName(root, 'where'); - const cmd2 = generic.findCommandByName(root, 'limit'); - const cmd3 = generic.findCommandByName(root, 'from'); + const cmd1 = generic.commands.findByName(root, 'where'); + const cmd2 = generic.commands.findByName(root, 'limit'); + const cmd3 = generic.commands.findByName(root, 'from'); - generic.removeCommand(root, cmd1!); - generic.removeCommand(root, cmd2!); - generic.removeCommand(root, cmd3!); + generic.commands.remove(root, cmd1!); + generic.commands.remove(root, cmd2!); + generic.commands.remove(root, cmd3!); expect(root.commands.length).toBe(0); }); }); - - describe('.removeCommandOption()', () => { - it('can remove existing command option', () => { - const src = 'FROM index METADATA _score'; - const { root } = parse(src); - const option = generic.findCommandOptionByName(root, 'from', 'metadata'); - - generic.removeCommandOption(root, option!); - - const src2 = BasicPrettyPrinter.print(root); - - expect(src2).toBe('FROM index'); - }); - }); }); diff --git a/packages/kbn-esql-ast/src/mutate/generic/commands/index.ts b/packages/kbn-esql-ast/src/mutate/generic/commands/index.ts new file mode 100644 index 0000000000000..0582bb592edb8 --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/generic/commands/index.ts @@ -0,0 +1,131 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { ESQLAstQueryExpression, ESQLCommand } from '../../../types'; +import { Visitor } from '../../../visitor'; +import { Predicate } from '../../types'; + +export * as args from './args'; +export * as options from './options'; + +/** + * Returns an iterator for all command AST nodes in the query. If a predicate is + * provided, only commands that satisfy the predicate will be returned. + * + * @param ast Root AST node to search for commands. + * @param predicate Optional predicate to filter commands. + * @returns A list of commands found in the AST. + */ +export const list = ( + ast: ESQLAstQueryExpression, + predicate?: Predicate +): IterableIterator => { + return new Visitor() + .on('visitQuery', function* (ctx): IterableIterator { + for (const cmd of ctx.commands()) { + if (!predicate || predicate(cmd)) { + yield cmd; + } + } + }) + .visitQuery(ast); +}; + +/** + * Returns the first command AST node at a given index in the query that + * satisfies the predicate. If no index is provided, the first command found + * will be returned. + * + * @param ast Root AST node to search for commands. + * @param predicate Optional predicate to filter commands. + * @param index The index of the command to return. + * @returns The command found in the AST, if any. + */ +export const find = ( + ast: ESQLAstQueryExpression, + predicate?: Predicate, + index: number = 0 +): ESQLCommand | undefined => { + for (const cmd of list(ast, predicate)) { + if (!index) { + return cmd; + } + + index--; + } + + return undefined; +}; + +/** + * Returns the first command AST node at a given index with a given name in the + * query. If no index is provided, the first command found will be returned. + * + * @param ast Root AST node to search for commands. + * @param commandName The name of the command to find. + * @param index The index of the command to return. + * @returns The command found in the AST, if any. + */ +export const findByName = ( + ast: ESQLAstQueryExpression, + commandName: string, + index: number = 0 +): ESQLCommand | undefined => { + return find(ast, (cmd) => cmd.name === commandName, index); +}; + +/** + * Inserts a new command into the query AST node at the specified index. If the + * `index` is out of bounds, the command will be appended to the end of the + * command list. + * + * @param ast The root AST node. + * @param command The command AST node to insert. + * @param index The index to insert the command at. + * @returns The index the command was inserted at. + */ +export const insert = ( + ast: ESQLAstQueryExpression, + command: ESQLCommand, + index: number = Infinity +): number => { + const commands = ast.commands; + + if (index > commands.length || index < 0) { + index = commands.length; + } + + commands.splice(index, 0, command); + + return index; +}; + +/** + * Adds a new command to the query AST node. + * + * @param ast The root AST node to append the command to. + * @param command The command AST node to append. + */ +export const append = (ast: ESQLAstQueryExpression, command: ESQLCommand): void => { + ast.commands.push(command); +}; + +export const remove = (ast: ESQLAstQueryExpression, command: ESQLCommand): boolean => { + const cmds = ast.commands; + const length = cmds.length; + + for (let i = 0; i < length; i++) { + if (cmds[i] === command) { + cmds.splice(i, 1); + return true; + } + } + + return false; +}; diff --git a/packages/kbn-esql-ast/src/mutate/generic/commands/options/index.test.ts b/packages/kbn-esql-ast/src/mutate/generic/commands/options/index.test.ts new file mode 100644 index 0000000000000..00c3ee90eccdd --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/generic/commands/options/index.test.ts @@ -0,0 +1,49 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { parse } from '../../../../parser'; +import { BasicPrettyPrinter } from '../../../../pretty_print'; +import * as generic from '../..'; + +describe('generic.commands.options', () => { + describe('.findByName()', () => { + it('can the find a command option', () => { + const src = 'FROM index METADATA _score'; + const { root } = parse(src); + const option = generic.commands.options.findByName(root, 'from', 'metadata'); + + expect(option).toMatchObject({ + type: 'option', + name: 'metadata', + }); + }); + + it('returns undefined if there is no option', () => { + const src = 'FROM index'; + const { root } = parse(src); + const option = generic.commands.options.findByName(root, 'from', 'metadata'); + + expect(option).toBe(undefined); + }); + }); + + describe('.remove()', () => { + it('can remove existing command option', () => { + const src = 'FROM index METADATA _score'; + const { root } = parse(src); + const option = generic.commands.options.findByName(root, 'from', 'metadata'); + + generic.commands.options.remove(root, option!); + + const src2 = BasicPrettyPrinter.print(root); + + expect(src2).toBe('FROM index'); + }); + }); +}); diff --git a/packages/kbn-esql-ast/src/mutate/generic/commands/options/index.ts b/packages/kbn-esql-ast/src/mutate/generic/commands/options/index.ts new file mode 100644 index 0000000000000..b9b2bac452e31 --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/generic/commands/options/index.ts @@ -0,0 +1,130 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { Builder } from '../../../../builder'; +import { ESQLAstQueryExpression, ESQLCommand, ESQLCommandOption } from '../../../../types'; +import { Visitor } from '../../../../visitor'; +import { Predicate } from '../../../types'; +import * as commands from '..'; + +/** + * Returns the first command option AST node that satisfies the predicate. + * + * @param command The command AST node to search for options. + * @param predicate The predicate to filter options. + * @returns The option found in the command, if any. + */ +export const find = ( + command: ESQLCommand, + predicate: Predicate +): ESQLCommandOption | undefined => { + return new Visitor() + .on('visitCommand', (ctx): ESQLCommandOption | undefined => { + for (const opt of ctx.options()) { + if (predicate(opt)) { + return opt; + } + } + + return undefined; + }) + .visitCommand(command); +}; + +/** + * Returns the first command option AST node with a given name in the query. + * + * @param ast The root AST node to search for command options. + * @param commandName Command name to search for. + * @param optionName Option name to search for. + * @returns The option found in the command, if any. + */ +export const findByName = ( + ast: ESQLAstQueryExpression, + commandName: string, + optionName: string +): ESQLCommandOption | undefined => { + const command = commands.find(ast, (cmd) => cmd.name === commandName); + + if (!command) { + return undefined; + } + + return find(command, (opt) => opt.name === optionName); +}; + +/** + * Inserts a command option into the command's arguments list. The option can + * be specified as a string or an AST node. + * + * @param command The command AST node to insert the option into. + * @param option The option to insert. + * @returns The inserted option. + */ +export const append = ( + command: ESQLCommand, + option: string | ESQLCommandOption +): ESQLCommandOption => { + if (typeof option === 'string') { + option = Builder.option({ name: option }); + } + + command.args.push(option); + + return option; +}; + +/** + * Removes the first command option from the command's arguments list that + * satisfies the predicate. + * + * @param command The command AST node to remove the option from. + * @param predicate The predicate to filter options. + * @returns The removed option, if any. + */ +export const remove = (ast: ESQLAstQueryExpression, option: ESQLCommandOption): boolean => { + return new Visitor() + .on('visitCommandOption', (ctx): boolean => { + return ctx.node === option; + }) + .on('visitCommand', (ctx): boolean => { + let target: undefined | ESQLCommandOption; + + for (const opt of ctx.options()) { + if (opt === option) { + target = opt; + break; + } + } + + if (!target) { + return false; + } + + const index = ctx.node.args.indexOf(target); + + if (index === -1) { + return false; + } + + ctx.node.args.splice(index, 1); + + return true; + }) + .on('visitQuery', (ctx): boolean => { + for (const success of ctx.visitCommands()) { + if (success) { + return true; + } + } + + return false; + }) + .visitQuery(ast); +}; diff --git a/packages/kbn-esql-ast/src/mutate/generic/index.ts b/packages/kbn-esql-ast/src/mutate/generic/index.ts new file mode 100644 index 0000000000000..e7f26b9340af7 --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/generic/index.ts @@ -0,0 +1,10 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export * as commands from './commands'; diff --git a/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts index 9d822f78f9333..d05ed36204b17 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts @@ -69,6 +69,103 @@ describe('function AST nodes', () => { }, ]); }); + + it('parses out function name as identifier node', () => { + const query = 'ROW fn(1, 2, 3)'; + const { ast, errors } = parse(query); + + expect(errors.length).toBe(0); + expect(ast).toMatchObject([ + { + type: 'command', + name: 'row', + args: [ + { + type: 'function', + name: 'fn', + operator: { + type: 'identifier', + name: 'fn', + }, + }, + ], + }, + ]); + }); + + it('parses out function name as named param', () => { + const query = 'ROW ?insert_here(1, 2, 3)'; + const { ast, errors } = parse(query); + + expect(errors.length).toBe(0); + expect(ast).toMatchObject([ + { + type: 'command', + name: 'row', + args: [ + { + type: 'function', + name: '?insert_here', + operator: { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'insert_here', + }, + }, + ], + }, + ]); + }); + + it('parses out function name as unnamed param', () => { + const query = 'ROW ?(1, 2, 3)'; + const { ast, errors } = parse(query); + + expect(errors.length).toBe(0); + expect(ast).toMatchObject([ + { + type: 'command', + name: 'row', + args: [ + { + type: 'function', + name: '?', + operator: { + type: 'literal', + literalType: 'param', + paramType: 'unnamed', + }, + }, + ], + }, + ]); + }); + + it('parses out function name as positional param', () => { + const query = 'ROW ?30035(1, 2, 3)'; + const { ast, errors } = parse(query); + + expect(errors.length).toBe(0); + expect(ast).toMatchObject([ + { + type: 'command', + name: 'row', + args: [ + { + type: 'function', + name: '?30035', + operator: { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: 30035, + }, + }, + ], + }, + ]); + }); }); describe('"unary-expression"', () => { diff --git a/packages/kbn-esql-ast/src/parser/factories.ts b/packages/kbn-esql-ast/src/parser/factories.ts index 0fffb3a970e4c..b575447f7e744 100644 --- a/packages/kbn-esql-ast/src/parser/factories.ts +++ b/packages/kbn-esql-ast/src/parser/factories.ts @@ -11,7 +11,13 @@ * In case of changes in the grammar, this script should be updated: esql_update_ast_script.js */ -import type { Token, ParserRuleContext, TerminalNode, RecognitionException } from 'antlr4'; +import type { + Token, + ParserRuleContext, + TerminalNode, + RecognitionException, + ParseTree, +} from 'antlr4'; import { IndexPatternContext, QualifiedNameContext, @@ -21,6 +27,10 @@ import { type IntegerValueContext, type QualifiedIntegerLiteralContext, QualifiedNamePatternContext, + FunctionContext, + IdentifierContext, + InputParamContext, + InputNamedOrPositionalParamContext, } from '../antlr/esql_parser'; import { DOUBLE_TICKS_REGEX, SINGLE_BACKTICK, TICKS_REGEX } from './constants'; import type { @@ -42,6 +52,8 @@ import type { ESQLNumericLiteral, ESQLOrderExpression, InlineCastingType, + ESQLFunctionCallExpression, + ESQLIdentifier, } from '../types'; import { parseIdentifier, getPosition } from './helpers'; import { Builder, type AstNodeParserFields } from '../builder'; @@ -201,22 +213,71 @@ export function createFunction( return node; } +export const createFunctionCall = (ctx: FunctionContext): ESQLFunctionCallExpression => { + const functionExpressionCtx = ctx.functionExpression(); + const functionName = functionExpressionCtx.functionName(); + const node: ESQLFunctionCallExpression = { + type: 'function', + subtype: 'variadic-call', + name: functionName.getText().toLowerCase(), + text: ctx.getText(), + location: getPosition(ctx.start, ctx.stop), + args: [], + incomplete: Boolean(ctx.exception), + }; + + const identifierOrParameter = functionName.identifierOrParameter(); + if (identifierOrParameter) { + const identifier = identifierOrParameter.identifier(); + if (identifier) { + node.operator = createIdentifier(identifier); + } else { + const parameter = identifierOrParameter.parameter(); + if (parameter) { + node.operator = createParam(parameter); + } + } + } + + return node; +}; + +const createIdentifier = (identifier: IdentifierContext): ESQLIdentifier => { + return Builder.identifier( + { name: identifier.getText().toLowerCase() }, + createParserFields(identifier) + ); +}; + +export const createParam = (ctx: ParseTree) => { + if (ctx instanceof InputParamContext) { + return Builder.param.unnamed(createParserFields(ctx)); + } else if (ctx instanceof InputNamedOrPositionalParamContext) { + const text = ctx.getText(); + const value = text.slice(1); + const valueAsNumber = Number(value); + const isPositional = String(valueAsNumber) === value; + const parserFields = createParserFields(ctx); + + if (isPositional) { + return Builder.param.positional({ value: valueAsNumber }, parserFields); + } else { + return Builder.param.named({ value }, parserFields); + } + } +}; + export const createOrderExpression = ( ctx: ParserRuleContext, - arg: ESQLAstItem, + arg: ESQLColumn, order: ESQLOrderExpression['order'], nulls: ESQLOrderExpression['nulls'] ) => { - const node: ESQLOrderExpression = { - type: 'order', - name: '', - order, - nulls, - args: [arg], - text: ctx.getText(), - location: getPosition(ctx.start, ctx.stop), - incomplete: Boolean(ctx.exception), - }; + const node = Builder.expression.order( + arg as ESQLColumn, + { order, nulls }, + createParserFields(ctx) + ); return node; }; diff --git a/packages/kbn-esql-ast/src/parser/formatting.ts b/packages/kbn-esql-ast/src/parser/formatting.ts index 492e8a76ddeac..f7c556da63008 100644 --- a/packages/kbn-esql-ast/src/parser/formatting.ts +++ b/packages/kbn-esql-ast/src/parser/formatting.ts @@ -173,6 +173,10 @@ const attachCommentDecoration = ( ) => { const commentConsumesWholeLine = !comment.hasContentToLeft && !comment.hasContentToRight; + if (!comment.node.location) { + return; + } + if (commentConsumesWholeLine) { const node = Visitor.findNodeAtOrAfter(ast, comment.node.location.max - 1); diff --git a/packages/kbn-esql-ast/src/parser/walkers.ts b/packages/kbn-esql-ast/src/parser/walkers.ts index df10161f68bf8..60d69a17bb1c7 100644 --- a/packages/kbn-esql-ast/src/parser/walkers.ts +++ b/packages/kbn-esql-ast/src/parser/walkers.ts @@ -60,8 +60,6 @@ import { type ValueExpressionContext, ValueExpressionDefaultContext, InlineCastContext, - InputNamedOrPositionalParamContext, - InputParamContext, IndexPatternContext, InlinestatsCommandContext, } from '../antlr/esql_parser'; @@ -86,8 +84,9 @@ import { createInlineCast, createUnknownItem, createOrderExpression, + createFunctionCall, + createParam, } from './factories'; -import { getPosition } from './helpers'; import { ESQLLiteral, @@ -97,9 +96,6 @@ import { ESQLAstItem, ESQLAstField, ESQLInlineCast, - ESQLUnnamedParamLiteral, - ESQLPositionalParamLiteral, - ESQLNamedParamLiteral, ESQLOrderExpression, } from '../types'; import { firstItem, lastItem } from '../visitor/utils'; @@ -390,50 +386,8 @@ function getConstant(ctx: ConstantContext): ESQLAstItem { const values: ESQLLiteral[] = []; for (const child of ctx.children) { - if (child instanceof InputParamContext) { - const literal: ESQLUnnamedParamLiteral = { - type: 'literal', - literalType: 'param', - paramType: 'unnamed', - text: ctx.getText(), - name: '', - value: '', - location: getPosition(ctx.start, ctx.stop), - incomplete: Boolean(ctx.exception), - }; - values.push(literal); - } else if (child instanceof InputNamedOrPositionalParamContext) { - const text = child.getText(); - const value = text.slice(1); - const valueAsNumber = Number(value); - const isPositional = String(valueAsNumber) === value; - - if (isPositional) { - const literal: ESQLPositionalParamLiteral = { - type: 'literal', - literalType: 'param', - paramType: 'positional', - value: valueAsNumber, - text, - name: '', - location: getPosition(ctx.start, ctx.stop), - incomplete: Boolean(ctx.exception), - }; - values.push(literal); - } else { - const literal: ESQLNamedParamLiteral = { - type: 'literal', - literalType: 'param', - paramType: 'named', - value, - text, - name: '', - location: getPosition(ctx.start, ctx.stop), - incomplete: Boolean(ctx.exception), - }; - values.push(literal); - } - } + const param = createParam(child); + if (param) values.push(param); } return values; @@ -478,15 +432,7 @@ export function visitPrimaryExpression(ctx: PrimaryExpressionContext): ESQLAstIt } if (ctx instanceof FunctionContext) { const functionExpressionCtx = ctx.functionExpression(); - const functionNameContext = functionExpressionCtx.functionName().MATCH() - ? functionExpressionCtx.functionName().MATCH() - : functionExpressionCtx.functionName().identifierOrParameter(); - const fn = createFunction( - functionNameContext.getText().toLowerCase(), - ctx, - undefined, - 'variadic-call' - ); + const fn = createFunctionCall(ctx); const asteriskArg = functionExpressionCtx.ASTERISK() ? createColumnStar(functionExpressionCtx.ASTERISK()!) : undefined; @@ -671,7 +617,7 @@ const visitOrderExpression = (ctx: OrderExpressionContext): ESQLOrderExpression return arg; } - return createOrderExpression(ctx, arg, order, nulls); + return createOrderExpression(ctx, arg as ESQLColumn, order, nulls); }; export function visitOrderExpressions( diff --git a/packages/kbn-esql-ast/src/types.ts b/packages/kbn-esql-ast/src/types.ts index 0df75ee2e8f24..ea76fc3e0b9a4 100644 --- a/packages/kbn-esql-ast/src/types.ts +++ b/packages/kbn-esql-ast/src/types.ts @@ -26,6 +26,7 @@ export type ESQLSingleAstItem = | ESQLTimeInterval | ESQLList | ESQLLiteral + | ESQLIdentifier | ESQLCommandMode | ESQLInlineCast | ESQLOrderExpression @@ -132,6 +133,11 @@ export interface ESQLFunction< */ subtype?: Subtype; + /** + * A node representing the function or operator being called. + */ + operator?: ESQLIdentifier | ESQLParamLiteral; + args: ESQLAstItem[]; } @@ -363,6 +369,10 @@ export interface ESQLNamedParamLiteral extends ESQLParamLiteral<'named'> { value: string; } +export interface ESQLIdentifier extends ESQLAstBaseItem { + type: 'identifier'; +} + export const isESQLNamedParamLiteral = (node: ESQLAstItem): node is ESQLNamedParamLiteral => isESQLAstBaseItem(node) && (node as ESQLNamedParamLiteral).literalType === 'param' && @@ -376,6 +386,11 @@ export interface ESQLPositionalParamLiteral extends ESQLParamLiteral<'positional value: number; } +export type ESQLParam = + | ESQLUnnamedParamLiteral + | ESQLNamedParamLiteral + | ESQLPositionalParamLiteral; + export interface ESQLMessage { type: 'error' | 'warning'; text: string; @@ -404,7 +419,7 @@ export interface ESQLAstGenericComment; diff --git a/packages/kbn-esql-editor/src/esql_editor.tsx b/packages/kbn-esql-editor/src/esql_editor.tsx index 97340dc20d422..e8ca582ac5229 100644 --- a/packages/kbn-esql-editor/src/esql_editor.tsx +++ b/packages/kbn-esql-editor/src/esql_editor.tsx @@ -336,7 +336,7 @@ export const ESQLEditor = memo(function ESQLEditor({ const sources = await memoizedSources(dataViews, core).result; return sources; }, - getFieldsFor: async ({ query: queryToExecute }: { query?: string } | undefined = {}) => { + getColumnsFor: async ({ query: queryToExecute }: { query?: string } | undefined = {}) => { if (queryToExecute) { // ES|QL with limit 0 returns only the columns and is more performant const esqlQuery = { diff --git a/packages/kbn-esql-validation-autocomplete/src/__tests__/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/__tests__/helpers.ts index abac86ab0e323..2f46356acee37 100644 --- a/packages/kbn-esql-validation-autocomplete/src/__tests__/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/__tests__/helpers.ts @@ -56,7 +56,7 @@ export const policies = [ export function getCallbackMocks() { return { - getFieldsFor: jest.fn(async ({ query }) => { + getColumnsFor: jest.fn(async ({ query }) => { if (/enrich/.test(query)) { return enrichFields; } diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.from.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.from.test.ts index fa2e81ded897e..571e7c295e14c 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.from.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.from.test.ts @@ -91,14 +91,12 @@ describe('autocomplete.suggest', () => { test('on SPACE after "METADATA" keyword suggests all metadata fields', async () => { const { assertSuggestions } = await setup(); - await assertSuggestions('from a, b [METADATA /]', metadataFields); await assertSuggestions('from a, b METADATA /', metadataFields); }); test('on SPACE after "METADATA" column suggests command and pipe operators', async () => { const { assertSuggestions } = await setup(); - await assertSuggestions('from a, b [metadata _index /]', [',', '| ']); await assertSuggestions('from a, b metadata _index /', [',', '| ']); await assertSuggestions('from a, b metadata _index, _source /', [',', '| ']); await assertSuggestions(`from a, b metadata ${METADATA_FIELDS.join(', ')} /`, ['| ']); @@ -107,7 +105,6 @@ describe('autocomplete.suggest', () => { test('filters out already used metadata fields', async () => { const { assertSuggestions } = await setup(); - await assertSuggestions('from a, b [metadata _index, /]', metadataFieldsAndIndex); await assertSuggestions('from a, b metadata _index, /', metadataFieldsAndIndex); }); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.test.ts index 51302d0d4cde5..c7bf9079f9155 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.test.ts @@ -42,6 +42,6 @@ describe('autocomplete.suggest', () => { await suggest('sHoW ?'); await suggest('row ? |'); - expect(callbacks.getFieldsFor.mock.calls.length).toBe(0); + expect(callbacks.getColumnsFor.mock.calls.length).toBe(0); }); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts index 93fd194d93a54..3234417c1f1a4 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts @@ -18,7 +18,6 @@ import * as autocomplete from '../autocomplete'; import type { ESQLCallbacks } from '../../shared/types'; import type { EditorContext, SuggestionRawDefinition } from '../types'; import { TIME_SYSTEM_PARAMS, TRIGGER_SUGGESTION_COMMAND, getSafeInsertText } from '../factories'; -import { getFunctionSignatures } from '../../definitions/helpers'; import { ESQLRealField } from '../../validation/types'; import { FieldType, @@ -214,13 +213,9 @@ export function getFunctionSignaturesByReturnType( label: name.toUpperCase(), }; } - const printedSignatures = getFunctionSignatures(definition, { - withTypes: true, - capitalize: true, - }); return { text: `${name.toUpperCase()}($0)`, - label: printedSignatures[0].declaration, + label: name.toUpperCase(), }; }); } @@ -249,7 +244,17 @@ export function getDateLiteralsByFieldType(_requestedType: FieldType | FieldType } export function createCustomCallbackMocks( - customFields?: ESQLRealField[], + /** + * Columns that will come from Elasticsearch since the last command + * e.g. the test case may be `FROM index | EVAL foo = 1 | KEEP /` + * + * In this case, the columns available for the KEEP command will be the ones + * that were available after the EVAL command + * + * `FROM index | EVAL foo = 1 | LIMIT 0` will be used to fetch columns. The response + * will include "foo" as a column. + */ + customColumnsSinceLastCommand?: ESQLRealField[], customSources?: Array<{ name: string; hidden: boolean }>, customPolicies?: Array<{ name: string; @@ -258,11 +263,11 @@ export function createCustomCallbackMocks( enrichFields: string[]; }> ) { - const finalFields = customFields || fields; + const finalColumnsSinceLastCommand = customColumnsSinceLastCommand || fields; const finalSources = customSources || indexes; const finalPolicies = customPolicies || policies; return { - getFieldsFor: jest.fn(async () => finalFields), + getColumnsFor: jest.fn(async () => finalColumnsSinceLastCommand), getSources: jest.fn(async () => finalSources), getPolicies: jest.fn(async () => finalPolicies), }; diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts index deb4592428089..f5a5e5ca551b7 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts @@ -31,6 +31,8 @@ import { TIME_PICKER_SUGGESTION, setup, attachTriggerCommand, + SuggestOptions, + fields, } from './__tests__/helpers'; import { METADATA_FIELDS } from '../shared/constants'; import { ESQL_COMMON_NUMERIC_TYPES, ESQL_STRING_TYPES } from '../shared/esql_types'; @@ -102,7 +104,7 @@ describe('autocomplete', () => { .map(({ name }) => name.toUpperCase() + ' $0') ); testSuggestions( - 'from a [metadata _id] | /', + 'from a metadata _id | /', commandDefinitions .filter(({ name }) => !sourceCommands.includes(name)) .map(({ name }) => name.toUpperCase() + ' $0') @@ -114,7 +116,7 @@ describe('autocomplete', () => { .map(({ name }) => name.toUpperCase() + ' $0') ); testSuggestions( - 'from a [metadata _id] | eval var0 = a | /', + 'from a metadata _id | eval var0 = a | /', commandDefinitions .filter(({ name }) => !sourceCommands.includes(name)) .map(({ name }) => name.toUpperCase() + ' $0') @@ -385,24 +387,56 @@ describe('autocomplete', () => { '```````round(doubleField) + 1```` + 1`` + 1`', '```````````````round(doubleField) + 1```````` + 1```` + 1`` + 1`', '```````````````````````````````round(doubleField) + 1```````````````` + 1```````` + 1```` + 1`` + 1`', + ], + undefined, + [ + [ + ...fields, + // the following non-field columns will come over the wire as part of the response + { + name: 'round(doubleField) + 1', + type: 'double', + }, + { + name: '`round(doubleField) + 1` + 1', + type: 'double', + }, + { + name: '```round(doubleField) + 1`` + 1` + 1', + type: 'double', + }, + { + name: '```````round(doubleField) + 1```` + 1`` + 1` + 1', + type: 'double', + }, + { + name: '```````````````round(doubleField) + 1```````` + 1```` + 1`` + 1` + 1', + type: 'double', + }, + ], ] ); it('should not suggest already-used fields and variables', async () => { const { suggest: suggestTest } = await setup(); - const getSuggestions = async (query: string) => - (await suggestTest(query)).map((value) => value.text); + const getSuggestions = async (query: string, opts?: SuggestOptions) => + (await suggestTest(query, opts)).map((value) => value.text); - expect(await getSuggestions('from a_index | EVAL foo = 1 | KEEP /')).toContain('foo'); - expect(await getSuggestions('from a_index | EVAL foo = 1 | KEEP foo, /')).not.toContain( - 'foo' - ); - expect(await getSuggestions('from a_index | EVAL foo = 1 | KEEP /')).toContain( + expect( + await getSuggestions('from a_index | EVAL foo = 1 | KEEP /', { + callbacks: { getColumnsFor: () => [...fields, { name: 'foo', type: 'integer' }] }, + }) + ).toContain('foo'); + expect( + await getSuggestions('from a_index | EVAL foo = 1 | KEEP foo, /', { + callbacks: { getColumnsFor: () => [...fields, { name: 'foo', type: 'integer' }] }, + }) + ).not.toContain('foo'); + + expect(await getSuggestions('from a_index | KEEP /')).toContain('doubleField'); + expect(await getSuggestions('from a_index | KEEP doubleField, /')).not.toContain( 'doubleField' ); - expect( - await getSuggestions('from a_index | EVAL foo = 1 | KEEP doubleField, /') - ).not.toContain('doubleField'); }); }); } @@ -504,7 +538,7 @@ describe('autocomplete', () => { }); describe('callbacks', () => { - it('should send the fields query without the last command', async () => { + it('should send the columns query without the last command', async () => { const callbackMocks = createCustomCallbackMocks(undefined, undefined, undefined); const statement = 'from a | drop keywordField | eval var0 = abs(doubleField) '; const triggerOffset = statement.lastIndexOf(' '); @@ -516,7 +550,7 @@ describe('autocomplete', () => { async (text) => (text ? getAstAndSyntaxErrors(text) : { ast: [], errors: [] }), callbackMocks ); - expect(callbackMocks.getFieldsFor).toHaveBeenCalledWith({ + expect(callbackMocks.getColumnsFor).toHaveBeenCalledWith({ query: 'from a | drop keywordField', }); }); @@ -532,7 +566,7 @@ describe('autocomplete', () => { async (text) => (text ? getAstAndSyntaxErrors(text) : { ast: [], errors: [] }), callbackMocks ); - expect(callbackMocks.getFieldsFor).toHaveBeenCalledWith({ query: 'from a' }); + expect(callbackMocks.getColumnsFor).toHaveBeenCalledWith({ query: 'from a' }); }); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index 98a26b0c8dd4b..5bdbd9d995fc9 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -14,12 +14,11 @@ import type { ESQLCommand, ESQLCommandOption, ESQLFunction, - ESQLLiteral, ESQLSingleAstItem, } from '@kbn/esql-ast'; import { i18n } from '@kbn/i18n'; import { ESQL_NUMBER_TYPES, isNumericType } from '../shared/esql_types'; -import type { EditorContext, ItemKind, SuggestionRawDefinition, GetFieldsByTypeFn } from './types'; +import type { EditorContext, ItemKind, SuggestionRawDefinition, GetColumnsByTypeFn } from './types'; import { getColumnForASTNode, getCommandDefinition, @@ -49,6 +48,7 @@ import { getColumnByName, sourceExists, findFinalWord, + getAllCommands, } from '../shared/helpers'; import { collectVariables, excludeVariablesFromCurrentCommand } from '../shared/variables'; import type { ESQLPolicy, ESQLRealField, ESQLVariable, ReferenceMaps } from '../validation/types'; @@ -56,9 +56,9 @@ import { allStarConstant, colonCompleteItem, commaCompleteItem, - commandAutocompleteDefinitions, getAssignmentDefinitionCompletitionItem, getBuiltinCompatibleFunctionDefinition, + getCommandAutocompleteDefinitions, getNextTokenForNot, listCompleteItem, pipeCompleteItem, @@ -101,15 +101,12 @@ import { isAggFunctionUsedAlready, removeQuoteForSuggestedSources, getValidSignaturesAndTypesToSuggestNext, + handleFragment, + getFieldsOrFunctionsSuggestions, + pushItUpInTheList, + extractTypeFromASTArg, } from './helper'; -import { getSortPos } from './commands/sort/helper'; -import { - FunctionParameter, - FunctionReturnType, - SupportedDataType, - isParameterType, - isReturnType, -} from '../definitions/types'; +import { FunctionParameter, isParameterType, isReturnType } from '../definitions/types'; import { metadataOption } from '../definitions/options'; import { comparisonFunctions } from '../definitions/builtin'; import { countBracketsUnclosed } from '../shared/helpers'; @@ -181,7 +178,7 @@ export async function suggest( if (astContext.type === 'newCommand') { // propose main commands here // filter source commands if already defined - const suggestions = commandAutocompleteDefinitions; + const suggestions = getCommandAutocompleteDefinitions(getAllCommands()); if (!ast.length) { // Display the recommended queries if there are no commands (empty state) const recommendedQueriesSuggestions: SuggestionRawDefinition[] = []; @@ -211,7 +208,7 @@ export async function suggest( if (astContext.type === 'expression') { // suggest next possible argument, or option // otherwise a variable - return getExpressionSuggestionsByType( + return getSuggestionsWithinCommand( innerText, ast, astContext, @@ -275,7 +272,7 @@ export async function suggest( export function getFieldsByTypeRetriever( queryString: string, resourceRetriever?: ESQLCallbacks -): { getFieldsByType: GetFieldsByTypeFn; getFieldsMap: GetFieldsMapFn } { +): { getFieldsByType: GetColumnsByTypeFn; getFieldsMap: GetFieldsMapFn } { const helpers = getFieldsByTypeHelper(queryString, resourceRetriever); return { getFieldsByType: async ( @@ -389,43 +386,6 @@ function areCurrentArgsValid( return true; } -export function extractTypeFromASTArg( - arg: ESQLAstItem, - references: Pick -): - | ESQLLiteral['literalType'] - | SupportedDataType - | FunctionReturnType - | 'timeInterval' - | string // @TODO remove this - | undefined { - if (Array.isArray(arg)) { - return extractTypeFromASTArg(arg[0], references); - } - if (isColumnItem(arg) || isLiteralItem(arg)) { - if (isLiteralItem(arg)) { - return arg.literalType; - } - if (isColumnItem(arg)) { - const hit = getColumnForASTNode(arg, references); - if (hit) { - return hit.type; - } - } - } - if (isTimeIntervalItem(arg)) { - return arg.type; - } - if (isFunctionItem(arg)) { - const fnDef = getFunctionDefinition(arg.name); - if (fnDef) { - // @TODO: improve this to better filter down the correct return type based on existing arguments - // just mind that this can be highly recursive... - return fnDef.signatures[0].returnType; - } - } -} - // @TODO: refactor this to be shared with validation function isFunctionArgComplete( arg: ESQLFunction, @@ -484,6 +444,55 @@ function extractArgMeta( return { argIndex, prevIndex, lastArg, nodeArg }; } +async function getSuggestionsWithinCommand( + innerText: string, + commands: ESQLCommand[], + { + command, + option, + node, + }: { + command: ESQLCommand; + option: ESQLCommandOption | undefined; + node: ESQLSingleAstItem | undefined; + }, + getSources: () => Promise, + getColumnsByType: GetColumnsByTypeFn, + getFieldsMap: GetFieldsMapFn, + getPolicies: GetPoliciesFn, + getPolicyMetadata: GetPolicyMetadataFn +) { + const commandDef = getCommandDefinition(command.name); + + // collect all fields + variables to suggest + const fieldsMap: Map = await getFieldsMap(); + const anyVariables = collectVariables(commands, fieldsMap, innerText); + + const references = { fields: fieldsMap, variables: anyVariables }; + if (commandDef.suggest) { + // The new path. + return commandDef.suggest(innerText, command, getColumnsByType, (col: string) => + Boolean(getColumnByName(col, references)) + ); + } else { + // The deprecated path. + return getExpressionSuggestionsByType( + innerText, + commands, + { command, option, node }, + getSources, + getColumnsByType, + getFieldsMap, + getPolicies, + getPolicyMetadata + ); + } +} + +/** + * @deprecated — this generic logic will be replaced with the command-specific suggest functions + * from each command definition. + */ async function getExpressionSuggestionsByType( innerText: string, commands: ESQLCommand[], @@ -497,7 +506,7 @@ async function getExpressionSuggestionsByType( node: ESQLSingleAstItem | undefined; }, getSources: () => Promise, - getFieldsByType: GetFieldsByTypeFn, + getFieldsByType: GetColumnsByTypeFn, getFieldsMap: GetFieldsMapFn, getPolicies: GetPoliciesFn, getPolicyMetadata: GetPolicyMetadataFn @@ -505,6 +514,15 @@ async function getExpressionSuggestionsByType( const commandDef = getCommandDefinition(command.name); const { argIndex, prevIndex, lastArg, nodeArg } = extractArgMeta(command, node); + // collect all fields + variables to suggest + const fieldsMap: Map = await getFieldsMap(); + const anyVariables = collectVariables(commands, fieldsMap, innerText); + + const references = { fields: fieldsMap, variables: anyVariables }; + if (!commandDef.signature || !commandDef.options) { + return []; + } + // TODO - this is a workaround because it was too difficult to handle this case in a generic way :( if (commandDef.name === 'from' && node && isSourceItem(node) && /\s/.test(node.name)) { // FROM " " @@ -537,7 +555,7 @@ async function getExpressionSuggestionsByType( command.args.filter((arg) => isOptionItem(arg)) as ESQLCommandOption[] ).map(({ name }) => ({ name, - index: commandDef.options.findIndex(({ name: defName }) => defName === name), + index: commandDef.options!.findIndex(({ name: defName }) => defName === name), })); const optionsAvailable = commandDef.options.filter(({ name }, index) => { const optArg = optionsAlreadyDeclared.find(({ name: optionName }) => optionName === name); @@ -577,23 +595,12 @@ async function getExpressionSuggestionsByType( } } - // collect all fields + variables to suggest - const fieldsMap: Map = await (argDef ? getFieldsMap() : new Map()); - const anyVariables = collectVariables(commands, fieldsMap, innerText); - const previousWord = findPreviousWord(innerText); // enrich with assignment has some special rules who are handled somewhere else const canHaveAssignments = ['eval', 'stats', 'row'].includes(command.name) && !comparisonFunctions.map((fn) => fn.name).includes(previousWord); - const references = { fields: fieldsMap, variables: anyVariables }; - if (command.name === 'sort') { - return await suggestForSortCmd(innerText, getFieldsByType, (col) => - Boolean(getColumnByName(col, references)) - ); - } - const suggestions: SuggestionRawDefinition[] = []; // When user types and accepts autocomplete suggestion, and cursor is placed at the end of a valid field @@ -1075,7 +1082,7 @@ async function getBuiltinFunctionNextArgument( nodeArg: ESQLFunction, nodeArgType: string, references: Pick, - getFieldsByType: GetFieldsByTypeFn + getFieldsByType: GetColumnsByTypeFn ) { const suggestions = []; const isFnComplete = isFunctionArgComplete(nodeArg, references); @@ -1171,96 +1178,6 @@ async function getBuiltinFunctionNextArgument( }); } -function pushItUpInTheList(suggestions: SuggestionRawDefinition[], shouldPromote: boolean) { - if (!shouldPromote) { - return suggestions; - } - return suggestions.map(({ sortText, ...rest }) => ({ - ...rest, - sortText: `1${sortText}`, - })); -} - -/** - * TODO — split this into distinct functions, one for fields, one for functions, one for literals - */ -async function getFieldsOrFunctionsSuggestions( - types: string[], - commandName: string, - optionName: string | undefined, - getFieldsByType: GetFieldsByTypeFn, - { - functions, - fields, - variables, - literals = false, - }: { - functions: boolean; - fields: boolean; - variables?: Map; - literals?: boolean; - }, - { - ignoreFn = [], - ignoreColumns = [], - }: { - ignoreFn?: string[]; - ignoreColumns?: string[]; - } = {} -): Promise { - const filteredFieldsByType = pushItUpInTheList( - (await (fields - ? getFieldsByType(types, ignoreColumns, { - advanceCursor: commandName === 'sort', - openSuggestions: commandName === 'sort', - }) - : [])) as SuggestionRawDefinition[], - functions - ); - - const filteredVariablesByType: string[] = []; - if (variables) { - for (const variable of variables.values()) { - if ( - (types.includes('any') || types.includes(variable[0].type)) && - !ignoreColumns.includes(variable[0].name) - ) { - filteredVariablesByType.push(variable[0].name); - } - } - // due to a bug on the ES|QL table side, filter out fields list with underscored variable names (??) - // avg( numberField ) => avg_numberField_ - const ALPHANUMERIC_REGEXP = /[^a-zA-Z\d]/g; - if ( - filteredVariablesByType.length && - filteredVariablesByType.some((v) => ALPHANUMERIC_REGEXP.test(v)) - ) { - for (const variable of filteredVariablesByType) { - const underscoredName = variable.replace(ALPHANUMERIC_REGEXP, '_'); - const index = filteredFieldsByType.findIndex( - ({ label }) => underscoredName === label || `_${underscoredName}_` === label - ); - if (index >= 0) { - filteredFieldsByType.splice(index); - } - } - } - } - // could also be in stats (bucket) but our autocomplete is not great yet - const displayDateSuggestions = types.includes('date') && ['where', 'eval'].includes(commandName); - - const suggestions = filteredFieldsByType.concat( - displayDateSuggestions ? getDateLiterals() : [], - functions ? getCompatibleFunctionDefinition(commandName, optionName, types, ignoreFn) : [], - variables - ? pushItUpInTheList(buildVariablesDefinitions(filteredVariablesByType), functions) - : [], - literals ? getCompatibleLiterals(commandName, types) : [] - ); - - return suggestions; -} - const addCommaIf = (condition: boolean, text: string) => (condition ? `${text},` : text); async function getFunctionArgsSuggestions( @@ -1275,7 +1192,7 @@ async function getFunctionArgsSuggestions( option: ESQLCommandOption | undefined; node: ESQLFunction; }, - getFieldsByType: GetFieldsByTypeFn, + getFieldsByType: GetColumnsByTypeFn, getFieldsMap: GetFieldsMapFn, getPolicyMetadata: GetPolicyMetadataFn, fullText: string, @@ -1504,7 +1421,7 @@ async function getListArgsSuggestions( command: ESQLCommand; node: ESQLSingleAstItem | undefined; }, - getFieldsByType: GetFieldsByTypeFn, + getFieldsByType: GetColumnsByTypeFn, getFieldsMaps: GetFieldsMapFn, getPolicyMetadata: GetPolicyMetadataFn ) { @@ -1559,13 +1476,13 @@ async function getSettingArgsSuggestions( command: ESQLCommand; node: ESQLSingleAstItem | undefined; }, - getFieldsByType: GetFieldsByTypeFn, + getFieldsByType: GetColumnsByTypeFn, getFieldsMaps: GetFieldsMapFn, getPolicyMetadata: GetPolicyMetadataFn ) { const suggestions = []; - const settingDefs = getCommandDefinition(command.name).modes; + const settingDefs = getCommandDefinition(command.name).modes || []; if (settingDefs.length) { const lastChar = getLastCharFromTrimmed(innerText); @@ -1590,7 +1507,7 @@ async function getOptionArgsSuggestions( option: ESQLCommandOption; node: ESQLSingleAstItem | undefined; }, - getFieldsByType: GetFieldsByTypeFn, + getFieldsByType: GetColumnsByTypeFn, getFieldsMaps: GetFieldsMapFn, getPolicyMetadata: GetPolicyMetadataFn, getPreferences?: () => Promise<{ histogramBarTarget: number } | undefined> @@ -1601,6 +1518,9 @@ async function getOptionArgsSuggestions( } const optionDef = getCommandOption(option.name); + if (!optionDef || !optionDef.signature) { + return []; + } const { nodeArg, argIndex, lastArg } = extractArgMeta(option, node); const suggestions = []; const isNewExpression = isRestartingExpression(innerText) || option.args.length === 0; @@ -1899,236 +1819,3 @@ async function getOptionArgsSuggestions( } return suggestions; } - -/** - * This function handles the logic to suggest completions - * for a given fragment of text in a generic way. A good example is - * a field name. - * - * When typing a field name, there are 2 scenarios - * - * 1. field name is incomplete (includes the empty string) - * KEEP / - * KEEP fie/ - * - * 2. field name is complete - * KEEP field/ - * - * This function provides a framework for detecting and handling both scenarios in a clean way. - * - * @param innerText - the query text before the current cursor position - * @param isFragmentComplete — return true if the fragment is complete - * @param getSuggestionsForIncomplete — gets suggestions for an incomplete fragment - * @param getSuggestionsForComplete - gets suggestions for a complete fragment - * @returns - */ -function handleFragment( - innerText: string, - isFragmentComplete: (fragment: string) => boolean, - getSuggestionsForIncomplete: ( - fragment: string, - rangeToReplace?: { start: number; end: number } - ) => SuggestionRawDefinition[] | Promise, - getSuggestionsForComplete: ( - fragment: string, - rangeToReplace: { start: number; end: number } - ) => SuggestionRawDefinition[] | Promise -): SuggestionRawDefinition[] | Promise { - /** - * @TODO — this string manipulation is crude and can't support all cases - * Checking for a partial word and computing the replacement range should - * really be done using the AST node, but we'll have to refactor further upstream - * to make that available. This is a quick fix to support the most common case. - */ - const fragment = findFinalWord(innerText); - if (!fragment) { - return getSuggestionsForIncomplete(''); - } else { - const rangeToReplace = { - start: innerText.length - fragment.length + 1, - end: innerText.length + 1, - }; - if (isFragmentComplete(fragment)) { - return getSuggestionsForComplete(fragment, rangeToReplace); - } else { - return getSuggestionsForIncomplete(fragment, rangeToReplace); - } - } -} - -const sortModifierSuggestions = { - ASC: { - label: 'ASC', - text: 'ASC', - detail: '', - kind: 'Keyword', - sortText: '1-ASC', - command: TRIGGER_SUGGESTION_COMMAND, - } as SuggestionRawDefinition, - DESC: { - label: 'DESC', - text: 'DESC', - detail: '', - kind: 'Keyword', - sortText: '1-DESC', - command: TRIGGER_SUGGESTION_COMMAND, - } as SuggestionRawDefinition, - NULLS_FIRST: { - label: 'NULLS FIRST', - text: 'NULLS FIRST', - detail: '', - kind: 'Keyword', - sortText: '2-NULLS FIRST', - command: TRIGGER_SUGGESTION_COMMAND, - } as SuggestionRawDefinition, - NULLS_LAST: { - label: 'NULLS LAST', - text: 'NULLS LAST', - detail: '', - kind: 'Keyword', - sortText: '2-NULLS LAST', - command: TRIGGER_SUGGESTION_COMMAND, - } as SuggestionRawDefinition, -}; - -export const suggestForSortCmd = async ( - innerText: string, - getFieldsByType: GetFieldsByTypeFn, - columnExists: (column: string) => boolean -): Promise => { - const prependSpace = (s: SuggestionRawDefinition) => ({ ...s, text: ' ' + s.text }); - - const { pos, nulls } = getSortPos(innerText); - - switch (pos) { - case 'space2': { - return [ - sortModifierSuggestions.ASC, - sortModifierSuggestions.DESC, - sortModifierSuggestions.NULLS_FIRST, - sortModifierSuggestions.NULLS_LAST, - pipeCompleteItem, - { ...commaCompleteItem, text: ', ', command: TRIGGER_SUGGESTION_COMMAND }, - ]; - } - case 'order': { - return handleFragment( - innerText, - (fragment) => ['ASC', 'DESC'].some((completeWord) => noCaseCompare(completeWord, fragment)), - (_fragment, rangeToReplace) => { - return Object.values(sortModifierSuggestions).map((suggestion) => ({ - ...suggestion, - rangeToReplace, - })); - }, - (fragment, rangeToReplace) => { - return [ - { ...pipeCompleteItem, text: ' | ' }, - { ...commaCompleteItem, text: ', ' }, - prependSpace(sortModifierSuggestions.NULLS_FIRST), - prependSpace(sortModifierSuggestions.NULLS_LAST), - ].map((suggestion) => ({ - ...suggestion, - filterText: fragment, - text: fragment + suggestion.text, - rangeToReplace, - command: TRIGGER_SUGGESTION_COMMAND, - })); - } - ); - } - case 'space3': { - return [ - sortModifierSuggestions.NULLS_FIRST, - sortModifierSuggestions.NULLS_LAST, - pipeCompleteItem, - { ...commaCompleteItem, text: ', ', command: TRIGGER_SUGGESTION_COMMAND }, - ]; - } - case 'nulls': { - return handleFragment( - innerText, - (fragment) => - ['FIRST', 'LAST'].some((completeWord) => noCaseCompare(completeWord, fragment)), - (_fragment) => { - const end = innerText.length + 1; - const start = end - nulls.length; - return Object.values(sortModifierSuggestions).map((suggestion) => ({ - ...suggestion, - // we can't use the range generated by handleFragment here - // because it doesn't really support multi-word completions - rangeToReplace: { start, end }, - })); - }, - (fragment, rangeToReplace) => { - return [ - { ...pipeCompleteItem, text: ' | ' }, - { ...commaCompleteItem, text: ', ' }, - ].map((suggestion) => ({ - ...suggestion, - filterText: fragment, - text: fragment + suggestion.text, - rangeToReplace, - command: TRIGGER_SUGGESTION_COMMAND, - })); - } - ); - } - case 'space4': { - return [ - pipeCompleteItem, - { ...commaCompleteItem, text: ', ', command: TRIGGER_SUGGESTION_COMMAND }, - ]; - } - } - - const fieldSuggestions = await getFieldsByType('any', [], { - openSuggestions: true, - }); - const functionSuggestions = await getFieldsOrFunctionsSuggestions( - ['any'], - 'sort', - undefined, - getFieldsByType, - { - functions: true, - fields: false, - } - ); - - return await handleFragment( - innerText, - columnExists, - (_fragment: string, rangeToReplace?: { start: number; end: number }) => { - // SORT fie - return [ - ...pushItUpInTheList( - fieldSuggestions.map((suggestion) => ({ - ...suggestion, - command: TRIGGER_SUGGESTION_COMMAND, - rangeToReplace, - })), - true - ), - ...functionSuggestions, - ]; - }, - (fragment: string, rangeToReplace: { start: number; end: number }) => { - // SORT field - return [ - { ...pipeCompleteItem, text: ' | ' }, - { ...commaCompleteItem, text: ', ' }, - prependSpace(sortModifierSuggestions.ASC), - prependSpace(sortModifierSuggestions.DESC), - prependSpace(sortModifierSuggestions.NULLS_FIRST), - prependSpace(sortModifierSuggestions.NULLS_LAST), - ].map((s) => ({ - ...s, - filterText: fragment, - text: fragment + s.text, - command: TRIGGER_SUGGESTION_COMMAND, - rangeToReplace, - })); - } - ); -}; diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/drop/index.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/drop/index.ts new file mode 100644 index 0000000000000..ed5f0ee3d3f6b --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/drop/index.ts @@ -0,0 +1,70 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { ESQLCommand } from '@kbn/esql-ast'; +import { + findPreviousWord, + getLastCharFromTrimmed, + isColumnItem, + noCaseCompare, +} from '../../../shared/helpers'; +import type { GetColumnsByTypeFn, SuggestionRawDefinition } from '../../types'; +import { commaCompleteItem, pipeCompleteItem } from '../../complete_items'; +import { handleFragment } from '../../helper'; +import { TRIGGER_SUGGESTION_COMMAND } from '../../factories'; + +export async function suggest( + innerText: string, + command: ESQLCommand<'drop'>, + getColumnsByType: GetColumnsByTypeFn, + columnExists: (column: string) => boolean +): Promise { + if ( + /\s/.test(innerText[innerText.length - 1]) && + getLastCharFromTrimmed(innerText) !== ',' && + !noCaseCompare(findPreviousWord(innerText), 'drop') + ) { + return [pipeCompleteItem, commaCompleteItem]; + } + + const alreadyDeclaredFields = command.args.filter(isColumnItem).map((arg) => arg.name); + const fieldSuggestions = await getColumnsByType('any', alreadyDeclaredFields); + + return handleFragment( + innerText, + (fragment) => columnExists(fragment), + (_fragment: string, rangeToReplace?: { start: number; end: number }) => { + // KEEP fie + return fieldSuggestions.map((suggestion) => ({ + ...suggestion, + text: suggestion.text, + command: TRIGGER_SUGGESTION_COMMAND, + rangeToReplace, + })); + }, + (fragment: string, rangeToReplace: { start: number; end: number }) => { + // KEEP field + const finalSuggestions = [{ ...pipeCompleteItem, text: ' | ' }]; + if (fieldSuggestions.length > 1) + // when we fix the editor marker, this should probably be checked against 0 instead of 1 + // this is because the last field in the AST is currently getting removed (because it contains + // the editor marker) so it is not included in the ignored list which is used to filter out + // existing fields above. + finalSuggestions.push({ ...commaCompleteItem, text: ', ' }); + + return finalSuggestions.map((s) => ({ + ...s, + filterText: fragment, + text: fragment + s.text, + command: TRIGGER_SUGGESTION_COMMAND, + rangeToReplace, + })); + } + ); +} diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/keep/index.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/keep/index.ts new file mode 100644 index 0000000000000..c2480ffbcde72 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/keep/index.ts @@ -0,0 +1,70 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { ESQLCommand } from '@kbn/esql-ast'; +import { + findPreviousWord, + getLastCharFromTrimmed, + isColumnItem, + noCaseCompare, +} from '../../../shared/helpers'; +import type { GetColumnsByTypeFn, SuggestionRawDefinition } from '../../types'; +import { commaCompleteItem, pipeCompleteItem } from '../../complete_items'; +import { handleFragment } from '../../helper'; +import { TRIGGER_SUGGESTION_COMMAND } from '../../factories'; + +export async function suggest( + innerText: string, + command: ESQLCommand<'keep'>, + getColumnsByType: GetColumnsByTypeFn, + columnExists: (column: string) => boolean +): Promise { + if ( + /\s/.test(innerText[innerText.length - 1]) && + getLastCharFromTrimmed(innerText) !== ',' && + !noCaseCompare(findPreviousWord(innerText), 'keep') + ) { + return [pipeCompleteItem, commaCompleteItem]; + } + + const alreadyDeclaredFields = command.args.filter(isColumnItem).map((arg) => arg.name); + const fieldSuggestions = await getColumnsByType('any', alreadyDeclaredFields); + + return handleFragment( + innerText, + (fragment) => columnExists(fragment), + (_fragment: string, rangeToReplace?: { start: number; end: number }) => { + // KEEP fie + return fieldSuggestions.map((suggestion) => ({ + ...suggestion, + text: suggestion.text, + command: TRIGGER_SUGGESTION_COMMAND, + rangeToReplace, + })); + }, + (fragment: string, rangeToReplace: { start: number; end: number }) => { + // KEEP field + const finalSuggestions = [{ ...pipeCompleteItem, text: ' | ' }]; + if (fieldSuggestions.length > 1) + // when we fix the editor marker, this should probably be checked against 0 instead of 1 + // this is because the last field in the AST is currently getting removed (because it contains + // the editor marker) so it is not included in the ignored list which is used to filter out + // existing fields above. + finalSuggestions.push({ ...commaCompleteItem, text: ', ' }); + + return finalSuggestions.map((s) => ({ + ...s, + filterText: fragment, + text: fragment + s.text, + command: TRIGGER_SUGGESTION_COMMAND, + rangeToReplace, + })); + } + ); +} diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/sort/helper.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/sort/helper.ts index 96546eff7d391..63dea06667cd8 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/sort/helper.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/sort/helper.ts @@ -7,6 +7,9 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { TRIGGER_SUGGESTION_COMMAND } from '../../factories'; +import { SuggestionRawDefinition } from '../../types'; + const regexStart = /.+\|\s*so?r?(?t?)(.+,)?(?\s+)?/i; const regex = /.+\|\s*sort(.+,)?((?\s+)(?[^\s]+)(?\s*)(?(AS?C?)|(DE?S?C?))?(?\s*)(?NU?L?L?S? ?(FI?R?S?T?|LA?S?T?)?)?(?\s*))?/i; @@ -43,6 +46,41 @@ export interface SortCaretPosition { nulls: string; } +export const sortModifierSuggestions = { + ASC: { + label: 'ASC', + text: 'ASC', + detail: '', + kind: 'Keyword', + sortText: '1-ASC', + command: TRIGGER_SUGGESTION_COMMAND, + } as SuggestionRawDefinition, + DESC: { + label: 'DESC', + text: 'DESC', + detail: '', + kind: 'Keyword', + sortText: '1-DESC', + command: TRIGGER_SUGGESTION_COMMAND, + } as SuggestionRawDefinition, + NULLS_FIRST: { + label: 'NULLS FIRST', + text: 'NULLS FIRST', + detail: '', + kind: 'Keyword', + sortText: '2-NULLS FIRST', + command: TRIGGER_SUGGESTION_COMMAND, + } as SuggestionRawDefinition, + NULLS_LAST: { + label: 'NULLS LAST', + text: 'NULLS LAST', + detail: '', + kind: 'Keyword', + sortText: '2-NULLS LAST', + command: TRIGGER_SUGGESTION_COMMAND, + } as SuggestionRawDefinition, +}; + export const getSortPos = (query: string): SortCaretPosition => { const match = query.match(regex); let pos: SortCaretPosition['pos'] = 'none'; diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/sort/index.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/sort/index.ts new file mode 100644 index 0000000000000..61561dea96b72 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/sort/index.ts @@ -0,0 +1,159 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { ESQLCommand } from '@kbn/esql-ast'; +import { noCaseCompare } from '../../../shared/helpers'; +import { commaCompleteItem, pipeCompleteItem } from '../../complete_items'; +import { TRIGGER_SUGGESTION_COMMAND } from '../../factories'; +import { getFieldsOrFunctionsSuggestions, handleFragment, pushItUpInTheList } from '../../helper'; +import type { GetColumnsByTypeFn, SuggestionRawDefinition } from '../../types'; +import { getSortPos, sortModifierSuggestions } from './helper'; + +export async function suggest( + innerText: string, + _command: ESQLCommand<'sort'>, + getColumnsByType: GetColumnsByTypeFn, + columnExists: (column: string) => boolean +): Promise { + const prependSpace = (s: SuggestionRawDefinition) => ({ ...s, text: ' ' + s.text }); + + const { pos, nulls } = getSortPos(innerText); + + switch (pos) { + case 'space2': { + return [ + sortModifierSuggestions.ASC, + sortModifierSuggestions.DESC, + sortModifierSuggestions.NULLS_FIRST, + sortModifierSuggestions.NULLS_LAST, + pipeCompleteItem, + { ...commaCompleteItem, text: ', ', command: TRIGGER_SUGGESTION_COMMAND }, + ]; + } + case 'order': { + return handleFragment( + innerText, + (fragment) => ['ASC', 'DESC'].some((completeWord) => noCaseCompare(completeWord, fragment)), + (_fragment, rangeToReplace) => { + return Object.values(sortModifierSuggestions).map((suggestion) => ({ + ...suggestion, + rangeToReplace, + })); + }, + (fragment, rangeToReplace) => { + return [ + { ...pipeCompleteItem, text: ' | ' }, + { ...commaCompleteItem, text: ', ' }, + prependSpace(sortModifierSuggestions.NULLS_FIRST), + prependSpace(sortModifierSuggestions.NULLS_LAST), + ].map((suggestion) => ({ + ...suggestion, + filterText: fragment, + text: fragment + suggestion.text, + rangeToReplace, + command: TRIGGER_SUGGESTION_COMMAND, + })); + } + ); + } + case 'space3': { + return [ + sortModifierSuggestions.NULLS_FIRST, + sortModifierSuggestions.NULLS_LAST, + pipeCompleteItem, + { ...commaCompleteItem, text: ', ', command: TRIGGER_SUGGESTION_COMMAND }, + ]; + } + case 'nulls': { + return handleFragment( + innerText, + (fragment) => + ['FIRST', 'LAST'].some((completeWord) => noCaseCompare(completeWord, fragment)), + (_fragment) => { + const end = innerText.length + 1; + const start = end - nulls.length; + return Object.values(sortModifierSuggestions).map((suggestion) => ({ + ...suggestion, + // we can't use the range generated by handleFragment here + // because it doesn't really support multi-word completions + rangeToReplace: { start, end }, + })); + }, + (fragment, rangeToReplace) => { + return [ + { ...pipeCompleteItem, text: ' | ' }, + { ...commaCompleteItem, text: ', ' }, + ].map((suggestion) => ({ + ...suggestion, + filterText: fragment, + text: fragment + suggestion.text, + rangeToReplace, + command: TRIGGER_SUGGESTION_COMMAND, + })); + } + ); + } + case 'space4': { + return [ + pipeCompleteItem, + { ...commaCompleteItem, text: ', ', command: TRIGGER_SUGGESTION_COMMAND }, + ]; + } + } + + const fieldSuggestions = await getColumnsByType('any', [], { + openSuggestions: true, + }); + const functionSuggestions = await getFieldsOrFunctionsSuggestions( + ['any'], + 'sort', + undefined, + getColumnsByType, + { + functions: true, + fields: false, + } + ); + + return await handleFragment( + innerText, + columnExists, + (_fragment: string, rangeToReplace?: { start: number; end: number }) => { + // SORT fie + return [ + ...pushItUpInTheList( + fieldSuggestions.map((suggestion) => ({ + ...suggestion, + command: TRIGGER_SUGGESTION_COMMAND, + rangeToReplace, + })), + true + ), + ...functionSuggestions, + ]; + }, + (fragment: string, rangeToReplace: { start: number; end: number }) => { + // SORT field + return [ + { ...pipeCompleteItem, text: ' | ' }, + { ...commaCompleteItem, text: ', ' }, + prependSpace(sortModifierSuggestions.ASC), + prependSpace(sortModifierSuggestions.DESC), + prependSpace(sortModifierSuggestions.NULLS_FIRST), + prependSpace(sortModifierSuggestions.NULLS_LAST), + ].map((s) => ({ + ...s, + filterText: fragment, + text: fragment + s.text, + command: TRIGGER_SUGGESTION_COMMAND, + rangeToReplace, + })); + } + ); +} diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts index 000c196b49e5e..b115e30c47efe 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts @@ -10,14 +10,13 @@ import { i18n } from '@kbn/i18n'; import type { ItemKind, SuggestionRawDefinition } from './types'; import { builtinFunctions } from '../definitions/builtin'; -import { getAllCommands } from '../shared/helpers'; import { getSuggestionBuiltinDefinition, getSuggestionCommandDefinition, TRIGGER_SUGGESTION_COMMAND, buildConstantsDefinitions, } from './factories'; -import { FunctionParameterType, FunctionReturnType } from '../definitions/types'; +import { CommandDefinition, FunctionParameterType, FunctionReturnType } from '../definitions/types'; import { getTestFunctions } from '../shared/test_functions'; export function getAssignmentDefinitionCompletitionItem() { @@ -87,9 +86,10 @@ export const getBuiltinCompatibleFunctionDefinition = ( .map(getSuggestionBuiltinDefinition); }; -export const commandAutocompleteDefinitions: SuggestionRawDefinition[] = getAllCommands() - .filter(({ hidden }) => !hidden) - .map(getSuggestionCommandDefinition); +export const getCommandAutocompleteDefinitions = ( + commands: Array> +): SuggestionRawDefinition[] => + commands.filter(({ hidden }) => !hidden).map(getSuggestionCommandDefinition); function buildCharCompleteItem( label: string, diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index 43f6f8ccff365..f522e9bc65863 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -64,7 +64,7 @@ function getSafeInsertSourceText(text: string) { export function getSuggestionFunctionDefinition(fn: FunctionDefinition): SuggestionRawDefinition { const fullSignatures = getFunctionSignatures(fn, { capitalize: true, withTypes: true }); return { - label: fullSignatures[0].declaration, + label: fn.name.toUpperCase(), text: `${fn.name.toUpperCase()}($0)`, asSnippet: true, kind: 'Function', @@ -123,7 +123,7 @@ export const getCompatibleFunctionDefinition = ( }; export function getSuggestionCommandDefinition( - command: CommandDefinition + command: CommandDefinition ): SuggestionRawDefinition { const commandDefinition = getCommandDefinition(command.name); const commandSignature = getCommandSignature(commandDefinition); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts index dd450e28b66a9..6585a04c98c59 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts @@ -7,21 +7,40 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { ESQLAstItem, ESQLCommand, ESQLFunction, ESQLSource } from '@kbn/esql-ast'; +import type { + ESQLAstItem, + ESQLCommand, + ESQLFunction, + ESQLLiteral, + ESQLSource, +} from '@kbn/esql-ast'; import { uniqBy } from 'lodash'; -import type { FunctionDefinition } from '../definitions/types'; +import type { + FunctionDefinition, + FunctionReturnType, + SupportedDataType, +} from '../definitions/types'; import { + findFinalWord, + getColumnForASTNode, getFunctionDefinition, isAssignment, + isColumnItem, isFunctionItem, isLiteralItem, + isTimeIntervalItem, } from '../shared/helpers'; -import type { SuggestionRawDefinition } from './types'; +import type { GetColumnsByTypeFn, SuggestionRawDefinition } from './types'; import { compareTypesWithLiterals } from '../shared/esql_types'; -import { TIME_SYSTEM_PARAMS } from './factories'; +import { + TIME_SYSTEM_PARAMS, + buildVariablesDefinitions, + getCompatibleFunctionDefinition, + getCompatibleLiterals, + getDateLiterals, +} from './factories'; import { EDITOR_MARKER } from '../shared/constants'; -import { extractTypeFromASTArg } from './autocomplete'; -import { ESQLRealField, ESQLVariable } from '../validation/types'; +import { ESQLRealField, ESQLVariable, ReferenceMaps } from '../validation/types'; function extractFunctionArgs(args: ESQLAstItem[]): ESQLFunction[] { return args.flatMap((arg) => (isAssignment(arg) ? arg.args[1] : arg)).filter(isFunctionItem); @@ -272,3 +291,185 @@ export function getValidSignaturesAndTypesToSuggestNext( currentArg, }; } + +/** + * This function handles the logic to suggest completions + * for a given fragment of text in a generic way. A good example is + * a field name. + * + * When typing a field name, there are 2 scenarios + * + * 1. field name is incomplete (includes the empty string) + * KEEP / + * KEEP fie/ + * + * 2. field name is complete + * KEEP field/ + * + * This function provides a framework for detecting and handling both scenarios in a clean way. + * + * @param innerText - the query text before the current cursor position + * @param isFragmentComplete — return true if the fragment is complete + * @param getSuggestionsForIncomplete — gets suggestions for an incomplete fragment + * @param getSuggestionsForComplete - gets suggestions for a complete fragment + * @returns + */ +export function handleFragment( + innerText: string, + isFragmentComplete: (fragment: string) => boolean, + getSuggestionsForIncomplete: ( + fragment: string, + rangeToReplace?: { start: number; end: number } + ) => SuggestionRawDefinition[] | Promise, + getSuggestionsForComplete: ( + fragment: string, + rangeToReplace: { start: number; end: number } + ) => SuggestionRawDefinition[] | Promise +): SuggestionRawDefinition[] | Promise { + /** + * @TODO — this string manipulation is crude and can't support all cases + * Checking for a partial word and computing the replacement range should + * really be done using the AST node, but we'll have to refactor further upstream + * to make that available. This is a quick fix to support the most common case. + */ + const fragment = findFinalWord(innerText); + if (!fragment) { + return getSuggestionsForIncomplete(''); + } else { + const rangeToReplace = { + start: innerText.length - fragment.length + 1, + end: innerText.length + 1, + }; + if (isFragmentComplete(fragment)) { + return getSuggestionsForComplete(fragment, rangeToReplace); + } else { + return getSuggestionsForIncomplete(fragment, rangeToReplace); + } + } +} +/** + * TODO — split this into distinct functions, one for fields, one for functions, one for literals + */ +export async function getFieldsOrFunctionsSuggestions( + types: string[], + commandName: string, + optionName: string | undefined, + getFieldsByType: GetColumnsByTypeFn, + { + functions, + fields, + variables, + literals = false, + }: { + functions: boolean; + fields: boolean; + variables?: Map; + literals?: boolean; + }, + { + ignoreFn = [], + ignoreColumns = [], + }: { + ignoreFn?: string[]; + ignoreColumns?: string[]; + } = {} +): Promise { + const filteredFieldsByType = pushItUpInTheList( + (await (fields + ? getFieldsByType(types, ignoreColumns, { + advanceCursor: commandName === 'sort', + openSuggestions: commandName === 'sort', + }) + : [])) as SuggestionRawDefinition[], + functions + ); + + const filteredVariablesByType: string[] = []; + if (variables) { + for (const variable of variables.values()) { + if ( + (types.includes('any') || types.includes(variable[0].type)) && + !ignoreColumns.includes(variable[0].name) + ) { + filteredVariablesByType.push(variable[0].name); + } + } + // due to a bug on the ES|QL table side, filter out fields list with underscored variable names (??) + // avg( numberField ) => avg_numberField_ + const ALPHANUMERIC_REGEXP = /[^a-zA-Z\d]/g; + if ( + filteredVariablesByType.length && + filteredVariablesByType.some((v) => ALPHANUMERIC_REGEXP.test(v)) + ) { + for (const variable of filteredVariablesByType) { + const underscoredName = variable.replace(ALPHANUMERIC_REGEXP, '_'); + const index = filteredFieldsByType.findIndex( + ({ label }) => underscoredName === label || `_${underscoredName}_` === label + ); + if (index >= 0) { + filteredFieldsByType.splice(index); + } + } + } + } + // could also be in stats (bucket) but our autocomplete is not great yet + const displayDateSuggestions = types.includes('date') && ['where', 'eval'].includes(commandName); + + const suggestions = filteredFieldsByType.concat( + displayDateSuggestions ? getDateLiterals() : [], + functions ? getCompatibleFunctionDefinition(commandName, optionName, types, ignoreFn) : [], + variables + ? pushItUpInTheList(buildVariablesDefinitions(filteredVariablesByType), functions) + : [], + literals ? getCompatibleLiterals(commandName, types) : [] + ); + + return suggestions; +} + +export function pushItUpInTheList(suggestions: SuggestionRawDefinition[], shouldPromote: boolean) { + if (!shouldPromote) { + return suggestions; + } + return suggestions.map(({ sortText, ...rest }) => ({ + ...rest, + sortText: `1${sortText}`, + })); +} + +export function extractTypeFromASTArg( + arg: ESQLAstItem, + references: Pick +): + | ESQLLiteral['literalType'] + | SupportedDataType + | FunctionReturnType + | 'timeInterval' + | string // @TODO remove this + | undefined { + if (Array.isArray(arg)) { + return extractTypeFromASTArg(arg[0], references); + } + if (isColumnItem(arg) || isLiteralItem(arg)) { + if (isLiteralItem(arg)) { + return arg.literalType; + } + if (isColumnItem(arg)) { + const hit = getColumnForASTNode(arg, references); + if (hit) { + return hit.type; + } + } + } + if (isTimeIntervalItem(arg)) { + return arg.type; + } + if (isFunctionItem(arg)) { + const fnDef = getFunctionDefinition(arg.name); + if (fnDef) { + // @TODO: improve this to better filter down the correct return type based on existing arguments + // just mind that this can be highly recursive... + return fnDef.signatures[0].returnType; + } + } +} diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/recommended_queries/suggestions.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/recommended_queries/suggestions.ts index fbcfbabb2b63c..29c598af93501 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/recommended_queries/suggestions.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/recommended_queries/suggestions.ts @@ -7,11 +7,11 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { SuggestionRawDefinition, GetFieldsByTypeFn } from '../types'; +import type { SuggestionRawDefinition, GetColumnsByTypeFn } from '../types'; import { getRecommendedQueries } from './templates'; export const getRecommendedQueriesSuggestions = async ( - getFieldsByType: GetFieldsByTypeFn, + getFieldsByType: GetColumnsByTypeFn, fromCommand: string = '' ): Promise => { const fieldSuggestions = await getFieldsByType('date', [], { diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/types.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/types.ts index 030bff4da181c..cbd6ead535932 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/types.ts @@ -81,7 +81,7 @@ export interface EditorContext { triggerKind: number; } -export type GetFieldsByTypeFn = ( +export type GetColumnsByTypeFn = ( type: string | string[], ignored?: string[], options?: { advanceCursor?: boolean; openSuggestions?: boolean; addComma?: boolean } diff --git a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts index b608570854950..4563379642767 100644 --- a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts @@ -18,7 +18,7 @@ import type { ESQLCallbacks, PartialFieldsMetadataClient } from '../shared/types function getCallbackMocks(): jest.Mocked { return { - getFieldsFor: jest.fn, any>(async ({ query }) => { + getColumnsFor: jest.fn, any>(async ({ query }) => { if (/enrich/.test(query)) { const fields: ESQLRealField[] = [ { name: 'otherField', type: 'keyword' }, @@ -375,11 +375,11 @@ describe('quick fixes logic', () => { const statement = `FROM index | DROP any#Char$Field`; const { errors } = await validateQuery(statement, getAstAndSyntaxErrors, undefined, { ...callbackMocks, - getFieldsFor: undefined, + getColumnsFor: undefined, }); const edits = await getActions(statement, errors, getAstAndSyntaxErrors, undefined, { ...callbackMocks, - getFieldsFor: undefined, + getColumnsFor: undefined, }); expect(edits.length).toBe(0); }); @@ -400,7 +400,7 @@ describe('quick fixes logic', () => { const statement = `FROM index | DROP any#Char$Field`; const { errors } = await validateQuery(statement, getAstAndSyntaxErrors, undefined, { ...callbackMocks, - getFieldsFor: undefined, + getColumnsFor: undefined, getFieldsMetadata: undefined, }); const actions = await getActions( @@ -412,7 +412,7 @@ describe('quick fixes logic', () => { }, { ...callbackMocks, - getFieldsFor: undefined, + getColumnsFor: undefined, getFieldsMetadata: undefined, } ); @@ -435,7 +435,7 @@ describe('quick fixes logic', () => { ); try { await getActions(statement, errors, getAstAndSyntaxErrors, undefined, { - getFieldsFor: undefined, + getColumnsFor: undefined, getSources: undefined, getPolicies: undefined, }); @@ -460,7 +460,7 @@ describe('quick fixes logic', () => { getAstAndSyntaxErrors, { relaxOnMissingCallbacks: true }, { - getFieldsFor: undefined, + getColumnsFor: undefined, getSources: undefined, getPolicies: undefined, getFieldsMetadata: undefined, diff --git a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.ts b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.ts index 02627c5f1abdf..37ab56350ffb2 100644 --- a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.ts +++ b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.ts @@ -403,7 +403,7 @@ export async function getActions( const { getPolicies, getPolicyFields } = getPolicyRetriever(resourceRetriever); const callbacks = { - getFieldsByType: resourceRetriever?.getFieldsFor ? getFieldsByType : undefined, + getFieldsByType: resourceRetriever?.getColumnsFor ? getFieldsByType : undefined, getSources: resourceRetriever?.getSources ? getSources : undefined, getPolicies: resourceRetriever?.getPolicies ? getPolicies : undefined, getPolicyFields: resourceRetriever?.getPolicies ? getPolicyFields : undefined, diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts index 54504ac1a2a18..f4482a5b33c17 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts @@ -32,6 +32,9 @@ import { withOption, } from './options'; import type { CommandDefinition } from './types'; +import { suggest as suggestForSort } from '../autocomplete/commands/sort'; +import { suggest as suggestForKeep } from '../autocomplete/commands/keep'; +import { suggest as suggestForDrop } from '../autocomplete/commands/drop'; const statsValidator = (command: ESQLCommand) => { const messages: ESQLMessage[] = []; @@ -148,7 +151,7 @@ const statsValidator = (command: ESQLCommand) => { } return messages; }; -export const commandDefinitions: CommandDefinition[] = [ +export const commandDefinitions: Array> = [ { name: 'row', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.rowDoc', { @@ -311,6 +314,7 @@ export const commandDefinitions: CommandDefinition[] = [ defaultMessage: 'Rearranges fields in the input table by applying the keep clauses in fields', }), examples: ['… | keep a', '… | keep a,b'], + suggest: suggestForKeep, options: [], modes: [], signature: { @@ -330,6 +334,7 @@ export const commandDefinitions: CommandDefinition[] = [ multipleParams: true, params: [{ name: 'column', type: 'column', wildcards: true }], }, + suggest: suggestForDrop, validate: (command: ESQLCommand) => { const messages: ESQLMessage[] = []; const wildcardItems = command.args.filter((arg) => isColumnItem(arg) && arg.name === '*'); @@ -386,7 +391,9 @@ export const commandDefinitions: CommandDefinition[] = [ multipleParams: true, params: [{ name: 'expression', type: 'any' }], }, + suggest: suggestForSort, }, + { name: 'where', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.whereDoc', { diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts index 28b4cd4f66443..f73521ddf3a87 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts @@ -823,7 +823,7 @@ const maxDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -1035,7 +1035,7 @@ const minDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -1491,7 +1491,7 @@ const topDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, ], supportedCommands: ['stats', 'inlinestats', 'metrics'], @@ -1590,7 +1590,7 @@ const valuesDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts index 2ace3e9ddc537..4b0ea8ee564ed 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts @@ -941,7 +941,7 @@ const coalesceDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', minParams: 1, }, { @@ -957,7 +957,7 @@ const coalesceDefinition: FunctionDefinition = { optional: true, }, ], - returnType: 'text', + returnType: 'keyword', minParams: 1, }, { @@ -1973,7 +1973,7 @@ const greatestDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', minParams: 1, }, { @@ -1989,7 +1989,7 @@ const greatestDefinition: FunctionDefinition = { optional: true, }, ], - returnType: 'text', + returnType: 'keyword', minParams: 1, }, { @@ -2484,7 +2484,7 @@ const leastDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', minParams: 1, }, { @@ -2500,7 +2500,7 @@ const leastDefinition: FunctionDefinition = { optional: true, }, ], - returnType: 'text', + returnType: 'keyword', minParams: 1, }, { @@ -3198,7 +3198,7 @@ const ltrimDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, ], supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'], @@ -3475,7 +3475,7 @@ const mvAppendDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -3920,7 +3920,7 @@ const mvDedupeDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -4067,7 +4067,7 @@ const mvFirstDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -4224,7 +4224,7 @@ const mvLastDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -4341,7 +4341,7 @@ const mvMaxDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -4583,7 +4583,7 @@ const mvMinDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -5054,7 +5054,7 @@ const mvSliceDefinition: FunctionDefinition = { optional: true, }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -5221,7 +5221,7 @@ const mvSortDefinition: FunctionDefinition = { acceptedValues: ['asc', 'desc'], }, ], - returnType: 'text', + returnType: 'keyword', }, { params: [ @@ -6131,7 +6131,7 @@ const reverseDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, ], supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'], @@ -6323,7 +6323,7 @@ const rtrimDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, ], supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'], @@ -8597,7 +8597,7 @@ const toLowerDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, ], supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'], @@ -8995,7 +8995,7 @@ const toUpperDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, ], supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'], @@ -9077,7 +9077,7 @@ const trimDefinition: FunctionDefinition = { optional: false, }, ], - returnType: 'text', + returnType: 'keyword', }, ], supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'], diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/helpers.ts index 867c68ab4f1df..2b50c9da541ce 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/helpers.ts @@ -56,14 +56,13 @@ function handleAdditionalArgs( } export function getCommandSignature( - { name, signature, options, examples }: CommandDefinition, + { name, signature, options, examples }: CommandDefinition, { withTypes }: { withTypes: boolean } = { withTypes: true } ) { return { - declaration: `${name.toUpperCase()} ${printCommandArguments( - signature, - withTypes - )} ${options.map( + declaration: `${name.toUpperCase()} ${printCommandArguments(signature, withTypes)} ${( + options || [] + ).map( (option) => `${ option.wrapped ? option.wrapped[0] : '' @@ -76,7 +75,7 @@ export function getCommandSignature( } function printCommandArguments( - { multipleParams, params }: CommandDefinition['signature'], + { multipleParams, params }: CommandDefinition['signature'], withTypes: boolean ): string { return `${params.map((arg) => printCommandArgument(arg, withTypes)).join(', `')}${ @@ -87,7 +86,7 @@ function printCommandArguments( } function printCommandArgument( - param: CommandDefinition['signature']['params'][number], + param: CommandDefinition['signature']['params'][number], withTypes: boolean ): string { if (!withTypes) { diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts index 31d443a8cbb2b..87c91ddaabaa0 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts @@ -38,16 +38,6 @@ export const metadataOption: CommandOptionsDefinition = { skipCommonValidation: true, validate: (option, command, references) => { const messages: ESQLMessage[] = []; - // need to test the parent command here - if (/\[metadata/i.test(command.text)) { - messages.push( - getMessageFromId({ - messageId: 'metadataBracketsDeprecation', - values: {}, - locations: option.location, - }) - ); - } const fields = option.args.filter(isColumnItem); const metadataFieldsAvailable = references as unknown as Set; if (metadataFieldsAvailable.size > 0) { diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts index dee08766745df..a83908b41617f 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts @@ -8,6 +8,7 @@ */ import type { ESQLCommand, ESQLCommandOption, ESQLFunction, ESQLMessage } from '@kbn/esql-ast'; +import { GetColumnsByTypeFn, SuggestionRawDefinition } from '../autocomplete/types'; /** * All supported field types in ES|QL. This is all the types @@ -158,14 +159,21 @@ export interface FunctionDefinition { validate?: (fnDef: ESQLFunction) => ESQLMessage[]; } -export interface CommandBaseDefinition { - name: string; +export interface CommandBaseDefinition { + name: CommandName; alias?: string; description: string; /** * Whether to show or hide in autocomplete suggestion list */ hidden?: boolean; + suggest?: ( + innerText: string, + command: ESQLCommand, + getColumnsByType: GetColumnsByTypeFn, + columnExists: (column: string) => boolean + ) => Promise; + /** @deprecated this property will disappear in the future */ signature: { multipleParams: boolean; // innerTypes here is useful to drill down the type in case of "column" @@ -183,7 +191,8 @@ export interface CommandBaseDefinition { }; } -export interface CommandOptionsDefinition extends CommandBaseDefinition { +export interface CommandOptionsDefinition + extends CommandBaseDefinition { wrapped?: string[]; optional: boolean; skipCommonValidation?: boolean; @@ -201,12 +210,15 @@ export interface CommandModeDefinition { prefix?: string; } -export interface CommandDefinition extends CommandBaseDefinition { - options: CommandOptionsDefinition[]; +export interface CommandDefinition + extends CommandBaseDefinition { examples: string[]; validate?: (option: ESQLCommand) => ESQLMessage[]; - modes: CommandModeDefinition[]; hasRecommendedQueries?: boolean; + /** @deprecated this property will disappear in the future */ + modes: CommandModeDefinition[]; + /** @deprecated this property will disappear in the future */ + options: CommandOptionsDefinition[]; } export interface Literals { diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts index 0078e0fac119c..b5f14ecfd0227 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts @@ -9,7 +9,7 @@ import { parse } from '@kbn/esql-ast'; import { getExpressionType, shouldBeQuotedSource } from './helpers'; -import { SupportedDataType } from '../definitions/types'; +import type { SupportedDataType } from '../definitions/types'; import { setTestFunctions } from './test_functions'; describe('shouldBeQuotedSource', () => { @@ -225,79 +225,47 @@ describe('getExpressionType', () => { }); it('detects the return type of a function', () => { - expect( - getExpressionType(getASTForExpression('returns_keyword()'), new Map(), new Map()) - ).toBe('keyword'); + expect(getExpressionType(getASTForExpression('returns_keyword()'))).toBe('keyword'); }); it('selects the correct signature based on the arguments', () => { - expect(getExpressionType(getASTForExpression('test("foo")'), new Map(), new Map())).toBe( - 'keyword' - ); - expect(getExpressionType(getASTForExpression('test(1.)'), new Map(), new Map())).toBe( - 'double' - ); - expect(getExpressionType(getASTForExpression('test(1., "foo")'), new Map(), new Map())).toBe( - 'long' - ); + expect(getExpressionType(getASTForExpression('test("foo")'))).toBe('keyword'); + expect(getExpressionType(getASTForExpression('test(1.)'))).toBe('double'); + expect(getExpressionType(getASTForExpression('test(1., "foo")'))).toBe('long'); }); it('supports nested functions', () => { expect( - getExpressionType( - getASTForExpression('test(1., test(test(test(returns_keyword()))))'), - new Map(), - new Map() - ) + getExpressionType(getASTForExpression('test(1., test(test(test(returns_keyword()))))')) ).toBe('long'); }); it('supports functions with casted results', () => { - expect( - getExpressionType(getASTForExpression('test(1.)::keyword'), new Map(), new Map()) - ).toBe('keyword'); + expect(getExpressionType(getASTForExpression('test(1.)::keyword'))).toBe('keyword'); }); it('handles nulls and string-date casting', () => { - expect(getExpressionType(getASTForExpression('test(NULL)'), new Map(), new Map())).toBe( - 'null' - ); - expect(getExpressionType(getASTForExpression('test(NULL, NULL)'), new Map(), new Map())).toBe( - 'null' - ); - expect( - getExpressionType(getASTForExpression('accepts_dates("", "")'), new Map(), new Map()) - ).toBe('keyword'); + expect(getExpressionType(getASTForExpression('test(NULL)'))).toBe('null'); + expect(getExpressionType(getASTForExpression('test(NULL, NULL)'))).toBe('null'); + expect(getExpressionType(getASTForExpression('accepts_dates("", "")'))).toBe('keyword'); }); it('deals with functions that do not exist', () => { - expect(getExpressionType(getASTForExpression('does_not_exist()'), new Map(), new Map())).toBe( - 'unknown' - ); + expect(getExpressionType(getASTForExpression('does_not_exist()'))).toBe('unknown'); }); it('deals with bad function invocations', () => { - expect( - getExpressionType(getASTForExpression('test(1., "foo", "bar")'), new Map(), new Map()) - ).toBe('unknown'); + expect(getExpressionType(getASTForExpression('test(1., "foo", "bar")'))).toBe('unknown'); - expect(getExpressionType(getASTForExpression('test()'), new Map(), new Map())).toBe( - 'unknown' - ); + expect(getExpressionType(getASTForExpression('test()'))).toBe('unknown'); - expect(getExpressionType(getASTForExpression('test("foo", 1.)'), new Map(), new Map())).toBe( - 'unknown' - ); + expect(getExpressionType(getASTForExpression('test("foo", 1.)'))).toBe('unknown'); }); it('deals with the CASE function', () => { - expect(getExpressionType(getASTForExpression('CASE(true, 1, 2)'), new Map(), new Map())).toBe( - 'integer' - ); + expect(getExpressionType(getASTForExpression('CASE(true, 1, 2)'))).toBe('integer'); - expect( - getExpressionType(getASTForExpression('CASE(true, 1., true, 1., 2.)'), new Map(), new Map()) - ).toBe('double'); + expect(getExpressionType(getASTForExpression('CASE(true, 1., true, 1., 2.)'))).toBe('double'); expect( getExpressionType( @@ -306,6 +274,20 @@ describe('getExpressionType', () => { new Map() ) ).toBe('keyword'); + + expect( + getExpressionType( + getASTForExpression('CASE(true, "", true, "", keywordVar)'), + new Map(), + new Map([ + [`keywordVar`, [{ name: 'keywordVar', type: 'keyword', location: { min: 0, max: 0 } }]], + ]) + ) + ).toBe('keyword'); + }); + + it('supports COUNT(*)', () => { + expect(getExpressionType(getASTForExpression('COUNT(*)'))).toBe('long'); }); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts index 2392a44814997..02dff9720cd9b 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts @@ -132,7 +132,7 @@ export function isSourceCommand({ label }: { label: string }) { } let fnLookups: Map | undefined; -let commandLookups: Map | undefined; +let commandLookups: Map> | undefined; function buildFunctionLookup() { // we always refresh if we have test functions @@ -197,7 +197,7 @@ export function getFunctionDefinition(name: string) { const unwrapStringLiteralQuotes = (value: string) => value.slice(1, -1); -function buildCommandLookup() { +function buildCommandLookup(): Map> { if (!commandLookups) { commandLookups = commandDefinitions.reduce((memo, def) => { memo.set(def.name, def); @@ -205,12 +205,12 @@ function buildCommandLookup() { memo.set(def.alias, def); } return memo; - }, new Map()); + }, new Map>()); } - return commandLookups; + return commandLookups!; } -export function getCommandDefinition(name: string): CommandDefinition { +export function getCommandDefinition(name: string): CommandDefinition { return buildCommandLookup().get(name.toLowerCase())!; } @@ -218,7 +218,7 @@ export function getAllCommands() { return Array.from(buildCommandLookup().values()); } -export function getCommandOption(optionName: CommandOptionsDefinition['name']) { +export function getCommandOption(optionName: CommandOptionsDefinition['name']) { return [byOption, metadataOption, asOption, onOption, withOption, appendSeparatorOption].find( ({ name }) => name === optionName ); @@ -815,15 +815,31 @@ export function getExpressionType( return 'unknown'; } + /** + * Special case for COUNT(*) because + * the "*" column doesn't match any + * of COUNT's function definitions + */ + if ( + fnDefinition.name === 'count' && + root.args[0] && + isColumnItem(root.args[0]) && + root.args[0].name === '*' + ) { + return 'long'; + } + if (fnDefinition.name === 'case' && root.args.length) { - // The CASE function doesn't fit our system of function definitions - // and needs special handling. This is imperfect, but it's a start because - // at least we know that the final argument to case will never be a conditional - // expression, always a result expression. - // - // One problem with this is that if a false case is not provided, the return type - // will be null, which we aren't detecting. But this is ok because we consider - // variables and fields to be nullable anyways and account for that during validation. + /** + * The CASE function doesn't fit our system of function definitions + * and needs special handling. This is imperfect, but it's a start because + * at least we know that the final argument to case will never be a conditional + * expression, always a result expression. + * + * One problem with this is that if a false case is not provided, the return type + * will be null, which we aren't detecting. But this is ok because we consider + * variables and fields to be nullable anyways and account for that during validation. + */ return getExpressionType(root.args[root.args.length - 1], fields, variables); } diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/resources_helpers.ts b/packages/kbn-esql-validation-autocomplete/src/shared/resources_helpers.ts index a4da3907a4d6b..5e7d951d8bdbf 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/resources_helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/resources_helpers.ts @@ -36,7 +36,7 @@ export function getFieldsByTypeHelper(queryText: string, resourceRetriever?: ESQ const getFields = async () => { const metadata = await getEcsMetadata(); if (!cacheFields.size && queryText) { - const fieldsOfType = await resourceRetriever?.getFieldsFor?.({ query: queryText }); + const fieldsOfType = await resourceRetriever?.getColumnsFor?.({ query: queryText }); const fieldsWithMetadata = enrichFieldsWithECSInfo(fieldsOfType || [], metadata); for (const field of fieldsWithMetadata || []) { cacheFields.set(field.name, field); diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/types.ts b/packages/kbn-esql-validation-autocomplete/src/shared/types.ts index bc1e1d337e4b3..1caa2c480864e 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/types.ts @@ -39,7 +39,7 @@ export interface ESQLSourceResult { export interface ESQLCallbacks { getSources?: CallbackFn<{}, ESQLSourceResult>; - getFieldsFor?: CallbackFn<{ query: string }, ESQLRealField>; + getColumnsFor?: CallbackFn<{ query: string }, ESQLRealField>; getPolicies?: CallbackFn< {}, { name: string; sourceIndices: string[]; matchField: string; enrichFields: string[] } diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/callbacks.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/callbacks.test.ts index aaa7a3d88f5ca..61c0455fa1b0d 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/callbacks.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/callbacks.test.ts @@ -19,7 +19,7 @@ describe('FROM', () => { await validate('SHOW'); await validate('ROW \t'); - expect(callbacks.getFieldsFor.mock.calls.length).toBe(0); + expect(callbacks.getColumnsFor.mock.calls.length).toBe(0); }); test('loads fields with FROM source when commands after pipe present', async () => { @@ -27,6 +27,6 @@ describe('FROM', () => { await validate('FROM kibana_ecommerce METADATA _id | eval'); - expect(callbacks.getFieldsFor.mock.calls.length).toBe(1); + expect(callbacks.getColumnsFor.mock.calls.length).toBe(1); }); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.from.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.from.ts index 491c44fe699df..2a316cdb7a2e9 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.from.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.from.ts @@ -106,7 +106,7 @@ export const validationFromCommandTestSuite = (setup: helpers.Setup) => { await expectErrors('from index metadata _id, \t\n _index\n ', []); }); - test('errors when wrapped in brackets', async () => { + test('errors when wrapped in parentheses', async () => { const { expectErrors } = await setup(); await expectErrors(`from index (metadata _id)`, [ @@ -114,65 +114,20 @@ export const validationFromCommandTestSuite = (setup: helpers.Setup) => { ]); }); - for (const isWrapped of [true, false]) { - function setWrapping(option: string) { - return isWrapped ? `[${option}]` : option; - } - - function addBracketsWarning() { - return isWrapped - ? ["Square brackets '[]' need to be removed from FROM METADATA declaration"] - : []; - } - - describe(`wrapped = ${isWrapped}`, () => { - test('no errors on correct usage, waning on square brackets', async () => { - const { expectErrors } = await setup(); - - await expectErrors(`from index ${setWrapping('METADATA _id')}`, []); - await expectErrors( - `from index ${setWrapping('METADATA _id')}`, - [], - addBracketsWarning() - ); - await expectErrors( - `from index ${setWrapping('metadata _id')}`, - [], - addBracketsWarning() - ); - await expectErrors( - `from index ${setWrapping('METADATA _id, _source')}`, - [], - addBracketsWarning() - ); - }); - - test('validates fields', async () => { - const { expectErrors } = await setup(); - - await expectErrors( - `from index ${setWrapping('METADATA _id, _source2')}`, - [ - `Metadata field [_source2] is not available. Available metadata fields are: [${METADATA_FIELDS.join( - ', ' - )}]`, - ], - addBracketsWarning() - ); - await expectErrors( - `from index ${setWrapping('metadata _id, _source')} ${setWrapping( - 'METADATA _id2' - )}`, - [ - isWrapped - ? "SyntaxError: mismatched input '[' expecting " - : "SyntaxError: mismatched input 'METADATA' expecting ", - ], - addBracketsWarning() - ); - }); + describe('validates fields', () => { + test('validates fields', async () => { + const { expectErrors } = await setup(); + + await expectErrors(`from index METADATA _id, _source2`, [ + `Metadata field [_source2] is not available. Available metadata fields are: [${METADATA_FIELDS.join( + ', ' + )}]`, + ]); + await expectErrors(`from index metadata _id, _source METADATA _id2`, [ + "SyntaxError: mismatched input 'METADATA' expecting ", + ]); }); - } + }); }); }); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.ccs.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.ccs.test.ts index 5cdb83be618d1..81e54b0b5cf1a 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.ccs.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.ccs.test.ts @@ -24,33 +24,13 @@ describe('validation', () => { }); describe('... METADATA ', () => { - for (const isWrapped of [true, false]) { - function setWrapping(option: string) { - return isWrapped ? `[${option}]` : option; - } - - function addBracketsWarning() { - return isWrapped - ? ["Square brackets '[]' need to be removed from FROM METADATA declaration"] - : []; - } - - describe(`wrapped = ${isWrapped}`, () => { - test('no errors on correct usage, waning on square brackets', async () => { - const { expectErrors } = await setup(); - await expectErrors( - `from remote-ccs:indexes ${setWrapping('METADATA _id')}`, - ['Unknown index [remote-ccs:indexes]'], - addBracketsWarning() - ); - await expectErrors( - `from *:indexes ${setWrapping('METADATA _id')}`, - ['Unknown index [*:indexes]'], - addBracketsWarning() - ); - }); - }); - } + test('no errors on correct usage', async () => { + const { expectErrors } = await setup(); + await expectErrors(`from remote-ccs:indexes METADATA _id`, [ + 'Unknown index [remote-ccs:indexes]', + ]); + await expectErrors(`from *:indexes METADATA _id`, ['Unknown index [*:indexes]']); + }); }); }); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json index c66aaadf98df8..25fb880da5ff0 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json +++ b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json @@ -9947,83 +9947,19 @@ ], "warning": [] }, - { - "query": "from index [METADATA _id]", - "error": [], - "warning": [] - }, - { - "query": "from index [METADATA _id]", - "error": [], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] - }, - { - "query": "from index [metadata _id]", - "error": [], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] - }, - { - "query": "from index [METADATA _id, _source]", - "error": [], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] - }, - { - "query": "from index [METADATA _id, _source2]", - "error": [ - "Metadata field [_source2] is not available. Available metadata fields are: [_version, _id, _index, _source, _ignored]" - ], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] - }, - { - "query": "from index [metadata _id, _source] [METADATA _id2]", - "error": [ - "SyntaxError: mismatched input '[' expecting " - ], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] - }, - { - "query": "from index METADATA _id", - "error": [], - "warning": [] - }, - { - "query": "from index METADATA _id", - "error": [], - "warning": [] - }, - { - "query": "from index metadata _id", - "error": [], - "warning": [] - }, - { - "query": "from index METADATA _id, _source", - "error": [], - "warning": [] - }, { "query": "from index METADATA _id, _source2", "error": [ - "Metadata field [_source2] is not available. Available metadata fields are: [_version, _id, _index, _source, _ignored]" + "Metadata field [_source2] is not available. Available metadata fields are: [_version, _id, _index, _source, _ignored, _index_mode]" ], "warning": [] }, { - "query": "from index metadata _id, _source METADATA _id2", + "query": "from index METADATA _id, _source METADATA _id2", "error": [ "SyntaxError: mismatched input 'METADATA' expecting " ], "warning": [] } ] -} \ No newline at end of file +} diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index fae4ca16797cc..e6546ec996547 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -1532,7 +1532,7 @@ describe('validation logic', () => { it(`should not fetch source and fields list when a row command is set`, async () => { const callbackMocks = getCallbackMocks(); await validateQuery(`row a = 1 | eval a`, getAstAndSyntaxErrors, undefined, callbackMocks); - expect(callbackMocks.getFieldsFor).not.toHaveBeenCalled(); + expect(callbackMocks.getColumnsFor).not.toHaveBeenCalled(); expect(callbackMocks.getSources).not.toHaveBeenCalled(); }); @@ -1545,7 +1545,7 @@ describe('validation logic', () => { it(`should not fetch source and fields for empty command`, async () => { const callbackMocks = getCallbackMocks(); await validateQuery(` `, getAstAndSyntaxErrors, undefined, callbackMocks); - expect(callbackMocks.getFieldsFor).not.toHaveBeenCalled(); + expect(callbackMocks.getColumnsFor).not.toHaveBeenCalled(); expect(callbackMocks.getSources).not.toHaveBeenCalled(); }); @@ -1559,8 +1559,8 @@ describe('validation logic', () => { ); expect(callbackMocks.getSources).not.toHaveBeenCalled(); expect(callbackMocks.getPolicies).toHaveBeenCalled(); - expect(callbackMocks.getFieldsFor).toHaveBeenCalledTimes(1); - expect(callbackMocks.getFieldsFor).toHaveBeenLastCalledWith({ + expect(callbackMocks.getColumnsFor).toHaveBeenCalledTimes(1); + expect(callbackMocks.getColumnsFor).toHaveBeenLastCalledWith({ query: `from enrich_index | keep otherField, yetAnotherField`, }); }); @@ -1575,8 +1575,8 @@ describe('validation logic', () => { ); expect(callbackMocks.getSources).not.toHaveBeenCalled(); expect(callbackMocks.getPolicies).not.toHaveBeenCalled(); - expect(callbackMocks.getFieldsFor).toHaveBeenCalledTimes(1); - expect(callbackMocks.getFieldsFor).toHaveBeenLastCalledWith({ + expect(callbackMocks.getColumnsFor).toHaveBeenCalledTimes(1); + expect(callbackMocks.getColumnsFor).toHaveBeenLastCalledWith({ query: 'show info', }); }); @@ -1591,8 +1591,8 @@ describe('validation logic', () => { ); expect(callbackMocks.getSources).toHaveBeenCalled(); expect(callbackMocks.getPolicies).toHaveBeenCalled(); - expect(callbackMocks.getFieldsFor).toHaveBeenCalledTimes(2); - expect(callbackMocks.getFieldsFor).toHaveBeenLastCalledWith({ + expect(callbackMocks.getColumnsFor).toHaveBeenCalledTimes(2); + expect(callbackMocks.getColumnsFor).toHaveBeenLastCalledWith({ query: `from enrich_index | keep otherField, yetAnotherField`, }); }); @@ -1604,7 +1604,7 @@ describe('validation logic', () => { getAstAndSyntaxErrors, undefined, { - getFieldsFor: undefined, + getColumnsFor: undefined, getSources: undefined, getPolicies: undefined, } @@ -1718,7 +1718,7 @@ describe('validation logic', () => { const contentByCallback = { getSources: /Unknown index/, getPolicies: /Unknown policy/, - getFieldsFor: /Unknown column|Argument of|it is unsupported or not indexed/, + getColumnsFor: /Unknown column|Argument of|it is unsupported or not indexed/, getPreferences: /Unknown/, getFieldsMetadata: /Unknown/, }; @@ -1741,7 +1741,7 @@ describe('validation logic', () => { it('should basically work when all callbacks are passed', async () => { const allErrors = await Promise.all( fixtures.testCases - .filter(({ query }) => query === 'from index [METADATA _id, _source2]') + .filter(({ query }) => query === 'from index METADATA _id, _source2') .map(({ query }) => validateQuery( query, @@ -1753,7 +1753,7 @@ describe('validation logic', () => { ); for (const [index, { errors }] of Object.entries(allErrors)) { expect(errors.map((e) => ('severity' in e ? e.message : e.text))).toEqual( - fixtures.testCases.filter(({ query }) => query === 'from index [METADATA _id, _source2]')[ + fixtures.testCases.filter(({ query }) => query === 'from index METADATA _id, _source2')[ Number(index) ].error ); @@ -1761,7 +1761,7 @@ describe('validation logic', () => { }); // test excluding one callback at the time - it.each(['getSources', 'getFieldsFor', 'getPolicies'] as Array)( + it.each(['getSources', 'getColumnsFor', 'getPolicies'] as Array)( `should not error if %s is missing`, async (excludedCallback) => { const filteredTestCases = fixtures.testCases.filter((t) => @@ -1790,7 +1790,7 @@ describe('validation logic', () => { ); it('should work if no callback passed', async () => { - const excludedCallbacks = ['getSources', 'getPolicies', 'getFieldsFor'] as Array< + const excludedCallbacks = ['getSources', 'getPolicies', 'getColumnsFor'] as Array< keyof typeof ignoreErrorsMap >; for (const testCase of fixtures.testCases.filter((t) => diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts index 9605da8460eed..111fe79b3f5e0 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -1074,7 +1074,7 @@ function validateUnsupportedTypeFields(fields: Map) { } export const ignoreErrorsMap: Record = { - getFieldsFor: ['unknownColumn', 'wrongArgumentType', 'unsupportedFieldType'], + getColumnsFor: ['unknownColumn', 'wrongArgumentType', 'unsupportedFieldType'], getSources: ['unknownIndex'], getPolicies: ['unknownPolicy'], getPreferences: [], diff --git a/packages/kbn-flot-charts/lib/jquery_flot.js b/packages/kbn-flot-charts/lib/jquery_flot.js index 50524fd8f4926..3b13b317c616c 100644 --- a/packages/kbn-flot-charts/lib/jquery_flot.js +++ b/packages/kbn-flot-charts/lib/jquery_flot.js @@ -1,6 +1,8 @@ /* JavaScript plotting library for jQuery, version 0.8.3. + Copyright (c) 2007-2014 IOLA and Ole Laursen. Licensed under the MIT license. + */ // first an inline dependency, jquery.colorhelpers.js, we inline it here @@ -27,602 +29,482 @@ Licensed under the MIT license. * V. 1.1: Fix error handling so e.g. parsing an empty string does * produce a color rather than just crashing. */ - (function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return valuemax?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery); // the actual Flot code -/* Javascript plotting library for jQuery, version 0.9.0-alpha. - -Copyright (c) 2007-2013 IOLA and Ole Laursen. -Licensed under the MIT license. - -*/ - (function($) { - // A jquery-esque isNumeric method since we currently support 1.4.4 - // and $.isNumeric was introduced on in 1.7 - var isNumeric = $.isNumeric || function(obj) { - return obj - parseFloat( obj ) >= 0; - }; - - /** - * The Canvas object is a wrapper around an HTML5 tag. - * - * @constructor - * @param {string} cls List of classes to apply to the canvas. - * @param {element} container Element onto which to append the canvas. - * - * Requiring a container is a little iffy, but unfortunately canvas - * operations don't work unless the canvas is attached to the DOM. - */ - function Canvas(cls, container) { - - var element = container.children("." + cls)[0]; + // Cache the prototype hasOwnProperty for faster access - if (element == null) { + var hasOwnProperty = Object.prototype.hasOwnProperty; - element = document.createElement("canvas"); - element.className = cls; + // A shim to provide 'detach' to jQuery versions prior to 1.4. Using a DOM + // operation produces the same effect as detach, i.e. removing the element + // without touching its jQuery data. - $(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 }) - .appendTo(container); + // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+. - // If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas - - if (!element.getContext) { - if (window.G_vmlCanvasManager) { - element = window.G_vmlCanvasManager.initElement(element); - } else { - throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode."); + if (!$.fn.detach) { + $.fn.detach = function() { + return this.each(function() { + if (this.parentNode) { + this.parentNode.removeChild( this ); } - } - } - - this.element = element; - - var context = this.context = element.getContext("2d"); - - // Determine the screen's ratio of physical to device-independent - // pixels. This is the ratio between the canvas width that the browser - // advertises and the number of pixels actually present in that space. - - // The iPhone 4, for example, has a device-independent width of 320px, - // but its screen is actually 640px wide. It therefore has a pixel - // ratio of 2, while most normal devices have a ratio of 1. - - var devicePixelRatio = window.devicePixelRatio || 1, - backingStoreRatio = - context.webkitBackingStorePixelRatio || - context.mozBackingStorePixelRatio || - context.msBackingStorePixelRatio || - context.oBackingStorePixelRatio || - context.backingStorePixelRatio || 1; - - this.pixelRatio = devicePixelRatio / backingStoreRatio; - - // Size the canvas to match the internal dimensions of its container - - this.resize(container.width(), container.height()); - - // Collection of HTML div layers for text overlaid onto the canvas - - this.textContainer = null; - this.text = {}; - - // Cache of text fragments and metrics, so we can avoid expensively - // re-calculating them when the plot is re-rendered in a loop. - - this._textCache = {}; + }); + }; } - /** - * Resizes the canvas to the given dimensions. - * - * @param {number} width New width of the canvas, in pixels. - * @param {number} width New height of the canvas, in pixels. - */ - Canvas.prototype.resize = function(width, height) { - - if (width <= 0 || height <= 0) { - throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height); - } - - var element = this.element, - context = this.context, - pixelRatio = this.pixelRatio; - - // Resize the canvas, increasing its density based on the display's - // pixel ratio; basically giving it more pixels without increasing the - // size of its element, to take advantage of the fact that retina - // displays have that many more pixels in the same advertised space. - - // Resizing should reset the state (excanvas seems to be buggy though) - - if (this.width !== width) { - element.width = width * pixelRatio; - element.style.width = width + "px"; - this.width = width; - } - - if (this.height !== height) { - element.height = height * pixelRatio; - element.style.height = height + "px"; - this.height = height; - } - - // Save the context, so we can reset in case we get replotted. The - // restore ensure that we're really back at the initial state, and - // should be safe even if we haven't saved the initial state yet. - - context.restore(); - context.save(); - - // Scale the coordinate space to match the display density; so even though we - // may have twice as many pixels, we still want lines and other drawing to - // appear at the same size; the extra pixels will just make them crisper. - - context.scale(pixelRatio, pixelRatio); - }; - - /** - * Clears the entire canvas area, not including any overlaid HTML text - */ - Canvas.prototype.clear = function() { - this.context.clearRect(0, 0, this.width, this.height); - }; - - /** - * Finishes rendering the canvas, including managing the text overlay. - */ - Canvas.prototype.render = function() { - - var cache = this._textCache; - - // For each text layer, add elements marked as active that haven't - // already been rendered, and remove those that are no longer active. - - for (var layerKey in cache) { - if (Object.prototype.hasOwnProperty.call(cache, layerKey)) { - - var layer = this.getTextLayer(layerKey), - layerCache = cache[layerKey]; - - layer.hide(); - - for (var styleKey in layerCache) { - if (Object.prototype.hasOwnProperty.call(layerCache, styleKey)) { - var styleCache = layerCache[styleKey]; - for (var angleKey in styleCache) { - if (Object.prototype.hasOwnProperty.call(styleCache, angleKey)) { - var angleCache = styleCache[angleKey]; - for (var key in angleCache) { - if (Object.prototype.hasOwnProperty.call(angleCache, key)) { - - var positions = angleCache[key].positions; - - for (var i = 0, position; position = positions[i]; i++) { - if (position.active) { - if (!position.rendered) { - layer.append(position.element); - position.rendered = true; - } - } else { - positions.splice(i--, 1); - if (position.rendered) { - position.element.detach(); - } - } - } - - if (positions.length === 0) { - delete angleCache[key]; - } - } - } - } - } - } - } - - layer.show(); - } - } - }; - - /** - * Creates (if necessary) and returns the text overlay container. - * - * @param {string} classes String of space-separated CSS classes used to - * uniquely identify the text layer. - * @return {object} The jQuery-wrapped text-layer div. - */ - Canvas.prototype.getTextLayer = function(classes) { - - var layer = this.text[classes]; - - // Create the text layer if it doesn't exist - - if (layer == null) { - - // Create the text layer container, if it doesn't exist - - if (this.textContainer == null) { - this.textContainer = $("
") - .css({ - position: "absolute", - top: 0, - left: 0, - bottom: 0, - right: 0, - "font-size": "smaller", - color: "#545454" - }) - .insertAfter(this.element); - } - - layer = this.text[classes] = $("
") - .addClass(classes) - .css({ - position: "absolute", - top: 0, - left: 0, - bottom: 0, - right: 0 - }) - .appendTo(this.textContainer); - } + /////////////////////////////////////////////////////////////////////////// + // The Canvas object is a wrapper around an HTML5 tag. + // + // @constructor + // @param {string} cls List of classes to apply to the canvas. + // @param {element} container Element onto which to append the canvas. + // + // Requiring a container is a little iffy, but unfortunately canvas + // operations don't work unless the canvas is attached to the DOM. - return layer; - }; + function Canvas(cls, container) { - /** - * Creates (if necessary) and returns a text info object. - * - * The object looks like this: - * - * { - * width: Width of the text's wrapper div. - * height: Height of the text's wrapper div. - * element: The jQuery-wrapped HTML div containing the text. - * positions: Array of positions at which this text is drawn. - * } - * - * The positions array contains objects that look like this: - * - * { - * active: Flag indicating whether the text should be visible. - * rendered: Flag indicating whether the text is currently visible. - * element: The jQuery-wrapped HTML div containing the text. - * x: X coordinate at which to draw the text. - * y: Y coordinate at which to draw the text. - * } - * - * Each position after the first receives a clone of the original element. - * - * The idea is that that the width, height, and general 'identity' of the - * text is constant no matter where it is placed; the placements are a - * secondary property. - * - * Canvas maintains a cache of recently-used text info objects; getTextInfo - * either returns the cached element or creates a new entry. - * - * @param {string} layer A string of space-separated CSS classes uniquely - * identifying the layer containing this text. - * @param {string} text Text string to retrieve info for. - * @param {(string|object)=} font Either a string of space-separated CSS - * classes or a font-spec object, defining the text's font and style. - * @param {number=} angle Angle at which to rotate the text, in degrees. - * @param {number=} width Maximum width of the text before it wraps. - * @return {object} a text info object. - */ - Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) { - - var textStyle, layerCache, styleCache, angleCache, info; - - text = "" + text; // Cast to string in case we have a number or such - angle = (360 + (angle || 0)) % 360; // Normalize the angle to 0...359 - - // If the font is a font-spec object, generate a CSS font definition - - if (typeof font === "object") { - textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family; - } else { - textStyle = font; - } + var element = container.children("." + cls)[0]; - // Retrieve or create the caches for the text's layer, style, and angle + if (element == null) { - layerCache = this._textCache[layer]; - if (layerCache == null) { - layerCache = this._textCache[layer] = {}; - } + element = document.createElement("canvas"); + element.className = cls; - styleCache = layerCache[textStyle]; - if (styleCache == null) { - styleCache = layerCache[textStyle] = {}; - } + $(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 }) + .appendTo(container); - angleCache = styleCache[angle]; - if (angleCache == null) { - angleCache = styleCache[angle] = {}; - } + // If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas - info = angleCache[text]; + if (!element.getContext) { + if (window.G_vmlCanvasManager) { + element = window.G_vmlCanvasManager.initElement(element); + } else { + throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode."); + } + } + } - // If we can't find a matching element in our cache, create a new one + this.element = element; - if (info == null) { + var context = this.context = element.getContext("2d"); - var element = $("
").html(text) - .css({ - position: "absolute", - "max-width": width, - top: -9999 - }) - .appendTo(this.getTextLayer(layer)); + // Determine the screen's ratio of physical to device-independent + // pixels. This is the ratio between the canvas width that the browser + // advertises and the number of pixels actually present in that space. - if (typeof font === "object") { - element.css({ - font: textStyle, - color: font.color - }); - } else if (typeof font === "string") { - element.addClass(font); - } - - // Save the original dimensions of the text; we'll modify these - // later to take into account rotation, if there is any. - - var textWidth = element.outerWidth(true), - textHeight = element.outerHeight(true); - - // Apply rotation to the text using CSS3/IE matrix transforms - - // Note how we also set the element's width, as a work-around for - // the way most browsers resize the div on rotate, which may cause - // the contents to wrap differently. The extra +1 is because IE - // rounds the width differently and needs a little extra help. - - if (angle) { - - var radians = angle * Math.PI / 180, - sin = Math.sin(radians), - cos = Math.cos(radians), - a = cos.toFixed(6), // Use fixed-point so these don't - b = (-sin).toFixed(6), // show up in scientific notation - c = sin.toFixed(6), // when we add them to the string - transformRule; - - if ($.support.leadingWhitespace) { - - // The transform origin defaults to '50% 50%', producing - // blurry text on some browsers (Chrome) when the width or - // height happens to be odd, making 50% fractional. Avoid - // this by setting the origin to rounded values. - - var cx = textWidth / 2, - cy = textHeight / 2, - transformOrigin = Math.floor(cx) + "px " + Math.floor(cy) + "px"; - - // Transforms alter the div's appearance without changing - // its origin. This will make it difficult to position it - // later, since we'll be positioning the new bounding box - // with respect to the old origin. We can work around this - // by adding a translation to align the new bounding box's - // top-left corner with the origin, using the same matrix. - - // Rather than examining all four points, we can use the - // angle to figure out in advance which two points are in - // the top-left quadrant; we can then use the x-coordinate - // of the first (left-most) point and the y-coordinate of - // the second (top-most) point as the bounding box corner. - - var x, y; - if (angle < 90) { - x = Math.floor(cx * cos + cy * sin - cx); - y = Math.floor(cx * sin + cy * cos - cy); - } else if (angle < 180) { - x = Math.floor(cy * sin - cx * cos - cx); - y = Math.floor(cx * sin - cy * cos - cy); - } else if (angle < 270) { - x = Math.floor(-cx * cos - cy * sin - cx); - y = Math.floor(-cx * sin - cy * cos - cy); - } else { - x = Math.floor(cx * cos - cy * sin - cx); - y = Math.floor(cy * cos - cx * sin - cy); - } - - transformRule = "matrix(" + a + "," + c + "," + b + "," + a + "," + x + "," + y + ")"; - - element.css({ - width: textWidth + 1, - transform: transformRule, - "-o-transform": transformRule, - "-ms-transform": transformRule, - "-moz-transform": transformRule, - "-webkit-transform": transformRule, - "transform-origin": transformOrigin, - "-o-transform-origin": transformOrigin, - "-ms-transform-origin": transformOrigin, - "-moz-transform-origin": transformOrigin, - "-webkit-transform-origin": transformOrigin - }); + // The iPhone 4, for example, has a device-independent width of 320px, + // but its screen is actually 640px wide. It therefore has a pixel + // ratio of 2, while most normal devices have a ratio of 1. - } else { + var devicePixelRatio = window.devicePixelRatio || 1, + backingStoreRatio = + context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; - // The IE7/8 matrix filter produces very ugly aliasing for - // text with a transparent background. Using a solid color - // greatly improves text clarity, although it does result - // in ugly boxes for plots using a non-white background. + this.pixelRatio = devicePixelRatio / backingStoreRatio; - // TODO: Instead of white use the actual background color? - // This still wouldn't solve the problem when the plot has - // a gradient background, but it would at least help. + // Size the canvas to match the internal dimensions of its container - transformRule = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + a + ",sizingMethod='auto expand')"; + this.resize(container.width(), container.height()); - element.css({ - width: textWidth + 1, - filter: transformRule, - "-ms-filter": transformRule, - "background-color": "#fff" - }); - } + // Collection of HTML div layers for text overlaid onto the canvas - // Compute the final dimensions of the text's bounding box + this.textContainer = null; + this.text = {}; - var ac = Math.abs(cos), - as = Math.abs(sin), - originalWidth = textWidth; - textWidth = Math.round(ac * textWidth + as * textHeight); - textHeight = Math.round(as * originalWidth + ac * textHeight); - } + // Cache of text fragments and metrics, so we can avoid expensively + // re-calculating them when the plot is re-rendered in a loop. - info = angleCache[text] = { - width: textWidth, - height: textHeight, - element: element, - positions: [] - }; + this._textCache = {}; + } - element.detach(); - } + // Resizes the canvas to the given dimensions. + // + // @param {number} width New width of the canvas, in pixels. + // @param {number} width New height of the canvas, in pixels. - return info; - }; + Canvas.prototype.resize = function(width, height) { - /** - * Adds a text string to the canvas text overlay. - * - * The text isn't drawn immediately; it is marked as rendering, which will - * result in its addition to the canvas on the next render pass. - * - * @param {string} layer A string of space-separated CSS classes uniquely - * identifying the layer containing this text. - * @param {number} x X coordinate at which to draw the text. - * @param {number} y Y coordinate at which to draw the text. - * @param {string} text Text string to draw. - * @param {(string|object)=} font Either a string of space-separated CSS - * classes or a font-spec object, defining the text's font and style. - * @param {number=} angle Angle at which to rotate the text, in degrees. - * @param {number=} width Maximum width of the text before it wraps. - * @param {string=} halign Horizontal alignment of the text; either "left", - * "center" or "right". - * @param {string=} valign Vertical alignment of the text; either "top", - * "middle" or "bottom". - */ - Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) { - - var info = this.getTextInfo(layer, text, font, angle, width), - positions = info.positions; - - // Tweak the div's position to match the text's alignment - - if (halign === "center") { - x -= info.width / 2; - } else if (halign === "right") { - x -= info.width; - } + if (width <= 0 || height <= 0) { + throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height); + } - if (valign === "middle") { - y -= info.height / 2; - } else if (valign === "bottom") { - y -= info.height; - } + var element = this.element, + context = this.context, + pixelRatio = this.pixelRatio; - // Determine whether this text already exists at this position. - // If so, mark it for inclusion in the next render pass. + // Resize the canvas, increasing its density based on the display's + // pixel ratio; basically giving it more pixels without increasing the + // size of its element, to take advantage of the fact that retina + // displays have that many more pixels in the same advertised space. - for (var i = 0, position; position = positions[i]; i++) { - if (position.x === x && position.y === y) { - position.active = true; - return; - } - } + // Resizing should reset the state (excanvas seems to be buggy though) - // If the text doesn't exist at this position, create a new entry + if (this.width != width) { + element.width = width * pixelRatio; + element.style.width = width + "px"; + this.width = width; + } - // For the very first position we'll re-use the original element, - // while for subsequent ones we'll clone it. + if (this.height != height) { + element.height = height * pixelRatio; + element.style.height = height + "px"; + this.height = height; + } - position = { - active: true, - rendered: false, - element: positions.length ? info.element.clone() : info.element, - x: x, - y: y - }; + // Save the context, so we can reset in case we get replotted. The + // restore ensure that we're really back at the initial state, and + // should be safe even if we haven't saved the initial state yet. - positions.push(position); + context.restore(); + context.save(); - // Move the element to its final position within the container + // Scale the coordinate space to match the display density; so even though we + // may have twice as many pixels, we still want lines and other drawing to + // appear at the same size; the extra pixels will just make them crisper. - position.element.css({ - top: Math.round(y), - left: Math.round(x), - "text-align": halign // In case the text wraps - }); - }; + context.scale(pixelRatio, pixelRatio); + }; - /** - * Removes one or more text strings from the canvas text overlay. - * - * If no parameters are given, all text within the layer is removed. - * - * Note that the text is not immediately removed; it is simply marked as - * inactive, which will result in its removal on the next render pass. - * This avoids the performance penalty for 'clear and redraw' behavior, - * where we potentially get rid of all text on a layer, but will likely - * add back most or all of it later, as when redrawing axes, for example. - * - * @param {string} layer A string of space-separated CSS classes uniquely - * identifying the layer containing this text. - * @param {number=} x X coordinate of the text. - * @param {number=} y Y coordinate of the text. - * @param {string=} text Text string to remove. - * @param {(string|object)=} font Either a string of space-separated CSS - * classes or a font-spec object, defining the text's font and style. - * @param {number=} angle Angle at which the text is rotated, in degrees. - * Angle is currently unused, it will be implemented in the future. - */ - Canvas.prototype.removeText = function(layer, x, y, text, font, angle) { - var i, positions, position; - if (text == null) { - var layerCache = this._textCache[layer]; - if (layerCache != null) { - for (var styleKey in layerCache) { - if (Object.prototype.hasOwnProperty.call(layerCache, styleKey)) { - var styleCache = layerCache[styleKey]; - for (var angleKey in styleCache) { - if (Object.prototype.hasOwnProperty.call(styleCache, angleKey)) { - var angleCache = styleCache[angleKey]; - for (var key in angleCache) { - if (Object.prototype.hasOwnProperty.call(angleCache, key)) { - positions = angleCache[key].positions; - for (i = 0; position = positions[i]; i++) { - position.active = false; - } - } - } - } - } - } - } - } - } else { - positions = this.getTextInfo(layer, text, font, angle).positions; - for (i = 0; position = positions[i]; i++) { - if (position.x === x && position.y === y) { - position.active = false; - } - } - } - }; + // Clears the entire canvas area, not including any overlaid HTML text + + Canvas.prototype.clear = function() { + this.context.clearRect(0, 0, this.width, this.height); + }; + + // Finishes rendering the canvas, including managing the text overlay. + + Canvas.prototype.render = function() { + + var cache = this._textCache; + + // For each text layer, add elements marked as active that haven't + // already been rendered, and remove those that are no longer active. + + for (var layerKey in cache) { + if (hasOwnProperty.call(cache, layerKey)) { + + var layer = this.getTextLayer(layerKey), + layerCache = cache[layerKey]; + + layer.hide(); + + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + + var positions = styleCache[key].positions; + + for (var i = 0, position; position = positions[i]; i++) { + if (position.active) { + if (!position.rendered) { + layer.append(position.element); + position.rendered = true; + } + } else { + positions.splice(i--, 1); + if (position.rendered) { + position.element.detach(); + } + } + } + + if (positions.length == 0) { + delete styleCache[key]; + } + } + } + } + } + + layer.show(); + } + } + }; + + // Creates (if necessary) and returns the text overlay container. + // + // @param {string} classes String of space-separated CSS classes used to + // uniquely identify the text layer. + // @return {object} The jQuery-wrapped text-layer div. + + Canvas.prototype.getTextLayer = function(classes) { + + var layer = this.text[classes]; + + // Create the text layer if it doesn't exist + + if (layer == null) { + + // Create the text layer container, if it doesn't exist + + if (this.textContainer == null) { + this.textContainer = $("
") + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0, + 'font-size': "smaller", + color: "#545454" + }) + .insertAfter(this.element); + } + + layer = this.text[classes] = $("
") + .addClass(classes) + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0 + }) + .appendTo(this.textContainer); + } + + return layer; + }; + + // Creates (if necessary) and returns a text info object. + // + // The object looks like this: + // + // { + // width: Width of the text's wrapper div. + // height: Height of the text's wrapper div. + // element: The jQuery-wrapped HTML div containing the text. + // positions: Array of positions at which this text is drawn. + // } + // + // The positions array contains objects that look like this: + // + // { + // active: Flag indicating whether the text should be visible. + // rendered: Flag indicating whether the text is currently visible. + // element: The jQuery-wrapped HTML div containing the text. + // x: X coordinate at which to draw the text. + // y: Y coordinate at which to draw the text. + // } + // + // Each position after the first receives a clone of the original element. + // + // The idea is that that the width, height, and general 'identity' of the + // text is constant no matter where it is placed; the placements are a + // secondary property. + // + // Canvas maintains a cache of recently-used text info objects; getTextInfo + // either returns the cached element or creates a new entry. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {string} text Text string to retrieve info for. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @return {object} a text info object. + + Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) { + + var textStyle, layerCache, styleCache, info; + + // Cast the value to a string, in case we were given a number or such + + text = "" + text; + + // If the font is a font-spec object, generate a CSS font definition + + if (typeof font === "object") { + textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family; + } else { + textStyle = font; + } + + // Retrieve (or create) the cache for the text's layer and styles + + layerCache = this._textCache[layer]; + + if (layerCache == null) { + layerCache = this._textCache[layer] = {}; + } + + styleCache = layerCache[textStyle]; + + if (styleCache == null) { + styleCache = layerCache[textStyle] = {}; + } + + info = styleCache[text]; + + // If we can't find a matching element in our cache, create a new one + + if (info == null) { + + var element = $("
").text(text) + .css({ + position: "absolute", + 'max-width': width, + top: -9999 + }) + .appendTo(this.getTextLayer(layer)); + + if (typeof font === "object") { + element.css({ + font: textStyle, + color: font.color + }); + } else if (typeof font === "string") { + element.addClass(font); + } + + info = styleCache[text] = { + width: element.outerWidth(true), + height: element.outerHeight(true), + element: element, + positions: [] + }; + + element.detach(); + } + + return info; + }; + + // Adds a text string to the canvas text overlay. + // + // The text isn't drawn immediately; it is marked as rendering, which will + // result in its addition to the canvas on the next render pass. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number} x X coordinate at which to draw the text. + // @param {number} y Y coordinate at which to draw the text. + // @param {string} text Text string to draw. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @param {string=} halign Horizontal alignment of the text; either "left", + // "center" or "right". + // @param {string=} valign Vertical alignment of the text; either "top", + // "middle" or "bottom". + + Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) { + + var info = this.getTextInfo(layer, text, font, angle, width), + positions = info.positions; + + // Tweak the div's position to match the text's alignment + + if (halign == "center") { + x -= info.width / 2; + } else if (halign == "right") { + x -= info.width; + } + + if (valign == "middle") { + y -= info.height / 2; + } else if (valign == "bottom") { + y -= info.height; + } + + // Determine whether this text already exists at this position. + // If so, mark it for inclusion in the next render pass. + + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = true; + return; + } + } + + // If the text doesn't exist at this position, create a new entry + + // For the very first position we'll re-use the original element, + // while for subsequent ones we'll clone it. + + position = { + active: true, + rendered: false, + element: positions.length ? info.element.clone() : info.element, + x: x, + y: y + }; + + positions.push(position); + + // Move the element to its final position within the container + + position.element.css({ + top: Math.round(y), + left: Math.round(x), + 'text-align': halign // In case the text wraps + }); + }; + + // Removes one or more text strings from the canvas text overlay. + // + // If no parameters are given, all text within the layer is removed. + // + // Note that the text is not immediately removed; it is simply marked as + // inactive, which will result in its removal on the next render pass. + // This avoids the performance penalty for 'clear and redraw' behavior, + // where we potentially get rid of all text on a layer, but will likely + // add back most or all of it later, as when redrawing axes, for example. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number=} x X coordinate of the text. + // @param {number=} y Y coordinate of the text. + // @param {string=} text Text string to remove. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which the text is rotated, in degrees. + // Angle is currently unused, it will be implemented in the future. + + Canvas.prototype.removeText = function(layer, x, y, text, font, angle) { + if (text == null) { + var layerCache = this._textCache[layer]; + if (layerCache != null) { + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + var positions = styleCache[key].positions; + for (var i = 0, position; position = positions[i]; i++) { + position.active = false; + } + } + } + } + } + } + } else { + var positions = this.getTextInfo(layer, text, font, angle).positions; + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = false; + } + } + } + }; + + /////////////////////////////////////////////////////////////////////////// + // The top-level container for the entire plot. - /** - * The top-level container for the entire plot. - */ function Plot(placeholder, data_, options_, plugins) { // data is on the form: // [ series1, series2 ... ] @@ -635,7 +517,7 @@ Licensed under the MIT license. colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"], legend: { show: true, - noColumns: 1, // number of colums in legend table + noColumns: 1, // number of columns in legend table labelFormatter: null, // fn: string -> string labelBoxBorderColor: "#ccc", // border color for the little label boxes container: null, // container (as jQuery object) to put legend in, null means default on top of graph @@ -646,45 +528,31 @@ Licensed under the MIT license. sorted: null // default to no legend sorting }, xaxis: { - - show: null, // null = auto-detect, true = always, false = never - position: "bottom", // or "top" - mode: null, // null or "time" - - color: null, // base color, labels, ticks - font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" } - - min: null, // min. value to show, null means set automatically - max: null, // max. value to show, null means set automatically - autoscaleMargin: null, // margin in % to add if auto-setting min/max - - transform: null, // null or f: number -> number to transform axis + show: null, // null = auto-detect, true = always, false = never + position: "bottom", // or "top" + mode: null, // null or "time" + font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" } + color: null, // base color, labels, ticks + tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)" + transform: null, // null or f: number -> number to transform axis inverseTransform: null, // if transform is set, this should be the inverse function - - ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks - tickSize: null, // number or [number, "unit"] - minTickSize: null, // number or [number, "unit"] - tickFormatter: null, // fn: number -> string - tickDecimals: null, // no. of decimals, null means auto - - tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)" - tickLength: null, // size in pixels of ticks, or "full" for whole line - - tickWidth: null, // width of tick labels in pixels - tickHeight: null, // height of tick labels in pixels - tickFont: null, // null or font-spec object (see font, above) - - label: null, // null or an axis label string - labelFont: null, // null or font-spec object (see font, above) - labelPadding: 2, // spacing between the axis and its label - - reserveSpace: null, // whether to reserve space even if axis isn't shown - alignTicksWithAxis: null // axis number or null for no sync + min: null, // min. value to show, null means set automatically + max: null, // max. value to show, null means set automatically + autoscaleMargin: null, // margin in % to add if auto-setting min/max + ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks + tickFormatter: null, // fn: number -> string + labelWidth: null, // size of tick labels in pixels + labelHeight: null, + reserveSpace: null, // whether to reserve space even if axis isn't shown + tickLength: null, // size in pixels of ticks, or "full" for whole line + alignTicksWithAxis: null, // axis number or null for no sync + tickDecimals: null, // no. of decimals, null means auto + tickSize: null, // number or [number, "unit"] + minTickSize: null // number or [number, "unit"] }, yaxis: { - position: "left", // or "right" autoscaleMargin: 0.02, - labelPadding: 2 + position: "left" // or "right" }, xaxes: [], yaxes: [], @@ -695,7 +563,6 @@ Licensed under the MIT license. lineWidth: 2, // in pixels fill: true, fillColor: "#ffffff", - strokeColor: null, symbol: "circle" // or callback }, lines: { @@ -747,26 +614,26 @@ Licensed under the MIT license. }, hooks: {} }, - surface = null, // the canvas for the plot itself - overlay = null, // canvas for interactive stuff on top of plot - eventHolder = null, // jQuery object that events should be bound to - ctx = null, octx = null, - xaxes = [], yaxes = [], - plotOffset = { left: 0, right: 0, top: 0, bottom: 0}, - plotWidth = 0, plotHeight = 0, - hooks = { - processOptions: [], - processRawData: [], - processDatapoints: [], - processOffset: [], - drawBackground: [], - drawSeries: [], - draw: [], - bindEvents: [], - drawOverlay: [], - shutdown: [] - }, - plot = this; + surface = null, // the canvas for the plot itself + overlay = null, // canvas for interactive stuff on top of plot + eventHolder = null, // jQuery object that events should be bound to + ctx = null, octx = null, + xaxes = [], yaxes = [], + plotOffset = { left: 0, right: 0, top: 0, bottom: 0}, + plotWidth = 0, plotHeight = 0, + hooks = { + processOptions: [], + processRawData: [], + processDatapoints: [], + processOffset: [], + drawBackground: [], + drawSeries: [], + draw: [], + bindEvents: [], + drawOverlay: [], + shutdown: [] + }, + plot = this; // public functions plot.setData = setData; @@ -785,11 +652,10 @@ Licensed under the MIT license. }; plot.getData = function () { return series; }; plot.getAxes = function () { - var res = {}; + var res = {}, i; $.each(xaxes.concat(yaxes), function (_, axis) { - if (axis) { - res[axis.direction + (axis.n !== 1 ? axis.n : "") + "axis"] = axis; - } + if (axis) + res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis; }); return res; }; @@ -808,9 +674,26 @@ Licensed under the MIT license. }; }; plot.shutdown = shutdown; + plot.destroy = function () { + shutdown(); + placeholder.removeData("plot").empty(); + + series = []; + options = null; + surface = null; + overlay = null; + eventHolder = null; + ctx = null; + octx = null; + xaxes = []; + yaxes = []; + hooks = null; + highlights = []; + plot = null; + }; plot.resize = function () { - var width = placeholder.width(), - height = placeholder.height(); + var width = placeholder.width(), + height = placeholder.height(); surface.resize(width, height); overlay.resize(width, height); }; @@ -830,9 +713,8 @@ Licensed under the MIT license. function executeHooks(hook, args) { args = [plot].concat(args); - for (var i = 0; i < hook.length; ++i) { + for (var i = 0; i < hook.length; ++i) hook[i].apply(this, args); - } } function initPlugins() { @@ -846,9 +728,8 @@ Licensed under the MIT license. for (var i = 0; i < plugins.length; ++i) { var p = plugins[i]; p.init(plot, classes); - if (p.options) { + if (p.options) $.extend(true, options, p.options); - } } } @@ -862,29 +743,23 @@ Licensed under the MIT license. // not expected behavior; avoid it by replacing them here. if (opts && opts.colors) { - options.colors = opts.colors; + options.colors = opts.colors; } - if (options.xaxis.color == null) { - options.xaxis.color = $.color.parse(options.grid.color).scale("a", 0.22).toString(); - } - if (options.yaxis.color == null) { - options.yaxis.color = $.color.parse(options.grid.color).scale("a", 0.22).toString(); - } + if (options.xaxis.color == null) + options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + if (options.yaxis.color == null) + options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); - if (options.xaxis.tickColor == null) { // grid.tickColor for back-compatibility + if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color; - } - if (options.yaxis.tickColor == null) { // grid.tickColor for back-compatibility + if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color; - } - if (options.grid.borderColor == null) { + if (options.grid.borderColor == null) options.grid.borderColor = options.grid.color; - } - if (options.grid.tickColor == null) { - options.grid.tickColor = $.color.parse(options.grid.color).scale("a", 0.22).toString(); - } + if (options.grid.tickColor == null) + options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString(); // Fill in defaults for axis options, including any unspecified // font-spec fields, if a font-spec was provided. @@ -893,16 +768,16 @@ Licensed under the MIT license. // since the rest of the code assumes that they exist. var i, axisOptions, axisCount, + fontSize = placeholder.css("font-size"), + fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13, fontDefaults = { style: placeholder.css("font-style"), - size: Math.round(0.8 * (+placeholder.css("font-size").replace("px", "") || 13)), + size: Math.round(0.8 * fontSizeDefault), variant: placeholder.css("font-variant"), weight: placeholder.css("font-weight"), family: placeholder.css("font-family") }; - fontDefaults.lineHeight = fontDefaults.size * 1.15; - axisCount = options.xaxes.length || 1; for (i = 0; i < axisCount; ++i) { @@ -911,29 +786,17 @@ Licensed under the MIT license. axisOptions.tickColor = axisOptions.color; } - // Compatibility with markrcote/flot-axislabels - - if (axisOptions) { - if (!axisOptions.label && axisOptions.axisLabel) { - axisOptions.label = axisOptions.axisLabel; - } - if (!axisOptions.labelPadding && axisOptions.axisLabelPadding) { - axisOptions.labelPadding = axisOptions.axisLabelPadding; - } - } - axisOptions = $.extend(true, {}, options.xaxis, axisOptions); options.xaxes[i] = axisOptions; - fontDefaults.color = axisOptions.color; if (axisOptions.font) { axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); - } - if (axisOptions.tickFont || axisOptions.font) { - axisOptions.tickFont = $.extend({}, axisOptions.font || fontDefaults, axisOptions.tickFont); - } - if (axisOptions.label && (axisOptions.labelFont || axisOptions.font)) { - axisOptions.labelFont = $.extend({}, axisOptions.font || fontDefaults, axisOptions.labelFont); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } } } @@ -945,83 +808,72 @@ Licensed under the MIT license. axisOptions.tickColor = axisOptions.color; } - // Compatibility with markrcote/flot-axislabels - - if (axisOptions) { - if (!axisOptions.label && axisOptions.axisLabel) { - axisOptions.label = axisOptions.axisLabel; - } - if (!axisOptions.labelPadding && axisOptions.axisLabelPadding) { - axisOptions.labelPadding = axisOptions.axisLabelPadding; - } - } - axisOptions = $.extend(true, {}, options.yaxis, axisOptions); options.yaxes[i] = axisOptions; - fontDefaults.color = axisOptions.color; if (axisOptions.font) { axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); - } - if (axisOptions.tickFont || axisOptions.font) { - axisOptions.tickFont = $.extend({}, axisOptions.font || fontDefaults, axisOptions.tickFont); - } - if (axisOptions.label && (axisOptions.labelFont || axisOptions.font)) { - axisOptions.labelFont = $.extend({}, axisOptions.font || fontDefaults, axisOptions.labelFont); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } } } // backwards compatibility, to be removed in future - if (options.xaxis.noTicks && options.xaxis.ticks == null) { + if (options.xaxis.noTicks && options.xaxis.ticks == null) options.xaxis.ticks = options.xaxis.noTicks; - } - if (options.yaxis.noTicks && options.yaxis.ticks == null) { + if (options.yaxis.noTicks && options.yaxis.ticks == null) options.yaxis.ticks = options.yaxis.noTicks; - } if (options.x2axis) { options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis); options.xaxes[1].position = "top"; + // Override the inherit to allow the axis to auto-scale + if (options.x2axis.min == null) { + options.xaxes[1].min = null; + } + if (options.x2axis.max == null) { + options.xaxes[1].max = null; + } } if (options.y2axis) { options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis); options.yaxes[1].position = "right"; + // Override the inherit to allow the axis to auto-scale + if (options.y2axis.min == null) { + options.yaxes[1].min = null; + } + if (options.y2axis.max == null) { + options.yaxes[1].max = null; + } } - if (options.grid.coloredAreas) { + if (options.grid.coloredAreas) options.grid.markings = options.grid.coloredAreas; - } - if (options.grid.coloredAreasColor) { + if (options.grid.coloredAreasColor) options.grid.markingsColor = options.grid.coloredAreasColor; - } - if (options.lines) { + if (options.lines) $.extend(true, options.series.lines, options.lines); - } - if (options.points) { + if (options.points) $.extend(true, options.series.points, options.points); - } - if (options.bars) { + if (options.bars) $.extend(true, options.series.bars, options.bars); - } - if (options.shadowSize != null) { + if (options.shadowSize != null) options.series.shadowSize = options.shadowSize; - } - if (options.highlightColor != null) { + if (options.highlightColor != null) options.series.highlightColor = options.highlightColor; - } // save options on axes for future reference - for (i = 0; i < options.xaxes.length; ++i) { + for (i = 0; i < options.xaxes.length; ++i) getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i]; - } - for (i = 0; i < options.yaxes.length; ++i) { + for (i = 0; i < options.yaxes.length; ++i) getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i]; - } // add hooks from options - for (var n in hooks) { - if (options.hooks[n] && options.hooks[n].length) { + for (var n in hooks) + if (options.hooks[n] && options.hooks[n].length) hooks[n] = hooks[n].concat(options.hooks[n]); - } - } executeHooks(hooks.processOptions, [options]); } @@ -1044,9 +896,9 @@ Licensed under the MIT license. $.extend(true, s, d[i]); d[i].data = s.data; - } else { - s.data = d[i]; } + else + s.data = d[i]; res.push(s); } @@ -1055,12 +907,10 @@ Licensed under the MIT license. function axisNumber(obj, coord) { var a = obj[coord + "axis"]; - if (typeof a === "object") { // if we got a real axis, extract number + if (typeof a == "object") // if we got a real axis, extract number a = a.n; - } - if (!isNumeric(a)) { + if (typeof a != "number") a = 1; // default to first axis - } return a; } @@ -1074,24 +924,20 @@ Licensed under the MIT license. var res = {}, i, axis; for (i = 0; i < xaxes.length; ++i) { axis = xaxes[i]; - if (axis && axis.used) { + if (axis && axis.used) res["x" + axis.n] = axis.c2p(pos.left); - } } for (i = 0; i < yaxes.length; ++i) { axis = yaxes[i]; - if (axis && axis.used) { + if (axis && axis.used) res["y" + axis.n] = axis.c2p(pos.top); - } } - if (res.x1 !== undefined) { + if (res.x1 !== undefined) res.x = res.x1; - } - if (res.y1 !== undefined) { + if (res.y1 !== undefined) res.y = res.y1; - } return res; } @@ -1104,9 +950,8 @@ Licensed under the MIT license. axis = xaxes[i]; if (axis && axis.used) { key = "x" + axis.n; - if (pos[key] == null && axis.n === 1) { + if (pos[key] == null && axis.n == 1) key = "x"; - } if (pos[key] != null) { res.left = axis.p2c(pos[key]); @@ -1119,9 +964,8 @@ Licensed under the MIT license. axis = yaxes[i]; if (axis && axis.used) { key = "y" + axis.n; - if (pos[key] == null && axis.n === 1) { + if (pos[key] == null && axis.n == 1) key = "y"; - } if (pos[key] != null) { res.top = axis.p2c(pos[key]); @@ -1134,13 +978,12 @@ Licensed under the MIT license. } function getOrCreateAxis(axes, number) { - if (!axes[number - 1]) { + if (!axes[number - 1]) axes[number - 1] = { n: number, // save the number for future reference - direction: axes === xaxes ? "x" : "y", - options: $.extend(true, {}, axes === xaxes ? options.xaxis : options.yaxis) + direction: axes == xaxes ? "x" : "y", + options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis) }; - } return axes[number - 1]; } @@ -1156,7 +999,7 @@ Licensed under the MIT license. var sc = series[i].color; if (sc != null) { neededColors--; - if (isNumeric(sc) && sc > maxIndex) { + if (typeof sc == "number" && sc > maxIndex) { maxIndex = sc; } } @@ -1187,19 +1030,15 @@ Licensed under the MIT license. // Reset the variation after every few cycles, or else // it will end up producing only white or black colors. - if (i % colorPoolSize === 0 && i) { + if (i % colorPoolSize == 0 && i) { if (variation >= 0) { if (variation < 0.5) { variation = -variation - 0.2; - } else { - variation = 0; - } - } else { - variation = -variation; - } + } else variation = 0; + } else variation = -variation; } - colors[i] = c.scale("rgb", 1 + variation); + colors[i] = c.scale('rgb', 1 + variation); } // Finalize the series options, filling in their colors @@ -1212,22 +1051,20 @@ Licensed under the MIT license. if (s.color == null) { s.color = colors[colori].toString(); ++colori; - } else if (isNumeric(s.color)) { - s.color = colors[s.color].toString(); } + else if (typeof s.color == "number") + s.color = colors[s.color].toString(); // turn on lines automatically in case nothing is set if (s.lines.show == null) { var v, show = true; - for (v in s) { + for (v in s) if (s[v] && s[v].show) { show = false; break; } - } - if (show) { + if (show) s.lines.show = true; - } } // If nothing was provided for lines.zero, default it to match @@ -1247,15 +1084,15 @@ Licensed under the MIT license. var topSentry = Number.POSITIVE_INFINITY, bottomSentry = Number.NEGATIVE_INFINITY, fakeInfinity = Number.MAX_VALUE, - i, j, k, m, s, points, ps, val, f, p, data, format; + i, j, k, m, length, + s, points, ps, x, y, axis, val, f, p, + data, format; function updateAxis(axis, min, max) { - if (min < axis.datamin && min !== -fakeInfinity) { + if (min < axis.datamin && min != -fakeInfinity) axis.datamin = min; - } - if (max > axis.datamax && max !== fakeInfinity) { + if (max > axis.datamax && max != fakeInfinity) axis.datamax = max; - } } $.each(allAxes(), function (_, axis) { @@ -1268,6 +1105,7 @@ Licensed under the MIT license. for (i = 0; i < series.length; ++i) { s = series[i]; s.datapoints = { points: [] }; + executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]); } @@ -1296,9 +1134,8 @@ Licensed under the MIT license. s.datapoints.format = format; } - if (s.datapoints.pointsize != null) { + if (s.datapoints.pointsize != null) continue; // already filled in - } s.datapoints.pointsize = format.length; @@ -1320,23 +1157,20 @@ Licensed under the MIT license. if (f) { if (f.number && val != null) { val = +val; // convert to number - if (isNaN(val)) { + if (isNaN(val)) val = null; - } else if (val === Infinity) { + else if (val == Infinity) val = fakeInfinity; - } else if (val === -Infinity) { + else if (val == -Infinity) val = -fakeInfinity; - } } if (val == null) { - if (f.required) { + if (f.required) nullify = true; - } - if (f.defaultValue != null) { + if (f.defaultValue != null) val = f.defaultValue; - } } } @@ -1350,7 +1184,7 @@ Licensed under the MIT license. if (val != null) { f = format[m]; // extract min/max info - if (f.autoscale) { + if (f.autoscale !== false) { if (f.x) { updateAxis(s.xaxis, val, val); } @@ -1361,18 +1195,18 @@ Licensed under the MIT license. } points[k + m] = null; } - } else { + } + else { // a little bit of line specific stuff that // perhaps shouldn't be here, but lacking // better means... - if (insertSteps && k > 0 && - points[k - ps] != null && - points[k - ps] !== points[k] && - points[k - ps + 1] !== points[k + 1]) { + if (insertSteps && k > 0 + && points[k - ps] != null + && points[k - ps] != points[k] + && points[k - ps + 1] != points[k + 1]) { // copy the point to make room for a middle point - for (m = 0; m < ps; ++m) { + for (m = 0; m < ps; ++m) points[k + ps + m] = points[k + m]; - } // middle point has same y points[k + 1] = points[k - ps + 1]; @@ -1402,32 +1236,26 @@ Licensed under the MIT license. xmax = bottomSentry, ymax = bottomSentry; for (j = 0; j < points.length; j += ps) { - if (points[j] == null) { + if (points[j] == null) continue; - } for (m = 0; m < ps; ++m) { val = points[j + m]; f = format[m]; - if (!f || f.autoscale === false || val === fakeInfinity || val === -fakeInfinity) { + if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity) continue; - } if (f.x) { - if (val < xmin) { + if (val < xmin) xmin = val; - } - if (val > xmax) { + if (val > xmax) xmax = val; - } } if (f.y) { - if (val < ymin) { + if (val < ymin) ymin = val; - } - if (val > ymax) { + if (val > ymax) ymax = val; - } } } } @@ -1437,23 +1265,21 @@ Licensed under the MIT license. var delta; switch (s.bars.align) { - case "left": - delta = 0; - break; - case "right": - delta = -s.bars.barWidth; - break; - case "center": - delta = -s.bars.barWidth / 2; - break; - default: - throw new Error("Invalid bar alignment: " + s.bars.align); + case "left": + delta = 0; + break; + case "right": + delta = -s.bars.barWidth; + break; + default: + delta = -s.bars.barWidth / 2; } if (s.bars.horizontal) { ymin += delta; ymax += delta + s.bars.barWidth; - } else { + } + else { xmin += delta; xmax += delta + s.bars.barWidth; } @@ -1464,12 +1290,10 @@ Licensed under the MIT license. } $.each(allAxes(), function (_, axis) { - if (axis.datamin === topSentry) { + if (axis.datamin == topSentry) axis.datamin = null; - } - if (axis.datamax === bottomSentry) { + if (axis.datamax == bottomSentry) axis.datamax = null; - } }); } @@ -1479,11 +1303,12 @@ Licensed under the MIT license. // from a previous plot in this container that we'll try to re-use. placeholder.css("padding", 0) // padding messes up the positioning - .children(":not(.flot-base,.flot-overlay)").remove(); + .children().filter(function(){ + return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base'); + }).remove(); - if (placeholder.css("position") === "static") { + if (placeholder.css("position") == 'static') placeholder.css("position", "relative"); // for positioning labels and overlay - } surface = new Canvas("flot-base", placeholder); overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features @@ -1521,17 +1346,15 @@ Licensed under the MIT license. eventHolder.bind("mouseleave", onMouseLeave); } - if (options.grid.clickable) { + if (options.grid.clickable) eventHolder.click(onClick); - } executeHooks(hooks.bindEvents, [eventHolder]); } function shutdown() { - if (redrawTimeout) { + if (redrawTimeout) clearTimeout(redrawTimeout); - } eventHolder.unbind("mousemove", onMouseMove); eventHolder.unbind("mouseleave", onMouseLeave); @@ -1551,143 +1374,136 @@ Licensed under the MIT license. // precompute how much the axis is scaling a point // in canvas space - if (axis.direction === "x") { + if (axis.direction == "x") { s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min)); m = Math.min(t(axis.max), t(axis.min)); - } else { + } + else { s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min)); s = -s; m = Math.max(t(axis.max), t(axis.min)); } // data point to canvas coordinate - if (t === identity) { // slight optimization + if (t == identity) // slight optimization axis.p2c = function (p) { return (p - m) * s; }; - } else { + else axis.p2c = function (p) { return (t(p) - m) * s; }; - } // canvas coordinate to data point - if (!it) { + if (!it) axis.c2p = function (c) { return m + c / s; }; - } else { + else axis.c2p = function (c) { return it(m + c / s); }; - } } function measureTickLabels(axis) { var opts = axis.options, ticks = axis.ticks || [], - // Label width & height are deprecated; remove in 1.0! - tickWidth = opts.tickWidth || opts.labelWidth || 0, - tickHeight = opts.tickHeight || opts.labelHeight || 0, - maxWidth = tickWidth || axis.direction === "x" ? Math.floor(surface.width / (ticks.length || 1)) : null, - layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + axis.direction + "Axis " + axis.direction + axis.n + "Axis", - font = opts.tickFont || "flot-tick-label tickLabel"; + labelWidth = opts.labelWidth || 0, + labelHeight = opts.labelHeight || 0, + maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null), + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = opts.font || "flot-tick-label tickLabel"; for (var i = 0; i < ticks.length; ++i) { var t = ticks[i]; - if (!t.label) { + if (!t.label) continue; - } var info = surface.getTextInfo(layer, t.label, font, null, maxWidth); - tickWidth = Math.max(tickWidth, info.width); - tickHeight = Math.max(tickHeight, info.height); + labelWidth = Math.max(labelWidth, info.width); + labelHeight = Math.max(labelHeight, info.height); } - axis.tickWidth = opts.tickWidth || opts.labelWidth || tickWidth; - axis.tickHeight = opts.tickHeight || opts.labelHeight || tickHeight; - - // Label width/height properties are deprecated; remove in 1.0! - - axis.labelWidth = axis.tickWidth; - axis.labelHeight = axis.tickHeight; + axis.labelWidth = opts.labelWidth || labelWidth; + axis.labelHeight = opts.labelHeight || labelHeight; } - /////////////////////////////////////////////////////////////////////// - // Compute the axis bounding box based on the dimensions of its label - // and tick labels, then adjust the plotOffset to make room for it. - // - // This first phase only considers one dimension per axis; the other - // dimension depends on the other axes, and will be calculated later. - function allocateAxisBoxFirstPhase(axis) { - - var contentWidth = axis.tickWidth, - contentHeight = axis.tickHeight, - axisOptions = axis.options, - tickLength = axisOptions.tickLength, - axisPosition = axisOptions.position, + // find the bounding box of the axis by looking at label + // widths/heights and ticks, make room by diminishing the + // plotOffset; this first phase only looks at one + // dimension per axis, the other dimension depends on the + // other axes so will have to wait + + var lw = axis.labelWidth, + lh = axis.labelHeight, + pos = axis.options.position, + isXAxis = axis.direction === "x", + tickLength = axis.options.tickLength, axisMargin = options.grid.axisMargin, padding = options.grid.labelMargin, - all = axis.direction === "x" ? xaxes : yaxes, - innermost; - - // Determine the margin around the axis - - var samePosition = $.grep(all, function(axis) { - return axis && axis.options.position === axisPosition && axis.reserveSpace; + innermost = true, + outermost = true, + first = true, + found = false; + + // Determine the axis's position in its direction and on its side + + $.each(isXAxis ? xaxes : yaxes, function(i, a) { + if (a && (a.show || a.reserveSpace)) { + if (a === axis) { + found = true; + } else if (a.options.position === pos) { + if (found) { + outermost = false; + } else { + innermost = false; + } + } + if (!found) { + first = false; + } + } }); - if ($.inArray(axis, samePosition) === samePosition.length - 1) { - axisMargin = 0; // outermost - } - // Determine whether the axis is the first (innermost) on its side + // The outermost axis on each side has no margin - innermost = $.inArray(axis, samePosition) === 0; + if (outermost) { + axisMargin = 0; + } - // Determine the length of the tick marks + // The ticks for the first axis in each direction stretch across if (tickLength == null) { - if (innermost) { - tickLength = "full"; - } else { - tickLength = 5; - } + tickLength = first ? "full" : 5; } - if (!isNaN(+tickLength)) { + if (!isNaN(+tickLength)) padding += +tickLength; - } - // Measure the dimensions of the axis label, if it has one + if (isXAxis) { + lh += padding; - if (axisOptions.label) { - var layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + axis.direction + "Axis " + axis.direction + axis.n + "Axis", - font = axisOptions.labelFont || "flot-axis-label axisLabels " + axis.direction + axis.n + "axisLabel", - angle = axis.direction === "x" ? 0 : axisOptions.position === "right" ? 90 : -90, - labelInfo = surface.getTextInfo(layer, axisOptions.label, font, angle); - contentWidth += labelInfo.width + axisOptions.labelPadding; - contentHeight += labelInfo.height + axisOptions.labelPadding; + if (pos == "bottom") { + plotOffset.bottom += lh + axisMargin; + axis.box = { top: surface.height - plotOffset.bottom, height: lh }; + } + else { + axis.box = { top: plotOffset.top + axisMargin, height: lh }; + plotOffset.top += lh + axisMargin; + } } + else { + lw += padding; - // Compute the axis bounding box and update the plot bounds - - if (axis.direction === "x") { - contentHeight += padding; - if (axisPosition === "top") { - axis.box = { top: plotOffset.top + axisMargin, height: contentHeight }; - plotOffset.top += contentHeight + axisMargin; - } else { - plotOffset.bottom += contentHeight + axisMargin; - axis.box = { top: surface.height - plotOffset.bottom, height: contentHeight }; + if (pos == "left") { + axis.box = { left: plotOffset.left + axisMargin, width: lw }; + plotOffset.left += lw + axisMargin; } - } else { - contentWidth += padding; - if (axisPosition === "right") { - plotOffset.right += contentWidth + axisMargin; - axis.box = { left: surface.width - plotOffset.right, width: contentWidth }; - } else { - axis.box = { left: plotOffset.left + axisMargin, width: contentWidth }; - plotOffset.left += contentWidth + axisMargin; + else { + plotOffset.right += lw + axisMargin; + axis.box = { left: surface.width - plotOffset.right, width: lw }; } } - axis.position = axisPosition; + // save for future reference + axis.position = pos; axis.tickLength = tickLength; axis.box.padding = padding; axis.innermost = innermost; @@ -1696,12 +1512,13 @@ Licensed under the MIT license. function allocateAxisBoxSecondPhase(axis) { // now that all axis boxes have been placed in one // dimension, we can set the remaining dimension coordinates - if (axis.direction === "x") { - axis.box.left = plotOffset.left - axis.tickWidth / 2; - axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.tickWidth; - } else { - axis.box.top = plotOffset.top - axis.tickHeight / 2; - axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.tickHeight; + if (axis.direction == "x") { + axis.box.left = plotOffset.left - axis.labelWidth / 2; + axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth; + } + else { + axis.box.top = plotOffset.top - axis.labelHeight / 2; + axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight; } } @@ -1710,92 +1527,95 @@ Licensed under the MIT license. // inside the canvas and isn't clipped off var minMargin = options.grid.minBorderMargin, - margins = { x: 0, y: 0 }, i; + axis, i; // check stuff from the plot (FIXME: this should just read // a value from the series, otherwise it's impossible to // customize) if (minMargin == null) { minMargin = 0; - for (i = 0; i < series.length; ++i) { + for (i = 0; i < series.length; ++i) minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2)); - } } - margins.x = margins.y = Math.ceil(minMargin); + var margins = { + left: minMargin, + right: minMargin, + top: minMargin, + bottom: minMargin + }; // check axis labels, note we don't check the actual // labels but instead use the overall width/height to not // jump as much around with replots $.each(allAxes(), function (_, axis) { - var dir = axis.direction; - if (axis.reserveSpace) { - margins[dir] = Math.ceil(Math.max(margins[dir], (dir === "x" ? axis.tickWidth : axis.tickHeight) / 2)); + if (axis.reserveSpace && axis.ticks && axis.ticks.length) { + if (axis.direction === "x") { + margins.left = Math.max(margins.left, axis.labelWidth / 2); + margins.right = Math.max(margins.right, axis.labelWidth / 2); + } else { + margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2); + margins.top = Math.max(margins.top, axis.labelHeight / 2); + } } }); - plotOffset.left = Math.max(margins.x, plotOffset.left); - plotOffset.right = Math.max(margins.x, plotOffset.right); - plotOffset.top = Math.max(margins.y, plotOffset.top); - plotOffset.bottom = Math.max(margins.y, plotOffset.bottom); + plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left)); + plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right)); + plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top)); + plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom)); } function setupGrid() { - var axes = allAxes(), - showGrid = options.grid.show, - margin = options.grid.margin || 0, - i, a; + var i, axes = allAxes(), showGrid = options.grid.show; // Initialize the plot's offset from the edge of the canvas - for (a in plotOffset) { - if (Object.prototype.hasOwnProperty.call(plotOffset, a)) { - plotOffset[a] = isNumeric(margin) ? margin : margin[a] || 0; - } + for (var a in plotOffset) { + var margin = options.grid.margin || 0; + plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0; } executeHooks(hooks.processOffset, [plotOffset]); // If the grid is visible, add its border width to the offset - for (a in plotOffset) { - if(typeof(options.grid.borderWidth) === "object") { + for (var a in plotOffset) { + if(typeof(options.grid.borderWidth) == "object") { plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0; - } else { + } + else { plotOffset[a] += showGrid ? options.grid.borderWidth : 0; } } - // init axes $.each(axes, function (_, axis) { - axis.show = axis.options.show; - if (axis.show == null) { - axis.show = axis.used; // by default an axis is visible if it's got data - } - - axis.reserveSpace = axis.show || axis.options.reserveSpace; - + var axisOpts = axis.options; + axis.show = axisOpts.show == null ? axis.used : axisOpts.show; + axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace; setRange(axis); }); if (showGrid) { - var allocatedAxes = $.grep(axes, function (axis) { return axis.reserveSpace; }); + var allocatedAxes = $.grep(axes, function (axis) { + return axis.show || axis.reserveSpace; + }); $.each(allocatedAxes, function (_, axis) { // make the ticks setupTickGeneration(axis); setTicks(axis); snapRangeToTicks(axis, axis.ticks); + // find labelWidth/Height for axis measureTickLabels(axis); }); // with all dimensions calculated, we can compute the // axis bounding boxes, start from the outside // (reverse order) - for (i = allocatedAxes.length - 1; i >= 0; --i) { + for (i = allocatedAxes.length - 1; i >= 0; --i) allocateAxisBoxFirstPhase(allocatedAxes[i]); - } // make sure we've got enough space for things that // might stick out @@ -1827,19 +1647,18 @@ Licensed under the MIT license. max = +(opts.max != null ? opts.max : axis.datamax), delta = max - min; - if (delta === 0.0) { + if (delta == 0.0) { // degenerate case - var widen = max === 0 ? 1 : 0.01; + var widen = max == 0 ? 1 : 0.01; - if (opts.min == null) { + if (opts.min == null) min -= widen; - } // always widen max if we couldn't widen min to ensure we // don't fall into min == max which doesn't work - if (opts.max == null || opts.min != null) { + if (opts.max == null || opts.min != null) max += widen; - } - } else { + } + else { // consider autoscaling var margin = opts.autoscaleMargin; if (margin != null) { @@ -1847,15 +1666,13 @@ Licensed under the MIT license. min -= delta * margin; // make sure we don't go below zero if all values // are positive - if (min < 0 && axis.datamin != null && axis.datamin >= 0) { + if (min < 0 && axis.datamin != null && axis.datamin >= 0) min = 0; - } } if (opts.max == null) { max += delta * margin; - if (max > 0 && axis.datamax != null && axis.datamax <= 0) { + if (max > 0 && axis.datamax != null && axis.datamax <= 0) max = 0; - } } } } @@ -1868,13 +1685,12 @@ Licensed under the MIT license. // estimate number of ticks var noTicks; - if (isNumeric(opts.ticks) && opts.ticks > 0) { + if (typeof opts.ticks == "number" && opts.ticks > 0) noTicks = opts.ticks; - } else { + else // heuristic based on the model a*sqrt(x) fitted to // some data points that seemed reasonable - noTicks = 0.3 * Math.sqrt(axis.direction === "x" ? surface.width : surface.height); - } + noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height); var delta = (axis.max - axis.min) / noTicks, dec = -Math.floor(Math.log(delta) / Math.LN10), @@ -1913,10 +1729,10 @@ Licensed under the MIT license. axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec); axis.tickSize = opts.tickSize || size; - // Time mode was moved to a plug-in in 0.8, but since so many people use this - // we'll add an especially friendly make sure they remembered to include it. + // Time mode was moved to a plug-in in 0.8, and since so many people use it + // we'll add an especially friendly reminder to make sure they included it. - if (opts.mode === "time" && !axis.tickGenerator) { + if (opts.mode == "time" && !axis.tickGenerator) { throw new Error("Time mode requires the flot.time plugin."); } @@ -1938,46 +1754,43 @@ Licensed under the MIT license. v = start + i * axis.tickSize; ticks.push(v); ++i; - } while (v < axis.max && v !== prev); + } while (v < axis.max && v != prev); return ticks; }; - axis.tickFormatter = function (value, axis) { + axis.tickFormatter = function (value, axis) { - var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1; - var formatted = "" + Math.round(value * factor) / factor; + var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1; + var formatted = "" + Math.round(value * factor) / factor; - // If tickDecimals was specified, ensure that we have exactly that - // much precision; otherwise default to the value's own precision. + // If tickDecimals was specified, ensure that we have exactly that + // much precision; otherwise default to the value's own precision. - if (axis.tickDecimals != null) { - var decimal = formatted.indexOf("."); - var precision = decimal === -1 ? 0 : formatted.length - decimal - 1; - if (precision < axis.tickDecimals) { - return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision); - } - } + if (axis.tickDecimals != null) { + var decimal = formatted.indexOf("."); + var precision = decimal == -1 ? 0 : formatted.length - decimal - 1; + if (precision < axis.tickDecimals) { + return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision); + } + } return formatted; }; } - if ($.isFunction(opts.tickFormatter)) { + if ($.isFunction(opts.tickFormatter)) axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); }; - } if (opts.alignTicksWithAxis != null) { - var otherAxis = (axis.direction === "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1]; - if (otherAxis && otherAxis.used && otherAxis !== axis) { + var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1]; + if (otherAxis && otherAxis.used && otherAxis != axis) { // consider snapping min/max to outermost nice ticks var niceTicks = axis.tickGenerator(axis); if (niceTicks.length > 0) { - if (opts.min == null) { + if (opts.min == null) axis.min = Math.min(axis.min, niceTicks[0]); - } - if (opts.max == null && niceTicks.length > 1) { + if (opts.max == null && niceTicks.length > 1) axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]); - } } axis.tickGenerator = function (axis) { @@ -2000,9 +1813,8 @@ Licensed under the MIT license. // only proceed if the tick interval rounded // with an extra decimal doesn't give us a // zero at end - if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec)))) { + if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec)))) axis.tickDecimals = extraDec; - } } } } @@ -2010,15 +1822,14 @@ Licensed under the MIT license. function setTicks(axis) { var oticks = axis.options.ticks, ticks = []; - if (oticks == null || (isNumeric(oticks) && oticks > 0)) { + if (oticks == null || (typeof oticks == "number" && oticks > 0)) ticks = axis.tickGenerator(axis); - } else if (oticks) { - if ($.isFunction(oticks)) { + else if (oticks) { + if ($.isFunction(oticks)) // generate the ticks ticks = oticks(axis); - } else { + else ticks = oticks; - } } // clean up/labelify the supplied ticks, copy them over @@ -2027,32 +1838,27 @@ Licensed under the MIT license. for (i = 0; i < ticks.length; ++i) { var label = null; var t = ticks[i]; - if (typeof t === "object") { + if (typeof t == "object") { v = +t[0]; - if (t.length > 1) { + if (t.length > 1) label = t[1]; - } - } else { - v = +t; } - if (label == null) { + else + v = +t; + if (label == null) label = axis.tickFormatter(v, axis); - } - if (!isNaN(v)) { + if (!isNaN(v)) axis.ticks.push({ v: v, label: label }); - } } } function snapRangeToTicks(axis, ticks) { if (axis.options.autoscaleMargin && ticks.length > 0) { // snap to ticks - if (axis.options.min == null) { + if (axis.options.min == null) axis.min = Math.min(axis.min, ticks[0].v); - } - if (axis.options.max == null && ticks.length > 1) { + if (axis.options.max == null && ticks.length > 1) axis.max = Math.max(axis.max, ticks[ticks.length - 1].v); - } } } @@ -2065,9 +1871,8 @@ Licensed under the MIT license. var grid = options.grid; // draw background, if any - if (grid.show && grid.backgroundColor) { + if (grid.show && grid.backgroundColor) drawBackground(); - } if (grid.show && !grid.aboveData) { drawGrid(); @@ -2097,11 +1902,10 @@ Licensed under the MIT license. for (var i = 0; i < axes.length; ++i) { axis = axes[i]; - if (axis.direction === coord) { + if (axis.direction == coord) { key = coord + axis.n + "axis"; - if (!ranges[key] && axis.n === 1) { + if (!ranges[key] && axis.n == 1) key = coord + "axis"; // support x1axis as xaxis - } if (ranges[key]) { from = ranges[key].from; to = ranges[key].to; @@ -2112,7 +1916,7 @@ Licensed under the MIT license. // backwards-compat stuff - to be removed in future if (!ranges[key]) { - axis = coord === "x" ? xaxes[0] : yaxes[0]; + axis = coord == "x" ? xaxes[0] : yaxes[0]; from = ranges[coord + "1"]; to = ranges[coord + "2"]; } @@ -2163,50 +1967,53 @@ Licensed under the MIT license. yrange = extractRange(m, "y"); // fill in missing - if (xrange.from == null) { + if (xrange.from == null) xrange.from = xrange.axis.min; - } - if (xrange.to == null) { + if (xrange.to == null) xrange.to = xrange.axis.max; - } - if (yrange.from == null) { + if (yrange.from == null) yrange.from = yrange.axis.min; - } - if (yrange.to == null) { + if (yrange.to == null) yrange.to = yrange.axis.max; - } // clip if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max || - yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) { + yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) continue; - } xrange.from = Math.max(xrange.from, xrange.axis.min); xrange.to = Math.min(xrange.to, xrange.axis.max); yrange.from = Math.max(yrange.from, yrange.axis.min); yrange.to = Math.min(yrange.to, yrange.axis.max); - if (xrange.from === xrange.to && yrange.from === yrange.to) { + var xequal = xrange.from === xrange.to, + yequal = yrange.from === yrange.to; + + if (xequal && yequal) { continue; } // then draw - xrange.from = xrange.axis.p2c(xrange.from); - xrange.to = xrange.axis.p2c(xrange.to); - yrange.from = yrange.axis.p2c(yrange.from); - yrange.to = yrange.axis.p2c(yrange.to); - - if (xrange.from === xrange.to || yrange.from === yrange.to) { - // draw line + xrange.from = Math.floor(xrange.axis.p2c(xrange.from)); + xrange.to = Math.floor(xrange.axis.p2c(xrange.to)); + yrange.from = Math.floor(yrange.axis.p2c(yrange.from)); + yrange.to = Math.floor(yrange.axis.p2c(yrange.to)); + + if (xequal || yequal) { + var lineWidth = m.lineWidth || options.grid.markingsLineWidth, + subPixel = lineWidth % 2 ? 0.5 : 0; ctx.beginPath(); ctx.strokeStyle = m.color || options.grid.markingsColor; - ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth; - ctx.moveTo(xrange.from, yrange.from); - ctx.lineTo(xrange.to, yrange.to); + ctx.lineWidth = lineWidth; + if (xequal) { + ctx.moveTo(xrange.to + subPixel, yrange.from); + ctx.lineTo(xrange.to + subPixel, yrange.to); + } else { + ctx.moveTo(xrange.from, yrange.to + subPixel); + ctx.lineTo(xrange.to, yrange.to + subPixel); + } ctx.stroke(); } else { - // fill area ctx.fillStyle = m.color || options.grid.markingsColor; ctx.fillRect(xrange.from, yrange.to, xrange.to - xrange.from, @@ -2222,27 +2029,25 @@ Licensed under the MIT license. for (var j = 0; j < axes.length; ++j) { var axis = axes[j], box = axis.box, t = axis.tickLength, x, y, xoff, yoff; - if (!axis.show || axis.ticks.length === 0) { + if (!axis.show || axis.ticks.length == 0) continue; - } ctx.lineWidth = 1; // find the edges - if (axis.direction === "x") { + if (axis.direction == "x") { x = 0; - if (t === "full") { - y = (axis.position === "top" ? 0 : plotHeight); - } else { - y = box.top - plotOffset.top + (axis.position === "top" ? box.height : 0); - } - } else { + if (t == "full") + y = (axis.position == "top" ? 0 : plotHeight); + else + y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0); + } + else { y = 0; - if (t === "full") { - x = (axis.position === "left" ? 0 : plotWidth); - } else { - x = box.left - plotOffset.left + (axis.position === "left" ? box.width : 0); - } + if (t == "full") + x = (axis.position == "left" ? 0 : plotWidth); + else + x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0); } // draw tick bar @@ -2250,14 +2055,13 @@ Licensed under the MIT license. ctx.strokeStyle = axis.options.color; ctx.beginPath(); xoff = yoff = 0; - if (axis.direction === "x") { + if (axis.direction == "x") xoff = plotWidth + 1; - } else { + else yoff = plotHeight + 1; - } - if (ctx.lineWidth === 1) { - if (axis.direction === "x") { + if (ctx.lineWidth == 1) { + if (axis.direction == "x") { y = Math.floor(y) + 0.5; } else { x = Math.floor(x) + 0.5; @@ -2279,36 +2083,33 @@ Licensed under the MIT license. xoff = yoff = 0; - if (isNaN(v) || v < axis.min || v > axis.max || ( + if (isNaN(v) || v < axis.min || v > axis.max // skip those lying on the axes if we got a border - t === "full" && ((typeof bw === "object" && bw[axis.position] > 0) || bw > 0) && - (v === axis.min || v === axis.max) - )) { + || (t == "full" + && ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0) + && (v == axis.min || v == axis.max))) continue; - } - if (axis.direction === "x") { + if (axis.direction == "x") { x = axis.p2c(v); - yoff = t === "full" ? -plotHeight : t; + yoff = t == "full" ? -plotHeight : t; - if (axis.position === "top") { + if (axis.position == "top") yoff = -yoff; - } - } else { + } + else { y = axis.p2c(v); - xoff = t === "full" ? -plotWidth : t; + xoff = t == "full" ? -plotWidth : t; - if (axis.position === "left") { + if (axis.position == "left") xoff = -xoff; - } } - if (ctx.lineWidth === 1) { - if (axis.direction === "x") { + if (ctx.lineWidth == 1) { + if (axis.direction == "x") x = Math.floor(x) + 0.5; - } else { + else y = Math.floor(y) + 0.5; - } } ctx.moveTo(x, y); @@ -2324,7 +2125,7 @@ Licensed under the MIT license. // If either borderWidth or borderColor is an object, then draw the border // line by line instead of as one rectangle bc = options.grid.borderColor; - if(typeof bw === "object" || typeof bc === "object") { + if(typeof bw == "object" || typeof bc == "object") { if (typeof bw !== "object") { bw = {top: bw, right: bw, bottom: bw, left: bw}; } @@ -2367,7 +2168,8 @@ Licensed under the MIT license. ctx.lineTo(0- bw.left/2, 0); ctx.stroke(); } - } else { + } + else { ctx.lineWidth = bw; ctx.strokeStyle = options.grid.borderColor; ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw); @@ -2380,48 +2182,31 @@ Licensed under the MIT license. function drawAxisLabels() { $.each(allAxes(), function (_, axis) { - if (!axis.show || axis.ticks.length === 0) { - return; - } - var box = axis.box, - axisOptions = axis.options, - layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + axis.direction + "Axis " + axis.direction + axis.n + "Axis", - labelFont = axisOptions.labelFont || "flot-axis-label axisLabels " + axis.direction + axis.n + "axisLabel", - tickFont = axisOptions.tickFont || "flot-tick-label tickLabel", + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = axis.options.font || "flot-tick-label tickLabel", tick, x, y, halign, valign; - surface.removeText(layer); + // Remove text before checking for axis.show and ticks.length; + // otherwise plugins, like flot-tickrotor, that draw their own + // tick labels will end up with both theirs and the defaults. - if (axisOptions.label) { - if (axis.direction === "x") { - if (axisOptions.position === "top") { - surface.addText(layer, box.left + box.width / 2, box.top, axisOptions.label, labelFont, 0, null, "center", "top"); - } else { - surface.addText(layer, box.left + box.width / 2, box.top + box.height, axisOptions.label, labelFont, 0, null, "center", "bottom"); - } - } else { - if (axisOptions.position === "right") { - surface.addText(layer, box.left + box.width, box.top + box.height / 2, axisOptions.label, labelFont, 90, null, "right", "middle"); - } else { - surface.addText(layer, box.left, box.top + box.height / 2, axisOptions.label, labelFont, -90, null, "left", "middle"); - } - } - } + surface.removeText(layer); - // Add labels for the ticks on this axis + if (!axis.show || axis.ticks.length == 0) + return; for (var i = 0; i < axis.ticks.length; ++i) { tick = axis.ticks[i]; - if (!tick.label || tick.v < axis.min || tick.v > axis.max) { + if (!tick.label || tick.v < axis.min || tick.v > axis.max) continue; - } - if (axis.direction === "x") { + if (axis.direction == "x") { halign = "center"; x = plotOffset.left + axis.p2c(tick.v); - if (axis.position === "bottom") { + if (axis.position == "bottom") { y = box.top + box.padding; } else { y = box.top + box.height - box.padding; @@ -2430,7 +2215,7 @@ Licensed under the MIT license. } else { valign = "middle"; y = plotOffset.top + axis.p2c(tick.v); - if (axis.position === "left") { + if (axis.position == "left") { x = box.left + box.width - box.padding; halign = "right"; } else { @@ -2438,21 +2223,18 @@ Licensed under the MIT license. } } - surface.addText(layer, x, y, tick.label, tickFont, null, null, halign, valign); + surface.addText(layer, x, y, tick.label, font, null, null, halign, valign); } }); } function drawSeries(series) { - if (series.lines.show) { + if (series.lines.show) drawSeriesLines(series); - } - if (series.bars.show) { + if (series.bars.show) drawSeriesBars(series); - } - if (series.points.show) { + if (series.points.show) drawSeriesPoints(series); - } } function drawSeriesLines(series) { @@ -2466,74 +2248,68 @@ Licensed under the MIT license. var x1 = points[i - ps], y1 = points[i - ps + 1], x2 = points[i], y2 = points[i + 1]; - if (x1 == null || x2 == null) { + if (x1 == null || x2 == null) continue; - } // clip with ymin if (y1 <= y2 && y1 < axisy.min) { - if (y2 < axisy.min) { + if (y2 < axisy.min) continue; // line segment is outside - } // compute new intersection point x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.min; - } else if (y2 <= y1 && y2 < axisy.min) { - if (y1 < axisy.min) { + } + else if (y2 <= y1 && y2 < axisy.min) { + if (y1 < axisy.min) continue; - } x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.min; } // clip with ymax if (y1 >= y2 && y1 > axisy.max) { - if (y2 > axisy.max) { + if (y2 > axisy.max) continue; - } x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.max; - } else if (y2 >= y1 && y2 > axisy.max) { - if (y1 > axisy.max) { + } + else if (y2 >= y1 && y2 > axisy.max) { + if (y1 > axisy.max) continue; - } x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.max; } // clip with xmin if (x1 <= x2 && x1 < axisx.min) { - if (x2 < axisx.min) { + if (x2 < axisx.min) continue; - } y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.min; - } else if (x2 <= x1 && x2 < axisx.min) { - if (x1 < axisx.min) { + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) continue; - } y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.min; } // clip with xmax if (x1 >= x2 && x1 > axisx.max) { - if (x2 > axisx.max) { + if (x2 > axisx.max) continue; - } y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.max; - } else if (x2 >= x1 && x2 > axisx.max) { - if (x1 > axisx.max) { + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) continue; - } y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.max; } - if (x1 !== prevx || y1 !== prevy) { + if (x1 != prevx || y1 != prevy) ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); - } prevx = x2; prevy = y2; @@ -2546,16 +2322,15 @@ Licensed under the MIT license. var points = datapoints.points, ps = datapoints.pointsize, bottom = Math.min(Math.max(0, axisy.min), axisy.max), - i = 0, areaOpen = false, + i = 0, top, areaOpen = false, ypos = 1, segmentStart = 0, segmentEnd = 0; // we process each segment in two turns, first forward // direction to sketch out top, then once we hit the // end we go backwards to sketch the bottom while (true) { - if (ps > 0 && i > points.length + ps) { + if (ps > 0 && i > points.length + ps) break; - } i += ps; // ps is negative if going backwards @@ -2572,7 +2347,7 @@ Licensed under the MIT license. continue; } - if (ps < 0 && i === segmentStart + ps) { + if (ps < 0 && i == segmentStart + ps) { // done with the reverse sweep ctx.fill(); areaOpen = false; @@ -2583,38 +2358,35 @@ Licensed under the MIT license. } } - if (x1 == null || x2 == null) { + if (x1 == null || x2 == null) continue; - } // clip x values // clip with xmin if (x1 <= x2 && x1 < axisx.min) { - if (x2 < axisx.min) { + if (x2 < axisx.min) continue; - } y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.min; - } else if (x2 <= x1 && x2 < axisx.min) { - if (x1 < axisx.min) { + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) continue; - } y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.min; } // clip with xmax if (x1 >= x2 && x1 > axisx.max) { - if (x2 > axisx.max) { + if (x2 > axisx.max) continue; - } y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.max; - } else if (x2 >= x1 && x2 > axisx.max) { - if (x1 > axisx.max) { + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) continue; - } y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.max; } @@ -2631,7 +2403,8 @@ Licensed under the MIT license. ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max)); continue; - } else if (y1 <= axisy.min && y2 <= axisy.min) { + } + else if (y1 <= axisy.min && y2 <= axisy.min) { ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min)); continue; @@ -2650,7 +2423,8 @@ Licensed under the MIT license. if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) { x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.min; - } else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { + } + else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.min; } @@ -2659,14 +2433,15 @@ Licensed under the MIT license. if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) { x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.max; - } else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { + } + else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.max; } // if the x value was changed we got a rectangle // to fill - if (x1 !== x1old) { + if (x1 != x1old) { ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1)); // it goes to (x1, y1), but we fill that below } @@ -2678,7 +2453,7 @@ Licensed under the MIT license. ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); // fill the other rectangle if it's there - if (x2 !== x2old) { + if (x2 != x2old) { ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2)); } @@ -2711,9 +2486,8 @@ Licensed under the MIT license. plotLineArea(series.datapoints, series.xaxis, series.yaxis); } - if (lw > 0) { + if (lw > 0) plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis); - } ctx.restore(); } @@ -2723,18 +2497,16 @@ Licensed under the MIT license. for (var i = 0; i < points.length; i += ps) { var x = points[i], y = points[i + 1]; - if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) { + if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) continue; - } ctx.beginPath(); x = axisx.p2c(x); y = axisy.p2c(y) + offset; - if (symbol === "circle") { + if (symbol == "circle") ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); - } else { + else symbol(ctx, x, y, radius, shadow); - } ctx.closePath(); if (fillStyle) { @@ -2758,9 +2530,8 @@ Licensed under the MIT license. // Doing the conditional here allows the shadow setting to still be // optional even with a lineWidth of 0. - if( lw === 0 ) { + if( lw == 0 ) lw = 0.0001; - } if (lw > 0 && sw > 0) { // draw shadow in two steps @@ -2776,14 +2547,14 @@ Licensed under the MIT license. } ctx.lineWidth = lw; - ctx.strokeStyle = series.points.strokeColor || series.color; + ctx.strokeStyle = series.color; plotPoints(series.datapoints, radius, getFillStyle(series.points, series.color), 0, false, series.xaxis, series.yaxis, symbol); ctx.restore(); } - function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { + function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { var left, right, bottom, top, drawLeft, drawRight, drawTop, drawBottom, tmp; @@ -2807,7 +2578,8 @@ Licensed under the MIT license. drawLeft = true; drawRight = false; } - } else { + } + else { drawLeft = drawRight = drawTop = true; drawBottom = false; left = x + barLeft; @@ -2827,9 +2599,8 @@ Licensed under the MIT license. // clip if (right < axisx.min || left > axisx.max || - top < axisy.min || bottom > axisy.max) { + top < axisy.min || bottom > axisy.max) return; - } if (left < axisx.min) { left = axisx.min; @@ -2858,13 +2629,8 @@ Licensed under the MIT license. // fill the bar if (fillStyleCallback) { - c.beginPath(); - c.moveTo(left, bottom); - c.lineTo(left, top); - c.lineTo(right, top); - c.lineTo(right, bottom); c.fillStyle = fillStyleCallback(bottom, top); - c.fill(); + c.fillRect(left, top, right - left, bottom - top) } // draw outline @@ -2872,40 +2638,35 @@ Licensed under the MIT license. c.beginPath(); // FIXME: inline moveTo is buggy with excanvas - c.moveTo(left, bottom + offset); - if (drawLeft) { - c.lineTo(left, top + offset); - } else { - c.moveTo(left, top + offset); - } - if (drawTop) { - c.lineTo(right, top + offset); - } else { - c.moveTo(right, top + offset); - } - if (drawRight) { - c.lineTo(right, bottom + offset); - } else { - c.moveTo(right, bottom + offset); - } - if (drawBottom) { - c.lineTo(left, bottom + offset); - } else { - c.moveTo(left, bottom + offset); - } + c.moveTo(left, bottom); + if (drawLeft) + c.lineTo(left, top); + else + c.moveTo(left, top); + if (drawTop) + c.lineTo(right, top); + else + c.moveTo(right, top); + if (drawRight) + c.lineTo(right, bottom); + else + c.moveTo(right, bottom); + if (drawBottom) + c.lineTo(left, bottom); + else + c.moveTo(left, bottom); c.stroke(); } } function drawSeriesBars(series) { - function plotBars(datapoints, barLeft, barRight, offset, fillStyleCallback, axisx, axisy) { + function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) { var points = datapoints.points, ps = datapoints.pointsize; for (var i = 0; i < points.length; i += ps) { - if (points[i] == null) { + if (points[i] == null) continue; - } - drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth); + drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth); } } @@ -2919,53 +2680,53 @@ Licensed under the MIT license. var barLeft; switch (series.bars.align) { - case "left": - barLeft = 0; - break; - case "right": - barLeft = -series.bars.barWidth; - break; - case "center": - barLeft = -series.bars.barWidth / 2; - break; - default: - throw new Error("Invalid bar alignment: " + series.bars.align); + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; } var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null; - plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, 0, fillStyleCallback, series.xaxis, series.yaxis); + plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis); ctx.restore(); } function getFillStyle(filloptions, seriesColor, bottom, top) { var fill = filloptions.fill; - if (!fill) { + if (!fill) return null; - } - if (filloptions.fillColor) { + if (filloptions.fillColor) return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor); - } var c = $.color.parse(seriesColor); - c.a = isNumeric(fill) ? fill : 0.4; + c.a = typeof fill == "number" ? fill : 0.4; c.normalize(); return c.toString(); } function insertLegend() { - placeholder.find(".legend").remove(); + if (options.legend.container != null) { + $(options.legend.container).html(""); + } else { + placeholder.find(".legend").remove(); + } if (!options.legend.show) { return; } - var entries = [], lf = options.legend.labelFormatter, s, label, i; + var fragments = [], entries = [], rowStarted = false, + lf = options.legend.labelFormatter, s, label; // Build a list of legend entries, with each having a label and a color - for (i = 0; i < series.length; ++i) { + for (var i = 0; i < series.length; ++i) { s = series[i]; if (s.label) { label = lf ? lf(s.label, s) : s.label; @@ -2978,24 +2739,18 @@ Licensed under the MIT license. } } - // No entries implies no legend - - if (entries.length === 0) { - return; - } - // Sort the legend using either the default or a custom comparator if (options.legend.sorted) { if ($.isFunction(options.legend.sorted)) { entries.sort(options.legend.sorted); - } else if (options.legend.sorted === "reverse") { - entries.reverse(); + } else if (options.legend.sorted == "reverse") { + entries.reverse(); } else { - var ascending = options.legend.sorted !== "descending"; + var ascending = options.legend.sorted != "descending"; entries.sort(function(a, b) { - return a.label === b.label ? 0 : ( - (a.label < b.label) !== ascending ? 1 : -1 // Logical XOR + return a.label == b.label ? 0 : ( + ((a.label < b.label) != ascending ? 1 : -1) // Logical XOR ); }); } @@ -3003,86 +2758,63 @@ Licensed under the MIT license. // Generate markup for the list of entries, in their final order - var table = $("
").css({ - "font-size": "smaller", - "color": options.grid.color - }), rowBuffer = null; - - for (i = 0; i < entries.length; ++i) { + for (var i = 0; i < entries.length; ++i) { var entry = entries[i]; - if (i % options.legend.noColumns === 0) { - if (rowBuffer !== null) { - table.append(rowBuffer); - } - rowBuffer = $(""); + if (i % options.legend.noColumns == 0) { + if (rowStarted) + fragments.push(''); + fragments.push(''); + rowStarted = true; } - var colorbox = $("
").css({ - "width": "4px", - "height": 0, - "border": "5px solid " + entry.color, - "overflow": "hidden" - }), - - borderbox = $("
").css({ - "border": "1px solid " + options.legend.labelBoxBorderColor, - "padding": "1px" - }); - - rowBuffer.append( - $("").addClass("legendColorBox").append(borderbox.append(colorbox)), - $("").addClass("legendLabel").html(entry.label) + fragments.push( + '
' + + '' + entry.label + '' ); } - table.append(rowBuffer); + if (rowStarted) + fragments.push(''); - if (options.legend.container != null) { + if (fragments.length == 0) + return; + + var table = '' + fragments.join("") + '
'; + if (options.legend.container != null) $(options.legend.container).html(table); - } else { - var pos = {"position": "absolute"}, + else { + var pos = "", p = options.legend.position, m = options.legend.margin; - if (m[0] == null) { + if (m[0] == null) m = [m, m]; - } - if (p.charAt(0) === "n") { - pos.top = (m[1] + plotOffset.top) + "px"; - } else if (p.charAt(0) === "s") { - pos.bottom = (m[1] + plotOffset.bottom) + "px"; - } - if (p.charAt(1) === "e") { - pos.right = (m[0] + plotOffset.right) + "px"; - } else if (p.charAt(1) === "w") { - pos.left = (m[0] + plotOffset.left) + "px"; - } - var legend = $("
").addClass("legend").append(table.css(pos)).appendTo(placeholder); - if (options.legend.backgroundOpacity !== 0.0) { + if (p.charAt(0) == "n") + pos += 'top:' + (m[1] + plotOffset.top) + 'px;'; + else if (p.charAt(0) == "s") + pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;'; + if (p.charAt(1) == "e") + pos += 'right:' + (m[0] + plotOffset.right) + 'px;'; + else if (p.charAt(1) == "w") + pos += 'left:' + (m[0] + plotOffset.left) + 'px;'; + var legend = $('
' + table.replace('style="', 'style="position:absolute;' + pos +';') + '
').appendTo(placeholder); + if (options.legend.backgroundOpacity != 0.0) { // put in the transparent background // separately to avoid blended labels and // label boxes var c = options.legend.backgroundColor; if (c == null) { c = options.grid.backgroundColor; - if (c && typeof c === "string") { + if (c && typeof c == "string") c = $.color.parse(c); - } else { - c = $.color.extract(legend, "background-color"); - } + else + c = $.color.extract(legend, 'background-color'); c.a = 1; c = c.toString(); } var div = legend.children(); - - // Position also applies to this - $("
").css(pos).css({ - "width": div.width() + "px", - "height": div.height() + "px", - "background-color": c, - "opacity": options.legend.backgroundOpacity - }).prependTo(legend); + $('
').prependTo(legend).css('opacity', options.legend.backgroundOpacity); } } } @@ -3097,12 +2829,11 @@ Licensed under the MIT license. function findNearbyItem(mouseX, mouseY, seriesFilter) { var maxDistance = options.grid.mouseActiveRadius, smallestDistance = maxDistance * maxDistance + 1, - item = null, i, j, ps; + item = null, foundPoint = false, i, j, ps; for (i = series.length - 1; i >= 0; --i) { - if (!seriesFilter(series[i])) { + if (!seriesFilter(series[i])) continue; - } var s = series[i], axisx = s.xaxis, @@ -3111,35 +2842,27 @@ Licensed under the MIT license. mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster my = axisy.c2p(mouseY), maxx = maxDistance / axisx.scale, - maxy = maxDistance / axisy.scale, - x, y; + maxy = maxDistance / axisy.scale; ps = s.datapoints.pointsize; // with inverse transforms, we can't use the maxx/maxy // optimization, sadly - if (axisx.options.inverseTransform) { + if (axisx.options.inverseTransform) maxx = Number.MAX_VALUE; - } - if (axisy.options.inverseTransform) { + if (axisy.options.inverseTransform) maxy = Number.MAX_VALUE; - } if (s.lines.show || s.points.show) { for (j = 0; j < points.length; j += ps) { - - x = points[j]; - y = points[j + 1]; - - if (x == null) { + var x = points[j], y = points[j + 1]; + if (x == null) continue; - } // For points and lines, the cursor must be within a // certain distance to the data point if (x - mx > maxx || x - mx < -maxx || - y - my > maxy || y - my < -maxy) { + y - my > maxy || y - my < -maxy) continue; - } // We have to calculate distances in pixels, not in // data units, because the scales of the axes may be different @@ -3157,25 +2880,34 @@ Licensed under the MIT license. } if (s.bars.show && !item) { // no other point can be nearby - var barLeft = s.bars.align === "left" ? 0 : -s.bars.barWidth/2, - barRight = barLeft + s.bars.barWidth; + + var barLeft, barRight; + + switch (s.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -s.bars.barWidth; + break; + default: + barLeft = -s.bars.barWidth / 2; + } + + barRight = barLeft + s.bars.barWidth; for (j = 0; j < points.length; j += ps) { - x = points[j]; - y = points[j + 1]; - var b = points[j + 2]; - if (x == null) { + var x = points[j], y = points[j + 1], b = points[j + 2]; + if (x == null) continue; - } // for a bar graph, the cursor must be inside the bar if (series[i].bars.horizontal ? (mx <= Math.max(b, x) && mx >= Math.min(b, x) && my >= y + barLeft && my <= y + barRight) : (mx >= x + barLeft && mx <= x + barRight && - my >= Math.min(b, y) && my <= Math.max(b, y))) { - item = [i, j / ps]; - } + my >= Math.min(b, y) && my <= Math.max(b, y))) + item = [i, j / ps]; } } } @@ -3195,22 +2927,20 @@ Licensed under the MIT license. } function onMouseMove(e) { - if (options.grid.hoverable) { + if (options.grid.hoverable) triggerClickHoverEvent("plothover", e, - function (s) { return s.hoverable !== false; }); - } + function (s) { return s["hoverable"] != false; }); } function onMouseLeave(e) { - if (options.grid.hoverable) { + if (options.grid.hoverable) triggerClickHoverEvent("plothover", e, - function () { return false; }); - } + function (s) { return false; }); } function onClick(e) { triggerClickHoverEvent("plotclick", e, - function (s) { return s.clickable !== false; }); + function (s) { return s["clickable"] != false; }); } // trigger click or hover event (they send the same parameters @@ -3236,18 +2966,15 @@ Licensed under the MIT license. // clear auto-highlights for (var i = 0; i < highlights.length; ++i) { var h = highlights[i]; - if (h.auto === eventname && !( - item && h.series === item.series && - h.point[0] === item.datapoint[0] && - h.point[1] === item.datapoint[1] - )) { + if (h.auto == eventname && + !(item && h.series == item.series && + h.point[0] == item.datapoint[0] && + h.point[1] == item.datapoint[1])) unhighlight(h.series, h.point); - } } - if (item) { + if (item) highlight(item.series, item.datapoint, eventname); - } } placeholder.trigger(eventname, [ pos, item ]); @@ -3255,14 +2982,13 @@ Licensed under the MIT license. function triggerRedrawOverlay() { var t = options.interaction.redrawOverlayInterval; - if (t === -1) { // skip event queue + if (t == -1) { // skip event queue drawOverlay(); return; } - if (!redrawTimeout) { + if (!redrawTimeout) redrawTimeout = setTimeout(drawOverlay, t); - } } function drawOverlay() { @@ -3277,11 +3003,10 @@ Licensed under the MIT license. for (i = 0; i < highlights.length; ++i) { hi = highlights[i]; - if (hi.series.bars.show) { + if (hi.series.bars.show) drawBarHighlight(hi.series, hi.point); - } else { + else drawPointHighlight(hi.series, hi.point); - } } octx.restore(); @@ -3289,22 +3014,22 @@ Licensed under the MIT license. } function highlight(s, point, auto) { - if (isNumeric(s)) { + if (typeof s == "number") s = series[s]; - } - if (isNumeric(point)) { + if (typeof point == "number") { var ps = s.datapoints.pointsize; point = s.datapoints.points.slice(ps * point, ps * (point + 1)); } var i = indexOfHighlight(s, point); - if (i === -1) { + if (i == -1) { highlights.push({ series: s, point: point, auto: auto }); + triggerRedrawOverlay(); - } else if (!auto) { - highlights[i].auto = false; } + else if (!auto) + highlights[i].auto = false; } function unhighlight(s, point) { @@ -3314,18 +3039,18 @@ Licensed under the MIT license. return; } - if (isNumeric(s)) { + if (typeof s == "number") s = series[s]; - } - if (isNumeric(point)) { + if (typeof point == "number") { var ps = s.datapoints.pointsize; point = s.datapoints.points.slice(ps * point, ps * (point + 1)); } var i = indexOfHighlight(s, point); - if (i !== -1) { + if (i != -1) { highlights.splice(i, 1); + triggerRedrawOverlay(); } } @@ -3333,9 +3058,9 @@ Licensed under the MIT license. function indexOfHighlight(s, p) { for (var i = 0; i < highlights.length; ++i) { var h = highlights[i]; - if (h.series === s && h.point[0] === p[0] && h.point[1] === p[1]) { + if (h.series == s && h.point[0] == p[0] + && h.point[1] == p[1]) return i; - } } return -1; } @@ -3343,52 +3068,54 @@ Licensed under the MIT license. function drawPointHighlight(series, point) { var x = point[0], y = point[1], axisx = series.xaxis, axisy = series.yaxis, - highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale("a", 0.5).toString(); + highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(); - if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) { + if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) return; - } - var pointRadius; - var radius; - if (series.points.show) { - pointRadius = series.points.radius + series.points.lineWidth / 2; - radius = 1.5 * pointRadius; - } else { - pointRadius = series.points.radius; - radius = 0.5 * pointRadius; - } + var pointRadius = series.points.radius + series.points.lineWidth / 2; octx.lineWidth = pointRadius; octx.strokeStyle = highlightColor; + var radius = 1.5 * pointRadius; x = axisx.p2c(x); y = axisy.p2c(y); octx.beginPath(); - if (series.points.symbol === "circle") { + if (series.points.symbol == "circle") octx.arc(x, y, radius, 0, 2 * Math.PI, false); - } else { + else series.points.symbol(octx, x, y, radius, false); - } octx.closePath(); octx.stroke(); } function drawBarHighlight(series, point) { - var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale("a", 0.5).toString(), + var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(), fillStyle = highlightColor, - barLeft = series.bars.align === "left" ? 0 : -series.bars.barWidth/2; + barLeft; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; + } octx.lineWidth = series.bars.lineWidth; octx.strokeStyle = highlightColor; drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth, - 0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth); + function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth); } function getColorOrGradient(spec, bottom, top, defaultColor) { - if (typeof spec === "string") { + if (typeof spec == "string") return spec; - } else { + else { // assume this is a gradient spec; IE currently only // supports a simple vertical gradient properly, so that's // what we support too @@ -3396,14 +3123,12 @@ Licensed under the MIT license. for (var i = 0, l = spec.colors.length; i < l; ++i) { var c = spec.colors[i]; - if (typeof c !== "string") { + if (typeof c != "string") { var co = $.color.parse(defaultColor); - if (c.brightness != null) { - co = co.scale("rgb", c.brightness); - } - if (c.opacity != null) { + if (c.brightness != null) + co = co.scale('rgb', c.brightness); + if (c.opacity != null) co.a *= c.opacity; - } c = co.toString(); } gradient.addColorStop(i / (l - 1), c); @@ -3423,7 +3148,7 @@ Licensed under the MIT license. return plot; }; - $.plot.version = "0.9.0-alpha"; + $.plot.version = "0.8.3"; $.plot.plugins = []; @@ -3440,4 +3165,4 @@ Licensed under the MIT license. return base * Math.floor(n / base); } -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/packages/kbn-ftr-common-functional-services/services/saml_auth/default_request_headers.ts b/packages/kbn-ftr-common-functional-services/services/saml_auth/default_request_headers.ts index e81f3383c9e93..b07ac58c56854 100644 --- a/packages/kbn-ftr-common-functional-services/services/saml_auth/default_request_headers.ts +++ b/packages/kbn-ftr-common-functional-services/services/saml_auth/default_request_headers.ts @@ -14,6 +14,7 @@ export const COMMON_REQUEST_HEADERS = { // possible change in 9.0 to match serverless const STATEFUL_INTERNAL_REQUEST_HEADERS = { ...COMMON_REQUEST_HEADERS, + 'x-elastic-internal-origin': 'kibana', }; const SERVERLESS_INTERNAL_REQUEST_HEADERS = { diff --git a/packages/kbn-ftr-common-functional-services/services/saml_auth/serverless/auth_provider.ts b/packages/kbn-ftr-common-functional-services/services/saml_auth/serverless/auth_provider.ts index 16c2dc9cfa844..b9583e3b8cb3a 100644 --- a/packages/kbn-ftr-common-functional-services/services/saml_auth/serverless/auth_provider.ts +++ b/packages/kbn-ftr-common-functional-services/services/saml_auth/serverless/auth_provider.ts @@ -7,6 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import getopts from 'getopts'; import { ServerlessProjectType, SERVERLESS_ROLES_ROOT_PATH } from '@kbn/es'; import { type Config } from '@kbn/test'; import { isServerlessProjectType, readRolesDescriptorsFromResource } from '@kbn/es/src/utils'; @@ -34,30 +35,23 @@ const getDefaultServerlessRole = (projectType: string) => { } }; -const isRoleManagementExplicitlyEnabled = (args: string[]): boolean => { - const roleManagementArg = args.find((arg) => - arg.startsWith('--xpack.security.roleManagementEnabled=') - ); - - // Return true if the value is explicitly set to 'true', otherwise false - return roleManagementArg?.split('=')[1] === 'true' || false; -}; - export class ServerlessAuthProvider implements AuthProvider { private readonly projectType: string; private readonly roleManagementEnabled: boolean; private readonly rolesDefinitionPath: string; constructor(config: Config) { - const kbnServerArgs = config.get('kbnTestServer.serverArgs') as string[]; - this.projectType = kbnServerArgs.reduce((acc, arg) => { - const match = arg.match(/--serverless[=\s](\w+)/); - return acc + (match ? match[1] : ''); - }, '') as ServerlessProjectType; + const options = getopts(config.get('kbnTestServer.serverArgs'), { + boolean: ['xpack.security.roleManagementEnabled'], + default: { + 'xpack.security.roleManagementEnabled': false, + }, + }); + this.projectType = options.serverless as ServerlessProjectType; // Indicates whether role management was explicitly enabled using // the `--xpack.security.roleManagementEnabled=true` flag. - this.roleManagementEnabled = isRoleManagementExplicitlyEnabled(kbnServerArgs); + this.roleManagementEnabled = options['xpack.security.roleManagementEnabled']; if (!isServerlessProjectType(this.projectType)) { throw new Error(`Unsupported serverless projectType: ${this.projectType}`); diff --git a/packages/kbn-grid-layout/grid/drag_preview.tsx b/packages/kbn-grid-layout/grid/drag_preview.tsx new file mode 100644 index 0000000000000..24aa81ffea1df --- /dev/null +++ b/packages/kbn-grid-layout/grid/drag_preview.tsx @@ -0,0 +1,71 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React, { useEffect, useRef } from 'react'; +import { combineLatest, skip } from 'rxjs'; + +import { transparentize } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; + +import { GridLayoutStateManager } from './types'; + +export const DragPreview = ({ + rowIndex, + gridLayoutStateManager, +}: { + rowIndex: number; + gridLayoutStateManager: GridLayoutStateManager; +}) => { + const dragPreviewRef = useRef(null); + + useEffect( + () => { + /** Update the styles of the drag preview via a subscription to prevent re-renders */ + const styleSubscription = combineLatest([ + gridLayoutStateManager.activePanel$, + gridLayoutStateManager.gridLayout$, + ]) + .pipe(skip(1)) // skip the first emit because the drag preview is only rendered after a user action + .subscribe(([activePanel, gridLayout]) => { + if (!dragPreviewRef.current) return; + + if (!activePanel || !gridLayout[rowIndex].panels[activePanel.id]) { + dragPreviewRef.current.style.display = 'none'; + } else { + const panel = gridLayout[rowIndex].panels[activePanel.id]; + dragPreviewRef.current.style.display = 'block'; + dragPreviewRef.current.style.gridColumnStart = `${panel.column + 1}`; + dragPreviewRef.current.style.gridColumnEnd = `${panel.column + 1 + panel.width}`; + dragPreviewRef.current.style.gridRowStart = `${panel.row + 1}`; + dragPreviewRef.current.style.gridRowEnd = `${panel.row + 1 + panel.height}`; + } + }); + + return () => { + styleSubscription.unsubscribe(); + }; + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [] + ); + + return ( +
+ ); +}; diff --git a/packages/kbn-grid-layout/grid/grid_layout.tsx b/packages/kbn-grid-layout/grid/grid_layout.tsx index c6bbd94dabe56..7f77a476579e9 100644 --- a/packages/kbn-grid-layout/grid/grid_layout.tsx +++ b/packages/kbn-grid-layout/grid/grid_layout.tsx @@ -7,9 +7,9 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React from 'react'; - -import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; +import React, { useEffect, useState } from 'react'; +import { distinctUntilChanged, map, skip } from 'rxjs'; +import { v4 as uuidv4 } from 'uuid'; import { GridHeightSmoother } from './grid_height_smoother'; import { GridRow } from './grid_row'; @@ -29,12 +29,28 @@ export const GridLayout = ({ }); useGridLayoutEvents({ gridLayoutStateManager }); - const [gridLayout, runtimeSettings, interactionEvent] = useBatchedPublishingSubjects( - gridLayoutStateManager.gridLayout$, - gridLayoutStateManager.runtimeSettings$, - gridLayoutStateManager.interactionEvent$ + const [rowCount, setRowCount] = useState( + gridLayoutStateManager.gridLayout$.getValue().length ); + useEffect(() => { + /** + * The only thing that should cause the entire layout to re-render is adding a new row; + * this subscription ensures this by updating the `rowCount` state when it changes. + */ + const rowCountSubscription = gridLayoutStateManager.gridLayout$ + .pipe( + skip(1), // we initialized `rowCount` above, so skip the initial emit + map((newLayout) => newLayout.length), + distinctUntilChanged() + ) + .subscribe((newRowCount) => { + setRowCount(newRowCount); + }); + return () => rowCountSubscription.unsubscribe(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return ( <> @@ -43,15 +59,12 @@ export const GridLayout = ({ setDimensionsRef(divElement); }} > - {gridLayout.map((rowData, rowIndex) => { + {Array.from({ length: rowCount }, (_, rowIndex) => { return ( { const currentLayout = gridLayoutStateManager.gridLayout$.value; diff --git a/packages/kbn-grid-layout/grid/grid_panel.tsx b/packages/kbn-grid-layout/grid/grid_panel.tsx index fbe34c4b68e15..64a4a2faff403 100644 --- a/packages/kbn-grid-layout/grid/grid_panel.tsx +++ b/packages/kbn-grid-layout/grid/grid_panel.tsx @@ -7,7 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React, { forwardRef } from 'react'; +import React, { forwardRef, useEffect, useMemo } from 'react'; +import { combineLatest, skip } from 'rxjs'; import { EuiIcon, @@ -20,108 +21,191 @@ import { import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; -import { GridPanelData, PanelInteractionEvent } from './types'; +import { GridLayoutStateManager, PanelInteractionEvent } from './types'; export const GridPanel = forwardRef< HTMLDivElement, { - panelData: GridPanelData; - activePanelId: string | undefined; + panelId: string; + rowIndex: number; renderPanelContents: (panelId: string) => React.ReactNode; interactionStart: ( type: PanelInteractionEvent['type'], e: React.MouseEvent ) => void; + gridLayoutStateManager: GridLayoutStateManager; } ->(({ activePanelId, panelData, renderPanelContents, interactionStart }, panelRef) => { - const { euiTheme } = useEuiTheme(); - const thisPanelActive = activePanelId === panelData.id; +>( + ( + { panelId, rowIndex, renderPanelContents, interactionStart, gridLayoutStateManager }, + panelRef + ) => { + const { euiTheme } = useEuiTheme(); - return ( -
- - {/* drag handle */} -
interactionStart('drag', e)} - onMouseUp={(e) => interactionStart('drop', e)} - > - -
- {/* Resize handle */} -
interactionStart('resize', e)} - onMouseUp={(e) => interactionStart('drop', e)} - css={css` - right: 0; - bottom: 0; - opacity: 0; - margin: -2px; - position: absolute; - width: ${euiThemeVars.euiSizeL}; - height: ${euiThemeVars.euiSizeL}; - transition: opacity 0.2s, border 0.2s; - border-radius: 7px 0 7px 0; - border-bottom: 2px solid ${euiThemeVars.euiColorSuccess}; - border-right: 2px solid ${euiThemeVars.euiColorSuccess}; - :hover { - background-color: ${transparentize(euiThemeVars.euiColorSuccess, 0.05)}; - cursor: se-resize; + /** Set initial styles based on state at mount to prevent styles from "blipping" */ + const initialStyles = useMemo(() => { + const initialPanel = gridLayoutStateManager.gridLayout$.getValue()[rowIndex].panels[panelId]; + return css` + grid-column-start: ${initialPanel.column + 1}; + grid-column-end: ${initialPanel.column + 1 + initialPanel.width}; + grid-row-start: ${initialPanel.row + 1}; + grid-row-end: ${initialPanel.row + 1 + initialPanel.height}; + `; + }, [gridLayoutStateManager, rowIndex, panelId]); + + useEffect( + () => { + /** Update the styles of the panel via a subscription to prevent re-renders */ + const styleSubscription = combineLatest([ + gridLayoutStateManager.activePanel$, + gridLayoutStateManager.gridLayout$, + gridLayoutStateManager.runtimeSettings$, + ]) + .pipe(skip(1)) // skip the first emit because the `initialStyles` will take care of it + .subscribe(([activePanel, gridLayout, runtimeSettings]) => { + const ref = gridLayoutStateManager.panelRefs.current[rowIndex][panelId]; + const panel = gridLayout[rowIndex].panels[panelId]; + if (!ref || !panel) return; + + const currentInteractionEvent = gridLayoutStateManager.interactionEvent$.getValue(); + if (panelId === activePanel?.id) { + // if the current panel is active, give it fixed positioning depending on the interaction event + const { position: draggingPosition } = activePanel; + + ref.style.zIndex = `${euiThemeVars.euiZModal}`; + if (currentInteractionEvent?.type === 'resize') { + // if the current panel is being resized, ensure it is not shrunk past the size of a single cell + ref.style.width = `${Math.max( + draggingPosition.right - draggingPosition.left, + runtimeSettings.columnPixelWidth + )}px`; + ref.style.height = `${Math.max( + draggingPosition.bottom - draggingPosition.top, + runtimeSettings.rowHeight + )}px`; + + // undo any "lock to grid" styles **except** for the top left corner, which stays locked + ref.style.gridColumnStart = `${panel.column + 1}`; + ref.style.gridRowStart = `${panel.row + 1}`; + ref.style.gridColumnEnd = ``; + ref.style.gridRowEnd = ``; + } else { + // if the current panel is being dragged, render it with a fixed position + size + ref.style.position = 'fixed'; + ref.style.left = `${draggingPosition.left}px`; + ref.style.top = `${draggingPosition.top}px`; + ref.style.width = `${draggingPosition.right - draggingPosition.left}px`; + ref.style.height = `${draggingPosition.bottom - draggingPosition.top}px`; + + // undo any "lock to grid" styles + ref.style.gridColumnStart = ``; + ref.style.gridRowStart = ``; + ref.style.gridColumnEnd = ``; + ref.style.gridRowEnd = ``; + } + } else { + ref.style.zIndex = '0'; + + // if the panel is not being dragged and/or resized, undo any fixed position styles + ref.style.position = ''; + ref.style.left = ``; + ref.style.top = ``; + ref.style.width = ``; + ref.style.height = ``; + + // and render the panel locked to the grid + ref.style.gridColumnStart = `${panel.column + 1}`; + ref.style.gridColumnEnd = `${panel.column + 1 + panel.width}`; + ref.style.gridRowStart = `${panel.row + 1}`; + ref.style.gridRowEnd = `${panel.row + 1 + panel.height}`; } - `} - /> -
{ + styleSubscription.unsubscribe(); + }; + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [] + ); + + return ( +
+ - {renderPanelContents(panelData.id)} -
- -
- ); -}); + {/* drag handle */} +
interactionStart('drag', e)} + onMouseUp={(e) => interactionStart('drop', e)} + > + +
+ {/* Resize handle */} +
interactionStart('resize', e)} + onMouseUp={(e) => interactionStart('drop', e)} + css={css` + right: 0; + bottom: 0; + opacity: 0; + margin: -2px; + position: absolute; + width: ${euiThemeVars.euiSizeL}; + height: ${euiThemeVars.euiSizeL}; + transition: opacity 0.2s, border 0.2s; + border-radius: 7px 0 7px 0; + border-bottom: 2px solid ${euiThemeVars.euiColorSuccess}; + border-right: 2px solid ${euiThemeVars.euiColorSuccess}; + :hover { + background-color: ${transparentize(euiThemeVars.euiColorSuccess, 0.05)}; + cursor: se-resize; + } + `} + /> +
+ {renderPanelContents(panelId)} +
+ +
+ ); + } +); diff --git a/packages/kbn-grid-layout/grid/grid_row.tsx b/packages/kbn-grid-layout/grid/grid_row.tsx index 917f661c91740..e797cd570550a 100644 --- a/packages/kbn-grid-layout/grid/grid_row.tsx +++ b/packages/kbn-grid-layout/grid/grid_row.tsx @@ -7,41 +7,23 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React, { forwardRef, useMemo, useRef } from 'react'; +import React, { forwardRef, useCallback, useEffect, useMemo, useState } from 'react'; +import { combineLatest, map, pairwise, skip } from 'rxjs'; import { EuiButtonIcon, EuiFlexGroup, EuiSpacer, EuiTitle, transparentize } from '@elastic/eui'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { euiThemeVars } from '@kbn/ui-theme'; -import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; +import { DragPreview } from './drag_preview'; import { GridPanel } from './grid_panel'; -import { - GridLayoutStateManager, - GridRowData, - PanelInteractionEvent, - RuntimeGridSettings, -} from './types'; - -const gridColor = transparentize(euiThemeVars.euiColorSuccess, 0.2); -const getGridBackgroundCSS = (settings: RuntimeGridSettings) => { - const { gutterSize, columnPixelWidth, rowHeight } = settings; - return css` - background-position: top -${gutterSize / 2}px left -${gutterSize / 2}px; - background-size: ${columnPixelWidth + gutterSize}px ${rowHeight + gutterSize}px; - background-image: linear-gradient(to right, ${gridColor} 1px, transparent 1px), - linear-gradient(to bottom, ${gridColor} 1px, transparent 1px); - `; -}; +import { GridLayoutStateManager, GridRowData, PanelInteractionEvent } from './types'; export const GridRow = forwardRef< HTMLDivElement, { rowIndex: number; - rowData: GridRowData; toggleIsCollapsed: () => void; - targetRowIndex: number | undefined; - runtimeSettings: RuntimeGridSettings; renderPanelContents: (panelId: string) => React.ReactNode; setInteractionEvent: (interactionData?: PanelInteractionEvent) => void; gridLayoutStateManager: GridLayoutStateManager; @@ -49,10 +31,7 @@ export const GridRow = forwardRef< >( ( { - rowData, rowIndex, - targetRowIndex, - runtimeSettings, toggleIsCollapsed, renderPanelContents, setInteractionEvent, @@ -60,19 +39,122 @@ export const GridRow = forwardRef< }, gridRef ) => { - const dragPreviewRef = useRef(null); - const activePanel = useStateFromPublishingSubject(gridLayoutStateManager.activePanel$); + const currentRow = gridLayoutStateManager.gridLayout$.value[rowIndex]; + const [panelIds, setPanelIds] = useState(Object.keys(currentRow.panels)); + const [rowTitle, setRowTitle] = useState(currentRow.title); + const [isCollapsed, setIsCollapsed] = useState(currentRow.isCollapsed); - const { gutterSize, columnCount, rowHeight } = runtimeSettings; - const isGridTargeted = activePanel?.id && targetRowIndex === rowIndex; + const getRowCount = useCallback( + (row: GridRowData) => { + const maxRow = Object.values(row.panels).reduce((acc, panel) => { + return Math.max(acc, panel.row + panel.height); + }, 0); + return maxRow || 1; + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [rowIndex] + ); + + /** Set initial styles based on state at mount to prevent styles from "blipping" */ + const initialStyles = useMemo(() => { + const initialRow = gridLayoutStateManager.gridLayout$.getValue()[rowIndex]; + const runtimeSettings = gridLayoutStateManager.runtimeSettings$.getValue(); + const { gutterSize, columnCount, rowHeight } = runtimeSettings; + + return css` + gap: ${gutterSize}px; + grid-template-columns: repeat( + ${columnCount}, + calc((100% - ${gutterSize * (columnCount - 1)}px) / ${columnCount}) + ); + grid-template-rows: repeat(${getRowCount(initialRow)}, ${rowHeight}px); + `; + }, [gridLayoutStateManager, getRowCount, rowIndex]); + + useEffect( + () => { + /** Update the styles of the grid row via a subscription to prevent re-renders */ + const styleSubscription = combineLatest([ + gridLayoutStateManager.interactionEvent$, + gridLayoutStateManager.gridLayout$, + gridLayoutStateManager.runtimeSettings$, + ]) + .pipe(skip(1)) // skip the first emit because the `initialStyles` will take care of it + .subscribe(([interactionEvent, gridLayout, runtimeSettings]) => { + const rowRef = gridLayoutStateManager.rowRefs.current[rowIndex]; + if (!rowRef) return; + + const { gutterSize, rowHeight, columnPixelWidth } = runtimeSettings; - // calculate row count based on the number of rows needed to fit all panels - const rowCount = useMemo(() => { - const maxRow = Object.values(rowData.panels).reduce((acc, panel) => { - return Math.max(acc, panel.row + panel.height); - }, 0); - return maxRow || 1; - }, [rowData]); + rowRef.style.gridTemplateRows = `repeat(${getRowCount( + gridLayout[rowIndex] + )}, ${rowHeight}px)`; + + const targetRow = interactionEvent?.targetRowIndex; + if (rowIndex === targetRow && interactionEvent?.type !== 'drop') { + // apply "targetted row" styles + const gridColor = transparentize(euiThemeVars.euiColorSuccess, 0.2); + rowRef.style.backgroundPosition = `top -${gutterSize / 2}px left -${ + gutterSize / 2 + }px`; + rowRef.style.backgroundSize = ` ${columnPixelWidth + gutterSize}px ${ + rowHeight + gutterSize + }px`; + rowRef.style.backgroundImage = `linear-gradient(to right, ${gridColor} 1px, transparent 1px), + linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)`; + rowRef.style.backgroundColor = `${transparentize( + euiThemeVars.euiColorSuccess, + 0.05 + )}`; + } else { + // undo any "targetted row" styles + rowRef.style.backgroundPosition = ``; + rowRef.style.backgroundSize = ``; + rowRef.style.backgroundImage = ``; + rowRef.style.backgroundColor = `transparent`; + } + }); + + /** + * The things that should trigger a re-render are title, collapsed state, and panel ids - panel positions + * are being controlled via CSS styles, so they do not need to trigger a re-render. This subscription ensures + * that the row will re-render when one of those three things changes. + */ + const rowStateSubscription = gridLayoutStateManager.gridLayout$ + .pipe( + skip(1), // we are initializing all row state with a value, so skip the initial emit + map((gridLayout) => { + return { + title: gridLayout[rowIndex].title, + isCollapsed: gridLayout[rowIndex].isCollapsed, + panelIds: Object.keys(gridLayout[rowIndex].panels), + }; + }), + pairwise() + ) + .subscribe(([oldRowData, newRowData]) => { + if (oldRowData.title !== newRowData.title) setRowTitle(newRowData.title); + if (oldRowData.isCollapsed !== newRowData.isCollapsed) + setIsCollapsed(newRowData.isCollapsed); + if ( + oldRowData.panelIds.length !== newRowData.panelIds.length || + !( + oldRowData.panelIds.every((p) => newRowData.panelIds.includes(p)) && + newRowData.panelIds.every((p) => oldRowData.panelIds.includes(p)) + ) + ) { + setPanelIds(newRowData.panelIds); + } + }); + + return () => { + styleSubscription.unsubscribe(); + rowStateSubscription.unsubscribe(); + }; + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [rowIndex] + ); return ( <> @@ -85,51 +167,43 @@ export const GridRow = forwardRef< aria-label={i18n.translate('kbnGridLayout.row.toggleCollapse', { defaultMessage: 'Toggle collapse', })} - iconType={rowData.isCollapsed ? 'arrowRight' : 'arrowDown'} + iconType={isCollapsed ? 'arrowRight' : 'arrowDown'} onClick={toggleIsCollapsed} /> -

{rowData.title}

+

{rowTitle}

)} - {!rowData.isCollapsed && ( + {!isCollapsed && (
- {Object.values(rowData.panels).map((panelData) => ( + {panelIds.map((panelId) => ( { e.preventDefault(); e.stopPropagation(); - const panelRef = gridLayoutStateManager.panelRefs.current[rowIndex][panelData.id]; + const panelRef = gridLayoutStateManager.panelRefs.current[rowIndex][panelId]; if (!panelRef) return; const panelRect = panelRef.getBoundingClientRect(); setInteractionEvent({ type, - id: panelData.id, + id: panelId, panelDiv: panelRef, targetRowIndex: rowIndex, mouseOffsets: { @@ -144,32 +218,12 @@ export const GridRow = forwardRef< if (!gridLayoutStateManager.panelRefs.current[rowIndex]) { gridLayoutStateManager.panelRefs.current[rowIndex] = {}; } - gridLayoutStateManager.panelRefs.current[rowIndex][panelData.id] = element; + gridLayoutStateManager.panelRefs.current[rowIndex][panelId] = element; }} /> ))} - {/* render the drag preview if this row is currently being targetted */} - {isGridTargeted && ( -
- )} +
)} diff --git a/packages/kbn-grid-layout/grid/use_grid_layout_events.ts b/packages/kbn-grid-layout/grid/use_grid_layout_events.ts index dfbd013d3642a..bd6343b9e5652 100644 --- a/packages/kbn-grid-layout/grid/use_grid_layout_events.ts +++ b/packages/kbn-grid-layout/grid/use_grid_layout_events.ts @@ -8,6 +8,7 @@ */ import { useEffect, useRef } from 'react'; +import deepEqual from 'fast-deep-equal'; import { resolveGridRow } from './resolve_grid_row'; import { GridLayoutStateManager, GridPanelData } from './types'; @@ -121,6 +122,7 @@ export const useGridLayoutEvents = ({ maxColumn ); const targetRow = Math.max(Math.round(localYCoordinate / (rowHeight + gutterSize)), 0); + const requestedGridData = { ...currentGridData }; if (isResize) { requestedGridData.width = Math.max(targetColumn - requestedGridData.column, 1); @@ -154,8 +156,9 @@ export const useGridLayoutEvents = ({ const resolvedOriginGrid = resolveGridRow(originGrid); nextLayout[lastRowIndex] = resolvedOriginGrid; } - - gridLayout$.next(nextLayout); + if (!deepEqual(currentLayout, nextLayout)) { + gridLayout$.next(nextLayout); + } } }; diff --git a/packages/kbn-grid-layout/grid/use_grid_layout_state.ts b/packages/kbn-grid-layout/grid/use_grid_layout_state.ts index cdb99a9ebbfd0..fe657ae253107 100644 --- a/packages/kbn-grid-layout/grid/use_grid_layout_state.ts +++ b/packages/kbn-grid-layout/grid/use_grid_layout_state.ts @@ -7,10 +7,11 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { i18n } from '@kbn/i18n'; import { useEffect, useMemo, useRef } from 'react'; -import { BehaviorSubject, combineLatest, debounceTime, map, retry } from 'rxjs'; +import { BehaviorSubject, debounceTime } from 'rxjs'; + import useResizeObserver, { type ObservedSize } from 'use-resize-observer/polyfilled'; + import { ActivePanel, GridLayoutData, @@ -43,10 +44,14 @@ export const useGridLayoutState = ({ ...gridSettings, columnPixelWidth: 0, }); + const panelIds$ = new BehaviorSubject( + initialLayout.map(({ panels }) => Object.keys(panels)) + ); return { rowRefs, panelRefs, + panelIds$, gridLayout$, activePanel$, gridDimensions$, @@ -67,117 +72,12 @@ export const useGridLayoutState = ({ const columnPixelWidth = (elementWidth - gridSettings.gutterSize * (gridSettings.columnCount - 1)) / gridSettings.columnCount; - gridLayoutStateManager.runtimeSettings$.next({ ...gridSettings, columnPixelWidth }); - }); - - /** - * on layout change, update the styles of every panel so that it renders as expected - */ - const onLayoutChangeSubscription = combineLatest([ - gridLayoutStateManager.gridLayout$, - gridLayoutStateManager.activePanel$, - ]) - .pipe( - map(([gridLayout, activePanel]) => { - // wait for all panel refs to be ready before continuing - for (let rowIndex = 0; rowIndex < gridLayout.length; rowIndex++) { - const currentRow = gridLayout[rowIndex]; - Object.keys(currentRow.panels).forEach((key) => { - const panelRef = gridLayoutStateManager.panelRefs.current[rowIndex][key]; - if (!panelRef && !currentRow.isCollapsed) { - throw new Error( - i18n.translate('kbnGridLayout.panelRefNotFoundError', { - defaultMessage: 'Panel reference does not exist', // the retry will catch this error - }) - ); - } - }); - } - return { gridLayout, activePanel }; - }), - retry({ delay: 10 }) // retry until panel references all exist - ) - .subscribe(({ gridLayout, activePanel }) => { - const runtimeSettings = gridLayoutStateManager.runtimeSettings$.getValue(); - const currentInteractionEvent = gridLayoutStateManager.interactionEvent$.getValue(); - for (let rowIndex = 0; rowIndex < gridLayout.length; rowIndex++) { - if (activePanel && rowIndex !== currentInteractionEvent?.targetRowIndex) { - /** - * If there is an interaction event happening but the current row is not being targetted, it - * does not need to be re-rendered; so, skip setting the panel styles of this row. - * - * If there is **no** interaction event, then this is the initial render so the styles of every - * panel should be initialized; so, don't skip setting the panel styles. - */ - continue; - } - - // re-render the targetted row - const currentRow = gridLayout[rowIndex]; - Object.keys(currentRow.panels).forEach((key) => { - const panel = currentRow.panels[key]; - const panelRef = gridLayoutStateManager.panelRefs.current[rowIndex][key]; - if (!panelRef) { - return; - } - - const isResize = currentInteractionEvent?.type === 'resize'; - if (panel.id === activePanel?.id) { - // if the current panel is active, give it fixed positioning depending on the interaction event - const { position: draggingPosition } = activePanel; - - if (isResize) { - // if the current panel is being resized, ensure it is not shrunk past the size of a single cell - panelRef.style.width = `${Math.max( - draggingPosition.right - draggingPosition.left, - runtimeSettings.columnPixelWidth - )}px`; - panelRef.style.height = `${Math.max( - draggingPosition.bottom - draggingPosition.top, - runtimeSettings.rowHeight - )}px`; - - // undo any "lock to grid" styles **except** for the top left corner, which stays locked - panelRef.style.gridColumnStart = `${panel.column + 1}`; - panelRef.style.gridRowStart = `${panel.row + 1}`; - panelRef.style.gridColumnEnd = ``; - panelRef.style.gridRowEnd = ``; - } else { - // if the current panel is being dragged, render it with a fixed position + size - panelRef.style.position = 'fixed'; - panelRef.style.left = `${draggingPosition.left}px`; - panelRef.style.top = `${draggingPosition.top}px`; - panelRef.style.width = `${draggingPosition.right - draggingPosition.left}px`; - panelRef.style.height = `${draggingPosition.bottom - draggingPosition.top}px`; - - // undo any "lock to grid" styles - panelRef.style.gridColumnStart = ``; - panelRef.style.gridRowStart = ``; - panelRef.style.gridColumnEnd = ``; - panelRef.style.gridRowEnd = ``; - } - } else { - // if the panel is not being dragged and/or resized, undo any fixed position styles - panelRef.style.position = ''; - panelRef.style.left = ``; - panelRef.style.top = ``; - panelRef.style.width = ``; - panelRef.style.height = ``; - - // and render the panel locked to the grid - panelRef.style.gridColumnStart = `${panel.column + 1}`; - panelRef.style.gridColumnEnd = `${panel.column + 1 + panel.width}`; - panelRef.style.gridRowStart = `${panel.row + 1}`; - panelRef.style.gridRowEnd = `${panel.row + 1 + panel.height}`; - } - }); - } + gridLayoutStateManager.runtimeSettings$.next({ ...gridSettings, columnPixelWidth }); }); return () => { resizeSubscription.unsubscribe(); - onLayoutChangeSubscription.unsubscribe(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/packages/kbn-grid-layout/tsconfig.json b/packages/kbn-grid-layout/tsconfig.json index 5a1888db0dc64..f0dd3232a42d5 100644 --- a/packages/kbn-grid-layout/tsconfig.json +++ b/packages/kbn-grid-layout/tsconfig.json @@ -17,7 +17,6 @@ "target/**/*" ], "kbn_references": [ - "@kbn/presentation-publishing", "@kbn/ui-theme", "@kbn/i18n", ] diff --git a/packages/kbn-language-documentation/src/sections/esql_documentation_sections.tsx b/packages/kbn-language-documentation/src/sections/esql_documentation_sections.tsx index 66c93fc0f7787..59f9b999c8a5f 100644 --- a/packages/kbn-language-documentation/src/sections/esql_documentation_sections.tsx +++ b/packages/kbn-language-documentation/src/sections/esql_documentation_sections.tsx @@ -19,7 +19,7 @@ export const initialSection = ( @@ -77,7 +77,7 @@ ES|QL can access the following metadata fields: Use the \`METADATA\` directive to enable metadata fields: \`\`\` -FROM index [METADATA _index, _id] +FROM index METADATA _index, _id \`\`\` Metadata fields are only available if the source of the data is an index. Consequently, \`FROM\` is the only source commands that supports the \`METADATA\` directive. @@ -85,7 +85,7 @@ Metadata fields are only available if the source of the data is an index. Conseq Once enabled, the fields are then available to subsequent processing commands, just like the other index fields: \`\`\` -FROM ul_logs, apps [METADATA _index, _version] +FROM ul_logs, apps METADATA _index, _version | WHERE id IN (13, 14) AND _version == 1 | EVAL key = CONCAT(_index, "_", TO_STR(id)) | SORT id, _index @@ -95,7 +95,7 @@ FROM ul_logs, apps [METADATA _index, _version] Also, similar to the index fields, once an aggregation is performed, a metadata field will no longer be accessible to subsequent commands, unless used as grouping field: \`\`\` -FROM employees [METADATA _index, _id] +FROM employees METADATA _index, _id | STATS max = MAX(emp_no) BY _index \`\`\` `, @@ -114,7 +114,7 @@ FROM employees [METADATA _index, _id] markdownContent={i18n.translate('languageDocumentation.documentationESQL.row.markdown', { defaultMessage: `### ROW The \`ROW\` source command produces a row with one or more columns with values that you specify. This can be useful for testing. - + \`\`\` ROW a = 1, b = "two", c = null \`\`\` @@ -207,7 +207,7 @@ ROW a = "1953-01-23T12:15:00Z - some text - 127.0.0.1" markdownContent={i18n.translate('languageDocumentation.documentationESQL.drop.markdown', { defaultMessage: `### DROP Use \`DROP\` to remove columns from a table: - + \`\`\` FROM employees | DROP height @@ -347,7 +347,7 @@ ROW a = "12 15.5 15.6 true" The \`KEEP\` command enables you to specify what columns are returned and the order in which they are returned. To limit the columns that are returned, use a comma-separated list of column names. The columns are returned in the specified order: - + \`\`\` FROM employees | KEEP first_name, last_name, height @@ -384,7 +384,7 @@ FROM employees { defaultMessage: `### LIMIT The \`LIMIT\` processing command enables you to limit the number of rows: - + \`\`\` FROM employees | LIMIT 5 @@ -407,7 +407,7 @@ FROM employees 'languageDocumentation.documentationESQL.mvExpand.markdown', { defaultMessage: `### MV_EXPAND -The \`MV_EXPAND\` processing command expands multivalued fields into one row per value, duplicating other fields: +The \`MV_EXPAND\` processing command expands multivalued fields into one row per value, duplicating other fields: \`\`\` ROW a=[1,2,3], b="b", j=["a","b"] | MV_EXPAND a @@ -607,7 +607,7 @@ FROM employees { defaultMessage: `### WHERE Use \`WHERE\` to produce a table that contains all the rows from the input table for which the provided condition evaluates to \`true\`: - + \`\`\` FROM employees | KEEP first_name, last_name, still_hired @@ -654,7 +654,7 @@ export const groupingFunctions = { defaultMessage: `### BUCKET Creates groups of values - buckets - out of a datetime or numeric input. The size of the buckets can either be provided directly, or chosen based on a recommended count and values range. -\`BUCKET\` works in two modes: +\`BUCKET\` works in two modes: 1. Where the size of the bucket is computed based on a buckets count recommendation (four parameters) and a range. 2. Where the bucket size is provided directly (two parameters). diff --git a/packages/kbn-management/settings/setting_ids/index.ts b/packages/kbn-management/settings/setting_ids/index.ts index e926007f77f25..b146be6f6e252 100644 --- a/packages/kbn-management/settings/setting_ids/index.ts +++ b/packages/kbn-management/settings/setting_ids/index.ts @@ -83,7 +83,6 @@ export const DISCOVER_SAMPLE_SIZE_ID = 'discover:sampleSize'; export const DISCOVER_SEARCH_FIELDS_FROM_SOURCE_ID = 'discover:searchFieldsFromSource'; export const DISCOVER_SEARCH_ON_PAGE_LOAD_ID = 'discover:searchOnPageLoad'; export const DISCOVER_SHOW_FIELD_STATISTICS_ID = 'discover:showFieldStatistics'; -export const DISCOVER_SHOW_LEGACY_FIELD_TOP_VALUES_ID = 'discover:showLegacyFieldTopValues'; export const DISCOVER_SHOW_MULTI_FIELDS_ID = 'discover:showMultiFields'; export const DISCOVER_SORT_DEFAULT_ORDER_ID = 'discover:sort:defaultOrder'; export const DOC_TABLE_HIDE_TIME_COLUMNS_ID = 'doc_table:hideTimeColumn'; @@ -122,10 +121,6 @@ export const OBSERVABILITY_APM_TRACE_EXPLORER_TAB_ID = 'observability:apmTraceEx export const OBSERVABILITY_ENABLE_AWS_LAMBDA_METRICS_ID = 'observability:enableAwsLambdaMetrics'; export const OBSERVABILITY_ENABLE_COMPARISON_BY_DEFAULT_ID = 'observability:enableComparisonByDefault'; -export const OBSERVABILITY_ENABLE_INFRASTRUCTURE_HOSTS_VIEW_ID = - 'observability:enableInfrastructureHostsView'; -export const OBSERVABILITY_ENABLE_INFRASTRUCTURE_CONTAINER_ASSET_VIEW_ID = - 'observability:enableInfrastructureContainerAssetView'; export const OBSERVABILITY_ENABLE_INFRASTRUCTURE_ASSET_CUSTOM_DASHBOARDS_ID = 'observability:enableInfrastructureAssetCustomDashboards'; export const OBSERVABILITY_ENABLE_INSPECT_ES_QUERIES_ID = 'observability:enableInspectEsQueries'; diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 96a17a6ae7229..b5da9566878e1 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -280,6 +280,14 @@ export function getWebpackConfig( plugins: ['@babel/plugin-transform-logical-assignment-operators'], }, }, + { + test: /node_modules[\/\\]launchdarkly[^\/\\]+[\/\\].*.js$/, + loaders: 'babel-loader', + options: { + envName: worker.dist ? 'production' : 'development', + presets: [BABEL_PRESET], + }, + }, { test: /\.(html|md|txt|tmpl)$/, use: { diff --git a/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap b/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap index fef935624ae64..1c1f5bed02a0e 100644 --- a/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap +++ b/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap @@ -44,7 +44,7 @@ Object { "paths": Object { "/foo/{id}": Object { "get": Object { - "operationId": "%2Ffoo%2F%7Bid%7D#0", + "operationId": "get-foo-id", "parameters": Array [ Object { "description": "The version of the API to use", @@ -138,7 +138,7 @@ Object { "/bar": Object { "get": Object { "deprecated": true, - "operationId": "%2Fbar#0", + "operationId": "get-bar", "parameters": Array [ Object { "description": "The version of the API to use", @@ -231,7 +231,7 @@ OK response oas-test-version-2", "/foo/{id}/{path*}": Object { "delete": Object { "description": "route description", - "operationId": "%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#2", + "operationId": "delete-foo-id-path", "parameters": Array [ Object { "description": "The version of the API to use", @@ -269,7 +269,7 @@ OK response oas-test-version-2", }, "get": Object { "description": "route description", - "operationId": "%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#0", + "operationId": "get-foo-id-path", "parameters": Array [ Object { "description": "The version of the API to use", @@ -415,7 +415,7 @@ OK response oas-test-version-2", }, "post": Object { "description": "route description", - "operationId": "%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#1", + "operationId": "post-foo-id-path", "parameters": Array [ Object { "description": "The version of the API to use", @@ -573,7 +573,7 @@ OK response oas-test-version-2", "/no-xsrf/{id}/{path*}": Object { "post": Object { "deprecated": true, - "operationId": "%2Fno-xsrf%2F%7Bid%7D%2F%7Bpath*%7D#1", + "operationId": "post-no-xsrf-id-path-2", "parameters": Array [ Object { "description": "The version of the API to use", @@ -725,7 +725,7 @@ Object { "paths": Object { "/recursive": Object { "get": Object { - "operationId": "%2Frecursive#0", + "operationId": "get-recursive", "parameters": Array [ Object { "description": "The version of the API to use", @@ -808,7 +808,7 @@ Object { "paths": Object { "/foo/{id}": Object { "get": Object { - "operationId": "%2Ffoo%2F%7Bid%7D#0", + "operationId": "get-foo-id", "parameters": Array [ Object { "description": "The version of the API to use", @@ -846,7 +846,7 @@ Object { }, "/test": Object { "get": Object { - "operationId": "%2Ftest#0", + "operationId": "get-test", "parameters": Array [ Object { "description": "The version of the API to use", diff --git a/packages/kbn-router-to-openapispec/src/extract_authz_description.test.ts b/packages/kbn-router-to-openapispec/src/extract_authz_description.test.ts new file mode 100644 index 0000000000000..8da2324e68f02 --- /dev/null +++ b/packages/kbn-router-to-openapispec/src/extract_authz_description.test.ts @@ -0,0 +1,81 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { schema } from '@kbn/config-schema'; +import { extractAuthzDescription } from './extract_authz_description'; +import { InternalRouterRoute } from './type'; +import { RouteSecurity } from '@kbn/core-http-server'; + +describe('extractAuthzDescription', () => { + it('should return empty if route does not require privileges', () => { + const route: InternalRouterRoute = { + path: '/foo', + options: { access: 'internal' }, + handler: jest.fn(), + validationSchemas: { request: { body: schema.object({}) } }, + method: 'get', + isVersioned: false, + }; + const description = extractAuthzDescription(route.security); + expect(description).toBe(''); + }); + + it('should return route authz description for simple privileges', () => { + const routeSecurity: RouteSecurity = { + authz: { + requiredPrivileges: ['manage_spaces'], + }, + }; + const description = extractAuthzDescription(routeSecurity); + expect(description).toBe('[Authz] Route required privileges: ALL of [manage_spaces].'); + }); + + it('should return route authz description for privilege groups', () => { + { + const routeSecurity: RouteSecurity = { + authz: { + requiredPrivileges: [{ allRequired: ['console'] }], + }, + }; + const description = extractAuthzDescription(routeSecurity); + expect(description).toBe('[Authz] Route required privileges: ALL of [console].'); + } + { + const routeSecurity: RouteSecurity = { + authz: { + requiredPrivileges: [ + { + anyRequired: ['manage_spaces', 'taskmanager'], + }, + ], + }, + }; + const description = extractAuthzDescription(routeSecurity); + expect(description).toBe( + '[Authz] Route required privileges: ANY of [manage_spaces OR taskmanager].' + ); + } + { + const routeSecurity: RouteSecurity = { + authz: { + requiredPrivileges: [ + { + allRequired: ['console', 'filesManagement'], + anyRequired: ['manage_spaces', 'taskmanager'], + }, + ], + }, + }; + const description = extractAuthzDescription(routeSecurity); + expect(description).toBe( + '[Authz] Route required privileges: ALL of [console, filesManagement] AND ANY of [manage_spaces OR taskmanager].' + ); + } + }); +}); diff --git a/packages/kbn-router-to-openapispec/src/extract_authz_description.ts b/packages/kbn-router-to-openapispec/src/extract_authz_description.ts new file mode 100644 index 0000000000000..4cd6875913780 --- /dev/null +++ b/packages/kbn-router-to-openapispec/src/extract_authz_description.ts @@ -0,0 +1,60 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { AuthzEnabled, AuthzDisabled, InternalRouteSecurity } from '@kbn/core-http-server'; + +interface PrivilegeGroupValue { + allRequired: string[]; + anyRequired: string[]; +} + +export const extractAuthzDescription = (routeSecurity: InternalRouteSecurity | undefined) => { + if (!routeSecurity) { + return ''; + } + if (!('authz' in routeSecurity) || (routeSecurity.authz as AuthzDisabled).enabled === false) { + return ''; + } + + const privileges = (routeSecurity.authz as AuthzEnabled).requiredPrivileges; + + const groupedPrivileges = privileges.reduce( + (groups, privilege) => { + if (typeof privilege === 'string') { + groups.allRequired.push(privilege); + + return groups; + } + groups.allRequired.push(...(privilege.allRequired ?? [])); + groups.anyRequired.push(...(privilege.anyRequired ?? [])); + + return groups; + }, + { + anyRequired: [], + allRequired: [], + } + ); + + const getPrivilegesDescription = (allRequired: string[], anyRequired: string[]) => { + const allDescription = allRequired.length ? `ALL of [${allRequired.join(', ')}]` : ''; + const anyDescription = anyRequired.length ? `ANY of [${anyRequired.join(' OR ')}]` : ''; + + return `${allDescription}${allDescription && anyDescription ? ' AND ' : ''}${anyDescription}`; + }; + + const getDescriptionForRoute = () => { + const allRequired = [...groupedPrivileges.allRequired]; + const anyRequired = [...groupedPrivileges.anyRequired]; + + return `Route required privileges: ${getPrivilegesDescription(allRequired, anyRequired)}.`; + }; + + return `[Authz] ${getDescriptionForRoute()}`; +}; diff --git a/packages/kbn-router-to-openapispec/src/generate_oas.test.fixture.ts b/packages/kbn-router-to-openapispec/src/generate_oas.test.fixture.ts index b3f20da38915b..f4ba66f992134 100644 --- a/packages/kbn-router-to-openapispec/src/generate_oas.test.fixture.ts +++ b/packages/kbn-router-to-openapispec/src/generate_oas.test.fixture.ts @@ -35,7 +35,7 @@ export const sharedOas = { get: { deprecated: true, 'x-discontinued': 'route discontinued version or date', - operationId: '%2Fbar#0', + operationId: 'get-bar', parameters: [ { description: 'The version of the API to use', @@ -154,7 +154,7 @@ export const sharedOas = { '/foo/{id}/{path*}': { get: { description: 'route description', - operationId: '%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#0', + operationId: 'get-foo-id-path', parameters: [ { description: 'The version of the API to use', @@ -278,7 +278,7 @@ export const sharedOas = { }, post: { description: 'route description', - operationId: '%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#1', + operationId: 'post-foo-id-path', parameters: [ { description: 'The version of the API to use', diff --git a/packages/kbn-router-to-openapispec/src/generate_oas.ts b/packages/kbn-router-to-openapispec/src/generate_oas.ts index 8bc3333193624..9c7423147721b 100644 --- a/packages/kbn-router-to-openapispec/src/generate_oas.ts +++ b/packages/kbn-router-to-openapispec/src/generate_oas.ts @@ -10,10 +10,9 @@ import type { CoreVersionedRouter, Router } from '@kbn/core-http-router-server-internal'; import type { OpenAPIV3 } from 'openapi-types'; import { OasConverter } from './oas_converter'; -import { createOperationIdCounter } from './operation_id_counter'; import { processRouter } from './process_router'; import { processVersionedRouter } from './process_versioned_router'; -import { buildGlobalTags } from './util'; +import { buildGlobalTags, createOpIdGenerator } from './util'; export const openApiVersion = '3.0.0'; @@ -40,8 +39,8 @@ export const generateOpenApiDocument = ( ): OpenAPIV3.Document => { const { filters } = opts; const converter = new OasConverter(); - const getOpId = createOperationIdCounter(); const paths: OpenAPIV3.PathsObject = {}; + const getOpId = createOpIdGenerator(); for (const router of appRouters.routers) { const result = processRouter(router, converter, getOpId, filters); Object.assign(paths, result.paths); diff --git a/packages/kbn-router-to-openapispec/src/operation_id_counter.test.ts b/packages/kbn-router-to-openapispec/src/operation_id_counter.test.ts deleted file mode 100644 index dbc4bf5956d69..0000000000000 --- a/packages/kbn-router-to-openapispec/src/operation_id_counter.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { createOperationIdCounter } from './operation_id_counter'; - -test('empty case', () => { - const opIdCounter = createOperationIdCounter(); - expect(opIdCounter('')).toBe('#0'); -}); - -test('other cases', () => { - const opIdCounter = createOperationIdCounter(); - const tests = [ - ['/', '%2F#0'], - ['/api/cool', '%2Fapi%2Fcool#0'], - ['/api/cool', '%2Fapi%2Fcool#1'], - ['/api/cool', '%2Fapi%2Fcool#2'], - ['/api/cool/{variable}', '%2Fapi%2Fcool%2F%7Bvariable%7D#0'], - ['/api/cool/{optionalVariable?}', '%2Fapi%2Fcool%2F%7BoptionalVariable%3F%7D#0'], - ['/api/cool/{optionalVariable?}', '%2Fapi%2Fcool%2F%7BoptionalVariable%3F%7D#1'], - ]; - - tests.forEach(([input, expected]) => { - expect(opIdCounter(input)).toBe(expected); - }); -}); diff --git a/packages/kbn-router-to-openapispec/src/operation_id_counter.ts b/packages/kbn-router-to-openapispec/src/operation_id_counter.ts deleted file mode 100644 index 2d576b1ca67c3..0000000000000 --- a/packages/kbn-router-to-openapispec/src/operation_id_counter.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export type OperationIdCounter = (name: string) => string; - -export const createOperationIdCounter = () => { - const operationIdCounters = new Map(); - return (name: string): string => { - name = encodeURIComponent(name); - // Aliases an operationId to ensure it is unique across - // multiple method+path combinations sharing a name. - // "search" -> "search#0", "search#1", etc. - const operationIdCount = operationIdCounters.get(name) ?? 0; - const aliasedName = name + '#' + operationIdCount.toString(); - operationIdCounters.set(name, operationIdCount + 1); - return aliasedName; - }; -}; diff --git a/packages/kbn-router-to-openapispec/src/process_router.test.ts b/packages/kbn-router-to-openapispec/src/process_router.test.ts index 22e03efdf08fc..17191e7ab1b1c 100644 --- a/packages/kbn-router-to-openapispec/src/process_router.test.ts +++ b/packages/kbn-router-to-openapispec/src/process_router.test.ts @@ -10,8 +10,9 @@ import { schema } from '@kbn/config-schema'; import { Router } from '@kbn/core-http-router-server-internal'; import { OasConverter } from './oas_converter'; -import { createOperationIdCounter } from './operation_id_counter'; -import { extractResponses, processRouter, type InternalRouterRoute } from './process_router'; +import { extractResponses, processRouter } from './process_router'; +import { type InternalRouterRoute } from './type'; +import { createOpIdGenerator } from './util'; describe('extractResponses', () => { let oasConverter: OasConverter; @@ -85,36 +86,69 @@ describe('processRouter', () => { const testRouter = { getRoutes: () => [ { + method: 'get', path: '/foo', options: { access: 'internal', deprecated: true, discontinued: 'discontinued router' }, handler: jest.fn(), validationSchemas: { request: { body: schema.object({}) } }, }, { + method: 'get', path: '/bar', options: {}, handler: jest.fn(), validationSchemas: { request: { body: schema.object({}) } }, }, { + method: 'get', path: '/baz', options: {}, handler: jest.fn(), validationSchemas: { request: { body: schema.object({}) } }, }, + { + path: '/qux', + method: 'post', + options: {}, + handler: jest.fn(), + validationSchemas: { request: { body: schema.object({}) } }, + security: { + authz: { + requiredPrivileges: [ + 'manage_spaces', + { + allRequired: ['taskmanager'], + anyRequired: ['console'], + }, + ], + }, + }, + }, ], } as unknown as Router; it('only provides routes for version 2023-10-31', () => { - const result1 = processRouter(testRouter, new OasConverter(), createOperationIdCounter(), { + const result1 = processRouter(testRouter, new OasConverter(), createOpIdGenerator(), { version: '2023-10-31', }); - expect(Object.keys(result1.paths!)).toHaveLength(3); + expect(Object.keys(result1.paths!)).toHaveLength(4); - const result2 = processRouter(testRouter, new OasConverter(), createOperationIdCounter(), { + const result2 = processRouter(testRouter, new OasConverter(), createOpIdGenerator(), { version: '2024-10-31', }); expect(Object.keys(result2.paths!)).toHaveLength(0); }); + + it('updates description with privileges required', () => { + const result = processRouter(testRouter, new OasConverter(), createOpIdGenerator(), { + version: '2023-10-31', + }); + + expect(result.paths['/qux']?.post).toBeDefined(); + + expect(result.paths['/qux']?.post?.description).toEqual( + '[Authz] Route required privileges: ALL of [manage_spaces, taskmanager] AND ANY of [console].' + ); + }); }); diff --git a/packages/kbn-router-to-openapispec/src/process_router.ts b/packages/kbn-router-to-openapispec/src/process_router.ts index f0d37fd208b7b..e11c4057a05b8 100644 --- a/packages/kbn-router-to-openapispec/src/process_router.ts +++ b/packages/kbn-router-to-openapispec/src/process_router.ts @@ -24,15 +24,16 @@ import { mergeResponseContent, prepareRoutes, setXState, + GetOpId, } from './util'; -import type { OperationIdCounter } from './operation_id_counter'; import type { GenerateOpenApiDocumentOptionsFilters } from './generate_oas'; -import type { CustomOperationObject } from './type'; +import type { CustomOperationObject, InternalRouterRoute } from './type'; +import { extractAuthzDescription } from './extract_authz_description'; export const processRouter = ( appRouter: Router, converter: OasConverter, - getOpId: OperationIdCounter, + getOpId: GetOpId, filters?: GenerateOpenApiDocumentOptionsFilters ) => { const paths: OpenAPIV3.PathsObject = {}; @@ -63,10 +64,19 @@ export const processRouter = ( parameters.push(...pathObjects, ...queryObjects); } + let description = ''; + if (route.security) { + const authzDescription = extractAuthzDescription(route.security); + + description = `${route.options.description ?? ''}${authzDescription ?? ''}`; + } + const hasDeprecations = !!route.options.deprecated; + const operation: CustomOperationObject = { summary: route.options.summary ?? '', tags: route.options.tags ? extractTags(route.options.tags) : [], + ...(description ? { description } : {}), ...(route.options.description ? { description: route.options.description } : {}), ...(hasDeprecations ? { deprecated: true } : {}), ...(route.options.discontinued ? { 'x-discontinued': route.options.discontinued } : {}), @@ -81,7 +91,7 @@ export const processRouter = ( : undefined, responses: extractResponses(route, converter), parameters, - operationId: getOpId(route.path), + operationId: getOpId({ path: route.path, method: route.method }), }; setXState(route.options.availability, operation); @@ -99,7 +109,6 @@ export const processRouter = ( return { paths }; }; -export type InternalRouterRoute = ReturnType[0]; export const extractResponses = (route: InternalRouterRoute, converter: OasConverter) => { const responses: OpenAPIV3.ResponsesObject = {}; if (!route.validationSchemas) return responses; diff --git a/packages/kbn-router-to-openapispec/src/process_versioned_router.test.ts b/packages/kbn-router-to-openapispec/src/process_versioned_router.test.ts index f9f4f4898c1d0..839ba5f298134 100644 --- a/packages/kbn-router-to-openapispec/src/process_versioned_router.test.ts +++ b/packages/kbn-router-to-openapispec/src/process_versioned_router.test.ts @@ -11,13 +11,13 @@ import { schema } from '@kbn/config-schema'; import type { CoreVersionedRouter } from '@kbn/core-http-router-server-internal'; import { get } from 'lodash'; import { OasConverter } from './oas_converter'; -import { createOperationIdCounter } from './operation_id_counter'; import { processVersionedRouter, extractVersionedResponses, extractVersionedRequestBodies, } from './process_versioned_router'; import { VersionedRouterRoute } from '@kbn/core-http-server'; +import { createOpIdGenerator } from './util'; let oasConverter: OasConverter; beforeEach(() => { @@ -125,7 +125,7 @@ describe('processVersionedRouter', () => { const baseCase = processVersionedRouter( { getRoutes: () => [createTestRoute()] } as unknown as CoreVersionedRouter, new OasConverter(), - createOperationIdCounter(), + createOpIdGenerator(), {} ); @@ -137,13 +137,29 @@ describe('processVersionedRouter', () => { const filteredCase = processVersionedRouter( { getRoutes: () => [createTestRoute()] } as unknown as CoreVersionedRouter, new OasConverter(), - createOperationIdCounter(), + createOpIdGenerator(), { version: '2023-10-31' } ); expect(Object.keys(get(filteredCase, 'paths["/foo"].get.responses.200.content')!)).toEqual([ 'application/test+json; Elastic-Api-Version=2023-10-31', ]); }); + + it('correctly updates the authz description for routes that require privileges', () => { + const results = processVersionedRouter( + { getRoutes: () => [createTestRoute()] } as unknown as CoreVersionedRouter, + new OasConverter(), + createOpIdGenerator(), + {} + ); + expect(results.paths['/foo']).toBeDefined(); + + expect(results.paths['/foo']!.get).toBeDefined(); + + expect(results.paths['/foo']!.get!.description).toBe( + '[Authz] Route required privileges: ALL of [manage_spaces].' + ); + }); }); const createTestRoute: () => VersionedRouterRoute = () => ({ @@ -155,6 +171,11 @@ const createTestRoute: () => VersionedRouterRoute = () => ({ deprecated: true, discontinued: 'discontinued versioned router', options: { body: { access: ['application/test+json'] } as any }, + security: { + authz: { + requiredPrivileges: ['manage_spaces'], + }, + }, }, handlers: [ { diff --git a/packages/kbn-router-to-openapispec/src/process_versioned_router.ts b/packages/kbn-router-to-openapispec/src/process_versioned_router.ts index 7eee0d20c11d2..380bbd2e86c26 100644 --- a/packages/kbn-router-to-openapispec/src/process_versioned_router.ts +++ b/packages/kbn-router-to-openapispec/src/process_versioned_router.ts @@ -14,10 +14,10 @@ import { } from '@kbn/core-http-router-server-internal'; import type { RouteMethod, VersionedRouterRoute } from '@kbn/core-http-server'; import type { OpenAPIV3 } from 'openapi-types'; +import { extractAuthzDescription } from './extract_authz_description'; import type { GenerateOpenApiDocumentOptionsFilters } from './generate_oas'; import type { OasConverter } from './oas_converter'; import { isReferenceObject } from './oas_converter/common'; -import type { OperationIdCounter } from './operation_id_counter'; import { prepareRoutes, getPathParameters, @@ -29,12 +29,13 @@ import { mergeResponseContent, getXsrfHeaderForMethod, setXState, + GetOpId, } from './util'; export const processVersionedRouter = ( appRouter: CoreVersionedRouter, converter: OasConverter, - getOpId: OperationIdCounter, + getOpId: GetOpId, filters?: GenerateOpenApiDocumentOptionsFilters ) => { const routes = prepareRoutes(appRouter.getRoutes(), filters); @@ -90,6 +91,13 @@ export const processVersionedRouter = ( ]; } + let description = ''; + if (route.options.security) { + const authzDescription = extractAuthzDescription(route.options.security); + + description = `${route.options.description ?? ''}${authzDescription ?? ''}`; + } + const hasBody = Boolean(extractValidationSchemaFromVersionedHandler(handler)?.request?.body); const contentType = extractContentType(route.options.options?.body); const hasVersionFilter = Boolean(filters?.version); @@ -98,6 +106,7 @@ export const processVersionedRouter = ( const operation: OpenAPIV3.OperationObject = { summary: route.options.summary ?? '', tags: route.options.options?.tags ? extractTags(route.options.options.tags) : [], + ...(description ? { description } : {}), ...(route.options.description ? { description: route.options.description } : {}), ...(hasDeprecations ? { deprecated: true } : {}), ...(route.options.discontinued ? { 'x-discontinued': route.options.discontinued } : {}), @@ -112,7 +121,7 @@ export const processVersionedRouter = ( ? extractVersionedResponse(handler, converter, contentType) : extractVersionedResponses(route, converter, contentType), parameters, - operationId: getOpId(route.path), + operationId: getOpId({ path: route.path, method: route.method }), }; setXState(route.options.options?.availability, operation); diff --git a/packages/kbn-router-to-openapispec/src/type.ts b/packages/kbn-router-to-openapispec/src/type.ts index 5c5f992a0de0f..f57e4d00ad7db 100644 --- a/packages/kbn-router-to-openapispec/src/type.ts +++ b/packages/kbn-router-to-openapispec/src/type.ts @@ -7,6 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import type { Router } from '@kbn/core-http-router-server-internal'; import type { OpenAPIV3 } from '../openapi-types'; export type { OpenAPIV3 } from '../openapi-types'; export interface KnownParameters { @@ -39,3 +40,5 @@ export type CustomOperationObject = OpenAPIV3.OperationObject<{ // Custom OpenAPI from ES API spec based on @availability 'x-state'?: 'Technical Preview' | 'Beta'; }>; + +export type InternalRouterRoute = ReturnType[0]; diff --git a/packages/kbn-router-to-openapispec/src/util.test.ts b/packages/kbn-router-to-openapispec/src/util.test.ts index abbb605df79e5..f9692e57e1f50 100644 --- a/packages/kbn-router-to-openapispec/src/util.test.ts +++ b/packages/kbn-router-to-openapispec/src/util.test.ts @@ -15,6 +15,8 @@ import { mergeResponseContent, prepareRoutes, getPathParameters, + createOpIdGenerator, + GetOpId, } from './util'; import { assignToPaths, extractTags } from './util'; @@ -260,3 +262,83 @@ describe('getPathParameters', () => { expect(getPathParameters(input)).toEqual(output); }); }); + +describe('createOpIdGenerator', () => { + let getOpId: GetOpId; + beforeEach(() => { + getOpId = createOpIdGenerator(); + }); + test('empty', () => { + expect(() => getOpId({ method: '', path: '/asd' })).toThrow(/Must provide method and path/); + expect(() => getOpId({ method: 'get', path: '' })).toThrow(/Must provide method and path/); + expect(() => getOpId({ method: '', path: '' })).toThrow(/Must provide method and path/); + }); + test('disambiguate', () => { + expect(getOpId({ method: 'get', path: '/test' })).toBe('get-test'); + expect(getOpId({ method: 'get', path: '/test' })).toBe('get-test-2'); + expect(getOpId({ method: 'get', path: '/test' })).toBe('get-test-3'); + expect(getOpId({ method: 'get', path: '/test' })).toBe('get-test-4'); + }); + test.each([ + { input: { method: 'GET', path: '/api/file' }, output: 'get-file' }, + { input: { method: 'GET', path: '///api/file///' }, output: 'get-file' }, + { input: { method: 'POST', path: '/internal/api/file' }, output: 'post-file' }, + { input: { method: 'PUT', path: '/internal/file' }, output: 'put-file' }, + { input: { method: 'Put', path: 'fOO/fILe' }, output: 'put-foo-file' }, + { + input: { method: 'delete', path: '/api/my/really/cool/domain/resource' }, + output: 'delete-my-really-cool-domain-resource', + }, + { + input: { + method: 'delete', + path: '/api/my/really/cool/domain/resource', + }, + output: 'delete-my-really-cool-domain-resource', + }, + { + input: { + method: 'get', + path: '/api/my/resource/{id}', + }, + output: 'get-my-resource-id', + }, + { + input: { + method: 'get', + path: '/api/my/resource/{id}/{type?}', + }, + output: 'get-my-resource-id-type', + }, + { + input: { + method: 'get', + path: '/api/my/resource/{id?}', + }, + output: 'get-my-resource-id', + }, + { + input: { + method: 'get', + path: '/api/my/resource/{path*}', + }, + output: 'get-my-resource-path', + }, + { + input: { + method: 'get', + path: '/api/my/underscore_resource', + }, + output: 'get-my-underscore-resource', + }, + { + input: { + method: 'get', + path: '/api/my/_underscore_resource', + }, + output: 'get-my-underscore-resource', + }, + ])('$input.method $input.path -> $output', ({ input, output }) => { + expect(getOpId(input)).toBe(output); + }); +}); diff --git a/packages/kbn-router-to-openapispec/src/util.ts b/packages/kbn-router-to-openapispec/src/util.ts index beefbebc0aec7..a5718fa92120f 100644 --- a/packages/kbn-router-to-openapispec/src/util.ts +++ b/packages/kbn-router-to-openapispec/src/util.ts @@ -166,10 +166,10 @@ export const getXsrfHeaderForMethod = ( ]; }; -export function setXState( +export const setXState = ( availability: RouteConfigOptions['availability'], operation: CustomOperationObject -): void { +): void => { if (availability) { if (availability.stability === 'experimental') { operation['x-state'] = 'Technical Preview'; @@ -178,4 +178,45 @@ export function setXState( operation['x-state'] = 'Beta'; } } -} +}; + +export type GetOpId = (input: { path: string; method: string }) => string; + +/** + * Best effort to generate operation IDs from route values + */ +export const createOpIdGenerator = (): GetOpId => { + const idMap = new Map(); + return function getOpId({ path, method }) { + if (!method || !path) { + throw new Error( + `Must provide method and path, received: method: "${method}", path: "${path}"` + ); + } + + path = path + .trim() + .replace(/^[\/]+/, '') + .replace(/[\/]+$/, '') + .toLowerCase(); + + const removePrefixes = ['internal/api/', 'internal/', 'api/']; // longest to shortest + for (const prefix of removePrefixes) { + if (path.startsWith(prefix)) { + path = path.substring(prefix.length); + break; + } + } + + path = path + .replace(/[\{\}\?\*]/g, '') // remove special chars + .replace(/[\/_]/g, '-') // everything else to dashes + .replace(/[-]+/g, '-'); // single dashes + + const opId = `${method.toLowerCase()}-${path}`; + + const cachedCount = idMap.get(opId) ?? 0; + idMap.set(opId, cachedCount + 1); + return cachedCount > 0 ? `${opId}-${cachedCount + 1}` : opId; + }; +}; diff --git a/packages/kbn-router-to-openapispec/tsconfig.json b/packages/kbn-router-to-openapispec/tsconfig.json index d82ca0bf48910..3536a90a8256f 100644 --- a/packages/kbn-router-to-openapispec/tsconfig.json +++ b/packages/kbn-router-to-openapispec/tsconfig.json @@ -17,6 +17,6 @@ "@kbn/core-http-router-server-internal", "@kbn/core-http-server", "@kbn/config-schema", - "@kbn/zod" + "@kbn/zod", ] } diff --git a/packages/kbn-rrule/rrule.ts b/packages/kbn-rrule/rrule.ts index 9b5eea7d4979f..43e89ee209cb7 100644 --- a/packages/kbn-rrule/rrule.ts +++ b/packages/kbn-rrule/rrule.ts @@ -16,6 +16,7 @@ export enum Frequency { DAILY = 3, HOURLY = 4, MINUTELY = 5, + SECONDLY = 6, } export enum Weekday { @@ -270,6 +271,13 @@ export const getNextRecurrences = function ({ ...opts, }); } + case Frequency.SECONDLY: { + const nextRef = moment(refDT).add(interval, 's'); + return getMinuteOfRecurrences({ + refDT: nextRef, + ...opts, + }); + } } }; diff --git a/packages/kbn-search-connectors/components/configuration/connector_configuration_field.tsx b/packages/kbn-search-connectors/components/configuration/connector_configuration_field.tsx index a43163caa6091..08b91ffc1842c 100644 --- a/packages/kbn-search-connectors/components/configuration/connector_configuration_field.tsx +++ b/packages/kbn-search-connectors/components/configuration/connector_configuration_field.tsx @@ -52,7 +52,7 @@ export const ConfigInputField: React.FC = ({ isLoading, validateAndSetConfigValue, }) => { - const { isValid, required, placeholder, value } = configEntry; + const { isValid, required, placeholder, value, label } = configEntry; const [innerValue, setInnerValue] = useState(value); return ( = ({ validateAndSetConfigValue(event.target.value); }} placeholder={placeholder} + aria-label={label} /> ); }; @@ -74,7 +75,7 @@ export const ConfigInputTextArea: React.FC = ({ configEntry, validateAndSetConfigValue, }) => { - const { isValid, required, placeholder, value } = configEntry; + const { isValid, required, placeholder, value, label } = configEntry; const [innerValue, setInnerValue] = useState(value); return ( = ({ validateAndSetConfigValue(event.target.value); }} placeholder={placeholder} + aria-label={label} /> ); }; @@ -129,7 +131,7 @@ export const ConfigInputPassword: React.FC = ({ configEntry, validateAndSetConfigValue, }) => { - const { required, value } = configEntry; + const { required, value, label } = configEntry; const [innerValue, setInnerValue] = useState(value); return ( = ({ setInnerValue(event.target.value); validateAndSetConfigValue(event.target.value); }} + aria-label={label} /> ); }; @@ -170,6 +173,7 @@ export const ConnectorConfigurationField: React.FC { validateAndSetConfigValue(event.target.value); }} + aria-label={label} /> ) : ( { validateAndSetConfigValue(id); }} + aria-label={label} /> ); @@ -227,6 +232,7 @@ export const ConnectorConfigurationField: React.FC { validateAndSetConfigValue(event.target.checked); }} + aria-label={label} /> {!hasPlatinumLicense && ( diff --git a/packages/kbn-search-response-warnings/src/extract_warnings.test.ts b/packages/kbn-search-response-warnings/src/extract_warnings.test.ts index cedf0546ae3a4..c5a1352c3d0f9 100644 --- a/packages/kbn-search-response-warnings/src/extract_warnings.test.ts +++ b/packages/kbn-search-response-warnings/src/extract_warnings.test.ts @@ -9,6 +9,7 @@ import { estypes } from '@elastic/elasticsearch'; import type { Start as InspectorStartContract } from '@kbn/inspector-plugin/public'; +import type { ESQLSearchResponse } from '@kbn/es-types'; import type { RequestAdapter } from '@kbn/inspector-plugin/common/adapters/request'; import { extractWarnings } from './extract_warnings'; @@ -108,6 +109,22 @@ describe('extract search response warnings', () => { expect(warnings).toEqual([]); }); + + it('should not include warnings when there is no _clusters or _shards information', () => { + const warnings = extractWarnings( + { + took: 46, + all_columns: [{ name: 'field1', type: 'string' }], + columns: [{ name: 'field1', type: 'string' }], + values: [['value1']], + } as ESQLSearchResponse, + mockInspectorService, + mockRequestAdapter, + 'My request' + ); + + expect(warnings).toEqual([]); + }); }); describe('remote clusters', () => { diff --git a/packages/kbn-search-response-warnings/src/extract_warnings.ts b/packages/kbn-search-response-warnings/src/extract_warnings.ts index 7d53a954f7715..58e963c239b12 100644 --- a/packages/kbn-search-response-warnings/src/extract_warnings.ts +++ b/packages/kbn-search-response-warnings/src/extract_warnings.ts @@ -8,6 +8,7 @@ */ import { estypes } from '@elastic/elasticsearch'; +import type { ESQLSearchResponse } from '@kbn/es-types'; import type { Start as InspectorStartContract, RequestAdapter } from '@kbn/inspector-plugin/public'; import type { SearchResponseWarning } from './types'; @@ -15,7 +16,7 @@ import type { SearchResponseWarning } from './types'; * @internal */ export function extractWarnings( - rawResponse: estypes.SearchResponse, + rawResponse: estypes.SearchResponse | ESQLSearchResponse, inspectorService: InspectorStartContract, requestAdapter: RequestAdapter, requestName: string, @@ -23,11 +24,13 @@ export function extractWarnings( ): SearchResponseWarning[] { const warnings: SearchResponseWarning[] = []; + // ES|QL supports _clusters in case of CCS but doesnt support _shards and timed_out (yet) const isPartial = rawResponse._clusters ? rawResponse._clusters.partial > 0 || rawResponse._clusters.skipped > 0 || rawResponse._clusters.running > 0 - : rawResponse.timed_out || rawResponse._shards.failed > 0; + : ('timed_out' in rawResponse && rawResponse.timed_out) || + ('_shards' in rawResponse && rawResponse._shards.failed > 0); if (isPartial) { warnings.push({ type: 'incomplete', @@ -39,9 +42,10 @@ export function extractWarnings( status: 'partial', indices: '', took: rawResponse.took, - timed_out: rawResponse.timed_out, - _shards: rawResponse._shards, - failures: rawResponse._shards.failures, + timed_out: 'timed_out' in rawResponse && rawResponse.timed_out, + ...('_shards' in rawResponse + ? { _shards: rawResponse._shards, failures: rawResponse._shards.failures } + : {}), }, }, openInInspector: () => { diff --git a/packages/kbn-search-response-warnings/tsconfig.json b/packages/kbn-search-response-warnings/tsconfig.json index 6823ef5abf8a1..1f87892403a61 100644 --- a/packages/kbn-search-response-warnings/tsconfig.json +++ b/packages/kbn-search-response-warnings/tsconfig.json @@ -10,6 +10,7 @@ "@kbn/core", "@kbn/react-kibana-mount", "@kbn/core-i18n-browser", + "@kbn/es-types", ], "exclude": ["target/**/*"] } diff --git a/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts b/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts index 724cf5bc2b25e..964359cdb7ee5 100644 --- a/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts +++ b/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts @@ -11,6 +11,7 @@ import Url from 'url'; import { resolve } from 'path'; import type { ToolingLog } from '@kbn/tooling-log'; import getPort from 'get-port'; +import getopts from 'getopts'; import { REPO_ROOT } from '@kbn/repo-info'; import type { ArtifactLicense, ServerlessProjectType } from '@kbn/es'; import { isServerlessProjectType, extractAndArchiveLogs } from '@kbn/es/src/utils'; @@ -196,12 +197,8 @@ function getESServerlessOptions( (config.get('kbnTestServer.serverArgs') as string[])) || []; - const projectType = kbnServerArgs - .filter((arg) => arg.startsWith('--serverless')) - .reduce((acc, arg) => { - const match = arg.match(/--serverless[=\s](\w+)/); - return acc + (match ? match[1] : ''); - }, '') as ServerlessProjectType; + const options = getopts(kbnServerArgs); + const projectType = options.serverless as ServerlessProjectType; if (!isServerlessProjectType(projectType)) { throw new Error(`Unsupported serverless projectType: ${projectType}`); diff --git a/packages/kbn-test/src/jest/resolver.js b/packages/kbn-test/src/jest/resolver.js index 8f985e9463962..aab1b0f597284 100644 --- a/packages/kbn-test/src/jest/resolver.js +++ b/packages/kbn-test/src/jest/resolver.js @@ -51,6 +51,13 @@ module.exports = (request, options) => { }); } + if (request === '@launchdarkly/js-sdk-common') { + return resolve.sync('@launchdarkly/js-sdk-common/dist/cjs/index.cjs', { + basedir: options.basedir, + extensions: options.extensions, + }); + } + if (request === `elastic-apm-node`) { return APM_AGENT_MOCK; } diff --git a/packages/kbn-test/src/mocha/junit_report_generation.test.js b/packages/kbn-test/src/mocha/junit_report_generation.test.js index caf023a795154..6dbc8bf6cf1f8 100644 --- a/packages/kbn-test/src/mocha/junit_report_generation.test.js +++ b/packages/kbn-test/src/mocha/junit_report_generation.test.js @@ -55,9 +55,12 @@ describe('dev/mocha/junit report generation', () => { const [testsuite] = report.testsuites.testsuite; expect(testsuite.$.time).toMatch(DURATION_REGEX); expect(testsuite.$.timestamp).toMatch(ISO_DATE_SEC_REGEX); - expect(testsuite.$).toEqual({ - 'command-line': - 'node scripts/jest --config=packages/kbn-test/jest.config.js --runInBand --coverage=false --passWithNoTests', + const expectedCommandLine = process.env.CI + ? 'node scripts/jest --config=packages/kbn-test/jest.config.js --runInBand --coverage=false --passWithNoTests' + : 'node node_modules/jest-worker/build/workers/processChild.js'; + + expect(testsuite.$).toMatchObject({ + 'command-line': expectedCommandLine, failures: '2', name: 'test', skipped: '1', diff --git a/packages/serverless/settings/observability_project/index.ts b/packages/serverless/settings/observability_project/index.ts index 44f30e4320463..d04b0238c5510 100644 --- a/packages/serverless/settings/observability_project/index.ts +++ b/packages/serverless/settings/observability_project/index.ts @@ -27,8 +27,6 @@ export const OBSERVABILITY_PROJECT_SETTINGS = [ settings.OBSERVABILITY_APM_TRACE_EXPLORER_TAB_ID, settings.OBSERVABILITY_ENABLE_AWS_LAMBDA_METRICS_ID, settings.OBSERVABILITY_APM_ENABLE_CRITICAL_PATH_ID, - settings.OBSERVABILITY_ENABLE_INFRASTRUCTURE_HOSTS_VIEW_ID, - settings.OBSERVABILITY_ENABLE_INFRASTRUCTURE_CONTAINER_ASSET_VIEW_ID, settings.OBSERVABILITY_ENABLE_INFRASTRUCTURE_ASSET_CUSTOM_DASHBOARDS_ID, settings.OBSERVABILITY_LOGS_EXPLORER_ALLOWED_DATA_VIEWS_ID, settings.OBSERVABILITY_APM_ENABLE_TABLE_SEARCH_BAR, diff --git a/packages/shared-ux/button/exit_full_screen/src/services.tsx b/packages/shared-ux/button/exit_full_screen/src/services.tsx index a167b2b116bf0..9497a6ed34468 100644 --- a/packages/shared-ux/button/exit_full_screen/src/services.tsx +++ b/packages/shared-ux/button/exit_full_screen/src/services.tsx @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React, { FC, useContext, PropsWithChildren } from 'react'; +import React, { FC, useContext, PropsWithChildren, useCallback } from 'react'; import type { Services, @@ -37,12 +37,16 @@ export const ExitFullScreenButtonProvider: FC > = ({ children, ...services }) => { + const setIsFullscreen = useCallback( + (isFullscreen: boolean) => { + services.coreStart.chrome.setIsVisible(!isFullscreen); + }, + [services.coreStart.chrome] + ); return ( { - services.coreStart.chrome.setIsVisible(!isFullscreen); - }, + setIsFullscreen, customBranding$: services.coreStart.customBranding.customBranding$, }} > diff --git a/packages/shared-ux/chrome/navigation/__jest__/active_node.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/active_node.test.tsx index af162996f5f85..9ed3604dcdb8a 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/active_node.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/active_node.test.tsx @@ -76,7 +76,7 @@ describe('Active node', () => { ]; const { findByTestId } = renderNavigation({ - navTreeDef: of({ body: navigationBody }), + navTreeDef: of({ id: 'es', body: navigationBody }), services: { activeNodes$: getActiveNodes$() }, }); diff --git a/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx index 15baf09d04dc3..4196dd3eca21c 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx @@ -21,6 +21,7 @@ describe('builds navigation tree', () => { test('render reference UI and build the navigation tree', async () => { const { findByTestId } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [ { id: 'group1', @@ -107,6 +108,7 @@ describe('builds navigation tree', () => { { const { findByTestId, unmount } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [accordionNode], }), services: { navigateToUrl }, @@ -121,6 +123,7 @@ describe('builds navigation tree', () => { { const { findByTestId } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [ { ...accordionNode, @@ -165,6 +168,7 @@ describe('builds navigation tree', () => { // Side nav is collapsed const { queryAllByTestId, unmount } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [nodes], }), services: { isSideNavCollapsed: true }, @@ -180,6 +184,7 @@ describe('builds navigation tree', () => { // Side nav is not collapsed const { queryAllByTestId, unmount } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [nodes], }), services: { isSideNavCollapsed: false }, // No conversion to accordion @@ -195,6 +200,7 @@ describe('builds navigation tree', () => { // Panel opener with a link const { queryAllByTestId, unmount } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [ { ...nodes, @@ -238,6 +244,7 @@ describe('builds navigation tree', () => { const { findByTestId } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [node], }), services: { navigateToUrl, eventTracker: new EventTracker({ reportEvent }) }, @@ -276,6 +283,7 @@ describe('builds navigation tree', () => { const { findByTestId } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [node], }), services: { navigateToUrl }, @@ -290,6 +298,7 @@ describe('builds navigation tree', () => { test('should not render the group if it does not have children', async () => { const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -338,6 +347,7 @@ describe('builds navigation tree', () => { ]); const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [{ type: 'recentlyAccessed' }], }; @@ -364,6 +374,7 @@ describe('builds navigation tree', () => { ]); const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [{ type: 'recentlyAccessed' }], }; diff --git a/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx index 01a1112ca7d1a..59c3463fb7326 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx @@ -21,6 +21,7 @@ import { renderNavigation } from './utils'; describe('Panel', () => { test('should render group as panel opener', async () => { const navigationTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -60,6 +61,7 @@ describe('Panel', () => { test('should not render group if all children are hidden', async () => { const navigationTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -146,6 +148,7 @@ describe('Panel', () => { ]); const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -196,6 +199,7 @@ describe('Panel', () => { describe('auto generated content', () => { test('should rendre block groups with title', async () => { const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -262,6 +266,7 @@ describe('Panel', () => { test('should rendre block groups without title', async () => { const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -327,6 +332,7 @@ describe('Panel', () => { test('should rendre accordion groups', async () => { const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/feedback_btn.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/feedback_btn.tsx index 3cc2fca2d8f81..182838d88b5d6 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/feedback_btn.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/feedback_btn.tsx @@ -10,11 +10,20 @@ import { EuiButton, EuiCallOut, useEuiTheme, EuiText, EuiSpacer } from '@elastic/eui'; import React, { FC, useState } from 'react'; import { i18n } from '@kbn/i18n'; +import type { SolutionId } from '@kbn/core-chrome-browser'; -const feedbackUrl = 'https://ela.st/nav-feedback'; +const feedbackUrls: { [id in SolutionId]: string } = { + es: 'https://ela.st/search-nav-feedback', + oblt: 'https://ela.st/o11y-nav-feedback', + security: 'https://ela.st/security-nav-feedback', +}; const FEEDBACK_BTN_KEY = 'core.chrome.sideNav.feedbackBtn'; -export const FeedbackBtn: FC = () => { +interface Props { + solutionId: SolutionId; +} + +export const FeedbackBtn: FC = ({ solutionId }) => { const { euiTheme } = useEuiTheme(); const [showCallOut, setShowCallOut] = useState( sessionStorage.getItem(FEEDBACK_BTN_KEY) !== 'hidden' @@ -26,7 +35,7 @@ export const FeedbackBtn: FC = () => { }; const onClick = () => { - window.open(feedbackUrl, '_blank'); + window.open(feedbackUrls[solutionId], '_blank'); onDismiss(); }; diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx index 6100dceaa2499..c90ec6a72152f 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx @@ -91,6 +91,7 @@ const NavigationWrapper: FC, 'c }; const groupExamplesNavigationTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ // My custom project { @@ -257,6 +258,7 @@ export const GroupsExamples = (args: NavigationServices) => { }; const navigationTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ // My custom project { @@ -568,6 +570,7 @@ const panelContentProvider: ContentProvider = (id: string) => { }; const navigationTreeWithPanels: NavigationTreeDefinitionUI = { + id: 'es', body: [ // My custom project { diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx index 688ee1e709e15..80365bd16133f 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx @@ -52,7 +52,8 @@ const NavigationComp: FC = ({ navigationTree$, dataTestSubj, panelContent useNavigationService(); const activeNodes = useObservable(activeNodes$, []); - const navigationTree = useObservable(navigationTree$, { body: [] }); + const navigationTree = useObservable(navigationTree$, { id: 'es', body: [] }); + const { id: solutionId } = navigationTree; const isFeedbackBtnVisible = useObservable(isFeedbackBtnVisible$, false); const contextValue = useMemo( @@ -95,7 +96,7 @@ const NavigationComp: FC = ({ navigationTree$, dataTestSubj, panelContent {renderNodes(navigationTree.body)} {isFeedbackBtnVisible && ( - + )} diff --git a/scripts/codeql/codeql.dockerfile b/scripts/codeql/codeql.dockerfile new file mode 100644 index 0000000000000..fce6b9c3fdd63 --- /dev/null +++ b/scripts/codeql/codeql.dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:latest + +ENV DEBIAN_FRONTEND=noninteractive + +ARG USERNAME=codeql +ARG CODEQL_VERSION="v2.19.0" +ENV CODEQL_HOME /usr/local/codeql-home + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + passwd \ + adduser \ + bash \ + curl \ + git \ + unzip \ + nodejs \ + jq + +RUN adduser --home ${CODEQL_HOME} ${USERNAME} + +RUN curl -Lk "https://github.com/github/codeql-action/releases/download/codeql-bundle-${CODEQL_VERSION}/codeql-bundle-linux64.tar.gz" -o codeql.tar.gz \ + && mkdir -p ${CODEQL_HOME} \ + && tar -xvzf codeql.tar.gz -C ${CODEQL_HOME} \ + && rm codeql.tar.gz + +RUN chmod +x ${CODEQL_HOME}/codeql/codeql + +RUN chown -R ${USERNAME}:${USERNAME} ${CODEQL_HOME} + +USER ${USERNAME} + +ENV PATH="${CODEQL_HOME}/codeql:${PATH}" + +RUN echo $PATH && codeql --version + +WORKDIR /workspace + +ENTRYPOINT ["/bin/bash", "-c"] diff --git a/scripts/codeql/quick_check.sh b/scripts/codeql/quick_check.sh new file mode 100644 index 0000000000000..15023bfb13bfa --- /dev/null +++ b/scripts/codeql/quick_check.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +LANGUAGE="javascript" +CODEQL_DIR=".codeql" +DATABASE_PATH="$CODEQL_DIR/database" +QUERY_OUTPUT="$DATABASE_PATH/results.sarif" +OUTPUT_FORMAT="sarif-latest" +DOCKER_IMAGE="codeql-env" +BASE_DIR="$(cd "$(dirname "$0")"; pwd)" + +# Colors +bold=$(tput bold) +reset=$(tput sgr0) +red=$(tput setaf 1) +green=$(tput setaf 2) +blue=$(tput setaf 4) +yellow=$(tput setaf 3) + +while getopts ":s:r:" opt; do + case $opt in + s) SRC_DIR="$OPTARG" ;; + r) CODEQL_DIR="$OPTARG"; DATABASE_PATH="$CODEQL_DIR/database"; QUERY_OUTPUT="$DATABASE_PATH/results.sarif" ;; + \?) echo "Invalid option -$OPTARG" >&2; exit 1 ;; + :) echo "Option -$OPTARG requires an argument." >&2; exit 1 ;; + esac +done + +if [ -z "$SRC_DIR" ]; then + echo "Usage: $0 -s [-r ]" + exit 1 +fi + +mkdir -p "$CODEQL_DIR" + +# Check the architecture +ARCH=$(uname -m) +PLATFORM_FLAG="" + +# CodeQL CLI binary does not support arm64 architecture, setting the platform to linux/amd64 +if [[ "$ARCH" == "arm64" ]]; then + PLATFORM_FLAG="--platform linux/amd64" +fi + +if [[ "$(docker images -q $DOCKER_IMAGE 2> /dev/null)" == "" ]]; then + echo "Docker image $DOCKER_IMAGE not found. Building locally..." + docker build $PLATFORM_FLAG -t "$DOCKER_IMAGE" -f "$BASE_DIR/codeql.dockerfile" "$BASE_DIR" + if [ $? -ne 0 ]; then + echo "${red}Docker image build failed.${reset}" + exit 1 + fi +fi + +cleanup_database() { + echo "Deleting contents of $CODEQL_DIR." + rm -rf "$CODEQL_DIR"/* +} + +SRC_DIR="$(cd "$(dirname "$SRC_DIR")"; pwd)/$(basename "$SRC_DIR")" +CODEQL_DIR="$(cd "$(dirname "$CODEQL_DIR")"; pwd)/$(basename "$CODEQL_DIR")" +DATABASE_PATH="$(cd "$(dirname "$DATABASE_PATH")"; pwd)/$(basename "$DATABASE_PATH")" + +# Step 1: Run the Docker container to create a CodeQL database from the source code. +echo "Creating a CodeQL database from the source code: $SRC_DIR" +docker run $PLATFORM_FLAG --rm -v "$SRC_DIR":/workspace/source-code \ + -v "${DATABASE_PATH}":/workspace/shared $DOCKER_IMAGE \ + "codeql database create /workspace/shared/codeql-db --language=javascript --source-root=/workspace/source-code --overwrite" + +if [ $? -ne 0 ]; then + echo "CodeQL database creation failed." + cleanup_database + exit 1 +fi + +echo "Analyzing a CodeQL database: $DATABASE_PATH" +# Step 2: Run the Docker container to analyze the CodeQL database. +docker run $PLATFORM_FLAG --rm -v "${DATABASE_PATH}":/workspace/shared $DOCKER_IMAGE \ + "codeql database analyze --format=${OUTPUT_FORMAT} --output=/workspace/shared/results.sarif /workspace/shared/codeql-db javascript-security-and-quality.qls" + +if [ $? -ne 0 ]; then + echo "CodeQL database analysis failed." + cleanup_database + exit 1 +fi + +# Step 3: Print summary of SARIF results +echo "Analysis complete. Results saved to $QUERY_OUTPUT" +if command -v jq &> /dev/null; then + vulnerabilities=$(jq -r '.runs[] | select(.results | length > 0)' "$QUERY_OUTPUT") + + if [[ -z "$vulnerabilities" ]]; then + echo "${blue}${bold}No vulnerabilities found in the SARIF results.${reset}" + else + echo "${yellow}${bold}Summary of SARIF results:${reset}" + jq -r ' + .runs[] | + .results[] as $result | + .tool.driver.rules[] as $rule | + select($rule.id == $result.ruleId) | + "Rule: \($result.ruleId)\nMessage: \($result.message.text)\nFile: \($result.locations[].physicalLocation.artifactLocation.uri)\nLine: \($result.locations[].physicalLocation.region.startLine)\nSecurity Severity: \($rule.properties."security-severity" // "N/A")\n"' "$QUERY_OUTPUT" | + while IFS= read -r line; do + case "$line" in + Rule:*) + echo "${red}${bold}$line${reset}" + ;; + Message:*) + echo "${green}$line${reset}" + ;; + File:*) + echo "${blue}$line${reset}" + ;; + Line:*) + echo "${yellow}$line${reset}" + ;; + Security\ Severity:*) + echo "${yellow}$line${reset}" + ;; + *) + echo "$line" + ;; + esac + done + fi +else + echo "${red}${bold}Please install jq to display a summary of the SARIF results.${reset}" + echo "${bold}You can view the full results in the SARIF file using a SARIF viewer.${reset}" +fi diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index e442a0efeea05..f31ec223e3d9b 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -59,7 +59,7 @@ describe('checking migration metadata changes on all registered SO types', () => "action": "0e6fc0b74c7312a8c11ff6b14437b93a997358b8", "action_task_params": "b50cb5c8a493881474918e8d4985e61374ca4c30", "ad_hoc_run_params": "d4e3c5c794151d0a4f5c71e886b2aa638da73ad2", - "alert": "05b07040b12ff45ab642f47464e8a6c903cf7b86", + "alert": "556a03378f5ee1c31593c3a37c66b54555ee14ff", "api_key_pending_invalidation": "8f5554d1984854011b8392d9a6f7ef985bcac03c", "apm-custom-dashboards": "b67128f78160c288bd7efe25b2da6e2afd5e82fc", "apm-indices": "8a2d68d415a4b542b26b0d292034a28ffac6fed4", diff --git a/src/core/server/integration_tests/saved_objects/routes/import.test.ts b/src/core/server/integration_tests/saved_objects/routes/import.test.ts index 917f7f1642e8c..bf1fae4967e95 100644 --- a/src/core/server/integration_tests/saved_objects/routes/import.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/import.test.ts @@ -13,7 +13,6 @@ import supertest from 'supertest'; import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server'; import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; import type { ICoreUsageStatsClient } from '@kbn/core-usage-data-base-server-internal'; -import type { Logger, LogLevelId } from '@kbn/logging'; import { coreUsageStatsClientMock, coreUsageDataServiceMock, @@ -28,6 +27,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { setupServer, createExportableType } from '@kbn/core-test-helpers-test-utils'; +import { loggerMock, type MockedLogger } from '@kbn/logging-mocks'; type SetupServerReturn = Awaited>; @@ -41,6 +41,7 @@ describe(`POST ${URL}`, () => { let httpSetup: SetupServerReturn['httpSetup']; let handlerContext: SetupServerReturn['handlerContext']; let savedObjectsClient: ReturnType; + let mockLogger: MockedLogger; const emptyResponse = { saved_objects: [], total: 0, per_page: 0, page: 0 }; const mockIndexPattern = { @@ -57,20 +58,10 @@ describe(`POST ${URL}`, () => { references: [], managed: false, }; - const mockLogger: jest.Mocked = { - debug: jest.fn(), - info: jest.fn(), - error: jest.fn(), - warn: jest.fn(), - trace: jest.fn(), - fatal: jest.fn(), - log: jest.fn(), - isLevelEnabled: jest.fn((level: LogLevelId) => true), - get: jest.fn(() => mockLogger), - }; beforeEach(async () => { ({ server, httpSetup, handlerContext } = await setupServer()); + mockLogger = loggerMock.create(); handlerContext.savedObjects.typeRegistry.getImportableAndExportableTypes.mockReturnValue( allowedTypes.map(createExportableType) ); diff --git a/src/dev/build/tasks/os_packages/docker_generator/run.ts b/src/dev/build/tasks/os_packages/docker_generator/run.ts index fcc9535d6bbb7..85cd6d7458ba9 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/run.ts +++ b/src/dev/build/tasks/os_packages/docker_generator/run.ts @@ -51,7 +51,7 @@ export async function runDockerGenerator( */ if (flags.baseImage === 'wolfi') baseImageName = - 'docker.elastic.co/wolfi/chainguard-base:latest@sha256:973431347ad45f40e01afbbd010bf9de929c088a63382239b90dd84f39618bc8'; + 'docker.elastic.co/wolfi/chainguard-base:latest@sha256:7082adcc2c4380be273ab5b80c4a762b4f17279c13c6fc8f87a60190aee2e2cd'; let imageFlavor = ''; if (flags.baseImage === 'ubi') imageFlavor += `-ubi`; diff --git a/src/dev/i18n_tools/bin/run_i18n_check.ts b/src/dev/i18n_tools/bin/run_i18n_check.ts index 9d7265f84520f..ff00148ab3012 100644 --- a/src/dev/i18n_tools/bin/run_i18n_check.ts +++ b/src/dev/i18n_tools/bin/run_i18n_check.ts @@ -9,7 +9,6 @@ import { Listr } from 'listr2'; import { run } from '@kbn/dev-cli-runner'; -import { ToolingLog } from '@kbn/tooling-log'; import { getTimeReporter } from '@kbn/ci-stats-reporter'; import { isFailError } from '@kbn/dev-cli-errors'; import { I18nCheckTaskContext, MessageDescriptor } from '../types'; @@ -24,13 +23,7 @@ import { import { TaskReporter } from '../utils/task_reporter'; import { flagFailError, isDefined, undefinedOrBoolean } from '../utils/verify_bin_flags'; -const toolingLog = new ToolingLog({ - level: 'info', - writeTo: process.stdout, -}); - const runStartTime = Date.now(); -const reportTime = getTimeReporter(toolingLog, 'scripts/i18n_check'); const skipOnNoTranslations = ({ config }: I18nCheckTaskContext) => !config?.translations.length && 'No translations found.'; @@ -50,9 +43,13 @@ run( namespace: namespace, fix = false, path, + silent, + quiet, }, log, }) => { + const reportTime = getTimeReporter(log, 'scripts/i18n_check'); + if ( fix && (isDefined(ignoreIncompatible) || @@ -131,13 +128,15 @@ run( { concurrent: false, exitOnError: true, - renderer: process.env.CI ? 'verbose' : ('default' as any), + forceTTY: false, + renderer: + ((silent || quiet) && 'silent') || (process.env.CI ? 'verbose' : ('default' as any)), } ); try { const messages: Map = new Map(); - const taskReporter = new TaskReporter({ toolingLog }); + const taskReporter = new TaskReporter({ toolingLog: log }); await list.run({ messages, taskReporter }); reportTime(runStartTime, 'total', { @@ -150,6 +149,7 @@ run( reportTime(runStartTime, 'error', { success: false, }); + log.error(error); } else { log.error('Unhandled exception!'); log.error(error); diff --git a/src/dev/license_checker/config.ts b/src/dev/license_checker/config.ts index 3a45c6394f20f..8609eef92a268 100644 --- a/src/dev/license_checker/config.ts +++ b/src/dev/license_checker/config.ts @@ -87,7 +87,7 @@ export const LICENSE_OVERRIDES = { 'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts '@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint '@elastic/ems-client@8.5.3': ['Elastic License 2.0'], - '@elastic/eui@97.2.0': ['Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0'], + '@elastic/eui@97.3.0': ['Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0'], 'language-subtag-registry@0.3.21': ['CC-BY-4.0'], // retired ODC‑By license https://github.com/mattcg/language-subtag-registry 'buffers@0.1.1': ['MIT'], // license in importing module https://www.npmjs.com/package/binary '@bufbuild/protobuf@1.2.1': ['Apache-2.0'], // license (Apache-2.0 AND BSD-3-Clause) diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx index ae9c5a844dcc3..467e6afa6a897 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx @@ -842,7 +842,7 @@ describe('XYChart component', () => { const lineArea = dataLayers.find(LineSeries).at(0); const expectedSeriesStyle = expect.objectContaining({ point: expect.objectContaining({ - visible: showPoints ? 'always' : 'never', + visible: showPoints ? 'always' : 'auto', }), }); expect(lineArea.prop('areaSeriesStyle')).toEqual(expectedSeriesStyle); diff --git a/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx b/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx index 473562b63ad5e..942909880f301 100644 --- a/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx @@ -298,7 +298,7 @@ export const getSeriesName: GetSeriesNameFn = ( const getPointConfig: GetPointConfigFn = ({ markSizeAccessor, showPoints, pointsRadius }) => { return { - visible: showPoints || markSizeAccessor ? 'always' : 'never', + visible: showPoints || markSizeAccessor ? 'always' : 'auto', radius: pointsRadius, fill: markSizeAccessor ? ColorVariant.Series : undefined, }; diff --git a/src/plugins/dashboard/kibana.jsonc b/src/plugins/dashboard/kibana.jsonc index c84d4a9dc293d..9d47ab95c8872 100644 --- a/src/plugins/dashboard/kibana.jsonc +++ b/src/plugins/dashboard/kibana.jsonc @@ -16,6 +16,7 @@ "dataViews", "dataViewEditor", "embeddable", + "fieldFormats", "controls", "inspector", "navigation", diff --git a/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.tsx b/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.tsx index 034ee2f8e45f4..59b3b3926060a 100644 --- a/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.tsx +++ b/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.tsx @@ -50,11 +50,16 @@ export const DashboardListingPage = ({ }, []); useEffect(() => { - coreServices.chrome.setBreadcrumbs([ + coreServices.chrome.setBreadcrumbs( + [ + { + text: getDashboardBreadcrumb(), + }, + ], { - text: getDashboardBreadcrumb(), - }, - ]); + project: { value: [] }, + } + ); if (serverlessService) { // if serverless breadcrumbs available, diff --git a/src/plugins/dashboard/public/dashboard_container/component/viewport/dashboard_viewport.tsx b/src/plugins/dashboard/public/dashboard_container/component/viewport/dashboard_viewport.tsx index 664a3c43a8d9d..027d2aee62b15 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/viewport/dashboard_viewport.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/viewport/dashboard_viewport.tsx @@ -10,7 +10,7 @@ import { debounce } from 'lodash'; import classNames from 'classnames'; import useResizeObserver from 'use-resize-observer/polyfilled'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { EuiPortal } from '@elastic/eui'; import { ReactEmbeddableRenderer, ViewMode } from '@kbn/embeddable-plugin/public'; @@ -22,10 +22,7 @@ import { ControlGroupSerializedState, } from '@kbn/controls-plugin/public'; import { CONTROL_GROUP_TYPE } from '@kbn/controls-plugin/common'; -import { - useBatchedPublishingSubjects, - useStateFromPublishingSubject, -} from '@kbn/presentation-publishing'; +import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; import { DashboardGrid } from '../grid'; import { useDashboardApi } from '../../../dashboard_api/use_dashboard_api'; import { DashboardEmptyScreen } from '../empty_screen/dashboard_empty_screen'; @@ -44,7 +41,7 @@ export const useDebouncedWidthObserver = (skipDebounce = false, wait = 100) => { return { ref, width }; }; -export const DashboardViewportComponent = () => { +export const DashboardViewport = () => { const dashboardApi = useDashboardApi(); const [hasControls, setHasControls] = useState(false); const [ @@ -70,6 +67,9 @@ export const DashboardViewportComponent = () => { dashboardApi.uuid$, dashboardApi.fullScreenMode$ ); + const onExit = useCallback(() => { + dashboardApi.setFullScreenMode(false); + }, [dashboardApi]); const panelCount = useMemo(() => { return Object.keys(panels).length; @@ -142,6 +142,11 @@ export const DashboardViewportComponent = () => { />
) : null} + {fullScreenMode && ( + + + + )} {panelCount === 0 && }
{
); }; - -// This fullscreen button HOC separates fullscreen button and dashboard content to reduce rerenders -// because ExitFullScreenButton sets isFullscreenMode to false on unmount while rerendering. -// This specifically fixed maximizing/minimizing panels without exiting fullscreen mode. -const WithFullScreenButton = ({ children }: { children: JSX.Element }) => { - const dashboardApi = useDashboardApi(); - - const isFullScreenMode = useStateFromPublishingSubject(dashboardApi.fullScreenMode$); - - return ( - <> - {children} - {isFullScreenMode && ( - - dashboardApi.setFullScreenMode(false)} - toggleChrome={!dashboardApi.isEmbeddedExternally} - /> - - )} - - ); -}; - -export const DashboardViewport = () => ( - - - -); diff --git a/src/plugins/data_views/public/data_views/data_views_api_client.test.ts b/src/plugins/data_views/public/data_views/data_views_api_client.test.ts index 8e1261802fbbc..4eaf2e88f56d9 100644 --- a/src/plugins/data_views/public/data_views/data_views_api_client.test.ts +++ b/src/plugins/data_views/public/data_views/data_views_api_client.test.ts @@ -30,9 +30,6 @@ describe('IndexPatternsApiClient', () => { expect(fetchSpy).toHaveBeenCalledWith(expectedPath, { // not sure what asResponse is but the rest of the results are useful asResponse: true, - headers: { - 'user-hash': '', - }, query: { allow_hidden: undefined, allow_no_index: undefined, diff --git a/src/plugins/data_views/public/data_views/data_views_api_client.ts b/src/plugins/data_views/public/data_views/data_views_api_client.ts index e569e7f25bff6..233b05ea7bc22 100644 --- a/src/plugins/data_views/public/data_views/data_views_api_client.ts +++ b/src/plugins/data_views/public/data_views/data_views_api_client.ts @@ -56,6 +56,7 @@ export class DataViewsApiClient implements IDataViewsApiClient { const userId = await this.getCurrentUserId(); const userHash = userId ? await sha1(userId) : ''; + const headers = userHash ? { 'user-hash': userHash } : undefined; const request = body ? this.http.post(url, { query, body, version, asResponse }) @@ -64,7 +65,7 @@ export class DataViewsApiClient implements IDataViewsApiClient { version, ...cacheOptions, asResponse, - headers: { 'user-hash': userHash }, + headers, }); return request.catch((resp) => { diff --git a/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/convert_to_top_nav_item.test.ts b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/convert_to_top_nav_item.test.ts new file mode 100644 index 0000000000000..2fb65563cddfb --- /dev/null +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/convert_to_top_nav_item.test.ts @@ -0,0 +1,118 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { + AppMenuActionPrimary, + AppMenuActionSecondary, + AppMenuActionSubmenuCustom, + AppMenuActionType, +} from '@kbn/discover-utils'; +import { convertAppMenuItemToTopNavItem } from './convert_to_top_nav_item'; +import { discoverServiceMock } from '../../../../../__mocks__/services'; + +describe('convertAppMenuItemToTopNavItem', () => { + it('should convert a primary AppMenuItem to TopNavMenuData', () => { + const appMenuItem: AppMenuActionPrimary = { + id: 'action-1', + type: AppMenuActionType.primary, + controlProps: { + label: 'Action 1', + testId: 'action-1', + iconType: 'share', + onClick: jest.fn(), + }, + }; + + const topNavItem = convertAppMenuItemToTopNavItem({ + appMenuItem, + services: discoverServiceMock, + }); + + expect(topNavItem).toEqual({ + id: 'action-1', + label: 'Action 1', + description: 'Action 1', + testId: 'action-1', + run: expect.any(Function), + iconType: 'share', + iconOnly: true, + }); + }); + + it('should convert a secondary AppMenuItem to TopNavMenuData', () => { + const appMenuItem: AppMenuActionSecondary = { + id: 'action-2', + type: AppMenuActionType.secondary, + controlProps: { + label: 'Action Secondary', + testId: 'action-secondary', + onClick: jest.fn(), + }, + }; + + const topNavItem = convertAppMenuItemToTopNavItem({ + appMenuItem, + services: discoverServiceMock, + }); + + expect(topNavItem).toEqual({ + id: 'action-2', + label: 'Action Secondary', + description: 'Action Secondary', + testId: 'action-secondary', + run: expect.any(Function), + }); + }); + + it('should convert a custom AppMenuItem to TopNavMenuData', () => { + const appMenuItem: AppMenuActionSubmenuCustom = { + id: 'action-3', + type: AppMenuActionType.custom, + label: 'Action submenu', + testId: 'action-submenu', + actions: [ + { + id: 'action-3-1', + type: AppMenuActionType.custom, + controlProps: { + label: 'Action 3.1', + testId: 'action-3-1', + onClick: jest.fn(), + }, + }, + { + id: 'action-3-2', + type: AppMenuActionType.submenuHorizontalRule, + }, + { + id: 'action-3-3', + type: AppMenuActionType.custom, + controlProps: { + label: 'Action 3.3', + testId: 'action-3-3', + onClick: jest.fn(), + }, + }, + ], + }; + + const topNavItem = convertAppMenuItemToTopNavItem({ + appMenuItem, + services: discoverServiceMock, + }); + + expect(topNavItem).toEqual({ + id: 'action-3', + label: 'Action submenu', + description: 'Action submenu', + testId: 'action-submenu', + run: expect.any(Function), + }); + }); +}); diff --git a/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/convert_to_top_nav_item.ts b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/convert_to_top_nav_item.ts new file mode 100644 index 0000000000000..2ff2d531d77cf --- /dev/null +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/convert_to_top_nav_item.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { AppMenuActionType, AppMenuItem } from '@kbn/discover-utils'; +import type { TopNavMenuData } from '@kbn/navigation-plugin/public'; +import { runAppMenuAction, runAppMenuPopoverAction } from './run_app_menu_action'; +import { DiscoverServices } from '../../../../../build_services'; + +export function convertAppMenuItemToTopNavItem({ + appMenuItem, + services, +}: { + appMenuItem: AppMenuItem; + services: DiscoverServices; +}): TopNavMenuData { + if ('actions' in appMenuItem) { + return { + id: appMenuItem.id, + label: appMenuItem.label, + description: appMenuItem.description ?? appMenuItem.label, + testId: appMenuItem.testId, + run: (anchorElement: HTMLElement) => { + runAppMenuPopoverAction({ + appMenuItem, + anchorElement, + services, + }); + }, + }; + } + + return { + id: appMenuItem.id, + label: appMenuItem.controlProps.label, + description: appMenuItem.controlProps.description ?? appMenuItem.controlProps.label, + testId: appMenuItem.controlProps.testId, + run: async (anchorElement: HTMLElement) => { + await runAppMenuAction({ + appMenuItem, + anchorElement, + services, + }); + }, + ...(appMenuItem.type === AppMenuActionType.primary + ? { iconType: appMenuItem.controlProps.iconType, iconOnly: true } + : {}), + }; +} diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.test.tsx b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_alerts.test.tsx similarity index 74% rename from src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.test.tsx rename to src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_alerts.test.tsx index fb9f127b83d86..a658ca750cf28 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.test.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_alerts.test.tsx @@ -10,28 +10,40 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { findTestSubject } from '@elastic/eui/lib/test'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { AlertsPopover } from './open_alerts_popover'; -import { discoverServiceMock } from '../../../../__mocks__/services'; -import { dataViewWithTimefieldMock } from '../../../../__mocks__/data_view_with_timefield'; -import { dataViewWithNoTimefieldMock } from '../../../../__mocks__/data_view_no_timefield'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { getDiscoverStateMock } from '../../../../__mocks__/discover_state.mock'; +import { AppMenuActionsMenuPopover } from './run_app_menu_action'; +import { getAlertsAppMenuItem } from './get_alerts'; +import { discoverServiceMock } from '../../../../../__mocks__/services'; +import { dataViewWithTimefieldMock } from '../../../../../__mocks__/data_view_with_timefield'; +import { dataViewWithNoTimefieldMock } from '../../../../../__mocks__/data_view_no_timefield'; +import { getDiscoverStateMock } from '../../../../../__mocks__/discover_state.mock'; const mount = (dataView = dataViewMock, isEsqlMode = false) => { const stateContainer = getDiscoverStateMock({ isTimeBased: true }); stateContainer.actions.setDataView(dataView); + + const discoverParamsMock = { + dataView, + adHocDataViews: [], + isEsqlMode, + onNewSearch: jest.fn(), + onOpenSavedSearch: jest.fn(), + onUpdateAdHocDataViews: jest.fn(), + }; + + const alertsAppMenuItem = getAlertsAppMenuItem({ + discoverParams: discoverParamsMock, + services: discoverServiceMock, + stateContainer, + }); + return mountWithIntl( - - - + ); }; diff --git a/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_alerts.tsx b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_alerts.tsx new file mode 100644 index 0000000000000..d6d8bb81bac09 --- /dev/null +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_alerts.tsx @@ -0,0 +1,179 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React, { useCallback, useMemo } from 'react'; +import type { DataView } from '@kbn/data-plugin/common'; +import { i18n } from '@kbn/i18n'; +import { + AppMenuActionId, + AppMenuActionSubmenuSecondary, + AppMenuActionType, +} from '@kbn/discover-utils'; +import { + AlertConsumers, + ES_QUERY_ID, + RuleCreationValidConsumer, + STACK_ALERTS_FEATURE_ID, +} from '@kbn/rule-data-utils'; +import { RuleTypeMetaData } from '@kbn/alerting-plugin/common'; +import { DiscoverStateContainer } from '../../../state_management/discover_state'; +import { AppMenuDiscoverParams } from './types'; +import { DiscoverServices } from '../../../../../build_services'; + +const EsQueryValidConsumer: RuleCreationValidConsumer[] = [ + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.LOGS, + AlertConsumers.OBSERVABILITY, + STACK_ALERTS_FEATURE_ID, +]; + +interface EsQueryAlertMetaData extends RuleTypeMetaData { + isManagementPage?: boolean; + adHocDataViewList: DataView[]; +} + +const CreateAlertFlyout: React.FC<{ + discoverParams: AppMenuDiscoverParams; + services: DiscoverServices; + onFinishAction: () => void; + stateContainer: DiscoverStateContainer; +}> = ({ stateContainer, discoverParams, services, onFinishAction }) => { + const query = stateContainer.appState.getState().query; + + const { dataView, isEsqlMode, adHocDataViews, onUpdateAdHocDataViews } = discoverParams; + const { triggersActionsUi } = services; + const timeField = getTimeField(dataView); + + /** + * Provides the default parameters used to initialize the new rule + */ + const getParams = useCallback(() => { + if (isEsqlMode) { + return { + searchType: 'esqlQuery', + esqlQuery: query, + timeField, + }; + } + const savedQueryId = stateContainer.appState.getState().savedQuery; + return { + searchType: 'searchSource', + searchConfiguration: stateContainer.savedSearchState + .getState() + .searchSource.getSerializedFields(), + savedQueryId, + }; + }, [isEsqlMode, stateContainer.appState, stateContainer.savedSearchState, query, timeField]); + + const discoverMetadata: EsQueryAlertMetaData = useMemo( + () => ({ + isManagementPage: false, + adHocDataViewList: adHocDataViews, + }), + [adHocDataViews] + ); + + return triggersActionsUi?.getAddRuleFlyout({ + metadata: discoverMetadata, + consumer: 'alerts', + onClose: (_, metadata) => { + onUpdateAdHocDataViews(metadata!.adHocDataViewList); + onFinishAction(); + }, + onSave: async (metadata) => { + onUpdateAdHocDataViews(metadata!.adHocDataViewList); + }, + canChangeTrigger: false, + ruleTypeId: ES_QUERY_ID, + initialValues: { params: getParams() }, + validConsumers: EsQueryValidConsumer, + useRuleProducer: true, + // Default to the Logs consumer if it's available. This should fall back to Stack Alerts if it's not. + initialSelectedConsumer: AlertConsumers.LOGS, + }); +}; + +export const getAlertsAppMenuItem = ({ + discoverParams, + services, + stateContainer, +}: { + discoverParams: AppMenuDiscoverParams; + services: DiscoverServices; + stateContainer: DiscoverStateContainer; +}): AppMenuActionSubmenuSecondary => { + const { dataView, isEsqlMode } = discoverParams; + const timeField = getTimeField(dataView); + const hasTimeFieldName = !isEsqlMode ? Boolean(dataView?.timeFieldName) : Boolean(timeField); + + return { + id: AppMenuActionId.alerts, + type: AppMenuActionType.secondary, + label: i18n.translate('discover.localMenu.localMenu.alertsTitle', { + defaultMessage: 'Alerts', + }), + description: i18n.translate('discover.localMenu.alertsDescription', { + defaultMessage: 'Alerts', + }), + testId: 'discoverAlertsButton', + actions: [ + { + id: AppMenuActionId.createRule, + type: AppMenuActionType.secondary, + controlProps: { + label: i18n.translate('discover.alerts.createSearchThreshold', { + defaultMessage: 'Create search threshold rule', + }), + iconType: 'bell', + testId: 'discoverCreateAlertButton', + disableButton: !hasTimeFieldName, + tooltip: hasTimeFieldName + ? undefined + : i18n.translate('discover.alerts.missedTimeFieldToolTip', { + defaultMessage: 'Data view does not have a time field.', + }), + onClick: async (params) => { + return ( + + ); + }, + }, + }, + { + id: 'alertsDivider', + type: AppMenuActionType.submenuHorizontalRule, + }, + { + id: AppMenuActionId.manageRulesAndConnectors, + type: AppMenuActionType.secondary, + controlProps: { + label: i18n.translate('discover.alerts.manageRulesAndConnectors', { + defaultMessage: 'Manage rules and connectors', + }), + iconType: 'tableOfContents', + testId: 'discoverManageAlertsButton', + href: services.application.getUrlForApp( + 'management/insightsAndAlerting/triggersActions/rules' + ), + onClick: undefined, + }, + }, + ], + }; +}; + +function getTimeField(dataView: DataView | undefined) { + const dateFields = dataView?.fields.getByType('date'); + return dataView?.timeFieldName || dateFields?.[0]?.name; +} diff --git a/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_inspect.tsx b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_inspect.tsx new file mode 100644 index 0000000000000..5943f598c9aef --- /dev/null +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_inspect.tsx @@ -0,0 +1,34 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { AppMenuActionId, AppMenuActionType, AppMenuActionSecondary } from '@kbn/discover-utils'; +import { i18n } from '@kbn/i18n'; + +export const getInspectAppMenuItem = ({ + onOpenInspector, +}: { + onOpenInspector: () => void; +}): AppMenuActionSecondary => { + return { + id: AppMenuActionId.inspect, + type: AppMenuActionType.secondary, + controlProps: { + label: i18n.translate('discover.localMenu.inspectTitle', { + defaultMessage: 'Inspect', + }), + description: i18n.translate('discover.localMenu.openInspectorForSearchDescription', { + defaultMessage: 'Open Inspector for search', + }), + testId: 'openInspectorButton', + onClick: () => { + onOpenInspector(); + }, + }, + }; +}; diff --git a/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_new_search.tsx b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_new_search.tsx new file mode 100644 index 0000000000000..b67f14f31c56a --- /dev/null +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_new_search.tsx @@ -0,0 +1,35 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { AppMenuActionId, AppMenuActionType, AppMenuActionPrimary } from '@kbn/discover-utils'; +import { i18n } from '@kbn/i18n'; + +export const getNewSearchAppMenuItem = ({ + onNewSearch, +}: { + onNewSearch: () => void; +}): AppMenuActionPrimary => { + return { + id: AppMenuActionId.new, + type: AppMenuActionType.primary, + controlProps: { + label: i18n.translate('discover.localMenu.localMenu.newSearchTitle', { + defaultMessage: 'New', + }), + description: i18n.translate('discover.localMenu.newSearchDescription', { + defaultMessage: 'New Search', + }), + iconType: 'plus', + testId: 'discoverNewButton', + onClick: () => { + onNewSearch(); + }, + }, + }; +}; diff --git a/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_open_search.tsx b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_open_search.tsx new file mode 100644 index 0000000000000..e8f6c5448d602 --- /dev/null +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_open_search.tsx @@ -0,0 +1,37 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React from 'react'; +import { AppMenuActionId, AppMenuActionType, AppMenuActionPrimary } from '@kbn/discover-utils'; +import { i18n } from '@kbn/i18n'; +import { OpenSearchPanel } from '../open_search_panel'; + +export const getOpenSearchAppMenuItem = ({ + onOpenSavedSearch, +}: { + onOpenSavedSearch: (savedSearchId: string) => void; +}): AppMenuActionPrimary => { + return { + id: AppMenuActionId.open, + type: AppMenuActionType.primary, + controlProps: { + label: i18n.translate('discover.localMenu.openTitle', { + defaultMessage: 'Open', + }), + description: i18n.translate('discover.localMenu.openSavedSearchDescription', { + defaultMessage: 'Open Saved Search', + }), + iconType: 'folderOpen', + testId: 'discoverOpenButton', + onClick: ({ onFinishAction }) => { + return ; + }, + }, + }; +}; diff --git a/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_share.tsx b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_share.tsx new file mode 100644 index 0000000000000..f1a030a40ea0a --- /dev/null +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/get_share.tsx @@ -0,0 +1,135 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { AppMenuActionPrimary, AppMenuActionId, AppMenuActionType } from '@kbn/discover-utils'; +import { omit } from 'lodash'; +import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { DiscoverStateContainer } from '../../../state_management/discover_state'; +import { getSharingData, showPublicUrlSwitch } from '../../../../../utils/get_sharing_data'; +import { DiscoverAppLocatorParams } from '../../../../../../common/app_locator'; +import { AppMenuDiscoverParams } from './types'; +import { DiscoverServices } from '../../../../../build_services'; + +export const getShareAppMenuItem = ({ + discoverParams, + services, + stateContainer, +}: { + discoverParams: AppMenuDiscoverParams; + services: DiscoverServices; + stateContainer: DiscoverStateContainer; +}): AppMenuActionPrimary => { + return { + id: AppMenuActionId.share, + type: AppMenuActionType.primary, + controlProps: { + label: i18n.translate('discover.localMenu.shareTitle', { + defaultMessage: 'Share', + }), + description: i18n.translate('discover.localMenu.shareSearchDescription', { + defaultMessage: 'Share Search', + }), + iconType: 'share', + testId: 'shareTopNavButton', + onClick: async ({ anchorElement }) => { + const { dataView, isEsqlMode } = discoverParams; + + if (!services.share) { + return; + } + + const savedSearch = stateContainer.savedSearchState.getState(); + const searchSourceSharingData = await getSharingData( + savedSearch.searchSource, + stateContainer.appState.getState(), + services, + isEsqlMode + ); + + const { locator, notifications } = services; + const appState = stateContainer.appState.getState(); + const { timefilter } = services.data.query.timefilter; + const timeRange = timefilter.getTime(); + const refreshInterval = timefilter.getRefreshInterval(); + const filters = services.filterManager.getFilters(); + + // Share -> Get links -> Snapshot + const params: DiscoverAppLocatorParams = { + ...omit(appState, 'dataSource'), + ...(savedSearch.id ? { savedSearchId: savedSearch.id } : {}), + ...(dataView?.isPersisted() + ? { dataViewId: dataView?.id } + : { dataViewSpec: dataView?.toMinimalSpec() }), + filters, + timeRange, + refreshInterval, + }; + const relativeUrl = locator.getRedirectUrl(params); + + // This logic is duplicated from `relativeToAbsolute` (for bundle size reasons). Ultimately, this should be + // replaced when https://github.com/elastic/kibana/issues/153323 is implemented. + const link = document.createElement('a'); + link.setAttribute('href', relativeUrl); + const shareableUrl = link.href; + + // Share -> Get links -> Saved object + let shareableUrlForSavedObject = await locator.getUrl( + { savedSearchId: savedSearch.id }, + { absolute: true } + ); + + // UrlPanelContent forces a '_g' parameter in the saved object URL: + // https://github.com/elastic/kibana/blob/a30508153c1467b1968fb94faf1debc5407f61ea/src/plugins/share/public/components/url_panel_content.tsx#L230 + // Since our locator doesn't add the '_g' parameter if it's not needed, UrlPanelContent + // will interpret it as undefined and add '?_g=' to the URL, which is invalid in Discover, + // so instead we add an empty object for the '_g' parameter to the URL. + shareableUrlForSavedObject = setStateToKbnUrl( + '_g', + {}, + undefined, + shareableUrlForSavedObject + ); + + services.share.toggleShareContextMenu({ + anchorElement, + allowEmbed: false, + allowShortUrl: !!services.capabilities.discover.createShortUrl, + shareableUrl, + shareableUrlForSavedObject, + shareableUrlLocatorParams: { locator, params }, + objectId: savedSearch.id, + objectType: 'search', + objectTypeMeta: { + title: i18n.translate('discover.share.shareModal.title', { + defaultMessage: 'Share this search', + }), + }, + sharingData: { + isTextBased: isEsqlMode, + locatorParams: [{ id: locator.id, params }], + ...searchSourceSharingData, + // CSV reports can be generated without a saved search so we provide a fallback title + title: + savedSearch.title || + i18n.translate('discover.localMenu.fallbackReportTitle', { + defaultMessage: 'Untitled discover search', + }), + }, + isDirty: !savedSearch.id || stateContainer.appState.hasChanged(), + showPublicUrlSwitch, + onClose: () => { + anchorElement?.focus(); + }, + toasts: notifications.toasts, + }); + }, + }, + }; +}; diff --git a/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/index.ts b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/index.ts new file mode 100644 index 0000000000000..6a5c2f31946a2 --- /dev/null +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/index.ts @@ -0,0 +1,16 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export { getAlertsAppMenuItem } from './get_alerts'; +export { getNewSearchAppMenuItem } from './get_new_search'; +export { getOpenSearchAppMenuItem } from './get_open_search'; +export { getShareAppMenuItem } from './get_share'; +export { getInspectAppMenuItem } from './get_inspect'; +export { convertAppMenuItemToTopNavItem } from './convert_to_top_nav_item'; +export * from './types'; diff --git a/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/run_app_menu_action.test.tsx b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/run_app_menu_action.test.tsx new file mode 100644 index 0000000000000..952063317d91c --- /dev/null +++ b/src/plugins/discover/public/application/main/components/top_nav/app_menu_actions/run_app_menu_action.test.tsx @@ -0,0 +1,120 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React from 'react'; +import { screen } from '@testing-library/react'; +import { AppMenuActionSubmenuCustom, AppMenuActionType, AppMenuItem } from '@kbn/discover-utils'; +import { discoverServiceMock } from '../../../../../__mocks__/services'; +import { runAppMenuAction, runAppMenuPopoverAction } from './run_app_menu_action'; + +describe('run app menu actions', () => { + describe('runAppMenuAction', () => { + it('should call the action correctly', () => { + const appMenuItem: AppMenuItem = { + id: 'action-1', + type: AppMenuActionType.primary, + controlProps: { + label: 'Action 1', + testId: 'action-1', + iconType: 'share', + onClick: jest.fn(), + }, + }; + + const anchorElement = document.createElement('div'); + + runAppMenuAction({ + appMenuItem, + anchorElement, + services: discoverServiceMock, + }); + + expect(appMenuItem.controlProps.onClick).toHaveBeenCalled(); + }); + + it('should call the action and render a custom content', async () => { + const appMenuItem: AppMenuItem = { + id: 'action-1', + type: AppMenuActionType.primary, + controlProps: { + label: 'Action 1', + testId: 'action-1', + iconType: 'share', + onClick: jest.fn(({ onFinishAction }) => ( +
); diff --git a/test/api_integration/apis/home/sample_data.ts b/test/api_integration/apis/home/sample_data.ts index d290f772fdec5..13ab83e85a05a 100644 --- a/test/api_integration/apis/home/sample_data.ts +++ b/test/api_integration/apis/home/sample_data.ts @@ -24,12 +24,6 @@ export default function ({ getService }: FtrProviderContext) { * @see {@link src/plugins/home/server/services/sample_data/data_sets/flights/index.ts} */ const FLIGHTS_OVERVIEW_DASHBOARD_ID = '7adfa750-4c81-11e8-b3d7-01146121b73d'; - const FLIGHTS_CANVAS_APPLINK_PATH = - '/app/canvas#/workpad/workpad-a474e74b-aedc-47c3-894a-db77e62c41e0'; // includes default ID of the flights canvas applink path - - const includesPathInAppLinks = (appLinks: Array<{ path: string }>, path: string): boolean => { - return appLinks.some((item) => item.path === path); - }; describe('sample data apis', () => { before(async () => { @@ -52,12 +46,7 @@ export default function ({ getService }: FtrProviderContext) { const flightsData = findFlightsData(resp); expect(flightsData.status).to.be('not_installed'); - // Check and make sure the sample dataset reflects the default object IDs, because no sample data objects exist. - // Instead of checking each object ID, we check the dashboard and canvas app link as representatives. expect(flightsData.overviewDashboard).to.be(FLIGHTS_OVERVIEW_DASHBOARD_ID); - expect(includesPathInAppLinks(flightsData.appLinks, FLIGHTS_CANVAS_APPLINK_PATH)).to.be( - true - ); }); }); @@ -79,7 +68,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.body).to.eql({ elasticsearchIndicesCreated: { kibana_sample_data_flights: 13014 }, - kibanaSavedObjectsLoaded: 8, + kibanaSavedObjectsLoaded: 7, }); }); @@ -136,19 +125,11 @@ export default function ({ getService }: FtrProviderContext) { const flightsData = findFlightsData(resp); expect(flightsData.status).to.be('installed'); - // Check and make sure the sample dataset reflects the existing object IDs in each space. - // Instead of checking each object ID, we check the dashboard and canvas app link as representatives. if (space === 'default') { expect(flightsData.overviewDashboard).to.be(FLIGHTS_OVERVIEW_DASHBOARD_ID); - expect(includesPathInAppLinks(flightsData.appLinks, FLIGHTS_CANVAS_APPLINK_PATH)).to.be( - true - ); } else { // the sample data objects installed in the 'other' space had their IDs regenerated upon import expect(flightsData.overviewDashboard).not.to.be(FLIGHTS_OVERVIEW_DASHBOARD_ID); - expect(includesPathInAppLinks(flightsData.appLinks, FLIGHTS_CANVAS_APPLINK_PATH)).to.be( - false - ); } }); }); @@ -186,12 +167,7 @@ export default function ({ getService }: FtrProviderContext) { const flightsData = findFlightsData(resp); expect(flightsData.status).to.be('not_installed'); - // Check and make sure the sample dataset reflects the default object IDs, because no sample data objects exist. - // Instead of checking each object ID, we check the dashboard and canvas app link as representatives. expect(flightsData.overviewDashboard).to.be(FLIGHTS_OVERVIEW_DASHBOARD_ID); - expect(includesPathInAppLinks(flightsData.appLinks, FLIGHTS_CANVAS_APPLINK_PATH)).to.be( - true - ); }); }); } diff --git a/test/examples/discover_customization_examples/customizations.ts b/test/examples/discover_customization_examples/customizations.ts index f9e29611dc0cc..38e8e8ab2a6c5 100644 --- a/test/examples/discover_customization_examples/customizations.ts +++ b/test/examples/discover_customization_examples/customizations.ts @@ -48,15 +48,9 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { }); it('Top nav', async () => { - await testSubjects.existOrFail('customOptionsButton'); await testSubjects.existOrFail('shareTopNavButton'); - await testSubjects.existOrFail('documentExplorerButton'); await testSubjects.missingOrFail('discoverNewButton'); await testSubjects.missingOrFail('discoverOpenButton'); - await testSubjects.click('customOptionsButton'); - await testSubjects.existOrFail('customOptionsPopover'); - await testSubjects.click('customOptionsButton'); - await testSubjects.missingOrFail('customOptionsPopover'); }); it('Search bar', async () => { diff --git a/test/functional/apps/console/_misc_console_behavior.ts b/test/functional/apps/console/_misc_console_behavior.ts index fc53b6b37fb51..4185a2198fa32 100644 --- a/test/functional/apps/console/_misc_console_behavior.ts +++ b/test/functional/apps/console/_misc_console_behavior.ts @@ -154,8 +154,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.console.openConsole(); }); - // Failing: See https://github.com/elastic/kibana/issues/193868 - describe.skip('customizable font size', () => { + describe('customizable font size', () => { it('should allow the font size to be customized', async () => { await PageObjects.console.openConfig(); await PageObjects.console.setFontSizeSetting(20); diff --git a/test/functional/apps/discover/context_awareness/extensions/_get_app_menu.ts b/test/functional/apps/discover/context_awareness/extensions/_get_app_menu.ts new file mode 100644 index 0000000000000..9b019a67d6507 --- /dev/null +++ b/test/functional/apps/discover/context_awareness/extensions/_get_app_menu.ts @@ -0,0 +1,73 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import kbnRison from '@kbn/rison'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const { common, discover, header } = getPageObjects([ + 'common', + 'timePicker', + 'discover', + 'header', + ]); + const esArchiver = getService('esArchiver'); + const testSubjects = getService('testSubjects'); + + describe('extension getAppMenu', () => { + before(async () => { + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + it('should render the main actions and the action from root profile', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from logstash* | sort @timestamp desc' }, + }); + await common.navigateToActualUrl('discover', `?_a=${state}`, { + ensureCurrentUrl: false, + }); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + await testSubjects.existOrFail('discoverNewButton'); + await testSubjects.existOrFail('discoverAlertsButton'); + await testSubjects.existOrFail('example-custom-root-submenu'); + }); + + it('should render custom actions', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-logs | sort @timestamp desc' }, + }); + await common.navigateToActualUrl('discover', `?_a=${state}`, { + ensureCurrentUrl: false, + }); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + await testSubjects.existOrFail('discoverNewButton'); + await testSubjects.existOrFail('discoverAlertsButton'); + await testSubjects.existOrFail('example-custom-root-submenu'); + await testSubjects.existOrFail('example-custom-action'); + + await testSubjects.click('example-custom-root-submenu'); + await testSubjects.existOrFail('example-custom-root-action12'); + + await testSubjects.click('example-custom-root-action12'); + await testSubjects.existOrFail('example-custom-root-action12-flyout'); + await testSubjects.click('euiFlyoutCloseButton'); + + await testSubjects.click('discoverAlertsButton'); + await testSubjects.existOrFail('example-custom-action-under-alerts'); + }); + }); +} diff --git a/test/functional/apps/discover/context_awareness/index.ts b/test/functional/apps/discover/context_awareness/index.ts index f937f38c741f9..40f2df358a4ce 100644 --- a/test/functional/apps/discover/context_awareness/index.ts +++ b/test/functional/apps/discover/context_awareness/index.ts @@ -45,5 +45,6 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid loadTestFile(require.resolve('./extensions/_get_cell_renderers')); loadTestFile(require.resolve('./extensions/_get_default_app_state')); loadTestFile(require.resolve('./extensions/_get_additional_cell_actions')); + loadTestFile(require.resolve('./extensions/_get_app_menu')); }); } diff --git a/test/functional/apps/discover/group6/_sidebar_field_stats.ts b/test/functional/apps/discover/group6/_sidebar_field_stats.ts index 3cfa2c1da20af..325adb313ed6c 100644 --- a/test/functional/apps/discover/group6/_sidebar_field_stats.ts +++ b/test/functional/apps/discover/group6/_sidebar_field_stats.ts @@ -148,7 +148,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await discover.selectTextBaseLang(); - const testQuery = `from logstash-* [METADATA _index, _id] | sort @timestamp desc | limit 500`; + const testQuery = `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500`; await monacoEditor.setCodeEditorValue(testQuery); await testSubjects.click('querySubmitButton'); await header.waitUntilLoadingHasFinished(); @@ -168,7 +168,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.clickFieldListPlusFilter('bytes', '0'); const editorValue = await monacoEditor.getCodeEditorValue(); expect(editorValue).to.eql( - `from logstash-* [METADATA _index, _id] | sort @timestamp desc | limit 500\n| WHERE \`bytes\`==0` + `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500\n| WHERE \`bytes\`==0` ); await unifiedFieldList.closeFieldPopover(); }); @@ -188,7 +188,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.clickFieldListPlusFilter('extension.raw', 'css'); const editorValue = await monacoEditor.getCodeEditorValue(); expect(editorValue).to.eql( - `from logstash-* [METADATA _index, _id] | sort @timestamp desc | limit 500\n| WHERE \`extension.raw\`=="css"` + `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500\n| WHERE \`extension.raw\`=="css"` ); await unifiedFieldList.closeFieldPopover(); @@ -209,7 +209,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.clickFieldListPlusFilter('clientip', '216.126.255.31'); const editorValue = await monacoEditor.getCodeEditorValue(); expect(editorValue).to.eql( - `from logstash-* [METADATA _index, _id] | sort @timestamp desc | limit 500\n| WHERE \`clientip\`::string=="216.126.255.31"` + `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500\n| WHERE \`clientip\`::string=="216.126.255.31"` ); await unifiedFieldList.closeFieldPopover(); @@ -234,7 +234,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.clickFieldListExistsFilter('@timestamp'); const editorValue = await monacoEditor.getCodeEditorValue(); expect(editorValue).to.eql( - `from logstash-* [METADATA _index, _id] | sort @timestamp desc | limit 500\n| WHERE \`@timestamp\` is not null` + `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500\n| WHERE \`@timestamp\` is not null` ); await testSubjects.missingOrFail('dscFieldStats-statsFooter'); await unifiedFieldList.closeFieldPopover(); @@ -269,7 +269,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.clickFieldListPlusFilter('extension', 'css'); const editorValue = await monacoEditor.getCodeEditorValue(); expect(editorValue).to.eql( - `from logstash-* [METADATA _index, _id] | sort @timestamp desc | limit 500\n| WHERE \`extension\`=="css"` + `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500\n| WHERE \`extension\`=="css"` ); await unifiedFieldList.closeFieldPopover(); diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index 29b88787e7ec2..71a4d05aecdb0 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -9,6 +9,7 @@ import { Key } from 'selenium-webdriver'; import { asyncForEach } from '@kbn/std'; +import expect from '@kbn/expect'; import { FtrService } from '../ftr_provider_context'; export class ConsolePageObject extends FtrService { @@ -368,10 +369,12 @@ export class ConsolePageObject extends FtrService { public async setFontSizeSetting(newSize: number) { // while the settings form opens/loads this may fail, so retry for a while await this.retry.try(async () => { + const newSizeString = String(newSize); const fontSizeInput = await this.testSubjects.find('setting-font-size-input'); await fontSizeInput.clearValue({ withJS: true }); await fontSizeInput.click(); - await fontSizeInput.type(String(newSize)); + await fontSizeInput.type(newSizeString); + expect(await fontSizeInput.getAttribute('value')).to.be(newSizeString); }); } diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index ab6356075fd81..979e4341931ab 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -164,6 +164,7 @@ export class DiscoverPageObject extends FtrService { public async clickNewSearchButton() { await this.testSubjects.click('discoverNewButton'); + await this.testSubjects.moveMouseTo('unifiedFieldListSidebar__toggle-collapse'); // cancel tooltips await this.header.waitUntilLoadingHasFinished(); } diff --git a/tsconfig.base.json b/tsconfig.base.json index 4471cb1bc6754..727cb930bc606 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1044,6 +1044,8 @@ "@kbn/index-patterns-test-plugin/*": ["test/plugin_functional/plugins/index_patterns/*"], "@kbn/inference_integration_flyout": ["x-pack/packages/ml/inference_integration_flyout"], "@kbn/inference_integration_flyout/*": ["x-pack/packages/ml/inference_integration_flyout/*"], + "@kbn/inference-common": ["x-pack/packages/ai-infra/inference-common"], + "@kbn/inference-common/*": ["x-pack/packages/ai-infra/inference-common/*"], "@kbn/inference-plugin": ["x-pack/plugins/inference"], "@kbn/inference-plugin/*": ["x-pack/plugins/inference/*"], "@kbn/infra-forge": ["x-pack/packages/kbn-infra-forge"], diff --git a/x-pack/packages/ai-infra/inference-common/README.md b/x-pack/packages/ai-infra/inference-common/README.md new file mode 100644 index 0000000000000..f16f1ce9cea75 --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/README.md @@ -0,0 +1,7 @@ +# @kbn/inference-common + +Common types and utilities for the inference APIs and features. + +The main purpose of the package is to have a clean line between the inference plugin's +implementation and the underlying types, so that other packages or plugins can leverage the +types without directly depending on the plugin. diff --git a/x-pack/packages/ai-infra/inference-common/index.ts b/x-pack/packages/ai-infra/inference-common/index.ts new file mode 100644 index 0000000000000..6de7ce3bb8008 --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/index.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { + MessageRole, + ChatCompletionEventType, + ToolChoiceType, + type Message, + type AssistantMessage, + type ToolMessage, + type UserMessage, + type ToolSchemaType, + type FromToolSchema, + type ToolSchema, + type UnvalidatedToolCall, + type ToolCallsOf, + type ToolCall, + type ToolDefinition, + type ToolOptions, + type FunctionCallingMode, + type ToolChoice, + type ChatCompleteAPI, + type ChatCompleteOptions, + type ChatCompletionResponse, + type ChatCompletionTokenCountEvent, + type ChatCompletionEvent, + type ChatCompletionChunkEvent, + type ChatCompletionChunkToolCall, + type ChatCompletionMessageEvent, + withoutTokenCountEvents, + withoutChunkEvents, + isChatCompletionMessageEvent, + isChatCompletionEvent, + isChatCompletionChunkEvent, + isChatCompletionTokenCountEvent, + ChatCompletionErrorCode, + type ChatCompletionToolNotFoundError, + type ChatCompletionToolValidationError, + type ChatCompletionTokenLimitReachedError, + isToolValidationError, + isTokenLimitReachedError, + isToolNotFoundError, +} from './src/chat_complete'; +export { + OutputEventType, + type OutputAPI, + type OutputResponse, + type OutputCompleteEvent, + type OutputUpdateEvent, + type Output, + type OutputEvent, + isOutputCompleteEvent, + isOutputUpdateEvent, + isOutputEvent, + withoutOutputUpdateEvents, +} from './src/output'; +export { + InferenceTaskEventType, + type InferenceTaskEvent, + type InferenceTaskEventBase, +} from './src/inference_task'; +export { + InferenceTaskError, + InferenceTaskErrorCode, + type InferenceTaskErrorEvent, + type InferenceTaskInternalError, + type InferenceTaskRequestError, + createInferenceInternalError, + createInferenceRequestError, + isInferenceError, + isInferenceInternalError, + isInferenceRequestError, +} from './src/errors'; diff --git a/x-pack/packages/ai-infra/inference-common/jest.config.js b/x-pack/packages/ai-infra/inference-common/jest.config.js new file mode 100644 index 0000000000000..faa0d30b40233 --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/jest.config.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/x-pack/packages/ai-infra/inference-common'], +}; diff --git a/x-pack/packages/ai-infra/inference-common/kibana.jsonc b/x-pack/packages/ai-infra/inference-common/kibana.jsonc new file mode 100644 index 0000000000000..568755d303c3b --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/inference-common", + "owner": "@elastic/appex-ai-infra" +} diff --git a/x-pack/packages/ai-infra/inference-common/package.json b/x-pack/packages/ai-infra/inference-common/package.json new file mode 100644 index 0000000000000..0c67ca7815f16 --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/inference-common", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0", + "sideEffects": false +} diff --git a/x-pack/packages/ai-infra/inference-common/src/chat_complete/api.ts b/x-pack/packages/ai-infra/inference-common/src/chat_complete/api.ts new file mode 100644 index 0000000000000..c6ffa9d4c8d5d --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/src/chat_complete/api.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Observable } from 'rxjs'; +import type { ToolOptions } from './tools'; +import type { Message } from './messages'; +import type { ChatCompletionEvent } from './events'; + +/** + * Request a completion from the LLM based on a prompt or conversation. + * + * @example using the API to get an event observable. + * ```ts + * const events$ = chatComplete({ + * connectorId: 'my-connector', + * system: "You are a helpful assistant", + * messages: [ + * { role: MessageRole.User, content: "First question?"}, + * { role: MessageRole.Assistant, content: "Some answer"}, + * { role: MessageRole.User, content: "Another question?"}, + * ] + * }); + */ +export type ChatCompleteAPI = ( + options: ChatCompleteOptions +) => ChatCompletionResponse; + +/** + * Options used to call the {@link ChatCompleteAPI} + */ +export type ChatCompleteOptions = { + /** + * The ID of the connector to use. + * Must be a genAI compatible connector, or an error will be thrown. + */ + connectorId: string; + /** + * Optional system message for the LLM. + */ + system?: string; + /** + * The list of messages for the current conversation + */ + messages: Message[]; + /** + * Function calling mode, defaults to "native". + */ + functionCalling?: FunctionCallingMode; +} & TToolOptions; + +/** + * Response from the {@link ChatCompleteAPI}. + * + * Observable of {@link ChatCompletionEvent} + */ +export type ChatCompletionResponse = Observable< + ChatCompletionEvent +>; + +/** + * Define the function calling mode when using inference APIs. + * - native will use the LLM's native function calling (requires the LLM to have native support) + * - simulated: will emulate function calling with function calling instructions + */ +export type FunctionCallingMode = 'native' | 'simulated'; diff --git a/x-pack/plugins/inference/common/chat_complete/errors.ts b/x-pack/packages/ai-infra/inference-common/src/chat_complete/errors.ts similarity index 61% rename from x-pack/plugins/inference/common/chat_complete/errors.ts rename to x-pack/packages/ai-infra/inference-common/src/chat_complete/errors.ts index 8497350d7b49b..b9d859a666761 100644 --- a/x-pack/plugins/inference/common/chat_complete/errors.ts +++ b/x-pack/packages/ai-infra/inference-common/src/chat_complete/errors.ts @@ -5,16 +5,22 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; import { InferenceTaskError } from '../errors'; import type { UnvalidatedToolCall } from './tools'; +/** + * List of code of error that are specific to the {@link ChatCompleteAPI} + */ export enum ChatCompletionErrorCode { TokenLimitReachedError = 'tokenLimitReachedError', ToolNotFoundError = 'toolNotFoundError', ToolValidationError = 'toolValidationError', } +/** + * Error thrown if the completion call fails because of a token limit + * error, e.g. when the context window is higher than the limit + */ export type ChatCompletionTokenLimitReachedError = InferenceTaskError< ChatCompletionErrorCode.TokenLimitReachedError, { @@ -23,13 +29,24 @@ export type ChatCompletionTokenLimitReachedError = InferenceTaskError< } >; +/** + * Error thrown if the LLM called a tool that was not provided + * in the list of available tools. + */ export type ChatCompletionToolNotFoundError = InferenceTaskError< ChatCompletionErrorCode.ToolNotFoundError, { + /** The name of the tool that got called */ name: string; } >; +/** + * Error thrown when the LLM called a tool with parameters that + * don't match the tool's schema. + * + * The level of details on the error vary depending on the underlying LLM. + */ export type ChatCompletionToolValidationError = InferenceTaskError< ChatCompletionErrorCode.ToolValidationError, { @@ -40,42 +57,9 @@ export type ChatCompletionToolValidationError = InferenceTaskError< } >; -export function createTokenLimitReachedError( - tokenLimit?: number, - tokenCount?: number -): ChatCompletionTokenLimitReachedError { - return new InferenceTaskError( - ChatCompletionErrorCode.TokenLimitReachedError, - i18n.translate('xpack.inference.chatCompletionError.tokenLimitReachedError', { - defaultMessage: `Token limit reached. Token limit is {tokenLimit}, but the current conversation has {tokenCount} tokens.`, - values: { tokenLimit, tokenCount }, - }), - { tokenLimit, tokenCount } - ); -} - -export function createToolNotFoundError(name: string): ChatCompletionToolNotFoundError { - return new InferenceTaskError( - ChatCompletionErrorCode.ToolNotFoundError, - `Tool ${name} called but was not available`, - { - name, - } - ); -} - -export function createToolValidationError( - message: string, - meta: { - name?: string; - arguments?: string; - errorsText?: string; - toolCalls?: UnvalidatedToolCall[]; - } -): ChatCompletionToolValidationError { - return new InferenceTaskError(ChatCompletionErrorCode.ToolValidationError, message, meta); -} - +/** + * Check if an error is a {@link ChatCompletionToolValidationError} + */ export function isToolValidationError(error?: Error): error is ChatCompletionToolValidationError { return ( error instanceof InferenceTaskError && @@ -83,6 +67,9 @@ export function isToolValidationError(error?: Error): error is ChatCompletionToo ); } +/** + * Check if an error is a {@link ChatCompletionTokenLimitReachedError} + */ export function isTokenLimitReachedError( error: Error ): error is ChatCompletionTokenLimitReachedError { @@ -92,6 +79,9 @@ export function isTokenLimitReachedError( ); } +/** + * Check if an error is a {@link ChatCompletionToolNotFoundError} + */ export function isToolNotFoundError(error: Error): error is ChatCompletionToolNotFoundError { return ( error instanceof InferenceTaskError && error.code === ChatCompletionErrorCode.ToolNotFoundError diff --git a/x-pack/packages/ai-infra/inference-common/src/chat_complete/event_utils.ts b/x-pack/packages/ai-infra/inference-common/src/chat_complete/event_utils.ts new file mode 100644 index 0000000000000..4749673264aff --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/src/chat_complete/event_utils.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { filter, OperatorFunction } from 'rxjs'; +import { InferenceTaskEvent } from '../inference_task'; +import { + ChatCompletionEventType, + ChatCompletionEvent, + ChatCompletionChunkEvent, + ChatCompletionMessageEvent, + ChatCompletionTokenCountEvent, +} from './events'; +import type { ToolOptions } from './tools'; + +/** + * Check if the provided {@link ChatCompletionEvent} is a {@link ChatCompletionChunkEvent} + */ +export function isChatCompletionChunkEvent( + event: ChatCompletionEvent +): event is ChatCompletionChunkEvent { + return event.type === ChatCompletionEventType.ChatCompletionChunk; +} + +/** + * Check if the provided {@link ChatCompletionEvent} is a {@link ChatCompletionMessageEvent} + */ +export function isChatCompletionMessageEvent( + event: ChatCompletionEvent +): event is ChatCompletionMessageEvent { + return event.type === ChatCompletionEventType.ChatCompletionMessage; +} + +/** + * Check if the provided {@link ChatCompletionEvent} is a {@link ChatCompletionMessageEvent} + */ +export function isChatCompletionTokenCountEvent( + event: ChatCompletionEvent +): event is ChatCompletionTokenCountEvent { + return event.type === ChatCompletionEventType.ChatCompletionTokenCount; +} + +/** + * Check if the provided {@link InferenceTaskEvent} is a {@link ChatCompletionEvent} + */ +export function isChatCompletionEvent(event: InferenceTaskEvent): event is ChatCompletionEvent { + return ( + event.type === ChatCompletionEventType.ChatCompletionChunk || + event.type === ChatCompletionEventType.ChatCompletionMessage || + event.type === ChatCompletionEventType.ChatCompletionTokenCount + ); +} + +/** + * Operator filtering out the chunk events from the provided observable. + */ +export function withoutChunkEvents(): OperatorFunction< + T, + Exclude +> { + return filter( + (event): event is Exclude => + event.type !== ChatCompletionEventType.ChatCompletionChunk + ); +} + +/** + * Operator filtering out the token count events from the provided observable. + */ +export function withoutTokenCountEvents(): OperatorFunction< + T, + Exclude +> { + return filter( + (event): event is Exclude => + event.type !== ChatCompletionEventType.ChatCompletionTokenCount + ); +} diff --git a/x-pack/packages/ai-infra/inference-common/src/chat_complete/events.ts b/x-pack/packages/ai-infra/inference-common/src/chat_complete/events.ts new file mode 100644 index 0000000000000..92c49e6ee7fc0 --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/src/chat_complete/events.ts @@ -0,0 +1,118 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { InferenceTaskEventBase } from '../inference_task'; +import type { ToolCallsOf, ToolOptions } from './tools'; + +/** + * List possible values of {@link ChatCompletionEvent} types. + */ +export enum ChatCompletionEventType { + ChatCompletionChunk = 'chatCompletionChunk', + ChatCompletionTokenCount = 'chatCompletionTokenCount', + ChatCompletionMessage = 'chatCompletionMessage', +} + +/** + * Message event, sent only once, after all the chunks were emitted, and containing + * the whole text content and potential tool calls of the response. + */ +export type ChatCompletionMessageEvent = + InferenceTaskEventBase & { + /** + * The text content of the LLM response. + */ + content: string; + /** + * The eventual tool calls performed by the LLM. + */ + toolCalls: ToolCallsOf['toolCalls']; + }; + +/** + * Represent a partial tool call present in a chunk event. + * + * Note that all properties of the structure, except from the index, + * are partial and must be aggregated. + */ +export interface ChatCompletionChunkToolCall { + /** + * The tool call index (position in the tool call array). + */ + index: number; + /** + * chunk of tool call id. + */ + toolCallId: string; + function: { + /** + * chunk of tool name. + */ + name: string; + /** + * chunk of tool call arguments. + */ + arguments: string; + }; +} + +/** + * Chunk event, containing a fragment of the total content, + * and potentially chunks of tool calls. + */ +export type ChatCompletionChunkEvent = + InferenceTaskEventBase & { + /** + * The content chunk + */ + content: string; + /** + * The tool call chunks + */ + tool_calls: ChatCompletionChunkToolCall[]; + }; + +/** + * Token count event, send only once, usually (but not necessarily) + * before the message event + */ +export type ChatCompletionTokenCountEvent = + InferenceTaskEventBase & { + tokens: { + /** + * Input token count + */ + prompt: number; + /** + * Output token count + */ + completion: number; + /** + * Total token count + */ + total: number; + }; + }; + +/** + * Events emitted from the {@link ChatCompletionResponse} observable + * returned from the {@link ChatCompleteAPI}. + * + * The chatComplete API returns 3 type of events: + * - {@link ChatCompletionChunkEvent}: message chunk events + * - {@link ChatCompletionTokenCountEvent}: token count event + * - {@link ChatCompletionMessageEvent}: message event + * + * Note that chunk events can be emitted any amount of times, but token count will be emitted + * at most once (could not be emitted depending on the underlying connector), and message + * event will be emitted ex + * + */ +export type ChatCompletionEvent = + | ChatCompletionChunkEvent + | ChatCompletionTokenCountEvent + | ChatCompletionMessageEvent; diff --git a/x-pack/packages/ai-infra/inference-common/src/chat_complete/index.ts b/x-pack/packages/ai-infra/inference-common/src/chat_complete/index.ts new file mode 100644 index 0000000000000..8199af4cf068b --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/src/chat_complete/index.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + ChatCompletionResponse, + ChatCompleteAPI, + ChatCompleteOptions, + FunctionCallingMode, +} from './api'; +export { + ChatCompletionEventType, + type ChatCompletionMessageEvent, + type ChatCompletionChunkEvent, + type ChatCompletionEvent, + type ChatCompletionChunkToolCall, + type ChatCompletionTokenCountEvent, +} from './events'; +export { + MessageRole, + type Message, + type AssistantMessage, + type UserMessage, + type ToolMessage, +} from './messages'; +export { type ToolSchema, type ToolSchemaType, type FromToolSchema } from './tool_schema'; +export { + ToolChoiceType, + type ToolOptions, + type ToolDefinition, + type ToolCall, + type ToolCallsOf, + type UnvalidatedToolCall, + type ToolChoice, +} from './tools'; +export { + isChatCompletionChunkEvent, + isChatCompletionEvent, + isChatCompletionMessageEvent, + isChatCompletionTokenCountEvent, + withoutChunkEvents, + withoutTokenCountEvents, +} from './event_utils'; +export { + ChatCompletionErrorCode, + type ChatCompletionToolNotFoundError, + type ChatCompletionToolValidationError, + type ChatCompletionTokenLimitReachedError, + isToolValidationError, + isTokenLimitReachedError, + isToolNotFoundError, +} from './errors'; diff --git a/x-pack/packages/ai-infra/inference-common/src/chat_complete/messages.ts b/x-pack/packages/ai-infra/inference-common/src/chat_complete/messages.ts new file mode 100644 index 0000000000000..ca74b094e0a3b --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/src/chat_complete/messages.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ToolCall } from './tools'; + +/** + * Enum for all possible {@link Message} roles. + */ +export enum MessageRole { + User = 'user', + Assistant = 'assistant', + Tool = 'tool', +} + +/** + * Base type for all subtypes of {@link Message}. + */ +interface MessageBase { + role: TRole; +} + +/** + * Represents a message from the user. + */ +export type UserMessage = MessageBase & { + /** + * The text content of the user message + */ + content: string; +}; + +/** + * Represents a message from the LLM. + */ +export type AssistantMessage = MessageBase & { + /** + * The text content of the message. + * Can be null if the LLM called a tool. + */ + content: string | null; + /** + * A potential list of {@ToolCall} the LLM asked to execute. + * Note that LLM with parallel tool invocation can potentially call multiple tools at the same time. + */ + toolCalls?: ToolCall[]; +}; + +/** + * Represents a tool invocation result, following a request from the LLM to execute a tool. + */ +export type ToolMessage | unknown> = + MessageBase & { + /** + * The call id matching the {@link ToolCall} this tool message is for. + */ + toolCallId: string; + /** + * The response from the tool invocation. + */ + response: TToolResponse; + }; + +/** + * Mixin composed of all the possible types of messages in a chatComplete discussion. + * + * Message can be of three types: + * - {@link UserMessage} + * - {@link AssistantMessage} + * - {@link ToolMessage} + */ +export type Message = UserMessage | AssistantMessage | ToolMessage; diff --git a/x-pack/plugins/inference/common/chat_complete/tool_schema.ts b/x-pack/packages/ai-infra/inference-common/src/chat_complete/tool_schema.ts similarity index 95% rename from x-pack/plugins/inference/common/chat_complete/tool_schema.ts rename to x-pack/packages/ai-infra/inference-common/src/chat_complete/tool_schema.ts index 2a2c61f8e9b70..bb4742c6b74d9 100644 --- a/x-pack/plugins/inference/common/chat_complete/tool_schema.ts +++ b/x-pack/packages/ai-infra/inference-common/src/chat_complete/tool_schema.ts @@ -72,8 +72,14 @@ type FromToolSchemaString = ? ValuesType : string; +/** + * Defines the schema for a {@link ToolDefinition} + */ export type ToolSchema = ToolSchemaTypeObject; +/** + * Utility type to infer the shape of a tool call from its schema. + */ export type FromToolSchema = TToolSchema extends ToolSchemaTypeObject ? FromToolSchemaObject diff --git a/x-pack/plugins/inference/common/chat_complete/tools.ts b/x-pack/packages/ai-infra/inference-common/src/chat_complete/tools.ts similarity index 53% rename from x-pack/plugins/inference/common/chat_complete/tools.ts rename to x-pack/packages/ai-infra/inference-common/src/chat_complete/tools.ts index a5db86c7c996d..0c7d5c6755f31 100644 --- a/x-pack/plugins/inference/common/chat_complete/tools.ts +++ b/x-pack/packages/ai-infra/inference-common/src/chat_complete/tools.ts @@ -4,15 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import type { ValuesType } from 'utility-types'; import { FromToolSchema, ToolSchema } from './tool_schema'; type Assert = TValue extends TType ? TValue & TType : never; -interface CustomToolChoice { - function: TName; -} - type ToolsOfChoice = TToolOptions['toolChoice'] extends { function: infer TToolName; } @@ -21,6 +18,9 @@ type ToolsOfChoice = TToolOptions['toolChoice' : TToolOptions['tools'] : TToolOptions['tools']; +/** + * Utility type to infer the tool calls response shape. + */ type ToolResponsesOf | undefined> = TTools extends Record ? Array< @@ -30,18 +30,64 @@ type ToolResponsesOf | undefined> > : never[]; +/** + * Utility type to infer the tool call response shape. + */ type ToolResponseOf = ToolCall< TName, TToolDefinition extends { schema: ToolSchema } ? FromToolSchema : {} >; +/** + * Tool invocation choice type. + * + * Refer to {@link ToolChoice} for more details. + */ +export enum ToolChoiceType { + none = 'none', + auto = 'auto', + required = 'required', +} + +/** + * Represent a tool choice where the LLM is forced to call a specific tool. + * + * Refer to {@link ToolChoice} for more details. + */ +interface CustomToolChoice { + function: TName; +} + +/** + * Defines the tool invocation for {@link ToolOptions}, either a {@link ToolChoiceType} or {@link CustomToolChoice}. + * - {@link ToolChoiceType.none}: the LLM will never call a tool + * - {@link ToolChoiceType.auto}: the LLM will decide if it should call a tool or provide a text response + * - {@link ToolChoiceType.required}: the LLM will always call a tool, but will decide with one to call + * - {@link CustomToolChoice}: the LLM will always call the specified tool + */ export type ToolChoice = ToolChoiceType | CustomToolChoice; +/** + * The definition of a tool that will be provided to the LLM for it to eventually call. + */ export interface ToolDefinition { + /** + * A description of what the tool does. Note that this will be exposed to the LLM, + * so the description should be explicit about what the tool does and when to call it. + */ description: string; + /** + * The input schema for the tool, representing the shape of the tool's parameters + * + * Even if optional, it is highly recommended to define a schema for all tool definitions, unless + * the tool is supposed to be called without parameters. + */ schema?: ToolSchema; } +/** + * Utility type to infer the toolCall type of {@link ChatCompletionMessageEvent}. + */ export type ToolCallsOf = TToolOptions extends { tools?: Record; } @@ -52,12 +98,11 @@ export type ToolCallsOf = TToolOptions extends } : { toolCalls: never }; -export enum ToolChoiceType { - none = 'none', - auto = 'auto', - required = 'required', -} - +/** + * Represents a tool call from the LLM before correctly converted to the schema type. + * + * Only publicly exposed because referenced by {@link ChatCompletionToolValidationError} + */ export interface UnvalidatedToolCall { toolCallId: string; function: { @@ -66,17 +111,39 @@ export interface UnvalidatedToolCall { }; } +/** + * Represents a tool call performed by the LLM. + */ export interface ToolCall< TName extends string = string, TArguments extends Record | undefined = Record | undefined > { + /** + * The id of the tool call, that must be re-used when providing the tool call response + */ toolCallId: string; function: { + /** + * The name of the tool that was called + */ name: TName; } & (TArguments extends Record ? { arguments: TArguments } : {}); } +/** + * Tool-related parameters of {@link ChatCompleteAPI} + */ export interface ToolOptions { + /** + * The choice of tool execution. + * + * Refer to {@link ToolChoice} + */ toolChoice?: ToolChoice; + /** + * The list of tool definitions that will be exposed to the LLM. + * + * Refer to {@link ToolDefinition}. + */ tools?: Record; } diff --git a/x-pack/plugins/inference/common/errors.ts b/x-pack/packages/ai-infra/inference-common/src/errors.ts similarity index 93% rename from x-pack/plugins/inference/common/errors.ts rename to x-pack/packages/ai-infra/inference-common/src/errors.ts index e8bcd4cf60aaf..5a99adc4321d9 100644 --- a/x-pack/plugins/inference/common/errors.ts +++ b/x-pack/packages/ai-infra/inference-common/src/errors.ts @@ -4,14 +4,20 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { i18n } from '@kbn/i18n'; + import { InferenceTaskEventBase, InferenceTaskEventType } from './inference_task'; +/** + * Enum for generic inference error codes. + */ export enum InferenceTaskErrorCode { internalError = 'internalError', requestError = 'requestError', } +/** + * Base class for all inference API errors. + */ export class InferenceTaskError< TCode extends string, TMeta extends Record | undefined @@ -51,9 +57,7 @@ export type InferenceTaskRequestError = InferenceTaskError< >; export function createInferenceInternalError( - message: string = i18n.translate('xpack.inference.internalError', { - defaultMessage: 'An internal error occurred', - }), + message = 'An internal error occurred', meta?: Record ): InferenceTaskInternalError { return new InferenceTaskError(InferenceTaskErrorCode.internalError, message, meta ?? {}); diff --git a/x-pack/plugins/inference/common/inference_task.ts b/x-pack/packages/ai-infra/inference-common/src/inference_task.ts similarity index 81% rename from x-pack/plugins/inference/common/inference_task.ts rename to x-pack/packages/ai-infra/inference-common/src/inference_task.ts index 7b8f65b7af2c9..15449e1275a5b 100644 --- a/x-pack/plugins/inference/common/inference_task.ts +++ b/x-pack/packages/ai-infra/inference-common/src/inference_task.ts @@ -5,7 +5,13 @@ * 2.0. */ +/** + * Base interface for all inference events. + */ export interface InferenceTaskEventBase { + /** + * Unique identifier of the event type. + */ type: TEventType; } diff --git a/x-pack/packages/ai-infra/inference-common/src/output/api.ts b/x-pack/packages/ai-infra/inference-common/src/output/api.ts new file mode 100644 index 0000000000000..677d2f7015c2a --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/src/output/api.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Observable } from 'rxjs'; +import type { Message, FunctionCallingMode, FromToolSchema, ToolSchema } from '../chat_complete'; +import type { OutputEvent } from './events'; + +/** + * Generate a response with the LLM for a prompt, optionally based on a schema. + * + * @param {string} id The id of the operation + * @param {string} options.connectorId The ID of the connector that is to be used. + * @param {string} options.input The prompt for the LLM. + * @param {string} options.messages Previous messages in a conversation. + * @param {ToolSchema} [options.schema] The schema the response from the LLM should adhere to. + */ +export type OutputAPI = < + TId extends string = string, + TOutputSchema extends ToolSchema | undefined = ToolSchema | undefined +>( + id: TId, + options: { + connectorId: string; + system?: string; + input: string; + schema?: TOutputSchema; + previousMessages?: Message[]; + functionCalling?: FunctionCallingMode; + } +) => OutputResponse; + +/** + * Response from the {@link OutputAPI}. + * + * Observable of {@link OutputEvent} + */ +export type OutputResponse< + TId extends string = string, + TOutputSchema extends ToolSchema | undefined = ToolSchema | undefined +> = Observable< + OutputEvent : undefined> +>; diff --git a/x-pack/packages/ai-infra/inference-common/src/output/event_utils.ts b/x-pack/packages/ai-infra/inference-common/src/output/event_utils.ts new file mode 100644 index 0000000000000..1139bac92c610 --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/src/output/event_utils.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { filter, OperatorFunction } from 'rxjs'; +import { OutputCompleteEvent, OutputEvent, OutputEventType, OutputUpdateEvent } from '.'; +import type { InferenceTaskEvent } from '../inference_task'; + +/** + * Check if the provided {@link ChatCompletionEvent} is a {@link ChatCompletionChunkEvent} + */ +export function isOutputCompleteEvent( + event: TOutputEvent +): event is Extract { + return event.type === OutputEventType.OutputComplete; +} + +/** + * Check if the provided {@link InferenceTaskEvent} is a {@link OutputEvent} + */ +export function isOutputEvent(event: InferenceTaskEvent): event is OutputEvent { + return ( + event.type === OutputEventType.OutputComplete || event.type === OutputEventType.OutputUpdate + ); +} + +/** + * Check if the provided {@link OutputEvent} is a {@link OutputUpdateEvent} + */ +export function isOutputUpdateEvent( + event: OutputEvent +): event is OutputUpdateEvent { + return event.type === OutputEventType.OutputComplete; +} + +/** + * Operator filtering out the update events from the provided observable. + */ +export function withoutOutputUpdateEvents(): OperatorFunction< + T, + Exclude +> { + return filter( + (event): event is Exclude => event.type !== OutputEventType.OutputUpdate + ); +} diff --git a/x-pack/packages/ai-infra/inference-common/src/output/events.ts b/x-pack/packages/ai-infra/inference-common/src/output/events.ts new file mode 100644 index 0000000000000..794f58bd7db79 --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/src/output/events.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { InferenceTaskEventBase } from '../inference_task'; + +/** + * List possible values of {@link OutputEvent} types. + */ +export enum OutputEventType { + OutputUpdate = 'output', + OutputComplete = 'complete', +} + +/** + * Task output of a {@link OutputCompleteEvent} + */ +export type Output = Record | undefined | unknown; + +/** + * Update (chunk) event for the {@link OutputAPI} + */ +export type OutputUpdateEvent = + InferenceTaskEventBase & { + /** + * The id of the operation, as provided as input + */ + id: TId; + /** + * The text content of the chunk + */ + content: string; + }; + +/** + * Completion (complete message) event for the {@link OutputAPI} + */ +export type OutputCompleteEvent< + TId extends string = string, + TOutput extends Output = Output +> = InferenceTaskEventBase & { + /** + * The id of the operation, as provided as input + */ + id: TId; + /** + * The task output, following the schema specified as input + */ + output: TOutput; + /** + * Potential text content provided by the LLM, + * if it was provided in addition to the tool call + */ + content: string; +}; + +/** + * Events emitted from the {@link OutputEvent}. + */ +export type OutputEvent = + | OutputUpdateEvent + | OutputCompleteEvent; diff --git a/x-pack/packages/ai-infra/inference-common/src/output/index.ts b/x-pack/packages/ai-infra/inference-common/src/output/index.ts new file mode 100644 index 0000000000000..ceac178f47faa --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/src/output/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { OutputAPI, OutputResponse } from './api'; +export { + OutputEventType, + type OutputCompleteEvent, + type OutputUpdateEvent, + type Output, + type OutputEvent, +} from './events'; +export { + isOutputCompleteEvent, + isOutputUpdateEvent, + isOutputEvent, + withoutOutputUpdateEvents, +} from './event_utils'; diff --git a/x-pack/packages/ai-infra/inference-common/tsconfig.json b/x-pack/packages/ai-infra/inference-common/tsconfig.json new file mode 100644 index 0000000000000..86d57b8d692f7 --- /dev/null +++ b/x-pack/packages/ai-infra/inference-common/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + ] +} diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx index 1343f5ed9a4bb..320beb1ca6b05 100644 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx @@ -47,6 +47,7 @@ export function ChatFlyout({ isOpen, onClose, navigateToConversation, + hideConversationList, }: { initialTitle: string; initialMessages: Message[]; @@ -54,6 +55,7 @@ export function ChatFlyout({ isOpen: boolean; onClose: () => void; navigateToConversation?: (conversationId?: string) => void; + hideConversationList?: boolean; }) { const { euiTheme } = useEuiTheme(); const breakpoint = useCurrentEuiBreakpoint(); @@ -174,84 +176,86 @@ export function ChatFlyout({ }} > - - - setConversationsExpanded(!conversationsExpanded)} - /> - - } - /> - - {conversationsExpanded ? ( - { - conversationList.deleteConversation(deletedConversationId).then(() => { - if (deletedConversationId === conversationId) { - setConversationId(undefined); - } - }); - }} - onConversationSelect={(nextConversationId) => { - setConversationId(nextConversationId); - }} - /> - ) : ( + {!hideConversationList ? ( + - { - setConversationId(undefined); - }} + className={expandButtonClassName} + color="text" + data-test-subj="observabilityAiAssistantChatFlyoutButton" + iconType={conversationsExpanded ? 'transitionLeftIn' : 'transitionLeftOut'} + onClick={() => setConversationsExpanded(!conversationsExpanded)} /> } - className={newChatButtonClassName} /> - )} - + + {conversationsExpanded ? ( + { + conversationList.deleteConversation(deletedConversationId).then(() => { + if (deletedConversationId === conversationId) { + setConversationId(undefined); + } + }); + }} + onConversationSelect={(nextConversationId) => { + setConversationId(nextConversationId); + }} + /> + ) : ( + + { + setConversationId(undefined); + }} + /> + + } + className={newChatButtonClassName} + /> + )} + + ) : null} (null); const [mode, setMode] = useState<'prompt' | 'function'>( @@ -121,16 +123,15 @@ export function PromptEditor({ setInnerMessage(undefined); setMode('prompt'); - onSendTelemetry({ type: ObservabilityAIAssistantTelemetryEventType.UserSentPromptInChat, - payload: message, + payload: { ...message, scopes }, }); } catch (_) { setInnerMessage(oldMessage); setMode(oldMessage.function_call?.name ? 'function' : 'prompt'); } - }, [addLastUsedPrompt, innerMessage, loading, onSendTelemetry, onSubmit]); + }, [addLastUsedPrompt, innerMessage, loading, onSendTelemetry, onSubmit, scopes]); // Submit on Enter useEffect(() => { diff --git a/x-pack/packages/kbn-ai-assistant/src/prompt_editor/prompt_editor_natural_language.tsx b/x-pack/packages/kbn-ai-assistant/src/prompt_editor/prompt_editor_natural_language.tsx index 0b84b504d9507..bdef8c5e3a079 100644 --- a/x-pack/packages/kbn-ai-assistant/src/prompt_editor/prompt_editor_natural_language.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/prompt_editor/prompt_editor_natural_language.tsx @@ -109,6 +109,15 @@ export function PromptEditorNaturalLanguage({ } }, [handleResizeTextArea, prompt]); + useEffect(() => { + // Attach the event listener to the window to catch mouseup outside the browser window + window.addEventListener('mouseup', handleResizeTextArea); + + return () => { + window.removeEventListener('mouseup', handleResizeTextArea); + }; + }, [handleResizeTextArea]); + return ( { + const { services } = useKibana(); + + const getNavUrlParams = useCallback( + ( + filterParams: NavFilter = {}, + findingsType?: 'configurations' | 'vulnerabilities', + groupBy?: string[] + ) => { + const filters = composeQueryFilters(filterParams); + + const searchParams = new URLSearchParams(encodeQueryUrl(services.data, filters, groupBy)); + + return `${findingsType ? findingsType : ''}?${searchParams.toString()}`; + }, + [services.data] + ); + + return getNavUrlParams; +}; diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_navigate_findings.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_navigate_findings.ts index 454c9a0056a58..00610d6b64b4e 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_navigate_findings.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_navigate_findings.ts @@ -7,74 +7,28 @@ import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; -import { Filter } from '@kbn/es-query'; -import { - SECURITY_DEFAULT_DATA_VIEW_ID, - CDR_MISCONFIGURATIONS_DATA_VIEW_ID_PREFIX, -} from '@kbn/cloud-security-posture-common'; +import { CDR_MISCONFIGURATIONS_DATA_VIEW_ID_PREFIX } from '@kbn/cloud-security-posture-common'; import type { CoreStart } from '@kbn/core/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { findingsNavigation } from '../constants/navigation'; import { useDataView } from './use_data_view'; import { CspClientPluginStartDeps } from '../..'; -import { encodeQuery } from '../utils/query_utils'; +import { NavFilter, encodeQueryUrl, composeQueryFilters } from '../utils/query_utils'; -interface NegatedValue { - value: string | number; - negate: boolean; -} - -type FilterValue = string | number | NegatedValue; - -export type NavFilter = Record; - -const createFilter = (key: string, filterValue: FilterValue, dataViewId: string): Filter => { - let negate = false; - let value = filterValue; - if (typeof filterValue === 'object') { - negate = filterValue.negate; - value = filterValue.value; - } - // If the value is '*', we want to create an exists filter - if (value === '*') { - return { - query: { exists: { field: key } }, - meta: { type: 'exists', index: dataViewId }, - }; - } - return { - meta: { - alias: null, - negate, - disabled: false, - type: 'phrase', - key, - index: dataViewId, - }, - query: { match_phrase: { [key]: value } }, - }; -}; -const useNavigate = (pathname: string, dataViewId = SECURITY_DEFAULT_DATA_VIEW_ID) => { +const useNavigate = (pathname: string, dataViewId?: string) => { const history = useHistory(); - const { services } = useKibana(); + const { services } = useKibana(); return useCallback( (filterParams: NavFilter = {}, groupBy?: string[]) => { - const filters = Object.entries(filterParams).map(([key, filterValue]) => - createFilter(key, filterValue, dataViewId) - ); + const filters = composeQueryFilters(filterParams, dataViewId); history.push({ pathname, - search: encodeQuery({ - // Set query language from user's preference - query: services.data.query.queryString.getDefaultQuery(), - filters, - ...(groupBy && { groupBy }), - }), + search: encodeQueryUrl(services.data, filters, groupBy), }); }, - [history, pathname, services.data.query.queryString, dataViewId] + [dataViewId, history, pathname, services.data] ); }; @@ -85,3 +39,17 @@ export const useNavigateFindings = () => { export const useNavigateVulnerabilities = () => useNavigate(findingsNavigation.vulnerabilities.path); + +export const useNavigateNativeVulnerabilities = () => { + const navToVulnerabilities = useNavigateVulnerabilities(); + + return useCallback( + (filterParams: NavFilter = {}, groupBy?: string[]) => { + navToVulnerabilities( + { ...filterParams, 'data_stream.dataset': 'cloud_security_posture.vulnerabilities' }, + groupBy + ); + }, + [navToVulnerabilities] + ); +}; diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/query_utils.test.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/query_utils.test.ts new file mode 100644 index 0000000000000..1302702b54287 --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/query_utils.test.ts @@ -0,0 +1,107 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { encodeQueryUrl, composeQueryFilters } from './query_utils'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; + +const DEFAULT_DATA_VIEW_ID = 'security-solution-default'; + +describe('composeQueryFilters', () => { + it('Should return correct filters given some filterParams', () => { + const testFilterParams = { + test_field: 'test_value', + }; + const testResult = [ + { + meta: { + alias: null, + negate: false, + disabled: false, + type: 'phrase', + key: 'test_field', + index: DEFAULT_DATA_VIEW_ID, + }, + query: { match_phrase: { test_field: 'test_value' } }, + }, + ]; + expect(composeQueryFilters(testFilterParams)).toEqual(testResult); + }); + + it('Should return empty filters given empty filterParams', () => { + expect(composeQueryFilters({})).toEqual([]); + }); + + it('Should return correct filters given some filterParams and dataviewId', () => { + const testFilterParams = { + test_field: 'test_value', + }; + const testResult = [ + { + meta: { + alias: null, + negate: false, + disabled: false, + type: 'phrase', + key: 'test_field', + index: 'test-data-view', + }, + query: { match_phrase: { test_field: 'test_value' } }, + }, + ]; + expect(composeQueryFilters(testFilterParams, 'test-data-view')).toEqual(testResult); + }); +}); + +describe('encodeQueryUrl', () => { + const getServicesMock = () => ({ + data: dataPluginMock.createStartContract(), + }); + + it('Should return correct URL given empty filters', () => { + const result = 'cspq=(filters:!())'; + expect(encodeQueryUrl(getServicesMock().data, [])).toEqual(result); + }); + + it('should return correct URL given filters', () => { + const filter = [ + { + meta: { + alias: null, + negate: false, + disabled: false, + type: 'phrase', + key: 'test_field', + index: DEFAULT_DATA_VIEW_ID, + }, + query: { match_phrase: { test_field: 'test_value' } }, + }, + ]; + const result = + 'cspq=(filters:!((meta:(alias:!n,disabled:!f,index:security-solution-default,key:test_field,negate:!f,type:phrase),query:(match_phrase:(test_field:test_value)))))'; + expect(encodeQueryUrl(getServicesMock().data, filter)).toEqual(result); + }); + + it('should return correct URL given filters and group by', () => { + const filter = [ + { + meta: { + alias: null, + negate: false, + disabled: false, + type: 'phrase', + key: 'test_field', + index: DEFAULT_DATA_VIEW_ID, + }, + query: { match_phrase: { test_field: 'test_value' } }, + }, + ]; + const groupByFilter = ['filterA']; + const result = + 'cspq=(filters:!((meta:(alias:!n,disabled:!f,index:security-solution-default,key:test_field,negate:!f,type:phrase),query:(match_phrase:(test_field:test_value)))),groupBy:!(filterA))'; + expect(encodeQueryUrl(getServicesMock().data, filter, groupByFilter)).toEqual(result); + }); +}); diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/query_utils.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/query_utils.ts index 3a051456733a6..6cb5c1384e732 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/query_utils.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/query_utils.ts @@ -4,8 +4,21 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { encode, decode } from '@kbn/rison'; import type { LocationDescriptorObject } from 'history'; +import { Filter } from '@kbn/es-query'; +import { SECURITY_DEFAULT_DATA_VIEW_ID } from '@kbn/cloud-security-posture-common'; +import { DataPublicPluginStart } from '@kbn/data-plugin/public'; + +interface NegatedValue { + value: string | number; + negate: boolean; +} + +type FilterValue = string | number | NegatedValue; + +export type NavFilter = Record; const encodeRison = (v: any): string | undefined => { try { @@ -38,3 +51,52 @@ export const decodeQuery = (search?: string): Partial | un if (!risonQuery) return; return decodeRison(risonQuery); }; + +export const encodeQueryUrl = ( + servicesStart: DataPublicPluginStart, + filters: Filter[], + groupBy?: string[] +): any => { + return encodeQuery({ + query: servicesStart.query.queryString.getDefaultQuery(), + filters, + ...(groupBy && { groupBy }), + }); +}; + +// dataViewId is used to prevent FilterManager from falling back to the default in the sorcerer (logs-*) +export const composeQueryFilters = ( + filterParams: NavFilter = {}, + dataViewId = SECURITY_DEFAULT_DATA_VIEW_ID +): Filter[] => { + return Object.entries(filterParams).map(([key, filterValue]) => + createFilter(key, filterValue, dataViewId) + ); +}; + +export const createFilter = (key: string, filterValue: FilterValue, dataViewId: string): Filter => { + let negate = false; + let value = filterValue; + if (typeof filterValue === 'object') { + negate = filterValue.negate; + value = filterValue.value; + } + // If the value is '*', we want to create an exists filter + if (value === '*') { + return { + query: { exists: { field: key } }, + meta: { type: 'exists', index: dataViewId }, + }; + } + return { + meta: { + alias: null, + negate, + disabled: false, + type: 'phrase', + key, + index: dataViewId, + }, + query: { match_phrase: { [key]: value } }, + }; +}; diff --git a/x-pack/packages/kbn-cloud-security-posture/public/tsconfig.json b/x-pack/packages/kbn-cloud-security-posture/public/tsconfig.json index e7f69a99c5199..8c950553c7cde 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/tsconfig.json +++ b/x-pack/packages/kbn-cloud-security-posture/public/tsconfig.json @@ -35,5 +35,6 @@ "@kbn/ui-theme", "@kbn/i18n-react", "@kbn/rison", + "@kbn/core-lifecycle-browser", ] } diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts index c1c101fd74cd8..54c24f6ce7b8f 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts @@ -19,6 +19,6 @@ export type AssistantFeatureKey = keyof AssistantFeatures; * Default features available to the elastic assistant */ export const defaultAssistantFeatures = Object.freeze({ - assistantKnowledgeBaseByDefault: false, + assistantKnowledgeBaseByDefault: true, assistantModelEvaluation: false, }); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts index fd599f5798cdc..aad215021da81 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts @@ -81,4 +81,5 @@ export const ReadKnowledgeBaseResponse = z.object({ is_setup_in_progress: z.boolean().optional(), pipeline_exists: z.boolean().optional(), security_labs_exists: z.boolean().optional(), + user_data_exists: z.boolean().optional(), }); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml index a61e98602ab40..0e0f1e9267916 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml @@ -78,6 +78,8 @@ paths: type: boolean security_labs_exists: type: boolean + user_data_exists: + type: boolean 400: description: Generic Error content: diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_knowledge_base_entries.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_knowledge_base_entries.ts index b41119779b21d..0775ed2d27a36 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_knowledge_base_entries.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_knowledge_base_entries.ts @@ -24,6 +24,7 @@ export interface UseKnowledgeBaseEntriesParams { signal?: AbortSignal | undefined; toasts?: IToasts; enabled?: boolean; // For disabling if FF is off + isRefetching?: boolean; // For enabling polling } const defaultQuery: FindKnowledgeBaseEntriesRequestQuery = { @@ -56,6 +57,7 @@ export const useKnowledgeBaseEntries = ({ signal, toasts, enabled = false, + isRefetching = false, }: UseKnowledgeBaseEntriesParams) => useQuery( KNOWLEDGE_BASE_ENTRY_QUERY_KEY, @@ -73,6 +75,7 @@ export const useKnowledgeBaseEntries = ({ enabled, keepPreviousData: true, initialData: { page: 1, perPage: 100, total: 0, data: [] }, + refetchInterval: isRefetching ? 30000 : false, onError: (error: IHttpFetchError) => { if (error.name !== 'AbortError') { toasts?.addError(error, { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx index 80ce3d27d8dcb..83073b5770ba0 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx @@ -34,6 +34,7 @@ const statusResponse = { elser_exists: true, index_exists: true, pipeline_exists: true, + security_labs_exists: true, }; const http = { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx index 75e78f2a06948..3ae89edc2a912 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx @@ -20,6 +20,7 @@ export interface UseKnowledgeBaseStatusParams { http: HttpSetup; resource?: string; toasts?: IToasts; + enabled: boolean; } /** @@ -36,6 +37,7 @@ export const useKnowledgeBaseStatus = ({ http, resource, toasts, + enabled, }: UseKnowledgeBaseStatusParams): UseQueryResult => { return useQuery( KNOWLEDGE_BASE_STATUS_QUERY_KEY, @@ -43,8 +45,11 @@ export const useKnowledgeBaseStatus = ({ return getKnowledgeBaseStatus({ http, resource, signal }); }, { + enabled, retry: false, keepPreviousData: true, + // Polling interval for Knowledge Base setup in progress + refetchInterval: (data) => (data?.is_setup_in_progress ? 30000 : false), // Deprecated, hoist to `queryCache` w/in `QueryClient. See: https://stackoverflow.com/a/76961109 onError: (error: IHttpFetchError) => { if (error.name !== 'AbortError') { @@ -86,12 +91,12 @@ export const useInvalidateKnowledgeBaseStatus = () => { * * @param kbStatus ReadKnowledgeBaseResponse */ -export const isKnowledgeBaseSetup = (kbStatus: ReadKnowledgeBaseResponse | undefined): boolean => { - return ( - (kbStatus?.elser_exists && - kbStatus?.security_labs_exists && - kbStatus?.index_exists && - kbStatus?.pipeline_exists) ?? - false - ); -}; +export const isKnowledgeBaseSetup = (kbStatus: ReadKnowledgeBaseResponse | undefined): boolean => + (kbStatus?.elser_exists && + kbStatus?.index_exists && + kbStatus?.pipeline_exists && + // Allows to use UI while importing Security Labs docs + (kbStatus?.security_labs_exists || + kbStatus?.is_setup_in_progress || + kbStatus?.user_data_exists)) ?? + false; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.test.tsx index 0de7adc484fc1..f72f85892d379 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.test.tsx @@ -57,6 +57,9 @@ describe('use chat send', () => { assistantTelemetry: { reportAssistantMessageSent, }, + assistantAvailability: { + isAssistantEnabled: true, + }, }); }); it('handleOnChatCleared clears the conversation', async () => { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx index 4ea376518b5a7..c240d5ac6b60b 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx @@ -52,12 +52,16 @@ export const useChatSend = ({ setSelectedPromptContexts, setCurrentConversation, }: UseChatSendProps): UseChatSend => { - const { assistantTelemetry, toasts } = useAssistantContext(); + const { + assistantTelemetry, + toasts, + assistantAvailability: { isAssistantEnabled }, + } = useAssistantContext(); const [userPrompt, setUserPrompt] = useState(null); const { isLoading, sendMessage, abortStream } = useSendMessage(); const { clearConversation, removeLastMessage } = useConversation(); - const { data: kbStatus } = useKnowledgeBaseStatus({ http }); + const { data: kbStatus } = useKnowledgeBaseStatus({ http, enabled: isAssistantEnabled }); const isSetupComplete = kbStatus?.elser_exists && kbStatus?.index_exists && diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/index.tsx index 06e0c8ebcc977..7a2da0d22fc3e 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/index.tsx @@ -37,6 +37,7 @@ export const useInlineActions = ( actions: [ { name: i18n.EDIT_BUTTON, + 'data-test-subj': 'edit-button', description: i18n.EDIT_BUTTON, icon: 'pencil', type: 'icon', diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.test.tsx index 1ef2db7b26c03..368477455c941 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.test.tsx @@ -24,7 +24,6 @@ import { Conversation } from '../assistant_context/types'; import * as all from './chat_send/use_chat_send'; import { useConversation } from './use_conversation'; import { AIConnector } from '../connectorland/connector_selector'; -import { omit } from 'lodash'; jest.mock('../connectorland/use_load_connectors'); jest.mock('../connectorland/connector_setup'); @@ -142,84 +141,6 @@ describe('Assistant', () => { }); describe('persistent storage', () => { - it('should refetchCurrentUserConversations after settings save button click', async () => { - const chatSendSpy = jest.spyOn(all, 'useChatSend'); - await renderAssistant(); - - fireEvent.click(screen.getByTestId('settings')); - - jest.mocked(useFetchCurrentUserConversations).mockReturnValue({ - data: { - ...mockData, - welcome_id: { - ...mockData.welcome_id, - apiConfig: { newProp: true }, - }, - }, - isLoading: false, - refetch: jest.fn().mockResolvedValue({ - isLoading: false, - data: { - ...mockData, - welcome_id: { - ...mockData.welcome_id, - apiConfig: { newProp: true }, - }, - }, - }), - isFetched: true, - } as unknown as DefinedUseQueryResult, unknown>); - - await act(async () => { - fireEvent.click(screen.getByTestId('save-button')); - }); - - expect(chatSendSpy).toHaveBeenLastCalledWith( - expect.objectContaining({ - currentConversation: { - apiConfig: { newProp: true }, - category: 'assistant', - id: mockData.welcome_id.id, - messages: [], - title: 'Welcome', - replacements: {}, - }, - }) - ); - }); - - it('should refetchCurrentUserConversations after settings save button click, but do not update convos when refetch returns bad results', async () => { - jest.mocked(useFetchCurrentUserConversations).mockReturnValue({ - data: mockData, - isLoading: false, - refetch: jest.fn().mockResolvedValue({ - isLoading: false, - data: omit(mockData, 'welcome_id'), - }), - isFetched: true, - } as unknown as DefinedUseQueryResult, unknown>); - const chatSendSpy = jest.spyOn(all, 'useChatSend'); - await renderAssistant(); - - fireEvent.click(screen.getByTestId('settings')); - await act(async () => { - fireEvent.click(screen.getByTestId('save-button')); - }); - - expect(chatSendSpy).toHaveBeenLastCalledWith( - expect.objectContaining({ - currentConversation: { - apiConfig: { connectorId: '123' }, - replacements: {}, - category: 'assistant', - id: mockData.welcome_id.id, - messages: [], - title: 'Welcome', - }, - }) - ); - }); - it('should delete conversation when delete button is clicked', async () => { await renderAssistant(); const deleteButton = screen.getAllByTestId('delete-option')[0]; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx index 3d18885902326..763a2578ee273 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx @@ -26,6 +26,9 @@ const mockUseAssistantContext = { }, setAllSystemPrompts: jest.fn(), setConversations: jest.fn(), + assistantAvailability: { + isAssistantEnabled: true, + }, }; jest.mock('../assistant_context', () => { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx index a46ba652574f6..18bc0cbe5a384 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx @@ -44,8 +44,16 @@ interface Props { */ export const KnowledgeBaseSettings: React.FC = React.memo( ({ knowledgeBase, setUpdatedKnowledgeBaseSettings, modalMode = false }) => { - const { http, toasts } = useAssistantContext(); - const { data: kbStatus, isLoading, isFetching } = useKnowledgeBaseStatus({ http }); + const { + http, + toasts, + assistantAvailability: { isAssistantEnabled }, + } = useAssistantContext(); + const { + data: kbStatus, + isLoading, + isFetching, + } = useKnowledgeBaseStatus({ http, enabled: isAssistantEnabled }); const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http, toasts }); // Resource enabled state @@ -53,9 +61,9 @@ export const KnowledgeBaseSettings: React.FC = React.memo( const isSecurityLabsEnabled = kbStatus?.security_labs_exists ?? false; const isKnowledgeBaseSetup = (isElserEnabled && - isSecurityLabsEnabled && kbStatus?.index_exists && - kbStatus?.pipeline_exists) ?? + kbStatus?.pipeline_exists && + (isSecurityLabsEnabled || kbStatus?.user_data_exists)) ?? false; const isSetupInProgress = kbStatus?.is_setup_in_progress ?? false; const isSetupAvailable = kbStatus?.is_setup_available ?? false; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/document_entry_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/document_entry_editor.tsx index 11d9ac2d62289..a48010f088c42 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/document_entry_editor.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/document_entry_editor.tsx @@ -14,18 +14,28 @@ import { EuiIcon, EuiText, } from '@elastic/eui'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { DocumentEntry } from '@kbn/elastic-assistant-common'; import * as i18n from './translations'; +import { isGlobalEntry } from './helpers'; interface Props { entry?: DocumentEntry; + originalEntry?: DocumentEntry; setEntry: React.Dispatch>>; hasManageGlobalKnowledgeBase: boolean; } export const DocumentEntryEditor: React.FC = React.memo( - ({ entry, setEntry, hasManageGlobalKnowledgeBase }) => { + ({ entry, setEntry, hasManageGlobalKnowledgeBase, originalEntry }) => { + const privateUsers = useMemo(() => { + const originalUsers = originalEntry?.users; + if (originalEntry && !isGlobalEntry(originalEntry)) { + return originalUsers; + } + return undefined; + }, [originalEntry]); + // Name const setName = useCallback( (e: React.ChangeEvent) => @@ -38,12 +48,13 @@ export const DocumentEntryEditor: React.FC = React.memo( (value: string) => setEntry((prevEntry) => ({ ...prevEntry, - users: value === i18n.SHARING_GLOBAL_OPTION_LABEL ? [] : undefined, + users: value === i18n.SHARING_GLOBAL_OPTION_LABEL ? [] : privateUsers, })), - [setEntry] + [privateUsers, setEntry] ); const sharingOptions = [ { + 'data-test-subj': 'sharing-private-option', value: i18n.SHARING_PRIVATE_OPTION_LABEL, inputDisplay: ( @@ -57,6 +68,7 @@ export const DocumentEntryEditor: React.FC = React.memo( ), }, { + 'data-test-subj': 'sharing-global-option', value: i18n.SHARING_GLOBAL_OPTION_LABEL, inputDisplay: ( @@ -111,6 +123,7 @@ export const DocumentEntryEditor: React.FC = React.memo( fullWidth > ( @@ -63,9 +65,68 @@ const wrapper = (props: { children: React.ReactNode }) => ( ); describe('KnowledgeBaseSettingsManagement', () => { + const mockCreateEntry = jest.fn(); + const mockUpdateEntry = jest.fn(); + const mockDeleteEntry = jest.fn(); const mockData = [ - { id: '1', name: 'Test Entry 1', type: 'document', kbResource: 'user', users: [{ id: 'hi' }] }, - { id: '2', name: 'Test Entry 2', type: 'index', kbResource: 'global', users: [] }, + { + id: '1', + createdAt: '2024-10-21T18:54:14.773Z', + createdBy: 'u_user_id_1', + updatedAt: '2024-10-23T17:33:15.933Z', + updatedBy: 'u_user_id_1', + users: [{ name: 'Test User 1' }], + name: 'Test Entry 1', + namespace: 'default', + type: 'document', + kbResource: 'user', + source: 'user', + text: 'Very nice text', + }, + { + id: '2', + createdAt: '2024-10-25T09:55:56.596Z', + createdBy: 'u_user_id_2', + updatedAt: '2024-10-25T09:55:56.596Z', + updatedBy: 'u_user_id_2', + users: [], + name: 'Test Entry 2', + namespace: 'default', + type: 'index', + index: 'index-1', + field: 'semantic_field1', + description: 'Test description', + queryDescription: 'Test query instruction', + }, + { + id: '3', + createdAt: '2024-10-25T09:55:56.596Z', + createdBy: 'u_user_id_1', + updatedAt: '2024-10-25T09:55:56.596Z', + updatedBy: 'u_user_id_1', + users: [{ name: 'Test User 1' }], + name: 'Test Entry 3', + namespace: 'default', + type: 'index', + index: 'index-2', + field: 'semantic_field2', + description: 'Test description', + queryDescription: 'Test query instruction', + }, + { + id: '4', + createdAt: '2024-10-21T18:54:14.773Z', + createdBy: 'u_user_id_3', + updatedAt: '2024-10-23T17:33:15.933Z', + updatedBy: 'u_user_id_3', + users: [], + name: 'Test Entry 4', + namespace: 'default', + type: 'document', + kbResource: 'user', + source: 'user', + text: 'Very nice text', + }, ]; beforeEach(() => { @@ -98,15 +159,15 @@ describe('KnowledgeBaseSettingsManagement', () => { closeFlyout: jest.fn(), }); (useCreateKnowledgeBaseEntry as jest.Mock).mockReturnValue({ - mutateAsync: jest.fn(), + mutateAsync: mockCreateEntry, isLoading: false, }); (useUpdateKnowledgeBaseEntries as jest.Mock).mockReturnValue({ - mutateAsync: jest.fn(), + mutateAsync: mockUpdateEntry, isLoading: false, }); (useDeleteKnowledgeBaseEntries as jest.Mock).mockReturnValue({ - mutateAsync: jest.fn(), + mutateAsync: mockDeleteEntry, isLoading: false, }); }); @@ -241,4 +302,142 @@ describe('KnowledgeBaseSettingsManagement', () => { }); expect(screen.queryByTestId('delete-entry-confirmation')).not.toBeInTheDocument(); }); + + it('does not create a duplicate document entry when switching sharing option twice', async () => { + (useFlyoutModalVisibility as jest.Mock).mockReturnValue({ + isFlyoutOpen: true, + openFlyout: jest.fn(), + closeFlyout: jest.fn(), + }); + render(, { + wrapper, + }); + + await waitFor(() => { + fireEvent.click(screen.getAllByTestId('edit-button')[0]); + }); + expect(screen.getByTestId('flyout')).toBeVisible(); + + await waitFor(() => { + expect(screen.getByText('Edit document entry')).toBeInTheDocument(); + }); + + const updatedName = 'New Entry Name'; + await waitFor(() => { + const nameInput = screen.getByTestId('entryNameInput'); + fireEvent.change(nameInput, { target: { value: updatedName } }); + }); + + await waitFor(() => { + fireEvent.click(screen.getByTestId('sharing-select')); + fireEvent.click(screen.getByTestId('sharing-global-option')); + fireEvent.click(screen.getByTestId('sharing-select')); + fireEvent.click(screen.getByTestId('sharing-private-option')); + fireEvent.click(screen.getByTestId('save-button')); + }); + + await waitFor(() => { + expect(mockUpdateEntry).toHaveBeenCalledTimes(1); + }); + expect(mockCreateEntry).toHaveBeenCalledTimes(0); + expect(mockUpdateEntry).toHaveBeenCalledWith([{ ...mockData[0], name: updatedName }]); + }); + + it('does not create a duplicate index entry when switching sharing option twice', async () => { + (useFlyoutModalVisibility as jest.Mock).mockReturnValue({ + isFlyoutOpen: true, + openFlyout: jest.fn(), + closeFlyout: jest.fn(), + }); + render(, { + wrapper, + }); + + await waitFor(() => { + fireEvent.click(screen.getAllByTestId('edit-button')[2]); + }); + expect(screen.getByTestId('flyout')).toBeVisible(); + + await waitFor(() => { + expect(screen.getByText('Edit index entry')).toBeInTheDocument(); + }); + + const updatedName = 'New Entry Name'; + await waitFor(() => { + const nameInput = screen.getByTestId('entry-name'); + fireEvent.change(nameInput, { target: { value: updatedName } }); + }); + + await waitFor(() => { + fireEvent.click(screen.getByTestId('sharing-select')); + fireEvent.click(screen.getByTestId('sharing-global-option')); + fireEvent.click(screen.getByTestId('sharing-select')); + fireEvent.click(screen.getByTestId('sharing-private-option')); + fireEvent.click(screen.getByTestId('save-button')); + }); + + await waitFor(() => { + expect(mockUpdateEntry).toHaveBeenCalledTimes(1); + }); + expect(mockCreateEntry).toHaveBeenCalledTimes(0); + expect(mockUpdateEntry).toHaveBeenCalledWith([{ ...mockData[2], name: updatedName }]); + }); + + it('shows duplicate entry modal when making global to private entry update', async () => { + (useFlyoutModalVisibility as jest.Mock).mockReturnValue({ + isFlyoutOpen: true, + openFlyout: jest.fn(), + closeFlyout: jest.fn(), + }); + render(, { + wrapper, + }); + + await waitFor(() => { + fireEvent.click(screen.getAllByTestId('edit-button')[3]); + }); + expect(screen.getByTestId('flyout')).toBeVisible(); + + await waitFor(() => { + expect(screen.getByText('Edit document entry')).toBeInTheDocument(); + }); + + await waitFor(() => { + fireEvent.click(screen.getByTestId('sharing-select')); + fireEvent.click(screen.getByTestId('sharing-private-option')); + fireEvent.click(screen.getByTestId('save-button')); + }); + + expect(screen.getByTestId('create-duplicate-entry-modal')).toBeInTheDocument(); + await waitFor(() => { + fireEvent.click(screen.getByTestId('confirmModalConfirmButton')); + }); + expect(screen.queryByTestId('create-duplicate-entry-modal')).not.toBeInTheDocument(); + + await waitFor(() => { + expect(mockCreateEntry).toHaveBeenCalledTimes(1); + }); + expect(mockUpdateEntry).toHaveBeenCalledTimes(0); + expect(mockCreateEntry).toHaveBeenCalledWith({ ...mockData[3], users: undefined }); + }); + + it('shows warning icon for index entries with missing indices', async () => { + render(, { + wrapper, + }); + + await waitFor(() => expect(screen.getByTestId('missing-index-icon')).toBeInTheDocument()); + + expect(screen.getAllByTestId('missing-index-icon').length).toEqual(1); + + fireEvent.mouseOver(screen.getByTestId('missing-index-icon')); + + await waitFor(() => screen.getByTestId('missing-index-tooltip')); + + expect( + screen.getByText( + 'The index assigned to this knowledge base entry is unavailable. Check the permissions on the configured index, or that the index has not been deleted. You can update the index to be used for this knowledge entry, or delete the entry entirely.' + ) + ).toBeInTheDocument(); + }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx index e3a86c62d1222..092cc7e36689e 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx @@ -30,6 +30,7 @@ import { } from '@kbn/elastic-assistant-common'; import { css } from '@emotion/react'; import { DataViewsContract } from '@kbn/data-views-plugin/public'; +import useAsync from 'react-use/lib/useAsync'; import { KnowledgeBaseTour } from '../../tour/knowledge_base'; import { AlertsSettingsManagement } from '../../assistant/settings/alerts_settings/alerts_settings_management'; import { useKnowledgeBaseEntries } from '../../assistant/api/knowledge_base/entries/use_knowledge_base_entries'; @@ -73,15 +74,24 @@ interface Params { export const KnowledgeBaseSettingsManagement: React.FC = React.memo(({ dataViews }) => { const { assistantFeatures: { assistantKnowledgeBaseByDefault: enableKnowledgeBaseByDefault }, - assistantAvailability: { hasManageGlobalKnowledgeBase }, + assistantAvailability: { hasManageGlobalKnowledgeBase, isAssistantEnabled }, http, toasts, } = useAssistantContext(); const [hasPendingChanges, setHasPendingChanges] = useState(false); - const { data: kbStatus, isFetched } = useKnowledgeBaseStatus({ http }); + const { data: kbStatus, isFetched } = useKnowledgeBaseStatus({ + http, + enabled: isAssistantEnabled, + }); const isKbSetup = isKnowledgeBaseSetup(kbStatus); const [deleteKBItem, setDeleteKBItem] = useState(null); + const [duplicateKBItem, setDuplicateKBItem] = useState( + null + ); + const [originalEntry, setOriginalEntry] = useState( + undefined + ); // Only needed for legacy settings management const { knowledgeBase, setUpdatedKnowledgeBaseSettings, resetSettings, saveSettings } = @@ -145,38 +155,55 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(({ d }); const isModifyingEntry = isCreatingEntry || isUpdatingEntries || isDeletingEntries; + const { + data: entries, + isFetching: isFetchingEntries, + refetch: refetchEntries, + } = useKnowledgeBaseEntries({ + http, + toasts, + enabled: enableKnowledgeBaseByDefault && isAssistantEnabled, + isRefetching: kbStatus?.is_setup_in_progress, + }); + // Flyout Save/Cancel Actions const onSaveConfirmed = useCallback(async () => { if (isKnowledgeBaseEntryResponse(selectedEntry)) { await updateEntries([selectedEntry]); closeFlyout(); } else if (isKnowledgeBaseEntryCreateProps(selectedEntry)) { + if (originalEntry) { + setDuplicateKBItem(selectedEntry); + return; + } await createEntry(selectedEntry); closeFlyout(); - } else if (isKnowledgeBaseEntryCreateProps(selectedEntry)) { - createEntry(selectedEntry); - closeFlyout(); } - }, [closeFlyout, selectedEntry, createEntry, updateEntries]); + }, [selectedEntry, originalEntry, updateEntries, closeFlyout, createEntry]); const onSaveCancelled = useCallback(() => { + setOriginalEntry(undefined); setSelectedEntry(undefined); closeFlyout(); }, [closeFlyout]); - const { - data: entries, - isFetching: isFetchingEntries, - refetch: refetchEntries, - } = useKnowledgeBaseEntries({ - http, - toasts, - enabled: enableKnowledgeBaseByDefault, - }); + const { value: existingIndices } = useAsync(() => { + const indices: string[] = []; + entries.data.forEach((entry) => { + if (entry.type === 'index') { + indices.push(entry.index); + } + }); + + return indices.length ? dataViews.getExistingIndices(indices) : Promise.resolve([]); + }, [entries.data]); + const { getColumns } = useKnowledgeBaseTable(); const columns = useMemo( () => getColumns({ + isKbSetupInProgress: kbStatus?.is_setup_in_progress ?? false, + existingIndices, isDeleteEnabled: (entry: KnowledgeBaseEntryResponse) => { return ( !isSystemEntry(entry) && (isGlobalEntry(entry) ? hasManageGlobalKnowledgeBase : true) @@ -193,11 +220,19 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(({ d }, onEditActionClicked: ({ id }: KnowledgeBaseEntryResponse) => { const entry = entries.data.find((e) => e.id === id); + setOriginalEntry(entry); setSelectedEntry(entry); openFlyout(); }, }), - [entries.data, getColumns, hasManageGlobalKnowledgeBase, openFlyout] + [ + entries.data, + existingIndices, + getColumns, + hasManageGlobalKnowledgeBase, + kbStatus?.is_setup_in_progress, + openFlyout, + ] ); // Refresh button @@ -281,6 +316,18 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(({ d } }, [deleteEntry, deleteKBItem, setDeleteKBItem]); + const handleCancelDuplicateEntry = useCallback(() => { + setDuplicateKBItem(null); + }, [setDuplicateKBItem]); + + const handleDuplicateEntry = useCallback(async () => { + if (duplicateKBItem) { + await createEntry(duplicateKBItem); + closeFlyout(); + setDuplicateKBItem(null); + } + }, [closeFlyout, createEntry, duplicateKBItem]); + if (!enableKnowledgeBaseByDefault) { return ( <> @@ -379,6 +426,7 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(({ d {selectedEntry?.type === DocumentEntryType.value ? ( >> } @@ -387,6 +435,7 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(({ d ) : ( >> @@ -412,6 +461,19 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(({ d

{i18n.DELETE_ENTRY_CONFIRMATION_CONTENT}

)} + {duplicateKBItem && ( + +

{i18n.DUPLICATE_ENTRY_CONFIRMATION_CONTENT}

+
+ )} ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.test.tsx index e4656b10d1d31..faa4653c9beab 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.test.tsx @@ -22,6 +22,7 @@ describe('IndexEntryEditor', () => { { name: 'field-2', esTypes: ['text'] }, { name: 'field-3', esTypes: ['semantic_text'] }, ]), + getExistingIndices: jest.fn().mockResolvedValue(['index-1']), } as unknown as DataViewsContract; const defaultProps = { @@ -147,4 +148,20 @@ describe('IndexEntryEditor', () => { expect(getByRole('combobox', { name: i18n.ENTRY_FIELD_PLACEHOLDER })).toBeDisabled(); }); }); + + it('fetches index options and updates on selection 2', async () => { + (mockDataViews.getExistingIndices as jest.Mock).mockResolvedValue([]); + const { getByText } = render( + + ); + + await waitFor(() => { + expect(mockDataViews.getExistingIndices).toHaveBeenCalled(); + }); + + expect(getByText("Index doesn't exist")).toBeInTheDocument(); + }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx index 550861bcbffd9..dfc3cd0086686 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx @@ -21,16 +21,26 @@ import React, { useCallback, useMemo } from 'react'; import { IndexEntry } from '@kbn/elastic-assistant-common'; import { DataViewsContract } from '@kbn/data-views-plugin/public'; import * as i18n from './translations'; +import { isGlobalEntry } from './helpers'; interface Props { dataViews: DataViewsContract; entry?: IndexEntry; + originalEntry?: IndexEntry; setEntry: React.Dispatch>>; hasManageGlobalKnowledgeBase: boolean; } export const IndexEntryEditor: React.FC = React.memo( - ({ dataViews, entry, setEntry, hasManageGlobalKnowledgeBase }) => { + ({ dataViews, entry, setEntry, hasManageGlobalKnowledgeBase, originalEntry }) => { + const privateUsers = useMemo(() => { + const originalUsers = originalEntry?.users; + if (originalEntry && !isGlobalEntry(originalEntry)) { + return originalUsers; + } + return undefined; + }, [originalEntry]); + // Name const setName = useCallback( (e: React.ChangeEvent) => @@ -43,9 +53,9 @@ export const IndexEntryEditor: React.FC = React.memo( (value: string) => setEntry((prevEntry) => ({ ...prevEntry, - users: value === i18n.SHARING_GLOBAL_OPTION_LABEL ? [] : undefined, + users: value === i18n.SHARING_GLOBAL_OPTION_LABEL ? [] : privateUsers, })), - [setEntry] + [privateUsers, setEntry] ); const sharingOptions = [ { @@ -96,12 +106,18 @@ export const IndexEntryEditor: React.FC = React.memo( })); }, [dataViews]); + const { value: isMissingIndex } = useAsync(async () => { + if (!entry?.index?.length) return false; + + return !(await dataViews.getExistingIndices([entry.index])).length; + }, [entry?.index]); + const indexFields = useAsync( async () => dataViews.getFieldsForWildcard({ pattern: entry?.index ?? '', }), - [] + [entry?.index] ); const fieldOptions = useMemo( @@ -251,11 +267,17 @@ export const IndexEntryEditor: React.FC = React.memo( fullWidth /> - + {i18n.MISSING_INDEX_ERROR}} + > { const { userProfileService } = useAssistantContext(); const userProfile = useAsync(async () => { + if (isSystemEntry(entry) || entry.createdBy === 'unknown') { + return; + } + const profile = await userProfileService?.bulkGet<{ avatar: UserProfileAvatarData }>({ uids: new Set([entry.createdBy]), dataPath: 'avatar', @@ -38,7 +51,7 @@ const AuthorColumn = ({ entry }: { entry: KnowledgeBaseEntryResponse }) => { () => userProfile?.value?.username ?? 'Unknown', [userProfile?.value?.username] ); - const userAvatar = userProfile.value?.avatar; + const userAvatar = userProfile?.value?.avatar; const badgeItem = isSystemEntry(entry) ? 'Elastic' : userName; const userImage = isSystemEntry(entry) ? ( { ); }; +const NameColumn = ({ + entry, + existingIndices, +}: { + entry: KnowledgeBaseEntryResponse; + existingIndices?: string[]; +}) => { + let showMissingIndexWarning = false; + if (existingIndices && entry.type === 'index') { + showMissingIndexWarning = !existingIndices.includes(entry.index); + } + return ( + <> + {entry.name} + {showMissingIndexWarning && ( + + + + )} + + ); +}; + export const useKnowledgeBaseTable = () => { const getActions = useInlineActions(); @@ -97,15 +143,19 @@ export const useKnowledgeBaseTable = () => { const getColumns = useCallback( ({ + existingIndices, isDeleteEnabled, isEditEnabled, onDeleteActionClicked, onEditActionClicked, + isKbSetupInProgress, }: { + existingIndices?: string[]; isDeleteEnabled: (entry: KnowledgeBaseEntryResponse) => boolean; isEditEnabled: (entry: KnowledgeBaseEntryResponse) => boolean; onDeleteActionClicked: (entry: KnowledgeBaseEntryResponse) => void; onEditActionClicked: (entry: KnowledgeBaseEntryResponse) => void; + isKbSetupInProgress: boolean; }): Array> => { return [ { @@ -115,7 +165,9 @@ export const useKnowledgeBaseTable = () => { }, { name: i18n.COLUMN_NAME, - render: ({ name }: KnowledgeBaseEntryResponse) => name, + render: (entry: KnowledgeBaseEntryResponse) => ( + + ), sortable: ({ name }: KnowledgeBaseEntryResponse) => name, width: '30%', }, @@ -136,11 +188,27 @@ export const useKnowledgeBaseTable = () => { { name: i18n.COLUMN_ENTRIES, render: (entry: KnowledgeBaseEntryResponse) => { - return isSystemEntry(entry) - ? entry.text - : entry.type === DocumentEntryType.value - ? '1' - : '-'; + return isSystemEntry(entry) ? ( + <> + {`${entry.text}`} + {isKbSetupInProgress ? ( + + ) : ( + + + + )} + + ) : entry.type === DocumentEntryType.value ? ( + '1' + ) : ( + '-' + ); }, }, { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx index d697fc7120d01..41656c968d38e 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx @@ -6,15 +6,16 @@ */ import React, { useCallback } from 'react'; -import { EuiButton, EuiButtonEmpty, EuiToolTip } from '@elastic/eui'; +import { EuiButton, EuiButtonIcon, EuiButtonEmpty, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { css } from '@emotion/react'; import { useAssistantContext } from '../..'; import { useSetupKnowledgeBase } from '../assistant/api/knowledge_base/use_setup_knowledge_base'; import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_knowledge_base_status'; interface Props { - display?: 'mini'; + display?: 'mini' | 'refresh'; } /** @@ -22,9 +23,13 @@ interface Props { * */ export const SetupKnowledgeBaseButton: React.FC = React.memo(({ display }: Props) => { - const { http, toasts } = useAssistantContext(); + const { + http, + toasts, + assistantAvailability: { isAssistantEnabled }, + } = useAssistantContext(); - const { data: kbStatus } = useKnowledgeBaseStatus({ http }); + const { data: kbStatus } = useKnowledgeBaseStatus({ http, enabled: isAssistantEnabled }); const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http, toasts }); const isSetupInProgress = kbStatus?.is_setup_in_progress || isSettingUpKB; @@ -48,6 +53,23 @@ export const SetupKnowledgeBaseButton: React.FC = React.memo(({ display } }) : undefined; + if (display === 'refresh') { + return ( + + ); + } + return ( {display === 'mini' ? ( diff --git a/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/overview.gif b/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/overview.gif index 4cf07dfecd6a98a1be155c8fccfd96c89a6e7430..2f2d372f5497de833702b22fb0ce7431193e7f0c 100644 GIT binary patch delta 1027235 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�~(0{dB0|{wg$Ld3G@BdreY{YhIa!W#HqPt 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

ythL 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%0DxzlAxl4n9kAjh0aD!xkem^KBTaIZD>;z7)!yWV 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

(g#3Y5du4Aa>6oq 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⪼=G3&viyw^DFCKZfZ>3$x%n7D#)R?%YIdT|%om41e zs0n6U%;d|I#{QZdn zILA51bo8IJCzma^_jre%D`=$jU;ZwcN*n~Ma=38>rW$;>m}$K}#{Q>%quCA^7}4#w z2$_+ykn+G)zfXU$=L+~UGw$m@6~&ip8k854_{`(Fj@!FPyyGu1{0Oe&I;C0hn!5mh zrC5x=o@FFp3=WeBCShbG^9x2M1%u`oDCUA+{RxJdGEhr}JbxHM&&a@-5#m%6!fHx? zqYgi%3gu#?=P?a^;vFh5M<>)2YB(M$DuARDAK{E z!5BWG5}qXyt`4Nt%m`Pg3D+H<(K`#5p^A7EO=D;panC!#bb#8tDI)k+1Q9SYd_2O= zncCholE*vJS%BKLDH66C2?j<5jYs+nQ2ClhF?&b(MNA%bvy2}`l`gz)^0txo?R$Z^9L=~)=eYFfxRlbk zq=C4^^|*Lo{9A$eD9!kA=lGE5cw|s%{Of^uzxDVRzyu$G1TW15Pv-=;=mh7|1c!kH zyY&PcV4}4^qJ?InsdJ)HbmF7ZME!w8-StE*AWB^TrK*Wiaz-gcqhw1_QUfT7b(APD zNmw9BKr@NgIf*MeiK8@$bs&jpJ&7KeOe2sC(@dsxP6kCM14@%g29gPB*ORXSDSw^# zby8y=BnjUYbxBbyMR)ly(cbkJ86?rgcc$uPrrxbdz56Tmv6(+1;eWM>f3ck}vEYCF z1+1D_Oy~cy-NPd1 z|6x17L&yjmR{f(R_=fFto4l+$@b)b{O-me4dQjXtxw`*0DEyo4oZ>lHX$rlRdj7+9 zEyWxEX1mq{x3EM(uXd|{*e(qD5n+C+xD2EM{lj*@1+Q8>WcNdT)^FJE=a=@X7h9G; zA^7c!E7_idMVkDMAMH16w?A5q6#gW0adH%0b-iIbbMkFOmzSn1PV9r|p(e?Oy+f?a&BIMlc!&Wuia_ zrW4VjKPXa>qIbe+;Ye^x0)l#~>h#B(E&S#BgCkwy`j3GOo@Yy}WeEK-CeRA-7nW=0 zxfsbRrF0|Ui|+YqO?e$kCU@c6@UM3atzR}?9l8(a7B&9JC29D!e6jtlPw&4F_xjD{ z9qVxg=A^?!`3`=LnY^LjMiBBs zA`$K+QZP3mfO-hik9UxrVzF8RQC+I|c~P(=V!Zp2mrEQsr$?9$GVVeDEOB&k^US-$ zWfd4hIi4A=e4Xh6sK@EReUl64f|sH^FNqoOs2sjg^%mXut!D+7SrH`3ys|~L?&Sfz zBINwT=JN;XO(R93?Q1-A%|2+8*T_`)36c>z=EDpus7qO-p37d6lA(cdK$?0&*Gbev zEx;yP@!GbZ$BxKb^sHY()C}d|H3`<)?p)nBg}s7>r{k5aRTjyUT@`rJ={ck1CG7C} zFU!L-IR2Dqefk4^cDc+pp2WMnSyV+q9+1cB#p!_f(50261Q`b1LxH(qh`Yb;bQO)N4}}xD4+A@0QY+P)q7O zM11L^TNjC9bklGyQpco#Lh*o4G-*WA4w#HPs66JCR8zVEF+jJG8^pf+;dfIEBw{Q& zbsGNcuA5QaQBli8TD8Rx(k-Q-m%IAnMK;o5)hb(Nu4Qvt>$OL+(JDy1mHMP6@_~pQ z|AI-Uxv>iR!DHL|3sXJpFKgni%uHz{=W#?;^`uHwE+)hOH3V#_bl{bHbv%lyhTUK5 zf7>*6ZpxW>24JwnL0;K<2M)xf4}V*eIc@I$h<@^ZI1edlHmfq%Uj4Fe`1?*kW9v5~ z58nc##8-05ZR-#IYaK9pCiUZCVtoRG$yb5MTKhlX>x;$?g6j{##JY=wEKQw21#x6r zk%&WE&!^KDM)IG#e!Ac29gJVFk@rWIAg`q?im~D%_7W8N>St!h2A>tP(ry_v-$d9z zkbi{jb)QmooPC!1Qj=gy_>0}*?C~gQGbYA}!byV1uu5A}g!W*G<1x>p${}OpD2iL$ zVkCoFCt3~Rx(=39Dnpcnw=-JfYG0b&gx1f{XG+sgJLKr#IWaBa?~H6gOs`3XO{@>H zp3@oGNvYBq5)iTP?-L7Ug!WSohUapGIw7UR0>+dlBJX)7gKcwe2ocl8tE=Snm^PH` z1^c05xmOHwagkkaeYV6>7sm6`4=$drRsiUB&{SC`z3;-H;*9u>TvUSL#rt?$Y+^$@ zxrpvWPsxeQZW`P=?@J2su2bRN(x54vG1Rh3u;=0Sr|>5Gh9kRg`e-GhlnB^&a`Qsp zto(v>2GjSPX^?mkgt?-QIlj`?3zi3a%6&u3tOfM(av3;19tiy&YVfgHbZrMo!b!eB z@+(9gL+D@%ClxkJ$6k=W)mgNi@*_}YC=ZS@xm?T+z*iqC^6gVlgxjf^F`Llt;|L%7 zV%DTeiAsq)L2|G+-`U_VD@;G`BcpdhflpuqatWHT$ahc8nlpU0FD+5QVEgevfxDFq zIlK3$SD0sUA%a|9F*hDu7>z*hm&Rj|nPDDr#F+-b2WtJ^{bF3N8X{Rp(lPA zN%lozgK-4TYfPUm7y#SO1uL&^-f1d9xf2E0yr6r9^@n(3&p}iEy#{1RZ#pi65TQbg zDTc{=G|_V)7hpJx5MT72U+u|3bQW8Irl%N_on0Fm9*%HXdj=s~l!D-4z|xD5V1SNua`z3_Y`cgXcgPxyu3N4L_Jlf+yNzbwZap#GBNx zv(I8#2(ry`vi@v5ObkFqjtkNTHTbICajAm8NIrqKh?Chz`xuLr_FLmGGuLiKM zs4!WHr!=NseUZ+@wq6Pu0Q^4D3k;bm1|(nVQyfhGzR~Urkr49HJ;!k;w~dLHG|^9u z`t5ENgKkE$jTn%fl${5^KiB6_anlInbx|9>h%plwqp|4qw21FO#I49kH%4*4CfCZ( zQGuqfJbv51>K6&ih`J7q4B+z!igvnkg5AQC1w=ZF^%DrTqmk#0wnW~x5JE@r??{f9 zFLaEflQaePf+>&*z$ou?=Mp)~l<@Zb~YCMl-%V*kwK=-cA7g{VcwGF+PJn z;hSc{f?vY7XcwRLhuvzh3l#tUnZTW*IE@MD>M`UjBk>HWX?SF0eR-C+ss=p@P9!oz zk@=&J77fU?3@Nk>iNB&?{x`J#iGj zG)l-nnWHS3?L6^{k!#N{iSe9g62^Ushg&n3ar-H!D4eI9z@bV^sk@7ieHhg3AmLAN z>b^7d1c^vF!a^mJxeU!v{s%mYF-dp>N-6&|SuI|=%rv`9eo50*#|?--7q7N|s*YLe zO*Z92CiEj|w2vVA=|;+pH{r-8N#;C_Ml$8qMv9Jfh6Xt_(j~)XgLlt4BWy6$PC6rm zDbqh0ZN-!rB*-~Z#F_LpL&rZU-algpmgPo`w7ejI=J{v5E8`F7&P>?ItUS+(Cr{i& zP!cgETKi{0i8AP!w9Uw~KMiI?`e)so^vL@PDQ-@U+sGbjepe}&UEhqp6O-NCoH-Kn zE{Z&>?<-`Z)37%avVqFkG06FaAIzF<&Z?7!9t0<)2<8yyXNL}^hWqCnxMVG6=KL5$ z=77ARI|#_yV$M&q_XNxsqO6?R=G0AbN@cB-+k?48zjAX0Gm|%rVKR9k=g>KLYE@>+ z-W-~uoDBj>%qh!DxSRiO!csdAdSU}Pu}K95WU~!%aFp}!du8*0%=US>_+6pv2&lSr z0mERn*gOYE?7OFQ3>OIK8VV}ES%4g8D%_VS?8;;i(1vISq?VH>=B*U&b#aC=6*1c} z2)IJ7Fz@5O=9|y6wQIfKfE%-3(Amlqe>N+A5KugyRGimb{KTB$S^0bKixl4$HpQ5C zuY`CA;Hf@yr(G0754oHnd;Rc*59rbtBYD9e*hr} z3Rh*y+NaWg6M_xU9Sf zTlLj06)V{4p|mvl2yL@&KnM)@1_!RdlD`R{NI*f$aO9OX3n*A@y>NyHin1O)DQL07QFI0S`1 zxMm-Zr7RVfxx|7y#VPxPA>VDlZ|os$IOrk{*?{Z(L}1i%6YjOJ)tmupUlVGfsc3u= z+CtZta{-6GUW8(>a8;byDB8oa3i`WvL30%5KshchHo_oiy71IE6`6-j?*mbFT!u&PvfFvT3A?`biX z{c9@0Zn8;ky0ohZ9$SqcE*1#Uc8)8sH!6H9GIOpwlgruuFq^ubm6~nz^YaI@*|xKf zgk}SGW-|%ra)sukZqC-(&Z%^9Z&BEOq?p!`n~U{eii=0idbo1R#6ngOa;U1x=$+BD z_PJ||L18Mn0If-)5Y8_ch?IK@G*#y@7 zk2~MStdR39Y@H8B@=m=dM&D2#!6|kPIylv!-z_M5y}o0ZDUYxZq9&>cMZUUc&TYyw z;dWph=9q~b*wX-tgT=9P1jRartGo*OJs2V{HiA9$aMS(Yi??@f4H9D*Wc@rIPhaTxMp z3|A)(Qhf~#>4b*AhUQ>FzmSFGlNi970VIh4l5`FIz7OnjlTGs2PKnZ1Qg>u)=s&5`R#jJ)xU18@3!K}cXl=RL*pnzY#@_}y(8p4aFzhXkO&E41^WAR z(!Yl`iG%Tr6a@s31Qc&4!A4CABxV6zV>5OZw0LXpzzuRp^=B`*nRC>7G5`g1{9q^X z4H(x+{w^0Nv9Oavu&S;IzU~Cq!J)Wd(0L~)ejk{Kf!1J-7IUHNSU@Rkgz3w-vEgIC z@jbHf?T3{}&K;ZfeJ`2QMUTBX2!n#?)h2}MJ#-VBPj#aWU&_I8x4Gb#^GGtPyG$EXTRR!k(V#LIhW+FHupPb-cz;va=PaW zT5?e>>35Hc{awQ|+?IqMVj%>1df%me7B5#-G7@u@Bf)IAQ>{+)2?F7>>2#<)fIBer`1wNXlZoZCdLvnyaQ`{8S<6u3GY)7|9&%bkRMv zzHE~{>ra7K*QBhb`!?MXl!t|ldj+yDc5p99`}Kd?2VRLh`TWl8(D6%-JaT4ad~G3_ z|8aHw>(hPLnJTM}NH&WT_xX?b?1SO^%|)_5Hb(-H$4;+{og2AzhKsVz&wSQKa}=Z4 ztuA~^xvV~i0X}?x<}>BJS?9ESw$UQm{$As~^;N*h&iAeQAJnpKzTbW#N%TE0EvH`Y z;Q`_ZLI4l8^SwZw+oy}64ZhCH6P+)L#QcR=Ww2Q9{>Q16Vb88zf;TYs$ur@-A_{#~ z2{k$sqZBxi+kiVqO zXIQLX?r>yKnr`9^A+*hFT!X(|I=oG7eW8!;S>>P4ccbKAes%hA`2)or@6|J?{k#3u zPnQCu$S0CI?jO%JSCtj~SJ6(N&e!6j6aqHn`GbnC)vx7W?=&*#`aOtg^a=RW&)@Op za2UUEvGru-Q{d^(SK9BVdcJGqdQU$ge{*&Ey90^G|K_+Rx#`f$_jH3ppAgYCb>^-U zTQ1HU5b{bXfsApX400GN)jkB|W@sLEHfTeFRANx3PRE7wt1gi#HYwA0kG&QMx2159 zQlT!#M%?dR+PioN4V)@qzp*hXnkz%O=*OcqRPCtKnpFAjjmKzw(;$0=RuM9;@x8)~ zKxISKZUt!E;qqUScXw8kOdpR6woMOWy-W4HcX^_2zL;1kk&DunMiN!br5~gtYdvLf$ku26pxVBwWFWR=vQ@= zOl#J4yf>LS7VdbbNcw@R@nqI4zSr>{@?-M@&zFQ5W^-)@jVe!4`GW`fw!y*}@^4(e`wK83!kDCSh zp3@aiNZm~PWQ=Rmrz@S*+{~w2j2jxJtDZ%;S+2^Mw9HIbzv^?dK5jAjbTa(`N$PGx zDmyp9mWqv1bGM^wHT`^VrY14M9dD21l{FhOo~cFmxjWu%HT&{%rtUqdhqIcj`9%6m zeTkZft5K`@OvB8_4-p>j4zd>WGcyg1eIA}KS}lH@%rth8dU{33TK=M+ZR%I^^hs;A zT)Q{hJQm^UTO@0>X*}C9+vh0_$g2cFa`m{iV&h+(c1pzak)*JeX@f36D}=@rh4COHOa zKGab6Nlv@nX3uy3>!5z5Pim2zgOJJBA(PKO=^xu1L|=U!enR&AW_p2p9{hBqeH%i% zS(tG9CqMlEa_ce?SQ0o9tNzFBbhB~GOsqXsf__L($8T}t%_TlF?n$vF$EeYC+5(Y%>ZYnqR&+ySHUM_}v>iTo`Cc5RfFOSNuBsh2) zZv9AornCO-FSL!Qxk1b>LjEY>ZUdd_v-UTXl@=|;(w3Qu4I9f)<%aWuv8Pv4&m}%b z@Q!$yQJ)%1+SB6?O^3*fF6Rb`J>-0<*Jj+aM{iHQIsAfO6!H0z;VE*2Qz4E=3Xf|J zyC40pi}pq6y77&R_Hkpt@r;qvsL-tC>vo|zi?^eKUrn>)h31Vbefz5Bc`ts zzrP&283;WY!b_q=I?isLDF*+&b#pVGGstfddHYk-Qn)O;^a|?md$C9uO~ScqVjsCHAbw zXzeyiQB`6TtL z{{G&5X%VEM)4--3vHxA=yZY8o+6;nZp8=77RGOpv)+b(G?|PE*11?%o$L#ADCE| z$GyneblD5wat@{oPKgX+a4`b>@*5f0UhsQcog;S6d&kr{_2I?r^uDR=|+GTk_SJSh~bK+l3kp?YJDogtUtU??!4 zSM7WuXug|(Tds$mJ*}617MB2Jk_YY~$}tVnhQbu?q1Aud7u z!jxgs;RZ)XH$h4nr(>dzd9q5^~-0(&GSF+Cdj1Q@7nF!N)A|j%`k0d zb~_~Xsb4t%iZ*HE>6dV?c(SFW5ZRz1Adv=nF)mo{bhi<_=yU|T>~=M1>aO9{_U+Wj zo~ItPWo}RYY%3)A_@TCd6;h=trVb(hieIxEYHe3hzC=h_aE=U!U;Y`K7JIRg@Mkbx zXD=NVb77HhH+EH9&=!_-JE)W?PC|caJ2hfboc|(=rvci))+~7zPxo{?D~Zxv}>g*vd6SFSEGT(U;gP{=YF&cS9M+ zb9;9M!5?~&n{pNfIje--Nds#k;k2;$k=m^o1NDi|6Cq)Z?#C?#c2gJATK)D2VQ+C% zl+_9&n1vSd8hm0G)s+XPhTZlX z@~-sXYW_an6}?IT(q3`7GVs0kl@i~wVV}znNt;Q^OT8u^-#Wk00lSH-A%cHe7$7D* zrQbz;N*=%S(Fm{k@u_K{Y0F#n52!6z z7RK&(qX~>!iCSLk<_px$znc7dJT3(GI7pArQ%Tm<;q(DRO;{f?RUVI9Uchm4eZDjN zCa2k+C#vnQfMNT(L!X_axSq!cucc~#k@?qBlpYGf+r%5wxAqNCcr^Ib1e7JS<3eD+ zE8um8D;hOgQ8)E?=jDr2BmZD6FIoJujjto1Kej#4lUaQYz-$NBh2`)>u=9^RZFurK z#nVWjf0Q00=cD$_dDvWh>yMJJL9+5dYQUc zik9SCx8;fNEELDp=laOR&wl%s^(?Rf;W}ijN6pb9lPgZrp{TioZ{KH|Fs*g7`ahe| zJfq43Eu)>kR$sWRiR^+l`$x<2Jr6$~maly>9zyg)RBZ6%bA*IwKn1bK86rCPkg2xt@gp?bp+?dMY%k+&c)W__beb>1b_yl}|%9QSeKnQso$ z2W|aO;)rJ|tKDSRB=6%|t)|Z8&)>h59m{%a3|@ymQz-vU@#vdCZ|=R8(HOs;t31WU zYSot0DhTz)U1=IgZrP0GZjv>S@zG)N;_c>tPlLVk$~)PC>Q_Ix#Na3qu=Alz9la3! z#dNYPY8Tg|#P>XVQ|EiVOe*gJ_jY2!M3Ro*nlk^zKErUWCL!j4!7hPG!5b>WujIc{ zZ2oF#NBy+W4vGUt^Tgc;uP-V8iER-9pU-(w?A7F%>;{G5NqG!%IXtj{bzK3nV6ReQ zXPPgK2w%gYflAD;U6(;&zK~ov8@eKx_ho>CO4OK@fJ1Q9R0aHNFl@cgiNPQC^8hx0 zVySUrIxvIQ%QDq$!6J~*CNhMAWL_kL$uulAM5ZPhmiJ_qWjND05k1h%Qpgp<{m&if zas8{62gEvxzB7h39cr~=$zX{|A~95;7|M~*+f;P~1(fOrg*rhjXwXmskzv&gFlXk^ z9RmA7fNjt~DM;uTO-y-iu$_C%;eOmIApCJ@m4U(c}*Do8(7v`v!6&^toN>Fu1tA zsEB?v1qE6pqJb>gj8t*@`W!fA4%|S3RgeIGP)=HLaomAP8euV7ElK}IlIA92ApVa+ z`Yl1*QRiD=ss!7I0v!MkO}I(4Xdbt9K`VFtqm0OX{kOnc%`b z2O~&3LYVX+R=_C* zd8xn6!yf;7^id*JH4Jt@Zzt#m1!1phxhWl)DZTB4Z4xh9>IHaDAXwhT`6QxP)lwMt zs5VMEhcXU9ses>Ya$~f7sM;)N;clX;zzL(6&NBlB0AL0+*E9CMi%IlG!W4x@gV%36e6PCNLz4`|^%s^pnr{ry`Q1 zUwdNS48`-=&rfU?Aw`~fh4X5~+y2isxC2IPT$0CKMr=}{Y6ZW0i#L81Poa~-&Km;H zh#q1`&x<4#7YTQE%|fku@xP|xj(_u?UO))`j+{fmW{57A7CaA71gWKTWlOivZ-lWU z!aAbl)qxfkRGR(*y@-V_5@FXs9^MI1s@A-Uho(FDh|`kbQz3)5+3YT@kgi}N(-fUnsMEN9~00}9TL?#Wid8mUO_@b z;b5-su%<20GZJh=5TYppIYTiw;lbHRXc8O(_ytZ9gdUJ$pTHrzA)uf+J*;Hu^rxzo zUsWu$)kQWu+r1B7eunKhK?`Id`(}Uv6tf;2_I{3@G6xpoX5d)>o)H->WLd0bf$b7Q_b=7OP^r3QojPXc>+J5%{0YwGt#zAtmLfAq2{LmZ z53VJE2Ap6=bEQ^-aAT@HM1<@+L5iGUEqHKG41F7k$yb)8kPO)(vm8=d7zu>ZmdDRq zlZZM`D#kCmsw>0iwiI53S8vil!4Sr5vKcyq$mmbQvXM!!p5wfZd_%xfQ_Hb!PT+Py zdIAYTz*Bt@#seCt5AmrQPbq_Xsg^oF<9qn^AH;8OU1qiv{1Cv!7#2bdeRv;mnFe}? z$Wn+0FAItlZfPS?F8YKbIe?S{Vh?^1A6%T8e18;2Q1JR%J$;V}n znE3r`;Ma{D;C66lC+aT?o+HZDnlbp382z)sz9`TP@{J1|95nY%pr5gZ1nY5v962!s z(16mZz7mn~*a;d*gzX?fX#}~l_oco(brn4PRfX_C3QytWts~(9X{7rngI8@lHOrt2 zd??S>LD{+b$>sUg$HbEpzOx#a8$5+RFEgTU6sFU6!RxCoq_iRj;19bA`Hy{A&7X@$ zc1=6O;FXp&7yOFV0$xwKzi;UlvL|Z1FP2Z?W8tveHS1RXQ#3z-et0b@~i`liH zxW7j`=MDn4#ZL|IX9Ht%3eTmdo7e4L{500C;3&Fn=Bt`h3QTD@gIVmiW2an6EbS*=u7?0Qixn z`oN_Bvj7P{fYl@2!GSRypIFeK{q;wmLmpKb4-Su@RFVeStsXUh{4mVRM~)mA&lyB} zJ(`FdBG=nD--CYTO#4v_%X~L5XFs@wvU^w=JXFi!f8d9fI{379ItUH%rLlriXU8K? zztHfJ>7Lrqk5e7qikU4Z_sB1Oay}bH(8b!|$-aVYtH+XI|3mkF7~!4ykM8CEz&t=2 z$;L%}qhbDvbzmAI_hLeU>0cg#AF)NTe506+C`XN|J{!IEVN@e(lq{HoJR8;J8`F;( zWz%Fq_r)ab4}SgV?-FcjR=qz=qcI}xFlrV$u5L0q7Bg;7MSEw)ozBJ|@J%>;U;#x< z1gefGwhT%SjrEN9R_^)UbGCGK-9|LCHe&CK!5&a+In`$APNdY>uJ45VL8If6MSSWlug z%aU%z!=K)NXbt`AbN%?)&(jY-&u4zpod2ZbpQDA|H+7#~C0c?jX9qezGmKawEZIbr ze<8H2;``=Cg+h~G%$aXn*K(xLmo#t>^SG-yA|%a*_8@uLt9aR`ec5kz8FjuKz`qjoYPnl!xj()8 z{Ae+9b|w0J@eX!nxMT&my@HKi#TM|d#?JDxyU5k}%UuQhPL38%pN-6n{+(A$_q!lB z!HWAbw552hwSBE^cCGzv3+q=0RQRkV8(Rsm<;~Mu^Ft0p1Au6w!4b$2xE(a<^C&UGtDOMvFUy-tqcF( zGB${5{?)`sw;|oc=dZNDV*g=mk}oe9Zt{W%@5P$r`%|2D=5(J^{?UAB-CJX5@MZJT znZJTgi8``KM5&I@QYj^&WcmFb7qoFniw<0pf+{ITa-IVqIyHyZY?rRPP5rzI z^mS*YXRT{CGnDpv#|D(<=W;TVx%?8K!@JJ;(A2WP)7|00HN6ogipN4`bUw{d8Xfp4 z^4Bx34-%R5!NPwkU6RZcUzBp1+nPO#=Zv?_PkZ&yvx2~RRE2z+q4=i+@X!|T?25+z zmvw$XQFXsAuqEe4%{o_02LX!yOyjVuS-HsL4KFG*eyvwR=f%}VA6+3#{(9q>rFt%o zTj`c~{*dk3M)Tb4^-lT)RwnVXc5KaN>-uKa)kc6b)6eL?P2PV$9NxO_+J3sfCUfuP zTzZQHJg2+@ z{-s6!gC4%*`gsj}st3?v1CKTDtj5`$n7q9E%j^g+BdDQMlSz)&2^&Ns;K$F&IGwLN z;7!I6O$_^%00Q2BS{@pQ>F;8HZuA@odMO-7o&!>3>7mRSadA#WK?eySi}hArw?$Jz_XnH73kIb1+qZ9Hbah4ww;yMMikDzYq|PF!S=#WiqZW& zx9ieGUlWVwjO&}4uFJ)7$nkO1_o+!fkP&_pbA6IirOAr4k=(}y{^_Lik$JZ6i3f0c zJW&-NptzlCdnblpQogC?sY%L9k$Gw0ih+$jIfc%go^MnFuca(6tg8?HCBgNsxo!g; zn3*ztGsreD$>39bzxmV0cS{8}Bn%CtzGh%|%h~y+^sJ60 z;;t$oYs*KuXL8Tzi-ZZ^Dff74(m3W^)CVl zEsd{-eXE(>Rkmu|;4_FEPlj)XAG9M1YV?LX@1GtYbjZ+xlw+9Y=*m{mZN74#hajIh zhK?J2e+~`e_Z~n4zh~U}PApcmv4Pa z$&G;vKe(g*7;Zlejg;~A5aB^i$fV(n7lr?qeb2}(YWyUB^vNvsO;&~R5^lNdv-N+{ z+2GREh@%0g-aHc8LJ3j)WkPzM+?Q-}*w2{LX4Z zB3P^@W*6q2K84xR?Se>Ri_iU;<5T7ZW>i6HC``JYX&(9tD`^+G|0^Rr3n})(GI(lm z+dKC3Vizk`x%Sd!UktKk3UEPJS9owE)-2+CsDGEX_=l>IQ@yg!$~>x#h4^#J@~Ir~ z?V*-kj1#4spH5OmfA=Zd7)|WWz!V%aXgo%ef0Sy+}9wIu?(m z##O-e3h2*Usjq?aT=gnCh9cWH|0zf&Q4U}BSw)Y;rZ8Wi5N~vzl&s31${uPkz@HkC4~S3&y-P*?*CBP1K$`_3782Vdn{L(2+qH_4UeX-Q0H@G z-q4Rpy(r{bT6_5KE8oQKTuQj$9{jhVz*i5@z*zDWvi>rX9!MV7#&tI!pkJ#>t8)z+`@HONEkUvZPfw*rUMye7GKeU9qY|+!D1Bp$sig^f%Rh+5^LNZaBe8Bq1 zAd1KTu~K>zyMMS?y}Z)5i#H6pm{x+tEckQ}?(*`(tTMux0s_+ayX z?yLh&A7wZHzGyfKYD&4Q8ZZn-Jb4MjCUUw=aw2K8Awo$U zWDwtC6zmYL8zYWIGN0q)S+~;|gkT$oFpW?@MqxOVB&vz7kYo^oGzh|P6OutCFo3n~ zDi(1X1~;J)Wy}-QWFzT^G6+MUI5AP2 zq|rw(W@60VIfoL)zSnM}j|8F4C`DIx?skX0m3mICB5Smx+D z-8mqNa7a7=;+j%d#z>crr0$e=5;Ot+`E(e_FWKkd`g}0r1vnjY{~FwZ=4I?lSn$hG z${Z|h83vI=JPE;}t(urU^^B#)-7Xx!0)M*#<+#tyV4=1_y5aC#N}_q z28_Tmxoy8@Mb8*Qd!Qd%_@qH2 zOkUR;4*!wx(yCFAjfLLU3Rx(9?O#05yb){%zr(}E#B}kKBy?ak?4mWIOwhFjD{{rK z{Hf5}T%CxEylA^-P%F|k8*Ge5nEKhE&E^MtWjA0&^d$QJ&!t=gS{e4qJ zi}EiJF$4&7e(F#Nztl?w-#}ANkT%KMO&Z8`0_aZ+`c3W+eJjon3{oGyC9xg^eTXgi zFsa^R?hjo>mXA~R+uU@myDZungW4$sZD%3>^%K~}k9Gyxdjn?7td}}=r7h=~uA#yo z{%AD$xdm-tyuB_+THj)!*MI{wNM|Q7rfCxMDT(Qn#AV`^D{H9!8*sg>|vq`pb9Hd6UAt7=iV)-)@U zt>@~$ZiGaSZl?R|!rXRkT0ZpUDz6g>)-{QcIiuxkk`l4(5Vy62rr+u;Z{qd3gaYg-DN^O5)TYqXwzh;UA(y#|Z ze=jGcBlq$>jNGR?^>MQ|J^{-@Cktcn{%=`@YOf#);lJ8k<=zsC?&&BJp&cim|6RHd zMnp6gp^bIZ-nGS6I1PL-jvJ7J7xNDO>tkFcGZ8!orTe`<4h|kSL&uqNQ>iU>=xK`^ z>cb|^pAYX1E7lHM%RMd%tyn+3p9u;t?c-QIb*&HQEL$FqPV&C?(8;j^Qh|i+8M6g| z>hPb_9o_0*t#dpx_zcovK1O10AihWqfKp=~IWw~je<#Dt6NCY*|)O zwgB#k`l2foE(7<-&!&x`+=3mTk(l5R9|m)v;|^%lhqVwTIzc;P>(9W1fV|9OWHdqC zAu~|~{i;vlqy4abV#@arSgTc7*da{l44!;6DxU*Z64W0h$Fds0D@fi?R!4MoVj~}S zIf5QTn*AY&aiARIlPy??EL$*~VIKv$Hb?#YEUFYN0{;5y*D2=hjFuiK8RagS-1J5) z!aX#08YrXzMt^2$cqU?-uHDmBmxjgP8i#xNxnK)uev->+!Y)Rpqs-CWT?;j;&^z~pl4E|J*wr-#9*)8}L3H>-{z_ig7A5H3k>mNZ%=W&OfIE`I& z{>I=A=gA$#P{3$}p356Jy04^hVkfx$j6nkPT>JjTr>?L>?yii&Xrm_P|A;K?u zK!ZN8>bnCdF-%=mFu?--z`p$wBYtAf$fk%mJ=Uu5yw6GS>>{ z;hGJRE%0s`QMge_=l?wPNshh$>|afI(A+Q`!b8v-hCX-(mkM^AvSIsV!~Bmhf5q!* zoh4xCj7u8H{G8>YK`Ok1ok%yr!WHdjA5bqza8Kr*A9@FWduAKr1gafGkgfn-WHSKi zK3eVUa0Nvy9{frYo&*QKwxo+-iIY15XH>y;%LC$9r-128fchy$rk$V{`~eC~AU2?b|%?YA9x(%3Yv$USIWv9}w2Q zgg;KA0k6z~fkv=yD8e%kl;Sj>mINP06Ck^!GN8Z6mp0BBa-3xal--wLF2=Uq^qo;| z5F#`Sb%rd%J)T?&+ns~Fr}_EkbP+baZ+60+;~%YT8ibIw4$W6ISv4v5Wh2;hJBDt2i86mQ zY>D2pe!gehv1bqC!yR~72ngu{qtwJiP>j2sXKl(4r!qEzo$haN3+wN~Zx&bC_@++2 zLWFs|W(~WKuATd?Lq_xF!c$S`-}>7vc0zvCg4-lB|8QjF_^Pb0o6q+oMmb3g3K99Qr&2@PzzcVrpLncMQLWY3ZjJOS4(-&?wwr#q z0%f~P2|h#er8|J2^*c=oGMM+e*8=3=R>SC>9kKFDcT2Rf1$p0l3hu3uxc420z4Ger zch)`Baa2kk_t1@Esd~B8A0XHkv3%RvWG}?&HM+&8)4>`Bdy2_ruw^^+`6Z?k!&f0@ zx&GWLc!Bkmf~1Ypmp*D}JH$FR+oU>zGvoxPJ68p#ysSG!OPW2>3%x_(u-&?b0_*(% zoNY)6qlP+E-%vLGuoO7kE%8}_eOMc^-zON`Z>oRO5WTd)_FO#WS*5t%+6?H)q19j# zlBec&ev{|#pFa7Wwr;|ML?hq{bj?>$=6^%mxsHZ^-^aI03zZ-l=&)+(ivLKd3Hvu+ z0i!35FQKdAy$&xaCzP8FgF@%!WQF`L>Y9mKR-PDi#`hks@TU<6qzc*j7Ul$^i*-$f z-dtqNC=u28XC`#vt!-z1j;wf;#GUBWF&b(DTkB7X$qQXpZQ z_gW+Amd=CWBCSi`+cxjKrza1Zkf%t#6?$}j zv@GD=K9ybisLR=1iaPLaT84?OHz$NLgp21n)!0MtXutlbZ09SW1MAUi7Zg?O3d_pQVO2>n*c58%--x zINYVbAbd9ca8~uGBIHJTZLD>co_@0JVR zF{rPXLSm1Xf|-QZ)?QK&wz?(sUsvi{rY4eqR(Hmhd1OKtEv;}r@g=*~f^0?atj+z>129I00e<*3Xk2~8y*ADVG z2LE`}rx`jE%B2wUQ!F%T|Iy=1?O_XP2LBt{e!TMhztDC?MSJ+#>pm@NXnUnS;%^5? zJ94|PdD{EmQ*rI6y>IUKkNEt*0BInl(0YQN3Dj(#3! zNCCD`JM_tzLZfM2)m$~k%jg9RSC12ew2Dpw%8c4=1at<=t*ZSO+Gbq5P_0i5Z8ynY zKTfpzFSLDef{azEE!nbf(c|AYi}^{+gC(fy3*WxYNvAfioqEV*BfBkdJAR(^#bJ-+ zjr1oSX2Pshs(3f{k>vZpvL@Gb{U^L5DK?^Ix{gA4rSr0<-dXf$-lfVOHK=Qf3orQc zH1`dy{gJd8n;UF>u7o?r)4R1ippQf@yM8rNB>Pz|GLHD?dE2(7~+ybU2 zpZ1B4d*s{_7ft{2-Bs$|yU+QG8UIgcJN#MW|Ae+{;Q>OPyP{XeB?c3+GIE_MmRTskfmpR5bD0I72PZ}7T^JWaK z3)+PDZiMK>%M>XHWm@AX;xzG}r@_}*D1zpey7l1PQ(9N2@kOa~1oYEt=`(ey`1{YR z;dd_g*a3tvg5vO79m3fanoDa-H$?C(m2m`=zYbG~Ec8OT9|sHHiWnswtEk!prIXCb zWbIkHUAb65y)*FYl6OQ!D{fkYxU-yD^$9xy7Vt{rNui0HMiIW5kLA+T%@&l0 zn_xd-%Oz6E6r;HJlod$6Y*r7~0gh+M+;CK7bEf_MQjE1p#9jBcKS=8ot;e=?Gm$^h zDdQ@%2SJDF3bLaF#Fr4eVJcWr&wH@wjG5vO)CRj3gh29g5BdyFYYxK<*S=QrG{#R{+MVnx+ckV z?{3ljC4V6-XN~y<8#v?qlF>|L~l)c~P!|&vE(qh}8vt1B39d z$hL(FqNy{B5&u=4o=dIqBdMQ ztWC^EHRt7`cX9=;zj@VL{<;0l-5^&!qphgZsFo9qpeDa!U&rA1Nb1>N0lsBH5KV2i zkx*8vAP%62#s!&?LYzn;d2c}RByc|cdPhx-_juYu3|$B^D^CYgua2ViYbQeAb-W9kX-xGq=(-k6wmgh&b6u!aqg*O`f z(cMbQabe(+qB6bVjT;S%jwVf;N%J%ihuyfu{-=g9AJHg!B6ngSO`O=|tAzNQ+d^3w>pnI8=V=lIJi)Lo zu^^f#>$PrxE=mfnR7=YPIq(uOM2?((@n96lTCFlK>(=f*>b7jX_e!-NB&h&+m47K1q^-CK*2H4-)JL2g+acYLNPXMcthopP6qA^bC$f ziVcb4e7TL=w~dWOap+03(TM2Kp8pyg0n>KO7{1`;ju-AY%Nc^0q?T zZSOH?;QH|XH2*thQ`4;BVP4j?9=*MIrc!nZ+rsOz{$D8N{J$E}#6w=w+NtN+YV4mH zP1k{B2C?E=b~r7)>6ipLTFopSX#|i;)O9fls2m)2dV?zH8aM{QA451|AvY&)gE)A; zWPthRKK|n|+b%LqLl*Ev751w0d=cd-6(Xrm-Fh}n{x>#29+OHSF$lK+0w)>l)Id&Q zNlXM7XH+rM2?#A=qJQC;*-_(2#3a4bD!uGRg5z952zjJbr|=}dpOR!;$n2Z@y>|H1 zu9*mZiille{ACC!fNz^Ve(z9U}r%b!XEq%N&ByK98bVK_T|?(74&GyuVGA2 z@Sw3rV`7-3KhN5IT%qFHmFB4}pa;}1%N`5D^EH`+JjUZF>T?(_RffmJc&~Vm6g;p1h#4-J;+(Yd31VsOMxNF$`QNVr5|}q<9ktrg}U#b zG#Su7oE|aOO-LNWlzsRdz4#m&C#VWA2*V)fa4KN{BRs}o6(~-`u^!5>T>ts0)?q)} z2^4UD%+T>iLxL>dsN7rn#B6*t0e6=Sda#O(62x`jaTclx-qsA6w)95U4ADgTfH{x{ z4TFmBl)1_MYtQER83>Fy_ETaL!AX;EbkfU4?>=~_fqTjozJ=S)Hb8?WoWYj&1)3fl zK_-e@oa*jc2)$#=zC!SR>QI|E!?*uK`o;of&tDf4cH18EVCut7UdKZIy%hPE5BP5{ zXz)L`cUh?E$@V2%foGl=^0^ceUGhGZO`rS3@@AsZJN?<; zV~h7@m-)LMrmZbQc3rM8tVqtf{@`d4-yv8{Kabg?1xjiw2bbN zO^~9x)m4Z`%5Ct_m`6ea);cl4^{J;9jpL2o+~P(L&w~^n|49Zv#?U4RUyG6)a`{a9&!VbBrU=I#)C;HMy2srPXYn-;T+sfB1F@S z#p3~FvR6V*ViS@6wHo#=l0NDoQ)ned2plV^ifu|az+FK>kPU53X$=Vd&=a-5?tkG3?!$;F#(TAt=0i zvvB$xBu_{b3wy=s6JP7-`N;2gl1H*lOQtW8-p)Ef7h=bb0tFZ*aM9qR@VHkqxOxwe z(TD^I{%&VzPwXE78KzQ7*$I7QVMR?{0e*5ayku#6PuR z>zlVCxJrTfD8R} z*TQI>2p}zZtRyNnG7Kmr2%zxMBzQ{13Qxu-`=DZ9iRr=<0eN7%$$QwtIP)04t09F6 zNOQguT+cs#Rzb|e-xwznZPpRiO{XaS5MZ{2x`{|sw$k{?@*GJPYHZtX?B7mRy@uWj zF`*xa?h|8XJsSTa{CjEq zG598XDEkjQem({KBqU@#3B-WLCu#5{as;k#+*o;JY3+Ii?4^pGXhH~Cfju@r5r)8< zmGOp$2m^Awpfv*peVA^0DUm!5%yb9~&r49xqvt@;a)n_WP{5mlTY~+#+j!tZ?0#bE zi%>B3Dj_fdJfMt7oIU}`;K9+T&G?qscy1^rrsLBj8CN1iB1ZQh@*lXD^S(z_OZX=hFRx|KyqJ=SzbUU*yr?q*H#cn` zD@MH0p{1y!=q?a}=zbjaHZl7J=UGXsMW!{H!--h`BOo7R@_>&g!@^Nq7Snfh53AFnT;^!>X!{Vw+B z_ZQ8X&y6Ul{5nrWJy~Cj_EYOGia#|h41X?A3EW(_c`@~+)F6|eg`@0lwPn56v&S-y zDgkfYGmS!zeSVPNh5p;Doc!w-)e%8)tU7e*PZu-IId4X9{%k|9$nK9HwyA}@P;b89 zQ*@?&xHaFGDPwxR|EcQUYquG%d}<{!Dfy%rCJ=Ve)Dm^z_qeD&AkF!kuBgFjH|-5i z`yd=WSCtEYyvpNm7V#XmVa^Y@y;__fuD)pE_ul-}bKj5SJh#YY(D`6adnb(47sNf3 zc|)4_d*!G$ntirKB&}?FOa!lUyjT)m^VWdv5m)i#WB@*UzlfRJIWCo*%X14PtLybn zEH`6(;fo_B0@LS^`>?=fMti?Sf#cdT@!R(ZG20f`7^x??VeMMi#-#kH<0E%t-YF%C z2Qe4JCESlHKfNrZ_yATC-%Cy*0_tC^E_(Q#mfdFIM&As)osD$@f=h>f$2nG2U2L_~ zJZ(I#uBq?3R#W@-Yj{oFyZP3dS08qcYhHKKsn-%evPRU_e-c*r)svx+GqqIBmoDs;l2$eZSFqvZ*~R(J-j}@l+&5wteowz~yt- z6B!aMQxSS2B3bk9rI+RP5;H-ogtFnFQRxmQ%TYp-UI4I%gU4 zcU1Vi?Os0kt?KpW*_D%11+oqk-z@HT-apf~!pHglhQY8i z#W8au&9`RPbK}O9ZykKv?aaM%rZnlC%om()aLLyLJuGy#usiAd{!Dp#jnfAD)rJD# zsJ1)bH?x%NJyV&(Ftv-gUQ2UTndN>~edt@U%vWN^r`f1{b4yf1bvfU=UClkg;@rbD zO(A+@o~P-$+0X3z!)j}F@6W@{L>#iRQ&rbSp+B!t0_E2~oSds~T{3^We@`el5LTTk z-J$Vs2(3=h*c~zY5_#iyrO8o1r+0_u0jB1_R1K%j_*Kc-9Kdq?yQV|yWaB+W>vVen zHgq&*-!P;|d2f8R@LQA{Ti^km1c{b`{+>h?<5IO!`#&9*3w@|LIbn%T$Q@!VXPY2{ zLS-k*)wt-fJO&w}JdgedK`~Z~z8-L87so4N5PDD!a`R3_b{%p-0M;f1RH^Ld+ri^p zI>FY}Ld>YGG*K>_ndh%E5n^wMNw{n&UAVF?cZ_;tK&cbzJ>1A(|c}H~ymCi?!O&nZ7A*Z4el;xb}RfIw70Cc7d5<-{cQR^2o+?CZp%( zg_oqhU3c4tS+$gM%$~YE-RXJapV2_AQPH?`ZM14Q_++5W#*xw8WJzKu3fyXS!xlO2Qb}`O_CX%MDwNl zNeaMGcoUoIu@|k$S9sM-Y}bWg5&c2V(9suaU!5Ckz24S1o=I7EOHI^gDAg{a*lfRq z-_y{f^ar%xz3B#3f-$19szN^0yf1CZ_(m#w9epP01dyKWq?Qq4H7`G4W4b%=LR?dl zdUF<$wrOj+9^{$D=%!FJH5Aa)fG$3}?4h*wZA9L(L08PdU%ck~IKSdsNyMPNEYpvv zuT4!&AFlWX+Sz@1pfB6&f5kga+FpH`A+J^QYCvYq^mMzvDv9rEP+3ja=U37JU$U=; zG}L^UTOBp6_?i~dEj>GjsBVkDB@sSaGrRYu`NL+EOyoi#8GW}eFZKOq*uNU|&u{t7 z9p`59S5v5Ws-TZ!b4Z7=> z5t(5<6!EKaPfTm)*&D(>Ugg}rUeNgqHrmoF!LvnZiOS2&%pKI;dpESTYVTdEineOj zDz!Jak%%q!C>5KQ7S*CgW0e{$ikdAgrACWtQ6o=2-|uVbn7yKYj{&wKbDx>ISpSO`0hcP#_ z*QzxLqaa zdTVi_r8JdXA18Yaat*NR1T?Rm5-fEm3!}65dhzp5V%GDVDY~?Ql{=E}EQMv_YgtSB zlt+6E*e_Pe3@T&s;vUqJa=5IBrwPa}7YYO=X5T8nvPQ~ouIh4My6AIP9?)>`t!}PA z@=1-(N7mjDJw~3r^gxyCkcTv>d?Eg6buROt!Y6Lta&}9{^_lrJuUE#eY z5##;rcjxDlYNanq6Lt%~^D>k-_1d;4ZrUGKUWu+YRNtI>B=g5zZ5eM-raY@|_b1*# zb=x8I>ulNlpXWKHu}-1i=SH7_AwNsIi#+dLUjjefxhC-=7R17US! zAE)Y7c3i*u5`XfV)xDGO=ixs#Qjyp8J#10>PyVZ`$?vIBcE20Zze9XSu4;=-0f1`mm_g{a}7iS}ov zc*>C5PzOAf(Jd-pJn8@MEm#a5Ze#<`z*EcJq<)O2d16iT3{R_UMcd=J#20rD(49Ol znQrAp10y&#BRU?;Sa$})eQ52uS=6Q;bGUu@8qt(?E?bY8hO-JS;fDTOq$@GO7iQvQ z#Kq?7rqAI?8|Fi0T{t-2fVr#kzVn^F|8&1{tYOGfiKrT>UIejH}oD-a_a37NC7xZE-+9H6}|)I1|CbSJG<8Oo6ZT(eOh=R-qqPk07 zi5X(WQxC}YGOt0bg_!ilDrMvJg&no89WNTUYlp9*RZN782Q-Xx8E@XL?C_yM{p~jm z_^RtVMPu#yVv``DB4q5b%E;)7Nh2_s=Fk^bXff)ldGr}t=&>vrj4>PK!TSx7f}a}) z)Icfc@Fk4iGz62j8i$`!x28aJS*S+!^1m0c1#VL;ZT>l z+c}@z)|jr>2iVXZCI~RP;XT3i`yL}Eg!y)VOFeY;_e0&woBetJ&?df=Vw+C9W?Dub zKP>99Z#u)t%Jrk9`u$r5z>9uy$7;(GJt@9SwL^+B!sm_UgvW{op7@gA||dJVdIK?6TJjOZ^G>f&}>>P2Is zo<0&W(lcN;_N%39$#7_v8l4dJOoNI6J0D^t0kh5V9{P!`2BURI;a)>0+-FkF=SWd{ z+Dv-SKzhbuciUEa)_3>2hxDhI#+5MXxeV#0q}_b+)!n8gJ#gs>XSOut?arr354{Nw z{nk~Zv^Di&%1VFEYZGFJ>jT;%B8VlY@YlOcMZ4HtEvr6W6I|ts3rKmiYxsqWK*k!D zLx!f$=ey68x)f1UctuRFo$TopG|B;5UQXb8*KdZB{{95`8e^;0zMU;wAUbg*(RQ0>dV6ZlfJM-B49Ycb!KDExUc zul(W@ zoZXj+m#|$8cpLCJF@|i1=v*)xpKv151i3f1J+%Y50irsYFW<#nrgYyc3)@xJ5t{Tu z!6C_WHRhw3ChA9q`!Rde&zllmFVnu+%Wp@~eL%HOUZ(%zH#&@B__c@GL?MVx;m0Td zAv;EeLh=%2N8qxImzzDrWSP{P*%naDH)LsyWiQ=p&R3LWdAPrBC(8=%FSE+R;qSe`nz8!fkeMef~i@d(e032Reb7 zc6CiST#-GWp3U*|kdB}&@)y!a0R{<;H;Ap6y{i@e}`qOJNw>;1yZ79-lP&mq}Q(ENS@?xU9@1e{5fuJRm275!4xV9(3tS{|5( znn6im=5dg7c?L=aKSY}!tAamoo4=?+z~#081%*KMwm^M_pc`#Lw-kc!wFSE?ggk5u z2~`LM+d@f42AOSP1q$J1ZQ->F5zj*-VDn!;%SR2hMSW0+{?r!zCG_^g5SKvtn1Ys= z%ON1FJr%bwx zO&JH2kWXJ_@$Lu4J{uEKVtv{gr>I1~XssB&rMpv;`=u!}E+jv+qX1MY#DX1#nMy?k z9YtkI#kC#9&y^mvbv!CC67LCzYxhczoIoG-bIx~A-`29-KKWzxQ2H#v=ro){v{%Yc zsr+6ej4!-G6jk}iyz+*0ZbyHx7&6slp>H#!O5JC;gR3;=b?w8~b(zZb1+VMNl%LeT ze)3%TY1`|kZNojZ>4!RhnnoyH7PAV#LU4aD9zO|7t0r|ChJ= zUt(MN|3hp~l89}V|0A~fD7SJb5YGyn7LkJBler6;|4nAg+z_9R{omr~L$?x(=C#qn zE8h7HKkh-A%H&gdOkW=^TTl$0caM{JLH+%#-U-?YhU7WzBa{F{8o-sSL`#ln0 z|2mwb-h(g4*xHX>nDQsB-g~gF-Qh@zQu!rFGHy{_;YCEDo3W=TswHpR$Lzp6Zk})I*SI$+wuY0wl)y+a zqnk7lM$E7N2(^-H-hN-d@i=N$zE7Q(?y#52;jiardD7QBckKb;t<6f@+rhaCD-mmts>1tE ze%xg>pV+LyCrUiAdz_)PRbN-*HRD${J0S7&$^X>7b-R_h8cCq`HuzuOd;2+oN^Zw6A{yJspV^TmXkWaEo58}G&^=ZC*pg1XADA1pHA6m(g#mMJR2ve z%~^x~XlNi@QY2`LN`ZNYPd=e~mzW1Q%r31F$IW3>tE)%LXjU)=xk7n!Qdg_SF-Ys1 zw`dTx)=ktvyrw7TGo_j{%8xHBh0b0atw1mtFTbS|bFkVMyW{3iVxbJlUPU-K{NAp; zbz;%V3Wf3zaWUqXZr+h2Ut+HpGl#{q2}NqAUe5ieenD*wU(DKgrdl@J6omw+R)Ny|E%lh!bslhy8;I5c{#2@h)X9!JzxPbpxDZtNdji8<*q z$6K|4S|01%dy`a#23L86e4Y%KP$$EcE>SdQ;ar8ZT*=$CNSRfP>${n*@_v`S$xOVC zy<(pQGZ?Zr#{KhH|GL(@5v%TRyw9VmwOo~e{O+lIBB5HwsmR!&rGckqVBO-MW}^*< z)s?ub$*+`WUwoh(Eb3Te{}52$=xP6=m}392{EK(v4iSNmzU+u7R-R<~bN?KzO#fm`1=qCLOwVDm#YQ)4?O#5z?S5kO zVq^w%)(I9FKZZSowxolu5Ki}Cc*?BT?5mbPjlSuUw?~Ztzv)Z$Vb|!4Z&aj#V*LhA zx^Fep7Sj4S{x)HB;TF}swsC$CUHFg0yOb0R??MtdvxSE=2(oqs*8S{6#UXXSV?4 z$QfN)S0<6#(a(Y^jhBDex4oX5Y1EBrws!OTWbk?SXXv@|=e_vQE(rCudQ~}nxx9_Q z0wGbp)&J8wFB|@lQYm*Zd!*|ht5JI1<&@3afNvq1>zhVXJk!_;<@NSnAf^c|$mIm0 zhrhjH3mH}Qt*}l2Z28~}yBa#)IR8T1YqlM~G)DN2QgeDA5sVAqSE6dkzA?hcV+MOe%A89BHGG%--(&`u`zZE6s8{a zu7aGuOMmHXO0mljD>+@HTdO8pHVkju+ljI4S1b552I4Ha@ebJQvlgyqkL+(z%}N!F z%HmSf>3E8h4|SjsTlU{v%Z}=R|}6$PO=(gIwpQSZ-=6kQN19w9&I; z8GnmQq<6i%Qxux7>k$#dz^H$5xzP-TN&!1a6UNmL~ z_(%#aXM~n+?B;}AANbfV&=Q71!0W*`p86K1@?`&`99{(Dld`WBZ3?|s+(YuVz9#T z&tvG3`A@+4sctuwX8)@a6hLk6NPhLkO#!Yw#1l?5xq9}Lx(*+3o6VI4Qm)}Hgn|aS z3az@Y>W_#AWZsOR5-{^heM>A4j(@P)#~2$6bq4-e&r`JAU&ho>f87Mp9w*FV9M}~} zfd$&E1sN%k;rFaxWA8S!{G@*e`}F+l!T9w7a{Hslxj$t9c#xKr^)q;GQr>i$@yK!iR;Cdd_}MokM~wfI$qvjHI0r^%`q-hu3NP0E`Lb ze_w{eFVh`Rr8L|&`YQ&q5Y4X2{?0k%5g4d>&6;xK2z)@!Qx?etm06FH+GYJaIn<-~ zK91o9;{JD%y|A+YSPZ$uRl&GXfZP!ULO&taZ-M?T^vgKUa!g2?I~zg_`JRl10trEh zA^~%{Q$FBfHhdq&M2Cu(+m9<#0REBrT4r-Xn(0|ZAiJOeh^3ATr$EBl+ZpX)zOq>e{|(@J1;81LRxA`zPGUDcrk~wIa48_Qv1pr37@|DX zNf9H>FZ}o@z}Ob(fLRioU^zp;(L@v^F1$$(D9ehxH7xq^R#-u^k+DZ4%qf9#GV%|B zR(X#{53B`*NtAE~3ZQKV)WsNiRzhfm0WovZY%n0D2zV&~Tz=3pxVc0vWzI2zbB{6_ zE}SOsJVNdlxQT&eVVScKk}iQK<|))ji&jyjULg`1eBO81U1^oFNy-0a^@KLevb4tmx0bCTkregZ`r1-*fIhuWDZRh^L6R5R1BYDlcOv{{qPxm zZxg&*C`>J(-AxFzSZ16aJ(aA-EefA+!bf zB~ZI`Y!o^a7Sik&C^{7#|MlxTM&y^X|HEZG)bs}J5XJQc0?o-Kim41)(no%XKOsQF zJmVRe>7j;9nG1$-A4=I<2q%98U5zE;i?j996U&2hPgqfe{MYXoU+uAXAF+?zC!_F3 zaMb}(-~?hHMM;k%lQYlyD+W*zlYvkinM4*@)gSiEJp^=*loDc^*h83z0-{Oi-FY^; zHYf!$JP}EEdL_?BA8Cy8W0MWNsL3;}g}qJ=Pu@f1wZkZ~Xz2Y#31ng=O^NK93}>F` z(q_h}cA#(wR*C1MUlF>a@F++zl;kix0b}WD0jReVBr*#^ZVikk7bB2x#?WGFe)2j; zG`U0>#VUMf174;HNNSJ=n+H=NsUf}49d|@#Z1~#~L`4VE%$#}|hlrdY>z+trYo_{( zqNnXmA+E&X*)SCRlz9^cjWzx~$P`n3sMK3BXMU*r50;S^K;a%jDwdiF2dam72GTiF z9qbhW{K85%kpL0Mq$DTL<^$+rp^qJbG(OS7~E2dQTSVT7_uI_a`<%1tv;}uY6NQfqSt9D!num{;+a8Y7V3YqXyb{ zQUwtQp|Bu>T9CiD2Mbb=^}s%ibzf<@0LUey33-zB0#_fZ2xv9s5@YeGzv|a?u;;9stWU5!_ydE3z#P?bH;_&)<_* zQV@|a=xPhszQ`%TSv-=FGqKUM;z7hpK(_)njfIUh?8T+52b4~ap_;JlHZnR~iO?kC zho7hr5=!ztY;17;HP51GCL^Vdq$lnbN3bB9)a7*mg%PBDn+lSkMrT3UWCd0)JX-v! zx?bTAek7E!m6PmqaZ=ytX!8)CnI6$<*38sPZ}QdF{9_z2AgwYlFUh98oWD}P7Ml|q zv!5IgbTf*q12N;+@k1V{*C~bh#|*k6+L9}7ofe-@(BJ7mdg4>q^cf|mXt3C-Emut2GRxHz-PhHL6wk(b2lPP2W&ak9l|LQMrQ^{|pqr@OY zs}MjczkM@CwzZl{epLNy4-lXxN9KrqT7z$`BEBov-exmheMy7cW*p09%8Tsg$}#!3 zXB_#+)X^*L<+L=dY|lKS0mXXkOslVTEL8EWx#s8Y$LU}f*ue%)O!WA zBD7XeR;&vT-S6uVK+&B6=c8$(15ez^`xPJbYp?RbvW!R~C9xF>nX|rYT>T8I>8LbT zr7=PeHIsueLlmLY{}hmq1YG{~lZrtvM_D@+Z)h(uafJ5R^S@Zd$+hop<>=7V=rIDB|*nD-6%YqKPP)k~2h6j?5b>mD5(4_*rkpgp$LjdzsXP~Aq8K=>bB?|(Vc|H8j-J~Y}PFznMA|9J4B zIq1V)+J`Qv@h^=JRL$=p{1X(K6GX=es%0;hv`eqi1XqHZDB zyCf?{efl1`ut7*)F8BS+L+tYV%*H( ze8!P`)>(Dd)pYiF;O*_ZOxAa2A1u%Mp3gd#&R*@Pdu5Xrz|9OI^FHa+eu~%yqPjoD za;FV4N~2Y!lTJS+anGfc&ZUiahFXM8EBL~Y^HSY_H#M?=#6w3jAMxddc6(l5VaPk5 zf4Wp&F6?{f)qGX=Lc{rBCEo6)3Q)PU5U@iD? z@)UswK1OMjFv@;;;C}zW8}ihz{%_L+l`KT&sDq;UF@&5ZRi7b<3~o#AfAX}O!imA^ z4Dr`IYBPd{J_1G|OHId5@rTgPiF_*W=m(qpYV!}_gObYI`Z{xh5GT+$g|9Hh(L(&` z$T=U=tWrqTfxbi(wZ%TJ9L&0lc0AIslf#^PRr$NSS`hD$T;Z2RC3wzqQck;scZ+}iDc`daC{&aRB)TPQ}X% z#*&1+ZB79iCZ~Is`e56G#7{40Hi3z~9|I|jSp`OPSODh+fv5vo-mJ;bm|-+VupNKd`l_>#-Rk*{Q?3A&jbiR-S-gpRs)28!v*Vh z?(l~RtgI6W8#@`m7Ao+p$yd_h8we?J zbzJN<^ZoMNWs;VLrhLuD$oxbRxJ-X3yQ%Iz$(&?g4(UCml#S1HL^y%!04W6dj29k( zqCIIE1e{JNh?)(F6ZA(Kbai~|BkI7YBXt;hBN2H5Yd#@P(9mQcl|Z1AP$byg8E%A_ z2L^R&smZcFd{)2x@8aBe@YhNoc*yX%`5JEZ&2`xJ`HSg?U$u;2f=&sq_8rx4&~aaU z6ti46%Ku-8`#bo5>8+Tvf9EFQQ}=r!{>k_rwl$UYlpP-IqB-))yD+DZFH(n0MlFQ= z8g!OcoN(wlB;S;Do$<|sopPk1q;!@0B~}KBxaVT*5jtw@Rl_N2tZTNOqoNma*lH=d zX77sYJza9OEY6CXjRN+2CMnY4!`R2F*5H)3Kxq#?gGiaLd^}W~;CNiF&Ak-{#j?3pV8kl{5XGLcr@2_Fi#G~UPXXfoa!fKf#%U0jp`$P+DJZ5Zo2*dK%{2QKG zB{uKw2a40DoQY!+o&|R=dUZu_hfpi2BcEl_cCq`F!b`zyv2w$_8oT5h9aQU?g$E3` zhcnaBa`8NoDY->g%n$6`E3LKqZBd{V)qR6J&}?p#NRo3JI}IiDz}iWQfw0KDLun*jz4Yf^o(eB;h4URH;j zrYU`=zWhZKqAwv)@773M3b@67j?d{^^?Pu-8_L~Ub9!L?^!(+>XDv1trsNey(`B;#5&te3br}*x3p%+U*c~ux+k)cEn zOizAlSk$fMU9P8&43(^bdiK}M#{@rq)gQ@1N=n8xla@IZt!@E+MWZ`AxMVTA6!rLd z4qIQk{FXJh|LJXg7X^81P3F}v#0mvvFjoo0fg10Sd6WO?Z9Oo*_Q!vGx=QcS%KvX~ z>+i=hBGf~JQrSG7Wf~77^|q9#jT7Z_%V|ixE#U}$tW9en(|^6KViW8WAyv-*dRr1@ z8CwB4tja?MASt*7&3judv!14_Ag7x@J6*#c?P=CVJ(%+TFrLF`!Iae7V#xblEl2s? zFlXy=-sW_@i7=_RWn^CYdb*;DeB@@d^UPDVKlN7s^|nUXt20QwEy|6{uKu`}eXfl@ z7|Gk~|1#UBf}i>ONNT(KOLaOkHIjN;a)bU2w@_=~C5-frx?}U)puk_=3^ysFiyhaabt-%FN_kMawJ9a9i*J>QanTOE);2(DhyVmm!!nx8$qi zMFeyZ3||)~ik=%6H?i95NYPrQYMqL+rhsbZE$Y)`Jw^>)va3x9S=9wR~Hk2B_C8%hX4X=_;sdKr*Rouo1m zjlYN0*<2gLvsiH&|9BZi+xFw|K4p_`CXv{$yj&Vs<(l)N@BE%KBZctPSX<|!I>@*p zIn~o$JKC1Mxfn?v6hK&r$u7`ro&YTZ!5!0CUO|EFY*2v>Zq9~i+jVtK-l#wLqUDyh0vdZ`zBWeG2|n z`DbBP>k3ri*0H`6!xW`$(CS1q;PW6=)%*7C!bVDwOlT|eQcy0}9b2||eo&4qpm%R& zf#`=p+p^?T^SZ*@1N1X4;?_X}CqXVS88y91mzX9{f%XI__BEirfcU+`w&;#O2!hn;+2lpS+yi=T^QUu>Rv~EmCU?Vp~mPK1_}xhG`B@t(3s&1-m4zn=xEMB+I6B}s2Br%H1Ar5Mr{0n z6!Mp^!8OG9p|y|xtf~qx%hMk;W$@R0p$`82-r-M5RUe~G|C`@xNSNSx_ww@zr7;WI z2m>Ccjv#~0N_DUpe*E+3=-}b`MW&_e5z7;EOxIRtPimtPPyJQVz)N z-K=~zs4ewZPGftjxs8I*pIuA_C4h=e+_$@u{WSB!VB;FJdqw_)l)<~lQ9=W)HFwa%s-O$40t_luVXT?8`bJ`7o3!Z78{ zu*A^g#M=ZNW2mlbmxlQR>VI}=tSU)&{Zr}e2W;-hwBoW1!3G`vF&+D}UVEXgip3=3 zc1l-5`Nv7!8(f1HV}qdBTf6DOiwNyJbL?IJLHD)B%Oi9qak|6`Y@Pl7WadLzrHg`%s_?Rlh5qm9Y01U&1q4mR6sM-CK+K#D0CoYF2VPg(SRCSV9 zVfs~92Fel;ej5K4J;uAFI3PTb9E=`*NCyip9QI?w5_4%_9Q*iCGOWKM{3SJZ?GzRw z^e$V{6U$M-mLMwI=Z$djGCCj&-LTtTL=6{9c>tmnk@7krt9oAQqUwMRO} z+*xVKdqeX3?`jf8+qsM?ghnb`jeEDLg8hV*x?mra;FT&yfw3dKLSubbP5M>fPlAfv z(6sSu^oYWw8-dC0;cr@7O*rjFF`N2fg+_f1#suj2#B`T0-#C7UH+ne5XKxe(jL!y* zgP*P%_0o+59mB?NCyxV}SAmXXk1JUQ6xdT3F~4(cwF~F5kkqg;hQW{YtBeJh=gqqg zW+kP@B*6%DBipX;cc$O>PLDV^<&d7Sly1XUOejk%t|mIh7YV)p5U~9aw`L1wKm>J<Kfvf~nVpitRz{AO z_)F&Mm&s@%fa~Ogbo+jl2^BuZS`nC33o$l+1usrvmWsyAH!aEiKPc{-!?=NT52pFGpW{IOACnERTz2CWp4p>0 zBNB}tHP&mdkJA)&borowRTPih!M?@wK^=GU@4h$z*jIbk` zPmO0Ln1^V)K+-~XnO4zF_Oz@A?8e!xbE3~7@;H~`?NCAnw#b71b z5-uCe$+AJD3KK6Un;lZ5d;Xy(UQvYK!(T65N%X2twhN1^avY2G$v_5A$HZc<$6_D1 z^6C$Bz0%3aTcNbxOLw}P9*E1&zf1D}qypX4{suJ;KF=~wVB7?u#8@)nU2J3$_Q4M- zQNMUmHc0+pTF54tZO-_qY!50(j#Q=iw8w|l^oPapk)_$f@4?$jaWMTl@(ed>O6wa! z$&^o-?8c22a@>SL!tEGGyRTuXGA9W-B$j-l(8aGXWz(45BTi!zD`!gyP9zv?F6@%M z$H38aVvpqgs5t|vLmd?o9dBpx%@-UmF;&}nA*q{3vp^Hw(VS?s?*v43Eq)G<0Af`e8)8r#t^s?Z0Si^^ z@qMt^azb0KsDJxMVw|Imq(3^EhWhUWgt?G<-f%RmJt3eSTdM;LOoA??Gc8J!V;m_X z$*4e)%|sS+xUntT+ar!dZ}a-0qy3=F1S%ytT;S5H7uJMH?z@xMUeY{X+)BFhFYt>g zA6AdFsNvA_jmwKSCqPGv0P`##1TX$81V{ z)8-M2AS8Md67_u7yqmC_aKXW*N;NOx7(5JJG(xcHF2`MelJ6!+K1`hUoJta?=JW2eZ^*e z>wdq_QvWXay9a}Kq_~nt{&(+uu^0X~AAG-`R%{&=-{s5Vo+O9;&9xE8lI-(Yv_y9! ziGuH=<`ZV!m&He>Y+?5XmpA6>{7|ZQOqh&)%T|-d$Nt zcn{b(-ykN~Qi}U6q{_ha3ibMu=!=~h_P3mp%y2p-wPqPW0xrJlZl8`u+)c&oT*s6l zgK8%JVZr3;+YXty+1gsv55Cm$?v<3N&7?%!o6TZM9d6MWl&kO-Ww9f;`BNjlN>x~& z#K4Ndi}JAojufIOsGlRe!v274{E2oz=pyvRWG6Xa34e~G>graJU;pH1@^OD5-YAf!GOo!5_PJPPFE~K zjI>R_;EOH-*6YIP)chT2sB`}DJ?Ni>jgr`MAaC(5>FNri44|Z-i$35i0#I-&Ci=qT ztLn&ONNN>;f*XYvAc+Ykp`0sm>P;|1cmjW2oLwOm$UPCame@aP%Msv~9JKl4viOz| z4cjT3=-ew>i{iwniTMOJc(|f(eHg7-6YR-#z_5w>I*#1r1aiu^voyRGRTsB30blZQ zFoi>%>&Qb%t2GqY@M5zG7)QIbpk;nH7;j_s&xQ8O${rAEqcnT9-+nysf_c()S6-FDs11*t7 zy4kOmdc+2&BND_OsKOJjG(m#rupF_BqAWGhNl<-7pIQT`F%a*zk}@h*hMYnhz}F1$ zSiANFJA*imy0}YC7@Z{ODm6t+d;Ti;xdB2*J_x^6Y-<|SgaPN|N6)e4_eCU77`3F_ z13r&JR4T3+*7h9`#ZoKeA(VNkyWFZbYTj~I!`N3aR<@AH6_~OCr6^fq)E>-(56cmj zddb1Z7>9leB#IlPHAO>>!f1P)oHmtd#MR;Uig51<28YYk#mB-~Yze&QAod42wxU$f z?R6YQ;kB%G^8QmSXW>f<$Bd%Ka6wdj-(%`doX;`}-oed9B#Ld{F%z~bMmQ3&;_!Gr zw)hY{_8=Tl(2Q2Ei&KT?vTj0+>&P#nx;I9(>%A?}p{) z^S_sA-ybo65ZRVQb6B9Mc%;}LLz-$Hb}*eRDUwLVDCM!o*N3KIm3y$c$3Kw7C~Dc@ zu}?y`ITQkRHunXGaRPz|-wJ*SjpPWD&}~CM9&UQ#_l^e7z-mH_Lg>K`3EkF@Bi+jW z7v1I`zqE!jAADm385e8x`u*4}L8~!fck3l6I{VytC|lb5)l=ml*^3TNkDu?W@ORcOHdyitaUg~D%J--FKD{@6U?E;hVUo_H#c^BPpPmbO zOgz%hktxMB{g`Hg&>vPT{9Nr%B+h=jb^2;|sXcW2=lE&cuN4B8_OjVo`~KQ+f#k#Y zXJE(g&57D=k-E!ehda}4-oM_TcOLDn45fZ5&HNlb{rujdc#;fK#^2tHPNl6!s`YH* zV)xB2qIxVjjUwLDWaid{(niDY%;>+!xjc7-ks?3llD%7|DvMV;KbAYB`!M7uxlb2T)(S7cFQX?vx`3wDe)h%v%gNv z{Yd}VSH@MOIA!@oy5=sKl4v=Ggl=0TXemwPc`H|aP|Y$@7O&2;j}WgZGNYL+gSvrs z8|p>;$`bX}#YR~b#P$yQYhk{>B^sLFM$k9DT!@f-*0J?k@_F0HKktSvuIcyrwH%RB zEyHiWtyP3w^n1mOatZFr&e%svznb^zlx|y&INfa>HP;?j?_#bOZ7!#@{`;I?z%a6jY?X1GnRp)3e`n_{cKO$#7oIs$xfMeQ+;jg z>AjfgBuUipzZ5RHcY=@Z$c>0Tz0=Z8l#XnWtt2`^obP4<12O|j+g-mk;o6?EmCt3M zS0>px?_QnKmn^;d(U|i*NRw@}i%yZUHvxqKy7q3s^UiblKRBf>qv~#iXfr$pEh#$X z7yk#{{xHJrt?63~ahvBb+CwPxE!2LVi=%be>Vj4WzIx(O86C2a{?JNjji{s6v6g2Q z)3ILU($leyGbY_=Z`1@{!vbdszcp0odX%>@2Q8yAl=F<5@5 z61vSbugwGX*T23%-c8^0E9U4FW~Bx1L#8yLg;dI^t&;jKrI_=72V+0~FsmgX3@bJ1 z9`P{*hE@FDN#KF_!{$n=GL-3?lXg)8jG1)+v>Jn0HOuix#gk*_J zdx^?t0&J=})$s!m12>g#?5pK(ueCI%`$h?JeG?l}8re^SCSx^ps%uaO&6zP(Ni`JW z!TMrmg)@MCFtK$99jG#zI=GLeP zOI%~hw{B_4dv<2z&U`XLw40hT7w=e?Mt<$Tdy!Dkvm;Du6OTDE1{S`R5|IP#a3zQJ z`R}7dO8mr43G}YTvt1+wOZ~WyrIo?NnTX<>wY2}x?eE|j_R2*4`=FM<(w`4RRlbOS z2%8Fg{I|hfnbtDRXRjZ-dM2t7iY||148oHMz^>M@PhjM(;%WXQu_kBtB+0i{uq--wAyhNH@0mq+oZ~A0=3G6kpdoKKo=`o#Hl!To z0f!8}Y|dyjx4nnQpz$+|G8#JFKzs((C3L+dC@@R|XkkI1@{&=sxS?U()KJT-mrv@A zl~et3uN(SPThC!KbrHQYEdAVPErTk|e=Xu$<2ARMO1*QQ-jQJ((A+?Y-_=rBJd{O? zD+bEwFxM=u2efs5K9>n2q1*e}q1EG3IZ~q}blYsR%iZX5in>A;RrhYPvFeyQ)WIUQs7)vgqOZ1{fd zMaQ^r%$1UFQX5Ji=lk_9-8S1=S`awXb~a(3)7k1=d&1@<8~SPlFFcj0ExCrUVw20( zy(Gk)L^d%jv96)~;?l9)+shP1RN80ZxI-GxG&}LDA;@*7)Dsg*r^#oL=b4^!{g-c-{CRZSuX2K=fiIgaiQdeKoz?m`U-swE>aSjn z#kpPP-(@GJj`L(Eu?�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

V6V1=TQ0A#}CJOKHGnR+hZaFt0j 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%0D5$GMvAmM1w%&J)(7bGq=4egggBA%9@K;%n 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½>$miiW6J4I`4AgAfwH&#*X6O+GVD+etG*N;Bz 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%0D?OL%A^p0TB-mv!cM}58Q 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

EA7Wi_h`3@?)nhE)@4$@?FpK{4x11dNNGmq61fK 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 z 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≪%ojKoh7CDp7tJmDjsA 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%0A3UbevQJuL-(QeQb1^aXO*&JvDUbE9j>xbP%P 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±`fg^JsKTbl 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�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

4m*)re1gR_s{@Lx^2 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

(+b4NtLGBt5Tm7y^*^y|ozzmW5$;!kn6;7M$J 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 ZMcQK?-??bgd|Y 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

P%RVmWJkt-~rph%15RY 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

!BjmA#|JN#BF~XQcZ+_Z z7slnS#P2Fpr+kapU}fjA$qS%zY4+Za0I*RAQTN? zkc#V(J6GM*xRrjh0s*f?GGyb!_`xW7=~m+cEa$SP=Bt-~gpcn|PYc{Y1c&+tCCo1+ z?7V5*0sFuN2qZYZCHe$i10c1r>WczNlA%FvqwSE(2Kw`Qk^wQ1+9vj?X_C9Z2|iwt zE-EfJjkBy1Mzd4i|Ge^14J}G255}sNqH!Ko0^dap$YONDbaF(ihNNB^7dA3cFP;KQ zYPEnb{qkYRM>K*z*IY_Ow57$?PBH$vfEj9z2#GJU(YG~!%+GF?FZ{j#7 z&*VX)OW(b*X>I^64YYYQGBR>Re{<-1qC|&yKHeg_&BWe(R8Jl7Mj9bPr~ypv#V6OQg?bCr4`U%y# zt$MwMAv#MP$rKXEggx4DA;0jiH8`8W2_w~nD_7q?fL9|!k!`d*Botup9`NO7zW-+O zBGSGpz$GNMy1i*<`e-+ms*}X2{MqY^SZ5gVO%0w|Ne zexP`>vY`g>j44PV38=Tl8hu5gho8ANDRd>(UZK7o%ZP~h41^Nyel~su6@ujqw^*UV z0hiS|lwAANPrVP(l3(w^h%?n#N@1_=Gog>rtxfc|Z^-2EHjjMB7}y?9Pv}8^oq;G0 z%`*ZRL{PMdxYh|qE@^37MHIUQb|=h-{ntY*J#VpV$`0r3o)k=kz{|dKB3URZ!35ki z(_f5w^6kdLlT*%}LCvUMG+}=Y%b8NMSo(EjEO95kk!!EMs(S`tI6q%dn|Wy}@f!)+ z(~F2t9wg)aCMww|F8a-B#?~Cwp2hq4c?*5ch1ql}=jRk_4!X;|xG|NctuUiQ_V}Q_ z!HZgo3BtF#RR4{LQz`C?bDuD>wZ$#UpgzF8TfTbPy@Ot>Np8!Xt768K{wD8~_gJgq zcD}|~c+twHS1-y+msl9QIQOxY{vLgfq2w9_v>%y85ABsVMv9BFg}nBqJs;^KU+~l9 zGC0@Dlfv;eZfzX{-YMRks*HSqtH6yfVj6bt>$61(_DC9NrkhIPa3;@2@^NuJJv+5P z<)U-tdB}hksf|ChOqy0z0xIUn#s=7p4+LFbf_`byg3VcOq)3PSKz|rP?x}P?Eay~` zNa>pqIbaQgtjvg{JQMo-(h~DqFb1A45_RW@CML$W2O`pvC8e(qE#TnGrm_JkQXAyj zWfPcjh9oGEdfpF|)y%?%%-FI7rL}>-v#@C+O;dY8;bz9hNRyH;B#Z!>2Qc`V8PBOayqjj4P!Vh#8a1{u{=`_3?B>6v!}~5ESUk-EZ`Q`m!e3v&?VM zH;;1jprfT$SC=d!5p6!FoHT0}V!vj0Db%XY?M6*9GNyn138)6g_p9PUW1X z2mDCl@SYgSz_fA;@408i*Itq;6MuTFIf^|66eC&_n;O{fMX98Xjd`E4#wYPtqa!Xl z&Em)9-2F%7mK>T4gs*SCGfAJFsoCq<3)x59)OHydQAkLMe4_|Bs}H}4bPKmQ8G+1! zl(!*>NfHeiM8CGIHukP=QxKw>^Zio3M8ah`&8}|>Q$%d5s3U{H-FxGyOdF>Dd)5ib zhY#3=U7njVyqL+yssCn%D&TH5ZdE z%`!~GHgU*IvqeIA9rMG)Y%e_Jl!&9_AZdViAf*GrPfl4ISjgA$4(YV3Uu2{+1f{hlZWF@UNjEx?e+l z+G}xnAwCspiwumD^AVE8=zEU;xow9S7PGJM4eNK@6zLs)^~xBSe}RhG9T4M?S=dDX z_Q>HIqVhr@|$s25>USrCiF2?0i#(z1ne-uuN_7CY* zm05lJ{$@oe3iqz+eR=A`$j6y86dS)}cF6bV!}i$gIzPKvvoT_as5RA41ua_$#P*?6 z%TtLHK=}7s=H-y_mS177#W0IQ3ES)db5)JQxXkz$N&#c1>XOna4bPx|Y*evpfm(BX zv{fad@vG1|KgT2Ch z-^IJ7tB%*27U7VAlWL&!gyG-uZR14mdp`7^L29&E8S$2=_t zz`TEh;lc}0k??Yv=(G81z|O@u)ItI-S5G+u%9Ty_J&I;S_KEw0(wf<0(hdq`!KP>( z^(_#%1eBP;r-6Fq;lSx$#CML-fw>;~Y#fsI+w)a&$#HWe$8uHDwzf!d9Gtc}m0YF* z+Y{-zaKdctJei^ofr`};O9DC(nT%x6#8k2@SU-v&z*f`n?%d4DxH zaLbW#K*?O=o}UawR~AI?T<~&&>ULx_Y*5)>)Tn;8!ePh^{XWGgE=Pz;XeOIu z+q8(v$~1FPFJBltR9s}vQi8qFDL)e9(B*VBJ+V*M<;b(19pST>H)UA2cRbkT5zn&n zU)d77)8tyafIqcAvte2*T{_)4nled%O71?``&#Gj>X_<2%WNvD3?ip2SG$DwMp3fJ zcpqKz_QlZ)o7TIh?yxe!nmPBXtMoMGg&{>bf|pE?#}Y_^Edn2@ftF2gpChC2K{lh9 zmRTGe*h`)xV%4;VX5bl9(|t4|K#bP8B?l*8;2lCxY1e3a)4l#^33_t{ACHVws> zh@!s!ZrOnwzBQog`KeZZt}k)#;bml5`p`fTv zWOh?te3}m(GcRGLqC?)uy`ff%(CR3vP*CA5Q6-@iV02^4kw;}U6tR?1Wxx9|yGDUg z^rbGidof|P*=t?>O=M@iy~5VM{-^YL>yf1CU!BZQ?)_lPkPy@d5~rx`X=~q`ju&4? zlkTVwj1?)XiO2i5-gWE&sr;xxse<{gzHzDL*bA(it!@XK`WXATZekd1AjMCd#Cw?3#6oX^@6N^XSvG2wg)vpcI$<4sDavzX>AQA{DT2NvG-+OHe7a^jp0tia zEX_X0numV=@Yo^AtT#PEuVL+XeC+2$SM8V$(5#Ma>u)+F)QiKsPBFWAV#jfZLC+W4 zh5Jh+yB7>uFFJR`^@wi436+h@$x6tr#P=9p$0{ak>9mUAsS?Rtnjfx0eaZ^r(m`It z0Q7-mihTbD)u)_3Wju%R^+Rnh5x&FX>=`nn5}SFcUBNmtxz8CE>>46At+oF9ba(UK zg{q9A*DmxXASftsQrR+ad(z-76ZR?KU83~JLyq@_^XRmKJNVJ3_JT7bFUF6skMm#L z)sX2`9N@WNRgHt$bQ=n+6_366!4t?J61)+zIDT*I`6*ZM-7qaXp?)lXa)+EBiP(?b zRCSfkz08L%JNI6Aam#HNdPxqdaF-P}&y_`zRUOyVeNb?2_%ISyuMehD{4B{M{kx+` zs`(w?``g=OEIseG6~B01z6}4;D@OOHOeb)=`%B8#B9GUUuS5URFF*eH{`=!0z6c0E zn&;p3PUI66$Zi$gzhArAH~)TKrr%Qgz0HuK^zR45qd>p*-?wBI{tXt+P&A>LRbgJ# zkUR;f35K@&X5Oe)ORW5Jy$2Ju?Tl}wDwXS{n{O_iUEH+td8%I&KVu}TsYy9gZBw+6 zA1`&nl^WYXQ?z(@N$*B#>N^xs)g{hZNM<#X)BAhVit*8>BWg26nz8K>)}!LHr97qx z&BTsRV&RpVRsLUW9GtUBdpi0r7#*qUyNz5;$u+?8%}K1k*)+}e2joRfsP2{Wb6b|b zK|J+{%YI4^4`m#Zq%q)|Krd*3Lgg%*MIWGc=ml5?brvbGSfB91sGS_`1W0Ofbwu2$ zp1`1CTAD*kuf52_pSV^3GnuN@*?09z@Yi?B6I&m^o}Yi^xDG7$D5ii-d_a`SWf;Pv zRaX%=43QEh(=7_?Kdo*vWGLGAdIe4Qxrnnx+zuA$vl#>@-8C063R@;7zRtORJc&|Z zZup|&p)qIeYF>bidf-jrF_y>LmqT~=Qm)8jz}#kV=ok7@B9Yie39%vdh*GCoqpuD! zbEzjA@E0vNO_8RKW_GS9O|Pa>56Vi-RTK!&e}r(3zb2`FA~UPEp(~;<_ziIvY@$4O zT&>OmrgMWj8NFuRQP2*I4o!n8qH#wsd`Z177U;+;(1)o8&jgsZYi8AZnwNxh{kWbX z6`8|dmYi=olWOO5(gwGF0Y1+cxJTn01x zw^g25z~Bh27jp+vJ^X77&M5HHacjrUEp|GkVCy=62{%F+`TOs6c5%QSk|9t8^-&Ob zt8>gK=+3A(a{I%~zUbR2X%Iz$F)1;w%#%HulZ3AHR>_^12^~1_Dhi_TV>p5mF$J_# z8z9ig`H>;luqq`(f`Fc2k!1Ga;(|_0r})s-f~XQb3+}37=p_ zTR>1%$s480$RFqmi0fGi)w~H9m16>-Pt*dJ9Y5sMX{N4bQ*D{l>80R9ZafC_@p~!6 zCjH95K&CKCbS9Cu2dJDokWOT*ETTwYi-AH1NvRTQtn}S6J9lVY|25o{N^8nKJW%a6 z3RTC&oFyoMoM%sU1=chX`lQ_OJWu4lIAr_N%3rH@3x%LbuazJMx2+-ZAu(JI?-ON$ zoM;{8)X3N`6POKLUkA%+hbSRGl801pUXlu-5k|(X%TP`<&Z=R2OQYLj~q)XR%8+I zOJTT3ouVaPE7NBtU;2Gz(GMd^e36?{R3!% z)1y6Xq zuNNrWP?EBQJTAN4;e{Fz79k?vsbo*4x3pTq42tjftSOYuN|%j)2$mn*N+oaC`<+*2!c~Xk$W7gRIO7= z0ic-_A0?li(@92Za5KQAg=SaUfB<&Gt*yzO3#`#)jSabH`xf9o%w+b~Yia#gfrPIJNXxhK4ZLep`lrP%SlN&BQz^p4ObO&c#&s-lgZAGw*fZ!%!gi zw0bRzDFoDA1wc>j?V5`R)_H?*&hYN@_kIKJyn7CWw<`RFXQ|UkqaWA z|C09>-Z(QVp+8M?fkt>StX!Vv5sZPmZuI%?IScLpex@+OLmW~N3W4=OF;C}u5^{|fMuwu*_}qNsBw2u5A&Ca(X9A9 z(V}wqZs4Ib1}s|?r;A=g2zwv#FS_KA;x*5icJkP)!g=jt3>`2gC444m<0T%Bt{WFo z9N?qRUeFB7??N=AUQt$7pF7%xEN+tojwBn}&}l*rP_Wg$Uq&aAoxJD9c&wm&qJx)h zh5S@Qb2K^XoztQKB;e@Mr)X1AQGK<2a5=%i0SSsimkJTcGYB{}0Qu1#xJjVA%b7xh z_&8KNfV&vPASwKi)k0{aj!aH)#-DbNLtdmcG#}Db0@mvp@xg<`cmY9z&A=F|HGY&Q zw;SCPA-Z(;%Q8ITckM|E5*LYhBmqvWb zGp-(yAkd#+R$#wltra0F=2hO6LQ?oHSd_qJ%IT=GgPJL{swY@=kYQvkH+AvQ79^R8 zT~52*;WsX&bLM|+05pNA_NPXWXOyFhME^3T&*#ueiYrq-J0tFxE1qnlhYSR-q6*}X zBx^X{FH(`Qnf2h_RbF2;cL1D_$}l_SFCQhYq$Y|sk{nw_)aUx{7jPOKY02#AnZ(@v zxB1mY&GUs-Mcz{KwoPkIE_P~Z zXI_5!#(oYTe?58q7vV^W3N;}66tp!GO@}$VDIEAI*!;KBKCcL=uxQ+AebiGSxn^%I z#jUgA^7M}VZP!CezpB$=vEd?T1$HiVJzyUfSFic0c3Z(2405dsl+EJ+{+GXzL^?ZA zxUOpVUe^K^SIi!_%zS&3ae`;f|>S3>TP`u|-@b08XS#tApnh5Co zR%}IHUS72?y;H#ix3hS09&PUWv+~b9H?D_CQEW6(jx;q0W&+94dcXs=?`r$x-C%M7 z02o3hB}FK=0gznpk(;=fhz_$95JyBa2!@muU zc%0lUTOD-7!Jf+ZB0v_6{H7r($boEX9pw7DMZr7`oT?ws&OhiTvmKXZZ2IK7o| zT^8xNg|T9`rLq&h4f=NQE+pcSZ>dG+j??a)qTm;-&BG|~DDj*Ko?AuE<0pBip-r?4 zXLb@K7e0=F58^g&WLkKSanEkp!>wC!$7QtipRwQUd5btVbG4r;I|`bvVKWE8CtU0M zHfsuJEg#5+dV736dK?MX^h+Xm`Ers7h<=I9VQdjsR^UVtx!~FNwdQ%(T`?P(`fb5t z&Zv7zT^{2xd0tknITA-(7HXXwkQdPu!Tz#!7Jx@t1aL>6Um@|+8%5sngfyIx`uqC3ULr-fs7X1J zEKW2ehme|}mT~{5p5+aJRD2AFu2~;Rbi_{b?12yks&}I>;zuNGarP~w*qGJG`?6ff zatv2u2WOOVH`~AkUx$dA7F)F{^E4-ml`4=9T>N~}Xsv96SCvCHBKMP;^3cRBag1;3 z;|U+ipR#$dr4*((I;68k)vXW-RBr_NHII&}5Fi5j2N<6%&k}W=w!e5Gsot<&FL0(2 zsjtrAOj6`FQh7>J*#EOf$6D7}<6a!ypX1&_5^xPkpJ<#hy*KdM*%fG7Uq?YR(b@St?4sOev?faQTK#)>&(nGLn2DHg<#bIx zzuIptUsGcWgl~Gv#d_JV?j_qZ^@_oggZf^{>UaQhf|UlJTn@ezpqVjK8hDfw<^9K{ zaB*NYCNezSEhjb0q+xq}JtkC_il8A31-)aW@FHODlt+($>`q;ZG8xiH4eyDwiWJ_8 zGJy;{LAwh=nW~)!UdfY z=3O6?ZXUs*Knd-aFB`bsa~|0DyZek=^f3nitbc+YQCHP5tRcffM^j0+!V=ji{SQaPVh z5xO(;*;4z@s#Ymrw!7r!=LkV9o;lTwElY$98P@7txjWn_DGo1|z2t7W-O)Rhq65l(x&!sH%i5E+Yj*4Q8xEW5nWchZE@xckVVZGe3M-;-$?edG^G%&-(Ph$M3UdVDlg|Q@W$OvDM_&9N&3) zc=-!~GpFZijhU^?+8YdE&1z*K&=%UxAw z0W*|S-%|tqoLeq$u(|=2`uXzaW*)Nvhlarq4T|&y!bw^w0dn0B>i5HwCfC=pXs-~cOlx0A*BL-2dDrOMcc)c`jdh%uNEST-O!O;!zd$ zlLI#$)Z#vC{pAM->#O$|V?IXH-K%_X*MF~5O~`Fy?PtKzyKlO&4(oT$6c^fqe|4?@ z4!+#(PZ56Iq`CX`IM$%Ce&g@+>o5D0AGz~YLRNo#yExq3yt#RtNOIY^PbPbb1T&aT zDW4_VUbdZcXZWd6inT#o{xfjDP+M5qy;O&)Gx}>dqZnc|=Dw=?Ycksg`fCCo+0`T2 zyxP8KaUOa}Y4`H&ebI(TGJbtaeUCFulrF{Wsjg6d__&I2m8rCzXkFXa5x~9P8GiP+ zS6}s|KArK2NlScfHjte)yFJ9Wm?5ltZ#N@g0%{nDGcwQV2{2aq%_*gI|M{_ui5k_N zxpy~QbmRL5njFur9;~fI&C$yVw_lkWP_*8jRjS;JeQ2W2^bL;GHg_`Nw@`4bU?So? z@pmm`o>|!3GHhEwUKvD?Lb*fmKnjH%*Em-JK`<)~qo9Vv-O%X)qN61*nlg{Ps@N zjoZ4yNJu?>y5e=uWY0ra$ilXjf!yXvJjWx;D~4Zp@R4~`Qg&!O3@;x^&3YFJUafok z?_*`dipa(INB#wNxv^^%y|waW-&apuHW74}c-KLI0`%urbV_!G(_GmcYNw6EU}(>M%UyQEwqJC&x_iQz9ZlSOHF_8;q#hm z@FbQKo)#aA$8bC--*HR~(G-89^{R9C5!W7$;#Lk&__6n(K}(31tlB~30%ZxLT?!YQ zvC9d@KIS5KB8w=0kn&t$jHWD8U4_gPH?LaSmLaF3A(SR(+vmu_^ixOYmuu3j=VJkh zP~F*Um?gT;Sy)*lM@{P#SA3?YYv7Ueu#!Hr&df#3n)of(O3mu0fIdby(3PbVlIk)?#KPSUM8O5M)Zb+Ig zV?}B))3zfad5$il*qHxH7&6^8`NJN>xn`8Iu2*YGoIFT=*;dBSBtq#@K5XOPqV>Z$ z!NI00JA2?tQmU}Vz}{xIGfJpRND4!}oy)bD(O;G22sG9VFq;x!s?j(1e3<*otV)Zi z_F<-{`S{ZacLzj92YZEdj6zQR`3`$fhnw}G$3lyzd(jN?)Oy|1;>`#1MxXapT4yKB zZwv0c_DHI;?WHV9ZjPza`{{`~(_8E$Di1zB22QZwv^QO~na#-+XO9oN7Drr(X>I0b zw$fhKQ=Y_pu@|v14rZf<8>aNpcY2}Nru3AyDiMC_I|c z+v-KuT?pSPB=Cv1L{bUg2@j$wrs5eY}Ya3I63baPZYU?yf@Le|71R@A`Jsudx| zv{RiLK^je+zO2JEj7gdq@n#SeehhT5{&orBdD@qcY-%CO`Q%L*en8yVc8yt(%$j; z5S6VM#AI#?Na{)JWwLzMM>#DT^uv>p#U2h;C}lhU^Zwv7*=DXsZj$*jr7fe-uQ@Ix zuu@Il)So7IqUCWn*I7gm{AL*3o`3Xh_1&pItO9WCo2t>JFS^<&68n)p?ZUl8%&bZQ z`NM0tlvy84@Yw^D#L4G$+oAvQqiAR&8j}Ha!y*FG%;`u4a#2rXp)vqu+w+Ig!W00* zZ~G^^4lZ=KS-s|EJkjg05QN6+uT(zrgohA6V(BoLeGLGZP6Mgg0ii!lq8~87jt}+0 zfj?eLBIq!D=fLINcdDNMW*_gKoD zdf^5{cCr@htKQ5Fb<9S+^S+$BIh9ik^FUeft0>edmWH!1sgtt#fJNdOIokQ;4Fhd6J`T$8sm1Hz(gL=6J`#E_r%4>BG)rZJV$zdz z1A)LeQN)8ifFKu8I;wYVMt_Ogie?atT#{st0Mh_q^1WepWf~{L5aU6LHP=Jom{hVV zW+KUGiZFT-#EB;|cWYJd=j6!(R(%0qv`e}7_?fy#A-9R3FaW9rd%cRt;={w^n14`I z7U(pb>z?4+D~+PEC7j*4DI*v>j$II#Gc^=8JnGy&!q&~t-qGWFC6_H?)MDA>b`{a9 zfGw_0U1gTYG6~S48dLtf_&h4Hc-mkBYEFniT( zZKj+dT4#%K%22Vsu7HD3%h)JOHl%7mWJKs>aE=wSO^licCs^`CFiT9K6-hw~~qlei{rR;l;#*0>h zZLhWlCs+1J8aMf<;}4#4w?a5})+3-I-xHq3%( zBLrkOBf`u`KbFj`4~cLBfFVGF%gn*^ZA4p?js-NTzt8R)@|LPxdiQ;*WKtLM0?VTe z48GnvwLZ{(=Q8`9=O8v_Rtg}4_cE|LAKGL@FrPkF>vz+i5scNpx!?MLqOPO?^isJ5 z#*${(cm+KLW8+50)p=mNM2LaeB~K&4(Vn+XOVp9x0jB&Kc`QqtEwY>10Omc-;{HrvoQ2$ykeGR4t@dd06XwMas zE+7&rsrO(1vQZXbV`EA2q`Rh}hlRU)cSf(QX#P%hDZgDJW_^6BTk{lScf-yzABeTc zX(z7foGrC5CWUy{e2hHSzmp263!h^~0ZPySAeFcY&WF7bc&}(r9MXTRs52WE|5Rr4 zYu^NkbHw|rVPovH9Mz>HRi{yHBDQ?+*X&4SoN@Z>$eS^(`u3YC_e}XmdM%@R<&Mmi z+9z;!_IGs`g!~MGrid_v!cvcEjQtI^;U`ct0DCtPwXlNXC0YLmK)Q~48Lgtc0rmp` zD3Qo|7K(;jMLLf1HxtjYnNZ`C;98=jeJeLR2}uC(z9({Y1K5cGW+=%PB?lkTs{WJ{ zkus3|b!sPr=%B)T=r?h(?V5e@^!M*uYkj7T;%NcrT~0d=y2eFGMZuT{Q$*y6Ku)=y zvPMxGtv_ZLWNjy-MsY6T)2RAS#Q8)7jsga&Y$?8Q)!)_C|ADC&EgBQb|FVC%F0!Pd zXBo)2^8UQ(a`4Pe1!F^{E62gTklO=azUGo&5G!60mfVWNj>lZ032uUF&`M%%N(ub8dr3gkFnJ1U4gDa#vr z0pc)*EY=FiwJ|dL8+^7q8qaekUjq_x}7K* z?Iz~xE;dM%6b2%N{h@Rsl1Q}tkH|$iJcY>sS4xSip(!vk0EV4(-3!3i%(jpsJ^IOM z{>bj!)jNvT2EP8!*{W2eDto=puBD+R1Ac3>-URW?XWP zje9dZ#cGWKZ<}6$=)7GjdF3ScoBWf-oR~eYbAtv6f-YtHZhWE*L z04w9HRh2KJFvp=Y$MvvaP6e?s(#%lQUJT) z%UZ?$r+-Sh|8j?J>(*WMLc6D&@&FB-(FSUc!(!^O_v?%vsNi_W-_x^38hR#R{rJH& zOOxH#fZjq%*6=`+CM%Uu?-DnoX3I*pYgD)07%{?qDfnq*Im3;8r!7!y=d+QeYwKmi zDe$H{dq**z_hLTXssH+qxS@h@{CvMo-hif!0+#!~QHAb)0%ep9w6&=)XS-snc%I+D zk#8C?w4GM^zrQi;(7BTl<4r;1!yg|fJk7og@arEsKN$KbWH~7sXrhk7%Z?7MtKrK$ zN89&_x9s(_c8!!g--4_{;7>2YZ{=41)p+!`=t49`-O(52GY>hbt^&t4w9hv1X&jpH zz8PutWSSIX6zmuoCq8F7RmK9@X>RMKSC{lZvzncm6~DQG@vU-vCQXdqNaphvNOS~oxP zBv%2er+3rnh9@b28`cq(NR{t*z2_9Cx!I>90IYJcQ8&|CpAJ^`Jom%VDBW?^%I>D9 zz+skF|%>w5n!5S+1_RHHuLJlxs2Y>Vn+A%-S#1@ zZk*o8*OBp_<@DgO)1060VFy!QQ;SZc`gH?3L_Prj-OIAN!nM_9inTU8`c2tanrf*9 z#~BU+h=iIftR`6VeVR|}c; zFgFzDK^ z5Y42t3_oM7y6eqr_1~3^QOsOk918N%P=pJF0}Dk;hsg;uammR^Ned&ygqiu|6y&6l z5GH0JGz4qTY$C-B=YnIoAj}XhE)pCn1g(Z*Bgz$}#2?7HOW0!NFm_0+kP&jCoDXUw zBt8#+cxsE0Foa{Im*HqBKQ1wjo7;SLaA&1FLxd-nxKt`t;#gXyswb~}Hakez+lk)| zGGELs_0N1#ayY$|n}bW4KqCR;xa6+j%up5hTD%ZPR5yig0E2Q$Df6lrNXp>Xc_s2G z6;ks>Qab$0`GDcXG_6aUceaPum60B6_OtFgL$U1tsYcy?<-b*8^{va8u^`45&z_@T zzDJmY3QOkCh5k0M0pCCh=gNq-#>6KDl&OZ`Fs*L?Q+>iL!;99(kpM%&Y`j>aPzou>)>Hp6M;(#Ne+$~g*y5uBXRVhQv+Eb z@_;#?&1H;fXB=^mPV6~@zS5+`d4Yw&)y`cCywcxkUjb^*E$;7)o|Gvvp|v*ow``sj zFlVuPqB5d$L2r;`!vdgis=EjbYD7s50b%jBM$kJGB3}ER$}|GI=BR-XU+CU;A~r#0 zhb)onvy&wABy0yRmwFavr#vq6HdTGi=WUusVK>N7og<4y#;m0~TT)@|UW}+&Gay59 zlx#4J_DV94kdjlrkCw71MNMa8xM9^o&T_t>6zSBuDj9D%Cx-$Hy$}PZTQNby#R@Hf zi*UvD?dsxtrK1%vtK^Cgg89ntVoIVGLK2|jIs{;8CM9Po8ghOYbP5xKden$w7q*9> zBQ5zPNQs4qfr>C0KOZ6P<7VJ`C!B_n9(Qc{UrJcqu!pW`3)M?B-^Uk5y=pM+o#P|7 z{}LVIn0@DFsN*+@wmUmXiFpeccXQVJ3BHqsQe15kos;SN+wdEFj5x!D5Sl(zo`?cb zM58DMl!y-8FpFe9?JoRBF5#(`1XmCmD!ATf02j_C)|5yS8Klh3hsp+Ukw8iy%)uF5 z#O-9_^e)3GxniR0l7pX2SNKoKwnES0KNU}Tg!m2$hzVAngTYUn8V4yYMbeEDd)l{I zVhe~4Bn2YDuYNP_l~w;v5?=BNRnGb>{!7H^UlBXD*h`^K^N+;%MZOC< zR_v};5`=G~LtBXcpsFIdd}DZ zNByI2kK1ti;tUc*H?Q#E{9Y)FC45Bv!DWwPKVE+H+rZ#&0&fLRPhez^fha)NheKEk z6@#>QZ57V%msLWi;@C3S70re&m@F8Uqxkt7$cd0rKSO=_QsG~}`^0QB9uwKBuq?6_ znAQx+bi43mH#f~#>sw-S>h6fd)TFs{TV_6Zqg>|Cr1`5k)LrM@vS}j=H8<6a(pk^J z3u8@J>*uo!JgODG-*2|)s!hVS*%``dnpwWNYm)c7@_-j+dd;;hx9|FHBH4Tvx&IBH zuq3H?k+10H&$+^w(NR(K)QbR)EBPuhX2JvJr*lE?Vfc4eHCiw0D)@g=ibnzEtUTSr z;Q>LV-)3*={BpYdaP2$(zugbqejj+`Nc$XDKz0R6w$pK1M^re(ejY5jnCNU@!CG=w z=#9X0P}^fRE6bASK3E%?Fd~%HMM0t(23+-&M}M=i=4w^On*SDf)!x0~us*U8;M*}r zRoCLr7cN$~AJrP3zkMac!v2X|XPsr5oPEvlO1;*P`YWBc9a=4}Hs9{N_1Uw=k!ebd zC+$b0&y5f1T?K1hn7f8}M=t0J?xou7YID#FdDmagF9)|)pN5xwy2&Eo*b5J}P2~Vm z1Dz_bYUL&uS=fFrp9_2G;`+1V<-m4)oz;h#8;8B>hG$3r zU)03P7-89d1%oB@KY2QcGoJ>~3nX&u&>`C0Lnx)d7?C^V$8Ha*4qq@L&o{cVkNg@D zX8)RCy6MIdyFMzW)S7&`e}}7`cXYn5CAFazG&uWvT!THsJXpuW68vLA5TQy*RM-{c z{4;4{qner5xGSYr5P$v^APYbFJ&??3e?+_1=Q?l4q*$exGGBm+|_jN{6v*WmpaL&CuMl!LO({5C3XY z)|wW!rS7OlMv~UGpAoN1*`f;@KX7!mlw)a<` z%YT_HZKRUyHa(K_DDe5Y(^5f~qfY|yIvL1qHO}RWcCl}iYHm0F>HG|k&0f8ip2%Mz z>OJa+KR~7XDl8UQeSZ7FX=m^XlJnoI?DsLJe?QTFimy)y_X~Z3K9XP*`<_+35&QaV zdGFv((=1cp4nt7r1yjzyA86=19wZDeYn|#`i)yA2K?od4UXal-C;R`yygAf+ht4m!g?W})^f=84Xwx1pO;{;1 z5{=PnoHABe`p=v7c}()1K?V=o(y5dmawbUaTftzI8b_(-hE>k%D0MfWE0xWX+wHs9 zy5@;!IrTfnyWV1ODN#lro4T-8$A|R*F2!j+6p{Oq8Zq)L(LqWbdtA+`wFIhDeZ;Q{ zvQ&2Z@J%$rP^Vy2$XU!thytWn1x%WTVt!wb3?=c0X%lk;d%AS@VgMXO`Dh@->zhOf z-Y1z`z#elhW9;IirtApG%)mhzuw58i5-o) zR=pRzN4))^S^|R-H994nm(Fn8isz=fyM_@!Toi{xSs9Y2uOH;;p#bB92J!s~#vf38gkR2emlNEdzZYmgH{|(L*vLSG*oo zL=J)=;V)6=*CLytkQ6T{dI7>k5v+5J(3+G_9p`D5xgXNOSPJkC4k-8skoi*X9*qS~V78p(y+ai8pn^PT83iN{I#!Y#Fnx5VLQhUt^aWC^-0|1XIElpR4Z_NOp&^W@$V}<*hkQV^ zT6tlN(jDxjSG+k^%4Np9P}3`>_#vTt1mK8FIQS#Wfiz@MSs>&OHy=PG3J(T-MQ#z1 z27#3k;*euvb{`)S(E=`{F~<>E?lJ(vG~}%$xKJU_9c=0z9T?bi0YL|bw`9AV@ooH7 zA8NTFqO8UMZYg5+9u3AteW+*wHX(wSY1t2C!7fv=LP_}8-ESrzNR1Yg_GoiW|6>Gr@PmM@Tblz3zW5q z7-NB%`M_%`tXD~xR22KeMJPZHIHO#42x!>VNF8e}Dk4hnECA&Lxh;L_pUJT((6h9Y znayI6h1(F{7TAaxYq!?5R=gzUVi4uld9Ot|v)^K!gla4vutnu%ZYkdS2>Uj~IzSM3 zjuL%2#Cj$(Z-2yc09dyzLZ%A}#i&Zn^{n+O7a{FSddSIrC0bC2hf~c#Uh8spb#TIJbvv(`YwX@L}Z;l&oN%6#DZ^jJoZ@TD{?s|ba~Q6XcV3KYD7o&65vg^Vx3BREdi*v z|KO;n=sH=}0v8^I1BK(c1C)^!YNcm8SS6^T-L2lOrKn0P>6=GAgrA)Q3mko0mM@FA zrVsQWA^8@1Vni=pca+ECdkPnT!O939ROyr3?ekQyb1P=G<=&HzWg%G)AaXD;f0fyH zDJ2RDkG)jaVD`wAdC5 zT13^Er$4coKyCrL#<2spo#UK|@HTpu#}1EF!A%>idNdM4{5G!hxv>Sf4|k8%R#W5tO86J;0|>fGxL z{xvtiWDf`vBrI`CZ$fjBf@md=YxtrB5vfD0MS;kYigPUW=PdJcYw@GsP>{d)9;un; zVgaS2Pat>L5Mx8ugQR<_71TqCoXSA-6M&mBN=AXjZ8X+pI~RwQy;d>{4>oG!hGk&+Yk7oYXGLUn8f z71GtyX$@gSxG7yG`2eBs!s4OA)31CjoCh)FNG-?C@Zs4Em6?}21~7-(d|`{2Hze^2 z(C^dhxU@D5Ll#ty1Kr{T{_MN=ogzDrW#yv{wGkSkX5w{HWZf*&zs2?s;U$f`FDi;b zj*`;XH2d3BdGel#E*v!MWaQjYVWAzAnep{@FkoiKg%2ApPE5<}0^rNjO3~DdcDOQR zDoc+oL>Lc{nI5l4x1!y+t%&3QS%TsOx;B&n7#&0`8aZ20{5Nnu%u(QRPfi;xI;oB| z01M%qu4{3pwC;_e01S&8v$LS!0bSn9X4i5m8wpHI^tl*I>>}Ku-pd8 zTO}htX$z%zoccu;mL236G}IWT1ku%u`zXB33@_3i`VMcYhDe^)&E_wQbRp zW40G4kr8_Cb0HPIJ`vvq9x=fV7~iTrqY(b0J7SqF+`U2p6{i0>(o7CfBY<2r3ked; zF*Xb597@L@%B=0@4zYDdld4<;=fBz_3Ms(Cj8Nm2qD|Z0cl5FjdFE{@pHZUhCsf#& ztkzBHy?tvr%e_T|NbYa#a$L#T(b5a~NdjGMn0*?IBfU!Sq-V2rsoDkMK!pvtP<8nm zD~Z`vF;x^E){9%cp+hXOLqZ1Fq?(#VlW1-A@ZFawS=(HY1P$geF|flByTed+I4RC@ z4h6Cnm|&(4#x2h) zInKS^&w7}|>`cw3BsR&sfmCUME38;LV&$<1WtA?&5rJzSi)~SKSZCmLxLd^l>ghbH zs5ZGlgAL>+17Z3&!d?+6h6jKE4IA_#VLJAfqA&zS8sZi0cq_<9sM?}}^&7@Y7=p|# zNHVIjvl%8vX7y4j8C|qEDHln-G8)w)G=<_Dz={MdW^MB$6h7rXb~349K^vnWezPnO zr?zE;ih}87pDD7LAK2kdH9)x}N6K5hKj4wt;+}t@ZiB){nvD(0EKia#?`XWfH8p1S zEYbKchFf`muQPknpie$#@!_TS#7K@`kq%$M!P{8}r`N!nfNoM4l}?*7q464E5dm`$ z&YR5G$2k^!)K7QzE@>j&iA(LYo+@X-$6{pWyUP#jHkGKKnT6jsGqUpOld1R_5IN4F zoF10RW3kNQc-Gb&5OSh&9}<_ON<%McGTRcD2DRRes=bb=SJ#ohNHkIn{mdL=%+^6Zu{vjT_OF{VJgDWJLLAUj5E zLH01jfNla!SS&Fx?;E;#*Qd>AQ)WVw`S$6}&qMg8FPvjWL5W|Sv2BF&B?JKrKEz3@ z@CI(I6adpr>IIzJa4!G5U4SNXR1zs?GC%8s->@yGjSQ5K-K(8{UL^6}(&{OXC@ zm6<5H_$E%@kf6U;lk3yTYgPI5YDBH1WWj#H-eU*{$56H}=K_TeJo}HNOyD4sl ziAYhCY_k`F@=V=Ua-O%~i9ukPFYM zlHgIl+GSsG1v*or>L;w38C3P6Oe50ZhUQ8ftV+qsjJhDo^pYK^>S!N)*Eo*(syGBx z>0S)um|W=yydb;4aWTs#jJ$A$F?3BDLHMPAPwA=SnIj0 z^_TTJ(!AZH6WfnQvBT%;pFA;4f6hq%mQ?pQ^VR(GV(ih`P_S&{!Z7RkiW+S;&4Yyz zq~xaiNLszxWC#02!LQ{U7u`kk-{k{=V5FyK?3kzx6$|>S>|D+SX2W3{%hsLs`Bsv3 zmL??%bj+uui>@zC$&?pgfg({p1hDXkBL|-sW#g%Z?3BGKRcz4DY)Z`YZ;Kf!LsL#l z&Av)mknbgjzRB>8LRPr|Vh25{FDkyWV2HLp8kSDQuPmC1zLOEuSF5nce$#4X$D1~2 z$v*zD+h>l|6<(e^oveRfaaZpBKfBJW4mZ-c9m-W%m1y|b*D@F4E1W;e8P*tZ^;yeX zEz_=EOH;4d%l2Q}xK%#3fb^(rT5~r1Rr`JT`qOumD&0b;)#lo`V%}!(3u~S?_gDS% zZk*o>y0-OTCM|C(@&osnqUE_C*;w~Jgd?2-ba0$LutGUa+d z6nep{6swh5o}r|*Uzrn7xL=c&9^qS8a^X0sK5vl!LSxSs|Hry^_CCM*=So_8?V>Kc zhn*V%ea z%I1nmvUe+Ah%F2>^NEqLmT9|f4?vz_%P+3hwJUakEMROL#e7hwN2uPNm+uOF#QG&p z?(e;O^e2~GYtPRd@%e4WW#LiZoV$Y~cVyLvVg~uwQyQc#+#f_lJr*Q934l14vz_XrID}dNo*gWP1~_xF8;AtfB93LX zEF^uW5MJs0Foq?7ADKayQTM)AeIctz=$%}VK>Z#xk9&Gi-0U^STjshQjmM849(fpX z{WR78c-xZKJc%=G1*A%>hI382DeVrYNF>( zL~skK_c|uL9;1MF^4++vRd_(s)lKCT%WIx(ev|hm8>2)-Q`oXS5!DLjnBkW_4o7aR z)v1Zl;ccLraxA*e3IvVGV3i_@V$y<03eh9+>_#+@*g^(Obs-))Edv$q-C>2-TV(jf7|^(jy<=%OVat6$+zo6<@HqV_bXUE&p9nVAD00 zs-`Vmr!Vs)PR6qsB+cPQhxz0PhL^tc*446S)?Y0Vm}@LtO<){|DSd>)fLEs2_edZo z4i4CKJ&{=%B+u9$VG*a7vWMY-a2%1vH3k65&Z@e$)ZlE4B`H)dHy`l%-e5W=_Eso^ zLaS+(A8!Mzi&5DTIk@zLUI+9FHxOAncC+;lV1SUbK$>|6p97cXxJYa=gqxR^_(k3_QCTvthC=nmsz-)s)-k=YRIO<=-o0$V<9 zh-)t{9e(17p08l_$-xz0*bCqc(OtheEFHXNV?z`ZD#*4 z^u2TZ!98W@Mhg$eXpiMS--q}Sg#rIq$Y5~vsreGIYdBZAW*^~bwgGepj5F_Pt7{rUIN#L~pqpkE7}Yc6x&gpW=>?QaxnE6KF{(o&vN zJTS%}CbwPf8Qi=RPMp$YHO*@b4k6gH6+!j8w%ypD43%#SS``^tbt%HP+XG`K7-w@| z&#LwOoL3_@z7-GTG4cXgvdx;tm{#5<@N+9x&A>GMY6>y?yPx(91Sp@6SaNOeThJHwBb%<5&xy^xrXBupttj@1oaV~kyTF@ z|J5;>5T7-tt{f}2{@dTs!ExAABgrrRXixA-<2?8~=N)_)#IjuX!Dn#((4 zCDP3xZH)@u!@Vug|8?LO`Q=L7^;Zc8z}F+iG6c?xi0pCeI3pS8^PSnYN#y3oX;4i)`(^~Ko3pt*IPt}st?fJYq?&D}LUTZ@A`FBH10Fk2a$M^=I&1Vj|m@rg~TvdmcV zxncV&$M#Lj{idG+Y9q(f4^INx=aizZgHxD4meD|QV9VFXV#DM^KEu5nGN5jDILU`~ zlX~}QTg$m8N|HQ5TL%7u57NM}S>1KGfbMs-KW0<7?~gw+i<6Br%qFvxhxm_n-(BD3 zar>Z1_>fE7FSpq(>Tk*>e2_4*$O)K&>Ll?MYUG%gpLY&$q;Zj@=$9~{zNm5+H!i!0T??=>aD!6Z&>v(}POQ|NsxQruk z5pR7Jn8Gh-Zo(_7Q7)_Z3s!>}K~4e+XNQn9YX!Q#$Skh*7@#=)ofp0m++v3=rXslx zJ7s90^*emOKM1Se<_;oVm;h-F%~j6QtCQnkD^$ewIQYTxCEaX^WLp013KJ3g3)^lw zKd@z`L_~-0lddY0mty>00qPm*<{Js&*(>4c*#;MkWxM0A=|Ql~WH1OsfTKjScd!9t zp;5+q;FwBb%gEak508zlIAcuL_EO2zl3v4z-_rJ;ETTFp&6pia?wUs^8OG=NzrT+x z%a~5>!K(&qWR1yMbME`L1y(@5A7T8;-sBJd#qJ^BDskyJ#6J^4gt1a|jVQx_-_lgh z^*!I(kcLsbs2(?kQ7NTx-%{kfgIA7!^F4>W5V>=^);bk7lTZhJ@Iw>hm=lO20_rxa zZrCfAmfd+j0h>VBvt3{zF&kLi>2z-T5oYw=dH#vIq^IBx#EQ*5WtLFiwWs})+1b&Z zb0XWm+TEV^S>y<3A1{Sc>U3oq)3KQF8Q%`g6w`c94P=jzZuYRx#aVpiwgu-p#pK-V z>~s^l;GKWu=KtPY+u(O|BiVEJ!8Zf>SxXl%sKhn>p`h0_<_a1Oj(uV;dPGY?)tzeD z){5s-JsQMedY%7G+lmIYm9#7{b;NHPC0gQOAhjKrJ?SJLE;d2q%XUBYs;;`1{Pcy5 z+m>JO7CY|-zV+ebm!%~%yIPJqbbE&I)Jhf_GoAz8*?D_%i$j8J(@1i4DJQ6iKiQKA zC=*9H9PuV^OF~9;qu=_c#o5OoEbp%P)eHv=oR>V9@Y^4Tk>yoB4$q$Cn#^?iSDN{M z&o$YOU+Gmt1-1R@ZsjIZA5IT5?VJyCal1KY5Z^VzHDI+Vvx$)kOvPq_l*oVy0E;Vw+o(yi&s08Zovzt~c`=7+X-lgjDr_EloPypG^~*GizB>$(tQwR1QT({+zaYEqGi0 zOVzE&OU*rcGHj12)TPBHke~cI>Di_Q??Xdg@q>6jAZG8`KULf#pvr6u=xJd5Awi#tlS5Dtf>gu|-DwvUJLnezqKCSAy7AuG3Jmdwx zKeyf{lYKNiWbaP_lCI%h8?r&DfI`l)~o7N~2$sjBH|n zKD)x?;C1<*-GuR8_hvEw@hfa8-rLE}kBg5$DQn56He_@xPaFZLFfNPG7L|N^Xa1*q z+(u=0%lGMamRWeWYhdAk;c=MXxWm2T1%+lBi-HMl@W@V{>)dOc&zhM5=9U6i z8uWRg{0oqU{F7VHJi&t+Ls@Uk^G!a!eloxBz?}~3rAkY=Bb*5`7%{oJ_p0>wKgB*! z$RADuBBH})!8UOz>0K*DgwbNLih=7P+>Ou%MzkD|R|_V0j?yt4mCYXSYQh z8B}p$$8P_r0jY5T!mI+G8Zq1(UK)z%EoQb@?dOJdYbFLDo*7NHB`L4lr^S^5HeH7$mj!-#x{t{3Pt)Ia>sqq? zoMkbjq{J$o>ry~GC2Q0COHb;?eob66{5yUx3QxT_QREeoH-;>fYy270IJ|gq#e@4X zH7W%8<9F&gLTY!HmG0hjdMkLd-#YGuzO)uA;cNR$XzJp>rp2~YTB<~e!|$F2L-~dD z;-ATV9E!17;WPY}?2feD5B=N+hfBYQH~SIIiI%6&3A1fu8&NOME%ec9{ST8STpG?J zp4=**H?n*+%Y!sDM~qP$qkl{H(x-$5;2i()=@TW@Yn!!2b(z+Z~T~? zl97;ZRhKTXSuB>DX)A>8JR=LTt^CL5Fy5%bTvN>GjQ zkN@J{!#Fbruhom#1-UU-^ZZ{o3iZs6yB^Y?fktvH6_*viEcrh&`A9OJW=ifWh97jj zSdZDewN`8W=0-&sR~>qlP9B{b((5LVQsup?PPyq8Az|7)7K-#5`e94nGmo<&a3t%q zpR9AJ-UT3^&n{n>U;L4go~wI;?<*DS&^OO^_!UhQ?_eWaoz6sJI^%bj!3SyONcwPG6;^ zrX|vwA02 zwb4DDlzuNh`n`Jd*UOu~&w>cwJaY1vx=6qD->2vQ9bWqP{n4okMWf#?WH4@ zH7(h`A7xOvB-?p=z`gy&a&7HEn|;%{o;!M#^9}pSSB3hfnmYZ2yBZu1b#6YoE3jCt zxSfU&)~lmXQq{GRbxbZ8*jS|FU7g(nZihNVduyq3h~~mF>jG6SG^aNv_iIfD#VjRk zy?P(9ll(D9Ec`z>l9NZIxi+RWt~bS-QCKj)O2 zk;u??N`7(G^u+S~>z8l;_vyp;FJF+=#FyuUPm?&eSDLgdWyWxi5F#JNhrbxSsoKNDX~|3V zy~6!2e932C*?wHK-O%Q-y+&kEK*L8PNSm*Df%8-)*9Ld1?HzcVZv|nQ@@1=p`pR4G zO?~j;^b3~<$gP1#M;2GPE(=~Ow2zB!EeI|cl2f2JCG`&0+z ze9*Bq`!Ozr&!M9xzr6WojlPM2?7^$9c1b3e_;+w5pTfzUJ;LWME6vnVdw95*gA;2d z^Ed!f%=)Hm$m>RcgiVk%onKa@=fC#Mj_ap6RkycY;>es+FMY0w2`BY< zlI33BT!&5*P~`7*50;Y`rRhnSur&xsLV&>-)A32bH%F^*lfEOEu*&`EN!o+Dq*g5{#BH3?t8ch`&gd&oP^?%-4^4vf~J4|QJ+GWLI_lft02bL2DfA8l zm-100$X_oitr$%VJk5eUxV1n8VZ!+I&A8N+V_4#%3xFWFm1_+IF4J!DSN$`Pr6 zNbwLN4#+pz7Xz^?d#Lbk#I>{o=8q(`%O}XwyWo$-0evj5dvU`|9-#~X<+b_dtJ^MB zxow>&KOu(oyF&cI$H_1(2!bw#gyl6b4Kwpq8eo|O$Pinn4+_c2rezMqu30?QAA{1r zn|{Amr5FbiR_1_e5n`Yj^!sGaEXXECUAKt{9xtcm;{bvvURJ}Yup7+1RPARabPo)G z6ze>BT0c8UNifa^?AS9#*u0>QDU$$bG*hvV1;NTj#{sMgNPNug=dak}#+#*aQT5ma zXn#QS_$C2-PNK#kap~5n#w36jQI}7dB$Ra_VWo2+PHa+)U6THsOZA@Ar8|#Ny7W;@ z`bThH>`tp-5A$x$LExmCCta!P=>t!?V1B}|pjMEkw1N{oSFN@nJJqmQ@PDn2 z5Rl<#`Rw%At>41*XAs3YCacspcaym@F)_3HlAQXiMhnA5B}5x91t%u47AZ`aZ-h}l z#z+xx}+|6)YP&0t4-2x&$%g3v)ECdPLtG)$HrKU&XxUK0{4>c37juktwIIfD8 zq{HIGwrv1^JYu>+~) zz{G|FhKFUs+@+VM%tpEW+9~ds{TJxey2r^rvLf0AHQ)3No#d{2l0Q3&ciLKw*kX|fS{=0#Emm& zIddoA!Wr(F;z~0sXSphH;tco9(448I<|?(oy~10Yc3j*BkK{^yEfuAlvg+O`O6D>W3kG{rfa00jQSN*; zC>8{*=r_30IonhX4qkX$*7S%aDDENawrnOkO~u88C*L~!EFrDZ`r0p!rE4{clnng& zn-ESBI7vdba?LLDV|O*|ag;qKmz+D_76LU@n&4k=gelRMGdup29to)>&hk|JG4)uN z7(3`1JD%;2glO{!HeKTids=Mm0?-;1jdn{^0MHU4N-SG1?{#0f14fX@kui*i@P7en zDy*pv7B#FV-0^Kgw>$&e%6oZe|z=i?#uJ@~ad9IN%AjsDTp;gaOW7C<>bMBK zdG{%N=8)9vMw7KB@o%fMD~K@}rHmi-Uf-Iw@sy_(5U zpIP*dO8nDfH1UK%-^vu?!vW-3;Q9hQIM|AOe1}0+IA-n##FG5MnDT;Fh8Ry0$vQm` zlzVu-~mS zdwE=ysc)Qh95g<-ch*k=(%f0-`2aVbW8ApA4&m7+<9GU8;=y-1M{@yN`K&aDKZ84km6O-`Z)Q1;HfjRdS!lugPepWm<*=DC$098p>oh2__U)g}oY!^r>)77hWdk!%bop8T5w8@w-0%&EY@ zIbByQpwXTMjJ?zLMt*xNvO-@si!TJUD4`9YK+ZejyA>A@Ht6 z$eOD8iA4GY;ITA8Ipp^hSD6Bj>!YtiXYwYGBa7GPM6Pmhx+M9wAm?8&=d2g4fsT{b zI=O$gtO1|0V50?Lk+vlUaPpPcW)REt==XgQeA{_5OWr5F_9C-(;zISEKM_ml4Gx~v zseRb&)rt$TO?M366`0vfuH+HRL!_6qPnA-55-4ONY&x4O&J;ng)TG&wBCHpjoblG>!UHR9LOR!y7bdx=9 z|9q`%f1AFghNc2Ydjs9UraO|DnF;*kS|r8sk`Pw7%N+hqwZCiiE-BGBa-Ogg=aFpn z`o)}B*?$GMt-0o z9D~xEVH5_TT{=Jhpb4e}8xw1KLxePw5%1Cl(er*QfMO|sR{`6^HU*X&9NF_Fl|9m4 z{JrBP4<{uLo%vO{CPA>V&4Dk}^PL%^iE`50Dt9D%6JEbe-g-FzLn`Tn7G0HLDR`EF zn)CS{`daj74os;joWA|vZ|4?mTkCf&X6>FHV9*~|@itlxW{Yt3XaM#X<{SYCb}|mu zoy$7p-1Gz7aVZV{kl%X@OmTz1NYHpG6T@Nj;Z68Ir-mulpLsS*6L9hrzln*{4uW56 z9&Hjq_@Fj1tZTb{`0`a65$y)ZTFc*~*9ba2p#uWOjNbY&~ z;azz!yZ6AmOnU45Gc*OhB5bbdwlbht?QKKf8NrXfx`RmHSaDy(0G}I-&Yzvv!QEXy z^sr%G!ez)^5iC>5tS>aSoEgY2TDDpV-sV*Y4%vR^Gc+1TvE0bB&|wT~SM^6Gwg{*X zhrfWLJA?d2Am}q@tNc3x_f6P&-=mR3cM&P(*`Y$iRERx9V7=u`l&R>Js-PlODEGVQ z`{5IDo6hcciDTzs@z*Azbz=@hGvNb4iF>J+XhWjUziR_pHAeOmY~}!-f^)n4)R(I>PM_8{f8ut5@W5L8SXPrX$yV@w@S_f^2Q6 zgU%zGUW)NcB6s!|gkLVaiO3!-9pDjZgVr4Od3IVj^A3p&WY}0<_xiR!LXT7QPHFE(<-U1!H*;W4cHNA2*#ikZ*N|PUW{1PK|oEfKL zQ}#VlvVz{U1^yj$Api8Kjj&LhiadP~Zb;M6XVD!YTtp2L`c+k)s7YSd61x{3;V>e8 ze6_Qkza8S<$s2JX>aL<#$i{~WyBBqEy;EH!|G+-vAS!|F*1D?W50gy&i};@T)5)yOB=P1%89)s3Vtowt3p+bsg35?Lryp~}8t3C>*!0bSHn z%=iuHjX%Rl?on~M8WDvNLw$!Cw{gQUEdIHsLBa=D*R{P4I_~_qPGkA)W`By5_p=}n z7YUR6J2-Jj&oYV)~&uTYF}IVNbG zRbn+sbf~f)t+I@%wm+(NkE!uJs<9tW{5BNZ{G&3QrOwx^ltc;Yk6Oo>)hd4;t1~SO z6RZcaYTWf|egCvyj_nu+yN8?##CEG}cUgBsy9)6i>9J3$V!i8PyC47QHoD&PsJo|I zueblt)6yg0r}o|-e|rAJ_8$M~W%v%e0;d+b4|(kB*e;j|d!HD8ki;|2_GGHk8uYm>2e}JFe?^JnF@n z?#uvH{i&WSwD+C2H6q5LQpjFK^v!9hf76OLXCBAPDgB$(x;cC5-<+Yr%%rKHvHr`; z|6YannoGyL7Jtfr{=iCGOFc0r)9YX7ikzm?bBd&h25;iedcRlEjAtu<{`>al zRyd1cxRx&O^6=S=NwAiBWZ@{KQ$T+@C0rwahDf{Vw`bXT@NS$c9&}qD*Mm83Ov*+N z{0E0geGAPG|9-~FCozNxq zBR!wbcm*L{+hVnoXxCK|*dlc_KDWHFz5f@?!6z!CtZ86k?RdfeO61L?%$u6Cx$V7! zFXkN$By4{xSv?Sq-VM}gp$0mjdhBhzFY(3+Z#39N5x2A#?LU#_1lQcXbriTZ6Sfod zMTD|7(OXf@kC54aoq45?yJ`n=u!p`N5^szvAB&GF{l&g7e zJT{3ozA$UqC;l9$r=M2xUB_Sr<&=~8;ri*Zd}XhpGS?p$U*0w7m$v=#BXFkL6<0q5 zmnfQ(UACw|QjAaZZ=2E0SX^T2fT-+m?z@SJ?tE6U*MEmp3<%=_UuqXtc1)|PXZ<4R z%nES8FY)1tQAkO*Gw}h&4rq$J*A~ARFOmG0j8B&9ikv*|AW0-(GBNwv50Z?kkVL)1HL;w>60^rb}0>kcSpBb5INJ5ERqL{G7u`pTQ z{q>&eOO$S>unfAGe2kM%Rj_R{1w6%XV}I=fg2Z6I3WR8La!4e2f6|=|`<-XX=tLU`5`L)CN{GwVi^I%AW&2 z7OG?DW-4ia(Sx*(VG>~qL@GBvHrk)H5LoT}ZP)shioLMAD;sjBRj&{cPq-wJF?$u>jV zu&&YLm)eX^OJ64Ug}jchpKCfBQo^+z525j8G`c9!sjN@q^B1Z?dhy#BOqyJAC8!K*)q#q5~PGUgp=&TN&*FX|v z2H0+w;&J*B=tZ~x_o%{g-V-&XIN|=e=Eq5^jmV5+(EYxVN<*!M0pV|{e681|>b(NT zZ}RFm^|ZQnvOWE9(v@U5g-PLCmqQKt+g=$9{Sb>VbrqRv0UFruOVp-vJO(MKV1|Nb3%u`Th0iJBbVZ*G?2>!R!-*DKh!_>uWjn!lU z6wrokM)6&8g1j(ia*-r|NRxd;mhnlA@u^dXr~#wq(M} z6%>Wb^C_V03sS-!{26q8kYR$17IrAC$X~BXZ3w)U)U3MK<_B7W^0HNZs zbD48iK1ylB6`iroSP!KI32s`)3X2#TFFhxXX5R99TPWkaye2RlrEr$@b;b=5z6whd z6urge`tHFZGZ5(Aty=dC+g~Gw90Hf{#dA?H;3EJF{5Xc2%1b*#P}(YCwa`MvUOBD#>|v|`e%y~ ze&eE+-tEa-oHA|qw-1~DNSMC++2hsr<<$FF^AH#CYZyV^;`hRI#?Pdvh%SE4Gz}i| zX~8ygCVP?^Z^G=4BpF-xA4i1ks|ZJdUy)0BWV+eXzyGMc4exd&za2?V>_k3|UH;WM zd~;B+IQCr%D5txwSFU@S8m56$BcO3A_Pg6_cZ{UM&JUxFSGac2N#JJ*-8x6lQa05o zQ>`n9a&3At}#Ns%IR`2culTV-2;t8^6T2KgMQ~C`ee!7dk^W>Y2?JTa$-%c$#~qo;fmW_FGDMG||h8LX;G&y{+ZHl*ZjQu61J zEX_Q`N0kKa2~M4ee%;`HJ->eaI3t6${?9}seSH>hojw3(AJZptThlQ!I-y~Ch`-=Jf}pi|bz*_H2KYYd+0~7qYjOB%2(znsco~i1Fymo4hhZ5%v&{s>j@hB8yy0jE2teN` z#-RZ;fUuj>QTb$cxAgJtZ8HEjfBgP%yvWE2ndtKmRzMJe>N`S>AfzUaq#_cvJP?;g zMl$C{vNlHUw87%G6SSvBK9aI>HAeG{S@Jy0^Mk<|R-=O<<^^%11#P2+6C>Kl(YqU? zZ@w_gMOrZv8FJDvIgPP!rQ@+G1Y5N_OF7L)A#i+*sp=MS6xs z+8c8~+gMAFMXSbmtMT|_hw-*Vi+q-`&O}QI_kk`yMY9RS`9{SHbCy58B%J9=Y=2{H z-eb(pYh?wtvNX1`wwk!NJepUU#Z6lZ8q1p)(~tLD8MiaX`zd8ifnQ83 z!DfPCv%D{69A3Q#bB zt4>0D5knEgrGfMIb*Aq$z-JQGoEJo{eX`UFj29L$c4)?1llq=*WW|Ed&BJURsnDE- zbR0qNd{=3OQYyj`x9RY*Qip?!0}_bsul@@Q!z6^1r3R>seHR{QVJE|9X63`7 z6vzCsGM&S~{)|w&w)n`MiuXRGDm2b)p=Gql(+Yg`r(K3%CJj#Wu3i= zKU9-CuWJq0T*>kx7-3OQJ_C9_$vJ0(QhS9HJ!!^V+p`K~0`|RgdQG!Ij0gKJdfv^G zk?554km+ZMJ>?-Rg!?QPn^AfrdC@Ak>L(3`KLMZjvoHCp7%^wg{wrIWTX@N|wxQbM zqgdm)I39H&AYqUXxV3= z4Qy#n%-1w)y7Ek`Bt@pF&nFZ1H#_TGU1})vO{0oD_dL6ZfeaJ{vib_TStntA*NX!4=V(eoH(Qoe3-^M-x`Ql)Yx3Uq|_X7Ie+I#h_1lq%>Jh0%g zbPJW&5>N;(ewC$JwKwqo<)`x-RcF1W6Q9xw`O{#-Bbui6iDu?X?F*Vlf|P*=6`Vv~ zBvSaLj?2ZU^u;ZJaAk)ODA&W1>z9c6SYKW?P(nt9!cG;rq@6L9!BQ}#kxxu)`~zn+ zQ#oC9+h8mSXfB?>#{$L)>99wfmr34>E1ZWsqxVTiBo+8Os15)Lhw`w!Tk*(6@Z;8e zQKg-Avv_l*x-F9LcLiZeZYS)Fkvu1SGfTZZ1+UZQO5y9FcImvm|FmMwMrvM5O%oA{ zq^RdyD1AnNXF9dJ3+W8DRN5KnSf{(p#VxFUA0ca6Qt~}O(%vs(ab!5=n3b>#yMq}G zKsqrMS;3!J-?^-us3_s(3ud`KK8*C#3v6)cy2lTIu#o5FMLxFj6pf1-(mEnnRI*ty zu*sNbCD^y2I-6}&Fbk3l>F2(#PB!#TmlTpWe-huMD##K@_F`<_MqLDzNIu0BDk0;6 zih!M_xwO4T6IKe35CM4#wRF0ikbHX!S=vl5L7~~-zIUKZ<#vcv z=+DPlqIkOn>O#1RzKgd29;Z!FQ|*u?H95gVvWrd|_zAnp?lDiI_xpOXU?KMG6*{0Z z6(onL`uBuw*1Eu0g~Em{%WKKWB^0wY=ZOKcS?d6eOF3!OKE+EJ^{Js?mhg~ucB>D=x6#c?g&|0$8FhCn&R8C_=xKt-&k$r&*-=VS3C)DSoLm4NqiwN9YLQ>Ucv!{`!d5{ z0*c*$WgvRK(1Y1<;9aBmY};=ST6iy0au3SE0r)yy6jjA@<9v$cW5u}Ao|2s%TV+f2&JvSwVMolW!7BFKf>>A-YRF41705? z8Q;!bm^JCWjZLnb{sgEkRtFOCTvKhxBuHNi7!hyqp=_CMJk%xlmFPR%!+Z z>|{cJ6Isf*(K$~gcbe$++3BD|6f~zEfdr(IiWjd0MRX*iQ(#n7Eua!*a=+{Ff&UXh z7VlBbhAx3rIt=Lze4>-e+ec4TO=xjJ<<^Tnw>Vhf6bjsWKv&I^u1oc*D6O~@&5J71 za=YB#m9`K9=SbuAP%S6{0v`f`l0YceE8+I53k%Nqcjgmsd`_#&`eazb+S%2NlnA1Z zq|IOBskxQrX};sa+`~bOKgF_L|6ceQ{f`#~FV%D(E8wtJ2XQmXH$obHK{cC;qQh?0 zc^~&bsIYN$iM`f6uHn|EtX2SK+{z70Bi%}>kt!4q3#qk%y6&`77^;Tc-H}w@?{#i; z)Ai{seKm#Dqz}60YD-q8VXXwy0)p8zRbSV(V1I7L&dGW_p{b1&B zs`WLjw9Hh_WS{J0Pgt3KIY1^56_!mWqWV;r09z(QHM9)r(-(rH5IJ%fq`Q^zqTG}z z07o`nEt|-+?Xv}Dhg9%BGL}xjXi_ zTvSPHcVoQN@Xop3qn}fb8H})A2g|aT&KZGZ)`7b`C@kSSi2{+`o@0t}kdLv#!lEuy zDPdl`t4xygc7z3)gNno$)25_deEa5nXyMh=6(SU~C5?c;(ceYrEGClA!}B*s=!6(3)-7f8GTQ2S_?hzgIYF!h-yi|F#H2 zY!mnFpe_+D@q!8dJ~^j+u9JksHC&lIK6soD#m{=bhW(^#^lIvAOyUszv{VsR*alPV z2V{&MkJJOf-q&=XFvKaK(P->mS3?cAKB+Stu!YobGoUh#N&aeQfLhb zrk}*{g+{F~E9f6uoX&`%X_O0WGy+H{z+(XzVjtO4+82N!otO!z*w5})HFnVxS8qZ| z+|AN6AVJPdRFXiaa+Ei(V%+qWZ;99%)Q|2;#&wH^5K4L?*eBkq!VSH99oY{+h z;Y>qp_Uxfee34o*Tc?hXBwtthiXHL%e&;ZzswgKwRun+Ukb^w4L;2Y>#-~^?)=-Y2 zU~eoIzC38mu_cKM&6$#6$*I85f?i^fE%bK;3ASQ72qiKiY^5B4>oUrKFQ`C%TmdSj z#Mmfr@0CpO8rzC8OhNP(1b-0;1ckkN&S;IltRu;Ls7GPtl+a{7w@Nx<3V%`}vX7+#WKTA#mEeAe zRVw3VoGngW2@qejoe7bif}c)KZZ)m@fUiC*WGiomB?)3=M_127J$%Xc>55`zf(Qk* zkh~h1Aq5A(2V1;pqio2k7f=cZ@XCh5sSJ-o795xh2kPpAswTLs!xKRzt~nr^5H)d( zP8AqjJ|%f2gbABMc3WYYEbYOP^V(VxZoCyz(j=x}=6#Tl!-kZ1-ALU6Kd+fI*cPC1 z9~_yBKa#szzTa4D(B6-aeiwf4?{@9#_G7JGhKU7>KNEW)tjY2FRr;;JNDqrpA~k5I zg8jo?c0^ip{7n2Yc(s4YL~N;=Gp-(Dvq6S+*iyK<9)QOznRjf6@z+8y5S5tZJyKZJ zj&i^F+dmBPb1Qa|qg!aD3q$Z^m_V>?YNb`X-1+3tsXDfP25DLZpPYiEIBRgo$io?qu-oeeRCI43xrHnjkg~0H!tkTuIF+zPzM{m zX;|*x#~P5xxBYz{F;H+SqX45(lH{@TN~SAw3%~ekr1s)|W02-GdlNp)Y{b{IKcoUp zaur@tIBg!@x&OdqR*2Z}pYwfv)X2@BpC-YIQOwOnaJ(R56=qrFAab`kdjHbBcTumo zwhU5Lkp4Z%cBqO>Ubv$9U%X*^a@s%DxDIvy3Za!aha`kJ@Z^xfv1D{RWD1?#PTZdF?2!M>j} zyq5_dRZcV=Sw{PFwAtf~NBctj19VFRk6eop-u^j!oc;9Ao#Z zoyTJyq!;rprz>wP_3w0aKL0A(S1q)>arz(v9kBDI==_^`X6ohfge}yY1+VTa2Zz#)brHT_ zh}EwSlwXN_-Otc7C=C&FDGS>*)<1(<_0#SXF5jgZ#jSBY>gqppIy5~YDKzwZ=ddB? z9^|9?hV-|ySWC|hHm{FkA90r>pua_Hr)>0EuIqF@zwfn|cjM!~vt<`J()NOxwI5Mp zP#pC*DS|F%@X5;S>1-+I&ss}^&kkO?W^Xh18ZY1c@;OxH^>fZuDa7CPU(sUeljqjO zYi@oGIMwpz!;4>C_iyfm-TPiMskmnmYc~3?x;DT~%~$r--JL}7o>lfchy4db`M#{n zlvJC$Z-)+h*QV^I^<<|DASR`k7VliNSnX;>{n$-~MhH-9CC$``?d- zJO931_BvYp_}{MzudWzQ!{ygI5x*_({I_4|zWn*x@%yRX$hVi{R%=4i{_$n)TB|e& z{5?oI{=-E+K0ZYT638d_R0x&Ks!e_vacjobhwJdVq%6gA(@j($x*)}G>x7?Yc3ZUQ zwm9{+gv)KoEs8WOUWytoQxuOu+kjSYoq;8&$|Y2?UQ!QCcpDm~vfw#$)+qEt!X4Jc zvchP5SF}--mrtjtoNSaOI?B54dhhGlpi@atwUVr~ee^0QjOz*RBS{ywlK3|xz2uUo zD2XaCzp5~9XK13{uY@aI$x#78SE-KwwTdjQ^8TqM!xz}2>QW}wZpRg+fVxEBNn(E0 z0lrjfY8^GbF6jO+)e9Zu-gSBEy6vMOC$|OBXElLI5rnVTZy=+hcaoy*U3|2FzFM|v z8m6|#9&2V_Y{MBfsoyC{{`~1}+Ud{FMyPxY(@IXivz7iFmXXqbiy4)$>nwJhBbq6o zEgBi__UoF$4WE#Y{&U_wXS6&QBobeJC!XZUDSiZjeB$XAk?NoR)7sH|fmx+DvOZC> z$|F6CwC4;N}CK<4yEV)HxshE%6)7v z?Tek0sv)JZ=UdoIUqMFNXw}?^n&)=R&z)J#F*3UxRuJxBl09h~+=rh3LEkKWkYb~+Sc9s1hm8<=4d6e?^?)q~NtG{skP!$gW13TR&`Z zyzhI0o;j7-!qYGd?AQ;e=CQdICW)8e|ra-EwPAjKPiGiqonk>uEIAcgS5h=39aU|S4d2#ptr1hyS|z!W5{v1of@ zZ7N-JuIhY|4|gk%>N5a;tcEU%#nv&q#(y@jVm7cAsyew|^ER*PR13_>)X{Mo80&EM zR-f(t@J9?(UObV<(bPKH&A&GkFBGqmPV{%Ee>l#(uo)hU{DG1r)^yeiGAOmECm_25 zD5C8Ro(&Q1mUG82?0P+Q{5LM zgbOuJCy;s3swd_@0G}&+ML6r;1{$UU^&Iawh!Hvu@IT&!qbUlbp%QKo*vCI&JKsB4 zK^8+2!1_wfK>Eq#3(SVG^wa|%yCo?&VA(TPz+?T^V>xD9~u*bzq0dwwe(Dm4My0ts7>wK+~iN(Btw z`$+pU0_#-(J*#G~e!!0Ow(QG>B&cej03ru^;K6L57PIN0vF`a0;od3n{YwI$L5KvV z&F3}#8{2Sbi?VE}>Cv>%qwL|#UufAWM}t!KEj9lTkm})gna4g-3iBLBd?0QWpbXI; zg9O$7;Y1MiH;ABP=`hJg>;V(}5jr5Gk)Od7c8vdnSXPaAlAnmr8eH7u z!B>B_x)~sZ4iGLCY?XOd?G4Dg-!pVHWHqI7DXj5y5Y$~lC_}~HSrsrDLudqvWHW+B zpFpGiAwlVEKW&9W+%N*IP_Gqs><=;NcHuB$9a%--`?6pU0~6DzdtlLSzB?!|2$fZ{ zG$m=;n*!^m;eslsW2VOM_>_gszI5u-vx82bjzbQ~H`kF-Xl@AH8*++w0oGonfK@24{~9~iTiFiMP&C^qPac@N z?a=X2_!I$ScTh0seD_v=>b#p)*W9X*dT5)2CEI2==2N;x+X;Vq8vKJ@=rVv66Ur(F zhB$m-H~I`mUO`>0V2$k74UCm7Yqu?&AcYnGMil z#JrS9I(;Yf`3scUESN`xq7x+n;gA4FJ{bDz-8W<|%uR>=TO~BpxvPr%6;N`g!X$PL zES;x%j7TE7(x^wa>bx4$YmSy^v}FDIA$+D zu5{-K3{QqV*#$fbmylCEYmxOp?CHGYPPA3fhwrS_`mZjZ)+M-bXOH6AbC7I3>&Rek z{^C%WBn?<~iI_~DZN4u)J`J~{f$JFU_Y>GSfvP1En^{vt1x}dZY)`9EyS@EXo}2*3 z*Ir&#a0p5K(O*4mj>l|2;MPi>G>uCh3*-smkWt~#n&V8RfsS9>gGA|eck-8HR`R3( zNO=s%sEQ-|4^TDdZrK*dZ9eca1`T$~J9|LD^$Vez8A4xR!pio@6c zBC>lIf#?eY0GrhcTnHvag3)hhnO@+(C(aid$;w^A1%uq#2rWiAWw?)R!h*wDo3a{s`=b)Wd z#4d-Je(uvnAXJYMu-PlEgDA^3F#y3lRald)`u%*71wcY&DjS7#Zm1YqlM5Z_FoPDoteasF*5ceuq?-up0m61K^=HSiV|Wa5od4wZcDv`mco+lXVW7 zydqfB!uIILzqv#abrj*eiXR@M$v?n)d>%=-*4=mfgAa?zrpaaV5Pa0kv6Y1NRaIL$ z7xHp@t45cklKEbs3xR(yeD0E*v{Wh{fltFOOINQaU$^;eHfID(^BXkz#_W^w@q_zq zoUiClknA5Dgn%Dbyy(N5m^4w=Hi&5!6#PIi!m82e!;Cb((r!aqvj35UQFTG=dJDvwK) zSf(?c-dA^Ov4uRmWykI)B_!r&9)JJ!LuCTeLOwoND_;s$j1F}sX>|#ktq8ADg_rm< z)_~W6ldGwgL5pdmR!Nqmd`0Dp`-Ls*aJ<|%`3?DN3P$DdCuy00HSh=pklJc#kpE`z zCC~GTQW3kAJP8l2nwQ*r?}FyVcy7t2&8&qAv|LH?*g6kC=O&=;Gp)ZnYarw5LVFq3 zOS@btVenr~*0nVmBq~^RyRf+9de+2OoynXq&*lY*7LEOLVfU_02+|lJ4t*r^r0hzo zgNVi<`(W8mcF=UE;|DZ_+waUb`{EV0M_OEs8FKyHUqdSfsvYJ|_3)kvRzZ`obSzB5 zSbJNI9MNMX&Rr;J3sH(d%nWA%K4+Uq|AU8_OTZtD7N8RlP%&?pt@L4~dY>E<35vrW zf%o}e>(LJ}9tb&Zux*8V~5mqF4zv02YYB51ZpKsp5@k0K57)ZT+-o^i} zW6{-R`5IC6*Q0!|Lgqey;^Eg8er4s;t-$XZpYviqsr;<;oqvih1ByRiK^E{wkzNAig1i;H{P_U-&nNa=5H3GZ~-ei#yd^7Wbfa)dT-l+&|+ z5GvTa+cVhCD)sjbd!JWsBB9rYolM_aKDBKWOtiwX{}|VtEc@|7vzA?X>g!(5j~VlW zWu>0;j!r*cT{yli`fEWn(e~Gp^0~!d!5+CEgY|m<_I`RyF)WFy9zRzeSd-56v^1m8 z`y)?Wb<=CckhLv_`m)BXvcrQY}@Cr=M`j&JHNEc zJtgs1)1L5n%i^11`0s9yW3U|8#Q(M54l4kGK z>lQLmg4cUc`YfKOgvA#ON`8+p<{KUSVk{KCdhXDyMCjdAvd(}6XY73=@txfi9Jtc7 z>_%38h+Nw&&uNt0ns5INWHQqCn`m~?kAm1Yu{k|s$5Ym6#(o#emdujICc>1qF=ymt>;X)>{AI;fE#kdb)uyT%vG<-eVsApNDiwPxs;#1}+1f=ZRd4zD{te&zm-FK}=ZE`#ob$S_ z>v=)p`2*+i21d=AU-}2OxFph(H~IMaaB9=nJJd`rt1=neDDV{DT}f*Vg)@YqR#t23 z{!kTl$*z{hkuQy?&m)m99~jgvXMwPxEgK?#2m$`XmoDKXiko;fqD!&Hc(O9ceZD=W z5tdWHqdma=pF~8plRtMQrP}jzkvMxM$&3gv8TWry)Gserfr(Xzh1MT;E#6FMBnMnUVWH7W$aRlvu5{qO< zW!4697zmS89vPBA5|64O|HKzzNl?MboMb^0d`$Qml<{;db1Hl&UAZV_AfNlEM|`tD z^O|^&pwC`X)KP*}6chL{bWr4c4S4g7+r;Fvr}IR)eE3G~S8h~uc=MrlxN42DNUC2Y zpI{B+$N^_)?TK;&@MhOy!A z$6w*EAFE$0(sGI>ks?7kQn(rK zU@c<<+O&m2+65pW_~a4Uk}v2)z8^%v8G)<;V1wcSg4y_HR(X81jtpwxseNtC=jDje z$1)_aF%)Ug9DpDBrI{6la^aQWro%Zk35F9MOW4JJ@QUaTLM}rf-89(@emV9 zt1pTe@T)XYkp&!7hi9OfCvHF|c_kiNLlEFY{mQU(-h})A!OMVvpv4B46F*Ztl@*eU z|3M<}HS>r3Pp42K>l=@A|6a$`?!A7>U+uz@)5JiZ8<%U zt!jk0j)~C8A5Nu0UFSM3%H+m+f`e+Q$1&N3Yx#HiH$-qlfyrL;uEAxHB51eNotaqv zTUC&3v|5kmJ1ga*`4xk)37De7+SsD&q{Cbn-+E&ZEG%rZ#<6|G9F$;h7p#bLk+P5F zacpE~Wi|+EssGv#nCs=Z{rRJW>%aW3dj^$|qXW{u$@_kHdh)?s?t?5MYnHI>cg%EF z>(lWM!#1QFqDF6*Sk(hLyYjMO(67UEOcXB0uM1#4`GJk}5kIN=K2u758)jdzSsIjI z>opyT9q|CtC#l7J$#F?tlk=i^+>BvT(UN)606AQQ=u$rc7=;}+R>1o;3iT=%>PuPyL%itK0!V4-ZFmh~+(?+Rf-<`S z1?8V=KB;T7F`DOZfSM#izEZ7iPmIex9nd(uE!DJj+CXpNeNdHHnw3iaYL=XPsIS;4 z2sC9bYsAn);I%oTS4=u`Kr~)Dttp_IxxCdF63H)D@uDb%$Xdk`_!EDc$f*}zVbumj zAW>@~4*`;|Q^{^VMzE;QcGZ(yV2rIW#&B_%m&%z!|E;|JHMYt+oyXf|%F^P(%$tuZ zKPBYEh;Uck!mDA}b11~bYnih!G*hCB3qJR9&;uqLU}>I4v=|k-u^puh<0tC1X%S50 zQ1glrpD$3s5) zkZRco#$OtTF08Tl4!P$#7{zmLtACl%+|BKO4UPm>vwC|!nMbA)hri+_WWZeI!*lFVkAG+_HlN3j6})CL* z*N#j1tP_Go#d5U*8-sX--_dMEOM%G zfND!Q^%fV)ut1~hgCmS_j<%SnR@TJUgPSdjE`|8*@xLRwDzQfU8ex}3Z;g-|Th$F2 z%}4llY}_cWpOM?j&Mx=c>fLO{#mIJ)|7oQz@KP1SlnmS8Rk~ms;RlnM8lI?7knGZ?jCi%sHn!=g^!_Xbc$Qb&)l*F|Lf^H%MGBO?f_Wg$Xh@>z zx4F)*)z5TMCg$R4sEupbG|`7ourEZxXR>H@h~7LYxZ5al|CNPouLaAOfv~r0_c_7R zntrz%`+52CIR)y_Dix}``!tJu&2}oVGE5H}nszl2nwD~g&o*D)p}HI zkIAm>yXnm%5qsg3h89jEg!avA^q>fEv6#S=M@egf8sKr{JvpR=1G8ie{&k^X9jLVl zfUP}6?-2m_IIT%zt-B1T$Tig({w6=0L_%(d>xa_wF}ECl3}j9CYA*X&l-Ody|Va&~2uT zGL-MN>Eehi0^ly3suwXIJziTr7l=|2 zcC%JLQK;@8rX&DFajJ2LKP4Oon3NBgJS)dMnV6pLgz86wmQ_kFGuQ)z4v5~ag9Q)FPH)L97vd$>@h$OF1r?Vl zIWYtEQOYqQnucNuwUeX=>Y{ z%|F!+JL?W0KE2*GzrG$IVVbBj)6rKBX409Yj(~u~-j9bmPGVuqX1HU1J^drm4kq1& znKSKL!@a_Nyy8A06?M+$P04i+rgk81qpL>ESQ2~O8vW@ABc@}+dhD`nGg+0_u%)3q z8%I2)nVA`Onx+!BnO$h3A^>cN1Vfr~>LDJG-x6bz==p`tIV^=jw4stlgnT!@`Jaul zymZjXmk;=kgw=>v_(#6GUgrLMoSVFoEC_y1GUtLH5lp=27{36m+RUwW9ruk++X?oSEb*Fw(+QY!3P55zqTuB8HauHm49g&h z%{AJP61}f&n*5sG9O2ZiZ=WdoI2*oDVfCL)-}yfdos7O|MA+*H)PuGpqby;6qF*E^ zo*=jFD>Gsvqt&lzX3CAB1i$r+v;QaKJ0$fTAx0dNPb3cAiH@3C z3lrKIlJ~X$EbZ}mZ|JkXJ-3McqHWLf*srXh9(?o`g0#ihJ34%^P!FC-+XOLjopcU8 znR)#@$z|SZTg5R1GJ6tX)n*{<^Fb>2lf*EXVMlt7g7>_TEEL*nM(5W5TcCfB^ZU=? z#dG_9aE}-eE6Lyk-z6*BB=chiHp&)993yLM4idtqb!ui+l|Kggv#CWJ6fc2 zNf-2PuSLTnxx>ntGF3OeVq^4jW6&F73D2q>NXqyXtBT7t;|3&A<(hY4{7rnJDJa2E zXAv_XL#~=cI>%)4yZAJ&iPZ3m>#sYV%(qLp{3d$-9;x2pq>-J#n7b0oT6@qnBd9L= zfN?m$Z*mpSgzYY*R0AvLe`03n$1zFr!r2XHFRTRb-qJqCfZViYM}*~o5) z{=ZYx@28f1gO%UT+H>b0DzS*az_NG^8ceT#TPs%8XU@5Bz^yO4*rxW1hS4i(<^}+B(o|Q>ZZoWzj?H_BT9?Wl3@qRrrQSP1{yh&` zqm*eN(OX|TLV*`iK?ja7fLw^OE~TJj3$N@r2Djl6U{;@VtCnadVm+Gu8uCJ;dR`=_ zuGhQqo2cAXrPSmPY57Kn*UN`;3gRUn_Ws;gZ2tcH-?b7N$5RX&pWtySTj%8~n1Jej zi&u+?7@mizlR(rp6US5|wPLVQZX+bn$#`hAx^C={mfDDxYE)H}+E9WvSSv9TJf@== zl`yKR5g7%ULui4?DbzJIhQ?st(!+yI!)b8|QL$>ILKNeXV`FbrJVz7akgtaaNvbCl z;wC5JK#~+ccmvQ?x@uq=QBfD8xq+zH)O;EW5~Ty?_{5v8bHFir32H=@90&;UU5xZf zwrKU*IT4u3lX^7Y;PG2iHCe@hv zF8jbG0t_KYMMIL28lvR=WrctwO&9~5{0lixA=z9uS4dob?pIerCOk+`HLWdA&jf@WYMqlMi|3qW^3b3Vsp0uZ9`b~2 zxmoknU&U~Vt)I!HmnXZiqyNP#w%i9qZPx|5-x^X`9aUB$5siyIkb@4CLwh7hBcni*H|w8JhN^<_q-p+3?e*f3`J>nNt z%W5=9c-LAyUrNVH^8M?(o9TTnm7Cc&z?+Qs%IPIPiu|viDd{}__Fm-K4WX<2Y)_3GJJ6UDK)J3&suQbe?e}s#Sc$r-j`nM?F;RMpBzu7jv=z%fA1jgQw@Lp z)xd`Q>OasTbc7s_A2tOd5i(mr1t3Wc;J%KMVQUuwiwe4%kQXi#N&&P0|NvQI^L zodK121Udx{fc@1}*`}el%ixE^*dQ$@x`u6R4N^?xsX`>@`>`kmI&6A~OgSB$HJ@ey z5TpBwL?F0ETZBW+>h@>C23BSZ#XZvf%b*~vG9;v%$y7KQbvff+? z%0;TO2omOBiFQqJQ218;4x}$cnQBUlqU)~Wadxcx0!oB<^`{9>6uT&e=;cR{0+f!5 z**gTOa$#M%f!1W5NqU)eAlAOHR=0YSj9esPGLa`MWn*_n=?klgP=~YUz9u<9ZrV&p5DM? z{v$r~r8=ZIx(>5_hc;-t5y_vHNg>*9Ug`Z2(zUuvho7iy4UOgu@~Fq?#Z%pnHV6An z=xNQ5FI1OJY4%+1k-&Y-{JNF7)$-O^0rA6bm!e4yYx4>-{_IUmyv;s^aYnr+aU6B+ zt-kzp_kCKT(pG=gGo?>GfD?=tF20vmlP>+QCpK611Unm|%?o<8w4WyWBc zE_kBJjtWo>Dk2~NlX&o3W$VulOqGcIC-#s{%6Gi&LpoB*iuy?nv^QOETxmk|CmM`z zg8)D(Bf<^0euI)S4rFdjNHQsnx7c1EDc1%is1LH#e#_H%^B9ozpu)w|Y)iQMudgcu z8UuNYVK9F)k?Oj}NW;jGl&tTv>tb*X(b2}VG27{t)0MHg1S^U&=b&31_ZUVfmQS=#B2cwa}7VKx^BuF7`kd1GZtt!n7pYJHF_I2@-y?AGBc!Ntk#!aTYW}@bw zAe@YLTiCy6ngpF}V*Rgxy_6}Kn)N{**6OlO5UFiW8U2KuQmTQjOY)w#DV+Q75>vJK zq`OR(PeRm^+(eg%c>*UL4bKg>!(bTheYGC7LOTAUMF!%v@5wx7(@oPEpnNke$w0A6 z?HNhVR!WaDko8(c>Z{(L>W|`Z5J;&yAw*Z*w+C|C6GAaA`N6FLX?~`nxSo3jyWe6c`oW*_x<8J$UQ8f?v!UPKLcJ2s+Sqqh z>_)obBli;OS58GpJB1@vOAJS7u0`$-_v&l*JK6bi?i=6!hqO5jeVcb(SCS#*SR9Uc zWz)OZSaKgSM7_bk;I}8v+h$)(16nDmq#Qd)x@7P~V&)sWVTqOsBx}n6v zVa{>|^S{HK%fO}m%CBT~I%kbBq;;^=bgQ{`oUeN^MN?EerHVvX|M?9ULo0&8%y40I zl@^bo)}eu4qt7TEsWRqi1rZS1>2nsxbod(0Ar8(|O3k)LC53RftIQzd$QZOnA5uyk zzQ*9?$P!el8diE5=g6v2dN1CPE_}^@pNBoik)ElPv#yl>8-i}%ku!*fd8U*x)R9CP zF`9*-Usy#@BcS7@G=inPevYJ&Qcextk!?qA`E^dZX?mA3MqVnxP&i`5kz&q~(FDQZ z#LFX9Dp0U4bcse7Lh)aQ_*T9s=3{;iCe{m*6wkaGN3!h^t zkjgkhb(M$O+h8tkhBY)%!sb0J8OXdk#F(Xg`kem1@RRXr=IL!-mk!^%!OCjtbp({CeVv zCc~R-VZ8d^_ziw+0$EXXGME*ge1n__1gU^AQ>Ae$)f{J~iMW8NY^7-v*if<3%s{~0 zVoNn+N!+Bu+*`mhsM3Q$odBf;b*gZLp^X44r;=#3yxpk45P;r@f9w(QxjpoG-M5{axoBe6@fd2&uR~V zoteg+Evg=c3%bX+kgt?eS1P~gjcVr?xEJU)iAK4<6Z9JSp`TPmH(R9_hB0mFzc1MD zI#KoXTF{5|C*5L|?tYaImyn-eH815PyB&&8g20O+&}j*A0tCF-Mga{GBuJs)pr227 zo%q~c>7p=PctLu*>foyC(56Qj5`w9zGj*R0P=bG=w z#MHzWBNJxSVwoy1q}YdbK!>WDq#0yX&bBfsRq~ITltZNbNlofCGL23*2P~YwkANQ(WZH^A!za-v~Lw3q9^|9{dQaEwD;TZM_pkC&C9U?Za( zK&r9P35iL`DXD4c8JStxIk}RgMMKb@dI6P0je0*4J(A9i3fo zy5IKnzUw3O4-5_skBp9uPfSit&%B?V^99a-{PcP8%hK}7*Kap(zP?e-z4>#1bbD|A z;4RbP@g~E`*`M>&+KYcz|6LOSZ?`F+Mv*tdHob`57`}8c7S5*=kV%NlqNJC8yfW6p z#}&n;n!usm>cT-SXj*4CPUl2|V6mMj)PC(Y0#c`5Tp52|{hnBYiiC0MwAIX&Yh{Yq zPqfv3s5UCsDbi`L`&e)F`tjF^_WIAw=)nX|3JAaTEw}e|_LCir%bh+O6Ggh6O<&)J z{NDXK+1dQP4?{x16$XK<4aU*ma+vCB*%(dZ(=FC}bHX;5BklQZN?jk8Z z<3ojMJ$0RdmZz|g#bmMm+m3_fF8{qCw);VLk5w?gxE!8??=A38(>|QJ3i$nVw){6a zqBqoOLxjbsziD8I?w2aR1W*b5jQd0+?DvfNO}N^K}!3pc7oF3f8jLANk{V|{bHLTW;o9q2aUoF;1ordufpj&!pO z3vOCYuLx%zjqqbsHah0baK>XbVVy(`yT4FIh$GiggWV>rQ>#dqb^O7aU4^SDR}mEfS5rI1*j2{m*c3gg z5cd^M)0KeL!bz*TqhINSxkWu4EB(m|6Z8pH^AhZ-8>lbV;j6D56FL3TGRW31N*j|b zvR_fe1l(y0z*TvKexyGB-dZH+Vbk_m(Z;KFd*%<(tJB&2-#0#L2e$h5s%+cC=X+K4 zzusN_+56Q8AQL?zfSJ9H`k_J%M+1~{`$vOtP0`~a21~EwVU|Y?$0Hof%ATVW^ zatEg$j5Nj07R)T4oEb(rG@gC33qCmejE)uiv*?ohPlK)Ebp{4dv8x8pJ`Nj_A`Oc!$NT0deG8g37DfowF`mhj(ACmv&n^mixP5 zqs;@J+DqxQ9=ko7TdZ#fLBG7ba6t);$$=b(2v(OLq|bQbZ}t0~{z<}jlJlXOqY6}e z#I@;*4~#Ep zqD$eazLXh|?*u~yEdn)e`y6S6nU#E?7TJhFW-=T#Q%Lb+DNJ2dIqGI$4x&~JwJfyO z$!YO=faz>2Ayq-p1k^BWCsVzs9-z#q6rDIFwpg~@H526Dz-1f|P_ryonX zBz&5xlI{Vu+ks#ZMr zkfl2LT|7D#AQHAEaEilec_yG= z*C)p)tzf}lNr8mVaKgm=?(0gT1Y=aNXxbd_g>=>3UXsciVV;jcrW!?6XB4ZmP{wvv zqorSGk~^_bC4W|Hlw4<4t@E+Y=B&A+H3+{3bJc@Esh6 zQQ-U$&^hn zch7tR2}M&Qbg035&n#?>_KVmMa3+GxnWIWjBA`Um$M%s+;Bzr38DEs4}O zQ}lmM@;@*BxcmMYd)E_@u7dT-gx*>n@8{iRw;P($15X+2kGS7iIPSO+^qSMq5j30s zzUeKd<`c|`F#c9CxO(h*q|XQVRI;(nAL;ypLqu5s;OwU~ zbRa^1hRK>zp%Cbf$ffA>k14OIIkqCWDi7cEa%^)PXTQIb8Z6>9`PpdfYun{F5y_sE z{jOjxTEQc}O9;J;-7o5p6Vs^Chpq8k8M1T}%&+28BNUk8^^w(t2Z4IOcFeV|QMFB2 z8hAK#!xE_W{NaD13vK`Dv2Yk9(Gzm=VQPJblD)EcgJ<8sgW$&~f7B41~Z80hq;Lq^T8?9zN8^ z$IloY8I%UqU4%3n$5^BJB2^NVz-~a}2zMQ+@U9#ul za1HgN2L@>f=&G^>6oNzC&tZThX|WgOfv2UR&(zeyw7@ZbvDRJSxSAVRA(+^Lgm~0| z-gH4E)1joOICXfEDLzpf4w$+CE5y=x(Zy;3jQgO;BB&P++TvAkfaVU5Kh>; zY5f8v=^*Y(S|N4dy6c zfZy=R)nM6`7%-XSI1!@=#_eJg90%pDe~K)aC>RH6b)wB%QwsXR+dNWeLMQ@bN&BsR zCFg=PN<&Jkvc2TO7UdpTRzXDNF<29!_npzcpTXExLr1=RHT;~#W`WY-!hj|r?%f(9Poj(6NQr>q`skntCn2Nf@+WwRZ zYHbY;gr@xRpzA0TE1@knPPlFV`I(oTuzzMKQUn_e!$Kd!;(v<0xO{nA#h_6tH>4j| z0-*x!I-4g1Z(^%G*%;28NNagNtm6-F_8UioM=z8Mt!{83E^bFMM2 zMkPH{-jb4QNivSDe#@-BBUGZPpq|)cbH8D!KG3+BAYxc_uVEy#VXUAbqNRRf$zb(M z!z^1PM!J69rtwo~<6=SMQg`FZ5-I-XfTw-2D&LfMRKF?DKp)!lWwUm-&fxn}(?^%4 zBawSu^36#8=0A0J&kCBiBb#{#IRW>{eoZu+n+ELwxkz>KRFP5!wIHfj6qL70>FV); zX-yT%xA5_tJ$G6d5~=@nv+Pe)a7GvK-q+?}hjQy;pl@681Ff98>>g~7wQ_=gNWCsU z5qHui^?h7@`|a)9ks|E@q3BDDGYopYBrL28S#@kNgyR!-@YGl?L3Yx<=u}M!y!uev zQJEerUu_N7{xs91P)a1>B$$ZQ5!wMp4GxC1Vx>zpwP?oTgFaV1eWSCu0lD`)q(-Ro zPJV@PYbWn52uC3AyY%X?`n+8P<+I7>Tz^RuZ;`oHL9}h9wU>jc&uW+5%JEViRarvn z658>$q`%Icn}XX(%qvO~AyWn2_XgT;(|4|y>fRLZvG;wc&|3w%ne-Z;%12Lt&mZwzKZoF# zyCVKULj5|)Z3%rKuB6YVK)u0xu)Jv~clwC}?rW@)rDkbCg`>6owcgq+stzoX zhHoL^&(z5#`b}|s3)Xp#JORcWkQT?>@qgf`IH|dDFqzG;86i(=wb*;0R1H4z5LI-H zh=f0T%z7{1x)5wpGh&9Oby*?*4k8Trv`ynj^-u*FNZ{Z8wo-nSmtLptEP&RFwCh%% zzRwV7STt}SEI(D4SO`v|AGe%+X_o}0gu}4z!eG5ycqw0uR) zX^mCETFOang0iJqV*8e0-xY*Wy@>2Z^0ewL;<5J1j_rXncuN7oa74H9hJ2+(pmU#v zP@l*;Y>J+}$G-a3z-PuyLZvwhvePxC;sv3yo_j?mpX#A&u7_Nu#f(o)ni7EP#{ve( z4{z?1;jg3s2XaQ__daHGYRt~<2ZQM@3O%RZGnY=dp$f>RUwh8Z7@&YOX;WDeQ*r&J zM1s_ii;qB~ma;J@Tl0W4Zs>y=9!TAgNQD^_RL#b1DDyn5B(h49fYPCcYj4BWmUITalpXlW(*2pwqi=oDo_ndx~6y6y9VA@wm}RSe#uk$n&{%pc9_2 z>Eko(k_h$2t^Hsd?`|2d_7z?u!KsQb&g*~fzv-4+vG}h|@A31bq#rSpn>hc0XLQ}RK+W*FeD%BrGRTYZB?{U-rA+3QK3 zkbBhcxMsS;{dXLWx+{CuRuadrYT6^7z;$yY)gyG#|UZoT7 zmLdL^a?i^Th2G09zB>^oo=7NJiE;mydH7rQnUT_&#ltfz;;D_{neEFn`;s#|?mt9_+kenXf7~Aa zaVMTVHvHrH^3Ri!KVIDD-nY+vl+J@5o`(?s%oP95m;N0_JjZZfV3jVS9$v(}yof8g zNO<}y@%u#z@uEfD-g0a(jpk0T`QN;fzXBv|aZP^>KO7gANa1cqAP+CAUS8IeTxvU? z)P28fB3|OT|0(rfwm$sV@sRv7{9kw9zsT9YJ=}NS5dRG*U4=@ zPd$_nAzpo4`&SPCZ~omju0#L#?Kb0MZ5X4{^>fF0z2N@shtfWw zTL<4Ims?-g?e9NkC(69;zvz>m>%00#0~T3Jvy$OT*WSwb5};UWypv@^YC^Q5S4AbI<(0b13T8ZMcDYhjZy~xpgTtfalhY7=tvfScmcM>q+t~WKvv=_8`1jfQ z-+#SU|3Mh;rlFN1$%>58QUf+wG0@>*?A>%H^+e`+1&)&l5|j{mmfd^|tu-uDNW04H zO~w|%u3do*h)f^T&J+o#-S&I!I$o?4LCU!F-0!&)0c06``4O@cF2(=aW5+dV>Cb^SqK$?OC_asQqz=4aKa@g#%b&>gkeHOS~5hf+)PoIP1SC< zfQcbPhm1#ROv2CNd-&DdTe!cmx$}*%rK21*C7t-e(>o8WW=zZSuw;se zkJr$3Dh#T&B|xhFw$M|zqh)Ss+Si*xee&W?^aoguuqH(e_Mk{Z;~S@Us1D~w1c})Z zLxKgl^%?7(Mjz>q_8V!darfgxQrK=u0X%4I67gB|4<%dM$?cz+t1i07Uu4AJQ!Z8i zbSq74pbFD)u&48wWZy#0{X>_Uy6$zFOv)1~$>2EGE`aJct=cYP?uuK$vHQx5(Ui(V zY0^If_6{)dn`%vD(&yx;bE+L%qpWDidYoj(ffGW6>(NG%@((YeZ`2OXYw}(?)(M#h zV)@FssxghuLP1f%TQAF4%xPa0b?t0)ho|JL=|qCpNT`!#3#f{USb$b2pWy*(k*Xh* z(fQFS*13&a7nX5#?Qn!ai?hITT(x-@{o=0>#YbNo)~VJ+zyQZ330QZEl?yYI` zse0T!?0>zhLSsw)Uh>-z{m-|yHwU_K2JQuI;n5`3+XC41$FBSFqP^jxepA}1j|C?v zjC&mTFSd;hBVC_8Z|H9LrZ2mf%r&YU~~4TmExYe<%v~< zpD<1ppY^)NvY=emNt)u8xUU{X{X0&TI&d~&TKJp{q(+z>X`vOE#t4__4Q!%2=l2nU zOaK&UtAclMQIJria`486V0kX1Rso`gA~CL7#YQ3*U|Kq$*R81KYqiquyZd;VZh6Ps z-Yn51muXU?{u*R*XVGlRzUps%zw*>T6ZoaP67^0gr&0ie*3XP7?D_eE1SKJ648yK& zE>u2v%)v zgN%&qwoL)ad~JR2jLf3bO(A7g9pjXYtV)?JVdH!q^QMgK#(=F`j;y-YGZ{JUZChf# z`MUOp8M(cuTel-v^&F`)^M+-9NT%oOxr)<^bvgf#E@jpC;Kc@gXsdc86{7#7Km)LR z>h@&lLf)hr zU#lk1usMzXg>b9Qz50iJ`(_Zl0nnkt3M6u|^zj{*$4-bM_e|}mSy#p!%EPm+I~fq~ z6*}2e)Q+X6>6cbO1;S8ms)eFiS>o4?ffV}nbYYrHcg6yt0%2I#8Iu+N=C8n=knuiV zE$|`d>OJZ#taLU2X-Aa8AjQG9O0UDz>QLJPgkg$v*6Cn&vMe@H4^ z1Rsi#yJl1YoAIb3%rN9>6JH;tt|GZ_V<*V2j~RPJA$QJ%56@XZHZX^t7yo36VvM+Y5MiaM>mi)sLA0`K_~p7aMtH(hq2NHO5G^{uA$D&PJ54u+|YZ?zfa=8 zK_VB{lq168Z4aexdvA$$R;Sh+Mxd9ORK7Q)8YOcDo>&}Tyu(0_8|hIQN8EAItrzR($>Zrc0VV+4HD z8e|@4{p4lqh--44T1QNL@-{Vv!ES>F>7GVRz0FAbX?$IH#I@17`utOxl#1)i9Z*Z% zgHMN3ZbZY{Bg5;NItC5E+EN{md*mr}_Vp<#R{ zCEPGZly-H{nIp~do0C+rTb z&7q9RjaukSVnrz%XuA3jXB-d1`}ZVDY3ylveT=1yMoIK&DP>xi!w)Z$01z5wW=A4y zS5TF;9(_?jdMhTKs?CcTSlZQw(<|oF#LhuM@7Z6K4X)IL=N*%$`EpI9lZ&|RU;A`6 z%<--c6AF*v3CFDHMkn`F842TtZ<6*&sn>PxOdu$WMFi`~ZO$-H7N%pNP#?yB#*|gQ zNutfHr>ui?Z?eb^&LG8FJ_phEC}c5QpwY8XQ7WkuCv;?(XjHZWvNhQUOsUmF^Uj z&GY=%+WWuiU2DJlJ=*7UHV60pxv$@KeQ_9na?Uk8bvCOLsV8{tPngTSaTnyNhT_RY z^4>Ryv;lzBb6C4GN?Cc6W6GU*PT1!S%(RIKT$TI-NJ0yG!m$}tRWa2Dg1;X5ICYik zIlnom(Y+2vN@R9rzHk3k3kbpyTFN7_&`v6WwtPn8-g@|D6}AnR2o;t{E?m$nA6wH& zgvg99onI(Vi6K`?EOM1PH~3pkqw?jkw7GN5EJCA61}9zBR9`C}R>$nnz%-X9*0W_H z!!K^T!E$kiOJB+|V8-(3)WdGt=yHy8AVEjR9(FP(nbIKHH|s%%cx7{_1D5l>Sf+G0G_*w-qk#O41pWS z%I7v(qhdXvNz#*J()RP>oJ01W^F;ll-LLs^GF-di_}FmGM`UroB6OY^&kgs$lxxw1 z*HBMGk)oqWG44dLPoh!6vC?g!R5o1Y9!>N&La2}!r%GFObf`P#;}8wH8dVLL91WwZ z341T;c;7V^L_#^DBV3A9KN!O8YSb_QLl)yTyWw-*1lZSmkTzF|W@X#z?HQ=ihYbLOUW!zs2DQJ{IUVXA%LYrJ@GCCOa>Gp_-M|5R*^l|uWv5f@?@@E(?r?^R*%w8@9gY1J+ z04g+JtrHdu0?t>Jdj|1VnU3;~&9@rG%9(W!^W4tuz-iWqydhj8cG4UHoM42}7k<{A zA>)bDM`th8zL5kFR(VQcV)qXC#4x_xdhs&^4Vz68KPO3eeREj|&mjM1 zeSs0)C;Ztp?Qi3IKSK2jXP#%GRM*P+`B%g0K-WRA;{ZlK&@0j4Cvun+@MH&-sX=;G?Tdvu8Y;fA~l(DEG@x(_ciSo>JSZ{MO&9yHM?Yd*B4Kt#6ATj7<8f$IC2^|z2-g=#jFM@%tfFa#75sf8Q+KnjRmx%!>Xg)ebX`s!@4#tRj$#lNFRUut(D)af>nm73kDznGg5u9S_JxsCcXCWRHPI z-hlZKa{X7GI(nhRA)B*rX}T5d%Jm@RcgY1L#dg)Tho{LbSA9`t|TK_=p&b(o_ALHI?hjODU8wq zz`M4xnj7Yj7N&b(h)l~?&0vhu{O_jV99fk^PFc)g_T~q;zHQ!cA2y;a)cne zHXB=GNa~% zp?ZxwC%CUxn4$RMi|p7)%}-G-%;k7pV!7;~T70qkT1Ah54DOA@$7zCCyV|6ulno0E zYF{HdjJ+Xr^lCy>uSAw5B&_6jQ*yCq2yk4hu-5=+w@ph0iAxV74Id_w^5zXaAZ0|J zFVKW5MJP92eb!bpZI>k+WkZTP1Yfj#@$3f7Zwwtio3~Ch2ptV$I>cxDK=&?xY z6cgTjHD3U4t=}fNBc~Bj)&8s!_rb`bZgmSR$%EN}|2Y#^i3;ynq^H{vr^M=!rxDhK zSmMRQc9TAFPCJ3|2r+U0>) ziV%Vs16)ig9UjGN#h0q$^@@(JaqKlp#vJTo!vld6oM8+#T<#Y)^YijJ-rBv?##3sn3fWOe(g%$R+VDEx4l#yLx=&dAP;uUxok zoI`h{*VtjZyn2J~mGvG2Ez7u5$7930NrI4%V#=Mu=kJ{ZCM}Gj?~Dl!1ywVJUQ!F> z-?%K0c3*A&bcs18N~6~DwX}?S0f-@ivR3A(3RX~u(SUI0r z6cz4BRT)ygEQqix*k5YY0rqn-OM z2-9qzt6T16kM)3=oP*a+<`aT#F>EN>?$kYsga(GbI72@CM_jf}F;{;n2g_O$t>^v< zO586PT)gKqz23UI05Lm=hM!#Ytu!Kc3vD2G(DdeNTf3QEoKKfH1i|jw7-IAwSPuuv3nM zpZyIY)&Id*?vI%gfKocTo*r46)H?a;X*Q#z*6-##)D10Ir=PCgMw~uzjHz+QN2+j^ zt=X>Iyz$GE*1g{W1MBqyuY?lkcJBo{O&+&@d$|2_=-oK`^{n^k{t*ZZtGK8*ix}@T zn>U9|LMt1trlo6WYHnrc;Oy>wsOXmSuSGi~m3I61$xtPbh_kp32v5Bd)*;x6NWtfJUy#pV{ zr{)$IT(nga-{JV4)1D9!YQ&1Y1L4!FlsVE#t9{j~Ba-9Mp(AFVrkgF^14Klri6vTX19=PvLsW$62Cfo)ADSoxCOzxB%xw3 z%?!(h{ZoZ*t)V}^455OL4YJ@~%oVVsnJ2vp@1j@aNHE*gn4s2WG^dXsh$J4Ma1S%! z@d*7h+5Blb5haaNN~ByyZk%Na0g^^)fwcw=`bh<~^nw}3yeSQeyZ!?Q|2 zX(=3R-+eP1qzS9Lpb$oPPCz5X1os&cp-ZA=yDOsw0<=MtlJxKOG{DjCX=TVE1P|-# z>x3+Xyc&c;^fTrJqNMlz=mFAqVYzYAgzXu@iqxx=4n|A?bkTA=EV4<`t|P!;d5Go~ z0TZ!SC8gW;>Cq<>&WL65X#cx1pb zSrphgimO5Skg@JjK#c0KQgEZ9cpYVE?&ZPC5()CrG(sULm z)S7VONl=Vj5T7S;ACqQ(v#NqyTC;{LR0?8@RWH)_+VR=ov|U{yfoMo2+Am`R0UBBB zR~(uhByHQw;Sfij;3?|&zJ4OaN_2j$hn;6J3tawJLy1u8vTQ;{Lf=wZQ@z2KjNNVH zO_A2=+Itq6aXcC_SM4PtE^E=*+CrL_G;6YcBr6v=J-^)F3x?bzk<5SAOJwVfakA+O z#kLJk!bnwgnTe%vF2}vf$$Q=dn}%Ro5^~;I_iArO@H89H0y%6X*rb-$6%NC;W#W0vc_i&|Yyflpf|fBj)SIxMLEA&z0lZOMKG9GeGOSOkbOEt_ zX5>lha=iV#G0s^Q()-ON(C|r!*S-vT=Cr&h247qN_2#cX3M10=eDM)Yk4VbN2SfnV z*!MQZj7%K1qbpD1VkwGZY(x5nS7aJ!=Gz(Blx@ef3;2>NjF~uwR$J7vc9XGYh{+-r z#*EhaQh(T>F4CNYOfdM<`iVDKdeK|NN1W5fjG6iMEXKvAImz{?F@R}j6ISN@nP1K^ zma6jTifkp>9L1yrxFriL=+_W3@X|aXy&y{m{+!b+>nodbpsUaj-{n_n(rPp{kie== z!C4_GNLR(1ULYR}7vw$fsG-2O?MxvSL`P;f6Uol!VGPg5@}FY`wgfyT*}{`lrzfvP z2o$pqZ80|Tq?_HOb0q;sw*G}5KtSMfwVHeu6@v{RIUJ3h=e+_Mo; zFOfcHzQB*lXT9T`BgrGRLV6MqYe(;Xsx9FTBtZ{UZ3&DPESK@@2*VGQVk6`mbYM{S ziE#^g)O-A5KJZmMME`bo;pyy_Fb`w2o0irCejw~?~Yuv$Nj_9RdA&&$pD_T=qR z;W8capjDP!q1&;E(We65x(z0G9@PiF&!|~rndI`_8|Q}C=clsspioG6lTe`4tF=D)r}wHnY9yOZ zc<-9H10hSFcrIs}**)joljpvP+_mCUq;V&g)qMj6iVW^QdgKDvnB+pV_}PloVL^*b zqm4c54ap^fFb?e0ixNc+^3!}DauLS#7ycB@vQCvg~>J- zb+FVCAMSBoMg@hY4hxpRrxSe%xP&slYM4ag>X{#sZwA6Tchyg6RS7uNgV}$GZ5Vj4 z+cL^(XT=H_JstmgOowrk5zAU~BQi)}mP2*0ot-XQn*6DsbyQ;~Z)nI9%awzuz`9dD zP;~y8MFCY9I#58xi<7M$uOeMTW;{n)$}MyzI-}vM5D0QN6o-jIx+E7 z+ojpBZ?k5k`QhpcC;Rp*gz&92AQUew4)fX0#~0qDiv`Xl(%k{@*bcIDEt0}cz>dy$ zZ|Y^~j>dDDVZ_^!xq)!nYL{Eq_+k&T$z1EkoVy{^LJ~$_pmsiQIcMsTXCu0 z?#5R^@8WZ%x)%3I`{{ID*Ry(f^J5&6X9|28! z@vl9jB+e`JRAqkQY3g607oVlkWZB3n-pVXihyNBM!0%)g8llPS7=f8YL$f&kZAgJ!gN8sVpKoo1D1n$*fViq& z)38{B*qJU-@{v*3vVQf)3Re=MOGB~(I;m`b{EuI>Q9UI!?I%~*@( znLhaFq6<|P<9Iq4e4$Hiu{o@L?KnNW^bs2S+D16xUq=!{*;cmtC?PZ57xlRbBkKFq`;S1j1GW=dSRKUw zB}mJ6{(C_GYHCoRJV00m$vS-n0HmIWB-t(SZr`u*wo>rI2q;O-z7sEZCwvR#Y)Ko8 zV5Fz}PC%EBG>e)baW;-=gs!f~+SuA)Sa*@60b*rPR+hv}E%l6X8gfg31Sw+u0Q;_d zgp`{R;Z0BwtL2VDqLl{QR(idy=Te5$W*ZfeDyhN`0)re4!+6Juo#1qv%XIQw9i9(V z)}183f^xL|LIP5=S$BUH#>uho6ea1}?G&e3RqT{xx$o|j=7q5DmKCMg?Ut97RP0t% zwe0Rz)(x}oRk3F?e~6MsD(=<1la&vxcJm44s2xuLzcVcTYk{bBodN#*@v$9~J+VdwEM$5Gcg7vOdG^^gC=zdPHr z>BqSZwi$p!!BLlo(sm3WIhLZNDWAuexr{gAl;Ijw+ zuIlTs(9f^)bxBzwW0|6uxI;rmVWWy+Qh)h(drudJ99adBkXcRm$oZ#AR^)?!r|$Bp zz@$?4oaBmK%ze=y`&&rkyzCg&N1G2O31c6rQ9<7v$Dc&_sh0T`Rl;3}q#`^4sjVxB z>u6v~t;Q4Hb?+xQPw67m9d5SLtZQz54A)KG{2V#13Tw_wHI?5g(F^w8t;%Ka+N=A( zb-UlR;BYTS6#Bj9_OR>f@b(CW$$fV`NcQ&bWQ3*m?sP)<=GNebF*E_y_o1)dGzP@_yhO--TA`X``_0;Yw!QuT^&96!8mzn zmC00az6JunaYP4m$Hd!XtenuBCx6Y5=d4LO-DtmL#)E zK9=4{KWWEtFi%uIjn zt6Ee6ajC)(yWvTMew6HC16Zuz=_C??v+=l#bvR&u7$9dfMLIq*EW}*!+QDaKcU`~Z z%fx+rOl~Iw&DF>UiC+YMy*Gt0OvMo?%G0c> zCK-$79%C0^m{YlK$N1hMP#FYe&#zfv$D`bjC(Ojn(~s%`sOi9D@8na!1Hz*-_u zu68!KQnw8UVeK!+#L8bwsQQ{gN~D_Ei+$4B@TsJq~J~ujrN?&lc6&!|u_&cTP+w zw(8nmBw(b+goCaV`nsxYjtrXY!M~X&d%Dr)ydk`+24QHus;tN4B~)NwXkYL7#u0Iw z=)&L)Zl5EHn}KN`1djDrqWNg0$~zHa%AVL`waOe`j9Oz0YIEoQC>3?2@j_`{1P>fM z5H$c*SVq@}-5Li>5&Qeo8kv2tNvj}`D7Vzsm?I+{3RGj_-NN8%&0~Tz@IOpII?R`h z#v+anSs6pADgmRxC|f>fsup`*KvHPfQ0^se5pa z`WUT{n`^QH`6(eHV<#=`7tuh4;30Fqy{g^R$ohqJ?ST|)FNn&l8~w6=$gz-*$9rkI zgdfWa@Y$wOvj0<#PFeNjfx|m7|F?fy+CIF&eU^Cpbz7~qV`1{pz4P|laZGF1Pt_yu z<=d6(kF7mdlSh8Hx8Kq5+fbNl#{r?rOCa^OezK3pA!2uH(Ac&?7PXTIqr3GSrv7A} znyNQ0cN;L;(N`$yQys6a%`_>IF};tcDV=wJ`*+rAXBo?P5B^>IM~{zZIk$H|;rJcX zy>YwwRKK?s)H~1=bFh**e(z|+ddp{VT?}b-@9xx5637MJyD4TXd^QQ49UYL!B+O3U zw@H2Swl?RorStbe_V#SDf}>o=RQI80Z|BO^M~}{{$A|gmVyl?yo@Aum$6@MS>ts{c z!}3zcF|l2nEb2F7Mt@Gzrn-IzPu+Zc_vb7Rzk6F={nu>fpYt;H?p?j9U!ObwT-3#O z?^~C*tLdrxxwYpZ zX9FD5i}dfK9bfhH`2EtuKd{!NXkZ=<0b;a4@J9g7De!wx8zI3W&hk&pVN#s1WPe<3 zf6QwfGV*{DfRIC-e~M%PG~UlGPesLpLkbn3wdT)00@gbf@_iB57Wd{Q%EXXQr2xqS zDh^zB420=}wweuPSiv|W$k2W>fo&}73m@fc+#!PCKtvD~8I&Q-WqBdk6&CcO%*hE6 zB#UrowgJ3u!4w&gn3Kbj7QxpC%iMhkQ4s;8$^pGD6ln!b_!gmVV9cFz zvoE9&VXsiaFJZn5b$)%wun+JsQCD~WW{q><5PCfw8Q#z!mhhRRuuFJ&mWXbS2soyZ zC`IJ$z$J*)26Ivupl}+RW$wUT6m$U>XxYZOuLMSvf`JI~D4}{Mmjt=omf#y`WTIS@ z$%U=uB89DhUYY{F{C3o$4Jm?9>2q@Q%60TAdCa;<%%*`l#sLiCKwfd1A&d)QakD4})JPnZBA)PR zJh4GMsaHICdOW2Udu>}h%?=yA#^Y-;irr=~!;bXlg~(<`UHo)9r)^)^>G-tigb+7O zfp)%(dDmuTjnz#X2j$Tz&kyo=EfCUMv)5Yau z15C=QH?;u>g`!?1FgnuX);T4J4^rF<4u`3n0<9<@l);g_i@@XQ2th%B_NNr%ycCN% z^k<)$O%d(fX{0n(pQ?LI#fFkDRRiVFhH!kSJtJL>lTLR& zLNLHGW&}u3mLLOl2z?4d)0fHAPxD4g1JOmu1p{gGQcYGfmeR8mD^h9+dZQZCjyJYus(T3 zr-;nE&(EF-12Wbzm?*m5*RFH;U0id`;$m!5odX;ZhT z`(l=HN-x@0KaqVSm)IkxE-%V`m7>xm&eNi+hSh2T0{mA33+wzETfzdY-2s!YZL?G0*gomb4n zRe2&+r?H3+fLH1unqEvd zwdZBtZa3fSz?&jqO{Df9%SeF6GQmxIOC_q&i>;N?nst{QoAZ~_+rm(jy1G=Bpme3= z^oRxoETkXS_VWueCnDy(U5LE1+Ec#uy1j&d0sutC?=SSnafZkU##vW zM~9qLa1*TjU9+AyQ@n2^q<#;uXxRLAs}B2Bt@}H$fMV-$c#oFg^i&?M`y{^cWj7m`Th|)>HZpXs(RSYb-C1=sbIhH#Ek*OZ7~n=+!I-a8azU z8Cvy@86?Yz&8#wLhc@VJF~rK_Z;*v$S_K(d#<>AB1x*hy>8QaeA$BSclNvxoR5XEz zRB?X#Navs)&j%@<9$$@~j5@|wT|nz7OdlLfBTg9-@j*r8pvy2mOywbw@s_AD|KMSF z-J6Bo5f=Ymq(Aa4FANT_OYZWy7;uV0{n>$*1TZ)LK>rs;OkTx4ozf zNF7ixr&>CD#TxRF4#sW5q~lBj7bOCrC0udwE+;bTqB4&Y&y=QNlMGpk{Z z+I^*R>^1LfivKJ|Yx^HB=XAhK`|(WThaLrv1N=kP4C2?+37`Pmz+r{)~Aj??-C z3A_qLO4;)&-vC!qMcFJ*3eiX2kj*;NebVpl8*!Wpw=6V{28ll*%%Re}pQOg-%YNQX zT_E%fFN_L{V7UYFCbV}CAW;1&#I;Oi`z?U=yo$0Cu5uj|DpDj5s~tqcHAHGX9&%fL$uq?NS{&oLkXL2; z)#|hokI=v~z+3EZ#z^f?)d0e1klPc`IS#P-M+X)Mh%y>L=9{7)f-9~)@^uH;mp!Po z%AsR|xfl%$yY^L})cRi4Z>X{C3;o`2@lsYi(iUa*gNNn91Q5Kxa&NXu-J(EC0z{PcM3JW02OI;E_$gqsY5O7Pv|+1iap>QjR%ZHza12A*4`u|T)>m%7 zU#S+euF8&?80_J!x;W}g7Y%>LNb9UvmWQ<DN6bCCh|l=!Bt zF)kk7$`9C-g-xHJmLz?*Ba!(`Zx&`(*Jn8wGf$SnxbVWC?N}avW3t-GFwIx<23d4( z*T8l%@j`dJ1DyL~L;L{!r*?tINhqH}-{ab#&=>43ZuFEX_i{*91+JBaknxodHAt8z zE7xwB`{z&@v$tHB6g{pc$H17&AdOv+=YCt1}0Q0nu zhD-_t-h7=u4MA*wwmfLu3fg+ISE#=TQ^%t0I=kaJs)X-LJU{=QSC6lHCe!Vn3ImXd;zqn~Ped&1dc*yeC`0AK$Ir3=Ymq}d7 zpC`9b8kEMLKKp8$y~*8|ue(8S&l)OzCC;$@oem>EwkPa8=8Lzt$Jv0%SgFm!yQ0HJU-RYCptk;$u(cW*Lq7>oxvS_k! z?)%8qK#38+C_aF3{y+EcQkMUne}^CZ_9n};_4|p}@0{=d>faqG;o<)6-_g=BFtM<4 zJo&J$#J90NEgB51m+4WES(l4eTGPUB$25=H(mB zz{vE*n9-EXNU7q=>e~9o=4SD+oX(uyzQNXS5`R99e_Ht4zhju&2q*NW-HxP)*gyMy zj}9U(v+vLLB8Wkd>lY35(@{{%CH?K+*{k``4Kr`Z#?nfL5I;>|Y>CcSbG0OmrWsG* zHXBZQdX}xkDP*hGpPp!~p8MRtVVOM1Mzc^po|!~Z^)LT!?SIF=YsLKy`j7q{4WG{6 z{vEz~#y|YKP||0A`FEw7Vj&tfZgvm;-O-zGmM_T->YaXm?#}$nzwTZg@22}O>7q2Go(BADHSqr|wfJXbaW<;@ zUnK+o|41!x{yS>1x%K1c_7wWg{=wnV@dLG}B00ahzWMc!YTzTR`9_DlzCbV$y9@(j z#6S3<8km))DwTmv{C735Fai9JYT&<6i_wPS{|U9Qoe5EEhDR$k@79!SSN~Hr@PCt9 zv^Q*xr}5kW*)wbWIc27Xq*3h4cGOt7p*3P%t<-M1EV zrAe&)CL)-dj=VG}LT}Z>H0p8Me!pcr}Ol6CZvxl=EEbv&VY+#7Ef-*XmRoU8m zsj$!YRKcuh*Fj;5S@87`RvLGD0{Q@(^+?^eHgjeejbwf}+Yf!p7}oRQ4GR7kJ=r+P zT^mMYSwqQ{$mdowmh1(xUYkiey0%-%`c~yzDaP(QTd9Z;wjXJhDYie-ZA!|2WV~+K zVW#}p&Gs|P^|LJt1?fup&m5mig9S`Kkf=2{T84EyKbl}nAv#PbLq8|xZ)%Z(Y5O0j zg@j8vG%BTH*SWlAx5B#gQeWzA?dJ}ogq9z629+I`yL+`L5Xb(*Xo>xP{RngAe#3;& z-fQAE366uNd0qRzsl^+fCWrr&T8yW?H<#FPC=K~&&rNx%_7H%sUwNno4v3;ThClkN z8fb?arp^Nk`y>?L{i7O4jq9%>QyDZ&YOnS71B{Fh#Rd(H8i9Pv$Ql`8Z{0r~&pO5W zi(2@kOgPAl*H4NE#yd|L9pIc#e@cQ0{Abm`Px{vXNj0#v`tl#uK*tYHJo0d+9;$(! z@{N)!K34}<-;s|5a=qm-9j@2HSZc1bix zOjEJ=Q4{rV|DqPLZGZmQr`b%9!IRPB_%JzPjo>nPB2%6JBMaDH)M8$tE`aDA4D{2j z57*oAp>K&$5M`AL46X}eRiWD}vdqk_jwNPkQp1Vmk!E`1FY{3D#ob955F)P*orfjh zj<5FfdTz7Ao5I5)JWE818Nz2_auIoL5O!y?(1|_;o;s1Rj&JCUK4#`j5-C`Z%&?;3 zuW=RI%E&N?`yxJ1=adws#ce3uM?_0$STOCLfp}+SV|5qFSaA?wNxR4(KLL6ghWzYw zCM1D@lZ+#|o{UJsP-IlN<)RHku$(B}i^wb;pPIZOdhvu;4P{2ZS9s9;XSQSt44BkT zhe-KM&EAI8ZPD|TD|@V-G7>jz#>wf2YVZMtyQ%3TSE2nHpLvvqIi&<3%)z$wbn)2r zR+K>yP&Te)rb8OO(1+ z6Ee<=SXIlF^u}gWI?f-efr5drm3ZdTAD-~_7&`>N+~(v)opGKY*cR~^L^x2qD4Py1 zQ~n&TVVX3^PwIC4$29JZ9uKL}DQAD-uc)&+9x?$Qk^g%)2@&@)jgvW!3iE_S;1r(KQ$;VCP~feBfa9Yq(u>l2J|I+9={>Y%X}L3M5;w|6@|e=Z_J>t2bp*R zB`h)`S~s1me7M_}^4LPkDYpG+(*nOGoXCXys!+DLf`EKJp_bpqT|rJS*dd=eAn*25 z35l+coGeh$1TZsO4eSC?H6@wP%CqH zOiFDxncN>;&`~E-5U%e-tI;e2w1wT6xH9Y{V9h&UPp&`Jj>Uepd)8&7Ctus9h*#4H zmo>Gv1q{1`%0egi!++Q=O~$k|DaV^WSI^WT?rCXh{fk=MF0bOXwtY}_D1mo=%{Aoz zi&|*7w*5EMg6eJ+tbYBtxBQ=}MP^vZ2nlUsC4Wy=^k38hzkNhr?KC0tZj)8L{ohlI z(B%!Gzo~`GwO7aA)IyMNJKtz}n@5v;Hud9qiP!_R2n{ZFqH*i}i(2@zf0lQ-pYoZA z0N_wgEqvm)29fyg1&}vreT=z$AJTmQRCg!e#JlQn!QXJ7>Rh??bR*8x?kmg(eL#PkD<*C+P7u#>!`Gc|Oxw_xXh~BRse`3a=oBw74 z^j^`~_SUgO*Vr!$?|j4OZt@BIFXXFlgV2zVPTtAKS$PUWgHHWI8QzDl|0cnk(M^W=n(5b>`(t|WEE&Cu zRv>$sn0kXoMZ^1i5a{tB5A}#xiBJ%$!jo$cz+*>hMOJ_^7${$cEeyuhyoSiK1`7xT zduv${d4lMnuYX^>mPUAgYVx6z3OO!?hk(}GMY?T(D(`v-?Y0My zJah=EZp*3~G$2={8GOwbii8IB=J6H^THhtTOOXw<8i5plwrivh(LZKP3ByeH#4`Hy zBtRtKRhcMHLSS4OkY}5bWtLqLLl+w6qX1W*7GMa{r*8z~^DhF!$^=@k!I?Io`)(0B ziVc7`ld||CsCOH)lN>m@jWaLop{*Sy2eojB^K+g?za8SZ;iVnjq$CppOp^QiqL7xb zm?BG(OL(*qEc!i>p9(xiV^x;eJwlzwrb7iRP-uoM;JXMW zjuqfL3;yIiZbw3m;PLWMgdQqJ?%3~x0w&{5 zyn|zcTb(JZg_RBLHE$X&?1oU#KrE_F*1rV6z@x?lOZ<$cOkb8@uOY+IpvHj_78R=Y(u5I zLI^l4d0ELOsiE^S4J5E4Q(fCrpIC(X+@vBY(gL2Q1sSA;c%_A z>RtI=QbbkH4cH<7;tQXNOr*#XF* zB^r4#v#Ui^7q65nOk-DN+1OQg9%8Uc#x`SC>Bl8wj)@t^Fdb3O21NkAmcQI_K>&(Z z-Vo#^Rdxmjw&>WaB=dQ*11?wd$VCd!fss^=jAAYV!~w9_wA`)Z1ap)OM+C-8Yjqhw zDTTCNfn(Xmj|%tcVjLFkV(;*i&nj1=U@Z2i`$ag7vt?jN1>jAY%aUSbT?M8mR$e$y zN}nQO=a;JK2vJ9yw3H0|f-lM829+~*mDBCjQ*|XPV**x`HIazow>*WL88wbPe(Q)D zM~%`RXt`qpc*9#LaGy+&%eq z25v+IxPe^)2Ro|jm0`a;5cLc6K@|KY;@O!k>2nO&geWfUtsRlkLuDY4iocGBij3hF zvyrfY_g!NeqEW$7QZ%wr-`&5;9Ro>U*Yl9WZO?d(z?T(he74;f497V=t@Yh)TH^`5 z#sXbBVsPvMw=+O@hQOCpkXSd*sr0J*2xyB=CD0@ja8Uv1KB+xJG_quPs6+yds32q< zSkH`{P1CtW6B~}pD;}0isg;9@uOmXR+o;|(Mu4l7w%Uf+aU%BO!!x}L$=m(Mee}vw z)HJx=INEG^+Hq4G-Y*N_n|O-Dx}KpXN;12tWSf9zPHc+ z4+ol2{eK~c*FA?3Z6|e%jY;@x+oF)K+%fg{u zAo_CmX8<|VEZ{-t(38)&v7A6L9B|JT`YRQ1G!8Im0%-F!wPaC}mvqdVXAFCS1UUh` z92eSu)b|cG7B)e8UqkE{Sq19u3dn5(gz%{{7NDGkfZky#3Z$6sLSf0%qZ%5cuJDem zM6+Rmq>_hc2K(UH*FIlV|2wy&^wn<6L5cc1L8Nh2u9w@ecuwtV+`+!)Ds^_H8we+I z^doXAi~qwGT542g#i2cJ%~!y!GV`C;8li3 z5;`c0HaX!qtCp#tgEM1@n$w9Ztb|UrqRDamcAQCiqm_g%@XS;eHC2L|NBix$PSIg> zG4uKXP*d37*N)JAi^4X?^={#`AK~PXMYE>Hh_rn(|J|}KIFY@=rpo0FuA%Be=P~MC zv;z(<#jpK^kl(%MiY&62pYH^w=HjgVC+ojMm%w@x8+&Ts>+B{_i*(XqS&nogJC^!f$g1X-n*g0bsej{VA_Bkyke^S&(D@hp=ze!0q9Ub$O-Jw6!@E3O&; zoW#Qsz2QXRIQOa;#ET0ph@bOdg}}cRwYwNt`{J}kV+TLUr97F?_>V12(7^x_LY)3jgI>$)k+XQuoH;Q$*#Y!beo>E4NEe{Hg0HS`TwWJS!_HRT1$Ap9MZSdK(bHW6|5#y;AHLeHj34#C`) z%@EB-dBaepKhDGAn+x(icaO0&ciPxOIf6IBy;Wyj;wB7#`l&T!g|f?7E-+g9!OKa* z>P(PTlHr^MI@Rt1us;p@A4SB@a^^>0MJm_Lqb&&UTFv?X6icqmGXlE3UT2GnlvNY0 z*_UNLMz>?cK%65VTk1dGSnWWrxxx{Tx_w~=hD;mOM@_;LPa2Mlfhw}AQHYfSp7B?x z{QCw8K(#46NK47P%c#T=-ArspEkU|;0@BF^_*e;`dj@E6*uxE4m5qDT#R-@PSH4i4 zW{unTh^uNk1f`pTPk$QquILacu_}9;P5%L9ZCb9B&qt|2sOnY<2yZ=O(t=^Z~7Y#cyB2&q3V|12m}E~p`3=CJ8E0hSN`?vvklB zPvBF*fapt9r9Q)BOb8S&i1s|*WF2D25PgUx=={E&d|n$bwTg~2a8Y7&Qu;yW{t|a9 z=NSIo6li@9tXBxkvY$7T-!H;#XTI-FTKsZus*-!tQEYG?v8t~*E3LJ3`D^qn5O%Gz zlxc8eariADd@7WU`_!UtzZj)|&|EUBb}18gj1K`%#@wX)KoZ`9ZSm7$55f6IH>HT} zXgpgfM{@%84_0+YI*yUI4~qd1+{;b)GOhd=*?-$H4Sgc^Q3j81N5rRD#i7Om}_-P+;N zaVPzgS#Qp$V?6VxXOse@KlT1U)xdJe-?HHzK@^0K0j-)Iy@JKRV ztNFH>Wq1tj6c2T=qf#*A22IC?0JBtrvj&WYV5TTQAQtBIW4`@wYT=b25U4dNBT3KV zT^_b+MP0ymA1@9J(jwLP*J|K1WFeZ6U;$z90R78o9hEPyN*b6QCOK7=i|q9Nr5eaR z>~HTMo=v2#Le|F&!eS$&Blm{AHhc`ai0H z!);rZjiINzo zB77p#&Hn|X4>cvFzA05u$CwV!5QFdIjvV;f5Z>3pyX!(UFI*JNs!w2RaAR(Zzf-oMv0-ty}UWTsaziNt&M^0 z-Usa0-@dMV3jNuvRT7BCzq%dq^|GD{PUXJ3(_42HxgE{buxcBub;P&#=F!=zT_`B= zVlP>he{DZiSIhKsx~cox=S-VK(}Qdm_p7xWuNl+B{J^ud!@@8EGiOB(`t_sIWG%Df z@<-uFZTzf6vyb*Pr*&kq(JM(P-{EbKG@;kr9#fX?%-o+@>TZ_wauEx#FNugPbtLaDI zHm_!737=ihs|svgFY0PPyZK<+!GZlx+J@tQpl$wB>gxXlwfR5nT>W1ftsa0I5DJ<4 z|ChFTg%S5}wX6S`w#h(m{(r4q{e!ldZe9IX?doB-GA1~DD1CjEUq8FBg9Kn3pc&y` z{=HkRQc_7Wq2crs$br!RLEDsU6U`URVfV38F#T1#Djn5bC&f-i9+m!0+f3=tfn}J! z8~t6o>d7#*)SJ%)7Ek}9b`^w<@ptWtFVpLPs9jyAa{l+UjhFB4R*C;VYghjbZS&9F zO3S6B<#4*_p?0O&-Fm!OrC*zIcz1QOg0NF|*)sb_?ds!nPsg`U$Ov2pt=`Uyy|Gjt zWAokkFXOZs>I@UGg&39T%IBXxaz;EQ84>qnAnfqT!19qJ-FXx{4F18<%o0XesPbA7 zeT?`D+W)lm&?p%25v)n)#Xy9qMYIK`u5udoBf|44V)&(5Y$+wjTBHD%gPo(4Rqq2! z!a`X?{0Cw3@ngU^d5clF_LL3+9;ZmVO`yegFt#3R>!|{K;}~NM3{u8+8OKUQRPLoD zgkhDDevrMerzYUurAwwGXR@Qw7d|e3aZo=0ncBo`Fw8$4e)~Bmg9#joWn-kDpFl7$ zc96dUrz$6V$&FUL`#aR>s}JpOXp<(~ zU)8*}@~q|VQ<5AXZRByUb*(=G{eRc4{M~R8=%edcikUOrn%NBt>Mkdo;^%lL1xGha zrbIoAZCJQg>UD@Dk5sCrP?+|i6q$lQM88rdH?8>|IA z{|9Yjb~+vx)m#n!Jx30+k#>AgwfwpPun1gm__=mAGlOCg*`M-~a> ze>tm7e)sFwn-)~x?-un#?sClCuVF8(phYg;H}7JHXK`gx6EFx5()~ZQ4Kww{zi1n& zi&&k1qiv>2$UDYH_=EnUZAv8+ywUF?p%E=ygE%8&N^%A|xE_->G>4thn1QIUc%>r% z_VL)LzT0^4Ydm|_kDPzgHqKOGMV|06rDb`%Pd;U=@=QajX3fOAW_xTB0|C)G)_^~;RTsd9e*@kz`3%Su((b+HZ`g^zfX{tL0^eAm!-#LckN(|@+ahv~ zt*plWfrp}&|9TIssc5PTF8>0_bBz%@nDAB;%Q5W%j1B61XjHkaS!|~^b;A$SEjBwP zK4rtyV>18{Zu0)@ENbjF3q$yltpFf8OiEfiM(QSY;BF4!bOWndNzQ^IS!AzHaxFNQ zdhSw1+Jqnaop8V}!#*7lem1V$UKv(H>lK9lCyAHnQSTWMIj*qC*r5zP4ll*rL}Uu% zFvsp|l$>3xXE#%lG3WErGsZueA2XY9+TgbUaCpW?r9PX!#77O>Zqmd|5CG2QhrzI) zhCn&j=iuMZ!f%QMWtp~|GQA&C)Ksprje>@_&Gm*HPXWh=Xa21f8c zCcv5?T)z&`l*lT=i%I~yT>H1UxQPl6ey^QiS;tVKf1?QqG#vbS~Q#>WkbuMlN zipRzdV79ZEfnac}hkm9kR2NBkIS3q?a$=V31hb3F6?VU=p+=OUJO)>*jUy0p?#yU2YZ$D<^HaT#$ zmQ7PT`%`dh97qDYIWWZ`-9Ex(1U)ktOMZlM`@hVvYfVd@)j&xb5{?Of^8qT@J! zu#t049~ev<`j|2RmoN+Sc*V-&D%4tsjUfQYwF;uWWsF&Tsf&P3toSuDGZ7l`bCCPr zrTA+p+hyKheKi(PfpLx+GW;fkzlMaX!r;$g(jg8nl>$IvAHx6KJnl|05|Ly;mWSI2 z!eqj@hX&#G5)axn%yhVcfpe5d1g6meV-mZc3pSXi3Ve9uQ%jWLf2;=WlGNw+gg%#)KV7E6oA)jDbJJW8+qh8#*vwVaI9B z(K`Nk27oh7>w1_YV@U?#d7Pk0{n%Ix_mD%GMiVRoZ;g}WCx-scD5WGXYpD6<0Z2mL z+{gNbb_Es>`SYP8;JYZCr3$QR6EKB!y!$-t4+M>tINJFoR&gZBLI#jl(DoNmf`3x% zm?EPV)Vmalc8~=`a)MSmFpHzGm`3rgA&D@%gb$ICqY>CRMK9DK4hl$yC3!T01y{AA zq%%Lz#Zl6!3J7uttjS^>N%A@}i6DvvT?JrMo+ox86Uug28JAud>#)N-br)68nHZDw z1koH3fTWwGdO(U86B+>`nZYJCTpy+hi3`|H)k3B!$^t#af&8k#U$?mG$L=JuV9ZrV zIxcLc0JKF)f|~$zsc~`iNHq34OwKhd+N5MtkP}OR3LAeLK&b;M zuRt^B!dd1_b54slW7M_3!}2(mpg&Jn0T}PIaqf~}s(7b8Uyam6I4c!Fb&66c<~T@P zybW(LGg#hmOEUFTnyP}*>=|j%WQb{-qqa zP;V~hGFcEQm;d*O8r4`fCO7Qt5?D(R_qwR8FuVT9rtD` z5VLAzuvmCcbViD8gdWUYK{;~IC5qru`i4m!b@V>h4q9yCjBC?XsIeP3b159w!HGJ0 zHpr!N6ze2EWW)&y^SiQOsVQklD&{yUnI6g(Fes^q!!@1M@Tt|MPhy4dOQEicPpHcj z;y;t*l`!h6@ElR*qOypfs+gRr zxbCW^@v6l8swC>_6shVov+58GdViN{X}i)KZejEF>LTiz5~-Rpvzm&anyQ?dn(msq z^_qtJ8U%H1vs7)X*+c58mfXIovzrdp)Lcs^!dDoS+uu#=ELB%XQum&l447RvwO)68 zRL2xiH|I(`d5@j)=%2N#{npCOAc=+h`rVp}JvDU|iiXc8;Jg~jqnw7b93f3Gjc8D9 zw;879eZy@|<2|*?*Y3uQPHF=mlRr6FI-@WrNC0nh1I8Ln7KM@d`CSvI(Qu8MA zS51_;P1HS2v>Q$IKbsh7nwh1WSY>Cj*HfmUjp}Ueoag?1((1t!6eXcM!i}vuDHOFF zELW+kALydJUXpi+X}p1rvf5DkvHsWvS2-V=n&J626$kBkEjTO|v^A93SpmG^#&I(Z z;;=5)+aUM+(6N0D&djdz`+{?E4|zq?iMH2{JwoI|L#={^9rpnU{|Qdmc&hsxJD&$6 z_62xlhTT`)!D;tA`n*d7v%|iqTc@V`jWQTU5{Q<7hs@g=A7$* zh~4x{XQ?XL=0fY+h#pxpL?DZ3hn|?pVq7gJR)3GkU3H*HWskXj5i}MCf7$o6I`4G7 zoEXbC@BmGwxc~H(r53=Jh_pKj`ixe*3l`Qw81^nxl+Dz^)rLYj&OgYMGj@YGJVB9* zDXCO%&aNVmt|Q|q3Mm~##7hDa!`^x{AYd={9EWSoJZ9l?0FoE8i)&-Z0`vk7l64N? zRShO12Lp5m!jpKXzNqf&AsS@45#9r3k|skNL*g23S%D0J<%P~kh%yP@f#^tnJTPUj zalbA0BU-fynw}718-c?>w#Ue>FGKu!gM~zqxC^^CI z)5Uj5W2ST#=4N$3ho2;#dEIiienK%IhWiLVHx=_&LkinA&|p(zdF%EO0eorhd~|vv z@v)F8pO+(pYa7EA%ch1j1c6MmIY)6O~m)n$W$zH!fqQ-<_5+$m`#Rt z0AHa;OY7S2PYs@caA>hEdGTM4(C74)1@f}52Gpy<=#_T41x*c_gLCTVW>?durV-NG zZkQO)@CW=DzWR&7lIHqx0!r{KWE~dDJpI$$dflK4T1hdscotab?>7;{YKQd!c#9tn z_(D>8#ioH|PsB=B@?~CQndUxK#K)!no$8ji(iqzdu;h zE!#d>M%h1Gc6`0;oWJbax9qmH?EZV%lWxWP$%^l@m6xwq_LR}P<5ygFCN`&5V05eD zPgWBl6L5UW__>Y`!K)@{+0VyU!-f2l`p8OznTW?0d7rE;K_##j-j$cHnKCJJ2FDbA z9Z$E_k$SdX)3;u?wchZ19YMFz+*gzRWMglo@%*vidEUlrUWim`_7w?VD( zV!ISPXDk47Z()Ge-aTW)YBu0A`i$h025cjDptV-ARnhcN?=xgAVR{+AL_tZQ_0%*Y zu}S}aU+a!qAoyDUKm#_bGPmzOZ{}O_IXT z@Ig_(ffic80DfSGI~iTSF1jCA6$s6)0CT8!Q?uxZj*|1&W12BnLQ6}hw(~+%egXDa zJCKt3$X*A4ygkm=0aVXOLbKOZt)0HgFZBUbf@JnAb>w_8=(`9$Rdg$57)Dq+eSOKe zE>bYe5z-sxStj+PvEgE&>(M4KZEm$;aZCm)A!O&MS#SFcdzwQ`-$H&ZkdNztelcN> zws9 z2sPuW1MIWnH*6IvOzQ2!=u;q>?DehLmy(%i3&9gXniF@6uO3jh=f>Q}ho1`Jd0P=rPr9?@9}C z8!WwR83=Vy_rC;PEkAwM)A`vffTi{gsEL9k75+pv;?+FA@H$_ze>y!-_$z?vehK<3 z@yGg1C~@%0^h6`BQu+Pi;IHJG+fbcdkx=mU*By7{Z?F5GA3}+Ho>C_9w>iJV@ASYq z2>tUF^2dGpCJgaM&GX=#A5{cJwO|1`cFsweA8J>uD*t=!>c7x754EeVCDFIJ=PG*7 zraJy}?P^>@P3v+{g$8S^`yeZgFKy>EF9mW5G0MwL?!jYcwxIM@#M4=z^Ekbh^g!2*+Ljz~SlaL+$GI z=gH+eA~Z?W+;kWB%|0K)q)i{793shRXTYegQ)bp?k{=_pDtdOTE-FAOHV9LW0?U9j z__XV<+LfF$&cN6X_H>O}o9OFsv?)vi(vQxP$aVV zhdU<9xUjzRg|#;|-Xt&kVYhnesD6i6-r~gT9E*%>{*~j-yZlM#>0mMg!?25I$NV+7 zaLPAJ1dD12aA^Nrfm>Nspt9@15BE^JDpdKIb!Yuini={Ck&2serNednj!#RUFf~05 z%7}N=aP%!!ikGV<3)Hslj!XChS9h2wm$NbH9l0B`A_s^Swfh9aMju^C8YnE;d+Jh5|f;hdSx}4O-H<7xt%i&S^Q~0Xz{J z{7C0ZIN69Z_k{nLoKMWnt~#?I$MU3G^9)FB0fz*fJX!K*xl{oIlFz&=Bl0IgF!p}N z(^`uO`$^a!$u;RPK&ci$%qsNg>yrL@Q49yzfn1-RE-*@DzErJm6+R_lG9F7gmjQOwk+oR;`64@X={8^RI{tB z3##NLUOqu&qP*^ydmB1KMf+>;WiRCd_aCdJ1&{lgP%107^$2oful5l;OR3Aq7%Cs# z!ORqs!)(V-fwz3vd11$06uYm!Fm>$2w8fQ-xycfk+P`U{93zL9uP!qVE&Ns(ax$=t z=(X(`khHVsUS@SncU3I?+@&B#g<~Mnl)Z2C_5i#Vm>|==$Apb>XjrWHuv<0Y{oHlR zv>mc13#d9{F0UA$k(}xI*g9s#-&yyP=;^k5=dlobtw?@bG2pm;_5z744oGWKzv%DeZsIOwc;X;=4|3 z5}!#Fbwio7AzBj*b|R(Ih~%*w8|;Om5O@gn1?pFGC|wzj5n zVlNunJ|sITvuDJLL_$v=)TBDAk6B5fW_xApnK@PJ9IUBCzYGqaVi3uTnLvvw=02|> z0Tg$EBl5Vf<>~k(A7-$$k{(Z6a+6WA*9Chack_-S5EI>Gr6CRcF=xfCSgDWw8MtR)rN`uIaSpZgS*w zzPvb%*}T+{W2x9z7yK`#OAQ%q&3Fz1Mk{7(GvY8?!-yBA;Ub(%c)_hVe7at*K>2AI z%=5hwt|G$5&f+im$9{kHA#;kY8pgLs%Zt2L3m16nHk6S|jQ!;O=jfZXIF9XS%&}6p z(u_G2Y?A?o>7#zgp3XPD3DT|gRGo5Xh<)5PLE0;Ta2J2+zcqa%#{WjGPQ<5tm859 z?6)mQKOBS2Qa_N`cd2WLUvVNL_Jd8VyLvr^$k30u+VVuf>w#A!QLf2Mh1s*wx9S|8 zIJoi)Ypep`Ynkt~WkQ8TBD$8>45ZK_8SQRDr=(UzEN>VS&=mWLI}`g@O%&$lBgWVR za?+(u_#Z~4h3bmyS`t*L1&1Ux(LMgDN~%80A^{(U``)lB4zbnyGfFL^c~#X*J@kk(&I@L%G{VjCk+t(3U$c+pVVzV~03}c>51DHtyBV zjj${|6V%HsC(9wHV23euz#!Eb#Bs2jgi!YE_R4e%GpRgC_Fn z=T3SDb8oU)o+k2V`Gp;N4lneyRN>cWp{j3v-4{$>f_{>~VZRqaX6IQdUsk0Z5Fe&``GzeFo9{8!=xBQOBKA7_1@o^zUpp@5FXSe~Xl~zGT zXRXlRefU&oTOlYIp}BIaH>Zy%cRX9qT1i<#?aS8}hMY~;7@Kj$#!IO-$h1b;mw+$7SWi zhy_&gpA#COo}aUO0#R5tG7!3EJL7PdCd0 zX*oVIV>^mCV}uZ`iHJ>^pnmjDt?Z7riP-5m-m`C;v@^tyyqbx5wK_dt^$o>@~s$(NZl59Av{|z%H-rW zBUCazc^pRS1(mV_1nZEpxQV*{g1X5I{t-fHSp{ghpm`-n-KdB^&_t`POiMOOGwnqu z3;MHqLAN7B@1aib6GLR@O4AkNd~~t3ee zWBOUnSewlFBARvw$*hXT%;wF4J3yg6z!C|grWgR>qoI$LP(Dh*zi99>N?}{(XR}FZ zPvt) zl*E5Jw|O7v@sEp}?C6If;B8<+drE3%PHtgL-atudRZa!6wic0#n0w!%+0xqiaCh^c zEVo+|vH!P`@rPTRjQ{r5rrmTk=-oCVK!ZPb_NX;z+P&w~d1tUz;#n4zm7fTj%}GUyOLiUg*5X$=T6gjQE4u*5)L%%NX?I zkLxDn^G{{O10!zC>wG*H&O}bYr_~A=0AdWjF(KADZjNDj|MoRBj@NdcdYE~(;F@N< zSxuE!puCROdt0?NQ|ueijq3%&EUM7hw*9>N%@%|Rn#zA6ju@X|RVWO2wQwD$RQ}o9 zcB@QF4a!RF6==p$_Q|Z5C=&aDun2hdI9{_JQRzX(# z6Lj57c3xChTVCP)5jKr6Et6x9;cH$M>XvtnE(7`)s=2VD^%}X`P^j9>BJ4WC%_E)d z4NEIyI{9+VmN>{AKJznA9z7R&|DH}RZ**h)<6P+>*zL;?%Bh9p-DfER(0+fVUj}Er z_5nod%PqB5g;DL~9vf|0PTKGKfB(GA4)9?}JoVuu`0TG81WV%B4#Q@z+78DPKiZCf zC~@w?fL_u2PBX28MB^M-t3EK|{Z-|9R_jEL zng3$M8F}lD4{|-<|AP@f%nvxY!^I6&nm?coJ>fbkg5Q%l7ss%#uexfQtf7O=pfyJi zX500_VyKPlaYf(nE_7Tw{?hP@%#8U%;xcz)?#jCM98iW?ffRG0QR2xFBO8J#xwf~V z>kCOUvlmZAbp>~1z5FJQ3L?zRrH*u#ys3sXMaK0-o1MbOm-fy6u+NR<)Ixkz>xn{x zWZZQSlw+4_*_@IypIbX-k1revYTr8ODaK~BUJ1wIjexRl8}0*AY`-`;~mRKp-IqPlr7SQNfALNGhd&xvqZWKSU`?D3K9??djKCO8k{ z&uHb?iN2!aG}(9%9oiBVK@@%JTH!{2D133XXVp(ei7&)~ev#we*P{vw5myvt;WUb1 z6C91A{luRj!D-~=}#_=Y)v=!TSu*juiQ ze-s+d!|_H|WP)sTXY+OZfuR|wuXjdm#Pc0{ssP?$5bCAoFgpA23;3~W5rN-HEy)X1 zwE)fz{OXwO-@a5$Vz@~X>}SJ+ zfJ<}2P4@jFH{w0PxXw%@G69k3++k4~F!goDq{rv@1JOhpwzBS>z|k9dPBwty@5iwG zuVhKSd{qo2XINZhpeX{ZYbZvp37q6ahw+e7c0Q?USUeo=rE$J{nuzEl??vh0m~G}0 z1q1*k)e>#goY#oaJK<7#Heouqnpckp-m{D9fte}M9H}35a_-M3WYL0pR6dW|)9pB# z;+2!=CB0+nRDbhDpQ=@gszIQb(II$&{PO|@(Ze^+_)H#+2bG1z?s%E`Fs>7!r`HIK zxMnf>kmADEo>-ETxEpuw6uu`Dh6hfh%26&BLor31GbS=M0Efgc!BgI#MeH)~72$VO zlf1-Nxi)$$g32E%kD9(|zeq`cEDNeJuU5|!+^i((8=q9SjMF|2Pfs^W3V*4FoBv(` zqbJK{CXPHVYY=ZuD$o=jB*SBJtx>^w6+5LqGF3c%Un)N$SeMxD6OOX_Wv_bms3vK` zwNxmdU3C^P$Ai=+*zZ-~=2Kg;x=pU&$2Bfg>NGG^bAPrLU#`TktRGUdAz3c5c*YX zjitUiNc~bz>}#p9nBU4q`VAr}!HsHxdu_r@Tr0h|&hbNB{!CDDjNI5Mi9*lXLJm36 z+od5L?aB3JS9HCdFYLse($TBk-`m60zH%7-)X_L6??CdM+QkZPZd0$6gwrZ{y`9{Q zW6vZoqs_F)Ro^->`_a8hHtf?h*Zfsxpm6Q>#miCkkJ7w`HAgQ{ZhJkWeyCU6Q?>N}!biZcG`7)cZjsm^`*4b>ZIJY8=j3YyoI_&=$NYAX zat0A4QCH!mm^H-6fAV@V@<4cQRGWh?_lUMFPHGbvg7?xvKvzaaT1HjI+45~>-~+$ zH`K}O!}Bsk&kfW|mj&c2xefB+-!7yG7n!eXN4tQ0>~9y4(CrN$jjJ zFogFh{pn}fq#?W(*X82-4P5WEn@r$BL&*)g&CmZv}OQg&F&59~FYCG0sr%r$W}j8-BN7PGlbT=KP)^CBs-b zM{LNev1ba$R9m)Mpox#oU}n!AV$1%Px<+PCKD!Ek<47(!`kllbUYEIJK<`(v-`G!| z!AiJ3IG0TqU&18Y^6HEH4Q1xOwO1L^zjG4scx<_{Lc&SB`W>*^hq#GLTs{`raS7(J zw1_VjCNU_CA)H;uC!rkk`Q_QKC7g(vkM*QJdMo@;qd@GLCK<5Av5|;3{%sWvHJCpH zzP4wxh?3qL$4YM?Pg=(9p+%c4c85Ew^e!31+~vfczdGn(WJ}6lD9tkl)a%O}9zc_{ecsPQ! zMRW7vv?|fy&Uo&n@4njZ3g3RcD~}ar%xq{VqF~J^CIQAC#b#51_bES>vkpMD`b#o`tgW^ z_8UO-gh_(6H7`#9FiQn9S;;wMU#g4~1Xuy}Iw#!NM8_i%7?}li(m~&Vp;ZfY@Onl~Jnw;7Q) zl$|%#l{e#(Hx168tOO+tOyiTgq>4_(_MtOUPN$T z1fecQ5la=5niZ1=6;tLEQ+F5Bt{2na7c)|qFiUZw9+j{Mm2l>ia7!`WbFuSui!M|# zqp1PES6g>*_~=#w&u*eWm1FYVmo#0Jnq+~pl-}M-VqV*d7(%%H*Phsvl;vQT&B;pi z1+w^5n-2}7AF<%!bCr`*zLj4nHv`0(e2DNUqLSw4KQ0u=jE5qeK3 zvC5pYKuYj~G*4b$le=065$JjD96JtttOm@IrJ13`7w3x1KB2I^dLlB;tW;dy28cru zR08XD0U_K(rR%W@h^!VII`Sgt!**s~M2$QnS8+v?$-1w5iG37>>_507B?yl6PDiE5Oh-KU30x%n7rC5avRn5mF$0a|SZpras|@^&*L<#Z4^7O*#vS6zZ6c zU_3gVQp%o`N+K#Av}UfK#XSqc)hBfV<}DbdwMw2jJ+Nl+p5#WN+HoI1`XN3)4OXNs zG08?thhVc>nvr5{>yL|89qBd$^EPW_t5I(CP)?i0b4>g7HtX6_wWL-X^LCWutM;vB zp#7V6ou9ONlkJf1Hb`8X;pD5~9L1ncE)U!eDz%Q_=j@_yObCB=Kqgz@>a34BF(u6_ z)8%*snmeMUwL?WZlg+!p=v^7O6@E8~*|==68(q#nyHdSt#ho-O-UxpP?<#texjL3m zo7?U|UL_)^b@6xOngE|W4 z(mC_oVzd_g;-xFGZZ&~k-(oI4_j@vYj6y16PUJ=(aDe|a4xdJxA28)CK{J97W=}1GIL=vqu!dG8#)?QOO zQad)?u+Bt(W_N(16^KXXsgPG{Tf{{~uI?}uLKUysY^H4|JW|4=lY;HhnG3WU%+yMv zx%1^o3DBq}rY33i!ub*<;re#2*arN@<8YXe)3Ev=bh06D~#VypPbtba9Z^8y=3^ z7@qjG&--w+i6+n6YN6lH`YZ?!6KA_y8K;6CWUaP7sd?kOz|ALWXoZ$DS&Z=lyh(FF zBA_9dy1L6L)#JY-5+G-d-V{kn=LW3CF*=k-cS{qk_Cxn(L(kgD_Qx6(Jj6^cV_Qwm z)e)rLZsr+hd4DV7YKRbAZ3?+cf6Q?~eYjg^!QMp}PCA=D@`QsgKE6?_E6P=}{jU3! zX9Sl?-mofy=Y1U}5yH&ma!3~naEIznlqm9QatmAlaJ*ETe!Y0&G+{8v&jB^{l%;71 z0A= zjYY>!(NmQ;89?vFgP}vhdd_gTK*&o`s|2Z3LSy)WMG?W`G_e4kFv_J&sS=}pp$Rc} zSS%oO3Yi1AtirhzMmy^)h?#ZVVVan?&2($#vwqMtDOYg;-CQz8^mhwr9NTD5+h!g% z_l0ZLS=$=DZ7lYrsuw9FDw*_&W|-7XRkkmn+7L!#CP483TJW4i^m=cJE|B52P1bp> zO81dG0PO_kHaX;_WG$IKFnX>0Q3>(v!Fx-D9KJ^Kuj7h<3`ruGgzQLpSm#lT1Xu`b`w}QDCFgjIsky6dgd6eXjPL6CL|JxIb&bB?Zj@KonyA zu>vS`6-bPZMEm7K2F)@Z8t{yUpcTKs+=KM-ZSTmR)Bcgdyh9QkKOvV#P@?GsA{e){ zttDsYoX3YYztQaxumV3^()3Bstm_1d6-#&H2;ezoumc7d&pA%52U8b;^S@MZNjO70 z`w!_p9>fD_bpYjP`+h}`7$-Ty^I$jSNI}wa*Dw3^McqI7q)ZTg?y>?EPbv+Hq+^D$ z=!qCZK$v0P*u`{Ydr)*Pc^cK%Z-83B*5s@NINEy*g)l8zc|odkHQ)?3?oG7kqeRE5 z@WTlR6)k|g_4T{7KeQrE491K0+uoe0rfO+hA9OKyKHZqbRXV3DH8)?Doq~RUjk#l7 zBFr-qh7LFz!;tu|V#Q2W(hhvOS0T>zZt5CIgtKH+kU3{FVfNMCH8lj?avv~jzDHRH zt=Ew6mRY4S5wrUTX|*@{9y1pNMj4q5RYatZ_I2K5X(=EGgIy@dg?wjm$R809QR_mn zT6tn*$${}ib!B8OQ3BIn0C_CuiaKgp+!}mZ?=^G)S55%;g!f9;b@q&h3WCs3Z-4-i zXwNP`vCc{mE3lg4Ej3HGLlFCHm;%vz+Uo^su7R^f&8I4jK%Rm#5s7bFf_@kX=*b*f zS-K;}`N!@T$7jvgT6{pWooA>NVg@p(uBQ#avJuGZF+fU8^$P7nyzObyzAA)wPQGXd z59lt<<#w_=6L-TKZr=fQ0%~b5sGpQ>83W%^FnI6dTgbbbh^qCUU2zlA9Y4o9$s)9U z%x>mI3rWuQMo}ojsKPi&BO7Z93xM6JxCBTgMrcog31-aBg^G1XWdV?&i3AMb!q6pC z{^N$ws#!~9vB1Y}d_2he z=0L%d|LNi7xXT~EkZuD+ouM3iVt=pYDM5VXu)g0^B?n9Kdb-swUQ@?%BpC(GzlJ>%>?PhEF!aVhA{Uid- z{Cir;S>9mGc7X|LKF*pRCH`M#TLB>vF^Nagu|};X%h0!aH3rKD3dea0R94Am1|-GS z-{_kX4QfoxskuVU1Dv?DyA4*_k5U}S7OBFMc9XGKQc7;s!U$su3it18 zrd}V-dJKeWUOq75lV#7|MAfPr3#8<|>ekH7v2z@$-O7B?(V0Yq zps{qtg4-|-IbnDhM{C}~UyQi^wAh+ki|pzj*dU(3LH2ec&(@Uw?326GzZmh6GLgqv zUf&YQc(@i~1q)+D=Kg~b7k#<_8iVsIk&JA|GD!#x=&GyoeOS`h)x6PNI5ilA8=1Gr ze=v2a|FCTCHF7Z^aJ(b7^1z52t=h!$AzBz8$!5enAvL^+(S4I(wC++}|8kl8Mvoll zMg7<14UbA!;!Q8KVe)>*@xK`HwHGT}{yPcA9|Mp5Qa6GwrcuV9Uf=!2h@%nQT6tl% z6EubsX_@Rq{>6w#GbK{4s<1Y!?!FP4G1*IabarcO{+PgY|A7(jQuNXMixIz(%l?}Y zcdW(f@;bcp(0i(rC`fts!} z>YchLd$HDAUdtoYclp6sh8^n6 zui158>8U3qQ(YM~Y1}ZvrZeEa-pcGg|rb4@U=~)XtR) zNTO)Uz zKN3a~jtlqmnmnXLe?zel&Z&}(Eo>doHFv>GGKrWZ3TC0DGYfyjmaX#RvN-k4QetRA z@-_*6@jJHDaN?iaJ0zsQAyjoKyY3?Vi*GU!ud5fandHFojJ%xOk#@KrS_#LTGq|a^ zBt8p)OP7ftP`8gtSP!)O{-=suEr0`+^aM|rmZrw znGY1Od!O09`XOt;_mc?OHB}uM(lWYxl8NhZ>740NTTYx~IBhXj63!=iAU^O2jJqu0 zzC5KwH##ujVU0-ng2#bX>M|owCmW`pyTKwJ{YFq!lTedW4{O7e5raC0pwDd}OK!ZJ z99g65a4Fw+9iza#Ie;cx1G4cYQA|okOT`w_Tvj1UCJ%@!EhaJWPTW(HA}e9{2$K_N zh)&g1XyuKAE>ro1;qs9lN3)~I_Bkq&U^t>F1$>kz?1i37MttYR(DHDugN*p!$S?wV z>wRJb495vi)`$mIbI>al=ewzbU*1VOpHeKbkycVObY93cc3|k4C_w&#GE8!YTaQ^Y z4Or`N?4(08Eb)Bej%@CBu+(> z97AxqWN;n(m5`4$1${}#fipN!rePlJO<}8UyKL`Cr|R%sGPIyDECsz-A=(egY1ZhT z3ZH==Y-2GBgu`TCpVU-n6?+v(@jX#luVM*^^UcvY+SQob>?0Q=Df@!-eg`cUq&1{r zMIv=lkz1VD8Q45>&L}YjMjkBjMC`SC0lv3IW+<(2431SLu6bEKg>fcyY&JQ24yMGX z=N;&D=K@%XQXsxOqXYuVFw#PV#gWmV4p%3CjFja1W$OhokK2GBnQ5&Np9BepI8go- zc!!c64PB42M()KXdZgCAGy(Y~L!;}aT+nx7*@kE=QrT#xS&V0h9Ax@z_C5!~NQ;zA zxX$s*!@r(X)wy#Q$%QwIKojt^5hWMVsX>^CNBE>qJ8^c$+?Lv@^Rza?2UlszfdJZx z&T=b4`Z&^wO#_C;nh(psAF%%*cRS2i-NFE&t`wuapHt5AX3q+S%lz!ZBsgy(_O+N` ziU%w>B%-sZqaLAgJPlKC;olEqj$y}17k*#eJnQ1WbgXu6EQhl|6t0SzNJ*f6G%bZpbqL1&|^Sx{Wv#f*+~qKSZx6!YH@(Rvyv#LoGc zBfqD&3K0eiT>dWrRY0o0(`nF!5t!`YFYE{dNkCK|`rWE@+rh;qgyKE4!#E5AzgYm2#N7+Xx69_0$xq<7Q3# z2(Z$e14Za$4%h($5I{C{=4MY#M3TH)2xy0(cS&_A`lTo=EuS)-mS< z3n)R{N?^8`_t$X$EzdGCEkFPtrf_yBY~ToBe*)d@t`$S{o5vjBxhPrw1Ps_o$II<4 zshxm^3Pd2$l$ZeD!})|2jd=?%&+gy1d{Fn-bSrUw$sYL%>BZnx6m?6WO#}q2bQ8ury#>?L(kPR#$$#$dy9>Gq= zg#Mu5%=RGrJPqCiLD=3VvaU)Fmh0%EC=SUhs&YuL%%P+hh(|66dGLWy7O4YR@WDh4 zAJAdz?l10~ATofX0()V=q@W4Ch_8+y5S1YBDq-x7;Gc@)r1D4Nu+W>np#va~5;V-* z9N^HBY)*z`5Y8-4{E7tpj@Bv=1NHz<Kpfa33jw>_=lB`Lm_NPbGrVFGnEZ0Ew5J(zmk~Rqc z=@Ib94E3rI^hT^qCvBKum&Q^rgA#T2V`XG|42GZW1U{8cvKY!ZI(qz&_-PHpGe*f`J~#s*2LWEBInEq+=0?L4Hv3HX|{* zs*X6C;I-sZbPTf?5&^D)XBR+aH8!)}Ix&L6XMFGyu4?HaYzCGxONi)d9C~LzObRWl z?wVx5IkBo{m@b!8Y7HKNI`?Nbw+XBSDH*~Ck2>*+jA#kqpk{g`ue5SK$p(}{Xz73| zi&*Rvlv8x7Dx6qT5>W~-H48kNNe;e)^Q0gIVDjx+z!1%`1&nPVF_Ryj?nHS1Jf6<+Ev;wLn~!hJG9eugPLn5u;G@Sfywt`xGi zZec|y$cumjen99l88WBtAVAMaH}$IeIH5S7`0D1!Pt&KO)nu+FV&DLVN#3KiwNi> zKXXr7wNzpCDpa6T4S`WXH9zfPQ)3lBD3Km!t5Ro#RCiTm6f-f-#%3u0saNMv_QnBr>$sTDkQOt5sUT)kVI84z3j;k2Ef!%^|}zGN%GDTL1-s z6cfr7KvL|jvLk?!Ze8`Y6P^xNrIePI@-{t*UH8=|`}9={HenTZVHvhz9rj_>L<*4W zNg=jkE%st-%=b89OyWch)evJrHe_QJ@&a)Nw?w%_Hf2?|A%`IFNbg?>t^p4LTUWMb zZ5D9iL<}n-9=9O$ZuVz^wh|PpUo z)o%G#W$}#3JWdc>vTq5uaC2r%U?ph{cX1h)U0kM=^0sj$cXBnRUn%!;F?V5xLUA*< zb3ONSK{s?ocXUa&bc+R8O*eH_cXe5}bzOI7Q1^9ZcXnyFc5U}z3oCbhXdHGomU#Df zeK&Y@7kGzPczd^ak@t9&mw1=gc$xQkoi}=u7kZ~xdYiX;vG;nlmwLC?db#&|y*GTb z7ktN8e7hHUFM(C%lqJ=deb-lz+82J`H-71Ne(l$N@mGHHw|@8ce)ac%`4@owH-HIv zfDO2R5m@b^F<$HKyD`nJxD)l^2?!9fm?nbTKL^ z{~kjOKbD0jnxYv-{mxEQr{GpQ!KAOF5PI^5KN_SR=2lHXmqqu+m6t6O*>oqQk#{%%61;|qX?Q0VdAx=S|0zEFGy<_BEh#M>N-|Ir(!!N zvYDJA8MhO84dkF#?@Dh>(zcbmhAsOFqK?xp^j_A?SB$w<@_9T^U|zLHQjvkYA@#gf zDZR~Gz0143(R;n&+r8QQz2!T;>HEItJHPE)zw5id@q51k+`swzzXd$N3H-nZJi!fI z!3#W68yvwGJi;HG!6AIYCA`8hoWke-yKbRyX14$hK%h(}0D3yW$e4DzQG8sI8y{o^ z9eRXOGDQh0jmAoOLo4v9UDpKUK*yH_$3OX)BG)mFDj6am33Rn4iGWjDpvDt#(MD{7 z>o9bnNXn!9bgF#Ht(?lWJj=Np%f0-{!F ze9hmS&gZ<%@4U|O+|JirmDK|mn2ge>)~D;S9ABob7&*mV_`5lQX%8R)cxBF7O`&Ws z*@|T>#yQhVLeobiDLCEJH$BulUD2aiLhuRDAP3N<#t0fNv{xoNl*qD4{bp6kKUnOC zu*V-(1lwX_A$nb`*r%~&ebzhw*nx!O7lLt>rXw>#irAe!jhX1#rG46|z1pq)+Oa*` zwSC*Uz1zM0+rd5D#eLk#z1+?H+|fPV)qUOBz1`jY-Qhjn<-Og9ectW8QXZk3?|t9h z<*q7#(AA?L_J^JHnP_;`59;CY)O;RAN&m#b?@v$3z+=IMe9{%D{+`$aJ zMIy^iR>alAgQvHE;$!?0GM?iFc>?TuN{;qDKK=>1`^i}zq_2w6>E+V>;F58~=GTJ+R-Oo$Jm|lD#R2t0fP>=cD9T_PMltr9ves=>*v^J;sQs$ zUWmc|>#plA2%f95?-D)bew3w1_)TKA+cyYB8RHvP{@21RVkwricGDbtg1E1 z<$9@CBv{<-E{|pZqVv?+o}Z*Ry>4AM?M1x4U+4P;3Jww$8Xh7hDxRegnw+ty2u)Hg zO$ud^88w={^+^s*S#b`H2_*$ z`4R#5Ef--Rwcdp?D^A-rt7JAGcAr{dL??0wJ|~?kgFB@Y6N$PDk{-v`+u!5o6MyTs z2n#+-(~eCa3ThtpQ$`Qfz*~@vWSR18i>^7+3jIqs#9|VTe)tt>h)bkKWOdwV1o_dU zqaz@!WQ4e<j}b&;(@7Q6#zL_(ry zlKmkWO_~WH%vNACf#;jZ1}Ian!2R6fww2IU(h?b7ib&lS&X?OO-G%v+yo0I}(GKOO z9mv95>p7;oPJ$!Q&m2BoB>9tZ@{3F$-{LTa3E-{w;hj%&{8z+nR*fLu6Yt4JiePK4 zppqcGT-O2!@3mz_fkado9TaJJm*Eh%Nk~Xv%AuH|igb9#okRANfj|<#No53saTG^Z z3-mqzQCcR+Ignh0ar|{(DohQ56m5N==gxXbRQD8*jK*s80prtzL+C#J%} zGYiN#L{#|{R{|Y>8o}dVrY?F0jW6nPV+*XIP~#D~LNwPLz;?l^hx&+FgpqVXb4Ip? z$fswqd!9h)bVJ;97AGe_mgyniCQ*T-ahU59L4N#WEi1G>0q+rc0vecx?tU1ExGhls zS+Kx;%*(_G+sb5!s8+a%M7`G0WL^K;x3ud<5vNW+IaY8ePj}dIZ zOi;?Sd-`_6;4aJaH0u}*~QP{1>B)6QG}Swvd0 z(9sBH2VeX|@${n8eIbvez!675y@D1I%`4u%`}bh~VI&boq7(b}*v<_7+bFUBDe)Jg zL_Jx8C_)#8?6tsvXc!XS))7B2>|Os$gl#Pz)ad&}@)6Dr6XPShfdtT^EG05sVl<-~-6%)nF#-~p;xHiXh{>{&923Z{P~zLy?EXar z^SyK@8TkhYI);Ri+JQ&^?5H)r$Wv;*@hdz1DN&1R)VNfkdBV*9k{Bd$(cvi&Jqk=9 z=&JgJW??mf2+3*^npL@@f>n;c+}BgNLdSm2#HV3hD_h%2I|izOB0+_sTsNpzp+IsG z@YpLeR-wd&R6!I!oF5rIIaH%G^Vk>Le%a#NzA>1q_1o6o< zPV|MQ9OYy;6~!>#m4iz7VwOz<-Yy;6+R`M1xc}1@xKI_V1AS)**v~L{$erDK*l()MIUhw-y=r78I z5SFLZf_Cfs3okraiuv6HDean8GlEfJJ1U_RLQKdKCiuN^C2%;&kOe2aC#e>m=r}f; zLb&qwi4*}^FRr7f5OeGLJYN95C! z10lutG#rPZn7}KFq!cL{`lN}GjKeNH!U=?cX1VAjD^37b8*tI*6b{*UT^=>5r5PHp zfNE~m!%GoV?T0|`Mou$)rARnPx_dsv$}GlB#-w3#f>=*P zy;O&>%@;s?>RNc7APi8k^C_W@M->1!LuuQTdPMliQ$JnmbEDfcPx^;2PV*K)2t(Bw zw!;XD%>`($l4xBHEB!2$La zk3Jc>^$|9tnSYw8EERJO#GXVY=4ggH959k(tOA*N(^&-%F9HbgZ8L<+I#f~~Q5PtV0o$4|kAe?w}(+ z@p0LfFZ_;}+o;Ez1Ln{Wu7d|)D@UBOMz;v_)L} zNOh8SZtW=J$MHRZQfynCsN8(e!9O^G1MG#KK!BzP zdRjIh!OD1`^^sr+I+WljLir$p8!TV{?RB0aaD;(DLFUmzUksYj5P~o$;CS@O0lC)& znZ_ve!_Hve=uD6IL=5B{gU=NM^wh)Q2?A#9U~3q`Pt@RGGy)Tv;1+IS58V$G;=u&L zLQYVbojg-*`PiKRg%M0u62-w(kros1gE2_f`ZPjX1QQo^*cmy&U@@6{=|UDISDx{P z7B#{cf`ytX5ftJM72V+(>KiW|(}^WRW37-nl?XDKAs2FDCyvA(+|nf74)&ZCh~ZW& z2vS)I0$*v8B&~yyB^NEJgA%m^C8dWVDUvFRP7h6*!=|h`z0Wkv00`KWY;eW!E{BA2!vM2L)podV-ZTK{D3D z9DbXcwUbV_sV1ZPBIwUkc`65@ul<=3ydcVk+ihGG=2s=3_!;WJ=~_Qf6gZ=4E1L zW@_eUa%N|G=4XOtXo}`&l4fa|=4qm4YO3aHvSw?#=4--cY|7?r(q?Vi=569;ZtCW4 z@@8-P=5GRLa0=&e5@&H5=W!xuaw_L?GG}u-=W{}5bV}!RQfGBq=XGLdc53H#a%Xqe zrWOv^2zuvulBaRr1V8L$d8+4n;->Ub1$)A0d)wk}_$NI_Z-_X_QLolu~JxTIrQyX_ji~mU3yAdg+&fX_$7IbBSr0n(0Of zvBxA%}<9HOG7B!?EbO|WX z3JIW8x%BG)ndvH~nn-==0u60~txTk&4#A}{kW-4vnl*td#OfU+7Pz98Z4D!>5?KT3 zRJLO3H^`vpB|!?H>!pTMVBJe2;21>aTRNz~63jtFfq`rEp%X9-L(!cWWCEf|D*zh7 zVXQz>?nt2eYCk|wni0WYJVV$uV(PdjK(yD-^cg21g78&OwZ7wfHAKSR>wC_gjh5Kf z)oLfP?6Zwh60K{Cor5Au&@nuaIOdNxj>{C~DmV}kKM+RQh{9410Rvc}p$)+SbU>vE z43&Tf37ka&ctuP+LIP;V3T(_8g`gdNjF2(o5&Q%P5YRGs4fqj(0dQ#l{g^5E>BgEN zz>?Pg-0kek7QvUf!-%r#X`C$zA_3$*s^P*O*+?4`G!*#+!nBOWpD@P=Fo)r`V80AO zuzf_tt=NdU&gc}OZ-mkjz#))rN+GaBCfr)jqyY%DMe%V*3zmUlBtco20C{8tfVO}E zPz}x8Y_0-mrKy0TaDoa%Lj$skQv5>!w1&g#N1BL0Ry;)lbV?R*1n{-MmYBj;kbtN> zXlW?QS}?!>R0pVRiS6ty-&RYnwu3m4%*4DA1cZijc*j|k##3aA<5?L0LR_rHfpa7b zB?8D(kb-1nVenc?3m7hdA_cJcMmi`601H9_Y@6ZU?X`MVzkt)!72OcT%>8M{z|pGz zc+9OF3PN4*fp*-7Pca@8JZQ#Tt@PS~)%k*g=*I!v=f{@l5!5gdtnf=A1qWcjh#trT zBcS#!$GjvTX0(eDxJamp0`R&ApTaLH1FF#0JdyIpA2uOwWU1>~g2C3p)Gb2I= zZ!u$i1Di;O8>q|~#0iyP27P2fmt;l4bby;c26*tnSzvG+;F%SiMahC+f&M3a-RCb4 zf#X7fe?Tzbi~umyMLWM>g-&f0E@L$)^WYLeCo=*1;e#SRg+Sw4xFRdv#z7|5*8v=W z)va;<1@0NVvIsoI3ZDg)B#eG=0%Wj6d$EzVIht`Y$Vm`rKt#sDBqro04Wv@U-2 zh##y)hN#}k8o^p+3!bQwI2%if+5RE+Ta0|pfFH@Cq54<~@%Wyo4| zh(HTSOt7*r6aaTv#4G19y4Y|FL__BarM5VBRTqH)SWAWcg&8M7G-O?x$nqHkaZj&E z!yyb5h|4%ErEg%sPWMq9Kn>UcOTv%KqYt4oWNo`?bIZ#0(2CNC~7s)6oG!%q$s*xEJ{=wk~bG zHc%Zifme7$8Dz*5M8k0S0xzWAepEncI02+kUh&G4WGD-Fn2A@6Mrbgi@>~mZoX=R8 z0CY=Yon=T`LpaAq&O}r~S}Ce(eNlVm!EseIICd&~ZDaDN0VMlMY{ z^mytaZL2jb`UzE6jk>}*_Sb}autlxz?z{nXhyt@F*QMKdsmrCOvuYngSv|sP3+ebC z2@@!oQ2($)t*$_f1=jr3(9q6k&fZH4#n50uggt!$nKsD(xpvSj2vM@i1$quq*ws3Z z?zuMAprPA3tbau?a!_C1pBogBxzhqKEtjThx}_RfRD#z!#H>F05sYNIH~l&p%tNr*0E-iw*u2xiDW0O^(og@Zn68s+ZAU~yv0|%GmfmWM{2ik)V@j= zi$^@Ei<_t5_JSl-%9ng*b-ZVRw?*<|zn9jDP-?To*gI%ZF4^KsEd@jYij7Hhkw?Jggh(%9lFw zOF`1>Y~}n7iTj-&S)5%$sACiyC&En>nq&{|KQ#FNezf4;`~C8HePugM$jsEZ89v`< zeN`ULrZ$)x<^nd@WUKI1?5%w3RDBQ`TjcD^STzVaQuOe?}iG9S1vkH zZTstk%=;#WdgTNuG(?)R>tD8t@EZb3sTub#Ldy?n_D4Qd7ef$?5^Z1LhqV z7{f!qU*=H3rx#kCeSjV6{bBz(Mk)}fSgn?dcxm?d#qFrI4&7Ml%&2 zBSB7t0joQoT1#<`Wc(-=yh){RQdKz-1C@)n`0bMd>NwyC^Ex4}kKjbX>of(|t7AXa zP}wNHBchulBqE&C(2NCJ$jy=YqUf-N@Q^rAjug2`Fb%1`YB7oryQ8s28*juhN5V$5 z#gqdfq=Nw-&A=c)N4lb`zXAjQ5zGPmOc`(vBju6j6c1T0if zifXiM0lzsU4CX@i46Gx?fZ(jdDK`7UFbXxB$Sj^OPpSe6=ZJ&AF;ilkVk0(nWVBI7 zAB9v$<_x7{&mf~1Qk_yF*h|etiOBPl2woy0Q%BIm6x9Y*y|P=#P$mBZb0L!@|62umjy?hTaws zMi7(;a;-yKb|Z${UL}5zqrZ4R}IH9yhs>wz=aKQ&BT)SeX zy2}ftJptnj#UJMasKzIU-0{fcV7qNJGXAb|n zqBTU(8zL|wu{`(Nae=pR-+u=_cz-|{_AY~35rQFul6OOS=bML~dFhYW$7$+gHv=l@ z6U&9(C15uZ$JsOgZ~Yb4dsj&Nq|%;Vc}SOszxZl}r@wyt@2|V2Ww^LReK-8C7W!IO zJ5hWNb)h(*L{w0S#a*X?*}+ehd&N>(1RbePW+;`yrf;vZ>)eA z2({xr6+(oBtQ!RYTR1}+*3gFA@d80AM>!c11773cq2ruzIo<6LhMi;75evp3bS033 zLcC!Vr8q?@PKI3MO;YA4>0VAV0tF9Qg#FyG*g=zqYxd+*zGbc zaEb}G@s5qy44C0N!bYT`#H5iY3b;H1!_ab;Cd?>AX?zAXk6DLmge5qZ*@)P%3C-;s z&xEc-XFAonPHn76lSfz*LgE<;d&OrP^Xvm;PU)2@kjzbOGXrt{WDd?$!7|2N+9$e| z20ebF0;x%W%08jV5*?wUj*=NWHM&ub{?Rh6Q9-T{>WGn+?g&!xXF?k4%z`#cRKLWY z6i`*tBWUGGy-AK7-YErg9%d&u4aG$}I#i+-)u^RV(-4F@2M(aB2`hcXB_Bbp>Y*Y% z5?xsT3)aINhKXRQJ?unDrIH&5APSpEpeh6Gg-p7nARCsFg9DHh9SboNS9750QT4i4 zz7n-#RB?z1K!DXppb4l{5=C$rV6snaW&$C>5M$4?t2FHAXJ&w_H2*`{rJ4a44oGPy zIOnFke#IeM|t1FO>zpaTf;ek1z>@A4vOm2uQina z00s7%u90!%10$E16bhfM8NC~ZBGPMyHeQ2iBUZy9k`a&!BP0>nl*DoCJ7XHx_>a$< zp7C&ePOAZ;$8t!Xh7S{8Ah!j@BEF(0-iu%vrw(m4hH{jpOk*}g!iZoc2Zbp|kRo## z#gS`ID`2?Ox&eiJs|d4&r@Ur1x0${xaY!Os+?Wyet$hH^-dRPQx;I{|4gbJ$DVqGQ zLA%+|hek9F3!P$3=sABIlwF!C;*q@GTIk&~NVa}k&b*^;$A=8R*fUv1E#d8s(S}BBSEQXrTSR_PbT&m2()`oYyj%@8EZ zl2rJcY0|dH_aqT z)ekR~jlcb)72@~w6{Qa$ABr5B)cmKg_4lpwz!4PF@uz72Gu%(yb&W&>tzHE#-_L#i zpUdVLYq|GY2;!LtMGBO5paxech!5Mg?hwGkK!Fy3s__ei2fPaHFaeSy0@K(A6No^I zu)zKk!Bz@E-55OGs3079ny7IM0~?Hi;0IOE1p1>N3Jiq2dy4G;X^Eww1fb|I%RwB9 zXuT06!U3!T#zLP&>O7Mg5zAW#tf9S0GBEkMf)iPTxM8m<{F^q=m=`-IgK$AcK!P^f znwLNy)sc!Gbc0;FuqvyD1TiN=QMy-R2RwL|EEtQXNhk$N3cC`T?D4Yj$%YV_hFf4j zB_oIDIVIX#zRWQv7jwZe(2|_!h(dfCh=CZ!3oqBK&=`UkY#S3O#7P2y6DYwV zR7Hd81MiXp5Wu%4U?8yJi&cvPj`=$x_yZ$Ifz?2RJ5U;6Ac0(bxG}uNMPMMb0}<0f zq-0bA#|Q&ySO-c&0?AmQ6X*y@=!h|ZD?K=o6R9I3aEqV+nYv6^l`sPtTEM@#dnSM* zf(lR$49N-nC`4QEh8%>cDByrtlRaC+$5}f9O)Rzbkpm;?5MyZr;=q|T=&uIU1IIwc zG?EDt$P-#z#fy|dV>E;L=!>3-fL#y_r+^SD=!#4UkG}Yl>VS+D!7j+K3%VGWACsH( zr~uMvf&;0B4(Nc^NCB0RlWG8g32?R)xVr2+yVj@<5nvYc=!gjDMoCiy$1o2*5K3(6 z1iDCzYY`0&n7Pn60^=BgLJ*3q44;&WMIPh31?z($=?~)Y46HJNKk&sT`-B9ci|N>f zuTYZ@!H=(q0G!00-m#F8U`x+xf&N$&a{EQpAT?e8ITVb9%$ggFTX8B3fPfBotnnzy zN|ORtk%IRqk@;AG+*pCJsHoQ1yL|W(^SI0^&Cp#={33QBknZBa>x zO9iLEO?C`OBSR}oLIR|~Io1G>@%XkDz<|uafFU`c{-T-8NR6(5jDlkT64=Ue>jMYa z4|qWes9+f4=p%z039Wd_7HE+#ak{cmvkut|+gi)DtEtUeBg!&^_uNQ5iOm0`gQ^=H zJ#r$`kcp^^0#up9Qh)%VdIvs`j9pmIph(ab2$i&wgA(Bbdm1s#f~ysHuDx)8zx$Kc zfRN5|ml!$8*pvbdQ2~W4ygJB?Z7?pie21O?3KhCQPWCKDhGIpm0~7133goa%DTo#R zEEE4E0SD;KBR~~mG(6zSrankcPk50QNU7&!I>>0K-}nf+=nAz1&@tr%0hJO*=#Xvb z5V~-V^CE)Os~g(*kX>kl&0rHCSy1J46Tzzj2*8rG7=&%Wkn}JKaT|j1lEu)%kP46( zIE4&0af=ktiqs?r$ha)YIDxJRiH0&WG&QNc_z3g}sXaWUl-GJ5Q*A|GRO&Gb4vKCf^MyYSSi^MsHvf;=&n4nU|yuvsZ6 z5K86NBlwL*$k#p``vY2SB5V7pp47siQ`GgEElZslYyy$^}X}T!aYR z)WO`@c!M<4J%sDEx7maG)Fl(ZoR7$YmrV<#I1v#LffE_2G+J3UG=$H)z#sdwsgMa# zR5O#52H?O~pEejm@OZa^-~-9Yg73A*UF5JqK*l-Q z9Up5uVDw$6cwV|xT&M}L7zCe`&>kpw947!qjqI?g;6+ReKLG0;&k2X>Edua0k?QMP zSrAAUJFp0od?JE^#ohGL{=P{HsZj zyw1}yIvgV{ikm*H1tDO_vuiOxONqsug7ci*#?;)it715g<3~6vHKu}UAfX|Ay!9!D z6V~EMo;(0Hz&SdHOHSl5ELbE4<(oO);iO<${N3bL4E{MQ`4uoVE}!e8WO(T0#w7y{ zqhg1!NU+i66R^nTC}mX>d6VaU{-VJPgbK_&@GRT3);6a!#&nW-~9~WEu+RR5s^#hPxH8TOj_Oc2<{LuAd0A z7y)X#a`0!@VaR~~;(@kgfi7r*{%3er=+;8#HAA_ER%nP`=!vd8gGN4z#^{XJ=-_Fx zS)Q|0G(V93Es2(-Q-EE#MdX8cy>A#FxPo;&S1KS(_L}i?!gArjCCt4A5gKE5{?EX6u4uFD;4F%)?lCg-WnfM$Lcz~KE1}&U8 z#F8v`;fl&)o2*;UJXHnTh>`IawcC|IJ1~QVeYWAUPm%CS_M8%Q4X9nJ?BX`=CV*3O zeFy}oBqA7XBv^nb*Z?F5f#}9#LzaStn#v0OOr#BkkRk#MP$Id0x($3PDJ|y08-aMB zmJXp$?lw+eW?SE$0}{~e2rT0n$^50ruj=;{k(ZVHGYlwKK7sQ{s%YlSF_ zZGumUqtH$O8Cgh8Azl&^(C##djup7?nTdekK+>Mcy8Jfra@I4ieTC^}92z7AGNFRK zZi43je7&?_W(uE&27g7@6a|}P1&Wh2V#9h$PI&Lcb_A_3Q}eznUb?Fyr}J{I z9VzYu0EYx9H*bwuja1cG-Esv_`sEFC-0x0m1b+n1S-}>+?RF$FT=wZYr}QyR!LN?+ zx!J+KKCnNA+hgD|I8vHL!)FzfX(?pnOqk}EHdp{e;Yx>ftd24Im~V!KL={3yhky!+ zj`d#mbqVsN)0ocik+Xq3F|lTs^X=VBFJPPahcHx#T<%CHeH844+F!@^=nc9=kUnMq zUZf+MoqnF|b+KnED)($hcOndDo681jhc^VqZf{TbdH;1PnCE8-k)>FWrT~td?LXOY zcb%g5fe+Zt_c(Wzxb?b@KM4MgpM~CsZNCr$jja@}<^giP6HB za@1xi)yOtgXGQ5GNOac~sdPxhq9;`_q~=QGa6mMx#7ZUb6bsm*)_e8YVmg-GC)7bA z)#315WIGfwG|jBN&E4(&4IVB&PCj+4WT`53p0&8;9!%Tf(9*`xvZC@CLWMH)*uou^ zdx9`faIy?cLMZXLgt|5%3cxAXTByr~&&eMs^n{Qia<2#kfl$~v5wVD5i-=MVYT-wv zW5AI0h8eLaq#6;G8lOavSq7Doi9_hAh(o9dh5#U=B#ol8MMWq_r#MK0P6$mW0e{`FH?Q8ke95Wt3du?TwiXz~N({4Tg~^%` zR4#_{fLhipWrcXyvQf&Sk3$+3$*e?QXDOVm=6n`$MZ>4-a)Jp(1axU4k+&=ev2ch# zFl}bH*s4lTCeTt$K~VGf3DGSE?I;8{d&MX+U)5b>~}f*@FVl3WxLU=bNAE(xK| z7M?*9m`9@xB;GtGG^m6F0tN#hSOHyFMTrPu!A@;MSn!04LdbZ+0~SP-06;QI5!r*G zIl;manN>Cf1Y*%s5eIY$L8KGrod9AK6~5vbQ$?t7#4IWQM3obY15AKoBc$ko5fK7X z0hm%nQo#X&P7sKNibTMb*$HqBIFEKh$Z21ne*Ot)pn~=RUKmXhVb~B;LdQpxP?WI6 zgfMd9UJHdnA<&X>3S;J)L}YU(IH8&$)TC{w5*Z1QLR!V8-1Tw7V3Y}w<|RPFCd8;j zprX?~xJDtK(aSsMEsS=e4jt&ZLxZ;jW zZaAXh8V8&>4S_6+cv^vCOkVV|V-b)p0EMi5oYQU>(vorL6M8Zvg

DD#UI=Y@o!1 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

c4F)snPZ-{WPRC5x=R} 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ஊz7j5hArW<#M0Kp-62(FF0ySoGl?$)?N;{*#9 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

G1$8Z0R&nv`^{OF- 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�d=L;gonLEe~oG1+B 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

$LOWcu~1 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%0Dui70w4llOlk2M_U*DDU!c=!H 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%0AnvY$;%);y&qLERjW_P@?gR@? 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 z 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 diff --git a/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/video_toast.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/video_toast.test.tsx index 89979efd63fef..5322a34405621 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/video_toast.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/video_toast.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { VideoToast } from './video_toast'; +import { VIDEO_PAGE, VideoToast } from './video_toast'; describe('VideoToast', () => { const onCloseMock = jest.fn(); @@ -32,19 +32,13 @@ describe('VideoToast', () => { it('should open the video in a new tab when the gif is clicked', async () => { const videoGif = screen.getByTestId('video-gif'); await userEvent.click(videoGif); - expect(window.open).toHaveBeenCalledWith( - 'https://videos.elastic.co/watch/BrDaDBAAvdygvemFKNAkBW', - '_blank' - ); + expect(window.open).toHaveBeenCalledWith(VIDEO_PAGE, '_blank'); }); it('should open the video in a new tab when the "Watch overview video" button is clicked', async () => { const watchVideoButton = screen.getByRole('button', { name: 'Watch overview video' }); await userEvent.click(watchVideoButton); - expect(window.open).toHaveBeenCalledWith( - 'https://videos.elastic.co/watch/BrDaDBAAvdygvemFKNAkBW', - '_blank' - ); + expect(window.open).toHaveBeenCalledWith(VIDEO_PAGE, '_blank'); }); it('should call the onClose callback when the close button is clicked', async () => { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/video_toast.tsx b/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/video_toast.tsx index b1b2bfe02a1eb..8431cf687ff0c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/video_toast.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/tour/knowledge_base/video_toast.tsx @@ -18,10 +18,8 @@ import React, { useCallback } from 'react'; import * as i18n from './translations'; import theGif from './overview.gif'; -const VIDEO_CONTENT_WIDTH = 250; -// TODO before removing assistantKnowledgeBaseByDefault feature flag -// update the VIDEO_PAGE to the correct URL -const VIDEO_PAGE = `https://videos.elastic.co/watch/BrDaDBAAvdygvemFKNAkBW`; +const VIDEO_CONTENT_WIDTH = 330; +export const VIDEO_PAGE = `https://ela.st/seckb`; const VideoComponent: React.FC<{ onClose: () => void }> = ({ onClose }) => { const openVideoInNewTab = useCallback(() => { diff --git a/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.test.ts b/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.test.ts new file mode 100644 index 0000000000000..4557d0ba0bdd5 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.test.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ESQLSearchResponse } from '@kbn/es-types'; +import { esqlResultToPlainObjects } from './esql_result_to_plain_objects'; + +describe('esqlResultToPlainObjects', () => { + it('should return an empty array for an empty result', () => { + const result: ESQLSearchResponse = { + columns: [], + values: [], + }; + const output = esqlResultToPlainObjects(result); + expect(output).toEqual([]); + }); + + it('should return plain objects', () => { + const result: ESQLSearchResponse = { + columns: [{ name: 'name', type: 'keyword' }], + values: [['Foo Bar']], + }; + const output = esqlResultToPlainObjects(result); + expect(output).toEqual([{ name: 'Foo Bar' }]); + }); + + it('should return columns without "text" or "keyword" in their names', () => { + const result: ESQLSearchResponse = { + columns: [ + { name: 'name.text', type: 'text' }, + { name: 'age', type: 'keyword' }, + ], + values: [ + ['Foo Bar', 30], + ['Foo Qux', 25], + ], + }; + const output = esqlResultToPlainObjects(result); + expect(output).toEqual([ + { name: 'Foo Bar', age: 30 }, + { name: 'Foo Qux', age: 25 }, + ]); + }); + + it('should handle mixed columns correctly', () => { + const result: ESQLSearchResponse = { + columns: [ + { name: 'name', type: 'text' }, + { name: 'name.text', type: 'text' }, + { name: 'age', type: 'keyword' }, + ], + values: [ + ['Foo Bar', 'Foo Bar', 30], + ['Foo Qux', 'Foo Qux', 25], + ], + }; + const output = esqlResultToPlainObjects(result); + expect(output).toEqual([ + { name: 'Foo Bar', age: 30 }, + { name: 'Foo Qux', age: 25 }, + ]); + }); +}); diff --git a/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts b/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts index ad48bcb311b25..96049f75ef156 100644 --- a/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts +++ b/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts @@ -13,7 +13,17 @@ export function esqlResultToPlainObjects>( return result.values.map((row) => { return row.reduce>((acc, value, index) => { const column = result.columns[index]; - acc[column.name] = value; + + if (!column) { + return acc; + } + + // Removes the type suffix from the column name + const name = column.name.replace(/\.(text|keyword)$/, ''); + if (!acc[name]) { + acc[name] = value; + } + return acc; }, {}); }) as T[]; diff --git a/x-pack/packages/security-solution/upselling/messages/index.tsx b/x-pack/packages/security-solution/upselling/messages/index.tsx index 4bda9477f13c0..1283671911402 100644 --- a/x-pack/packages/security-solution/upselling/messages/index.tsx +++ b/x-pack/packages/security-solution/upselling/messages/index.tsx @@ -48,8 +48,8 @@ export const ALERT_SUPPRESSION_RULE_DETAILS = i18n.translate( ); export const UPGRADE_NOTES_MANAGEMENT_USER_FILTER = (requiredLicense: string) => - i18n.translate('securitySolutionPackages.noteManagement.userFilter.upsell', { - defaultMessage: 'Upgrade to {requiredLicense} to make use of user filters', + i18n.translate('securitySolutionPackages.noteManagement.createdByFilter.upsell', { + defaultMessage: 'Upgrade to {requiredLicense} to make use of createdBy filter', values: { requiredLicense, }, diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts b/x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts index 3d673fa25dc5f..6a10b3a4ee2ad 100644 --- a/x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts +++ b/x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts @@ -20,8 +20,16 @@ export const elasticsearchRoleSchema = schema.object({ * An optional list of cluster privileges. These privileges define the cluster level actions that * users with this role are able to execute */ - cluster: schema.maybe(schema.arrayOf(schema.string())), - + cluster: schema.maybe( + schema.arrayOf( + schema.string({ + meta: { + description: + 'Cluster privileges that define the cluster level actions that users can perform.', + }, + }) + ) + ), /** * An optional list of remote cluster privileges. These privileges define the remote cluster level actions that * users with this role are able to execute @@ -29,8 +37,24 @@ export const elasticsearchRoleSchema = schema.object({ remote_cluster: schema.maybe( schema.arrayOf( schema.object({ - privileges: schema.arrayOf(schema.string(), { minSize: 1 }), - clusters: schema.arrayOf(schema.string(), { minSize: 1 }), + privileges: schema.arrayOf( + schema.string({ + meta: { + description: + 'The cluster level privileges for the remote cluster. The allowed values are a subset of the cluster privileges.', + }, + }), + { minSize: 1 } + ), + clusters: schema.arrayOf( + schema.string({ + meta: { + description: + 'A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.', + }, + }), + { minSize: 1 } + ), }) ) ), @@ -45,7 +69,15 @@ export const elasticsearchRoleSchema = schema.object({ * Required list of indices (or index name patterns) to which the permissions in this * entry apply. */ - names: schema.arrayOf(schema.string(), { minSize: 1 }), + names: schema.arrayOf( + schema.string({ + meta: { + description: + 'The data streams, indices, and aliases to which the permissions in this entry apply. It supports wildcards (*).', + }, + }), + { minSize: 1 } + ), /** * An optional set of the document fields that the owners of the role have read access to. @@ -53,7 +85,13 @@ export const elasticsearchRoleSchema = schema.object({ field_security: schema.maybe( schema.recordOf( schema.oneOf([schema.literal('grant'), schema.literal('except')]), - schema.arrayOf(schema.string()) + schema.arrayOf( + schema.string({ + meta: { + description: 'The document fields that the role members have read access to.', + }, + }) + ) ) ), @@ -61,20 +99,42 @@ export const elasticsearchRoleSchema = schema.object({ * Required list of the index level privileges that the owners of the role have on the * specified indices. */ - privileges: schema.arrayOf(schema.string(), { minSize: 1 }), + privileges: schema.arrayOf( + schema.string({ + meta: { + description: + 'The index level privileges that the role members have for the data streams and indices.', + }, + }), + { minSize: 1 } + ), /** * An optional search query that defines the documents the owners of the role have read access * to. A document within the specified indices must match this query in order for it to be * accessible by the owners of the role. */ - query: schema.maybe(schema.string()), + query: schema.maybe( + schema.string({ + meta: { + description: + 'A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members.', + }, + }) + ), /** * An optional flag used to indicate if index pattern wildcards or regexps should cover * restricted indices. */ - allow_restricted_indices: schema.maybe(schema.boolean()), + allow_restricted_indices: schema.maybe( + schema.boolean({ + meta: { + description: + 'Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field covers the restricted indices too.', + }, + }) + ), }) ) ), @@ -88,13 +148,29 @@ export const elasticsearchRoleSchema = schema.object({ /** * Required list of remote clusters to which the permissions in this entry apply. */ - clusters: schema.arrayOf(schema.string(), { minSize: 1 }), + clusters: schema.arrayOf( + schema.string({ + meta: { + description: + 'A list of remote cluster aliases. It supports literal strings as well as wildcards and regular expressions.', + }, + }), + { minSize: 1 } + ), /** * Required list of remote indices (or index name patterns) to which the permissions in this * entry apply. */ - names: schema.arrayOf(schema.string(), { minSize: 1 }), + names: schema.arrayOf( + schema.string({ + meta: { + description: + 'A list of remote aliases, data streams, or indices to which the permissions apply. It supports wildcards (*).', + }, + }), + { minSize: 1 } + ), /** * An optional set of the document fields that the owners of the role have read access to. @@ -102,7 +178,13 @@ export const elasticsearchRoleSchema = schema.object({ field_security: schema.maybe( schema.recordOf( schema.oneOf([schema.literal('grant'), schema.literal('except')]), - schema.arrayOf(schema.string()) + schema.arrayOf( + schema.string({ + meta: { + description: 'The document fields that the role members have read access to.', + }, + }) + ) ) ), @@ -110,20 +192,42 @@ export const elasticsearchRoleSchema = schema.object({ * Required list of the index level privileges that the owners of the role have on the * specified indices. */ - privileges: schema.arrayOf(schema.string(), { minSize: 1 }), + privileges: schema.arrayOf( + schema.string({ + meta: { + description: + 'The index level privileges that role members have for the specified indices.', + }, + }), + { minSize: 1 } + ), /** * An optional search query that defines the documents the owners of the role have read access * to. A document within the specified indices must match this query in order for it to be * accessible by the owners of the role. */ - query: schema.maybe(schema.string()), + query: schema.maybe( + schema.string({ + meta: { + description: + 'A search query that defines the documents the role members have read access to. A document within the specified data streams and indices must match this query in order for it to be accessible by the role members. ', + }, + }) + ), /** * An optional flag used to indicate if index pattern wildcards or regexps should cover * restricted indices. */ - allow_restricted_indices: schema.maybe(schema.boolean()), + allow_restricted_indices: schema.maybe( + schema.boolean({ + meta: { + description: + 'Restricted indices are a special category of indices that are used internally to store configuration data and should not be directly accessed. Only internal system roles should normally grant privileges over the restricted indices. Toggling this flag is very strongly discouraged because it could effectively grant unrestricted operations on critical data, making the entire system unstable or leaking sensitive information. If for administrative purposes you need to create a role with privileges covering restricted indices, however, you can set this property to true. In that case, the names field will cover the restricted indices too.', + }, + }) + ), }) ) ), @@ -131,7 +235,13 @@ export const elasticsearchRoleSchema = schema.object({ /** * An optional list of users that the owners of this role can impersonate. */ - run_as: schema.maybe(schema.arrayOf(schema.string())), + run_as: schema.maybe( + schema.arrayOf( + schema.string({ + meta: { description: 'A user name that the role member can impersonate.' }, + }) + ) + ), }); const allSpacesSchema = schema.arrayOf(schema.literal(GLOBAL_RESOURCE), { @@ -147,6 +257,7 @@ const spacesSchema = schema.oneOf( allSpacesSchema, schema.arrayOf( schema.string({ + meta: { description: 'A space that the privilege applies to.' }, validate(value) { if (!/^[a-z0-9_-]+$/.test(value)) { return `must be lower case, a-z, 0-9, '_', and '-' are allowed`; @@ -188,6 +299,7 @@ export const getKibanaRoleSchema = ( allSpacesSchema, schema.arrayOf( schema.string({ + meta: { description: 'A base privilege that grants applies to all spaces.' }, validate(value) { const globalPrivileges = getBasePrivilegeNames().global; if (!globalPrivileges.some((privilege) => privilege === value)) { @@ -198,6 +310,7 @@ export const getKibanaRoleSchema = ( ), schema.arrayOf( schema.string({ + meta: { description: 'A base privilege that applies to specific spaces.' }, validate(value) { const spacePrivileges = getBasePrivilegeNames().space; if (!spacePrivileges.some((privilege) => privilege === value)) { @@ -218,6 +331,7 @@ export const getKibanaRoleSchema = ( feature: schema.maybe( schema.recordOf( schema.string({ + meta: { description: 'The name of a feature.' }, validate(value) { if (!FEATURE_NAME_VALUE_REGEX.test(value)) { return `only a-z, A-Z, 0-9, '_', and '-' are allowed`; @@ -226,6 +340,7 @@ export const getKibanaRoleSchema = ( }), schema.arrayOf( schema.string({ + meta: { description: 'The privileges that the role member has for the feature.' }, validate(value) { if (!FEATURE_NAME_VALUE_REGEX.test(value)) { return `only a-z, A-Z, 0-9, '_', and '-' are allowed`; diff --git a/x-pack/plugins/actions/kibana.jsonc b/x-pack/plugins/actions/kibana.jsonc index 3cb9e8bfd79c5..882c832245951 100644 --- a/x-pack/plugins/actions/kibana.jsonc +++ b/x-pack/plugins/actions/kibana.jsonc @@ -26,7 +26,8 @@ "spaces", "security", "monitoringCollection", - "serverless" + "serverless", + "cloud" ], "extraPublicDirs": [ "common" diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts index 7f15dd6287d6b..3421e381d07b6 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts @@ -39,13 +39,7 @@ import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/us import { actionExecutorMock } from '../lib/action_executor.mock'; import { v4 as uuidv4 } from 'uuid'; import { ActionsAuthorization } from '../authorization/actions_authorization'; -import { - getAuthorizationModeBySource, - AuthorizationMode, - bulkGetAuthorizationModeBySource, -} from '../authorization/get_authorization_mode_by_source'; import { actionsAuthorizationMock } from '../authorization/actions_authorization.mock'; -import { trackLegacyRBACExemption } from '../lib/track_legacy_rbac_exemption'; import { ConnectorTokenClient } from '../lib/connector_token_client'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { SavedObject } from '@kbn/core/server'; @@ -57,6 +51,7 @@ import { OAuthParams } from '../routes/get_oauth_access_token'; import { eventLogClientMock } from '@kbn/event-log-plugin/server/event_log_client.mock'; import { GetGlobalExecutionKPIParams, GetGlobalExecutionLogParams } from '../../common'; import { estypes } from '@elastic/elasticsearch'; +import { DEFAULT_USAGE_API_URL } from '../config'; jest.mock('@kbn/core-saved-objects-utils-server', () => { const actual = jest.requireActual('@kbn/core-saved-objects-utils-server'); @@ -68,25 +63,6 @@ jest.mock('@kbn/core-saved-objects-utils-server', () => { }; }); -jest.mock('../lib/track_legacy_rbac_exemption', () => ({ - trackLegacyRBACExemption: jest.fn(), -})); - -jest.mock('../authorization/get_authorization_mode_by_source', () => { - return { - getAuthorizationModeBySource: jest.fn(() => { - return 1; - }), - bulkGetAuthorizationModeBySource: jest.fn(() => { - return 1; - }), - AuthorizationMode: { - Legacy: 0, - RBAC: 1, - }, - }; -}); - jest.mock('../lib/get_oauth_jwt_access_token', () => ({ getOAuthJwtAccessToken: jest.fn(), })); @@ -613,6 +589,9 @@ describe('create()', () => { microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL, microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE, microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL, + usage: { + url: DEFAULT_USAGE_API_URL, + }, }); const localActionTypeRegistryParams = { @@ -2745,9 +2724,6 @@ describe('update()', () => { describe('execute()', () => { describe('authorization', () => { test('ensures user is authorised to excecute actions', async () => { - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.RBAC; - }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce(actionTypeIdFromSavedObjectMock()); await actionsClient.execute({ actionId: 'action-id', @@ -2764,9 +2740,6 @@ describe('execute()', () => { }); test('throws when user is not authorised to create the type of action', async () => { - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.RBAC; - }); authorization.ensureAuthorized.mockRejectedValue( new Error(`Unauthorized to execute all actions`) ); @@ -2790,28 +2763,7 @@ describe('execute()', () => { }); }); - test('tracks legacy RBAC', async () => { - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.Legacy; - }); - - await actionsClient.execute({ - actionId: 'action-id', - params: { - name: 'my name', - }, - source: asHttpRequestExecutionSource(request), - }); - - expect(trackLegacyRBACExemption as jest.Mock).toBeCalledWith('execute', mockUsageCounter); - expect(authorization.ensureAuthorized).not.toHaveBeenCalled(); - }); - test('ensures that system actions privileges are being authorized correctly', async () => { - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.RBAC; - }); - actionsClient = new ActionsClient({ inMemoryConnectors: [ { @@ -2872,10 +2824,6 @@ describe('execute()', () => { }); test('does not authorize kibana privileges for non system actions', async () => { - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.RBAC; - }); - actionsClient = new ActionsClient({ inMemoryConnectors: [ { @@ -2939,10 +2887,6 @@ describe('execute()', () => { }); test('pass the params to the actionTypeRegistry when authorizing system actions', async () => { - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.RBAC; - }); - const getKibanaPrivileges = jest.fn().mockReturnValue(['test/create']); actionsClient = new ActionsClient({ @@ -3106,9 +3050,6 @@ describe('execute()', () => { describe('bulkEnqueueExecution()', () => { describe('authorization', () => { test('ensures user is authorised to execute actions', async () => { - (bulkGetAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return { [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }; - }); await actionsClient.bulkEnqueueExecution([ { id: uuidv4(), @@ -3136,9 +3077,6 @@ describe('bulkEnqueueExecution()', () => { }); test('throws when user is not authorised to create the type of action', async () => { - (bulkGetAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return { [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }; - }); authorization.ensureAuthorized.mockRejectedValue( new Error(`Unauthorized to execute all actions`) ); @@ -3170,45 +3108,9 @@ describe('bulkEnqueueExecution()', () => { operation: 'execute', }); }); - - test('tracks legacy RBAC', async () => { - (bulkGetAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return { [AuthorizationMode.RBAC]: 0, [AuthorizationMode.Legacy]: 2 }; - }); - - await actionsClient.bulkEnqueueExecution([ - { - id: uuidv4(), - params: {}, - spaceId: 'default', - executionId: '123abc', - apiKey: null, - source: asHttpRequestExecutionSource(request), - actionTypeId: 'my-action-type', - }, - { - id: uuidv4(), - params: {}, - spaceId: 'default', - executionId: '456def', - apiKey: null, - source: asHttpRequestExecutionSource(request), - actionTypeId: 'my-action-type', - }, - ]); - - expect(trackLegacyRBACExemption as jest.Mock).toBeCalledWith( - 'bulkEnqueueExecution', - mockUsageCounter, - 2 - ); - }); }); test('calls the bulkExecutionEnqueuer with the appropriate parameters', async () => { - (bulkGetAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return { [AuthorizationMode.RBAC]: 0, [AuthorizationMode.Legacy]: 0 }; - }); const opts = [ { id: uuidv4(), @@ -3504,17 +3406,11 @@ describe('getGlobalExecutionLogWithAuth()', () => { test('ensures user is authorised to access logs', async () => { eventLogClient.aggregateEventsWithAuthFilter.mockResolvedValue(results); - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.RBAC; - }); await actionsClient.getGlobalExecutionLogWithAuth(opts); expect(authorization.ensureAuthorized).toHaveBeenCalledWith({ operation: 'get' }); }); test('throws when user is not authorised to access logs', async () => { - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.RBAC; - }); authorization.ensureAuthorized.mockRejectedValue(new Error(`Unauthorized to access logs`)); await expect(actionsClient.getGlobalExecutionLogWithAuth(opts)).rejects.toMatchInlineSnapshot( @@ -3563,17 +3459,11 @@ describe('getGlobalExecutionKpiWithAuth()', () => { test('ensures user is authorised to access kpi', async () => { eventLogClient.aggregateEventsWithAuthFilter.mockResolvedValue(results); - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.RBAC; - }); await actionsClient.getGlobalExecutionKpiWithAuth(opts); expect(authorization.ensureAuthorized).toHaveBeenCalledWith({ operation: 'get' }); }); test('throws when user is not authorised to access kpi', async () => { - (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { - return AuthorizationMode.RBAC; - }); authorization.ensureAuthorized.mockRejectedValue(new Error(`Unauthorized to access kpi`)); await expect(actionsClient.getGlobalExecutionKpiWithAuth(opts)).rejects.toMatchInlineSnapshot( diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.ts b/x-pack/plugins/actions/server/actions_client/actions_client.ts index de029ed2acf54..5c563fbd6aa82 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.ts @@ -10,7 +10,7 @@ import url from 'url'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { i18n } from '@kbn/i18n'; -import { compact, uniq } from 'lodash'; +import { uniq } from 'lodash'; import { IScopedClusterClient, SavedObjectsClientContract, @@ -35,7 +35,7 @@ import { IExecutionLogResult, } from '../../common'; import { ActionTypeRegistry } from '../action_type_registry'; -import { ActionExecutorContract, ActionExecutionSource, parseDate } from '../lib'; +import { ActionExecutorContract, parseDate } from '../lib'; import { ActionResult, RawAction, @@ -52,13 +52,7 @@ import { ExecutionResponse, } from '../create_execute_function'; import { ActionsAuthorization } from '../authorization/actions_authorization'; -import { - getAuthorizationModeBySource, - bulkGetAuthorizationModeBySource, - AuthorizationMode, -} from '../authorization/get_authorization_mode_by_source'; import { connectorAuditEvent, ConnectorAuditAction } from '../lib/audit_events'; -import { trackLegacyRBACExemption } from '../lib/track_legacy_rbac_exemption'; import { ActionsConfigurationUtilities } from '../actions_config'; import { OAuthClientCredentialsParams, @@ -496,51 +490,26 @@ export class ActionsClient { public async bulkEnqueueExecution( options: EnqueueExecutionOptions[] ): Promise { - const sources: Array> = compact( - (options ?? []).map((option) => option.source) - ); - - const authModes = await bulkGetAuthorizationModeBySource( - this.context.logger, - this.context.unsecuredSavedObjectsClient, - sources + /** + * For scheduled executions the additional authorization check + * for system actions (kibana privileges) will be performed + * inside the ActionExecutor at execution time + */ + await this.context.authorization.ensureAuthorized({ operation: 'execute' }); + await Promise.all( + uniq(options.map((o) => o.actionTypeId)).map((actionTypeId) => + this.context.authorization.ensureAuthorized({ operation: 'execute', actionTypeId }) + ) ); - if (authModes[AuthorizationMode.RBAC] > 0) { - /** - * For scheduled executions the additional authorization check - * for system actions (kibana privileges) will be performed - * inside the ActionExecutor at execution time - */ - await this.context.authorization.ensureAuthorized({ operation: 'execute' }); - await Promise.all( - uniq(options.map((o) => o.actionTypeId)).map((actionTypeId) => - this.context.authorization.ensureAuthorized({ operation: 'execute', actionTypeId }) - ) - ); - } - if (authModes[AuthorizationMode.Legacy] > 0) { - trackLegacyRBACExemption( - 'bulkEnqueueExecution', - this.context.usageCounter, - authModes[AuthorizationMode.Legacy] - ); - } return this.context.bulkExecutionEnqueuer(this.context.unsecuredSavedObjectsClient, options); } public async ephemeralEnqueuedExecution(options: EnqueueExecutionOptions): Promise { - const { source } = options; - if ( - (await getAuthorizationModeBySource(this.context.unsecuredSavedObjectsClient, source)) === - AuthorizationMode.RBAC - ) { - await this.context.authorization.ensureAuthorized({ - operation: 'execute', - actionTypeId: options.actionTypeId, - }); - } else { - trackLegacyRBACExemption('ephemeralEnqueuedExecution', this.context.usageCounter); - } + await this.context.authorization.ensureAuthorized({ + operation: 'execute', + actionTypeId: options.actionTypeId, + }); + return this.context.ephemeralExecutionEnqueuer( this.context.unsecuredSavedObjectsClient, options diff --git a/x-pack/plugins/actions/server/actions_config.test.ts b/x-pack/plugins/actions/server/actions_config.test.ts index a6966e0e85c40..2b5c4efc283b6 100644 --- a/x-pack/plugins/actions/server/actions_config.test.ts +++ b/x-pack/plugins/actions/server/actions_config.test.ts @@ -6,7 +6,7 @@ */ import { ByteSizeValue } from '@kbn/config-schema'; -import { ActionsConfig } from './config'; +import { ActionsConfig, DEFAULT_USAGE_API_URL } from './config'; import { DEFAULT_MICROSOFT_EXCHANGE_URL, DEFAULT_MICROSOFT_GRAPH_API_SCOPE, @@ -42,6 +42,9 @@ const defaultActionsConfig: ActionsConfig = { microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL, microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE, microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL, + usage: { + url: DEFAULT_USAGE_API_URL, + }, }; describe('ensureUriAllowed', () => { diff --git a/x-pack/plugins/actions/server/application/connector/methods/execute/execute.ts b/x-pack/plugins/actions/server/application/connector/methods/execute/execute.ts index f9922e0b61a8d..fc96f3a38caf5 100644 --- a/x-pack/plugins/actions/server/application/connector/methods/execute/execute.ts +++ b/x-pack/plugins/actions/server/application/connector/methods/execute/execute.ts @@ -10,11 +10,6 @@ import { RawAction, ActionTypeExecutorResult } from '../../../../types'; import { getSystemActionKibanaPrivileges } from '../../../../lib/get_system_action_kibana_privileges'; import { isPreconfigured } from '../../../../lib/is_preconfigured'; import { isSystemAction } from '../../../../lib/is_system_action'; -import { - getAuthorizationModeBySource, - AuthorizationMode, -} from '../../../../authorization/get_authorization_mode_by_source'; -import { trackLegacyRBACExemption } from '../../../../lib/track_legacy_rbac_exemption'; import { ConnectorExecuteParams } from './types'; import { ACTION_SAVED_OBJECT_TYPE } from '../../../../constants/saved_objects'; import { ActionsClientContext } from '../../../../actions_client'; @@ -25,43 +20,34 @@ export async function execute( ): Promise> { const log = context.logger; const { actionId, params, source, relatedSavedObjects } = connectorExecuteParams; - - if ( - (await getAuthorizationModeBySource(context.unsecuredSavedObjectsClient, source)) === - AuthorizationMode.RBAC - ) { - const additionalPrivileges = getSystemActionKibanaPrivileges(context, actionId, params); - let actionTypeId: string | undefined; - - try { - if (isPreconfigured(context, actionId) || isSystemAction(context, actionId)) { - const connector = context.inMemoryConnectors.find( - (inMemoryConnector) => inMemoryConnector.id === actionId - ); - - actionTypeId = connector?.actionTypeId; - } else { - // TODO: Optimize so we don't do another get on top of getAuthorizationModeBySource and within the actionExecutor.execute - const { attributes } = await context.unsecuredSavedObjectsClient.get( - ACTION_SAVED_OBJECT_TYPE, - actionId - ); - - actionTypeId = attributes.actionTypeId; - } - } catch (err) { - log.debug(`Failed to retrieve actionTypeId for action [${actionId}]`, err); + const additionalPrivileges = getSystemActionKibanaPrivileges(context, actionId, params); + let actionTypeId: string | undefined; + + try { + if (isPreconfigured(context, actionId) || isSystemAction(context, actionId)) { + const connector = context.inMemoryConnectors.find( + (inMemoryConnector) => inMemoryConnector.id === actionId + ); + + actionTypeId = connector?.actionTypeId; + } else { + const { attributes } = await context.unsecuredSavedObjectsClient.get( + ACTION_SAVED_OBJECT_TYPE, + actionId + ); + + actionTypeId = attributes.actionTypeId; } - - await context.authorization.ensureAuthorized({ - operation: 'execute', - additionalPrivileges, - actionTypeId, - }); - } else { - trackLegacyRBACExemption('execute', context.usageCounter); + } catch (err) { + log.debug(`Failed to retrieve actionTypeId for action [${actionId}]`, err); } + await context.authorization.ensureAuthorized({ + operation: 'execute', + additionalPrivileges, + actionTypeId, + }); + return context.actionExecutor.execute({ actionId, params, diff --git a/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts b/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts index ee11cf6a35d82..0f86a8e582e34 100644 --- a/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts +++ b/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts @@ -36,25 +36,6 @@ jest.mock('@kbn/core-saved-objects-utils-server', () => { }; }); -jest.mock('../../../../lib/track_legacy_rbac_exemption', () => ({ - trackLegacyRBACExemption: jest.fn(), -})); - -jest.mock('../../../../authorization/get_authorization_mode_by_source', () => { - return { - getAuthorizationModeBySource: jest.fn(() => { - return 1; - }), - bulkGetAuthorizationModeBySource: jest.fn(() => { - return 1; - }), - AuthorizationMode: { - Legacy: 0, - RBAC: 1, - }, - }; -}); - jest.mock('../../../../lib/get_oauth_jwt_access_token', () => ({ getOAuthJwtAccessToken: jest.fn(), })); diff --git a/x-pack/plugins/actions/server/authorization/actions_authorization.test.ts b/x-pack/plugins/actions/server/authorization/actions_authorization.test.ts index 41eab4fbc2e43..7755071e69c24 100644 --- a/x-pack/plugins/actions/server/authorization/actions_authorization.test.ts +++ b/x-pack/plugins/actions/server/authorization/actions_authorization.test.ts @@ -12,7 +12,6 @@ import { ACTION_SAVED_OBJECT_TYPE, ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, } from '../constants/saved_objects'; -import { AuthorizationMode } from './get_authorization_mode_by_source'; import { CONNECTORS_ADVANCED_EXECUTE_PRIVILEGE_API_TAG, CONNECTORS_BASIC_EXECUTE_PRIVILEGE_API_TAG, @@ -164,24 +163,6 @@ describe('ensureAuthorized', () => { ).rejects.toThrowErrorMatchingInlineSnapshot(`"Unauthorized to create a \\"myType\\" action"`); }); - test('exempts users from requiring privileges to execute actions when authorizationMode is Legacy', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - const actionsAuthorization = new ActionsAuthorization({ - request, - authorization, - authorizationMode: AuthorizationMode.Legacy, - }); - - await actionsAuthorization.ensureAuthorized({ operation: 'execute', actionTypeId: 'myType' }); - - expect(authorization.actions.savedObject.get).not.toHaveBeenCalled(); - expect(checkPrivileges).not.toHaveBeenCalled(); - }); - test('checks additional privileges correctly', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< diff --git a/x-pack/plugins/actions/server/authorization/actions_authorization.ts b/x-pack/plugins/actions/server/authorization/actions_authorization.ts index 5739af64050ee..e392f8bbcc14a 100644 --- a/x-pack/plugins/actions/server/authorization/actions_authorization.ts +++ b/x-pack/plugins/actions/server/authorization/actions_authorization.ts @@ -13,19 +13,10 @@ import { ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, } from '../constants/saved_objects'; import { isBidirectionalConnectorType } from '../lib/bidirectional_connectors'; -import { AuthorizationMode } from './get_authorization_mode_by_source'; export interface ConstructorOptions { request: KibanaRequest; authorization?: SecurityPluginSetup['authz']; - // In order to support legacy Alerts which predate the introduction of the - // Actions feature in Kibana we need a way of "dialing down" the level of - // authorization for certain opearations. - // Specifically, we want to allow these old alerts and their scheduled - // actions to continue to execute - which requires that we exempt auth on - // `get` for Connectors and `execute` for Action execution when used by - // these legacy alerts - authorizationMode?: AuthorizationMode; } const operationAlias: Record string[]> = { @@ -38,21 +29,13 @@ const operationAlias: Record; - -describe(`#getAuthorizationModeBySource`, () => { - test('should return RBAC if no source is provided', async () => { - expect(await getAuthorizationModeBySource(unsecuredSavedObjectsClient)).toEqual( - AuthorizationMode.RBAC - ); - }); - - test('should return RBAC if source is not an alert', async () => { - expect( - await getAuthorizationModeBySource( - unsecuredSavedObjectsClient, - asSavedObjectExecutionSource({ - type: 'action', - id: uuidv4(), - }) - ) - ).toEqual(AuthorizationMode.RBAC); - }); - - test('should return RBAC if source alert is not marked as legacy', async () => { - const id = uuidv4(); - unsecuredSavedObjectsClient.get.mockResolvedValue(mockRuleSO({ id })); - expect( - await getAuthorizationModeBySource( - unsecuredSavedObjectsClient, - asSavedObjectExecutionSource({ - type: 'alert', - id, - }) - ) - ).toEqual(AuthorizationMode.RBAC); - }); - - test('should return Legacy if source alert is marked as legacy', async () => { - const id = uuidv4(); - unsecuredSavedObjectsClient.get.mockResolvedValue( - mockRuleSO({ id, attributes: { meta: { versionApiKeyLastmodified: 'pre-7.10.0' } } }) - ); - expect( - await getAuthorizationModeBySource( - unsecuredSavedObjectsClient, - asSavedObjectExecutionSource({ - type: 'alert', - id, - }) - ) - ).toEqual(AuthorizationMode.Legacy); - }); - - test('should return RBAC if source alert is marked as modern', async () => { - const id = uuidv4(); - unsecuredSavedObjectsClient.get.mockResolvedValue( - mockRuleSO({ id, attributes: { meta: { versionApiKeyLastmodified: '7.10.0' } } }) - ); - expect( - await getAuthorizationModeBySource( - unsecuredSavedObjectsClient, - asSavedObjectExecutionSource({ - type: 'alert', - id, - }) - ) - ).toEqual(AuthorizationMode.RBAC); - }); - - test('should return RBAC if source alert doesnt have a last modified version', async () => { - const id = uuidv4(); - unsecuredSavedObjectsClient.get.mockResolvedValue(mockRuleSO({ id, attributes: { meta: {} } })); - expect( - await getAuthorizationModeBySource( - unsecuredSavedObjectsClient, - asSavedObjectExecutionSource({ - type: 'alert', - id, - }) - ) - ).toEqual(AuthorizationMode.RBAC); - }); -}); - -describe(`#bulkGetAuthorizationModeBySource`, () => { - beforeEach(() => { - jest.resetAllMocks(); - }); - - test('should return RBAC if no sources are provided', async () => { - expect(await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient)).toEqual({ - [AuthorizationMode.RBAC]: 1, - [AuthorizationMode.Legacy]: 0, - }); - expect(unsecuredSavedObjectsClient.bulkGet).not.toHaveBeenCalled(); - }); - - test('should return RBAC if no alert sources are provided', async () => { - expect( - await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ - asSavedObjectExecutionSource({ - type: 'action', - id: uuidv4(), - }), - asHttpRequestExecutionSource({} as KibanaRequest), - ]) - ).toEqual({ [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }); - - expect(unsecuredSavedObjectsClient.bulkGet).not.toHaveBeenCalled(); - }); - - test('should consolidate duplicate alert sources', async () => { - unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ - saved_objects: [mockRuleSO({ id: '1' }), mockRuleSO({ id: '2' })], - }); - expect( - await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ - asSavedObjectExecutionSource({ - type: 'alert', - id: '1', - }), - asSavedObjectExecutionSource({ - type: 'alert', - id: '1', - }), - asSavedObjectExecutionSource({ - type: 'alert', - id: '2', - }), - ]) - ).toEqual({ [AuthorizationMode.RBAC]: 2, [AuthorizationMode.Legacy]: 0 }); - - expect(unsecuredSavedObjectsClient.bulkGet).toHaveBeenCalledWith([ - { - type: 'alert', - id: '1', - }, - { - type: 'alert', - id: '2', - }, - ]); - }); - - test('should return RBAC if source alert is not marked as legacy', async () => { - const id = uuidv4(); - unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [mockRuleSO({ id })] }); - expect( - await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ - asSavedObjectExecutionSource({ - type: 'alert', - id, - }), - ]) - ).toEqual({ [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }); - }); - - test('should return Legacy if source alert is marked as legacy', async () => { - const id = uuidv4(); - unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ - saved_objects: [ - mockRuleSO({ id, attributes: { meta: { versionApiKeyLastmodified: 'pre-7.10.0' } } }), - ], - }); - expect( - await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ - asSavedObjectExecutionSource({ - type: 'alert', - id, - }), - ]) - ).toEqual({ [AuthorizationMode.RBAC]: 0, [AuthorizationMode.Legacy]: 1 }); - }); - - test('should return RBAC if source alert is marked as modern', async () => { - const id = uuidv4(); - unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ - saved_objects: [ - mockRuleSO({ id, attributes: { meta: { versionApiKeyLastmodified: '7.10.0' } } }), - ], - }); - expect( - await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ - asSavedObjectExecutionSource({ - type: 'alert', - id, - }), - ]) - ).toEqual({ [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }); - }); - - test('should return RBAC if source alert doesnt have a last modified version', async () => { - const id = uuidv4(); - unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ - saved_objects: [mockRuleSO({ id, attributes: { meta: {} } })], - }); - expect( - await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ - asSavedObjectExecutionSource({ - type: 'alert', - id, - }), - ]) - ).toEqual({ [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }); - }); - - test('should return RBAC and log warning if error getting source alert', async () => { - unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ - saved_objects: [ - mockRuleSO({ id: '1', attributes: { meta: { versionApiKeyLastmodified: 'pre-7.10.0' } } }), - // @ts-expect-error - { - id: '2', - type: 'alert', - error: { statusCode: 404, error: 'failed to get', message: 'fail' }, - }, - ], - }); - expect( - await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ - asSavedObjectExecutionSource({ - type: 'alert', - id: '1', - }), - asSavedObjectExecutionSource({ - type: 'alert', - id: '2', - }), - ]) - ).toEqual({ [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 1 }); - - expect(logger.warn).toHaveBeenCalledWith( - `Error retrieving saved object [alert/2] - fail - default to using RBAC authorization mode.` - ); - }); -}); - -const mockRuleSO = (overrides: Record = {}) => ({ - id: '1', - type: 'alert', - attributes: { - consumer: 'myApp', - schedule: { interval: '10s' }, - alertTypeId: 'myType', - enabled: false, - actions: [ - { - group: 'default', - id: '1', - actionTypeId: '1', - actionRef: '1', - params: { - foo: true, - }, - }, - ], - }, - version: '123', - references: [], - ...overrides, -}); diff --git a/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.ts b/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.ts deleted file mode 100644 index ace66798b24ba..0000000000000 --- a/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Logger, SavedObjectsClientContract } from '@kbn/core/server'; -import { ActionExecutionSource, isSavedObjectExecutionSource } from '../lib'; -import { ALERT_SAVED_OBJECT_TYPE } from '../constants/saved_objects'; -import { SavedObjectExecutionSource } from '../lib/action_execution_source'; - -const LEGACY_VERSION = 'pre-7.10.0'; - -export enum AuthorizationMode { - Legacy, - RBAC, -} - -export async function getAuthorizationModeBySource( - unsecuredSavedObjectsClient: SavedObjectsClientContract, - executionSource?: ActionExecutionSource -): Promise { - return isSavedObjectExecutionSource(executionSource) && - executionSource?.source?.type === ALERT_SAVED_OBJECT_TYPE && - ( - await unsecuredSavedObjectsClient.get<{ - meta?: { - versionApiKeyLastmodified?: string; - }; - }>(ALERT_SAVED_OBJECT_TYPE, executionSource.source.id) - ).attributes.meta?.versionApiKeyLastmodified === LEGACY_VERSION - ? AuthorizationMode.Legacy - : AuthorizationMode.RBAC; -} - -export async function bulkGetAuthorizationModeBySource( - logger: Logger, - unsecuredSavedObjectsClient: SavedObjectsClientContract, - executionSources: Array> = [] -): Promise> { - const authModes = { [AuthorizationMode.Legacy]: 0, [AuthorizationMode.RBAC]: 0 }; - - const alertSavedObjectExecutionSources: SavedObjectExecutionSource[] = executionSources.filter( - (source) => - isSavedObjectExecutionSource(source) && source?.source?.type === ALERT_SAVED_OBJECT_TYPE - ) as SavedObjectExecutionSource[]; - - // If no ALERT_SAVED_OBJECT_TYPE source, default to RBAC - if (alertSavedObjectExecutionSources.length === 0) { - authModes[AuthorizationMode.RBAC] = 1; - return authModes; - } - - // Collect the unique rule IDs for ALERT_SAVED_OBJECT_TYPE sources and bulk get the associated SOs - const rulesIds = new Set( - alertSavedObjectExecutionSources.map((source: SavedObjectExecutionSource) => source?.source?.id) - ); - - // Get rule saved objects to determine whether to use RBAC or legacy authorization source - const ruleSOs = await unsecuredSavedObjectsClient.bulkGet<{ - meta?: { - versionApiKeyLastmodified?: string; - }; - }>( - [...rulesIds].map((id) => ({ - type: ALERT_SAVED_OBJECT_TYPE, - id, - })) - ); - - return ruleSOs.saved_objects.reduce((acc, ruleSO) => { - if (ruleSO.error) { - logger.warn( - `Error retrieving saved object [${ruleSO.type}/${ruleSO.id}] - ${ruleSO.error?.message} - default to using RBAC authorization mode.` - ); - // If there's an error retrieving the saved object, default to RBAC auth mode to avoid privilege de-escalation - authModes[AuthorizationMode.RBAC]++; - } else { - // Check whether this is a legacy rule - const isLegacy = ruleSO.attributes?.meta?.versionApiKeyLastmodified === LEGACY_VERSION; - if (isLegacy) { - authModes[AuthorizationMode.Legacy]++; - } else { - authModes[AuthorizationMode.RBAC]++; - } - } - return acc; - }, authModes); -} diff --git a/x-pack/plugins/actions/server/config.test.ts b/x-pack/plugins/actions/server/config.test.ts index 5adc9c18b07a7..4034fc5cb50b5 100644 --- a/x-pack/plugins/actions/server/config.test.ts +++ b/x-pack/plugins/actions/server/config.test.ts @@ -38,6 +38,9 @@ describe('config validation', () => { "proxyRejectUnauthorizedCertificates": true, "rejectUnauthorized": true, "responseTimeout": "PT1M", + "usage": Object { + "url": "https://usage-api.usage-api/api/v1/usage", + }, } `); }); @@ -85,6 +88,9 @@ describe('config validation', () => { "proxyRejectUnauthorizedCertificates": false, "rejectUnauthorized": false, "responseTimeout": "PT1M", + "usage": Object { + "url": "https://usage-api.usage-api/api/v1/usage", + }, } `); }); @@ -225,6 +231,9 @@ describe('config validation', () => { "proxyVerificationMode": "none", "verificationMode": "none", }, + "usage": Object { + "url": "https://usage-api.usage-api/api/v1/usage", + }, } `); }); diff --git a/x-pack/plugins/actions/server/config.ts b/x-pack/plugins/actions/server/config.ts index d806bde1fa227..f475c05424df4 100644 --- a/x-pack/plugins/actions/server/config.ts +++ b/x-pack/plugins/actions/server/config.ts @@ -72,6 +72,8 @@ const connectorTypeSchema = schema.object({ maxAttempts: schema.maybe(schema.number({ min: MIN_MAX_ATTEMPTS, max: MAX_MAX_ATTEMPTS })), }); +export const DEFAULT_USAGE_API_URL = 'https://usage-api.usage-api/api/v1/usage'; + // We leverage enabledActionTypes list by allowing the other plugins to overwrite it by using "setEnabledConnectorTypes" in the plugin setup. // The list can be overwritten only if it's not already been set in the config. const enabledConnectorTypesSchema = schema.arrayOf( @@ -145,15 +147,14 @@ export const configSchema = schema.object({ max: schema.maybe(schema.number({ min: MIN_QUEUED_MAX, defaultValue: DEFAULT_QUEUED_MAX })), }) ), - usage: schema.maybe( - schema.object({ - ca: schema.maybe( - schema.object({ - path: schema.string(), - }) - ), - }) - ), + usage: schema.object({ + url: schema.string({ defaultValue: DEFAULT_USAGE_API_URL }), + ca: schema.maybe( + schema.object({ + path: schema.string(), + }) + ), + }), }); export type ActionsConfig = TypeOf; diff --git a/x-pack/plugins/actions/server/integration_tests/axios_utils_connection.test.ts b/x-pack/plugins/actions/server/integration_tests/axios_utils_connection.test.ts index 200656d339ac3..3a4101bb9f152 100644 --- a/x-pack/plugins/actions/server/integration_tests/axios_utils_connection.test.ts +++ b/x-pack/plugins/actions/server/integration_tests/axios_utils_connection.test.ts @@ -20,7 +20,7 @@ import { ByteSizeValue } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { createReadySignal } from '@kbn/event-log-plugin/server/lib/ready_signal'; -import { ActionsConfig } from '../config'; +import { ActionsConfig, DEFAULT_USAGE_API_URL } from '../config'; import { ActionsConfigurationUtilities, getActionsConfigurationUtilities } from '../actions_config'; import { resolveCustomHosts } from '../lib/custom_host_settings'; import { @@ -691,6 +691,9 @@ const BaseActionsConfig: ActionsConfig = { microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL, microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE, microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL, + usage: { + url: DEFAULT_USAGE_API_URL, + }, }; function getACUfromConfig(config: Partial = {}): ActionsConfigurationUtilities { diff --git a/x-pack/plugins/actions/server/integration_tests/axios_utils_proxy.test.ts b/x-pack/plugins/actions/server/integration_tests/axios_utils_proxy.test.ts index f29b2a9855186..1c1d411111253 100644 --- a/x-pack/plugins/actions/server/integration_tests/axios_utils_proxy.test.ts +++ b/x-pack/plugins/actions/server/integration_tests/axios_utils_proxy.test.ts @@ -20,7 +20,7 @@ import { ByteSizeValue } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { createReadySignal } from '@kbn/event-log-plugin/server/lib/ready_signal'; -import { ActionsConfig } from '../config'; +import { ActionsConfig, DEFAULT_USAGE_API_URL } from '../config'; import { ActionsConfigurationUtilities, getActionsConfigurationUtilities } from '../actions_config'; import { resolveCustomHosts } from '../lib/custom_host_settings'; import { @@ -597,6 +597,9 @@ const BaseActionsConfig: ActionsConfig = { microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL, microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE, microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL, + usage: { + url: DEFAULT_USAGE_API_URL, + }, }; function getACUfromConfig(config: Partial = {}): ActionsConfigurationUtilities { diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index 6e4ec1b69c876..76354dc882dd9 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -851,7 +851,7 @@ describe('Action Executor', () => { status: 'error', retry: false, message: `error validating action params: [param1]: expected value of type [string] but got [undefined]`, - errorSource: TaskErrorSource.FRAMEWORK, + errorSource: TaskErrorSource.USER, }); }); diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index a636f4b41566c..b0f9db0ef700c 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -685,6 +685,17 @@ function validateAction( try { validatedParams = validateParams(actionType, params, validatorServices); + } catch (err) { + throw new ActionExecutionError(err.message, ActionExecutionErrorReason.Validation, { + actionId, + status: 'error', + message: err.message, + retry: !!taskInfo, + errorSource: TaskErrorSource.USER, + }); + } + + try { validatedConfig = validateConfig(actionType, config, validatorServices); validatedSecrets = validateSecrets(actionType, secrets, validatorServices); if (actionType.validate?.connector) { diff --git a/x-pack/plugins/actions/server/lib/custom_host_settings.test.ts b/x-pack/plugins/actions/server/lib/custom_host_settings.test.ts index 818d7fb9bcd0a..0a9d9c6df31e7 100644 --- a/x-pack/plugins/actions/server/lib/custom_host_settings.test.ts +++ b/x-pack/plugins/actions/server/lib/custom_host_settings.test.ts @@ -10,7 +10,7 @@ import { resolve as pathResolve, join as pathJoin } from 'path'; import { ByteSizeValue } from '@kbn/config-schema'; import moment from 'moment'; -import { ActionsConfig } from '../config'; +import { ActionsConfig, DEFAULT_USAGE_API_URL } from '../config'; import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; @@ -82,6 +82,9 @@ describe('custom_host_settings', () => { microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL, microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE, microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL, + usage: { + url: DEFAULT_USAGE_API_URL, + }, }; test('ensure it copies over the config parts that it does not touch', () => { diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts index 6c4cdd31ccf6c..9733b56638d77 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts @@ -885,7 +885,8 @@ describe('Task Runner Factory', () => { expect(err).toBeDefined(); expect(isRetryableError(err)).toEqual(false); expect(taskRunnerFactoryInitializerParams.logger.error as jest.Mock).toHaveBeenCalledWith( - `Action '2' failed: Error message` + `Action '2' failed: Error message`, + { tags: ['connector-run-failed', 'framework-error'] } ); expect(getErrorSource(err)).toBe(TaskErrorSource.FRAMEWORK); }); @@ -934,7 +935,8 @@ describe('Task Runner Factory', () => { expect(err).toBeDefined(); expect(taskRunnerFactoryInitializerParams.logger.error as jest.Mock).toHaveBeenCalledWith( - `Action '2' failed: Error message: Service message` + `Action '2' failed: Error message: Service message`, + { tags: ['connector-run-failed', 'framework-error'] } ); }); @@ -1033,7 +1035,8 @@ describe('Task Runner Factory', () => { } expect(err).toBeDefined(); expect(taskRunnerFactoryInitializerParams.logger.error as jest.Mock).toHaveBeenCalledWith( - `Action '2' failed: Fail` + `Action '2' failed: Fail`, + { tags: ['connector-run-failed', 'framework-error'] } ); expect(thrownError).toEqual(err); expect(getErrorSource(err)).toBe(TaskErrorSource.FRAMEWORK); @@ -1140,10 +1143,16 @@ describe('Task Runner Factory', () => { try { await taskRunner.run(); + throw new Error('Should have thrown'); } catch (e) { expect(mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser).toHaveBeenCalledTimes(1); expect(getErrorSource(e)).toBe(TaskErrorSource.FRAMEWORK); expect(e).toEqual(error); + + expect(taskRunnerFactoryInitializerParams.logger.error).toHaveBeenCalledWith( + `Failed to load action task params ${mockedTaskInstance.params.actionTaskParamsId}: test`, + { tags: ['connector-run-failed', 'framework-error'] } + ); } }); }); diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index d6b418c481ea5..d067ddaaae7ad 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -115,7 +115,8 @@ export class TaskRunnerFactory { } = await getActionTaskParams( actionTaskExecutorParams, encryptedSavedObjectsClient, - spaceIdToNamespace + spaceIdToNamespace, + logger ); const { spaceId } = actionTaskExecutorParams; @@ -139,12 +140,18 @@ export class TaskRunnerFactory { ...getSource(references, source), }); } catch (e) { - logger.error(`Action '${actionId}' failed: ${e.message}`); + const errorSource = + e instanceof ActionTypeDisabledError + ? TaskErrorSource.USER + : getErrorSource(e) || TaskErrorSource.FRAMEWORK; + logger.error(`Action '${actionId}' failed: ${e.message}`, { + tags: ['connector-run-failed', `${errorSource}-error`], + }); if (e instanceof ActionTypeDisabledError) { // We'll stop re-trying due to action being forbidden - throwUnrecoverableError(createTaskRunError(e, TaskErrorSource.USER)); + throwUnrecoverableError(createTaskRunError(e, errorSource)); } - throw createTaskRunError(e, getErrorSource(e) || TaskErrorSource.FRAMEWORK); + throw createTaskRunError(e, errorSource); } inMemoryMetrics.increment(IN_MEMORY_METRICS.ACTION_EXECUTIONS); @@ -155,7 +162,9 @@ export class TaskRunnerFactory { if (executorResult.serviceMessage) { message = `${message}: ${executorResult.serviceMessage}`; } - logger.error(`Action '${actionId}' failed: ${message}`); + logger.error(`Action '${actionId}' failed: ${message}`, { + tags: ['connector-run-failed', `${executorResult.errorSource}-error`], + }); // Task manager error handler only kicks in when an error thrown (at this time) // So what we have to do is throw when the return status is `error`. @@ -175,7 +184,8 @@ export class TaskRunnerFactory { } = await getActionTaskParams( actionTaskExecutorParams, encryptedSavedObjectsClient, - spaceIdToNamespace + spaceIdToNamespace, + logger ); const request = getFakeRequest(apiKey); @@ -239,7 +249,8 @@ function getFakeRequest(apiKey?: string) { async function getActionTaskParams( executorParams: ActionTaskExecutorParams, encryptedSavedObjectsClient: EncryptedSavedObjectsClient, - spaceIdToNamespace: SpaceIdToNamespaceFunction + spaceIdToNamespace: SpaceIdToNamespaceFunction, + logger: Logger ): Promise { const { spaceId } = executorParams; const namespace = spaceIdToNamespace(spaceId); @@ -268,10 +279,17 @@ async function getActionTaskParams( }, }; } catch (e) { + const errorSource = SavedObjectsErrorHelpers.isNotFoundError(e) + ? TaskErrorSource.USER + : TaskErrorSource.FRAMEWORK; + logger.error( + `Failed to load action task params ${executorParams.actionTaskParamsId}: ${e.message}`, + { tags: ['connector-run-failed', `${errorSource}-error`] } + ); if (SavedObjectsErrorHelpers.isNotFoundError(e)) { - throw createRetryableError(createTaskRunError(e, TaskErrorSource.USER), true); + throw createRetryableError(createTaskRunError(e, errorSource), true); } - throw createRetryableError(createTaskRunError(e, TaskErrorSource.FRAMEWORK), true); + throw createRetryableError(createTaskRunError(e, errorSource), true); } } else { return { attributes: executorParams.taskParams, references: executorParams.references ?? [] }; diff --git a/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.test.ts b/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.test.ts deleted file mode 100644 index 6d44a5d982e62..0000000000000 --- a/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; -import { trackLegacyRBACExemption } from './track_legacy_rbac_exemption'; - -describe('trackLegacyRBACExemption', () => { - it('should call `usageCounter.incrementCounter`', () => { - const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); - const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - - trackLegacyRBACExemption('test', mockUsageCounter); - expect(mockUsageCounter.incrementCounter).toHaveBeenCalledWith({ - counterName: `source_test`, - counterType: 'legacyRBACExemption', - incrementBy: 1, - }); - }); - - it('should do nothing if no usage counter is provided', () => { - let err; - try { - trackLegacyRBACExemption('test', undefined); - } catch (e) { - err = e; - } - expect(err).toBeUndefined(); - }); - - it('should call `usageCounter.incrementCounter` and increment by the passed in value', () => { - const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); - const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - - trackLegacyRBACExemption('test', mockUsageCounter, 15); - expect(mockUsageCounter.incrementCounter).toHaveBeenCalledWith({ - counterName: `source_test`, - counterType: 'legacyRBACExemption', - incrementBy: 15, - }); - }); -}); diff --git a/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.ts b/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.ts deleted file mode 100644 index b6f1af3d9de76..0000000000000 --- a/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; - -export function trackLegacyRBACExemption( - source: string, - usageCounter?: UsageCounter, - increment?: number -) { - if (usageCounter) { - usageCounter.incrementCounter({ - counterName: `source_${source}`, - counterType: 'legacyRBACExemption', - incrementBy: increment ? increment : 1, - }); - } -} diff --git a/x-pack/plugins/actions/server/plugin.test.ts b/x-pack/plugins/actions/server/plugin.test.ts index 89efb80867fd7..4ff87aa0459ef 100644 --- a/x-pack/plugins/actions/server/plugin.test.ts +++ b/x-pack/plugins/actions/server/plugin.test.ts @@ -30,6 +30,7 @@ import { DEFAULT_MICROSOFT_GRAPH_API_SCOPE, DEFAULT_MICROSOFT_GRAPH_API_URL, } from '../common'; +import { cloudMock } from '@kbn/cloud-plugin/server/mocks'; const executor: ExecutorType<{}, {}, {}, void> = async (options) => { return { status: 'ok', actionId: options.actionId }; @@ -59,6 +60,9 @@ function getConfig(overrides = {}) { microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL, microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE, microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL, + usage: { + url: 'ca.path', + }, ...overrides, }; } @@ -84,6 +88,9 @@ describe('Actions Plugin', () => { microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL, microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE, microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL, + usage: { + url: 'ca.path', + }, }); plugin = new ActionsPlugin(context); coreSetup = coreMock.createSetup(); @@ -95,6 +102,7 @@ describe('Actions Plugin', () => { eventLog: eventLogMock.createSetup(), usageCollection: usageCollectionPluginMock.createSetupContract(), features: featuresPluginMock.createSetup(), + cloud: cloudMock.createSetup(), }; coreSetup.getStartServices.mockResolvedValue([ coreMock.createStart(), @@ -347,6 +355,7 @@ describe('Actions Plugin', () => { eventLog: eventLogMock.createSetup(), usageCollection: usageCollectionPluginMock.createSetupContract(), features: featuresPluginMock.createSetup(), + cloud: cloudMock.createSetup(), }; } @@ -374,6 +383,7 @@ describe('Actions Plugin', () => { usageCollection: usageCollectionPluginMock.createSetupContract(), features: featuresPluginMock.createSetup(), serverless: serverlessPluginMock.createSetupContract(), + cloud: cloudMock.createSetup(), }; } @@ -585,6 +595,9 @@ describe('Actions Plugin', () => { microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL, microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE, microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL, + usage: { + url: 'ca.path', + }, }); plugin = new ActionsPlugin(context); coreSetup = coreMock.createSetup(); @@ -596,6 +609,7 @@ describe('Actions Plugin', () => { eventLog: eventLogMock.createSetup(), usageCollection: usageCollectionPluginMock.createSetupContract(), features: featuresPluginMock.createSetup(), + cloud: cloudMock.createSetup(), }; pluginsStart = { licensing: licensingMock.createStart(), @@ -680,6 +694,7 @@ describe('Actions Plugin', () => { eventLog: eventLogMock.createSetup(), usageCollection: usageCollectionPluginMock.createSetupContract(), features: featuresPluginMock.createSetup(), + cloud: cloudMock.createSetup(), }; pluginsStart = { licensing: licensingMock.createStart(), diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 00dc17c2f92d7..57304c176c13d 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -42,6 +42,7 @@ import { import { MonitoringCollectionSetup } from '@kbn/monitoring-collection-plugin/server'; import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/server'; +import type { CloudSetup } from '@kbn/cloud-plugin/server'; import { ActionsConfig, AllowedHosts, EnabledConnectorTypes, getValidatedConfig } from './config'; import { resolveCustomHosts } from './lib/custom_host_settings'; import { events } from './lib/event_based_telemetry'; @@ -84,10 +85,6 @@ import { setupSavedObjects } from './saved_objects'; import { ACTIONS_FEATURE } from './feature'; import { ActionsAuthorization } from './authorization/actions_authorization'; import { ActionExecutionSource } from './lib/action_execution_source'; -import { - getAuthorizationModeBySource, - AuthorizationMode, -} from './authorization/get_authorization_mode_by_source'; import { ensureSufficientLicense } from './lib/ensure_sufficient_license'; import { renderMustacheObject } from './lib/mustache_renderer'; import { getAlertHistoryEsIndex } from './preconfigured_connectors/alert_history_es_index/alert_history_es_index'; @@ -112,6 +109,7 @@ import type { IUnsecuredActionsClient } from './unsecured_actions_client/unsecur import { UnsecuredActionsClient } from './unsecured_actions_client/unsecured_actions_client'; import { createBulkUnsecuredExecutionEnqueuerFunction } from './create_unsecured_execute_function'; import { createSystemConnectors } from './create_system_actions'; +import { ConnectorUsageReportingTask } from './usage/connector_usage_reporting_task'; export interface PluginSetupContract { registerType< @@ -184,6 +182,7 @@ export interface ActionsPluginsSetup { spaces?: SpacesPluginSetup; monitoringCollection?: MonitoringCollectionSetup; serverless?: ServerlessPluginSetup; + cloud: CloudSetup; } export interface ActionsPluginsStart { @@ -218,6 +217,7 @@ export class ActionsPlugin implements Plugin getActionsClientWithRequest(request); @@ -603,6 +606,8 @@ export class ActionsPlugin implements Plugin {}); + return { isActionTypeEnabled: (id, options = { notifyUsage: false }) => { return this.actionTypeRegistry!.isActionTypeEnabled(id, options); @@ -641,13 +646,9 @@ export class ActionsPlugin implements Plugin { + private instantiateAuthorization = (request: KibanaRequest) => { return new ActionsAuthorization({ request, - authorizationMode, authorization: this.security?.authz, }); }; diff --git a/x-pack/plugins/actions/server/routes/legacy/_mock_handler_arguments.ts b/x-pack/plugins/actions/server/routes/_mock_handler_arguments.ts similarity index 87% rename from x-pack/plugins/actions/server/routes/legacy/_mock_handler_arguments.ts rename to x-pack/plugins/actions/server/routes/_mock_handler_arguments.ts index 73906fa0a63e3..fc2610b804b69 100644 --- a/x-pack/plugins/actions/server/routes/legacy/_mock_handler_arguments.ts +++ b/x-pack/plugins/actions/server/routes/_mock_handler_arguments.ts @@ -9,10 +9,10 @@ import { KibanaRequest, KibanaResponseFactory } from '@kbn/core/server'; import { identity } from 'lodash'; import type { MethodKeysOf } from '@kbn/utility-types'; import { httpServerMock } from '@kbn/core/server/mocks'; -import { ActionsRequestHandlerContext } from '../../types'; -import { actionsClientMock } from '../../mocks'; -import { ActionsClientMock } from '../../actions_client/actions_client.mock'; -import { ConnectorType } from '../../application/connector/types'; +import { ActionsRequestHandlerContext } from '../types'; +import { actionsClientMock } from '../mocks'; +import { ActionsClientMock } from '../actions_client/actions_client.mock'; +import { ConnectorType } from '../application/connector/types'; export function mockHandlerArguments( { diff --git a/x-pack/plugins/actions/server/routes/connector/create/create.test.ts b/x-pack/plugins/actions/server/routes/connector/create/create.test.ts index 0f97015bd4f01..7bf91629023c8 100644 --- a/x-pack/plugins/actions/server/routes/connector/create/create.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/create/create.test.ts @@ -8,7 +8,7 @@ import { createConnectorRoute } from './create'; import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../../../lib/license_state.mock'; -import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from '../../_mock_handler_arguments'; import { verifyAccessAndContext } from '../../verify_access_and_context'; import { omit } from 'lodash'; import { actionsClientMock } from '../../../actions_client/actions_client.mock'; diff --git a/x-pack/plugins/actions/server/routes/connector/delete/delete.test.ts b/x-pack/plugins/actions/server/routes/connector/delete/delete.test.ts index 9fb3f7f3a8ae5..82e6a6584a641 100644 --- a/x-pack/plugins/actions/server/routes/connector/delete/delete.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/delete/delete.test.ts @@ -8,7 +8,7 @@ import { deleteConnectorRoute } from './delete'; import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../../../lib/license_state.mock'; -import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from '../../_mock_handler_arguments'; import { actionsClientMock } from '../../../mocks'; import { verifyAccessAndContext } from '../../verify_access_and_context'; diff --git a/x-pack/plugins/actions/server/routes/connector/execute/execute.test.ts b/x-pack/plugins/actions/server/routes/connector/execute/execute.test.ts index a9ae5e881f141..a0f5bf0629aec 100644 --- a/x-pack/plugins/actions/server/routes/connector/execute/execute.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/execute/execute.test.ts @@ -8,7 +8,7 @@ import { executeConnectorRoute } from './execute'; import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../../../lib/license_state.mock'; -import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from '../../_mock_handler_arguments'; import { asHttpRequestExecutionSource } from '../../../lib'; import { actionsClientMock } from '../../../actions_client/actions_client.mock'; import { ActionTypeExecutorResult } from '../../../types'; diff --git a/x-pack/plugins/actions/server/routes/connector/get/get.test.ts b/x-pack/plugins/actions/server/routes/connector/get/get.test.ts index 28293ae7947f2..cbf0cd86f9912 100644 --- a/x-pack/plugins/actions/server/routes/connector/get/get.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/get/get.test.ts @@ -8,7 +8,7 @@ import { getConnectorRoute } from './get'; import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../../../lib/license_state.mock'; -import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from '../../_mock_handler_arguments'; import { actionsClientMock } from '../../../actions_client/actions_client.mock'; import { verifyAccessAndContext } from '../../verify_access_and_context'; diff --git a/x-pack/plugins/actions/server/routes/connector/get_all/get_all.test.ts b/x-pack/plugins/actions/server/routes/connector/get_all/get_all.test.ts index 0ab3b57e238cf..5328cd76e2c4d 100644 --- a/x-pack/plugins/actions/server/routes/connector/get_all/get_all.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/get_all/get_all.test.ts @@ -8,7 +8,7 @@ import { getAllConnectorsRoute } from './get_all'; import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../../../lib/license_state.mock'; -import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from '../../_mock_handler_arguments'; import { verifyAccessAndContext } from '../../verify_access_and_context'; import { actionsClientMock } from '../../../actions_client/actions_client.mock'; diff --git a/x-pack/plugins/actions/server/routes/connector/get_all_system/get_all_system.test.ts b/x-pack/plugins/actions/server/routes/connector/get_all_system/get_all_system.test.ts index 07221aacddde7..a82eeef55ddda 100644 --- a/x-pack/plugins/actions/server/routes/connector/get_all_system/get_all_system.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/get_all_system/get_all_system.test.ts @@ -8,7 +8,7 @@ import { getAllConnectorsIncludingSystemRoute } from './get_all_system'; import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../../../lib/license_state.mock'; -import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from '../../_mock_handler_arguments'; import { verifyAccessAndContext } from '../../verify_access_and_context'; import { actionsClientMock } from '../../../actions_client/actions_client.mock'; diff --git a/x-pack/plugins/actions/server/routes/connector/list_types/list_types.test.ts b/x-pack/plugins/actions/server/routes/connector/list_types/list_types.test.ts index e7370c7638a89..bf1ab91c5b6ab 100644 --- a/x-pack/plugins/actions/server/routes/connector/list_types/list_types.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/list_types/list_types.test.ts @@ -8,7 +8,7 @@ import { httpServiceMock } from '@kbn/core/server/mocks'; import { LicenseType } from '@kbn/licensing-plugin/server'; import { licenseStateMock } from '../../../lib/license_state.mock'; -import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from '../../_mock_handler_arguments'; import { listTypesRoute } from './list_types'; import { verifyAccessAndContext } from '../../verify_access_and_context'; import { actionsClientMock } from '../../../mocks'; diff --git a/x-pack/plugins/actions/server/routes/connector/list_types_system/list_types_system.test.ts b/x-pack/plugins/actions/server/routes/connector/list_types_system/list_types_system.test.ts index 07d2d3adcd4f3..7398d020f5972 100644 --- a/x-pack/plugins/actions/server/routes/connector/list_types_system/list_types_system.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/list_types_system/list_types_system.test.ts @@ -8,7 +8,7 @@ import { httpServiceMock } from '@kbn/core/server/mocks'; import { LicenseType } from '@kbn/licensing-plugin/server'; import { licenseStateMock } from '../../../lib/license_state.mock'; -import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from '../../_mock_handler_arguments'; import { listTypesWithSystemRoute } from './list_types_system'; import { verifyAccessAndContext } from '../../verify_access_and_context'; import { actionsClientMock } from '../../../mocks'; diff --git a/x-pack/plugins/actions/server/routes/connector/update/update.test.ts b/x-pack/plugins/actions/server/routes/connector/update/update.test.ts index f48c87fca43c2..870882513c5ae 100644 --- a/x-pack/plugins/actions/server/routes/connector/update/update.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/update/update.test.ts @@ -8,7 +8,7 @@ import { updateConnectorRoute } from './update'; import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../../../lib/license_state.mock'; -import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from '../../_mock_handler_arguments'; import { actionsClientMock } from '../../../actions_client/actions_client.mock'; import { verifyAccessAndContext } from '../../verify_access_and_context'; import { updateConnectorBodySchema } from '../../../../common/routes/connector/apis/update'; diff --git a/x-pack/plugins/actions/server/routes/get_global_execution_kpi.test.ts b/x-pack/plugins/actions/server/routes/get_global_execution_kpi.test.ts index 066d558bcfd59..026a53caebe48 100644 --- a/x-pack/plugins/actions/server/routes/get_global_execution_kpi.test.ts +++ b/x-pack/plugins/actions/server/routes/get_global_execution_kpi.test.ts @@ -7,7 +7,7 @@ import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from './_mock_handler_arguments'; import { actionsClientMock } from '../actions_client/actions_client.mock'; import { getGlobalExecutionKPIRoute } from './get_global_execution_kpi'; import { verifyAccessAndContext } from './verify_access_and_context'; diff --git a/x-pack/plugins/actions/server/routes/get_global_execution_logs.test.ts b/x-pack/plugins/actions/server/routes/get_global_execution_logs.test.ts index 4654885a49bcb..c31dedb52bb9d 100644 --- a/x-pack/plugins/actions/server/routes/get_global_execution_logs.test.ts +++ b/x-pack/plugins/actions/server/routes/get_global_execution_logs.test.ts @@ -8,7 +8,7 @@ import { getGlobalExecutionLogRoute } from './get_global_execution_logs'; import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from './_mock_handler_arguments'; import { actionsClientMock } from '../actions_client/actions_client.mock'; import { IExecutionLogResult } from '../../common'; import { verifyAccessAndContext } from './verify_access_and_context'; diff --git a/x-pack/plugins/actions/server/routes/get_oauth_access_token.test.ts b/x-pack/plugins/actions/server/routes/get_oauth_access_token.test.ts index c1b7dd26aff15..e3474ebcaa0a6 100644 --- a/x-pack/plugins/actions/server/routes/get_oauth_access_token.test.ts +++ b/x-pack/plugins/actions/server/routes/get_oauth_access_token.test.ts @@ -8,7 +8,7 @@ import { getOAuthAccessToken } from './get_oauth_access_token'; import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from './_mock_handler_arguments'; import { verifyAccessAndContext } from './verify_access_and_context'; import { actionsConfigMock } from '../actions_config.mock'; import { actionsClientMock } from '../actions_client/actions_client.mock'; diff --git a/x-pack/plugins/actions/server/routes/index.ts b/x-pack/plugins/actions/server/routes/index.ts index 39efe6619176b..7e6d70148f4fb 100644 --- a/x-pack/plugins/actions/server/routes/index.ts +++ b/x-pack/plugins/actions/server/routes/index.ts @@ -19,7 +19,6 @@ import { executeConnectorRoute } from './connector/execute'; import { getConnectorRoute } from './connector/get'; import { updateConnectorRoute } from './connector/update'; import { getOAuthAccessToken } from './get_oauth_access_token'; -import { defineLegacyRoutes } from './legacy'; import { ActionsConfigurationUtilities } from '../actions_config'; import { getGlobalExecutionLogRoute } from './get_global_execution_logs'; import { getGlobalExecutionKPIRoute } from './get_global_execution_kpi'; @@ -32,9 +31,7 @@ export interface RouteOptions { } export function defineRoutes(opts: RouteOptions) { - const { router, licenseState, actionsConfigUtils, usageCounter } = opts; - - defineLegacyRoutes(router, licenseState, usageCounter); + const { router, licenseState, actionsConfigUtils } = opts; createConnectorRoute(router, licenseState); deleteConnectorRoute(router, licenseState); diff --git a/x-pack/plugins/actions/server/routes/legacy/create.test.ts b/x-pack/plugins/actions/server/routes/legacy/create.test.ts deleted file mode 100644 index 05993e44746f9..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/create.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { createActionRoute } from './create'; -import { httpServiceMock } from '@kbn/core/server/mocks'; -import { licenseStateMock } from '../../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { actionsClientMock } from '../../actions_client/actions_client.mock'; -import { verifyAccessAndContext } from '../verify_access_and_context'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; - -jest.mock('../verify_access_and_context', () => ({ - verifyAccessAndContext: jest.fn(), -})); - -jest.mock('../../lib/track_legacy_route_usage', () => ({ - trackLegacyRouteUsage: jest.fn(), -})); - -const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); -const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - -beforeEach(() => { - jest.resetAllMocks(); - (verifyAccessAndContext as jest.Mock).mockImplementation((license, handler) => handler); -}); - -describe('createActionRoute', () => { - it('creates an action with proper parameters', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - createActionRoute(router, licenseState); - - const [config, handler] = router.post.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions/action"`); - - const createResult = { - id: '1', - name: 'My name', - actionTypeId: 'abc', - config: { foo: true }, - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }; - - const actionsClient = actionsClientMock.create(); - actionsClient.create.mockResolvedValueOnce(createResult); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - body: { - name: 'My name', - actionTypeId: 'abc', - config: { foo: true }, - secrets: {}, - }, - }, - ['ok'] - ); - - expect(await handler(context, req, res)).toEqual({ body: createResult }); - - expect(actionsClient.create).toHaveBeenCalledTimes(1); - expect(actionsClient.create.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "action": Object { - "actionTypeId": "abc", - "config": Object { - "foo": true, - }, - "name": "My name", - "secrets": Object {}, - }, - }, - ] - `); - - expect(res.ok).toHaveBeenCalledWith({ - body: createResult, - }); - }); - - it('ensures the license allows creating actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - createActionRoute(router, licenseState); - - const [, handler] = router.post.mock.calls[0]; - - const actionsClient = actionsClientMock.create(); - actionsClient.create.mockResolvedValueOnce({ - id: '1', - name: 'My name', - actionTypeId: 'abc', - config: { foo: true }, - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }); - - const [context, req, res] = mockHandlerArguments({ actionsClient }, {}); - - await handler(context, req, res); - - expect(verifyAccessAndContext).toHaveBeenCalledWith(licenseState, expect.any(Function)); - }); - - it('ensures the license check prevents creating actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - (verifyAccessAndContext as jest.Mock).mockImplementation(() => async () => { - throw new Error('OMG'); - }); - - createActionRoute(router, licenseState); - - const [, handler] = router.post.mock.calls[0]; - - const actionsClient = actionsClientMock.create(); - actionsClient.create.mockResolvedValueOnce({ - id: '1', - name: 'My name', - actionTypeId: 'abc', - config: { foo: true }, - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }); - - const [context, req, res] = mockHandlerArguments({ actionsClient }, {}); - - await expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); - }); - - it('should track every call', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - const actionsClient = actionsClientMock.create(); - - createActionRoute(router, licenseState, mockUsageCounter); - const [, handler] = router.post.mock.calls[0]; - const [context, req, res] = mockHandlerArguments({ actionsClient }, {}); - await handler(context, req, res); - expect(trackLegacyRouteUsage).toHaveBeenCalledWith('create', mockUsageCounter); - }); -}); diff --git a/x-pack/plugins/actions/server/routes/legacy/create.ts b/x-pack/plugins/actions/server/routes/legacy/create.ts deleted file mode 100644 index f667a9e003a77..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/create.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { IRouter } from '@kbn/core/server'; -import { ActionsRequestHandlerContext } from '../../types'; -import { ILicenseState } from '../../lib'; -import { BASE_ACTION_API_PATH } from '../../../common'; -import { verifyAccessAndContext } from '../verify_access_and_context'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { connectorResponseSchemaV1 } from '../../../common/routes/connector/response'; - -export const bodySchema = schema.object({ - name: schema.string({ - meta: { description: 'The display name for the connector.' }, - }), - actionTypeId: schema.string({ - meta: { description: 'The connector type identifier.' }, - }), - config: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), - secrets: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), -}); - -export const createActionRoute = ( - router: IRouter, - licenseState: ILicenseState, - usageCounter?: UsageCounter -) => { - router.post( - { - path: `${BASE_ACTION_API_PATH}/action`, - options: { - access: 'public', - summary: `Create a connector`, - tags: ['oas-tag:connectors'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - }, - validate: { - request: { - body: bodySchema, - }, - response: { - 200: { - description: 'Indicates a successful call.', - body: () => connectorResponseSchemaV1, - }, - }, - }, - }, - router.handleLegacyErrors( - verifyAccessAndContext(licenseState, async function (context, req, res) { - const actionsClient = (await context.actions).getActionsClient(); - const action = req.body; - trackLegacyRouteUsage('create', usageCounter); - return res.ok({ - body: await actionsClient.create({ action }), - }); - }) - ) - ); -}; diff --git a/x-pack/plugins/actions/server/routes/legacy/delete.test.ts b/x-pack/plugins/actions/server/routes/legacy/delete.test.ts deleted file mode 100644 index 2bfb5c7810e46..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/delete.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { deleteActionRoute } from './delete'; -import { httpServiceMock } from '@kbn/core/server/mocks'; -import { licenseStateMock } from '../../lib/license_state.mock'; -import { verifyApiAccess } from '../../lib'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { actionsClientMock } from '../../mocks'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; - -jest.mock('../../lib/verify_api_access', () => ({ - verifyApiAccess: jest.fn(), -})); - -jest.mock('../../lib/track_legacy_route_usage', () => ({ - trackLegacyRouteUsage: jest.fn(), -})); - -const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); -const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - -beforeEach(() => { - jest.resetAllMocks(); -}); - -describe('deleteActionRoute', () => { - it('deletes an action with proper parameters', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - deleteActionRoute(router, licenseState); - - const [config, handler] = router.delete.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions/action/{id}"`); - - const actionsClient = actionsClientMock.create(); - actionsClient.delete.mockResolvedValueOnce({}); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { - id: '1', - }, - }, - ['noContent'] - ); - - expect(await handler(context, req, res)).toEqual(undefined); - - expect(actionsClient.delete).toHaveBeenCalledTimes(1); - expect(actionsClient.delete.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "id": "1", - }, - ] - `); - - expect(res.noContent).toHaveBeenCalled(); - }); - - it('ensures the license allows deleting actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - deleteActionRoute(router, licenseState); - - const [, handler] = router.delete.mock.calls[0]; - - const actionsClient = actionsClientMock.create(); - actionsClient.delete.mockResolvedValueOnce({}); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { id: '1' }, - } - ); - - await handler(context, req, res); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('ensures the license check prevents deleting actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - (verifyApiAccess as jest.Mock).mockImplementation(() => { - throw new Error('OMG'); - }); - - deleteActionRoute(router, licenseState); - - const [, handler] = router.delete.mock.calls[0]; - - const actionsClient = actionsClientMock.create(); - actionsClient.delete.mockResolvedValueOnce({}); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - id: '1', - } - ); - - await expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('should track every call', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - const actionsClient = actionsClientMock.create(); - - deleteActionRoute(router, licenseState, mockUsageCounter); - const [, handler] = router.delete.mock.calls[0]; - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { - id: '1', - }, - } - ); - await handler(context, req, res); - expect(trackLegacyRouteUsage).toHaveBeenCalledWith('delete', mockUsageCounter); - }); -}); diff --git a/x-pack/plugins/actions/server/routes/legacy/delete.ts b/x-pack/plugins/actions/server/routes/legacy/delete.ts deleted file mode 100644 index c7e1e985cc6f0..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/delete.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { IRouter } from '@kbn/core/server'; -import { ILicenseState, verifyApiAccess, isErrorThatHandlesItsOwnResponse } from '../../lib'; -import { BASE_ACTION_API_PATH } from '../../../common'; -import { ActionsRequestHandlerContext } from '../../types'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; - -const paramSchema = schema.object({ - id: schema.string({ - meta: { description: 'An identifier for the connector.' }, - }), -}); - -export const deleteActionRoute = ( - router: IRouter, - licenseState: ILicenseState, - usageCounter?: UsageCounter -) => { - router.delete( - { - path: `${BASE_ACTION_API_PATH}/action/{id}`, - options: { - access: 'public', - summary: `Delete a connector`, - description: 'WARNING: When you delete a connector, it cannot be recovered.', - tags: ['oas-tag:connectors'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - }, - validate: { - request: { - params: paramSchema, - }, - response: { - 204: { - description: 'Indicates a successful call.', - }, - }, - }, - }, - router.handleLegacyErrors(async function (context, req, res) { - verifyApiAccess(licenseState); - if (!context.actions) { - return res.badRequest({ body: 'RouteHandlerContext is not registered for actions' }); - } - const actionsClient = (await context.actions).getActionsClient(); - const { id } = req.params; - trackLegacyRouteUsage('delete', usageCounter); - try { - await actionsClient.delete({ id }); - return res.noContent(); - } catch (e) { - if (isErrorThatHandlesItsOwnResponse(e)) { - return e.sendResponse(res); - } - throw e; - } - }) - ); -}; diff --git a/x-pack/plugins/actions/server/routes/legacy/execute.test.ts b/x-pack/plugins/actions/server/routes/legacy/execute.test.ts deleted file mode 100644 index c989731407650..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/execute.test.ts +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { executeActionRoute } from './execute'; -import { httpServiceMock } from '@kbn/core/server/mocks'; -import { licenseStateMock } from '../../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { verifyApiAccess, ActionTypeDisabledError, asHttpRequestExecutionSource } from '../../lib'; -import { actionsClientMock } from '../../actions_client/actions_client.mock'; -import { ActionTypeExecutorResult } from '../../types'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; - -jest.mock('../../lib/verify_api_access', () => ({ - verifyApiAccess: jest.fn(), -})); - -jest.mock('../../lib/track_legacy_route_usage', () => ({ - trackLegacyRouteUsage: jest.fn(), -})); - -const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); -const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - -beforeEach(() => { - jest.resetAllMocks(); -}); - -describe('executeActionRoute', () => { - it('executes an action with proper parameters', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - const actionsClient = actionsClientMock.create(); - actionsClient.execute.mockResolvedValueOnce({ status: 'ok', actionId: '1' }); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - body: { - params: { - someData: 'data', - }, - }, - params: { - id: '1', - }, - }, - ['ok'] - ); - - const executeResult = { - actionId: '1', - status: 'ok', - }; - - executeActionRoute(router, licenseState); - - const [config, handler] = router.post.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions/action/{id}/_execute"`); - - expect(await handler(context, req, res)).toEqual({ body: executeResult }); - - expect(actionsClient.execute).toHaveBeenCalledWith({ - actionId: '1', - params: { - someData: 'data', - }, - source: asHttpRequestExecutionSource(req), - relatedSavedObjects: [], - }); - - expect(res.ok).toHaveBeenCalled(); - }); - - it('returns a "204 NO CONTENT" when the executor returns a nullish value', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - const actionsClient = actionsClientMock.create(); - actionsClient.execute.mockResolvedValueOnce(null as unknown as ActionTypeExecutorResult); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - body: { - params: {}, - }, - params: { - id: '1', - }, - }, - ['noContent'] - ); - - executeActionRoute(router, licenseState); - - const [, handler] = router.post.mock.calls[0]; - - expect(await handler(context, req, res)).toEqual(undefined); - - expect(actionsClient.execute).toHaveBeenCalledWith({ - actionId: '1', - params: {}, - source: asHttpRequestExecutionSource(req), - relatedSavedObjects: [], - }); - - expect(res.ok).not.toHaveBeenCalled(); - expect(res.noContent).toHaveBeenCalled(); - }); - - it('ensures the license allows action execution', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - const actionsClient = actionsClientMock.create(); - actionsClient.execute.mockResolvedValue({ - actionId: '1', - status: 'ok', - }); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - body: {}, - params: {}, - }, - ['ok'] - ); - - executeActionRoute(router, licenseState); - - const [, handler] = router.post.mock.calls[0]; - - await handler(context, req, res); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('ensures the license check prevents action execution', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - const actionsClient = actionsClientMock.create(); - actionsClient.execute.mockResolvedValue({ - actionId: '1', - status: 'ok', - }); - - (verifyApiAccess as jest.Mock).mockImplementation(() => { - throw new Error('OMG'); - }); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - body: {}, - params: {}, - }, - ['ok'] - ); - - executeActionRoute(router, licenseState); - - const [, handler] = router.post.mock.calls[0]; - - await expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('ensures the action type gets validated for the license', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - const actionsClient = actionsClientMock.create(); - actionsClient.execute.mockRejectedValue(new ActionTypeDisabledError('Fail', 'license_invalid')); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - body: {}, - params: {}, - }, - ['ok', 'forbidden'] - ); - - executeActionRoute(router, licenseState); - - const [, handler] = router.post.mock.calls[0]; - - await handler(context, req, res); - - expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); - }); - - it('should track every call', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - const actionsClient = actionsClientMock.create(); - - executeActionRoute(router, licenseState, mockUsageCounter); - const [, handler] = router.post.mock.calls[0]; - const [context, req, res] = mockHandlerArguments({ actionsClient }, { body: {}, params: {} }); - await handler(context, req, res); - expect(trackLegacyRouteUsage).toHaveBeenCalledWith('execute', mockUsageCounter); - }); -}); diff --git a/x-pack/plugins/actions/server/routes/legacy/execute.ts b/x-pack/plugins/actions/server/routes/legacy/execute.ts deleted file mode 100644 index 71b04262075d4..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/execute.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { IRouter } from '@kbn/core/server'; -import { ILicenseState, verifyApiAccess, isErrorThatHandlesItsOwnResponse } from '../../lib'; - -import { ActionTypeExecutorResult, ActionsRequestHandlerContext } from '../../types'; -import { BASE_ACTION_API_PATH } from '../../../common'; -import { asHttpRequestExecutionSource } from '../../lib/action_execution_source'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { connectorResponseSchemaV1 } from '../../../common/routes/connector/response'; - -const paramSchema = schema.object({ - id: schema.string({ - meta: { description: 'An identifier for the connector.' }, - }), -}); - -const bodySchema = schema.object({ - params: schema.recordOf(schema.string(), schema.any()), -}); - -export const executeActionRoute = ( - router: IRouter, - licenseState: ILicenseState, - usageCounter?: UsageCounter -) => { - router.post( - { - path: `${BASE_ACTION_API_PATH}/action/{id}/_execute`, - options: { - access: 'public', - summary: `Run a connector`, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - tags: ['oas-tag:connectors'], - }, - validate: { - request: { - body: bodySchema, - params: paramSchema, - }, - response: { - 200: { - description: 'Indicates a successful call.', - body: () => connectorResponseSchemaV1, - }, - }, - }, - }, - router.handleLegacyErrors(async function (context, req, res) { - verifyApiAccess(licenseState); - - if (!context.actions) { - return res.badRequest({ body: 'RouteHandlerContext is not registered for actions' }); - } - - const actionsClient = (await context.actions).getActionsClient(); - const { params } = req.body; - const { id } = req.params; - trackLegacyRouteUsage('execute', usageCounter); - try { - const body: ActionTypeExecutorResult = await actionsClient.execute({ - params, - actionId: id, - source: asHttpRequestExecutionSource(req), - relatedSavedObjects: [], - }); - return body - ? res.ok({ - body, - }) - : res.noContent(); - } catch (e) { - if (isErrorThatHandlesItsOwnResponse(e)) { - return e.sendResponse(res); - } - throw e; - } - }) - ); -}; diff --git a/x-pack/plugins/actions/server/routes/legacy/get.test.ts b/x-pack/plugins/actions/server/routes/legacy/get.test.ts deleted file mode 100644 index 732c964fb8284..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/get.test.ts +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getActionRoute } from './get'; -import { httpServiceMock } from '@kbn/core/server/mocks'; -import { licenseStateMock } from '../../lib/license_state.mock'; -import { verifyApiAccess } from '../../lib'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { actionsClientMock } from '../../actions_client/actions_client.mock'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; - -jest.mock('../../lib/verify_api_access', () => ({ - verifyApiAccess: jest.fn(), -})); - -jest.mock('../../lib/track_legacy_route_usage', () => ({ - trackLegacyRouteUsage: jest.fn(), -})); - -const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); -const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - -beforeEach(() => { - jest.resetAllMocks(); -}); - -describe('getActionRoute', () => { - it('gets an action with proper parameters', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - getActionRoute(router, licenseState); - - const [config, handler] = router.get.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions/action/{id}"`); - - const getResult = { - id: '1', - actionTypeId: '2', - name: 'action name', - config: {}, - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }; - - const actionsClient = actionsClientMock.create(); - actionsClient.get.mockResolvedValueOnce(getResult); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { id: '1' }, - }, - ['ok'] - ); - - expect(await handler(context, req, res)).toMatchInlineSnapshot(` - Object { - "body": Object { - "actionTypeId": "2", - "config": Object {}, - "id": "1", - "isDeprecated": false, - "isPreconfigured": false, - "isSystemAction": false, - "name": "action name", - }, - } - `); - - expect(actionsClient.get).toHaveBeenCalledTimes(1); - expect(actionsClient.get.mock.calls[0][0].id).toEqual('1'); - - expect(res.ok).toHaveBeenCalledWith({ - body: getResult, - }); - }); - - it('ensures the license allows getting actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - getActionRoute(router, licenseState); - - const [, handler] = router.get.mock.calls[0]; - - const actionsClient = actionsClientMock.create(); - actionsClient.get.mockResolvedValueOnce({ - id: '1', - actionTypeId: '2', - name: 'action name', - config: {}, - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { id: '1' }, - }, - ['ok'] - ); - - await handler(context, req, res); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('ensures the license check prevents getting actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - (verifyApiAccess as jest.Mock).mockImplementation(() => { - throw new Error('OMG'); - }); - - getActionRoute(router, licenseState); - - const [, handler] = router.get.mock.calls[0]; - - const actionsClient = actionsClientMock.create(); - actionsClient.get.mockResolvedValueOnce({ - id: '1', - actionTypeId: '2', - name: 'action name', - config: {}, - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { id: '1' }, - }, - ['ok'] - ); - - await expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('should track every call', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - const actionsClient = actionsClientMock.create(); - - getActionRoute(router, licenseState, mockUsageCounter); - const [, handler] = router.get.mock.calls[0]; - const [context, req, res] = mockHandlerArguments({ actionsClient }, { params: { id: '1' } }); - await handler(context, req, res); - expect(trackLegacyRouteUsage).toHaveBeenCalledWith('get', mockUsageCounter); - }); -}); diff --git a/x-pack/plugins/actions/server/routes/legacy/get.ts b/x-pack/plugins/actions/server/routes/legacy/get.ts deleted file mode 100644 index 571849ccaf478..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/get.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { IRouter } from '@kbn/core/server'; -import { ILicenseState, verifyApiAccess } from '../../lib'; -import { BASE_ACTION_API_PATH } from '../../../common'; -import { ActionsRequestHandlerContext } from '../../types'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { connectorResponseSchemaV1 } from '../../../common/routes/connector/response'; - -const paramSchema = schema.object({ - id: schema.string({ - meta: { description: 'An identifier for the connector.' }, - }), -}); - -export const getActionRoute = ( - router: IRouter, - licenseState: ILicenseState, - usageCounter?: UsageCounter -) => { - router.get( - { - path: `${BASE_ACTION_API_PATH}/action/{id}`, - options: { - access: 'public', - summary: `Get connector information`, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - tags: ['oas-tag:connectors'], - }, - validate: { - request: { - params: paramSchema, - }, - response: { - 200: { - description: 'Indicates a successful call.', - body: () => connectorResponseSchemaV1, - }, - }, - }, - }, - router.handleLegacyErrors(async function (context, req, res) { - verifyApiAccess(licenseState); - if (!context.actions) { - return res.badRequest({ body: 'RouteHandlerContext is not registered for actions' }); - } - const actionsClient = (await context.actions).getActionsClient(); - const { id } = req.params; - trackLegacyRouteUsage('get', usageCounter); - return res.ok({ - body: await actionsClient.get({ id }), - }); - }) - ); -}; diff --git a/x-pack/plugins/actions/server/routes/legacy/get_all.test.ts b/x-pack/plugins/actions/server/routes/legacy/get_all.test.ts deleted file mode 100644 index e8657e56259e1..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/get_all.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getAllActionRoute } from './get_all'; -import { httpServiceMock } from '@kbn/core/server/mocks'; -import { licenseStateMock } from '../../lib/license_state.mock'; -import { verifyApiAccess } from '../../lib'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { actionsClientMock } from '../../actions_client/actions_client.mock'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; - -jest.mock('../../lib/verify_api_access', () => ({ - verifyApiAccess: jest.fn(), -})); - -jest.mock('../../lib/track_legacy_route_usage', () => ({ - trackLegacyRouteUsage: jest.fn(), -})); - -const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); -const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - -beforeEach(() => { - jest.resetAllMocks(); -}); - -describe('getAllActionRoute', () => { - it('get all actions with proper parameters', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - getAllActionRoute(router, licenseState); - - const [config, handler] = router.get.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions"`); - - const actionsClient = actionsClientMock.create(); - actionsClient.getAll.mockResolvedValueOnce([]); - - const [context, req, res] = mockHandlerArguments({ actionsClient }, {}, ['ok']); - - expect(await handler(context, req, res)).toMatchInlineSnapshot(` - Object { - "body": Array [], - } - `); - - expect(actionsClient.getAll).toHaveBeenCalledTimes(1); - - expect(res.ok).toHaveBeenCalledWith({ - body: [], - }); - }); - - it('ensures the license allows getting all actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - getAllActionRoute(router, licenseState); - - const [config, handler] = router.get.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions"`); - - const actionsClient = actionsClientMock.create(); - actionsClient.getAll.mockResolvedValueOnce([]); - - const [context, req, res] = mockHandlerArguments({ actionsClient }, {}, ['ok']); - - await handler(context, req, res); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('ensures the license check prevents getting all actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - (verifyApiAccess as jest.Mock).mockImplementation(() => { - throw new Error('OMG'); - }); - - getAllActionRoute(router, licenseState); - - const [config, handler] = router.get.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions"`); - - const actionsClient = actionsClientMock.create(); - actionsClient.getAll.mockResolvedValueOnce([]); - - const [context, req, res] = mockHandlerArguments({ actionsClient }, {}, ['ok']); - - await expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('should track every call', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - const actionsClient = actionsClientMock.create(); - - getAllActionRoute(router, licenseState, mockUsageCounter); - const [, handler] = router.get.mock.calls[0]; - const [context, req, res] = mockHandlerArguments({ actionsClient }, {}); - await handler(context, req, res); - expect(trackLegacyRouteUsage).toHaveBeenCalledWith('getAll', mockUsageCounter); - }); -}); diff --git a/x-pack/plugins/actions/server/routes/legacy/get_all.ts b/x-pack/plugins/actions/server/routes/legacy/get_all.ts deleted file mode 100644 index f0a17acb96691..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/get_all.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IRouter } from '@kbn/core/server'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { ILicenseState, verifyApiAccess } from '../../lib'; -import { BASE_ACTION_API_PATH } from '../../../common'; -import { ActionsRequestHandlerContext } from '../../types'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; - -export const getAllActionRoute = ( - router: IRouter, - licenseState: ILicenseState, - usageCounter?: UsageCounter -) => { - router.get( - { - path: `${BASE_ACTION_API_PATH}`, - options: { - access: 'public', - summary: `Get all connectors`, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - tags: ['oas-tag:connectors'], - }, - validate: {}, - }, - router.handleLegacyErrors(async function (context, req, res) { - verifyApiAccess(licenseState); - if (!context.actions) { - return res.badRequest({ body: 'RouteHandlerContext is not registered for actions' }); - } - const actionsClient = (await context.actions).getActionsClient(); - const result = await actionsClient.getAll(); - trackLegacyRouteUsage('getAll', usageCounter); - return res.ok({ - body: result, - }); - }) - ); -}; diff --git a/x-pack/plugins/actions/server/routes/legacy/index.ts b/x-pack/plugins/actions/server/routes/legacy/index.ts deleted file mode 100644 index 37ed5efbd99b9..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IRouter } from '@kbn/core/server'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { ILicenseState } from '../../lib'; -import { ActionsRequestHandlerContext } from '../../types'; -import { createActionRoute } from './create'; -import { deleteActionRoute } from './delete'; -import { getAllActionRoute } from './get_all'; -import { getActionRoute } from './get'; -import { updateActionRoute } from './update'; -import { listActionTypesRoute } from './list_action_types'; -import { executeActionRoute } from './execute'; - -export function defineLegacyRoutes( - router: IRouter, - licenseState: ILicenseState, - usageCounter?: UsageCounter -) { - createActionRoute(router, licenseState, usageCounter); - deleteActionRoute(router, licenseState, usageCounter); - getActionRoute(router, licenseState, usageCounter); - getAllActionRoute(router, licenseState, usageCounter); - updateActionRoute(router, licenseState, usageCounter); - listActionTypesRoute(router, licenseState, usageCounter); - executeActionRoute(router, licenseState, usageCounter); -} diff --git a/x-pack/plugins/actions/server/routes/legacy/list_action_types.test.ts b/x-pack/plugins/actions/server/routes/legacy/list_action_types.test.ts deleted file mode 100644 index ec57c4b9a99a9..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/list_action_types.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { listActionTypesRoute } from './list_action_types'; -import { httpServiceMock } from '@kbn/core/server/mocks'; -import { licenseStateMock } from '../../lib/license_state.mock'; -import { verifyApiAccess } from '../../lib'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { LicenseType } from '@kbn/licensing-plugin/server'; -import { actionsClientMock } from '../../mocks'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; - -jest.mock('../../lib/verify_api_access', () => ({ - verifyApiAccess: jest.fn(), -})); - -jest.mock('../../lib/track_legacy_route_usage', () => ({ - trackLegacyRouteUsage: jest.fn(), -})); - -const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); -const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - -beforeEach(() => { - jest.resetAllMocks(); -}); - -describe('listActionTypesRoute', () => { - it('lists action types with proper parameters', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - listActionTypesRoute(router, licenseState); - - const [config, handler] = router.get.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions/list_action_types"`); - - const listTypes = [ - { - id: '1', - name: 'name', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'gold' as LicenseType, - supportedFeatureIds: ['alerting'], - isSystemActionType: false, - }, - ]; - - const actionsClient = actionsClientMock.create(); - actionsClient.listTypes.mockResolvedValueOnce(listTypes); - const [context, req, res] = mockHandlerArguments({ actionsClient }, {}, ['ok']); - - expect(await handler(context, req, res)).toMatchInlineSnapshot(` - Object { - "body": Array [ - Object { - "enabled": true, - "enabledInConfig": true, - "enabledInLicense": true, - "id": "1", - "isSystemActionType": false, - "minimumLicenseRequired": "gold", - "name": "name", - "supportedFeatureIds": Array [ - "alerting", - ], - }, - ], - } - `); - - expect(res.ok).toHaveBeenCalledWith({ - body: listTypes, - }); - }); - - it('ensures the license allows listing action types', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - listActionTypesRoute(router, licenseState); - - const [config, handler] = router.get.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions/list_action_types"`); - - const listTypes = [ - { - id: '1', - name: 'name', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'gold' as LicenseType, - supportedFeatureIds: ['alerting'], - isSystemActionType: false, - }, - ]; - - const actionsClient = actionsClientMock.create(); - actionsClient.listTypes.mockResolvedValueOnce(listTypes); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { id: '1' }, - }, - ['ok'] - ); - - await handler(context, req, res); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('ensures the license check prevents listing action types', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - (verifyApiAccess as jest.Mock).mockImplementation(() => { - throw new Error('OMG'); - }); - - listActionTypesRoute(router, licenseState); - - const [config, handler] = router.get.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions/list_action_types"`); - - const listTypes = [ - { - id: '1', - name: 'name', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'gold' as LicenseType, - supportedFeatureIds: ['alerting'], - isSystemActionType: false, - }, - ]; - - const actionsClient = actionsClientMock.create(); - actionsClient.listTypes.mockResolvedValueOnce(listTypes); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { id: '1' }, - }, - ['ok'] - ); - - await expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('should track every call', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - const actionsClient = actionsClientMock.create(); - - listActionTypesRoute(router, licenseState, mockUsageCounter); - const [, handler] = router.get.mock.calls[0]; - const [context, req, res] = mockHandlerArguments({ actionsClient }, {}); - await handler(context, req, res); - expect(trackLegacyRouteUsage).toHaveBeenCalledWith('listActionTypes', mockUsageCounter); - }); -}); diff --git a/x-pack/plugins/actions/server/routes/legacy/list_action_types.ts b/x-pack/plugins/actions/server/routes/legacy/list_action_types.ts deleted file mode 100644 index cc3e9c23f240d..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/list_action_types.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IRouter } from '@kbn/core/server'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { ILicenseState, verifyApiAccess } from '../../lib'; -import { BASE_ACTION_API_PATH } from '../../../common'; -import { ActionsRequestHandlerContext } from '../../types'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; - -/** - * Return all available action types - * expect system action types - */ -export const listActionTypesRoute = ( - router: IRouter, - licenseState: ILicenseState, - usageCounter?: UsageCounter -) => { - router.get( - { - path: `${BASE_ACTION_API_PATH}/list_action_types`, - options: { - access: 'public', - summary: `Get connector types`, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - tags: ['oas-tag:connectors'], - }, - validate: {}, - }, - router.handleLegacyErrors(async function (context, req, res) { - verifyApiAccess(licenseState); - if (!context.actions) { - return res.badRequest({ body: 'RouteHandlerContext is not registered for actions' }); - } - const actionsClient = (await context.actions).getActionsClient(); - trackLegacyRouteUsage('listActionTypes', usageCounter); - return res.ok({ - body: await actionsClient.listTypes(), - }); - }) - ); -}; diff --git a/x-pack/plugins/actions/server/routes/legacy/update.test.ts b/x-pack/plugins/actions/server/routes/legacy/update.test.ts deleted file mode 100644 index 493d1c873690e..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/update.test.ts +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { updateActionRoute } from './update'; -import { httpServiceMock } from '@kbn/core/server/mocks'; -import { licenseStateMock } from '../../lib/license_state.mock'; -import { verifyApiAccess, ActionTypeDisabledError } from '../../lib'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { actionsClientMock } from '../../actions_client/actions_client.mock'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; - -jest.mock('../../lib/verify_api_access', () => ({ - verifyApiAccess: jest.fn(), -})); - -jest.mock('../../lib/track_legacy_route_usage', () => ({ - trackLegacyRouteUsage: jest.fn(), -})); - -const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); -const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - -beforeEach(() => { - jest.resetAllMocks(); -}); - -describe('updateActionRoute', () => { - it('updates an action with proper parameters', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - updateActionRoute(router, licenseState); - - const [config, handler] = router.put.mock.calls[0]; - - expect(config.path).toMatchInlineSnapshot(`"/api/actions/action/{id}"`); - - const updateResult = { - id: '1', - actionTypeId: 'my-action-type-id', - name: 'My name', - config: { foo: true }, - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }; - - const actionsClient = actionsClientMock.create(); - actionsClient.update.mockResolvedValueOnce(updateResult); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { - id: '1', - }, - body: { - name: 'My name', - config: { foo: true }, - secrets: { key: 'i8oh34yf9783y39' }, - }, - }, - ['ok'] - ); - - expect(await handler(context, req, res)).toEqual({ body: updateResult }); - - expect(actionsClient.update).toHaveBeenCalledTimes(1); - expect(actionsClient.update.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "action": Object { - "config": Object { - "foo": true, - }, - "name": "My name", - "secrets": Object { - "key": "i8oh34yf9783y39", - }, - }, - "id": "1", - }, - ] - `); - - expect(res.ok).toHaveBeenCalled(); - }); - - it('ensures the license allows deleting actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - updateActionRoute(router, licenseState); - - const [, handler] = router.put.mock.calls[0]; - - const updateResult = { - id: '1', - actionTypeId: 'my-action-type-id', - name: 'My name', - config: { foo: true }, - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }; - - const actionsClient = actionsClientMock.create(); - actionsClient.update.mockResolvedValueOnce(updateResult); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { - id: '1', - }, - body: { - name: 'My name', - config: { foo: true }, - secrets: { key: 'i8oh34yf9783y39' }, - }, - }, - ['ok'] - ); - - await handler(context, req, res); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('ensures the license check prevents deleting actions', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - (verifyApiAccess as jest.Mock).mockImplementation(() => { - throw new Error('OMG'); - }); - - updateActionRoute(router, licenseState); - - const [, handler] = router.put.mock.calls[0]; - - const updateResult = { - id: '1', - actionTypeId: 'my-action-type-id', - name: 'My name', - config: { foo: true }, - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }; - - const actionsClient = actionsClientMock.create(); - actionsClient.update.mockResolvedValueOnce(updateResult); - - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { - params: { - id: '1', - }, - body: { - name: 'My name', - config: { foo: true }, - secrets: { key: 'i8oh34yf9783y39' }, - }, - }, - ['ok'] - ); - - await expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); - - expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - }); - - it('ensures the action type gets validated for the license', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - - updateActionRoute(router, licenseState); - - const [, handler] = router.put.mock.calls[0]; - - const actionsClient = actionsClientMock.create(); - actionsClient.update.mockRejectedValue(new ActionTypeDisabledError('Fail', 'license_invalid')); - - const [context, req, res] = mockHandlerArguments({ actionsClient }, { params: {}, body: {} }, [ - 'ok', - 'forbidden', - ]); - - await handler(context, req, res); - - expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); - }); - - it('should track every call', async () => { - const licenseState = licenseStateMock.create(); - const router = httpServiceMock.createRouter(); - const actionsClient = actionsClientMock.create(); - - updateActionRoute(router, licenseState, mockUsageCounter); - const [, handler] = router.put.mock.calls[0]; - const [context, req, res] = mockHandlerArguments( - { actionsClient }, - { params: { id: '1' }, body: {} } - ); - await handler(context, req, res); - expect(trackLegacyRouteUsage).toHaveBeenCalledWith('update', mockUsageCounter); - }); -}); diff --git a/x-pack/plugins/actions/server/routes/legacy/update.ts b/x-pack/plugins/actions/server/routes/legacy/update.ts deleted file mode 100644 index 0bf1ec7ece55d..0000000000000 --- a/x-pack/plugins/actions/server/routes/legacy/update.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { IRouter } from '@kbn/core/server'; -import { ILicenseState, verifyApiAccess, isErrorThatHandlesItsOwnResponse } from '../../lib'; -import { BASE_ACTION_API_PATH } from '../../../common'; -import { ActionsRequestHandlerContext } from '../../types'; -import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; -import { connectorResponseSchemaV1 } from '../../../common/routes/connector/response'; - -const paramSchema = schema.object({ - id: schema.string({ - meta: { description: 'An identifier for the connector.' }, - }), -}); - -const bodySchema = schema.object({ - name: schema.string(), - config: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), - secrets: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), -}); - -export const updateActionRoute = ( - router: IRouter, - licenseState: ILicenseState, - usageCounter?: UsageCounter -) => { - router.put( - { - path: `${BASE_ACTION_API_PATH}/action/{id}`, - options: { - access: 'public', - summary: `Update a connector`, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - tags: ['oas-tag:connectors'], - }, - validate: { - request: { - body: bodySchema, - params: paramSchema, - }, - response: { - 200: { - description: 'Indicates a successful call.', - body: () => connectorResponseSchemaV1, - }, - }, - }, - }, - router.handleLegacyErrors(async function (context, req, res) { - verifyApiAccess(licenseState); - if (!context.actions) { - return res.badRequest({ body: 'RouteHandlerContext is not registered for actions' }); - } - const actionsClient = (await context.actions).getActionsClient(); - const { id } = req.params; - const { name, config, secrets } = req.body; - trackLegacyRouteUsage('update', usageCounter); - - try { - return res.ok({ - body: await actionsClient.update({ - id, - action: { name, config, secrets }, - }), - }); - } catch (e) { - if (isErrorThatHandlesItsOwnResponse(e)) { - return e.sendResponse(res); - } - throw e; - } - }) - ); -}; diff --git a/x-pack/plugins/actions/server/routes/verify_access_and_context.test.ts b/x-pack/plugins/actions/server/routes/verify_access_and_context.test.ts index e079634fbfeff..7c1088e8c1d9e 100644 --- a/x-pack/plugins/actions/server/routes/verify_access_and_context.test.ts +++ b/x-pack/plugins/actions/server/routes/verify_access_and_context.test.ts @@ -7,7 +7,7 @@ import { licenseStateMock } from '../lib/license_state.mock'; import { verifyApiAccess, ActionTypeDisabledError } from '../lib'; -import { mockHandlerArguments } from './legacy/_mock_handler_arguments'; +import { mockHandlerArguments } from './_mock_handler_arguments'; import { actionsClientMock } from '../actions_client/actions_client.mock'; import { verifyAccessAndContext } from './verify_access_and_context'; diff --git a/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.test.ts b/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.test.ts new file mode 100644 index 0000000000000..77dec7f15e156 --- /dev/null +++ b/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.test.ts @@ -0,0 +1,394 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import fs from 'fs'; +import axios from 'axios'; +import { loggingSystemMock } from '@kbn/core/server/mocks'; +import { coreMock } from '@kbn/core/server/mocks'; +import { + TaskManagerSetupContract, + TaskManagerStartContract, + TaskStatus, +} from '@kbn/task-manager-plugin/server'; +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { + CONNECTOR_USAGE_REPORTING_SOURCE_ID, + CONNECTOR_USAGE_REPORTING_TASK_ID, + CONNECTOR_USAGE_REPORTING_TASK_SCHEDULE, + CONNECTOR_USAGE_REPORTING_TASK_TYPE, + ConnectorUsageReportingTask, +} from './connector_usage_reporting_task'; +import type { CoreSetup, ElasticsearchClient } from '@kbn/core/server'; +import { ActionsPluginsStart } from '../plugin'; +import { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; + +jest.mock('axios'); +const mockedAxiosPost = jest.spyOn(axios, 'post'); + +const nowStr = '2024-01-01T12:00:00.000Z'; +const nowDate = new Date(nowStr); + +jest.useFakeTimers(); +jest.setSystemTime(nowDate.getTime()); +const readFileSpy = jest.spyOn(fs, 'readFileSync'); + +describe('ConnectorUsageReportingTask', () => { + const logger = loggingSystemMock.createLogger(); + const { createSetup } = coreMock; + const { createSetup: taskManagerSetupMock, createStart: taskManagerStartMock } = taskManagerMock; + let mockEsClient: jest.Mocked; + let mockCore: CoreSetup; + let mockTaskManagerSetup: jest.Mocked; + let mockTaskManagerStart: jest.Mocked; + + beforeEach(async () => { + mockTaskManagerSetup = taskManagerSetupMock(); + mockTaskManagerStart = taskManagerStartMock(); + mockCore = createSetup(); + mockEsClient = (await mockCore.getStartServices())[0].elasticsearch.client + .asInternalUser as jest.Mocked; + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + const createTaskRunner = async ({ + lastReportedUsageDate, + projectId, + attempts = 0, + }: { + lastReportedUsageDate: Date; + projectId?: string; + attempts?: number; + }) => { + const timestamp = new Date(new Date().setMinutes(-15)); + const task = new ConnectorUsageReportingTask({ + eventLogIndex: 'test-index', + projectId, + logger, + core: mockCore, + taskManager: mockTaskManagerSetup, + config: { + url: 'usage-api', + ca: { + path: './ca.crt', + }, + }, + }); + + await task.start(mockTaskManagerStart); + + const createTaskRunnerFunction = + mockTaskManagerSetup.registerTaskDefinitions.mock.calls[0][0][ + CONNECTOR_USAGE_REPORTING_TASK_TYPE + ].createTaskRunner; + + return createTaskRunnerFunction({ + taskInstance: { + id: CONNECTOR_USAGE_REPORTING_TASK_ID, + runAt: timestamp, + attempts: 0, + ownerId: '', + status: TaskStatus.Running, + startedAt: timestamp, + scheduledAt: timestamp, + retryAt: null, + params: {}, + state: { + lastReportedUsageDate, + attempts, + }, + taskType: CONNECTOR_USAGE_REPORTING_TASK_TYPE, + }, + }); + }; + + it('registers the task', async () => { + readFileSpy.mockImplementationOnce(() => '---CA CERTIFICATE---'); + new ConnectorUsageReportingTask({ + eventLogIndex: 'test-index', + projectId: 'test-projecr', + logger, + core: createSetup(), + taskManager: mockTaskManagerSetup, + config: { + url: 'usage-api', + ca: { + path: './ca.crt', + }, + }, + }); + + expect(mockTaskManagerSetup.registerTaskDefinitions).toBeCalledTimes(1); + expect(mockTaskManagerSetup.registerTaskDefinitions).toHaveBeenCalledWith({ + [CONNECTOR_USAGE_REPORTING_TASK_TYPE]: { + title: 'Connector usage reporting task', + timeout: '1m', + createTaskRunner: expect.any(Function), + }, + }); + }); + + it('schedules the task', async () => { + readFileSpy.mockImplementationOnce(() => '---CA CERTIFICATE---'); + const core = createSetup(); + const taskManagerStart = taskManagerStartMock(); + + const task = new ConnectorUsageReportingTask({ + eventLogIndex: 'test-index', + projectId: 'test-projecr', + logger, + core, + taskManager: mockTaskManagerSetup, + config: { + url: 'usage-api', + ca: { + path: './ca.crt', + }, + }, + }); + + await task.start(taskManagerStart); + + expect(taskManagerStart.ensureScheduled).toBeCalledTimes(1); + expect(taskManagerStart.ensureScheduled).toHaveBeenCalledWith({ + id: CONNECTOR_USAGE_REPORTING_TASK_ID, + taskType: CONNECTOR_USAGE_REPORTING_TASK_TYPE, + schedule: { + ...CONNECTOR_USAGE_REPORTING_TASK_SCHEDULE, + }, + state: {}, + params: {}, + }); + }); + + it('logs error if task manager is not ready', async () => { + readFileSpy.mockImplementationOnce(() => '---CA CERTIFICATE---'); + const core = createSetup(); + const taskManagerStart = taskManagerStartMock(); + + const task = new ConnectorUsageReportingTask({ + eventLogIndex: 'test-index', + projectId: 'test-projecr', + logger, + core, + taskManager: mockTaskManagerSetup, + config: { + url: 'usage-api', + ca: { + path: './ca.crt', + }, + }, + }); + + await task.start(); + + expect(taskManagerStart.ensureScheduled).not.toBeCalled(); + expect(logger.error).toHaveBeenCalledWith( + `Missing required task manager service during start of ${CONNECTOR_USAGE_REPORTING_TASK_TYPE}` + ); + }); + + it('logs error if scheduling task fails', async () => { + readFileSpy.mockImplementationOnce(() => '---CA CERTIFICATE---'); + const core = createSetup(); + const taskManagerStart = taskManagerStartMock(); + taskManagerStart.ensureScheduled.mockRejectedValue(new Error('test')); + + const task = new ConnectorUsageReportingTask({ + eventLogIndex: 'test-index', + projectId: 'test-projecr', + logger, + core, + taskManager: mockTaskManagerSetup, + config: { + url: 'usage-api', + ca: { + path: './ca.crt', + }, + }, + }); + + await task.start(taskManagerStart); + + expect(logger.error).toHaveBeenCalledWith( + 'Error scheduling task actions:connector_usage_reporting, received test' + ); + }); + + it('returns the existing state and logs a warning when project id is missing', async () => { + const lastReportedUsageDateStr = '2024-01-01T00:00:00.000Z'; + const lastReportedUsageDate = new Date(lastReportedUsageDateStr); + + const taskRunner = await createTaskRunner({ lastReportedUsageDate }); + + const response = await taskRunner.run(); + + expect(logger.warn).toHaveBeenCalledWith( + 'Missing required project id while running actions:connector_usage_reporting' + ); + + expect(response).toEqual({ + state: { + attempts: 0, + lastReportedUsageDate, + }, + }); + }); + + it('returns the existing state and logs an error when the CA Certificate is missing', async () => { + const lastReportedUsageDateStr = '2024-01-01T00:00:00.000Z'; + const lastReportedUsageDate = new Date(lastReportedUsageDateStr); + readFileSpy.mockImplementationOnce((func) => { + throw new Error('Mock file read error.'); + }); + + const taskRunner = await createTaskRunner({ lastReportedUsageDate, projectId: 'test-id' }); + + const response = await taskRunner.run(); + + expect(logger.error).toHaveBeenCalledTimes(2); + + expect(logger.error).toHaveBeenNthCalledWith( + 1, + `CA Certificate for the project "test-id" couldn't be loaded, Error: Mock file read error.` + ); + + expect(logger.error).toHaveBeenNthCalledWith( + 2, + 'Missing required CA Certificate while running actions:connector_usage_reporting' + ); + + expect(response).toEqual({ + state: { + attempts: 0, + lastReportedUsageDate, + }, + }); + }); + + it('runs the task', async () => { + readFileSpy.mockImplementationOnce(() => '---CA CERTIFICATE---'); + mockEsClient.search.mockResolvedValueOnce({ + aggregations: { total_usage: 215 }, + } as SearchResponse); + + mockedAxiosPost.mockResolvedValueOnce(200); + + const lastReportedUsageDateStr = '2024-01-01T00:00:00.000Z'; + const lastReportedUsageDate = new Date(lastReportedUsageDateStr); + + const taskRunner = await createTaskRunner({ lastReportedUsageDate, projectId: 'test-project' }); + + const response = await taskRunner.run(); + + const report = [ + { + creation_timestamp: nowStr, + id: 'connector-request-body-bytes-test-project-2024-01-01T12:00:00.000Z', + source: { + id: CONNECTOR_USAGE_REPORTING_SOURCE_ID, + instance_group_id: 'test-project', + }, + usage: { + period_seconds: 43200, + quantity: 0, + type: 'connector_request_body_bytes', + }, + usage_timestamp: nowStr, + }, + ]; + + expect(mockedAxiosPost).toHaveBeenCalledWith('usage-api', report, { + headers: { 'Content-Type': 'application/json' }, + timeout: 30000, + httpsAgent: expect.any(Object), + }); + + expect(response).toEqual({ + state: { + attempts: 0, + lastReportedUsageDate: expect.any(Date), + }, + }); + }); + + it('re-runs the task when search for records fails', async () => { + readFileSpy.mockImplementationOnce(() => '---CA CERTIFICATE---'); + mockEsClient.search.mockRejectedValue(new Error('500')); + + mockedAxiosPost.mockResolvedValueOnce(200); + + const lastReportedUsageDate = new Date('2024-01-01T00:00:00.000Z'); + + const taskRunner = await createTaskRunner({ lastReportedUsageDate, projectId: 'test-project' }); + + const response = await taskRunner.run(); + + expect(response).toEqual({ + state: { + lastReportedUsageDate, + attempts: 0, + }, + runAt: nowDate, + }); + }); + + it('re-runs the task when it fails to push the usage record', async () => { + readFileSpy.mockImplementationOnce(() => '---CA CERTIFICATE---'); + mockEsClient.search.mockResolvedValueOnce({ + aggregations: { total_usage: 215 }, + } as SearchResponse); + + mockedAxiosPost.mockRejectedValueOnce(500); + + const lastReportedUsageDate = new Date('2024-01-01T00:00:00.000Z'); + + const taskRunner = await createTaskRunner({ lastReportedUsageDate, projectId: 'test-project' }); + + const response = await taskRunner.run(); + + expect(response).toEqual({ + state: { + lastReportedUsageDate, + attempts: 1, + }, + runAt: new Date(nowDate.getTime() + 60000), // After a min + }); + }); + + it('stops retrying after 5 attempts', async () => { + readFileSpy.mockImplementationOnce(() => '---CA CERTIFICATE---'); + mockEsClient.search.mockResolvedValueOnce({ + aggregations: { total_usage: 215 }, + } as SearchResponse); + + mockedAxiosPost.mockRejectedValueOnce(new Error('test-error')); + + const lastReportedUsageDate = new Date('2024-01-01T00:00:00.000Z'); + + const taskRunner = await createTaskRunner({ + lastReportedUsageDate, + projectId: 'test-project', + attempts: 4, + }); + + const response = await taskRunner.run(); + + expect(response).toEqual({ + state: { + lastReportedUsageDate, + attempts: 0, + }, + }); + + expect(logger.error).toHaveBeenCalledWith( + 'Usage data could not be pushed to usage-api. Stopped retrying after 5 attempts. Error:test-error' + ); + }); +}); diff --git a/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.ts b/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.ts new file mode 100644 index 0000000000000..ce44718749006 --- /dev/null +++ b/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.ts @@ -0,0 +1,309 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import fs from 'fs'; +import { Logger, CoreSetup, type ElasticsearchClient } from '@kbn/core/server'; +import { + IntervalSchedule, + type ConcreteTaskInstance, + TaskManagerStartContract, + TaskManagerSetupContract, +} from '@kbn/task-manager-plugin/server'; +import { AggregationsSumAggregate } from '@elastic/elasticsearch/lib/api/types'; +import axios from 'axios'; +import https from 'https'; +import { ActionsConfig } from '../config'; +import { ConnectorUsageReport } from './types'; +import { ActionsPluginsStart } from '../plugin'; + +export const CONNECTOR_USAGE_REPORTING_TASK_SCHEDULE: IntervalSchedule = { interval: '1h' }; +export const CONNECTOR_USAGE_REPORTING_TASK_ID = 'connector_usage_reporting'; +export const CONNECTOR_USAGE_REPORTING_TASK_TYPE = `actions:${CONNECTOR_USAGE_REPORTING_TASK_ID}`; +export const CONNECTOR_USAGE_REPORTING_TASK_TIMEOUT = 30000; +export const CONNECTOR_USAGE_TYPE = `connector_request_body_bytes`; +export const CONNECTOR_USAGE_REPORTING_SOURCE_ID = `task-connector-usage-report`; +export const MAX_PUSH_ATTEMPTS = 5; + +export class ConnectorUsageReportingTask { + private readonly logger: Logger; + private readonly eventLogIndex: string; + private readonly projectId: string | undefined; + private readonly caCertificate: string | undefined; + private readonly usageApiUrl: string; + + constructor({ + logger, + eventLogIndex, + core, + taskManager, + projectId, + config, + }: { + logger: Logger; + eventLogIndex: string; + core: CoreSetup; + taskManager: TaskManagerSetupContract; + projectId: string | undefined; + config: ActionsConfig['usage']; + }) { + this.logger = logger; + this.projectId = projectId; + this.eventLogIndex = eventLogIndex; + this.usageApiUrl = config.url; + const caCertificatePath = config.ca?.path; + + if (caCertificatePath && caCertificatePath.length > 0) { + try { + this.caCertificate = fs.readFileSync(caCertificatePath, 'utf8'); + } catch (e) { + this.caCertificate = undefined; + this.logger.error( + `CA Certificate for the project "${projectId}" couldn't be loaded, Error: ${e.message}` + ); + } + } + + taskManager.registerTaskDefinitions({ + [CONNECTOR_USAGE_REPORTING_TASK_TYPE]: { + title: 'Connector usage reporting task', + timeout: '1m', + createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { + return { + run: async () => this.runTask(taskInstance, core), + cancel: async () => {}, + }; + }, + }, + }); + } + + public start = async (taskManager?: TaskManagerStartContract) => { + if (!taskManager) { + this.logger.error( + `Missing required task manager service during start of ${CONNECTOR_USAGE_REPORTING_TASK_TYPE}` + ); + return; + } + + try { + await taskManager.ensureScheduled({ + id: CONNECTOR_USAGE_REPORTING_TASK_ID, + taskType: CONNECTOR_USAGE_REPORTING_TASK_TYPE, + schedule: { + ...CONNECTOR_USAGE_REPORTING_TASK_SCHEDULE, + }, + state: {}, + params: {}, + }); + } catch (e) { + this.logger.error( + `Error scheduling task ${CONNECTOR_USAGE_REPORTING_TASK_TYPE}, received ${e.message}` + ); + } + }; + + private runTask = async (taskInstance: ConcreteTaskInstance, core: CoreSetup) => { + const { state } = taskInstance; + + if (!this.projectId) { + this.logger.warn( + `Missing required project id while running ${CONNECTOR_USAGE_REPORTING_TASK_TYPE}` + ); + return { + state, + }; + } + + if (!this.caCertificate) { + this.logger.error( + `Missing required CA Certificate while running ${CONNECTOR_USAGE_REPORTING_TASK_TYPE}` + ); + return { + state, + }; + } + + const [{ elasticsearch }] = await core.getStartServices(); + const esClient = elasticsearch.client.asInternalUser; + + const now = new Date(); + const oneDayAgo = new Date(new Date().getTime() - 24 * 60 * 60 * 1000); + const lastReportedUsageDate: Date = !!state.lastReportedUsageDate + ? new Date(state.lastReportedUsageDate) + : oneDayAgo; + + let attempts: number = state.attempts || 0; + + const fromDate = lastReportedUsageDate; + const toDate = now; + + let totalUsage = 0; + try { + totalUsage = await this.getTotalUsage({ + esClient, + fromDate, + toDate, + }); + } catch (e) { + this.logger.error(`Usage data could not be fetched. It will be retried. Error:${e.message}`); + return { + state: { + lastReportedUsageDate, + attempts, + }, + runAt: now, + }; + } + + const record: ConnectorUsageReport = this.createUsageRecord({ + totalUsage, + fromDate, + toDate, + projectId: this.projectId, + }); + + this.logger.debug(`Record: ${JSON.stringify(record)}`); + + try { + attempts = attempts + 1; + await this.pushUsageRecord(record); + this.logger.info( + `Connector usage record has been successfully reported, ${record.creation_timestamp}, usage: ${record.usage.quantity}, period:${record.usage.period_seconds}` + ); + } catch (e) { + if (attempts < MAX_PUSH_ATTEMPTS) { + this.logger.error( + `Usage data could not be pushed to usage-api. It will be retried (${attempts}). Error:${e.message}` + ); + + return { + state: { + lastReportedUsageDate, + attempts, + }, + runAt: this.getDelayedRetryDate({ attempts, now }), + }; + } + this.logger.error( + `Usage data could not be pushed to usage-api. Stopped retrying after ${attempts} attempts. Error:${e.message}` + ); + return { + state: { + lastReportedUsageDate, + attempts: 0, + }, + }; + } + + return { + state: { lastReportedUsageDate: toDate, attempts: 0 }, + }; + }; + + private getTotalUsage = async ({ + esClient, + fromDate, + toDate, + }: { + esClient: ElasticsearchClient; + fromDate: Date; + toDate: Date; + }): Promise => { + const usageResult = await esClient.search({ + index: this.eventLogIndex, + sort: '@timestamp', + size: 0, + query: { + bool: { + filter: { + bool: { + must: [ + { + term: { 'event.action': 'execute' }, + }, + { + term: { 'event.provider': 'actions' }, + }, + { + exists: { + field: 'kibana.action.execution.usage.request_body_bytes', + }, + }, + { + range: { + '@timestamp': { + gt: fromDate, + lte: toDate, + }, + }, + }, + ], + }, + }, + }, + }, + aggs: { + total_usage: { sum: { field: 'kibana.action.execution.usage.request_body_bytes' } }, + }, + }); + + return (usageResult.aggregations?.total_usage as AggregationsSumAggregate)?.value ?? 0; + }; + + private createUsageRecord = ({ + totalUsage, + fromDate, + toDate, + projectId, + }: { + totalUsage: number; + fromDate: Date; + toDate: Date; + projectId: string; + }): ConnectorUsageReport => { + const period = Math.round((toDate.getTime() - fromDate.getTime()) / 1000); + const toStr = toDate.toISOString(); + const timestamp = new Date(toStr); + timestamp.setMinutes(0); + timestamp.setSeconds(0); + timestamp.setMilliseconds(0); + + return { + id: `connector-request-body-bytes-${projectId}-${timestamp.toISOString()}`, + usage_timestamp: toStr, + creation_timestamp: toStr, + usage: { + type: CONNECTOR_USAGE_TYPE, + period_seconds: period, + quantity: totalUsage, + }, + source: { + id: CONNECTOR_USAGE_REPORTING_SOURCE_ID, + instance_group_id: projectId, + }, + }; + }; + + private pushUsageRecord = async (record: ConnectorUsageReport) => { + return axios.post(this.usageApiUrl, [record], { + headers: { 'Content-Type': 'application/json' }, + timeout: CONNECTOR_USAGE_REPORTING_TASK_TIMEOUT, + httpsAgent: new https.Agent({ + ca: this.caCertificate, + }), + }); + }; + + private getDelayedRetryDate = ({ attempts, now }: { attempts: number; now: Date }) => { + const baseDelay = 60 * 1000; + const delayByAttempts = baseDelay * attempts; + + const delayedTime = now.getTime() + delayByAttempts; + + return new Date(delayedTime); + }; +} diff --git a/x-pack/plugins/actions/server/usage/types.ts b/x-pack/plugins/actions/server/usage/types.ts index 6bdfe316c76e2..d57de6f4dad33 100644 --- a/x-pack/plugins/actions/server/usage/types.ts +++ b/x-pack/plugins/actions/server/usage/types.ts @@ -65,3 +65,18 @@ export const byServiceProviderTypeSchema: MakeSchemaFrom['count_ac other: { type: 'long' }, ses: { type: 'long' }, }; + +export interface ConnectorUsageReport { + id: string; + usage_timestamp: string; + creation_timestamp: string; + usage: { + type: string; + period_seconds: number; + quantity: number | string | undefined; + }; + source: { + id: string | undefined; + instance_group_id: string; + }; +} diff --git a/x-pack/plugins/actions/tsconfig.json b/x-pack/plugins/actions/tsconfig.json index d060287d24143..384aba6a6b014 100644 --- a/x-pack/plugins/actions/tsconfig.json +++ b/x-pack/plugins/actions/tsconfig.json @@ -47,7 +47,8 @@ "@kbn/core-http-server", "@kbn/core-test-helpers-kbn-server", "@kbn/security-plugin-types-server", - "@kbn/core-application-common" + "@kbn/core-application-common", + "@kbn/cloud-plugin" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/index.ts b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/index.ts index c3e30072e7348..8715e176f9935 100644 --- a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/index.ts +++ b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/index.ts @@ -5,6 +5,20 @@ * 2.0. */ -export type { FindMaintenanceWindowsResponse } from './types/latest'; +export { + findMaintenanceWindowsRequestQuerySchema, + findMaintenanceWindowsResponseBodySchema, +} from './schemas/latest'; +export type { + FindMaintenanceWindowsRequestQuery, + FindMaintenanceWindowsResponse, +} from './types/latest'; -export type { FindMaintenanceWindowsResponse as FindMaintenanceWindowsResponseV1 } from './types/v1'; +export { + findMaintenanceWindowsRequestQuerySchema as findMaintenanceWindowsRequestQuerySchemaV1, + findMaintenanceWindowsResponseBodySchema as findMaintenanceWindowsResponseBodySchemaV1, +} from './schemas/v1'; +export type { + FindMaintenanceWindowsRequestQuery as FindMaintenanceWindowsRequestQueryV1, + FindMaintenanceWindowsResponse as FindMaintenanceWindowsResponseV1, +} from './types/v1'; diff --git a/x-pack/plugins/observability_solution/apm/common/entities/types.ts b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/schemas/latest.ts similarity index 72% rename from x-pack/plugins/observability_solution/apm/common/entities/types.ts rename to x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/schemas/latest.ts index 9775b1e32eae6..25300c97a6d2e 100644 --- a/x-pack/plugins/observability_solution/apm/common/entities/types.ts +++ b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/schemas/latest.ts @@ -5,8 +5,4 @@ * 2.0. */ -export enum EntityDataStreamType { - METRICS = 'metrics', - TRACES = 'traces', - LOGS = 'logs', -} +export * from './v1'; diff --git a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/schemas/v1.ts new file mode 100644 index 0000000000000..7c4dffdd1d94c --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/schemas/v1.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { maintenanceWindowResponseSchemaV1 } from '../../../response'; + +const MAX_DOCS = 10000; + +export const findMaintenanceWindowsRequestQuerySchema = schema.object( + { + // we do not need to use schema.maybe here, because if we do not pass property page, defaultValue will be used + page: schema.number({ + defaultValue: 1, + min: 1, + max: MAX_DOCS, + meta: { + description: 'The page number to return.', + }, + }), + // we do not need to use schema.maybe here, because if we do not pass property per_page, defaultValue will be used + per_page: schema.number({ + defaultValue: 1000, + min: 0, + max: 100, + meta: { + description: 'The number of maintenance windows to return per page.', + }, + }), + }, + { + validate: (params) => { + const pageAsNumber = params.page ?? 0; + const perPageAsNumber = params.per_page ?? 0; + + if (Math.max(pageAsNumber, pageAsNumber * perPageAsNumber) > MAX_DOCS) { + return `The number of documents is too high. Paginating through more than ${MAX_DOCS} documents is not possible.`; + } + }, + } +); + +export const findMaintenanceWindowsResponseBodySchema = schema.object({ + page: schema.number(), + per_page: schema.number(), + total: schema.number(), + data: schema.arrayOf(maintenanceWindowResponseSchemaV1), +}); diff --git a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/types/latest.ts b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/types/latest.ts index 4741df5c6c6c1..25300c97a6d2e 100644 --- a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/types/latest.ts +++ b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/types/latest.ts @@ -5,4 +5,4 @@ * 2.0. */ -export type { FindMaintenanceWindowsResponse } from './v1'; +export * from './v1'; diff --git a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/types/v1.ts b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/types/v1.ts index 0bdff90d3419f..0176d2e6689f8 100644 --- a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/types/v1.ts +++ b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/find/types/v1.ts @@ -5,11 +5,15 @@ * 2.0. */ -import { MaintenanceWindowResponseV1 } from '../../../response'; +import { TypeOf } from '@kbn/config-schema'; +import { + findMaintenanceWindowsResponseBodySchema, + findMaintenanceWindowsRequestQuerySchema, +} from '..'; -export interface FindMaintenanceWindowsResponse { - body: { - data: MaintenanceWindowResponseV1[]; - total: number; - }; -} +export type FindMaintenanceWindowsResponse = TypeOf< + typeof findMaintenanceWindowsResponseBodySchema +>; +export type FindMaintenanceWindowsRequestQuery = TypeOf< + typeof findMaintenanceWindowsRequestQuerySchema +>; diff --git a/x-pack/plugins/alerting/common/routes/maintenance_window/response/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/maintenance_window/response/schemas/v1.ts index 648b2b806978f..a9237e6be4ecc 100644 --- a/x-pack/plugins/alerting/common/routes/maintenance_window/response/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/maintenance_window/response/schemas/v1.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { maintenanceWindowStatusV1 } from '..'; +import { maintenanceWindowStatus as maintenanceWindowStatusV1 } from '../constants/v1'; import { maintenanceWindowCategoryIdsSchemaV1 } from '../../shared'; import { rRuleResponseSchemaV1 } from '../../../r_rule'; import { alertsFilterQuerySchemaV1 } from '../../../alerts_filter_query'; diff --git a/x-pack/plugins/alerting/common/routes/r_rule/response/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/r_rule/response/schemas/v1.ts index c9dec9d8cf1e6..463619a3cdb0e 100644 --- a/x-pack/plugins/alerting/common/routes/r_rule/response/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/r_rule/response/schemas/v1.ts @@ -78,86 +78,104 @@ export const rRuleResponseSchema = schema.object({ ) ), byweekday: schema.maybe( - schema.arrayOf( - schema.oneOf([schema.string(), schema.number()], { - meta: { - description: - 'Indicates the days of the week to recur or else nth-day-of-month strings. For example, "+2TU" second Tuesday of month, "-1FR" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination.', - }, - }) + schema.nullable( + schema.arrayOf( + schema.oneOf([schema.string(), schema.number()], { + meta: { + description: + 'Indicates the days of the week to recur or else nth-day-of-month strings. For example, "+2TU" second Tuesday of month, "-1FR" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination.', + }, + }) + ) ) ), bymonth: schema.maybe( - schema.arrayOf( - schema.number({ - meta: { - description: 'Indicates months of the year that this rule should recur.', - }, - }) + schema.nullable( + schema.arrayOf( + schema.number({ + meta: { + description: 'Indicates months of the year that this rule should recur.', + }, + }) + ) ) ), bysetpos: schema.maybe( - schema.arrayOf( - schema.number({ - meta: { - description: - 'A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.', - }, - }) + schema.nullable( + schema.arrayOf( + schema.number({ + meta: { + description: + 'A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.', + }, + }) + ) ) ), bymonthday: schema.maybe( - schema.arrayOf( - schema.number({ - meta: { - description: 'Indicates the days of the month to recur.', - }, - }) + schema.nullable( + schema.arrayOf( + schema.number({ + meta: { + description: 'Indicates the days of the month to recur.', + }, + }) + ) ) ), byyearday: schema.maybe( - schema.arrayOf( - schema.number({ - meta: { - description: 'Indicates the days of the year that this rule should recur.', - }, - }) + schema.nullable( + schema.arrayOf( + schema.number({ + meta: { + description: 'Indicates the days of the year that this rule should recur.', + }, + }) + ) ) ), byweekno: schema.maybe( - schema.arrayOf( - schema.number({ - meta: { - description: 'Indicates number of the week hours to recur.', - }, - }) + schema.nullable( + schema.arrayOf( + schema.number({ + meta: { + description: 'Indicates number of the week hours to recur.', + }, + }) + ) ) ), byhour: schema.maybe( - schema.arrayOf( - schema.number({ - meta: { - description: 'Indicates hours of the day to recur.', - }, - }) + schema.nullable( + schema.arrayOf( + schema.number({ + meta: { + description: 'Indicates hours of the day to recur.', + }, + }) + ) ) ), byminute: schema.maybe( - schema.arrayOf( - schema.number({ - meta: { - description: 'Indicates minutes of the hour to recur.', - }, - }) + schema.nullable( + schema.arrayOf( + schema.number({ + meta: { + description: 'Indicates minutes of the hour to recur.', + }, + }) + ) ) ), bysecond: schema.maybe( - schema.arrayOf( - schema.number({ - meta: { - description: 'Indicates seconds of the day to recur.', - }, - }) + schema.nullable( + schema.arrayOf( + schema.number({ + meta: { + description: 'Indicates seconds of the day to recur.', + }, + }) + ) ) ), }); diff --git a/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts index 069aca001d14f..6226a17d51025 100644 --- a/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts @@ -224,20 +224,21 @@ export const ruleExecutionStatusSchema = schema.object({ ), }); +export const outcome = schema.oneOf( + [ + schema.literal(ruleLastRunOutcomeValuesV1.SUCCEEDED), + schema.literal(ruleLastRunOutcomeValuesV1.WARNING), + schema.literal(ruleLastRunOutcomeValuesV1.FAILED), + ], + { + meta: { + description: 'Outcome of last run of the rule. Value could be succeeded, warning or failed.', + }, + } +); + export const ruleLastRunSchema = schema.object({ - outcome: schema.oneOf( - [ - schema.literal(ruleLastRunOutcomeValuesV1.SUCCEEDED), - schema.literal(ruleLastRunOutcomeValuesV1.WARNING), - schema.literal(ruleLastRunOutcomeValuesV1.FAILED), - ], - { - meta: { - description: - 'Outcome of last run of the rule. Value could be succeeded, warning or failed.', - }, - } - ), + outcome, outcome_order: schema.maybe( schema.number({ meta: { @@ -334,7 +335,7 @@ export const monitoringSchema = schema.object( duration: schema.maybe( schema.number({ meta: { description: 'Duration of the rule run.' } }) ), - outcome: schema.maybe(ruleLastRunSchema), + outcome: schema.maybe(outcome), }), { meta: { description: 'History of the rule run.' } } ), diff --git a/x-pack/plugins/alerting/public/services/maintenance_windows_api/find.ts b/x-pack/plugins/alerting/public/services/maintenance_windows_api/find.ts index c63e491198ce9..822fb6e2bae1f 100644 --- a/x-pack/plugins/alerting/public/services/maintenance_windows_api/find.ts +++ b/x-pack/plugins/alerting/public/services/maintenance_windows_api/find.ts @@ -16,7 +16,7 @@ export async function findMaintenanceWindows({ }: { http: HttpSetup; }): Promise { - const res = await http.get( + const res = await http.get( `${INTERNAL_BASE_ALERTING_API_PATH}/rules/maintenance_window/_find` ); return res.data.map((mw) => transformMaintenanceWindowResponse(mw)); diff --git a/x-pack/plugins/alerting/public/services/maintenance_windows_api/transform_maintenance_window_response.ts b/x-pack/plugins/alerting/public/services/maintenance_windows_api/transform_maintenance_window_response.ts index 329c2febf3b15..a7887e684140d 100644 --- a/x-pack/plugins/alerting/public/services/maintenance_windows_api/transform_maintenance_window_response.ts +++ b/x-pack/plugins/alerting/public/services/maintenance_windows_api/transform_maintenance_window_response.ts @@ -17,7 +17,6 @@ export const transformMaintenanceWindowResponse = ( duration: response.duration, expirationDate: response.expiration_date, events: response.events, - // @ts-expect-error upgrade typescript v5.1.6 rRule: response.r_rule, ...(response.category_ids !== undefined ? { categoryIds: response.category_ids } : {}), ...(response.scoped_query !== undefined ? { scopedQuery: response.scoped_query } : {}), diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/get_summarized_alerts_query.ts b/x-pack/plugins/alerting/server/alerts_client/lib/get_summarized_alerts_query.ts index 4f0aa0fb003df..ab3edece0becc 100644 --- a/x-pack/plugins/alerting/server/alerts_client/lib/get_summarized_alerts_query.ts +++ b/x-pack/plugins/alerting/server/alerts_client/lib/get_summarized_alerts_query.ts @@ -39,6 +39,7 @@ import { import { SummarizedAlertsChunk, ScopedQueryAlerts } from '../..'; import { FormatAlert } from '../../types'; import { expandFlattenedAlert } from './format_alert'; +import { injectAnalyzeWildcard } from './inject_analyze_wildcard'; const MAX_ALERT_DOCS_TO_RETURN = 100; enum AlertTypes { @@ -310,9 +311,14 @@ export const getQueryByScopedQueries = ({ return; } - const scopedQueryFilter = generateAlertsFilterDSL({ - query: scopedQuery as AlertsFilter['query'], - })[0] as { bool: BoolQuery }; + const scopedQueryFilter = generateAlertsFilterDSL( + { + query: scopedQuery as AlertsFilter['query'], + }, + { + analyzeWildcard: true, + } + )[0] as { bool: BoolQuery }; aggs[id] = { filter: { @@ -324,6 +330,7 @@ export const getQueryByScopedQueries = ({ aggs: { alertId: { top_hits: { + size: MAX_ALERT_DOCS_TO_RETURN, _source: { includes: [ALERT_UUID], }, @@ -340,11 +347,19 @@ export const getQueryByScopedQueries = ({ }; }; -const generateAlertsFilterDSL = (alertsFilter: AlertsFilter): QueryDslQueryContainer[] => { +const generateAlertsFilterDSL = ( + alertsFilter: AlertsFilter, + options?: { analyzeWildcard?: boolean } +): QueryDslQueryContainer[] => { const filter: QueryDslQueryContainer[] = []; + const { analyzeWildcard = false } = options || {}; if (alertsFilter.query) { - filter.push(JSON.parse(alertsFilter.query.dsl!)); + const parsedQuery = JSON.parse(alertsFilter.query.dsl!); + if (analyzeWildcard) { + injectAnalyzeWildcard(parsedQuery); + } + filter.push(parsedQuery); } if (alertsFilter.timeframe) { filter.push( diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/inject_analyze_wildcard.test.ts b/x-pack/plugins/alerting/server/alerts_client/lib/inject_analyze_wildcard.test.ts new file mode 100644 index 0000000000000..1e1db14d928ba --- /dev/null +++ b/x-pack/plugins/alerting/server/alerts_client/lib/inject_analyze_wildcard.test.ts @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { injectAnalyzeWildcard } from './inject_analyze_wildcard'; + +const getQuery = (query?: string) => { + return { + bool: { + must: [], + filter: [ + { + bool: { + filter: [ + { + bool: { + should: [ + { + query_string: { + fields: ['kibana.alert.instance.id'], + query: query || '*elastic*', + }, + }, + ], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + match: { + 'kibana.alert.action_group': 'test', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + ], + should: [], + must_not: [ + { + match_phrase: { + _id: 'assdasdasd', + }, + }, + ], + }, + }; +}; +describe('injectAnalyzeWildcard', () => { + test('should inject analyze_wildcard field', () => { + const query = getQuery(); + injectAnalyzeWildcard(query); + expect(query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "query_string": Object { + "analyze_wildcard": true, + "fields": Array [ + "kibana.alert.instance.id", + ], + "query": "*elastic*", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.action_group": "test", + }, + }, + ], + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [ + Object { + "match_phrase": Object { + "_id": "assdasdasd", + }, + }, + ], + "should": Array [], + }, + } + `); + }); + + test('should not inject analyze_wildcard if the query does not contain *', () => { + const query = getQuery('test'); + injectAnalyzeWildcard(query); + expect(query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "query_string": Object { + "fields": Array [ + "kibana.alert.instance.id", + ], + "query": "test", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.action_group": "test", + }, + }, + ], + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [ + Object { + "match_phrase": Object { + "_id": "assdasdasd", + }, + }, + ], + "should": Array [], + }, + } + `); + }); +}); diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/inject_analyze_wildcard.ts b/x-pack/plugins/alerting/server/alerts_client/lib/inject_analyze_wildcard.ts new file mode 100644 index 0000000000000..58a4f89948973 --- /dev/null +++ b/x-pack/plugins/alerting/server/alerts_client/lib/inject_analyze_wildcard.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +export const injectAnalyzeWildcard = (query: QueryDslQueryContainer): void => { + if (!query) { + return; + } + + if (Array.isArray(query)) { + return query.forEach((child) => injectAnalyzeWildcard(child)); + } + + if (typeof query === 'object') { + Object.entries(query).forEach(([key, value]) => { + if (key !== 'query_string') { + return injectAnalyzeWildcard(value); + } + + if (typeof value.query === 'string' && value.query.includes('*')) { + value.analyze_wildcard = true; + } + }); + } +}; diff --git a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts index d755463e9bc3e..534262aa31c31 100644 --- a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts +++ b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts @@ -10,7 +10,6 @@ import Boom from '@hapi/boom'; import { KueryNode, nodeBuilder } from '@kbn/es-query'; import { SavedObjectsFindResult } from '@kbn/core/server'; import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; -import { RuleAttributes } from '../../../../data/rule/types'; import { findRulesSo } from '../../../../data/rule'; import { alertingAuthorizationFilterOpts, @@ -27,6 +26,7 @@ import type { } from './types'; import { scheduleBackfillParamsSchema } from './schemas'; import { transformRuleAttributesToRuleDomain } from '../../../rule/transforms'; +import { RawRule } from '../../../../types'; export async function scheduleBackfill( context: RulesClientContext, @@ -116,7 +116,7 @@ export async function scheduleBackfill( ); const rulesFinder = - await context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( + await context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( { filter: kueryNodeFilterWithAuth, type: RULE_SAVED_OBJECT_TYPE, @@ -125,7 +125,7 @@ export async function scheduleBackfill( } ); - let rulesToSchedule: Array> = []; + let rulesToSchedule: Array> = []; for await (const response of rulesFinder.find()) { for (const rule of response.saved_objects) { context.auditLogger?.log( @@ -150,7 +150,7 @@ export async function scheduleBackfill( rules: rulesToSchedule.map(({ id, attributes, references }) => { const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId!); return transformRuleAttributesToRuleDomain( - attributes as RuleAttributes, + attributes, { id, logger: context.logger, diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/archive/archive_maintenance_window.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/archive/archive_maintenance_window.ts index 466167df6b8d7..461f88288ced3 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/archive/archive_maintenance_window.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/archive/archive_maintenance_window.ts @@ -69,7 +69,6 @@ async function archiveWithOCC( const events = mergeEvents({ newEvents: generateMaintenanceWindowEvents({ - // @ts-expect-error upgrade typescript v5.1.6 rRule: attributes.rRule, duration: attributes.duration, expirationDate, diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/find_maintenance_windows.test.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/find_maintenance_windows.test.ts index 8d06b335892b9..35c15ebb57c61 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/find_maintenance_windows.test.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/find_maintenance_windows.test.ts @@ -17,6 +17,7 @@ import { MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE, } from '../../../../../common'; import { getMockMaintenanceWindow } from '../../../../data/maintenance_window/test_helpers'; +import { findMaintenanceWindowsParamsSchema } from './schemas'; const savedObjectsClient = savedObjectsClientMock.create(); const uiSettings = uiSettingsServiceMock.createClient(); @@ -37,8 +38,47 @@ describe('MaintenanceWindowClient - find', () => { jest.useRealTimers(); }); + it('throws an error if page is string', async () => { + savedObjectsClient.find.mockResolvedValueOnce({ + saved_objects: [ + { + attributes: getMockMaintenanceWindow({ expirationDate: new Date().toISOString() }), + id: 'test-1', + }, + { + attributes: getMockMaintenanceWindow({ expirationDate: new Date().toISOString() }), + id: 'test-2', + }, + ], + page: 1, + per_page: 5, + } as unknown as SavedObjectsFindResponse); + + await expect( + // @ts-expect-error: testing validation of strings + findMaintenanceWindows(mockContext, { page: 'dfsd', perPage: 10 }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + '"Error validating find maintenance windows data - [page]: expected value of type [number] but got [string]"' + ); + }); + + it('throws an error if savedObjectsClient.find will throw an error', async () => { + jest.useFakeTimers().setSystemTime(new Date('2023-02-26T00:00:00.000Z')); + + savedObjectsClient.find.mockImplementation(() => { + throw new Error('something went wrong!'); + }); + + await expect( + findMaintenanceWindows(mockContext, { page: 1, perPage: 10 }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + '"Failed to find maintenance window, Error: Error: something went wrong!: something went wrong!"' + ); + }); + it('should find maintenance windows', async () => { jest.useFakeTimers().setSystemTime(new Date('2023-02-26T00:00:00.000Z')); + const spy = jest.spyOn(findMaintenanceWindowsParamsSchema, 'validate'); savedObjectsClient.find.mockResolvedValueOnce({ saved_objects: [ @@ -51,10 +91,13 @@ describe('MaintenanceWindowClient - find', () => { id: 'test-2', }, ], + page: 1, + per_page: 5, } as unknown as SavedObjectsFindResponse); - const result = await findMaintenanceWindows(mockContext); + const result = await findMaintenanceWindows(mockContext, {}); + expect(spy).toHaveBeenCalledWith({}); expect(savedObjectsClient.find).toHaveBeenLastCalledWith({ type: MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE, }); @@ -62,5 +105,7 @@ describe('MaintenanceWindowClient - find', () => { expect(result.data.length).toEqual(2); expect(result.data[0].id).toEqual('test-1'); expect(result.data[1].id).toEqual('test-2'); + expect(result.page).toEqual(1); + expect(result.perPage).toEqual(5); }); }); diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/find_maintenance_windows.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/find_maintenance_windows.ts index fe0f279ea4073..5cb1e01c1f1a0 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/find_maintenance_windows.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/find_maintenance_windows.ts @@ -9,17 +9,35 @@ import Boom from '@hapi/boom'; import { MaintenanceWindowClientContext } from '../../../../../common'; import { transformMaintenanceWindowAttributesToMaintenanceWindow } from '../../transforms'; import { findMaintenanceWindowSo } from '../../../../data/maintenance_window'; -import type { FindMaintenanceWindowsResult } from './types'; +import type { FindMaintenanceWindowsResult, FindMaintenanceWindowsParams } from './types'; +import { findMaintenanceWindowsParamsSchema } from './schemas'; export async function findMaintenanceWindows( - context: MaintenanceWindowClientContext + context: MaintenanceWindowClientContext, + params?: FindMaintenanceWindowsParams ): Promise { const { savedObjectsClient, logger } = context; try { - const result = await findMaintenanceWindowSo({ savedObjectsClient }); + if (params) { + findMaintenanceWindowsParamsSchema.validate(params); + } + } catch (error) { + throw Boom.badRequest(`Error validating find maintenance windows data - ${error.message}`); + } + + try { + const result = await findMaintenanceWindowSo({ + savedObjectsClient, + ...(params + ? { savedObjectsFindOptions: { page: params.page, perPage: params.perPage } } + : {}), + }); return { + page: result.page, + perPage: result.per_page, + total: result.total, data: result.saved_objects.map((so) => transformMaintenanceWindowAttributesToMaintenanceWindow({ attributes: so.attributes, diff --git a/x-pack/plugins/inference/common/output/is_output_update_event.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/find_maintenance_window_params_schema.ts similarity index 51% rename from x-pack/plugins/inference/common/output/is_output_update_event.ts rename to x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/find_maintenance_window_params_schema.ts index 459436e64014e..e874882450c26 100644 --- a/x-pack/plugins/inference/common/output/is_output_update_event.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/find_maintenance_window_params_schema.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { OutputEvent, OutputEventType, OutputUpdateEvent } from '.'; +import { schema } from '@kbn/config-schema'; -export function isOutputUpdateEvent( - event: OutputEvent -): event is OutputUpdateEvent { - return event.type === OutputEventType.OutputComplete; -} +export const findMaintenanceWindowsParamsSchema = schema.object({ + perPage: schema.maybe(schema.number()), + page: schema.maybe(schema.number()), +}); diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/find_maintenance_windows_result_schema.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/find_maintenance_windows_result_schema.ts index 1bdc2f00219ae..49b03325faa33 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/find_maintenance_windows_result_schema.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/find_maintenance_windows_result_schema.ts @@ -9,5 +9,8 @@ import { schema } from '@kbn/config-schema'; import { maintenanceWindowSchema } from '../../../schemas'; export const findMaintenanceWindowsResultSchema = schema.object({ + page: schema.number(), + perPage: schema.number(), data: schema.arrayOf(maintenanceWindowSchema), + total: schema.number(), }); diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/index.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/index.ts index 4b2f087c95505..4e6c55b08955f 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/index.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/schemas/index.ts @@ -6,3 +6,4 @@ */ export { findMaintenanceWindowsResultSchema } from './find_maintenance_windows_result_schema'; +export { findMaintenanceWindowsParamsSchema } from './find_maintenance_window_params_schema'; diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/types/find_maintenance_window_params.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/types/find_maintenance_window_params.ts new file mode 100644 index 0000000000000..878d5168c7e55 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/types/find_maintenance_window_params.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TypeOf } from '@kbn/config-schema'; +import { findMaintenanceWindowsParamsSchema } from '../schemas'; + +export type FindMaintenanceWindowsParams = TypeOf; diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/types/index.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/types/index.ts index a5f00973bb82e..97472fc231ab6 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/types/index.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/find/types/index.ts @@ -6,3 +6,4 @@ */ export type { FindMaintenanceWindowsResult } from './find_maintenance_window_result'; +export type { FindMaintenanceWindowsParams } from './find_maintenance_window_params'; diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/finish/finish_maintenance_window.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/finish/finish_maintenance_window.ts index b6de6dea7cb76..e318971993542 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/finish/finish_maintenance_window.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/finish/finish_maintenance_window.ts @@ -74,7 +74,6 @@ async function finishWithOCC( // Generate new events with new expiration date const newEvents = generateMaintenanceWindowEvents({ - // @ts-expect-error upgrade typescript v5.1.6 rRule: maintenanceWindow.rRule, duration: maintenanceWindow.duration, expirationDate: expirationDate.toISOString(), diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.test.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.test.ts index 6797b4f57d508..e377fb3209d63 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.test.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.test.ts @@ -135,6 +135,21 @@ describe('MaintenanceWindowClient - update', () => { eventEndTime: '2023-03-05T01:00:00.000Z', }) ); + + expect(uiSettings.get).toHaveBeenCalledTimes(3); + expect(uiSettings.get.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "query:allowLeadingWildcards", + ], + Array [ + "query:queryString:options", + ], + Array [ + "courier:ignoreFilterIfFieldNotInIndex", + ], + ] + `); }); it('should not regenerate all events if rrule and duration did not change', async () => { diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.ts index afff024b186c2..6c8fd65b6988f 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.ts @@ -10,6 +10,7 @@ import Boom from '@hapi/boom'; import { buildEsQuery, Filter } from '@kbn/es-query'; import type { MaintenanceWindowClientContext } from '../../../../../common'; import { getScopedQueryErrorMessage } from '../../../../../common'; +import { getEsQueryConfig } from '../../../../lib/get_es_query_config'; import type { MaintenanceWindow } from '../../types'; import { generateMaintenanceWindowEvents, @@ -45,9 +46,10 @@ async function updateWithOCC( context: MaintenanceWindowClientContext, params: UpdateMaintenanceWindowParams ): Promise { - const { savedObjectsClient, getModificationMetadata, logger } = context; + const { savedObjectsClient, getModificationMetadata, logger, uiSettings } = context; const { id, data } = params; const { title, enabled, duration, rRule, categoryIds, scopedQuery } = data; + const esQueryConfig = await getEsQueryConfig(uiSettings); try { updateMaintenanceWindowParamsSchema.validate(params); @@ -62,7 +64,8 @@ async function updateWithOCC( buildEsQuery( undefined, [{ query: scopedQuery.kql, language: 'kuery' }], - scopedQuery.filters as Filter[] + scopedQuery.filters as Filter[], + esQueryConfig ) ); scopedQueryWithGeneratedValue = { @@ -98,7 +101,6 @@ async function updateWithOCC( const modificationMetadata = await getModificationMetadata(); let events = generateMaintenanceWindowEvents({ - // @ts-expect-error upgrade typescript v5.1.6 rRule: rRule || maintenanceWindow.rRule, duration: typeof duration === 'number' ? duration : maintenanceWindow.duration, expirationDate, diff --git a/x-pack/plugins/alerting/server/application/r_rule/schemas/r_rule_schema.ts b/x-pack/plugins/alerting/server/application/r_rule/schemas/r_rule_schema.ts index 5325c571f5d3e..51f2b055bb822 100644 --- a/x-pack/plugins/alerting/server/application/r_rule/schemas/r_rule_schema.ts +++ b/x-pack/plugins/alerting/server/application/r_rule/schemas/r_rule_schema.ts @@ -34,13 +34,15 @@ export const rRuleSchema = schema.object({ schema.literal('SU'), ]) ), - byweekday: schema.maybe(schema.arrayOf(schema.oneOf([schema.string(), schema.number()]))), - bymonth: schema.maybe(schema.arrayOf(schema.number())), - bysetpos: schema.maybe(schema.arrayOf(schema.number())), - bymonthday: schema.maybe(schema.arrayOf(schema.number())), - byyearday: schema.maybe(schema.arrayOf(schema.number())), - byweekno: schema.maybe(schema.arrayOf(schema.number())), - byhour: schema.maybe(schema.arrayOf(schema.number())), - byminute: schema.maybe(schema.arrayOf(schema.number())), - bysecond: schema.maybe(schema.arrayOf(schema.number())), + byweekday: schema.maybe( + schema.nullable(schema.arrayOf(schema.oneOf([schema.string(), schema.number()]))) + ), + bymonth: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), + bysetpos: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), + bymonthday: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), + byyearday: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), + byweekno: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), + byhour: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), + byminute: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), + bysecond: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.ts index d2d5b47a893f3..0c1fa9a3fe1e9 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.ts @@ -31,7 +31,6 @@ import type { BulkDeleteRulesRequestBody, } from './types'; import { validateBulkDeleteRulesBody } from './validation'; -import type { RuleAttributes } from '../../../../data/rule/types'; import { bulkDeleteRulesSo } from '../../../../data/rule'; import { transformRuleAttributesToRuleDomain, transformRuleDomainToRule } from '../../transforms'; import { ruleDomainSchema } from '../../schemas'; @@ -103,7 +102,7 @@ export const bulkDeleteRules = async ( // when we are doing the bulk delete and this should fix itself const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId!); const ruleDomain = transformRuleAttributesToRuleDomain( - attributes as RuleAttributes, + attributes as RawRule, { id, logger: context.logger, @@ -144,17 +143,15 @@ const bulkDeleteWithOCC = async ( type: 'rules', }, () => - context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( - { - filter, - type: RULE_SAVED_OBJECT_TYPE, - perPage: 100, - ...(context.namespace ? { namespaces: [context.namespace] } : undefined), - } - ) + context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser({ + filter, + type: RULE_SAVED_OBJECT_TYPE, + perPage: 100, + ...(context.namespace ? { namespaces: [context.namespace] } : undefined), + }) ); - const rulesToDelete: Array> = []; + const rulesToDelete: Array> = []; const apiKeyToRuleIdMapping: Record = {}; const taskIdToRuleIdMapping: Record = {}; const ruleNameToRuleIdMapping: Record = {}; @@ -194,7 +191,7 @@ const bulkDeleteWithOCC = async ( ); for (const { id, attributes } of rulesToDelete) { - await untrackRuleAlerts(context, id, attributes as RuleAttributes); + await untrackRuleAlerts(context, id, attributes as RawRule); } const result = await withSpan( diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.ts index 11f1d43b02b42..1e56be531b0ca 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.ts @@ -33,7 +33,6 @@ import type { BulkDisableRulesResult, BulkDisableRulesRequestBody, } from './types'; -import type { RuleAttributes } from '../../../../data/rule/types'; import { validateBulkDisableRulesBody } from './validation'; import { ruleDomainSchema } from '../../schemas'; import type { RulesClientContext } from '../../../../rules_client/types'; @@ -96,7 +95,7 @@ export const bulkDisableRules = async ( // when we are doing the bulk disable and this should fix itself const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId!); const ruleDomain = transformRuleAttributesToRuleDomain( - attributes as RuleAttributes, + attributes as RawRule, { id, logger: context.logger, @@ -139,17 +138,15 @@ const bulkDisableRulesWithOCC = async ( type: 'rules', }, () => - context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( - { - filter, - type: RULE_SAVED_OBJECT_TYPE, - perPage: 100, - ...(context.namespace ? { namespaces: [context.namespace] } : undefined), - } - ) + context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser({ + filter, + type: RULE_SAVED_OBJECT_TYPE, + perPage: 100, + ...(context.namespace ? { namespaces: [context.namespace] } : undefined), + }) ); - const rulesToDisable: Array> = []; + const rulesToDisable: Array> = []; const errors: BulkOperationError[] = []; const ruleNameToRuleIdMapping: Record = {}; const username = await context.getUserName(); @@ -204,7 +201,7 @@ const bulkDisableRulesWithOCC = async ( // TODO (http-versioning) Remove casts when updateMeta has been converted attributes: { ...updatedAttributes, - } as RuleAttributes, + } as RawRule, ...(migratedActions.hasLegacyActions ? { references: migratedActions.resultedReferences } : {}), @@ -252,9 +249,7 @@ const bulkDisableRulesWithOCC = async ( () => bulkDisableRulesSo({ savedObjectsClient: context.unsecuredSavedObjectsClient, - bulkDisableRuleAttributes: rulesToDisable as Array< - SavedObjectsBulkCreateObject - >, + bulkDisableRuleAttributes: rulesToDisable as Array>, savedObjectsBulkCreateOptions: { overwrite: true }, }) ); @@ -262,7 +257,7 @@ const bulkDisableRulesWithOCC = async ( const taskIdsToDisable: string[] = []; const taskIdsToDelete: string[] = []; const taskIdsToClearState: string[] = []; - const disabledRules: Array> = []; + const disabledRules: Array> = []; result.saved_objects.forEach((rule) => { if (rule.error === undefined) { @@ -294,8 +289,7 @@ const bulkDisableRulesWithOCC = async ( return { errors, - // TODO: delete the casting when we do versioning of bulk disable api - rules: disabledRules as Array>, + rules: disabledRules, accListSpecificForBulkOperation: [taskIdsToDisable, taskIdsToDelete, taskIdsToClearState], }; }; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts index c7c795359aaee..61d38c2c37c19 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts @@ -37,11 +37,11 @@ import { migrateLegacyActions } from '../../../../rules_client/lib'; import { migrateLegacyActionsMock } from '../../../../rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock'; import { ConnectorAdapterRegistry } from '../../../../connector_adapters/connector_adapter_registry'; import { ConnectorAdapter } from '../../../../connector_adapters/types'; -import { RuleAttributes } from '../../../../data/rule/types'; import { SavedObject } from '@kbn/core/server'; import { bulkEditOperationsSchema } from './schemas'; import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { backfillClientMock } from '../../../../backfill_client/backfill_client.mock'; +import { RawRule } from '../../../../types'; jest.mock('../../../../rules_client/lib/siem_legacy_actions/migrate_legacy_actions', () => { return { @@ -1175,7 +1175,7 @@ describe('bulkEdit()', () => { }); const rule = unsecuredSavedObjectsClient.bulkCreate.mock.calls[0][0] as Array< - SavedObject + SavedObject >; expect(rule[0].attributes.actions).toEqual([ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts index a9a060b99664d..8868065fa43a5 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts @@ -74,7 +74,6 @@ import { ruleNotifyWhen } from '../../constants'; import { actionRequestSchema, ruleDomainSchema, systemActionRequestSchema } from '../../schemas'; import { RuleParams, RuleDomain, RuleSnoozeSchedule } from '../../types'; import { findRulesSo, bulkCreateRulesSo } from '../../../../data/rule'; -import { RuleAttributes, RuleActionAttributes } from '../../../../data/rule/types'; import { transformRuleAttributesToRuleDomain, transformRuleDomainToRuleAttributes, @@ -98,7 +97,7 @@ type ApiKeysMap = Map< } >; -type ApiKeyAttributes = Pick; +type ApiKeyAttributes = Pick; type RuleType = ReturnType; @@ -236,7 +235,7 @@ export async function bulkEditRules( // when we are doing the bulk create and this should fix itself const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId!); const ruleDomain = transformRuleAttributesToRuleDomain( - attributes as RuleAttributes, + attributes as RawRule, { id, logger: context.logger, @@ -279,13 +278,13 @@ async function bulkEditRulesOcc( } ): Promise<{ apiKeysToInvalidate: string[]; - rules: Array>; - resultSavedObjects: Array>; + rules: Array>; + resultSavedObjects: Array>; errors: BulkOperationError[]; skipped: BulkActionSkipResult[]; }> { const rulesFinder = - await context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( + await context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( { filter, type: RULE_SAVED_OBJECT_TYPE, @@ -294,7 +293,7 @@ async function bulkEditRulesOcc( } ); - const rules: Array> = []; + const rules: Array> = []; const skipped: BulkActionSkipResult[] = []; const errors: BulkOperationError[] = []; const apiKeysMap: ApiKeysMap = new Map(); @@ -311,7 +310,7 @@ async function bulkEditRulesOcc( await pMap( response.saved_objects, - async (rule: SavedObjectsFindResult) => + async (rule: SavedObjectsFindResult) => updateRuleAttributesAndParamsInMemory({ context, rule, @@ -436,11 +435,11 @@ async function updateRuleAttributesAndParamsInMemory( shouldIncrementRevision = () => true, }: { context: RulesClientContext; - rule: SavedObjectsFindResult; + rule: SavedObjectsFindResult; operations: BulkEditOperation[]; paramsModifier?: ParamsModifier; apiKeysMap: ApiKeysMap; - rules: Array>; + rules: Array>; skipped: BulkActionSkipResult[]; errors: BulkOperationError[]; username: string | null; @@ -556,7 +555,7 @@ async function updateRuleAttributesAndParamsInMemory( rule: updatedRule, params: { legacyId: rule.attributes.legacyId, - paramsWithRefs: updatedParams as RuleAttributes['params'], + paramsWithRefs: updatedParams, }, }); @@ -605,7 +604,7 @@ async function updateRuleAttributesAndParamsInMemory( async function ensureAuthorizationForBulkUpdate( context: RulesClientContext, operations: BulkEditOperation[], - rule: SavedObjectsFindResult + rule: SavedObjectsFindResult ): Promise { if (rule.attributes.actions.length === 0) { return; @@ -859,10 +858,10 @@ function validateScheduleOperation( async function prepareApiKeys( context: RulesClientContext, - rule: SavedObjectsFindResult, + rule: SavedObjectsFindResult, ruleType: RuleType, apiKeysMap: ApiKeysMap, - attributes: RuleAttributes, + attributes: RawRule, hasUpdateApiKeyOperation: boolean, username: string | null ): Promise<{ apiKeyAttributes: ApiKeyAttributes }> { @@ -890,13 +889,13 @@ async function prepareApiKeys( function updateAttributes( context: RulesClientContext, - attributes: RuleAttributes, + attributes: RawRule, apiKeyAttributes: ApiKeyAttributes, updatedParams: RuleParams, - rawAlertActions: RuleActionAttributes[], + rawAlertActions: RawRuleAction[], username: string | null ): { - updatedAttributes: RuleAttributes; + updatedAttributes: RawRule; } { // get notifyWhen const notifyWhen = getRuleNotifyWhenType( @@ -905,16 +904,16 @@ function updateAttributes( ); // TODO (http-versioning) Remove casts when updateMeta has been converted - const castedAttributes = attributes as RawRule; + const castedAttributes = attributes; const updatedAttributes = updateMeta(context, { ...castedAttributes, ...apiKeyAttributes, - params: updatedParams as RawRule['params'], - actions: rawAlertActions as RawRule['actions'], + params: updatedParams, + actions: rawAlertActions, notifyWhen, updatedBy: username, updatedAt: new Date().toISOString(), - }) as RuleAttributes; + }); // add mapped_params const mappedParams = getMappedParams(updatedParams); @@ -934,7 +933,7 @@ async function saveBulkUpdatedRules({ apiKeysMap, }: { context: RulesClientContext; - rules: Array>; + rules: Array>; apiKeysMap: ApiKeysMap; }) { const apiKeysToInvalidate: string[] = []; @@ -945,7 +944,7 @@ async function saveBulkUpdatedRules({ // bulk_disable, bulk_enable, etc. to fix this cast result = await bulkCreateRulesSo({ savedObjectsClient: context.unsecuredSavedObjectsClient, - bulkCreateRuleAttributes: rules as Array>, + bulkCreateRuleAttributes: rules as Array>, savedObjectsBulkCreateOptions: { overwrite: true }, }); } catch (e) { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_enable/bulk_enable_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_enable/bulk_enable_rules.ts index ff1852d8a4d4d..ac7510c2a5a9c 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_enable/bulk_enable_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_enable/bulk_enable_rules.ts @@ -18,7 +18,7 @@ import { Logger } from '@kbn/core/server'; import { TaskManagerStartContract, TaskStatus } from '@kbn/task-manager-plugin/server'; import { TaskInstanceWithDeprecatedFields } from '@kbn/task-manager-plugin/server/task'; import { bulkCreateRulesSo } from '../../../../data/rule'; -import { RawRule, RawRuleAction } from '../../../../types'; +import { RawRule } from '../../../../types'; import { RuleDomain, RuleParams } from '../../types'; import { convertRuleIdsToKueryNode } from '../../../../lib'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; @@ -37,7 +37,6 @@ import { } from '../../../../rules_client/lib'; import { RulesClientContext, BulkOperationError } from '../../../../rules_client/types'; import { validateScheduleLimit } from '../get_schedule_frequency'; -import { RuleAttributes } from '../../../../data/rule/types'; import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { BulkEnableRulesParams, BulkEnableRulesResult } from './types'; import { bulkEnableRulesParamsSchema } from './schemas'; @@ -122,7 +121,7 @@ export const bulkEnableRules = async ( // when we are doing the bulk delete and this should fix itself const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId!); const ruleDomain: RuleDomain = transformRuleAttributesToRuleDomain( - attributes as RuleAttributes, + attributes as RawRule, { id, logger: context.logger, @@ -159,7 +158,7 @@ const bulkEnableRulesWithOCC = async ( type: 'rules', }, async () => - await context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( + await context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( { filter, type: RULE_SAVED_OBJECT_TYPE, @@ -169,8 +168,8 @@ const bulkEnableRulesWithOCC = async ( ) ); - const rulesFinderRules: Array> = []; - const rulesToEnable: Array> = []; + const rulesFinderRules: Array> = []; + const rulesToEnable: Array> = []; const tasksToSchedule: TaskInstanceWithDeprecatedFields[] = []; const errors: BulkOperationError[] = []; const ruleNameToRuleIdMapping: Record = {}; @@ -221,12 +220,11 @@ const bulkEnableRulesWithOCC = async ( ruleNameToRuleIdMapping[rule.id] = ruleName; } - // TODO (http-versioning) Remove RawRuleAction and RawRule casts const migratedActions = await migrateLegacyActions(context, { ruleId: rule.id, - actions: rule.attributes.actions as RawRuleAction[], + actions: rule.attributes.actions, references: rule.references, - attributes: rule.attributes as RawRule, + attributes: rule.attributes, }); const updatedAttributes = updateMetaAttributes(context, { @@ -344,16 +342,14 @@ const bulkEnableRulesWithOCC = async ( // bulk_disable, bulk_enable, etc. to fix this cast bulkCreateRulesSo({ savedObjectsClient: context.unsecuredSavedObjectsClient, - bulkCreateRuleAttributes: rulesToEnable as Array< - SavedObjectsBulkCreateObject - >, + bulkCreateRuleAttributes: rulesToEnable as Array>, savedObjectsBulkCreateOptions: { overwrite: true, }, }) ); - const rules: Array> = []; + const rules: Array> = []; const taskIdsToEnable: string[] = []; result.saved_objects.forEach((rule) => { @@ -376,7 +372,7 @@ const bulkEnableRulesWithOCC = async ( return { errors, // TODO: delete the casting when we do versioning of bulk disable api - rules: rules as Array>, + rules: rules as Array>, accListSpecificForBulkOperation: [taskIdsToEnable], }; }; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/clone/clone_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/clone/clone_rule.ts index 4f83f5b8daa9c..9383a32b7c60a 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/clone/clone_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/clone/clone_rule.ts @@ -21,7 +21,6 @@ import { createNewAPIKeySet, createRuleSavedObject } from '../../../../rules_cli import { RulesClientContext } from '../../../../rules_client/types'; import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { CloneRuleParams } from './types'; -import { RuleAttributes } from '../../../../data/rule/types'; import { RuleDomain, RuleParams } from '../../types'; import { getDecryptedRuleSo, getRuleSo } from '../../../../data/rule'; import { transformRuleAttributesToRuleDomain, transformRuleDomainToRule } from '../../transforms'; @@ -40,7 +39,7 @@ export async function cloneRule( throw Boom.badRequest(`Error validating clone data - ${error.message}`); } - let ruleSavedObject: SavedObject; + let ruleSavedObject: SavedObject; try { ruleSavedObject = await withSpan( @@ -78,8 +77,7 @@ export async function cloneRule( * functionality until we resolve our difference */ if ( - // TODO (http-versioning): Remove this cast to RawRule - isDetectionEngineAADRuleType(ruleSavedObject as SavedObject) || + isDetectionEngineAADRuleType(ruleSavedObject) || ruleSavedObject.attributes.consumer === AlertConsumers.SIEM ) { throw Boom.badRequest( @@ -126,7 +124,7 @@ export async function cloneRule( errorMessage: 'Error creating rule: could not create API key', }); - const ruleAttributes: RuleAttributes = { + const ruleAttributes: RawRule = { ...ruleSavedObject.attributes, name: ruleName, ...apiKeyAttributes, @@ -139,10 +137,7 @@ export async function cloneRule( muteAll: false, mutedInstanceIds: [], executionStatus: getRuleExecutionStatusPendingAttributes(lastRunTimestamp.toISOString()), - // TODO (http-versioning): Remove this cast to RuleAttributes - monitoring: getDefaultMonitoring( - lastRunTimestamp.toISOString() - ) as RuleAttributes['monitoring'], + monitoring: getDefaultMonitoring(lastRunTimestamp.toISOString()), revision: 0, scheduledTaskId: null, running: false, @@ -168,7 +163,7 @@ export async function cloneRule( }) ); - // Convert ES RuleAttributes back to domain rule object + // Convert ES RawRule back to domain rule object const ruleDomain: RuleDomain = transformRuleAttributesToRuleDomain( clonedRuleAttributes.attributes, { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts index 876fb73b0c289..34e13b65d76c5 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts @@ -27,14 +27,13 @@ import { generateAPIKeyName, apiKeyAsRuleDomainProperties } from '../../../../ru import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; import { RulesClientContext } from '../../../../rules_client/types'; import { RuleDomain, RuleParams } from '../../types'; -import { SanitizedRule } from '../../../../types'; +import { RawRule, SanitizedRule } from '../../../../types'; import { transformRuleAttributesToRuleDomain, transformRuleDomainToRuleAttributes, transformRuleDomainToRule, } from '../../transforms'; import { ruleDomainSchema } from '../../schemas'; -import { RuleAttributes } from '../../../../data/rule/types'; import type { CreateRuleData } from './types'; import { createRuleDataSchema } from './schemas'; import { createRuleSavedObject } from '../../../../rules_client/lib'; @@ -225,12 +224,11 @@ export async function createRule( }, params: { legacyId, - // @ts-expect-error upgrade typescript v4.9.5 paramsWithRefs: updatedParams, }, }); - const createdRuleSavedObject: SavedObject = await withSpan( + const createdRuleSavedObject: SavedObject = await withSpan( { name: 'createRuleSavedObject', type: 'rules' }, () => createRuleSavedObject(context, { @@ -243,7 +241,7 @@ export async function createRule( }) ); - // Convert ES RuleAttributes back to domain rule object + // Convert ES RawRule back to domain rule object const ruleDomain: RuleDomain = transformRuleAttributesToRuleDomain( createdRuleSavedObject.attributes, { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/delete/delete_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/delete/delete_rule.ts index b738bafb3d690..dd3aaf5e82f78 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/delete/delete_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/delete/delete_rule.ts @@ -14,7 +14,6 @@ import { bulkMarkApiKeysForInvalidation } from '../../../../invalidate_pending_a import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; import { RulesClientContext } from '../../../../rules_client/types'; import { untrackRuleAlerts, migrateLegacyActions } from '../../../../rules_client/lib'; -import { RuleAttributes } from '../../../../data/rule/types'; import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { DeleteRuleParams } from './types'; import { deleteRuleParamsSchema } from './schemas'; @@ -40,7 +39,7 @@ async function deleteRuleWithOCC(context: RulesClientContext, { id }: { id: stri let taskIdToRemove: string | undefined | null; let apiKeyToInvalidate: string | null = null; let apiKeyCreatedByUser: boolean | undefined | null = false; - let attributes: RuleAttributes; + let attributes: RawRule; try { const decryptedRule = await getDecryptedRuleSo({ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/disable/disable_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/disable/disable_rule.ts index 3e0d3aa3c67f5..f1865f123484b 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/disable/disable_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/disable/disable_rule.ts @@ -13,7 +13,6 @@ import { retryIfConflicts } from '../../../../lib/retry_if_conflicts'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; import { RulesClientContext } from '../../../../rules_client/types'; import { untrackRuleAlerts, updateMeta, migrateLegacyActions } from '../../../../rules_client/lib'; -import { RuleAttributes } from '../../../../data/rule/types'; import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { DisableRuleParams } from './types'; import { disableRuleParamsSchema } from './schemas'; @@ -86,7 +85,7 @@ async function disableWithOCC( } if (untrack) { - await untrackRuleAlerts(context, id, attributes as RuleAttributes); + await untrackRuleAlerts(context, id, attributes); } context.auditLogger?.log( diff --git a/x-pack/plugins/alerting/server/application/rule/methods/mute_all/mute_all.ts b/x-pack/plugins/alerting/server/application/rule/methods/mute_all/mute_all.ts index 73cfe6e26fdce..d0d2c186ba126 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/mute_all/mute_all.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/mute_all/mute_all.ts @@ -14,7 +14,6 @@ import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common import { RulesClientContext } from '../../../../rules_client/types'; import { updateMetaAttributes } from '../../../../rules_client/lib'; import { clearUnscheduledSnoozeAttributes } from '../../../../rules_client/common'; -import { RuleAttributes } from '../../../../data/rule/types'; import { MuteAllRuleParams } from './types'; import { muteAllRuleParamsSchema } from './schemas'; @@ -77,7 +76,7 @@ async function muteAllWithOCC(context: RulesClientContext, params: MuteAllRulePa const updateAttributes = updateMetaAttributes(context, { muteAll: true, mutedInstanceIds: [], - snoozeSchedule: clearUnscheduledSnoozeAttributes(attributes as RuleAttributes), + snoozeSchedule: clearUnscheduledSnoozeAttributes(attributes), updatedBy: await context.getUserName(), updatedAt: new Date().toISOString(), }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/unmute_all/unmute_all.ts b/x-pack/plugins/alerting/server/application/rule/methods/unmute_all/unmute_all.ts index 722cfed3700d0..bc70f7206fbb4 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/unmute_all/unmute_all.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/unmute_all/unmute_all.ts @@ -14,7 +14,6 @@ import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common import { RulesClientContext } from '../../../../rules_client/types'; import { updateMetaAttributes } from '../../../../rules_client/lib'; import { clearUnscheduledSnoozeAttributes } from '../../../../rules_client/common'; -import { RuleAttributes } from '../../../../data/rule/types'; import { UnmuteAllRuleParams } from './types'; import { unmuteAllRuleParamsSchema } from './schemas'; @@ -77,7 +76,7 @@ async function unmuteAllWithOCC(context: RulesClientContext, params: UnmuteAllRu const updateAttributes = updateMetaAttributes(context, { muteAll: false, mutedInstanceIds: [], - snoozeSchedule: clearUnscheduledSnoozeAttributes(attributes as RuleAttributes), + snoozeSchedule: clearUnscheduledSnoozeAttributes(attributes), updatedBy: await context.getUserName(), updatedAt: new Date().toISOString(), }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts index 7f0663c879056..25759e8e06c70 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts @@ -37,13 +37,12 @@ import { createRuleSo, getDecryptedRuleSo, getRuleSo } from '../../../../data/ru import { validateScheduleLimit, ValidateScheduleLimitResult } from '../get_schedule_frequency'; import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { updateRuleDataSchema } from './schemas'; -import { RuleAttributes } from '../../../../data/rule/types'; import { transformRuleAttributesToRuleDomain, transformRuleDomainToRule } from '../../transforms'; import { ruleDomainSchema } from '../../schemas'; const validateCanUpdateFlapping = ( isFlappingEnabled: boolean, - originalFlapping: RuleAttributes['flapping'], + originalFlapping: RawRule['flapping'], updateFlapping: UpdateRuleParams['data']['flapping'] ) => { // If flapping is enabled, allow rule flapping to be updated and do nothing @@ -112,7 +111,7 @@ async function updateWithOCC( throw Boom.badRequest(`Error validating update data - ${error.message}`); } - let originalRuleSavedObject: SavedObject; + let originalRuleSavedObject: SavedObject; try { originalRuleSavedObject = await getDecryptedRuleSo({ @@ -296,7 +295,7 @@ async function updateRuleAttributes({ }: { context: RulesClientContext; updateRuleData: UpdateRuleData; - originalRuleSavedObject: SavedObject; + originalRuleSavedObject: SavedObject; validatedRuleTypeParams: Params; shouldIncrementRevision: (params?: Params) => boolean; isSystemAction: (connectorId: string) => boolean; @@ -376,7 +375,7 @@ async function updateRuleAttributes({ updatedRuleAttributes.mapped_params = mappedParams; } - let updatedRuleSavedObject: SavedObject; + let updatedRuleSavedObject: SavedObject; const { id, version } = originalRuleSavedObject; try { diff --git a/x-pack/plugins/alerting/server/application/rule/schemas/rule_schemas.ts b/x-pack/plugins/alerting/server/application/rule/schemas/rule_schemas.ts index da91ceb727d2c..978e11f0183cf 100644 --- a/x-pack/plugins/alerting/server/application/rule/schemas/rule_schemas.ts +++ b/x-pack/plugins/alerting/server/application/rule/schemas/rule_schemas.ts @@ -64,12 +64,14 @@ export const ruleExecutionStatusSchema = schema.object({ ), }); +const outcome = schema.oneOf([ + schema.literal(ruleLastRunOutcomeValues.SUCCEEDED), + schema.literal(ruleLastRunOutcomeValues.WARNING), + schema.literal(ruleLastRunOutcomeValues.FAILED), +]); + export const ruleLastRunSchema = schema.object({ - outcome: schema.oneOf([ - schema.literal(ruleLastRunOutcomeValues.SUCCEEDED), - schema.literal(ruleLastRunOutcomeValues.WARNING), - schema.literal(ruleLastRunOutcomeValues.FAILED), - ]), + outcome, outcomeOrder: schema.maybe(schema.number()), warning: schema.maybe( schema.nullable( @@ -105,7 +107,7 @@ export const monitoringSchema = schema.object({ success: schema.boolean(), timestamp: schema.number(), duration: schema.maybe(schema.number()), - outcome: schema.maybe(ruleLastRunSchema), + outcome: schema.maybe(outcome), }) ), calculated_metrics: schema.object({ diff --git a/x-pack/plugins/alerting/server/application/rule/transforms/transform_raw_actions_to_domain_actions.test.ts b/x-pack/plugins/alerting/server/application/rule/transforms/transform_raw_actions_to_domain_actions.test.ts index 591518e9b13ee..7b25ebf45ce8d 100644 --- a/x-pack/plugins/alerting/server/application/rule/transforms/transform_raw_actions_to_domain_actions.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/transforms/transform_raw_actions_to_domain_actions.test.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { RuleActionAttributes } from '../../../data/rule/types'; +import { RawRuleAction } from '../../../types'; import { transformRawActionsToDomainActions, transformRawActionsToDomainSystemActions, } from './transform_raw_actions_to_domain_actions'; -const defaultAction: RuleActionAttributes = { +const defaultAction: RawRuleAction = { group: 'default', uuid: '1', actionRef: 'default-action-ref', @@ -25,7 +25,7 @@ const defaultAction: RuleActionAttributes = { alertsFilter: { query: { kql: 'test:1', dsl: '{}', filters: [] } }, }; -const systemAction: RuleActionAttributes = { +const systemAction: RawRuleAction = { actionRef: 'system_action:my-system-action-id', uuid: '123', actionTypeId: '.test-system-action', diff --git a/x-pack/plugins/alerting/server/application/rule/transforms/transform_raw_actions_to_domain_actions.ts b/x-pack/plugins/alerting/server/application/rule/transforms/transform_raw_actions_to_domain_actions.ts index 14f376c7d8176..7242f4bb1c716 100644 --- a/x-pack/plugins/alerting/server/application/rule/transforms/transform_raw_actions_to_domain_actions.ts +++ b/x-pack/plugins/alerting/server/application/rule/transforms/transform_raw_actions_to_domain_actions.ts @@ -8,13 +8,12 @@ import { omit } from 'lodash'; import { SavedObjectReference } from '@kbn/core/server'; import { injectReferencesIntoActions } from '../../../rules_client/common'; -import { RuleAttributes } from '../../../data/rule/types'; import { RawRule } from '../../../types'; import { RuleDomain } from '../types'; interface Args { ruleId: string; - actions: RuleAttributes['actions'] | RawRule['actions']; + actions: RawRule['actions']; isSystemAction: (connectorId: string) => boolean; omitGeneratedValues?: boolean; references?: SavedObjectReference[]; @@ -42,8 +41,8 @@ export const transformRawActionsToDomainActions = ({ uuid: action.uuid, ...(action.frequency ? { frequency: action.frequency } : {}), ...(action.alertsFilter ? { alertsFilter: action.alertsFilter } : {}), - ...(action.useAlertDataAsTemplate - ? { useAlertDataAsTemplate: action.useAlertDataAsTemplate } + ...(action.useAlertDataForTemplate + ? { useAlertDataForTemplate: action.useAlertDataForTemplate } : {}), }; @@ -54,7 +53,7 @@ export const transformRawActionsToDomainActions = ({ return defaultAction; }); - return ruleDomainActions; + return ruleDomainActions as RuleDomain['actions']; }; export const transformRawActionsToDomainSystemActions = ({ @@ -76,8 +75,8 @@ export const transformRawActionsToDomainSystemActions = ({ params: action.params, actionTypeId: action.actionTypeId, uuid: action.uuid, - ...(action.useAlertDataAsTemplate - ? { useAlertDataAsTemplate: action.useAlertDataAsTemplate } + ...(action.useAlertDataForTemplate + ? { useAlertDataForTemplate: action.useAlertDataForTemplate } : {}), }; }); diff --git a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.test.ts b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.test.ts index 6a4e1824172ca..a96fbcceaffba 100644 --- a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.test.ts @@ -9,7 +9,7 @@ import { RecoveredActionGroup } from '../../../../common'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { transformRuleAttributesToRuleDomain } from './transform_rule_attributes_to_rule_domain'; import { UntypedNormalizedRuleType } from '../../../rule_type_registry'; -import { RuleActionAttributes } from '../../../data/rule/types'; +import { RawRuleAction } from '../../../types'; const ruleType: jest.Mocked = { id: 'test.rule-type', @@ -37,7 +37,7 @@ const ruleType: jest.Mocked = { validLegacyConsumers: [], }; -const defaultAction: RuleActionAttributes = { +const defaultAction: RawRuleAction = { group: 'default', uuid: '1', actionRef: 'default-action-ref', @@ -51,7 +51,7 @@ const defaultAction: RuleActionAttributes = { alertsFilter: { query: { kql: 'test:1', dsl: '{}', filters: [] } }, }; -const systemAction: RuleActionAttributes = { +const systemAction: RawRuleAction = { actionRef: 'system_action:my-system-action-id', uuid: '123', actionTypeId: '.test-system-action', @@ -82,6 +82,8 @@ describe('transformRuleAttributesToRuleDomain', () => { executionStatus: { lastExecutionDate: '2019-02-12T21:01:22.479Z', status: 'pending' as const, + error: null, + warning: null, }, params: {}, throttle: null, diff --git a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.ts b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.ts index 6b4917c96010f..8d71e43130647 100644 --- a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.ts +++ b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.ts @@ -10,8 +10,7 @@ import { SavedObjectReference } from '@kbn/core/server'; import { ruleExecutionStatusValues } from '../constants'; import { getRuleSnoozeEndTime } from '../../../lib'; import { RuleDomain, Monitoring, RuleParams } from '../types'; -import { PartialRule, SanitizedRule } from '../../../types'; -import { RuleAttributes, RuleExecutionStatusAttributes } from '../../../data/rule/types'; +import { PartialRule, RawRule, RawRuleExecutionStatus, SanitizedRule } from '../../../types'; import { UntypedNormalizedRuleType } from '../../../rule_type_registry'; import { injectReferencesIntoParams } from '../../../rules_client/common'; import { getActiveScheduledSnoozes } from '../../../lib/is_rule_snoozed'; @@ -32,7 +31,7 @@ const INITIAL_LAST_RUN_METRICS = { const transformEsExecutionStatus = ( logger: Logger, ruleId: string, - esRuleExecutionStatus: RuleExecutionStatusAttributes + esRuleExecutionStatus: RawRuleExecutionStatus ): RuleDomain['executionStatus'] => { const { lastExecutionDate, @@ -89,7 +88,7 @@ export const updateMonitoring = ({ const transformEsMonitoring = ( logger: Logger, ruleId: string, - monitoring?: RuleAttributes['monitoring'] + monitoring?: RawRule['monitoring'] ): Monitoring | undefined => { if (!monitoring) { return undefined; @@ -120,7 +119,7 @@ interface TransformEsToRuleParams { } export const transformRuleAttributesToRuleDomain = ( - esRule: RuleAttributes, + esRule: RawRule, transformParams: TransformEsToRuleParams, isSystemAction: (connectorId: string) => boolean ): RuleDomain => { @@ -251,5 +250,6 @@ export const transformRuleAttributesToRuleDomain = ; params: TransformRuleToEsParams; -}): RuleAttributes => { +}): RawRule => { const { legacyId, paramsWithRefs, meta } = params; const mappedParams = getMappedParams(paramsWithRefs); @@ -81,5 +81,5 @@ export const transformRuleDomainToRuleAttributes = ({ ...(rule.running !== undefined ? { running: rule.running } : {}), ...(rule.alertDelay !== undefined ? { alertDelay: rule.alertDelay } : {}), ...(rule.flapping !== undefined ? { flapping: rule.flapping } : {}), - }; + } as RawRule; }; diff --git a/x-pack/plugins/alerting/server/data/maintenance_window/methods/find_maintenance_window_so.ts b/x-pack/plugins/alerting/server/data/maintenance_window/methods/find_maintenance_window_so.ts index baaed546c88cb..d08a3c360cbb0 100644 --- a/x-pack/plugins/alerting/server/data/maintenance_window/methods/find_maintenance_window_so.ts +++ b/x-pack/plugins/alerting/server/data/maintenance_window/methods/find_maintenance_window_so.ts @@ -24,7 +24,7 @@ export const findMaintenanceWindowSo = ({ - ...savedObjectsFindOptions, + ...(savedObjectsFindOptions ? savedObjectsFindOptions : {}), type: MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE, }); }; diff --git a/x-pack/plugins/alerting/server/data/r_rule/types/r_rule_attributes.ts b/x-pack/plugins/alerting/server/data/r_rule/types/r_rule_attributes.ts index 54b2547a71b00..c97f593dd0a7b 100644 --- a/x-pack/plugins/alerting/server/data/r_rule/types/r_rule_attributes.ts +++ b/x-pack/plugins/alerting/server/data/r_rule/types/r_rule_attributes.ts @@ -17,13 +17,13 @@ export interface RRuleAttributes { count?: number; interval?: number; wkst?: WeekdayStr; - byweekday?: Array; - bymonth?: number[]; - bysetpos?: number[]; - bymonthday?: number[]; - byyearday?: number[]; - byweekno?: number[]; - byhour?: number[]; - byminute?: number[]; - bysecond?: number[]; + byweekday?: Array | null; + bymonth?: number[] | null; + bysetpos?: number[] | null; + bymonthday?: number[] | null; + byyearday?: number[] | null; + byweekno?: number[] | null; + byhour?: number[] | null; + byminute?: number[] | null; + bysecond?: number[] | null; } diff --git a/x-pack/plugins/alerting/server/data/rule/methods/bulk_create_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/bulk_create_rule_so.ts index 6bc0ee04b394d..057e44446030f 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/bulk_create_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/bulk_create_rule_so.ts @@ -11,20 +11,20 @@ import { SavedObjectsBulkCreateObject, SavedObjectsBulkResponse, } from '@kbn/core/server'; -import { RuleAttributes } from '../types'; +import { RawRule } from '../../../types'; export interface BulkCreateRulesSoParams { savedObjectsClient: SavedObjectsClientContract; - bulkCreateRuleAttributes: Array>; + bulkCreateRuleAttributes: Array>; savedObjectsBulkCreateOptions?: SavedObjectsCreateOptions; } export const bulkCreateRulesSo = ( params: BulkCreateRulesSoParams -): Promise> => { +): Promise> => { const { savedObjectsClient, bulkCreateRuleAttributes, savedObjectsBulkCreateOptions } = params; - return savedObjectsClient.bulkCreate( + return savedObjectsClient.bulkCreate( bulkCreateRuleAttributes, savedObjectsBulkCreateOptions ); diff --git a/x-pack/plugins/alerting/server/data/rule/methods/bulk_disable_rules_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/bulk_disable_rules_so.ts index 59c22765081ad..a32e38f255c3e 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/bulk_disable_rules_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/bulk_disable_rules_so.ts @@ -11,20 +11,20 @@ import { SavedObjectsBulkCreateObject, SavedObjectsBulkResponse, } from '@kbn/core/server'; -import { RuleAttributes } from '../types'; +import { RawRule } from '../../../types'; export interface BulkDisableRulesSoParams { savedObjectsClient: SavedObjectsClientContract; - bulkDisableRuleAttributes: Array>; + bulkDisableRuleAttributes: Array>; savedObjectsBulkCreateOptions?: SavedObjectsCreateOptions; } export const bulkDisableRulesSo = ( params: BulkDisableRulesSoParams -): Promise> => { +): Promise> => { const { savedObjectsClient, bulkDisableRuleAttributes, savedObjectsBulkCreateOptions } = params; - return savedObjectsClient.bulkCreate( + return savedObjectsClient.bulkCreate( bulkDisableRuleAttributes, savedObjectsBulkCreateOptions ); diff --git a/x-pack/plugins/alerting/server/data/rule/methods/create_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/create_rule_so.ts index b276bb0e2e10d..e5a45ee9f386e 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/create_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/create_rule_so.ts @@ -10,16 +10,16 @@ import { SavedObjectsCreateOptions, SavedObject, } from '@kbn/core/server'; +import { RawRule } from '../../../types'; import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; -import { RuleAttributes } from '../types'; export interface CreateRuleSoParams { savedObjectsClient: SavedObjectsClientContract; - ruleAttributes: RuleAttributes; + ruleAttributes: RawRule; savedObjectsCreateOptions?: SavedObjectsCreateOptions; } -export const createRuleSo = (params: CreateRuleSoParams): Promise> => { +export const createRuleSo = (params: CreateRuleSoParams): Promise> => { const { savedObjectsClient, ruleAttributes, savedObjectsCreateOptions } = params; return savedObjectsClient.create( diff --git a/x-pack/plugins/alerting/server/data/rule/methods/find_rules_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/find_rules_so.ts index e929ccf019205..1e73d52aba955 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/find_rules_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/find_rules_so.ts @@ -11,7 +11,7 @@ import { SavedObjectsFindResponse, } from '@kbn/core/server'; import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; -import { RuleAttributes } from '../types'; +import { RawRule } from '../../../types'; export interface FindRulesSoParams { savedObjectsClient: SavedObjectsClientContract; @@ -20,10 +20,10 @@ export interface FindRulesSoParams { export const findRulesSo = >( params: FindRulesSoParams -): Promise> => { +): Promise> => { const { savedObjectsClient, savedObjectsFindOptions } = params; - return savedObjectsClient.find({ + return savedObjectsClient.find({ ...savedObjectsFindOptions, type: RULE_SAVED_OBJECT_TYPE, }); diff --git a/x-pack/plugins/alerting/server/data/rule/methods/get_decrypted_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/get_decrypted_rule_so.ts index f7a4ab0baab9b..1171e53abda6f 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/get_decrypted_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/get_decrypted_rule_so.ts @@ -8,8 +8,8 @@ import { SavedObject } from '@kbn/core/server'; import { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; import { SavedObjectsGetOptions } from '@kbn/core-saved-objects-api-server'; +import { RawRule } from '../../../types'; import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; -import { RuleAttributes } from '../types'; export interface GetDecryptedRuleSoParams { encryptedSavedObjectsClient: EncryptedSavedObjectsClient; @@ -19,10 +19,10 @@ export interface GetDecryptedRuleSoParams { export const getDecryptedRuleSo = ( params: GetDecryptedRuleSoParams -): Promise> => { +): Promise> => { const { id, encryptedSavedObjectsClient, savedObjectsGetOptions } = params; - return encryptedSavedObjectsClient.getDecryptedAsInternalUser( + return encryptedSavedObjectsClient.getDecryptedAsInternalUser( RULE_SAVED_OBJECT_TYPE, id, savedObjectsGetOptions diff --git a/x-pack/plugins/alerting/server/data/rule/methods/get_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/get_rule_so.ts index 051644bab56f2..e02813d855ce9 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/get_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/get_rule_so.ts @@ -7,8 +7,8 @@ import { SavedObjectsClientContract, SavedObject } from '@kbn/core/server'; import { SavedObjectsGetOptions } from '@kbn/core-saved-objects-api-server'; +import { RawRule } from '../../../types'; import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; -import { RuleAttributes } from '../types'; export interface GetRuleSoParams { savedObjectsClient: SavedObjectsClientContract; @@ -16,8 +16,8 @@ export interface GetRuleSoParams { savedObjectsGetOptions?: SavedObjectsGetOptions; } -export const getRuleSo = (params: GetRuleSoParams): Promise> => { +export const getRuleSo = (params: GetRuleSoParams): Promise> => { const { savedObjectsClient, id, savedObjectsGetOptions } = params; - return savedObjectsClient.get(RULE_SAVED_OBJECT_TYPE, id, savedObjectsGetOptions); + return savedObjectsClient.get(RULE_SAVED_OBJECT_TYPE, id, savedObjectsGetOptions); }; diff --git a/x-pack/plugins/alerting/server/data/rule/methods/resolve_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/resolve_rule_so.ts index d0429b4166d8e..0c8e876dac540 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/resolve_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/resolve_rule_so.ts @@ -8,7 +8,7 @@ import { SavedObjectsClientContract, SavedObjectsResolveResponse } from '@kbn/core/server'; import { SavedObjectsResolveOptions } from '@kbn/core-saved-objects-api-server'; import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; -import { RuleAttributes } from '../types'; +import { RawRule } from '../../../types'; export interface ResolveRuleSoParams { savedObjectsClient: SavedObjectsClientContract; @@ -18,7 +18,7 @@ export interface ResolveRuleSoParams { export const resolveRuleSo = ( params: ResolveRuleSoParams -): Promise> => { +): Promise> => { const { savedObjectsClient, id, savedObjectsResolveOptions } = params; return savedObjectsClient.resolve(RULE_SAVED_OBJECT_TYPE, id, savedObjectsResolveOptions); diff --git a/x-pack/plugins/alerting/server/data/rule/methods/update_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/update_rule_so.ts index dfb8b6b5c1e7e..7358cf609d3c3 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/update_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/update_rule_so.ts @@ -11,21 +11,21 @@ import { SavedObjectsUpdateResponse, } from '@kbn/core/server'; import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; -import { RuleAttributes } from '../types'; +import { RawRule } from '../../../types'; export interface UpdateRuleSoParams { savedObjectsClient: SavedObjectsClientContract; id: string; - updateRuleAttributes: Partial; - savedObjectsUpdateOptions?: SavedObjectsUpdateOptions; + updateRuleAttributes: Partial; + savedObjectsUpdateOptions?: SavedObjectsUpdateOptions; } export const updateRuleSo = ( params: UpdateRuleSoParams -): Promise> => { +): Promise> => { const { savedObjectsClient, id, updateRuleAttributes, savedObjectsUpdateOptions } = params; - return savedObjectsClient.update( + return savedObjectsClient.update( RULE_SAVED_OBJECT_TYPE, id, updateRuleAttributes, diff --git a/x-pack/plugins/alerting/server/data/rule/types/index.ts b/x-pack/plugins/alerting/server/data/rule/types/index.ts deleted file mode 100644 index a742c1b28224b..0000000000000 --- a/x-pack/plugins/alerting/server/data/rule/types/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type { - RuleNotifyWhenAttributes, - RuleLastRunOutcomeValuesAttributes, - RuleActionAttributes, - RuleExecutionStatusValuesAttributes, - RuleExecutionStatusErrorReasonAttributes, - RuleExecutionStatusWarningReasonAttributes, - RuleSnoozeScheduleAttributes, - RuleExecutionStatusAttributes, - RuleLastRunAttributes, - RuleMonitoringHistoryAttributes, - RuleMonitoringCalculatedMetricsAttributes, - RuleMonitoringLastRunMetricsAttributes, - RuleMonitoringLastRunAttributes, - RuleMonitoringAttributes, - RuleAttributes, -} from './rule_attributes'; diff --git a/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts b/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts deleted file mode 100644 index e057662adbdf5..0000000000000 --- a/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { SavedObjectAttributes } from '@kbn/core/server'; -import { IsoWeekday } from '../../../../common'; -import { - ruleNotifyWhenAttributes, - ruleLastRunOutcomeValuesAttributes, - ruleExecutionStatusValuesAttributes, - ruleExecutionStatusErrorReasonAttributes, - ruleExecutionStatusWarningReasonAttributes, -} from '../constants'; -import { RRuleAttributes } from '../../r_rule/types'; -import { AlertsFilterQueryAttributes } from '../../alerts_filter_query/types'; - -export type RuleNotifyWhenAttributes = - (typeof ruleNotifyWhenAttributes)[keyof typeof ruleNotifyWhenAttributes]; -export type RuleLastRunOutcomeValuesAttributes = - (typeof ruleLastRunOutcomeValuesAttributes)[keyof typeof ruleLastRunOutcomeValuesAttributes]; -export type RuleExecutionStatusValuesAttributes = - (typeof ruleExecutionStatusValuesAttributes)[keyof typeof ruleExecutionStatusValuesAttributes]; -export type RuleExecutionStatusErrorReasonAttributes = - (typeof ruleExecutionStatusErrorReasonAttributes)[keyof typeof ruleExecutionStatusErrorReasonAttributes]; -export type RuleExecutionStatusWarningReasonAttributes = - (typeof ruleExecutionStatusWarningReasonAttributes)[keyof typeof ruleExecutionStatusWarningReasonAttributes]; - -export interface RuleSnoozeScheduleAttributes { - duration: number; - rRule: RRuleAttributes; - id?: string; - skipRecurrences?: string[]; -} - -export interface RuleExecutionStatusAttributes { - status: RuleExecutionStatusValuesAttributes; - lastExecutionDate: string; - lastDuration?: number; - error?: { - reason: RuleExecutionStatusErrorReasonAttributes; - message: string; - } | null; - warning?: { - reason: RuleExecutionStatusWarningReasonAttributes; - message: string; - } | null; -} - -export interface RuleLastRunAttributes { - outcome: RuleLastRunOutcomeValuesAttributes; - outcomeOrder?: number; - warning?: - | RuleExecutionStatusErrorReasonAttributes - | RuleExecutionStatusWarningReasonAttributes - | null; - outcomeMsg?: string[] | null; - alertsCount: { - active?: number | null; - new?: number | null; - recovered?: number | null; - ignored?: number | null; - }; -} - -export interface RuleMonitoringHistoryAttributes { - success: boolean; - timestamp: number; - duration?: number; - outcome?: RuleLastRunAttributes; -} - -export interface RuleMonitoringCalculatedMetricsAttributes { - p50?: number; - p95?: number; - p99?: number; - success_ratio: number; -} - -export interface RuleMonitoringLastRunMetricsAttributes { - duration?: number; - total_search_duration_ms?: number | null; - total_indexing_duration_ms?: number | null; - total_alerts_detected?: number | null; - total_alerts_created?: number | null; - gap_duration_s?: number | null; -} - -export interface RuleMonitoringLastRunAttributes { - timestamp: string; - metrics: RuleMonitoringLastRunMetricsAttributes; -} - -export interface RuleMonitoringAttributes { - run: { - history: RuleMonitoringHistoryAttributes[]; - calculated_metrics: RuleMonitoringCalculatedMetricsAttributes; - last_run: RuleMonitoringLastRunAttributes; - }; -} - -interface IntervaleScheduleAttributes extends SavedObjectAttributes { - interval: string; -} - -interface AlertsFilterTimeFrameAttributes { - days: IsoWeekday[]; - timezone: string; - hours: { - start: string; - end: string; - }; -} - -export interface AlertsFilterAttributes { - query?: AlertsFilterQueryAttributes; - timeframe?: AlertsFilterTimeFrameAttributes; -} - -export interface RuleActionAttributes { - uuid: string; - group?: string; - actionRef: string; - actionTypeId: string; - params: SavedObjectAttributes; - frequency?: { - summary: boolean; - notifyWhen: RuleNotifyWhenAttributes; - throttle: string | null; - }; - alertsFilter?: AlertsFilterAttributes; - useAlertDataAsTemplate?: boolean; -} - -type MappedParamsAttributes = SavedObjectAttributes & { - risk_score?: number; - severity?: string; -}; - -interface RuleMetaAttributes { - versionApiKeyLastmodified?: string; -} - -interface AlertDelayAttributes { - active: number; -} - -interface FlappingAttributes { - lookBackWindow: number; - statusChangeThreshold: number; -} - -export interface RuleAttributes { - name: string; - tags: string[]; - enabled: boolean; - alertTypeId: string; - consumer: string; - legacyId: string | null; - schedule: IntervaleScheduleAttributes; - actions: RuleActionAttributes[]; - params: SavedObjectAttributes; - mapped_params?: MappedParamsAttributes; - scheduledTaskId?: string | null; - createdBy: string | null; - updatedBy: string | null; - createdAt: string; - updatedAt: string; - apiKey: string | null; - apiKeyOwner: string | null; - apiKeyCreatedByUser?: boolean | null; - throttle?: string | null; - notifyWhen?: RuleNotifyWhenAttributes | null; - muteAll: boolean; - mutedInstanceIds: string[]; - meta?: RuleMetaAttributes; - executionStatus?: RuleExecutionStatusAttributes; - monitoring?: RuleMonitoringAttributes; - snoozeSchedule?: RuleSnoozeScheduleAttributes[]; - isSnoozedUntil?: string | null; - lastRun?: RuleLastRunAttributes | null; - nextRun?: string | null; - revision: number; - running?: boolean | null; - alertDelay?: AlertDelayAttributes; - flapping?: FlappingAttributes | null; -} diff --git a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap index 8c65843f2d844..0513842a6126b 100644 --- a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap +++ b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap @@ -9851,6 +9851,10 @@ Object { "required": false, "type": "text", }, + "error.stack_trace": Object { + "required": false, + "type": "wildcard", + }, "host.name": Object { "required": false, "type": "keyword", @@ -9991,6 +9995,10 @@ Object { "required": false, "type": "text", }, + "error.stack_trace": Object { + "required": false, + "type": "wildcard", + }, "host.name": Object { "required": false, "type": "keyword", @@ -10131,6 +10139,10 @@ Object { "required": false, "type": "text", }, + "error.stack_trace": Object { + "required": false, + "type": "wildcard", + }, "host.name": Object { "required": false, "type": "keyword", @@ -10271,6 +10283,10 @@ Object { "required": false, "type": "text", }, + "error.stack_trace": Object { + "required": false, + "type": "wildcard", + }, "host.name": Object { "required": false, "type": "keyword", @@ -10417,6 +10433,10 @@ Object { "required": false, "type": "text", }, + "error.stack_trace": Object { + "required": false, + "type": "wildcard", + }, "host.name": Object { "required": false, "type": "keyword", diff --git a/x-pack/plugins/alerting/server/maintenance_window_client/maintenance_window_client.ts b/x-pack/plugins/alerting/server/maintenance_window_client/maintenance_window_client.ts index 2c5e6f417ff3d..dba7ae0800ede 100644 --- a/x-pack/plugins/alerting/server/maintenance_window_client/maintenance_window_client.ts +++ b/x-pack/plugins/alerting/server/maintenance_window_client/maintenance_window_client.ts @@ -13,7 +13,10 @@ import type { GetMaintenanceWindowParams } from '../application/maintenance_wind import { updateMaintenanceWindow } from '../application/maintenance_window/methods/update/update_maintenance_window'; import type { UpdateMaintenanceWindowParams } from '../application/maintenance_window/methods/update/types'; import { findMaintenanceWindows } from '../application/maintenance_window/methods/find/find_maintenance_windows'; -import type { FindMaintenanceWindowsResult } from '../application/maintenance_window/methods/find/types'; +import type { + FindMaintenanceWindowsResult, + FindMaintenanceWindowsParams, +} from '../application/maintenance_window/methods/find/types'; import { deleteMaintenanceWindow } from '../application/maintenance_window/methods/delete/delete_maintenance_window'; import type { DeleteMaintenanceWindowParams } from '../application/maintenance_window/methods/delete/types'; import { archiveMaintenanceWindow } from '../application/maintenance_window/methods/archive/archive_maintenance_window'; @@ -75,7 +78,8 @@ export class MaintenanceWindowClient { getMaintenanceWindow(this.context, params); public update = (params: UpdateMaintenanceWindowParams): Promise => updateMaintenanceWindow(this.context, params); - public find = (): Promise => findMaintenanceWindows(this.context); + public find = (params?: FindMaintenanceWindowsParams): Promise => + findMaintenanceWindows(this.context, params); public delete = (params: DeleteMaintenanceWindowParams): Promise<{}> => deleteMaintenanceWindow(this.context, params); public archive = (params: ArchiveMaintenanceWindowParams): Promise => diff --git a/x-pack/plugins/alerting/server/manual_tests/action_param_templates.sh b/x-pack/plugins/alerting/server/manual_tests/action_param_templates.sh index 0b72c5e57f5d7..5a63a4a1ecf51 100644 --- a/x-pack/plugins/alerting/server/manual_tests/action_param_templates.sh +++ b/x-pack/plugins/alerting/server/manual_tests/action_param_templates.sh @@ -24,10 +24,10 @@ KIBANA_URL=https://elastic:changeme@localhost:5601 # create email action ACTION_ID_EMAIL=`curl -X POST --insecure --silent \ - $KIBANA_URL/api/actions/action \ + $KIBANA_URL/api/actions/connector \ -H "kbn-xsrf: foo" -H "content-type: application/json" \ -d '{ - "actionTypeId": ".email", + "connector_type_id": ".email", "name": "email for action_param_templates test", "config": { "from": "team-alerting@example.com", @@ -41,10 +41,10 @@ echo "email action id: $ACTION_ID_EMAIL" # create slack action ACTION_ID_SLACK=`curl -X POST --insecure --silent \ - $KIBANA_URL/api/actions/action \ + $KIBANA_URL/api/actions/connector \ -H "kbn-xsrf: foo" -H "content-type: application/json" \ -d "{ - \"actionTypeId\": \".slack\", + \"connector_type_id\": \".slack\", \"name\": \"slack for action_param_templates test\", \"config\": { }, @@ -56,10 +56,10 @@ echo "slack action id: $ACTION_ID_SLACK" # create webhook action ACTION_ID_WEBHOOK=`curl -X POST --insecure --silent \ - $KIBANA_URL/api/actions/action \ + $KIBANA_URL/api/actions/connector \ -H "kbn-xsrf: foo" -H "content-type: application/json" \ -d "{ - \"actionTypeId\": \".webhook\", + \"connector_type_id\": \".webhook\", \"name\": \"webhook for action_param_templates test\", \"config\": { \"url\": \"$SLACK_WEBHOOKURL\", @@ -108,7 +108,7 @@ ALERT_ID=`curl -X POST --insecure --silent \ } ], \"params\": { - \"index\": [\".kibana\"], + \"index\": [\".kibana\"], \"timeField\": \"updated_at\", \"aggType\": \"count\", \"groupBy\": \"all\", diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/archive/archive_maintenance_window_route.test.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/archive/archive_maintenance_window_route.test.ts index a1f06715eb4ce..1e8d159c17860 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/archive/archive_maintenance_window_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/archive/archive_maintenance_window_route.test.ts @@ -71,7 +71,6 @@ describe('archiveMaintenanceWindowRoute', () => { archive: true, }); expect(res.ok).toHaveBeenLastCalledWith({ - // @ts-expect-error upgrade typescript v5.1.6 body: rewritePartialMaintenanceBodyRes(mockMaintenanceWindow), }); }); diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.test.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.test.ts index bb1ff6b0e6ae6..99c1cf7b23f6a 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.test.ts @@ -22,6 +22,9 @@ jest.mock('../../../../lib/license_api_access', () => ({ })); const mockMaintenanceWindows = { + page: 1, + perPage: 3, + total: 2, data: [ { ...getMockMaintenanceWindow(), @@ -67,12 +70,54 @@ describe('findMaintenanceWindowsRoute', () => { await handler(context, req, res); - expect(maintenanceWindowClient.find).toHaveBeenCalled(); + expect(maintenanceWindowClient.find).toHaveBeenCalledWith({}); expect(res.ok).toHaveBeenLastCalledWith({ body: { - // @ts-expect-error upgrade typescript v5.1.6 data: mockMaintenanceWindows.data.map((data) => rewriteMaintenanceWindowRes(data)), total: 2, + page: 1, + per_page: 3, + }, + }); + }); + + test('should find the maintenance windows with query', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findMaintenanceWindowsRoute(router, licenseState); + + maintenanceWindowClient.find.mockResolvedValueOnce(mockMaintenanceWindows); + const [config, handler] = router.get.mock.calls[0]; + const [context, req, res] = mockHandlerArguments( + { maintenanceWindowClient }, + { + query: { + page: 1, + per_page: 3, + }, + } + ); + + expect(config.path).toEqual('/internal/alerting/rules/maintenance_window/_find'); + expect(config.options).toMatchInlineSnapshot(` + Object { + "access": "internal", + "tags": Array [ + "access:read-maintenance-window", + ], + } + `); + + await handler(context, req, res); + + expect(maintenanceWindowClient.find).toHaveBeenCalledWith({ page: 1, perPage: 3 }); + expect(res.ok).toHaveBeenLastCalledWith({ + body: { + data: mockMaintenanceWindows.data.map((data) => rewriteMaintenanceWindowRes(data)), + total: 2, + page: 1, + per_page: 3, }, }); }); diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.ts index 7a7fb13160252..1aa4653e3d8d3 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/find_maintenance_windows_route.ts @@ -15,7 +15,15 @@ import { import { MAINTENANCE_WINDOW_API_PRIVILEGES } from '../../../../../common'; import type { FindMaintenanceWindowsResult } from '../../../../application/maintenance_window/methods/find/types'; import type { FindMaintenanceWindowsResponseV1 } from '../../../../../common/routes/maintenance_window/apis/find'; -import { transformMaintenanceWindowToResponseV1 } from '../../transforms'; +import { + findMaintenanceWindowsRequestQuerySchemaV1, + findMaintenanceWindowsResponseBodySchemaV1, + type FindMaintenanceWindowsRequestQueryV1, +} from '../../../../../common/routes/maintenance_window/apis/find'; +import { + transformFindMaintenanceWindowParamsV1, + transformFindMaintenanceWindowResponseV1, +} from './transforms'; export const findMaintenanceWindowsRoute = ( router: IRouter, @@ -24,7 +32,23 @@ export const findMaintenanceWindowsRoute = ( router.get( { path: `${INTERNAL_ALERTING_API_MAINTENANCE_WINDOW_PATH}/_find`, - validate: {}, + validate: { + request: { + query: findMaintenanceWindowsRequestQuerySchemaV1, + }, + response: { + 200: { + body: () => findMaintenanceWindowsResponseBodySchemaV1, + description: 'Indicates a successful call.', + }, + 400: { + description: 'Indicates an invalid schema or parameters.', + }, + 403: { + description: 'Indicates that this call is forbidden.', + }, + }, + }, options: { access: 'internal', tags: [`access:${MAINTENANCE_WINDOW_API_PRIVILEGES.READ_MAINTENANCE_WINDOW}`], @@ -34,20 +58,17 @@ export const findMaintenanceWindowsRoute = ( verifyAccessAndContext(licenseState, async function (context, req, res) { licenseState.ensureLicenseForMaintenanceWindow(); + const query: FindMaintenanceWindowsRequestQueryV1 = req.query || {}; const maintenanceWindowClient = (await context.alerting).getMaintenanceWindowClient(); - const result: FindMaintenanceWindowsResult = await maintenanceWindowClient.find(); - - const response: FindMaintenanceWindowsResponseV1 = { - body: { - data: result.data.map((maintenanceWindow) => - transformMaintenanceWindowToResponseV1(maintenanceWindow) - ), - total: result.data.length, - }, - }; + const options = transformFindMaintenanceWindowParamsV1(query); + const findResult: FindMaintenanceWindowsResult = await maintenanceWindowClient.find( + options + ); + const responseBody: FindMaintenanceWindowsResponseV1 = + transformFindMaintenanceWindowResponseV1(findResult); - return res.ok(response); + return res.ok({ body: responseBody }); }) ) ); diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/index.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/index.ts new file mode 100644 index 0000000000000..43d428f9dd47a --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { transformFindMaintenanceWindowParams } from './transform_find_maintenance_window_params/latest'; +export { transformFindMaintenanceWindowResponse } from './transform_find_maintenance_window_to_response/latest'; + +export { transformFindMaintenanceWindowParams as transformFindMaintenanceWindowParamsV1 } from './transform_find_maintenance_window_params/v1'; +export { transformFindMaintenanceWindowResponse as transformFindMaintenanceWindowResponseV1 } from './transform_find_maintenance_window_to_response/v1'; diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_params/latest.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_params/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_params/latest.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './v1'; diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_params/v1.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_params/v1.ts new file mode 100644 index 0000000000000..c59f5d189716e --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_params/v1.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FindMaintenanceWindowsRequestQuery } from '../../../../../../../common/routes/maintenance_window/apis/find'; +import { FindMaintenanceWindowsParams } from '../../../../../../application/maintenance_window/methods/find/types'; + +export const transformFindMaintenanceWindowParams = ( + params: FindMaintenanceWindowsRequestQuery +): FindMaintenanceWindowsParams => ({ + ...(params.page ? { page: params.page } : {}), + ...(params.per_page ? { perPage: params.per_page } : {}), +}); diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_to_response/latest.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_to_response/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_to_response/latest.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './v1'; diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_to_response/v1.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_to_response/v1.ts new file mode 100644 index 0000000000000..9110914a998ca --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/find/transforms/transform_find_maintenance_window_to_response/v1.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { transformMaintenanceWindowToResponseV1 } from '../../../../transforms'; +import type { FindMaintenanceWindowsResponseV1 } from '../../../../../../../common/routes/maintenance_window/apis/find'; +import type { MaintenanceWindow } from '../../../../../../application/maintenance_window/types'; +import type { FindMaintenanceWindowsResult } from '../../../../../../application/maintenance_window/methods/find/types'; + +export const transformFindMaintenanceWindowResponse = ( + result: FindMaintenanceWindowsResult +): FindMaintenanceWindowsResponseV1 => { + return { + page: result.page, + per_page: result.perPage, + total: result.total, + data: result.data.map((maintenanceWindow: MaintenanceWindow) => + transformMaintenanceWindowToResponseV1(maintenanceWindow) + ), + }; +}; diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/finish/finish_maintenance_window_route.test.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/finish/finish_maintenance_window_route.test.ts index cfab8e5ede692..aa659a30c9b6c 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/finish/finish_maintenance_window_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/finish/finish_maintenance_window_route.test.ts @@ -61,7 +61,6 @@ describe('finishMaintenanceWindowRoute', () => { expect(maintenanceWindowClient.finish).toHaveBeenLastCalledWith({ id: 'test-id' }); expect(res.ok).toHaveBeenLastCalledWith({ - // @ts-expect-error upgrade typescript v5.1.6 body: rewritePartialMaintenanceBodyRes(mockMaintenanceWindow), }); }); diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/get/get_maintenance_window_route.test.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/get/get_maintenance_window_route.test.ts index f0dd021078314..e6d2eb585a3da 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/get/get_maintenance_window_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/get/get_maintenance_window_route.test.ts @@ -61,7 +61,6 @@ describe('getMaintenanceWindowRoute', () => { expect(maintenanceWindowClient.get).toHaveBeenLastCalledWith({ id: 'test-id' }); expect(res.ok).toHaveBeenLastCalledWith({ - // @ts-expect-error upgrade typescript v5.1.6 body: rewritePartialMaintenanceBodyRes(mockMaintenanceWindow), }); }); diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/get_active/get_active_maintenance_windows_route.test.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/get_active/get_active_maintenance_windows_route.test.ts index f9b83997d75a6..3ec493ec85136 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/get_active/get_active_maintenance_windows_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/get_active/get_active_maintenance_windows_route.test.ts @@ -69,7 +69,6 @@ describe('getActiveMaintenanceWindowsRoute', () => { expect(maintenanceWindowClient.getActiveMaintenanceWindows).toHaveBeenCalled(); expect(res.ok).toHaveBeenLastCalledWith({ - // @ts-expect-error upgrade typescript v5.1.6 body: mockMaintenanceWindows.map((data) => rewriteMaintenanceWindowRes(data)), }); }); diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/update/update_maintenance_window_route.test.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/update/update_maintenance_window_route.test.ts index 37c912b69afcb..194366c8b76d0 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/update/update_maintenance_window_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/update/update_maintenance_window_route.test.ts @@ -82,7 +82,6 @@ describe('updateMaintenanceWindowRoute', () => { }); expect(res.ok).toHaveBeenLastCalledWith({ - // @ts-expect-error upgrade typescript v5.1.6 body: rewritePartialMaintenanceBodyRes(mockMaintenanceWindow), }); }); diff --git a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts index 43e8a4b2b9ea6..c1ef6af4f36b0 100644 --- a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts @@ -30,7 +30,7 @@ export const transformMonitoring = (monitoring: Monitoring): MonitoringV1 => { success: history.success, timestamp: history.timestamp, ...(history.duration !== undefined ? { duration: history.duration } : {}), - ...(history.outcome ? { outcome: transformRuleLastRun(history.outcome) } : {}), + ...(history.outcome !== undefined ? { outcome: history.outcome } : {}), })), calculated_metrics: monitoring.run.calculated_metrics, last_run: monitoring.run.last_run, diff --git a/x-pack/plugins/alerting/server/rules_client/common/inject_references.ts b/x-pack/plugins/alerting/server/rules_client/common/inject_references.ts index 2938c91372325..867a6d7044c39 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/inject_references.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/inject_references.ts @@ -10,7 +10,6 @@ import { omit } from 'lodash'; import { SavedObjectReference, SavedObjectAttributes } from '@kbn/core/server'; import { UntypedNormalizedRuleType } from '../../rule_type_registry'; import { RawRule, RuleTypeParams } from '../../types'; -import { RuleActionAttributes } from '../../data/rule/types'; import { preconfiguredConnectorActionRefPrefix, extractedSavedObjectParamReferenceNamePrefix, @@ -19,7 +18,7 @@ import { export function injectReferencesIntoActions( alertId: string, - actions: RawRule['actions'] | RuleActionAttributes[], + actions: RawRule['actions'], references: SavedObjectReference[] ) { return actions.map((action) => { diff --git a/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.ts b/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.ts index 86e3897183849..20f32e483890d 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.ts @@ -12,24 +12,24 @@ import { Logger, SavedObjectsBulkUpdateObject, SavedObjectsUpdateResponse } from import { BulkActionSkipResult } from '../../../common/bulk_edit'; import { convertRuleIdsToKueryNode } from '../../lib'; import { BulkOperationError } from '../types'; -import { RuleAttributes } from '../../data/rule/types'; import { waitBeforeNextRetry, RETRY_IF_CONFLICTS_ATTEMPTS } from './wait_before_next_retry'; import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; +import { RawRule } from '../../types'; // max number of failed SO ids in one retry filter const MaxIdsNumberInRetryFilter = 1000; type BulkEditOperation = (filter: KueryNode | null) => Promise<{ apiKeysToInvalidate: string[]; - rules: Array>; - resultSavedObjects: Array>; + rules: Array>; + resultSavedObjects: Array>; errors: BulkOperationError[]; skipped: BulkActionSkipResult[]; }>; interface ReturnRetry { apiKeysToInvalidate: string[]; - results: Array>; + results: Array>; errors: BulkOperationError[]; skipped: BulkActionSkipResult[]; } @@ -55,7 +55,7 @@ export const retryIfBulkEditConflicts = async ( filter: KueryNode | null, retries: number = RETRY_IF_CONFLICTS_ATTEMPTS, accApiKeysToInvalidate: string[] = [], - accResults: Array> = [], + accResults: Array> = [], accErrors: BulkOperationError[] = [], accSkipped: BulkActionSkipResult[] = [] ): Promise => { diff --git a/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_operation_conflicts.ts b/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_operation_conflicts.ts index 7a652c5230f47..428f43a0dcfa6 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_operation_conflicts.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_operation_conflicts.ts @@ -13,13 +13,13 @@ import { withSpan } from '@kbn/apm-utils'; import { convertRuleIdsToKueryNode } from '../../lib'; import { BulkOperationError } from '../types'; import { waitBeforeNextRetry, RETRY_IF_CONFLICTS_ATTEMPTS } from './wait_before_next_retry'; -import { RuleAttributes } from '../../data/rule/types'; +import { RawRule } from '../../types'; const MAX_RULES_IDS_IN_RETRY = 1000; interface BulkOperationResult { errors: BulkOperationError[]; - rules: Array>; + rules: Array>; accListSpecificForBulkOperation: string[][]; } @@ -63,7 +63,7 @@ const handler = async ({ filter: KueryNode | null; accListSpecificForBulkOperation?: string[][]; accErrors?: BulkOperationError[]; - accRules?: Array>; + accRules?: Array>; retries?: number; }): Promise => { try { diff --git a/x-pack/plugins/alerting/server/rules_client/common/snooze_utils.ts b/x-pack/plugins/alerting/server/rules_client/common/snooze_utils.ts index dc6ecec0342ab..6e8e08bb3827f 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/snooze_utils.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/snooze_utils.ts @@ -12,13 +12,10 @@ import { RuleParams, RuleSnoozeSchedule as RuleDomainSnoozeSchedule, } from '../../application/rule/types'; -import { RuleAttributes } from '../../data/rule/types'; import { getActiveScheduledSnoozes } from '../../lib/is_rule_snoozed'; +import { RawRule } from '../../types'; -export function getSnoozeAttributes( - attributes: RuleAttributes, - snoozeSchedule: RuleDomainSnoozeSchedule -) { +export function getSnoozeAttributes(attributes: RawRule, snoozeSchedule: RuleDomainSnoozeSchedule) { // If duration is -1, instead mute all const { id: snoozeId, duration } = snoozeSchedule; @@ -70,7 +67,7 @@ export function getBulkSnooze( }; } -export function getUnsnoozeAttributes(attributes: RuleAttributes, scheduleIds?: string[]) { +export function getUnsnoozeAttributes(attributes: RawRule, scheduleIds?: string[]) { const snoozeSchedule = scheduleIds ? clearScheduledSnoozesAttributesById(attributes, scheduleIds) : clearCurrentActiveSnoozeAttributes(attributes); @@ -104,7 +101,7 @@ export function getBulkUnsnooze( }; } -export function clearUnscheduledSnoozeAttributes(attributes: RuleAttributes) { +export function clearUnscheduledSnoozeAttributes(attributes: RawRule) { // Clear any snoozes that have no ID property. These are "simple" snoozes created with the quick UI, e.g. snooze for 3 days starting now return attributes.snoozeSchedule ? attributes.snoozeSchedule.filter((s) => typeof s.id !== 'undefined') @@ -115,7 +112,7 @@ export function clearUnscheduledSnooze(rule: RuleDoma return rule.snoozeSchedule ? rule.snoozeSchedule.filter((s) => typeof s.id !== 'undefined') : []; } -export function clearScheduledSnoozesAttributesById(attributes: RuleAttributes, ids: string[]) { +export function clearScheduledSnoozesAttributesById(attributes: RawRule, ids: string[]) { return attributes.snoozeSchedule ? attributes.snoozeSchedule.filter((s) => !(s.id && ids.includes(s.id))) : []; @@ -128,11 +125,10 @@ export function clearScheduledSnoozesById( return rule.snoozeSchedule ? rule.snoozeSchedule.filter((s) => s.id && !ids.includes(s.id)) : []; } -export function clearCurrentActiveSnoozeAttributes(attributes: RuleAttributes) { +export function clearCurrentActiveSnoozeAttributes(attributes: RawRule) { // First attempt to cancel a simple (unscheduled) snooze const clearedUnscheduledSnoozes = clearUnscheduledSnoozeAttributes(attributes); // Now clear any scheduled snoozes that are currently active and never recur - // @ts-expect-error upgrade typescript v5.1.6 const activeSnoozes = getActiveScheduledSnoozes(attributes); const activeSnoozeIds = activeSnoozes?.map((s) => s.id) ?? []; const recurringSnoozesToSkip: string[] = []; @@ -160,7 +156,6 @@ export function clearCurrentActiveSnooze(rule: RuleDo // First attempt to cancel a simple (unscheduled) snooze const clearedUnscheduledSnoozes = clearUnscheduledSnooze(rule); // Now clear any scheduled snoozes that are currently active and never recur - // @ts-expect-error upgrade typescript v5.1.6 const activeSnoozes = getActiveScheduledSnoozes(rule); const activeSnoozeIds = activeSnoozes?.map((s) => s.id) ?? []; const recurringSnoozesToSkip: string[] = []; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/create_rule_saved_object.ts b/x-pack/plugins/alerting/server/rules_client/lib/create_rule_saved_object.ts index 644ad0626de6a..12a81c742f242 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/create_rule_saved_object.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/create_rule_saved_object.ts @@ -8,7 +8,6 @@ import { SavedObjectReference, SavedObject } from '@kbn/core/server'; import { withSpan } from '@kbn/apm-utils'; import { Rule, RuleWithLegacyId, RawRule, RuleTypeParams } from '../../types'; -import { RuleAttributes } from '../../data/rule/types'; import { bulkMarkApiKeysForInvalidation } from '../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { SavedObjectOptions } from '../types'; @@ -30,7 +29,7 @@ interface CreateRuleSavedObjectParams { interface CreateRuleSavedObjectAttributeParams { intervalInMs: number; - rawRule: RuleAttributes; + rawRule: RawRule; references: SavedObjectReference[]; ruleId: string; options?: SavedObjectOptions; @@ -46,11 +45,11 @@ export async function createRuleSavedObject( context: RulesClientContext, params: CreateRuleSavedObjectAttributeParams -): Promise>; +): Promise>; export async function createRuleSavedObject( context: RulesClientContext, params: CreateRuleSavedObjectParams | CreateRuleSavedObjectAttributeParams -): Promise | RuleWithLegacyId | SavedObject> { +): Promise | RuleWithLegacyId | SavedObject> { const { intervalInMs, rawRule, references, ruleId, options, returnRuleAttributes } = params; context.auditLogger?.log( @@ -61,14 +60,13 @@ export async function createRuleSavedObject; try { - createdAlert = (await withSpan( + createdAlert = await withSpan( { name: 'unsecuredSavedObjectsClient.create', type: 'rules' }, () => createRuleSo({ - ruleAttributes: updateMeta(context, rawRule as RawRule) as RuleAttributes, + ruleAttributes: updateMeta(context, rawRule), savedObjectsClient: context.unsecuredSavedObjectsClient, savedObjectsCreateOptions: { ...options, @@ -76,7 +74,7 @@ export async function createRuleSavedObject; + ); } catch (e) { // Avoid unused API key await bulkMarkApiKeysForInvalidation( @@ -138,7 +136,7 @@ export async function createRuleSavedObject; + return createdAlert as SavedObject; } return getAlertFromRaw({ diff --git a/x-pack/plugins/alerting/server/rules_client/lib/get_rule_saved_object.ts b/x-pack/plugins/alerting/server/rules_client/lib/get_rule_saved_object.ts index 18af10e677f3a..81952cfc938e1 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/get_rule_saved_object.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/get_rule_saved_object.ts @@ -10,8 +10,8 @@ import { withSpan } from '@kbn/apm-utils'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; import { getRuleSo } from '../../data/rule'; -import { RuleAttributes } from '../../data/rule/types'; import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; +import { RawRule } from '../../types'; interface GetRuleSavedObjectParams { ruleId: string; @@ -20,7 +20,7 @@ interface GetRuleSavedObjectParams { export async function getRuleSavedObject( context: RulesClientContext, params: GetRuleSavedObjectParams -): Promise> { +): Promise> { const { ruleId } = params; context.auditLogger?.log( diff --git a/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.test.ts index 7c650160100bd..766bbdf267652 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.test.ts @@ -8,13 +8,12 @@ import { mockedDateString } from '../tests/lib'; import { incrementRevision } from './increment_revision'; import { SavedObject } from '@kbn/core/server'; -import { RuleTypeParams } from '../../types'; +import { RawRule, RuleTypeParams } from '../../types'; import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; import { UpdateRuleData } from '../../application/rule/methods/update'; -import { RuleAttributes } from '../../data/rule/types'; describe('incrementRevision', () => { - const currentRule: SavedObject = { + const currentRule: SavedObject = { id: '1', type: RULE_SAVED_OBJECT_TYPE, attributes: { diff --git a/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.ts b/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.ts index dd6defdb3625b..e26d719d59127 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.ts @@ -6,17 +6,16 @@ */ import { get, isEqual } from 'lodash'; -import { RuleTypeParams } from '../../types'; +import { RuleTypeParams, RawRule } from '../../types'; import { fieldsToExcludeFromRevisionUpdates } from '..'; import { UpdateRuleData } from '../../application/rule/methods/update'; -import { RuleAttributes } from '../../data/rule/types'; export function incrementRevision({ originalRule, updateRuleData, updatedParams, }: { - originalRule: RuleAttributes; + originalRule: RawRule; updateRuleData: UpdateRuleData; updatedParams: RuleTypeParams; }): number { diff --git a/x-pack/plugins/alerting/server/rules_client/lib/resolve_rule_saved_object.ts b/x-pack/plugins/alerting/server/rules_client/lib/resolve_rule_saved_object.ts index f133aea9035a0..a32f86926c400 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/resolve_rule_saved_object.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/resolve_rule_saved_object.ts @@ -10,8 +10,8 @@ import { withSpan } from '@kbn/apm-utils'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; import { resolveRuleSo } from '../../data/rule'; -import { RuleAttributes } from '../../data/rule/types'; import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; +import { RawRule } from '../../types'; interface ResolveRuleSavedObjectParams { ruleId: string; @@ -20,7 +20,7 @@ interface ResolveRuleSavedObjectParams { export async function resolveRuleSavedObject( context: RulesClientContext, params: ResolveRuleSavedObjectParams -): Promise> { +): Promise> { const { ruleId } = params; context.auditLogger?.log( diff --git a/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts b/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts index be168b6d9f02e..0e2063a3738ad 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts @@ -8,19 +8,18 @@ import { mapValues } from 'lodash'; import { SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/server'; import { withSpan } from '@kbn/apm-utils'; -import { SanitizedRule, RawAlertInstance as RawAlert } from '../../types'; +import { SanitizedRule, RawAlertInstance as RawAlert, RawRule } from '../../types'; import { taskInstanceToAlertTaskInstance } from '../../task_runner/alert_task_instance'; import { Alert } from '../../alert'; import { EVENT_LOG_ACTIONS } from '../../plugin'; import { createAlertEventLogRecordObject } from '../../lib/create_alert_event_log_record_object'; import { RulesClientContext } from '../types'; -import { RuleAttributes } from '../../data/rule/types'; import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export const untrackRuleAlerts = async ( context: RulesClientContext, id: string, - attributes: RuleAttributes + attributes: RawRule ) => { return withSpan({ name: 'untrackRuleAlerts', type: 'rules' }, async () => { if (!context.eventLogger || !attributes.scheduledTaskId) return; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/update_meta.ts b/x-pack/plugins/alerting/server/rules_client/lib/update_meta.ts index 635778b5a5a1a..1f87dd0e2d6ee 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/update_meta.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/update_meta.ts @@ -16,8 +16,13 @@ export function updateMeta>( alertAttributes: T ): T { if (Object.hasOwn(alertAttributes, 'apiKey') || Object.hasOwn(alertAttributes, 'apiKeyOwner')) { - alertAttributes.meta = alertAttributes.meta ?? {}; - alertAttributes.meta.versionApiKeyLastmodified = context.kibanaVersion; + return { + ...alertAttributes, + meta: { + ...(alertAttributes.meta ?? {}), + versionApiKeyLastmodified: context.kibanaVersion, + }, + }; } return alertAttributes; } diff --git a/x-pack/plugins/alerting/server/rules_client/lib/update_meta_attributes.ts b/x-pack/plugins/alerting/server/rules_client/lib/update_meta_attributes.ts index 9570539b24046..f3c5ed48839ce 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/update_meta_attributes.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/update_meta_attributes.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RuleAttributes } from '../../data/rule/types'; +import { RawRule } from '../../types'; import { RulesClientContext } from '../types'; -export function updateMetaAttributes>( +export function updateMetaAttributes>( context: RulesClientContext, alertAttributes: T ): T { diff --git a/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts b/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts index 43f477f1530d2..33b1bfd315769 100644 --- a/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts +++ b/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts @@ -6,7 +6,7 @@ */ import { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; -import { rawRuleSchemaV1, rawRuleSchemaV2 } from '../schemas/raw_rule'; +import { rawRuleSchemaV1, rawRuleSchemaV2, rawRuleSchemaV3 } from '../schemas/raw_rule'; export const ruleModelVersions: SavedObjectsModelVersionMap = { '1': { @@ -23,4 +23,11 @@ export const ruleModelVersions: SavedObjectsModelVersionMap = { create: rawRuleSchemaV2, }, }, + '3': { + changes: [], + schemas: { + forwardCompatibility: rawRuleSchemaV3.extends({}, { unknowns: 'ignore' }), + create: rawRuleSchemaV3, + }, + }, }; diff --git a/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.test.ts b/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.test.ts index 5e53834bf73d8..1bbf7aa448fd4 100644 --- a/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.test.ts @@ -228,7 +228,7 @@ const DefaultAttributes = { const ExtraneousAttributes = { ...DefaultAttributes, foo: 'bar' }; -const DefaultAttributesForEsUpdate = { +const DefaultAttributesForEsUpdate: PartiallyUpdateableRuleAttributes = { running: false, executionStatus: { status: 'active' as RuleExecutionStatuses, @@ -247,7 +247,7 @@ const DefaultAttributesForEsUpdate = { success: true, timestamp: 1640991880000, duration: 12, - outcome: 'success', + outcome: 'succeeded', }, ], last_run: { diff --git a/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.ts b/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.ts index 24af1da5af62b..4ef0779707536 100644 --- a/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.ts +++ b/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.ts @@ -22,13 +22,9 @@ import { RuleAttributesNotPartiallyUpdatable, RULE_SAVED_OBJECT_TYPE, } from '.'; -import { RuleAttributes } from '../data/rule/types'; -// We have calling code that references both RawRule and RuleAttributes, -// so we need to support both of these types (they are effectively the same) export type PartiallyUpdateableRuleAttributes = Partial< - | Omit - | Omit + Omit >; interface PartiallyUpdateRuleSavedObjectOptions { @@ -54,7 +50,7 @@ export async function partiallyUpdateRule( ...RuleAttributesToEncrypt, ...RuleAttributesIncludedInAAD, ]); - const updateOptions: SavedObjectsUpdateOptions = pick( + const updateOptions: SavedObjectsUpdateOptions = pick( options, 'namespace', 'version', diff --git a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts index f770a5418cde7..c38a80601dc48 100644 --- a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts @@ -5,5 +5,8 @@ * 2.0. */ +export * from './latest'; + export { rawRuleSchema as rawRuleSchemaV1 } from './v1'; export { rawRuleSchema as rawRuleSchemaV2 } from './v2'; +export { rawRuleSchema as rawRuleSchemaV3 } from './v3'; diff --git a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/latest.ts b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/latest.ts new file mode 100644 index 0000000000000..dded0a98f6d53 --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/latest.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { TypeOf } from '@kbn/config-schema'; + +import { + rawRuleExecutionStatusSchema, + rawRuleActionSchema, + rawRuleAlertsFilterSchema, + rawRuleLastRunSchema, + rawRuleMonitoringSchema, + rawRuleSchema, +} from './v3'; + +type Mutable = { -readonly [P in keyof T]: T[P] extends object ? Mutable : T[P] }; + +export type RawRuleAction = Mutable>; +export type RawRuleExecutionStatus = Mutable>; +export type RawRuleAlertsFilter = Mutable>; +export type RawRuleLastRun = Mutable>; +export type RawRuleMonitoring = Mutable>; +export type RawRule = Mutable>; diff --git a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v2.ts b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v2.ts index 4474c47e9e770..51a4701caaf4a 100644 --- a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v2.ts +++ b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v2.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { rawRuleSchema as rawRuleSchemaV1 } from './v1'; +export * from './v1'; export const flappingSchema = schema.object({ lookBackWindow: schema.number(), diff --git a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v3.ts b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v3.ts new file mode 100644 index 0000000000000..2e07c73e1537a --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v3.ts @@ -0,0 +1,299 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { FilterStateStore } from '@kbn/es-query'; +import { + RuleExecutionStatusErrorReasons, + RuleExecutionStatusWarningReasons, +} from '@kbn/alerting-types'; +import { ruleLastRunOutcomeValues } from '../../../application/rule/constants'; + +export * from './v2'; + +export const executionStatusWarningReason = schema.oneOf([ + schema.literal(RuleExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS), // change + schema.literal(RuleExecutionStatusWarningReasons.MAX_ALERTS), // change + schema.literal(RuleExecutionStatusWarningReasons.MAX_QUEUED_ACTIONS), // change + schema.literal(RuleExecutionStatusWarningReasons.EXECUTION), // change +]); + +export const executionStatusErrorReason = schema.oneOf([ + schema.literal(RuleExecutionStatusErrorReasons.Read), // change + schema.literal(RuleExecutionStatusErrorReasons.Decrypt), // change + schema.literal(RuleExecutionStatusErrorReasons.Execute), // change + schema.literal(RuleExecutionStatusErrorReasons.Unknown), // change + schema.literal(RuleExecutionStatusErrorReasons.License), // change + schema.literal(RuleExecutionStatusErrorReasons.Timeout), // change + schema.literal(RuleExecutionStatusErrorReasons.Disabled), // change + schema.literal(RuleExecutionStatusErrorReasons.Validate), // change +]); + +export const rawRuleExecutionStatusSchema = schema.object({ + status: schema.oneOf([ + schema.literal('ok'), + schema.literal('active'), + schema.literal('error'), + schema.literal('pending'), + schema.literal('unknown'), + schema.literal('warning'), + ]), + lastExecutionDate: schema.string(), + lastDuration: schema.maybe(schema.number()), + error: schema.nullable( + schema.object({ + reason: executionStatusErrorReason, + message: schema.string(), + }) + ), + warning: schema.nullable( + schema.object({ + reason: executionStatusWarningReason, + message: schema.string(), + }) + ), +}); + +export const ISOWeekdaysSchema = schema.oneOf([ + schema.literal(1), + schema.literal(2), + schema.literal(3), + schema.literal(4), + schema.literal(5), + schema.literal(6), + schema.literal(7), +]); + +export const rRuleSchema = schema.object({ + dtstart: schema.string(), + tzid: schema.string(), + freq: schema.maybe( + schema.oneOf([ + schema.literal(0), + schema.literal(1), + schema.literal(2), + schema.literal(3), + schema.literal(4), + schema.literal(5), + schema.literal(6), + ]) + ), + until: schema.maybe(schema.string()), + count: schema.maybe(schema.number()), + interval: schema.maybe(schema.number()), + wkst: schema.maybe( + schema.oneOf([ + schema.literal('MO'), + schema.literal('TU'), + schema.literal('WE'), + schema.literal('TH'), + schema.literal('FR'), + schema.literal('SA'), + schema.literal('SU'), + ]) + ), + byweekday: schema.maybe( + schema.nullable(schema.arrayOf(schema.oneOf([schema.string(), schema.number()]))) // change + ), + bymonth: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), // change + bysetpos: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), // change + bymonthday: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), // change + byyearday: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), // change + byweekno: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), // change + byhour: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), // change + byminute: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), // change + bysecond: schema.maybe(schema.nullable(schema.arrayOf(schema.number()))), // change +}); + +export const outcome = schema.oneOf([ + schema.literal(ruleLastRunOutcomeValues.SUCCEEDED), // change + schema.literal(ruleLastRunOutcomeValues.WARNING), // change + schema.literal(ruleLastRunOutcomeValues.FAILED), // change +]); + +export const rawRuleLastRunSchema = schema.object({ + outcome, + outcomeOrder: schema.maybe(schema.number()), + alertsCount: schema.object({ + new: schema.maybe(schema.nullable(schema.number())), + active: schema.maybe(schema.nullable(schema.number())), + recovered: schema.maybe(schema.nullable(schema.number())), + ignored: schema.maybe(schema.nullable(schema.number())), + }), + outcomeMsg: schema.maybe(schema.nullable(schema.arrayOf(schema.string()))), + warning: schema.maybe( + schema.nullable(schema.oneOf([executionStatusErrorReason, executionStatusWarningReason])) + ), +}); + +export const rawRuleMonitoringSchema = schema.object({ + run: schema.object({ + history: schema.arrayOf( + schema.object({ + success: schema.boolean(), + timestamp: schema.number(), + duration: schema.maybe(schema.number()), + outcome: schema.maybe(outcome), + }) + ), + calculated_metrics: schema.object({ + p50: schema.maybe(schema.number()), + p95: schema.maybe(schema.number()), + p99: schema.maybe(schema.number()), + success_ratio: schema.number(), + }), + last_run: schema.object({ + timestamp: schema.string(), + metrics: schema.object({ + duration: schema.maybe(schema.number()), + total_search_duration_ms: schema.maybe(schema.nullable(schema.number())), + total_indexing_duration_ms: schema.maybe(schema.nullable(schema.number())), + total_alerts_detected: schema.maybe(schema.nullable(schema.number())), + total_alerts_created: schema.maybe(schema.nullable(schema.number())), + gap_duration_s: schema.maybe(schema.nullable(schema.number())), + }), + }), + }), +}); + +export const rawRuleAlertsFilterSchema = schema.object({ + query: schema.maybe( + schema.object({ + kql: schema.string(), + filters: schema.arrayOf( + schema.object({ + query: schema.maybe(schema.recordOf(schema.string(), schema.any())), + meta: schema.object({ + alias: schema.maybe(schema.nullable(schema.string())), + disabled: schema.maybe(schema.boolean()), + negate: schema.maybe(schema.boolean()), + controlledBy: schema.maybe(schema.string()), + group: schema.maybe(schema.string()), + index: schema.maybe(schema.string()), + isMultiIndex: schema.maybe(schema.boolean()), + type: schema.maybe(schema.string()), + key: schema.maybe(schema.string()), + params: schema.maybe(schema.any()), + value: schema.maybe(schema.string()), + field: schema.maybe(schema.string()), + relation: schema.maybe(schema.oneOf([schema.literal('OR'), schema.literal('AND')])), + }), + $state: schema.maybe( + schema.object({ + store: schema.oneOf([ + schema.literal(FilterStateStore.APP_STATE), // change + schema.literal(FilterStateStore.GLOBAL_STATE), // change + ]), + }) + ), + }) + ), + dsl: schema.string(), // change + }) + ), + timeframe: schema.maybe( + schema.object({ + days: schema.arrayOf(ISOWeekdaysSchema), + hours: schema.object({ + start: schema.string(), + end: schema.string(), + }), + timezone: schema.string(), + }) + ), +}); + +export const rawRuleActionSchema = schema.object({ + uuid: schema.string(), // change + group: schema.maybe(schema.string()), + actionRef: schema.string(), + actionTypeId: schema.string(), + params: schema.recordOf(schema.string(), schema.any()), + frequency: schema.maybe( + schema.object({ + summary: schema.boolean(), + notifyWhen: schema.oneOf([ + schema.literal('onActionGroupChange'), + schema.literal('onActiveAlert'), + schema.literal('onThrottleInterval'), + ]), + throttle: schema.nullable(schema.string()), + }) + ), + alertsFilter: schema.maybe(rawRuleAlertsFilterSchema), + useAlertDataForTemplate: schema.maybe(schema.boolean()), +}); + +export const alertDelaySchema = schema.object({ + active: schema.number(), +}); + +export const flappingSchema = schema.object({ + lookBackWindow: schema.number(), + statusChangeThreshold: schema.number(), +}); + +export const rawRuleSchema = schema.object({ + name: schema.string(), + enabled: schema.boolean(), + consumer: schema.string(), + tags: schema.arrayOf(schema.string()), + alertTypeId: schema.string(), + apiKeyOwner: schema.nullable(schema.string()), + apiKey: schema.nullable(schema.string()), + apiKeyCreatedByUser: schema.maybe(schema.nullable(schema.boolean())), + createdBy: schema.nullable(schema.string()), + updatedBy: schema.nullable(schema.string()), + updatedAt: schema.string(), + createdAt: schema.string(), + muteAll: schema.boolean(), + mutedInstanceIds: schema.arrayOf(schema.string()), + throttle: schema.maybe(schema.nullable(schema.string())), + revision: schema.number(), + running: schema.maybe(schema.nullable(schema.boolean())), + schedule: schema.object({ + interval: schema.string(), + }), + legacyId: schema.nullable(schema.string()), + scheduledTaskId: schema.maybe(schema.nullable(schema.string())), + isSnoozedUntil: schema.maybe(schema.nullable(schema.string())), + snoozeSchedule: schema.maybe( + schema.arrayOf( + schema.object({ + duration: schema.number(), + rRule: rRuleSchema, + id: schema.maybe(schema.string()), + skipRecurrences: schema.maybe(schema.arrayOf(schema.string())), + }) + ) + ), + meta: schema.maybe(schema.object({ versionApiKeyLastmodified: schema.maybe(schema.string()) })), + actions: schema.arrayOf(rawRuleActionSchema), + executionStatus: rawRuleExecutionStatusSchema, + notifyWhen: schema.maybe( + schema.nullable( + schema.oneOf([ + schema.literal('onActionGroupChange'), + schema.literal('onActiveAlert'), + schema.literal('onThrottleInterval'), + ]) + ) + ), + monitoring: schema.maybe(rawRuleMonitoringSchema), + lastRun: schema.maybe(schema.nullable(rawRuleLastRunSchema)), + nextRun: schema.maybe(schema.nullable(schema.string())), + mapped_params: schema.maybe( + schema.object({ + risk_score: schema.maybe(schema.number()), + severity: schema.maybe(schema.string()), + }) + ), + params: schema.recordOf(schema.string(), schema.maybe(schema.any())), + typeVersion: schema.maybe(schema.number()), + alertDelay: schema.maybe(alertDelaySchema), + flapping: schema.maybe(schema.nullable(flappingSchema)), // carry over from v2 +}); diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index 656f567219c1d..b660d348b9e06 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -26,7 +26,6 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { SharePluginStart } from '@kbn/share-plugin/server'; import type { DefaultAlert, FieldMap } from '@kbn/alerts-as-data-utils'; import { Alert } from '@kbn/alerts-as-data-utils'; -import { Filter } from '@kbn/es-query'; import { ActionsApiRequestHandlerContext } from '@kbn/actions-plugin/server'; import { AlertsHealth } from '@kbn/alerting-types'; import { RuleTypeRegistry as OrigruleTypeRegistry } from './rule_type_registry'; @@ -43,28 +42,14 @@ import { Rule, RuleTypeParams, RuleTypeState, - RuleActionParams, - RuleExecutionStatuses, - RuleExecutionStatusErrorReasons, - RuleExecutionStatusWarningReasons, - RuleNotifyWhenType, ActionGroup, AlertInstanceContext, AlertInstanceState, WithoutReservedActionGroups, ActionVariable, SanitizedRuleConfig, - RuleMonitoring, - MappedParams, - RuleSnooze, - IntervalSchedule, - RuleLastRun, SanitizedRule, - AlertsFilter, - AlertsFilterTimeframe, RuleAlertData, - AlertDelay, - Flapping, } from '../common'; import { PublicAlertFactory } from './alert/create_alert_factory'; import { RulesSettingsFlappingProperties } from '../common/rules_settings'; @@ -426,87 +411,13 @@ export type PublicRuleMonitoringService = PublicMetricsSetters; export type PublicRuleResultService = PublicLastRunSetters; -export interface RawRuleLastRun extends SavedObjectAttributes, RuleLastRun {} -export interface RawRuleMonitoring extends SavedObjectAttributes, RuleMonitoring {} - -export interface RawRuleAlertsFilter extends AlertsFilter { - query?: { - kql: string; - filters: Filter[]; - dsl: string; - }; - timeframe?: AlertsFilterTimeframe; -} - -export interface RawRuleAction extends SavedObjectAttributes { - uuid: string; - group?: string; - actionRef: string; - actionTypeId: string; - params: RuleActionParams; - frequency?: { - summary: boolean; - notifyWhen: RuleNotifyWhenType; - throttle: string | null; - }; - alertsFilter?: RawRuleAlertsFilter; - useAlertDataAsTemplate?: boolean; -} - -// note that the `error` property is "null-able", as we're doing a partial -// update on the rule when we update this data, but need to ensure we -// delete any previous error if the current status has no error -export interface RawRuleExecutionStatus extends SavedObjectAttributes { - status: RuleExecutionStatuses; - lastExecutionDate: string; - lastDuration?: number; - error: null | { - reason: RuleExecutionStatusErrorReasons; - message: string; - }; - warning: null | { - reason: RuleExecutionStatusWarningReasons; - message: string; - }; -} - -/** - * @deprecated in favor of Rule - */ -export interface RawRule extends SavedObjectAttributes { - enabled: boolean; - name: string; - tags: string[]; - alertTypeId: string; // this cannot be renamed since it is in the saved object - consumer: string; - legacyId: string | null; - schedule: IntervalSchedule; - actions: RawRuleAction[]; - params: SavedObjectAttributes; - mapped_params?: MappedParams; - scheduledTaskId?: string | null; - createdBy: string | null; - updatedBy: string | null; - createdAt: string; - updatedAt: string; - apiKey: string | null; - apiKeyOwner: string | null; - apiKeyCreatedByUser?: boolean | null; - throttle?: string | null; - notifyWhen?: RuleNotifyWhenType | null; - muteAll: boolean; - mutedInstanceIds: string[]; - meta?: RuleMeta; - executionStatus: RawRuleExecutionStatus; - monitoring?: RawRuleMonitoring; - snoozeSchedule?: RuleSnooze; // Remove ? when this parameter is made available in the public API - isSnoozedUntil?: string | null; - lastRun?: RawRuleLastRun | null; - nextRun?: string | null; - revision: number; - running?: boolean | null; - alertDelay?: AlertDelay; - flapping?: Flapping | null; -} +export type { + RawRule, + RawRuleAction, + RawRuleExecutionStatus, + RawRuleAlertsFilter, + RawRuleLastRun, + RawRuleMonitoring, +} from './saved_objects/schemas/raw_rule'; export type { DataStreamAdapter } from './alerts_service/lib/data_stream_adapter'; diff --git a/x-pack/plugins/canvas/server/plugin.ts b/x-pack/plugins/canvas/server/plugin.ts index 074d29ec977f9..bf15dd31100ba 100644 --- a/x-pack/plugins/canvas/server/plugin.ts +++ b/x-pack/plugins/canvas/server/plugin.ts @@ -19,7 +19,6 @@ import { ReportingServerPluginSetup } from '@kbn/reporting-server'; import { getCanvasFeature } from './feature'; import { initRoutes } from './routes'; import { registerCanvasUsageCollector } from './collectors'; -import { loadSampleData } from './sample_data'; import { setupInterpreter } from './setup_interpreter'; import { customElementType, workpadTypeFactory, workpadTemplateType } from './saved_objects'; import type { CanvasSavedObjectTypeMigrationsDeps } from './saved_objects/migrations'; @@ -82,11 +81,6 @@ export class CanvasPlugin implements Plugin { logger: this.logger, }); - loadSampleData( - plugins.home.sampleData.addSavedObjectsToSampleDataset, - plugins.home.sampleData.addAppLinksToSampleDataset - ); - const getIndexForType = (type: string) => coreSetup .getStartServices() diff --git a/x-pack/plugins/canvas/server/sample_data/ecommerce_saved_objects.json b/x-pack/plugins/canvas/server/sample_data/ecommerce_saved_objects.json deleted file mode 100644 index be5bc213e59a4..0000000000000 --- a/x-pack/plugins/canvas/server/sample_data/ecommerce_saved_objects.json +++ /dev/null @@ -1,1220 +0,0 @@ -[ - { - "id": "workpad-e08b9bdb-ec14-4339-94c4-063bddfd610e", - "type": "canvas-workpad", - "updated_at": "2018-10-22T15:19:02.081Z", - "version": 1, - "migrationVersion": { - "canvas-workpad": "7.0.0" - }, - "attributes": { - "name": "[eCommerce] Revenue Tracking", - "width": 1080, - "height": 720, - "page": 0, - "pages": [ - { - "id": "page-21cffafb-9eda-47f9-b35a-67a92e605abe", - "style": { - "background": "#fff" - }, - "elements": [ - { - "id": "element-3a220f56-0729-4464-b4fd-7975a8396d24", - "position": { - "left": 641, - "top": 97, - "width": 175, - "height": 510, - "angle": 0 - }, - "expression": "essql query=\"select COUNT(*) as total_count, SUM(CASE WHEN customer_gender='MALE' THEN 1 else 0 END) as male_count from kibana_sample_data_ecommerce\"\n| math \"male_count / total_count\" \n| revealImage origin=\"bottom\" image={asset \"asset-aaa14d64-2c1c-47f2-95c0-21306ee18cba\"} emptyImage={asset \"asset-960c8c6e-da72-412d-9d04-34a98cdb5760\"}" - }, - { - "id": "element-4a3fef74-5d8c-4bbe-8f3f-fe55afdd4b60", - "position": { - "left": 627.5, - "top": 82.5, - "width": 197, - "height": 521, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-8ae4b612-43a3-4846-8f0d-abb9785e95c3\"}" - }, - { - "id": "element-fb2761a1-df28-411a-8614-dbee0f437cfe", - "position": { - "left": 446, - "top": 93, - "width": 238, - "height": 520, - "angle": 0 - }, - "expression": "essql query=\"select COUNT(*) as total_count, SUM(CASE WHEN customer_gender='FEMALE' THEN 1 else 0 END) as female_count from kibana_sample_data_ecommerce\"\n| math \"female_count / total_count\" \n| revealImage origin=\"bottom\" image={asset \"asset-2f64bd10-953d-4163-90e9-a55e9ca4c52a\"} emptyImage={asset \"asset-3a26727a-b756-44be-a82c-273dd85bda09\"}", - "filter": null - }, - { - "id": "element-46b2f8df-f7db-4502-9cd0-b33c1c70b8b1", - "position": { - "left": 275, - "top": 306, - "width": 105, - "height": 102, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Clothing\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 2)'}\n| pointseries color=category size=percentage\n| pie hole=\"65\" labels=false seriesStyle={seriesStyle label=\"Women's Clothing\" color=\"#eb6c66\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#ede9e7\"}" - }, - { - "id": "element-eaa7f9a9-54ca-4c7c-9d27-62312d92a264", - "position": { - "left": 275, - "top": 157, - "width": 105, - "height": 102, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Accessories\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 2)'}\n| pointseries color=category size=percentage\n| pie hole=\"65\" labels=false seriesStyle={seriesStyle label=\"Women's Accessories\" color=\"#eb6c66\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#ede9e7\"}" - }, - { - "id": "element-58dfc1e8-a470-447f-8107-62bebe955475", - "position": { - "left": 275, - "top": 450, - "width": 106, - "height": 102, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Shoes\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 2)'}\n| pointseries color=category size=percentage\n| pie hole=\"65\" labels=false seriesStyle={seriesStyle label=\"Women's Shoes\" color=\"#eb6c66\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#ede9e7\"}" - }, - { - "id": "element-c0a5f8d9-f52f-4e0f-a8a4-08c1b7984bb2", - "position": { - "left": 893.5, - "top": 157, - "width": 105, - "height": 102, - "angle": 0 - }, - "expression": "essql \"SELECT category, COUNT(category) AS count FROM \\\"kibana_sample_data_ecommerce\\\" GROUP BY category\" \n| mapColumn \"category\" fn={if {getCell \"category\" | eq \"Men's Accessories\"} then={getCell \"category\"} else=\"Other\"} \n| ply by=\"category\" fn={math \"sum(count)\" | as \"count\"} | staticColumn \"total\" value={math \"sum(count)\"} \n| mapColumn \"percentage\" fn={math \"round(count/total * 100, 2)\"} \n| pointseries color=\"category\" size=\"percentage\" \n| pie hole=\"65\" labels=false seriesStyle={seriesStyle label=\"Men's Accessories\" color=\"#f8bd4a\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#ede9e7\"}" - }, - { - "id": "element-060eb797-c583-4c8f-b0e1-3ab9b58c4cf5", - "position": { - "left": 894, - "top": 305, - "width": 105, - "height": 102, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Men's Clothing\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 2)'}\n| pointseries color=category size=percentage\n| pie hole=\"65\" labels=false seriesStyle={seriesStyle label=\"Men's Clothing\" color=\"#f8bd4a\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#ede9e7\"}" - }, - { - "id": "element-8f811cd0-e4b2-48b3-a96f-b8384179bbfb", - "position": { - "left": 894, - "top": 451, - "width": 105, - "height": 102, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Men's Shoes\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 2)'}\n| pointseries color=category size=percentage\n| pie hole=\"65\" labels=false seriesStyle={seriesStyle label=\"Men's Shoes\" color=\"#f8bd4a\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#ede9e7\"}" - }, - { - "id": "element-c0595f68-81c5-43e7-9ecf-808e8cfe48c0", - "position": { - "left": 298, - "top": 517, - "width": 93, - "height": 44, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-66a89124-fc39-4109-8acd-e1ac7f382e04\"} | render" - }, - { - "id": "element-0a14f255-6445-4860-b41d-d1c0b7ca9c36", - "position": { - "left": 890, - "top": 516, - "width": 102, - "height": 54, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-4acbecf1-e514-4e3b-bce4-61920335941e\"} | render" - }, - { - "id": "element-6aeefa4f-6b4f-4a6c-99ff-2cca052f5be6", - "position": { - "top": 291, - "left": 960, - "height": 121, - "width": 95, - "angle": 12.8 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-ae290f99-dd16-41a4-8191-7dd7be154be6\"} | render" - }, - { - "id": "element-68d9cb72-7a0e-4cac-996a-0ec8356f0df8", - "position": { - "left": 245, - "top": 291, - "width": 62, - "height": 139, - "angle": -1 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-565cd264-9196-4ebd-9d6e-f413f1db734d\"} | render" - }, - { - "id": "element-9bac6c19-517c-46e6-8d71-9273910366d1", - "position": { - "left": 322, - "top": 230, - "width": 60, - "height": 27, - "angle": 10 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-6222f3e0-1dab-4aa9-a06c-63d7732cc5f4\"} | render" - }, - { - "id": "element-a58f99d3-8ea4-474e-9aba-e7ed3e91a178", - "position": { - "left": 892, - "top": 235, - "width": 64, - "height": 24, - "angle": 7 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-f8ac482e-0c7a-4cac-8bcf-6f4f55300081\"} | render" - }, - { - "id": "element-84dec4fd-ee5d-49c0-9600-41b951033e09", - "position": { - "left": 394, - "top": 393.0200895724113, - "width": 94, - "height": 56, - "angle": 0 - }, - "expression": "essql query=\"select COUNT(*) as total_count, SUM(CASE WHEN customer_gender='FEMALE' THEN 1 else 0 END) as female_count from kibana_sample_data_ecommerce\"\n| math \"round(100 * female_count / total_count)\" | markdown {context} \"%\" font={font family=\"Avenir\" size=48 align=\"center\" color=\"#eb6c66\" weight=\"normal\" underline=false italic=false}" - }, - { - "id": "element-9e0b6230-2bc9-4995-8207-043e3063faeb", - "position": { - "left": 794, - "top": 369, - "width": 94, - "height": 56, - "angle": 0 - }, - "expression": "essql query=\"select COUNT(*) as total_count, SUM(CASE WHEN customer_gender='MALE' THEN 1 else 0 END) as male_count from kibana_sample_data_ecommerce\"\n| math \"round(100 * male_count / total_count)\" | markdown {context} \"%\" font={font family=\"Avenir\" size=48 align=\"center\" color=\"#f8bd4a\" weight=\"normal\" underline=false italic=false}" - }, - { - "id": "element-2185edff-ac50-4162-b583-3bfd6469e925", - "position": { - "left": -3, - "top": -1, - "width": 214, - "height": 721, - "angle": 0 - }, - "expression": "markdown \"\" | render containerStyle={containerStyle backgroundColor=\"#ede9e7\"}" - }, - { - "id": "element-71b63f54-0961-4ed2-a85d-45584b48a631", - "position": { - "left": 8, - "top": 35, - "width": 122, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"TOTAL SALES\" font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=18 align=\"left\" color=\"#777\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-61fdb4ce-5dea-4699-b958-6c40e2a2b61a", - "position": { - "left": 398, - "top": 381.5200895724113, - "width": 78, - "height": 23, - "angle": 0 - }, - "expression": "markdown \"WOMEN\" font={font family=\"Avenir\" size=18 align=\"left\" color=\"#999\" weight=\"normal\" underline=false italic=false}" - }, - { - "id": "element-157ab7a7-e3ef-477f-8c97-84c67f7ab28e", - "position": { - "left": 840, - "top": 352, - "width": 46, - "height": 23, - "angle": 0 - }, - "expression": "markdown \"MEN\" font={font family=\"Avenir\" size=18 align=\"left\" color=\"#999\" weight=\"normal\" underline=false italic=false} | render" - }, - { - "id": "element-bfa6f8bc-c083-4817-a682-91eb50fc214d", - "position": { - "left": 299, - "top": 344, - "width": 60, - "height": 34, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Clothing\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Women's Clothing\"}}\n| markdown {getCell \"percentage\"} \"%\" font={font family=\"Avenir\" size=24 align=\"center\" color=\"#000\" weight=\"normal\" underline=false italic=false}" - }, - { - "id": "element-73e918d2-14d0-4ed6-9cfe-204ad4eaff24", - "position": { - "left": 300, - "top": 488, - "width": 59, - "height": 30, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Shoes\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Women's Shoes\"}}\n| markdown {getCell \"percentage\"} \"%\" font={font family=\"Avenir\" size=24 align=\"center\" color=\"#000\" weight=\"normal\" underline=false italic=false}" - }, - { - "id": "element-d9dd8a8e-3af7-4e59-9115-3fd13c312d39", - "position": { - "left": 297, - "top": 194, - "width": 62, - "height": 37, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Accessories\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Women's Accessories\"}}\n| markdown {getCell \"percentage\"} \"%\" font={font family=\"Avenir\" size=24 align=\"center\" color=\"#000\" weight=\"normal\" underline=false italic=false}" - }, - { - "id": "element-af25bb55-818c-4c69-b2ae-45245af131e6", - "position": { - "left": 923, - "top": 194, - "width": 51, - "height": 34, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Men's Accessories\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Men's Accessories\"}}\n| markdown {getCell \"percentage\"} \"%\" font={font family=\"Avenir\" size=24 align=\"center\" color=\"#000\" weight=\"normal\" underline=false italic=false}" - }, - { - "id": "element-9e02f39b-14b2-42a4-ae32-a4c292ece6ba", - "position": { - "left": 924, - "top": 343, - "width": 50, - "height": 33, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Men's Clothing\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Men's Clothing\"}}\n| markdown {getCell \"percentage\"} \"%\" font={font family=\"Avenir\" size=24 align=\"center\" color=\"#000\" weight=\"normal\" underline=false italic=false}" - }, - { - "id": "element-b5f950b0-bb0f-462d-a92f-35bc3f1f4c39", - "position": { - "left": 921, - "top": 489, - "width": 50, - "height": 33, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Men's Shoes\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Men's Shoes\"}}\n| markdown {getCell \"percentage\"} \"%\" font={font family=\"Avenir\" size=24 align=\"center\" color=\"#000\" weight=\"normal\" underline=false italic=false}" - }, - { - "id": "element-a4d410df-83b8-40dc-987f-e2c1380874a6", - "position": { - "left": -135.50000000000006, - "top": 330.5, - "width": 500, - "height": 217, - "angle": 90 - }, - "expression": "timelion \n \".es(index=kibana_sample_data_ecommerce, metric=sum:taxless_total_price, timefield=order_date)\" interval=\"1d\" from={essql \"SELECT order_date as min FROM kibana_sample_data_ecommerce order by order_date limit 1\" | getCell min} to={essql \"SELECT order_date as max FROM kibana_sample_data_ecommerce order by order_date DESC limit 1\" | getCell max}\n| pointseries x=\"@timestamp\" y=\"value\"\n| plot yaxis=false defaultStyle={seriesStyle points=\"0\" bars=\"50000000\" lines=\"0\" color=\"#62bb96\"} font={font size=12 family=\"Avenir\" color=\"#999\" align=\"left\"}", - "filter": null - }, - { - "id": "element-ccbb192a-725b-4479-a34b-9d70b0fa1a8a", - "position": { - "left": 441, - "top": 93, - "width": 242, - "height": 520, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-93e415d8-82c6-47d4-8c55-e38df329b88b\"}" - }, - { - "id": "element-18fc190c-e46a-408b-a220-8e1745eb77e6", - "position": { - "left": 394, - "top": 451, - "width": 115, - "height": 2, - "angle": 0 - }, - "expression": "markdown \"\" | render containerStyle={containerStyle backgroundColor=\"#000000\"}", - "filter": null - }, - { - "id": "element-1eb4fcd1-f8dd-4bd9-98a6-c5cbd4bcc8dc", - "position": { - "left": 767, - "top": 431, - "width": 119, - "height": 2, - "angle": 0 - }, - "expression": "markdown \"\" | render containerStyle={containerStyle backgroundColor=\"#000000\"}", - "filter": null - }, - { - "id": "element-2f976ef1-abc7-4bd2-82cb-cc114431eaea", - "position": { - "left": 744.5, - "top": 410, - "width": 35, - "height": 50, - "angle": 0 - }, - "expression": "markdown \"## ○\" font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=14 align=\"center\" color=\"#000000\" weight=\"normal\" underline=false italic=false} | render containerStyle={containerStyle}" - }, - { - "id": "element-532638f8-758e-4cf4-86f0-c4d896e4477d", - "position": { - "left": 497, - "top": 429.4483902138134, - "width": 35, - "height": 50, - "angle": 0 - }, - "expression": "markdown \"## ○\" font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=14 align=\"center\" color=\"#000000\" weight=\"normal\" underline=false italic=false} | render containerStyle={containerStyle}", - "filter": null - }, - { - "id": "element-62bf98c1-bd0c-40dd-ae44-abbcc50c0ae1", - "position": { - "left": -47, - "top": 410, - "width": 477, - "height": 63, - "angle": 90 - }, - "expression": "timelion \n \".es(index=kibana_sample_data_ecommerce, metric=sum:taxless_total_price, timefield=order_date)\" interval=\"1w\"\n| mapColumn \"value\" fn={math \"round(value,0)\"}\n| staticColumn \"mean\" value={math \"round(mean(value),0)\"}\n| mapColumn \"mean\" \"as\" \"rnd\" fn={math \"round(random(0.9,1.1),2)\"}\n| mapColumn \"value\" \"as\" \"final\" fn={math \"round(multiply(rnd,mean),2)\"}\n| pointseries x=\"@timestamp\" y=\"final\"\n| plot xaxis=false yaxis=false defaultStyle={seriesStyle points=\"0\" bars=\"0\" lines=\"3\" color=\"#eb6c66\"}\n| render containerStyle={containerStyle opacity=\"0.5\"}", - "filter": null - }, - { - "id": "element-e1b5a809-aed3-42e0-8806-46b0e462a9d4", - "position": { - "left": 488, - "top": 661, - "width": 279, - "height": 38, - "angle": 0 - }, - "expression": "markdown \"REVENUE BY CATEGORY\" font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=24 align=\"left\" color=\"#999\" weight=\"normal\" underline=false italic=false}", - "filter": null - }, - { - "id": "element-50ea8d53-383d-4582-9497-0692a81d9df8", - "position": { - "left": -7, - "top": 673, - "width": 219, - "height": 22, - "angle": 0 - }, - "expression": "markdown \"REVENUE BY DAY\" \n font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=14 align=\"center\" color=\"#62bb96\" weight=\"normal\" underline=false italic=false}", - "filter": null - }, - { - "id": "element-de932ce1-1c99-448b-bfb4-a98f91add877", - "position": { - "left": -7, - "top": 689, - "width": 219, - "height": 22, - "angle": 0 - }, - "expression": "markdown \"SALES PREDICTION\" \n font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=10 align=\"center\" color=\"#eb6c66\" weight=\"normal\" underline=false italic=false}", - "filter": null - }, - { - "id": "element-f5f539dd-1abe-42a9-bb2a-1d2a07ff108c", - "position": { - "left": 286, - "top": 263, - "width": 76, - "height": 16, - "angle": 0 - }, - "expression": "markdown \"ACCESSORIES\" \n font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=10 align=\"center\" color=\"#999\" weight=\"normal\" underline=false italic=false}", - "filter": null - }, - { - "id": "element-1eb8a1d1-beff-4d42-8b82-cddc28075bb0", - "position": { - "left": 911, - "top": 262, - "width": 76, - "height": 16, - "angle": 0 - }, - "expression": "markdown \"ACCESSORIES\" \n font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=10 align=\"center\" color=\"#999\" weight=\"normal\" underline=false italic=false}", - "filter": null - }, - { - "id": "element-d36fd045-500a-494c-8d1f-281c03a9720d", - "position": { - "left": 909, - "top": 409, - "width": 76, - "height": 16, - "angle": 0 - }, - "expression": "markdown \"CLOTHING\" \n font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=10 align=\"center\" color=\"#999\" weight=\"normal\" underline=false italic=false}", - "filter": null - }, - { - "id": "element-3388ba84-9109-4f1e-bb3b-8e7e4247b99e", - "position": { - "left": 291, - "top": 411, - "width": 76, - "height": 16, - "angle": 0 - }, - "expression": "markdown \"CLOTHING\" \n font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=10 align=\"center\" color=\"#999\" weight=\"normal\" underline=false italic=false}", - "filter": null - }, - { - "id": "element-4fe5f99e-ffea-4d21-9718-dbfbbd161a64", - "position": { - "left": 910, - "top": 570, - "width": 76, - "height": 16, - "angle": 0 - }, - "expression": "markdown \"SHOES\" \n font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=10 align=\"center\" color=\"#999\" weight=\"normal\" underline=false italic=false}", - "filter": null - }, - { - "id": "element-a6b5a208-6a75-42ad-8a1c-aa50359ecd44", - "position": { - "left": 293, - "top": 562, - "width": 76, - "height": 16, - "angle": 0 - }, - "expression": "markdown \"SHOES\" \n font={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=10 align=\"center\" color=\"#999\" weight=\"normal\" underline=false italic=false}", - "filter": null - }, - { - "id": "element-45310e03-f6dd-4283-aa04-8d27a4501665", - "position": { - "left": 5.999999999999915, - "top": 76.5, - "width": 201.00000000000009, - "height": 68.5, - "angle": 0 - }, - "expression": "essql \n query=\"SELECT sum(taxless_total_price) AS sum_total_price FROM \\\"kibana_sample_data_ecommerce\\\"\"\n| math \"sum_total_price\"\n| formatNumber \"$0a\"\n| metric \n metricFont={font family=\"'Avenir', Helvetica, Arial, sans-serif\" size=72 align=\"left\" color=\"#000000\" weight=\"normal\" underline=false italic=false}\n| render" - } - ] - }, - { - "id": "page-f704531f-3a72-4f29-a199-7e00d0c1ffef", - "style": { - "background": "#FAF0DD" - }, - "elements": [ - { - "id": "element-2c7e18fa-480f-4e3b-b4df-f649687229c6", - "position": { - "left": 788, - "top": 112.12093494719988, - "width": 204, - "height": 202, - "angle": 0 - }, - "expression": "essql query=\"select COUNT(*) as total_count, SUM(CASE WHEN customer_gender='MALE' THEN 1 else 0 END) as male_count from kibana_sample_data_ecommerce\"\n| math \"male_count / total_count\" \n| revealImage origin=\"bottom\" image={asset \"asset-803ec373-2608-4f6f-8cf9-0dbb2f6437ce\"} emptyImage={asset \"asset-18070a2a-cd01-410a-ba89-a4505e2fbc5b\"}" - }, - { - "id": "element-2379c3ca-2c31-4948-8412-d14115500efc", - "position": { - "left": 788, - "top": 369.6303606465582, - "width": 204, - "height": 202, - "angle": 0 - }, - "expression": "essql query=\"select COUNT(*) as total_count, SUM(CASE WHEN customer_gender='FEMALE' THEN 1 else 0 END) as female_count from kibana_sample_data_ecommerce\"\n| math \"female_count / total_count\" \n| revealImage origin=\"bottom\" image={asset \"asset-e644a484-4097-40b9-a08e-7250ba963059\"} emptyImage={asset \"asset-7e4f7119-b2d8-4527-9bd8-887cb25974e7\"}" - }, - { - "id": "element-3f52813f-7d0e-4ec7-9aad-c731b670d88d", - "position": { - "left": -69, - "top": 400.19203602130153, - "width": 388, - "height": 141, - "angle": 90 - }, - "expression": "timelion \n \".es(index=kibana_sample_data_ecommerce, metric=sum:taxless_total_price, timefield=order_date)\" interval=\"1d\" from={essql \"SELECT order_date as min FROM kibana_sample_data_ecommerce order by order_date limit 1\" | getCell min} to={essql \"SELECT order_date as max FROM kibana_sample_data_ecommerce order by order_date DESC limit 1\" | getCell max}\n| pointseries x=\"@timestamp\" y=\"value\"\n| plot yaxis=false defaultStyle={seriesStyle points=\"0\" bars=\"50000000\" lines=\"0\" color=\"#00A89C\"} \n font={font family=\"gilroy extrabold, Avenir\" size=16 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-dc86d147-0611-4ce8-9b0b-e95fc6f8ab80", - "position": { - "left": 244, - "top": 138, - "width": 157, - "height": 145, - "angle": -45 - }, - "expression": "essql \"SELECT category, COUNT(category) AS count FROM \\\"kibana_sample_data_ecommerce\\\" GROUP BY category\" \n| mapColumn \"category\" fn={if {getCell \"category\" | eq \"Men's Accessories\"} then={getCell \"category\"} else=\"Other\"} \n| ply by=\"category\" fn={math \"sum(count)\" | as \"count\"} | staticColumn \"total\" value={math \"sum(count)\"} \n| mapColumn \"percentage\" fn={math \"round(count/total * 100, 2)\"} \n| pointseries color=\"category\" size=\"percentage\"\n| pie hole=\"85\" labels=false seriesStyle={seriesStyle label=\"Men's Accessories\" color=\"#00A89C\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#CBCBCB\"}" - }, - { - "id": "element-29967798-174d-4109-b229-e776b0a4bf8c", - "position": { - "left": 425.5, - "top": 138, - "width": 157, - "height": 145, - "angle": -99 - }, - "expression": "essql \n \"SELECT category, COUNT(category) AS count FROM \\\"kibana_sample_data_ecommerce\\\" GROUP BY category ORDER BY category\"\n| mapColumn \"category\" \n fn={if {getCell \"category\" | eq \"Men's Clothing\"} then={getCell \"category\"} else=\"Other\"}\n| ply by=\"category\" fn={math \"sum(count)\" | as \"count\"}\n| staticColumn \"total\" value={math \"sum(count)\"}\n| mapColumn \"percentage\" fn={math \"round(count/total * 100, 2)\"}\n| sort \"category\"\n| pointseries color=\"category\" size=\"percentage\"\n| pie hole=\"85\" labels=false seriesStyle={seriesStyle label=\"Men's Clothing\" color=\"#00A89C\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#CBCBCB\"}" - }, - { - "id": "element-abaa4e35-cfc0-4171-8c34-0914cea35082", - "position": { - "left": 610, - "top": 136, - "width": 157, - "height": 145, - "angle": -56 - }, - "expression": "essql \"SELECT category, COUNT(category) AS count FROM \\\"kibana_sample_data_ecommerce\\\" GROUP BY category\" \n| mapColumn \"category\" fn={if {getCell \"category\" | eq \"Men's Shoes\"} then={getCell \"category\"} else=\"Other\"} \n| ply by=\"category\" fn={math \"sum(count)\" | as \"count\"} | staticColumn \"total\" value={math \"sum(count)\"} \n| mapColumn \"percentage\" fn={math \"round(count/total * 100, 2)\"} \n| pointseries color=\"category\" size=\"percentage\"\n| pie hole=\"85\" labels=false seriesStyle={seriesStyle label=\"Men's Shoes\" color=\"#00A89C\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#CBCBCB\"}" - }, - { - "id": "element-20da5d5d-2b29-4888-a304-a14377d727ec", - "position": { - "left": 245, - "top": 383, - "width": 157, - "height": 145, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Accessories\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 2)'}\n| pointseries color=category size=percentage\n| pie hole=\"85\" labels=false palette={palette \"#CBCBCB\" \"#F05A24\" gradient=false} seriesStyle={seriesStyle label=\"Women's Accessories\" color=\"#F05A24\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#CBCBCB\"}" - }, - { - "id": "element-9dd99310-e0a6-4ab7-b049-c7ea63180b4e", - "position": { - "left": 429, - "top": 380, - "width": 157, - "height": 145, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Clothing\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 2)'}\n| pointseries color=category size=percentage\n| pie hole=\"85\" labels=false seriesStyle={seriesStyle label=\"Women's Clothing\" color=\"#F05A24\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#CBCBCB\"}" - }, - { - "id": "element-715b318d-fe6d-42b2-abea-b238b0daa8c7", - "position": { - "left": 610, - "top": 384, - "width": 157, - "height": 145, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Shoes\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 2)'}\n| pointseries color=category size=percentage\n| pie hole=\"85\" labels=false seriesStyle={seriesStyle label=\"Women's Shoes\" color=\"#F05A24\"}\n seriesStyle={seriesStyle label=\"Other\" color=\"#CBCBCB\"}" - }, - { - "id": "element-9c27c6d0-b9d9-4adb-a5f3-abb7a3403977", - "position": { - "left": 239, - "top": 157, - "width": 172, - "height": 102, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-e79711e8-d9da-45e1-a234-9efe226a444d\"}\n| render" - }, - { - "id": "element-c9b7f707-f27c-44cc-b9f1-e7b693c66702", - "position": { - "left": 463, - "top": 165, - "width": 85, - "height": 86, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-9493e336-1b11-4e61-bad2-716c46194550\"}\n| render" - }, - { - "id": "element-8bcb4071-0012-46da-9316-524c06bb673a", - "position": { - "left": 648, - "top": 165, - "width": 85, - "height": 86, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-23f2bfe9-e58c-4a56-98c6-fad59eecdf74\"}\n| render" - }, - { - "id": "element-3532c81f-a341-4d23-90b6-68912c04ee46", - "position": { - "left": 1016, - "top": 391, - "width": 78, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"W\" \n font={font family=\"gilroy extrabold, Avenir\" size=24 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-2673d24b-2706-4ffe-a38b-5736c3bc616c", - "position": { - "left": 1018, - "top": 420, - "width": 78, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"O\" \n font={font family=\"gilroy extrabold, Avenir\" size=24 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-5d2b6fe8-34a9-49bc-8229-4e1c2b8029e1", - "position": { - "left": 1018, - "top": 446, - "width": 78, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"M\" \n font={font family=\"gilroy extrabold, Avenir\" size=24 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-b67e44c0-afe0-4f15-b521-af0759348dc6", - "position": { - "left": 1020, - "top": 475, - "width": 78, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"E\" \n font={font family=\"gilroy extrabold, Avenir\" size=24 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-370b7910-dd0b-4257-90de-229d25bd6610", - "position": { - "left": 1019, - "top": 504, - "width": 78, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"N\" \n font={font family=\"gilroy extrabold, Avenir\" size=24 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-cbdd2309-101d-4edc-874c-47c3e6c99df5", - "position": { - "left": 1018, - "top": 173, - "width": 78, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"M\" \n font={font family=\"gilroy extrabold, Avenir\" size=24 align=\"left\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-7288cfda-673f-4741-bec2-4675bc4952ed", - "position": { - "left": 1020, - "top": 201, - "width": 78, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"E\" \n font={font family=\"gilroy extrabold, Avenir\" size=24 align=\"left\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-e68822cc-f4b7-48a4-a8b2-86d84d8ddeb1", - "position": { - "left": 1019, - "top": 229, - "width": 78, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"N\" \n font={font family=\"gilroy extrabold, Avenir\" size=24 align=\"left\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-f446c8e1-b65e-4a1f-8476-e80e437a31ec", - "position": { - "left": 240, - "top": 414, - "width": 169, - "height": 100, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-86d05b5e-1a4b-4979-95e9-7071b9923470\"}\n| render" - }, - { - "id": "element-5406c1e9-9626-413c-9eaa-a73ca1e10b8c", - "position": { - "left": 464, - "top": 414, - "width": 85, - "height": 86, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-fdfc9cc7-2c6a-44fe-b9be-c4ff115c92c1\"}\n| render" - }, - { - "id": "element-d3fe9442-583b-4acb-a700-3935adb4316c", - "position": { - "left": 654, - "top": 419, - "width": 74, - "height": 76, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-58ae3445-4001-45e7-9603-19ec8d41e64e\"}\n| render" - }, - { - "id": "element-28ffc136-8702-4cfc-9643-9825dfd7a6a3", - "position": { - "left": 48, - "top": 247, - "width": 118, - "height": 22, - "angle": 0 - }, - "expression": "markdown \"P R O G R E S S\" \n font={font family=\"gilroy extrabold, Avenir\" size=12 align=\"center\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-c6b853cc-72a3-4110-b40b-359ecb7b1af6", - "position": { - "left": 92, - "top": 268, - "width": 27, - "height": 4, - "angle": 0 - }, - "expression": "markdown \"\"\n| render containerStyle={containerStyle backgroundColor=\"#F05A24\"}" - }, - { - "id": "element-692a539e-0c3b-4e8d-bc3e-3cf84ddd53c7", - "position": { - "left": 90, - "top": 98, - "width": 27, - "height": 4, - "angle": 0 - }, - "expression": "markdown \"\"\n| render containerStyle={containerStyle backgroundColor=\"#F05A24\"}" - }, - { - "id": "element-99bed359-ef39-403d-bcb3-81cf8d1f6c62", - "position": { - "left": 44, - "top": 77, - "width": 118, - "height": 22, - "angle": 0 - }, - "expression": "markdown \"T O T A L\" \n font={font family=\"gilroy extrabold, Avenir\" size=12 align=\"center\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-8d72d271-b12e-41af-a18b-795490cf7f38", - "position": { - "left": 276, - "top": 290, - "width": 93, - "height": 40, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Men's Accessories\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Men's Accessories\"}}\n| markdown {getCell \"percentage\"} font={font family=\"nexa bold, Avenir\" size=36 align=\"center\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-cc17144e-096c-47b1-85dc-047724cc095e", - "position": { - "left": 465, - "top": 291, - "width": 78, - "height": 40, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Men's Clothing\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Men's Clothing\"}}\n| markdown {getCell \"percentage\"} font={font family=\"nexa bold, Avenir\" size=36 align=\"center\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-f38ee1d6-4fd7-4ff9-b304-84663f60fab2", - "position": { - "left": 651, - "top": 290, - "width": 76, - "height": 40, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Men's Shoes\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Men's Shoes\"}}\n| markdown {getCell \"percentage\"} font={font family=\"nexa bold, Avenir\" size=36 align=\"center\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-0b0b1c4a-0acf-40e3-a3f0-3128bd59f45c", - "position": { - "left": 340, - "top": 293, - "width": 47, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"%\" \n font={font family=\"nexa extrabold, Avenir\" size=24 align=\"left\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-3efcd68f-7fca-4ad3-aa13-737260ec5436", - "position": { - "left": 525, - "top": 293, - "width": 47, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"%\" \n font={font family=\"nexa extrabold, Avenir\" size=24 align=\"left\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-a617cb84-6e50-47c3-bb95-ea67df89d117", - "position": { - "left": 710, - "top": 292, - "width": 47, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"%\" \n font={font family=\"nexa extrabold, Avenir\" size=24 align=\"left\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-5426b988-29d6-40aa-b0a2-40a4a0729ef0", - "position": { - "left": 277, - "top": 540, - "width": 93, - "height": 40, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Accessories\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Women's Accessories\"}}\n| markdown {getCell \"percentage\"} \"\" font={font family=\"nexa bold, Avenir\" size=36 align=\"center\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-c1579899-59fc-4960-9bf0-1187b3535593", - "position": { - "left": 461, - "top": 541, - "width": 93, - "height": 40, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Clothing\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Women's Clothing\"}}\n| markdown {getCell \"percentage\"} font={font family=\"nexa bold, Avenir\" size=36 align=\"center\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-31df9407-2156-408d-b9d4-54e32adfdc2b", - "position": { - "left": 644, - "top": 541, - "width": 93, - "height": 40, - "angle": 0 - }, - "expression": "essql 'SELECT category, COUNT(category) AS count FROM \"kibana_sample_data_ecommerce\" GROUP BY category'\n| mapColumn category fn={if {getCell category | eq \"Women's Shoes\"} then={getCell category} else=\"Other\"}\n| ply by=category fn={math 'sum(count)' | as count}\n| staticColumn total value={math 'sum(count)'}\n| mapColumn percentage fn={math 'round(count/total * 100, 0)'}\n| filterrows {getCell \"category\" | any {eq \"Women's Shoes\"}}\n| markdown {getCell \"percentage\"} font={font family=\"nexa bold, Avenir\" size=36 align=\"center\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-d82b37e0-2f8e-48cb-8a85-d3d22b019499", - "position": { - "left": 343, - "top": 543, - "width": 45, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"%\" \n font={font family=\"nexa extrabold, Avenir\" size=24 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-ae570ea8-06b8-4ffa-a2f1-b7281481779f", - "position": { - "left": 528, - "top": 543, - "width": 45, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"%\" \n font={font family=\"nexa extrabold, Avenir\" size=24 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-81dd855d-d4fa-4c1c-a72f-6c6ab5b100cf", - "position": { - "left": 711, - "top": 543, - "width": 45, - "height": 29, - "angle": 0 - }, - "expression": "markdown \"%\" \n font={font family=\"nexa extrabold, Avenir\" size=24 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-b8f13a87-b781-42d5-a663-5dbd4f645d6d", - "position": { - "left": 837, - "top": 468, - "width": 91, - "height": 63, - "angle": 0 - }, - "expression": "essql query=\"select COUNT(*) as total_count, SUM(CASE WHEN customer_gender='FEMALE' THEN 1 else 0 END) as female_count from kibana_sample_data_ecommerce\"\n| math \"round(100 * female_count / total_count)\" | markdown {context} font={font family=\"nexa bold, Avenir\" size=48 align=\"center\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-86b06b67-893e-4555-ad38-7fba9ea3153b", - "position": { - "left": 837, - "top": 215, - "width": 90, - "height": 72, - "angle": 0 - }, - "expression": "essql query=\"select COUNT(*) as total_count, SUM(CASE WHEN customer_gender='MALE' THEN 1 else 0 END) as male_count from kibana_sample_data_ecommerce\"\n| math \"round(100 * male_count / total_count)\" | markdown {context} font={font family=\"nexa bold, Avenir\" size=48 align=\"center\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-507337d9-6e0e-4752-8770-6ebe88e9b3da", - "position": { - "left": 913, - "top": 220, - "width": 44, - "height": 42, - "angle": 0 - }, - "expression": "markdown \"%\" \n font={font family=\"nexa extrabold, Avenir\" size=36 align=\"left\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-19f6b029-a6ef-426e-aa07-8f91ef846a95", - "position": { - "left": 914, - "top": 475, - "width": 44, - "height": 42, - "angle": 0 - }, - "expression": "markdown \"%\" \n font={font family=\"nexa extrabold, Avenir\" size=36 align=\"left\" color=\"#F05A24\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-8ef60cfc-3823-42b6-9651-75a07b8e412d", - "position": { - "left": 19, - "top": 124, - "width": 44, - "height": 42, - "angle": 0 - }, - "expression": "markdown \"$\" \n font={font family=\"nexa bold, Avenir\" size=36 align=\"left\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-3dfda897-cc59-4bf6-ad3d-38f00bd8814b", - "position": { - "left": 362, - "top": 606, - "width": 378, - "height": 92, - "angle": 0 - }, - "expression": "markdown \"ACME Inc.\" font={font family=\"gilroy extrabold, Avenir\" size=72 align=\"center\" color=\"#CDCDCD\" weight=\"bold\" underline=false italic=false}" - }, - { - "id": "element-b336534a-6604-41be-b34a-109d631dcdb2", - "position": { - "left": 27.25, - "top": 133.03796394394163, - "width": 195.5, - "height": 80.08297100325825, - "angle": 0 - }, - "expression": "essql \n query=\"SELECT sum(taxless_total_price) AS sum_total_price FROM \\\"kibana_sample_data_ecommerce\\\"\"\n| math \"sum_total_price\"\n| formatNumber \"0a\"\n| metric \n metricFont={font family=\"nexa bold, Avenir\" size=72 align=\"center\" color=\"#00A89C\" weight=\"bold\" underline=false italic=false}\n| render" - } - ] - } - ], - "colors": [ - "#37988d", - "#c19628", - "#b83c6f", - "#3f9939", - "#1785b0", - "#ca5f35", - "#45bdb0", - "#f2bc33", - "#e74b8b", - "#4fbf48", - "#1ea6dc", - "#fd7643", - "#72cec3", - "#f5cc5d", - "#ec77a8", - "#7acf74", - "#4cbce4", - "#fd986f", - "#a1ded7", - "#f8dd91", - "#f2a4c5", - "#a6dfa2", - "#86d2ed", - "#fdba9f", - "#000000", - "#444444", - "#777777", - "#BBBBBB", - "#FFFFFF", - "rgba(255,255,255,0)" - ], - "@timestamp": "2019-03-18T17:22:07.449Z", - "@created": "2019-03-18T16:05:37.945Z", - "assets": { - "asset-66a89124-fc39-4109-8acd-e1ac7f382e04": { - "id": "asset-66a89124-fc39-4109-8acd-e1ac7f382e04", - "@created": "2018-07-10T18:33:25.683Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-4acbecf1-e514-4e3b-bce4-61920335941e": { - "id": "asset-4acbecf1-e514-4e3b-bce4-61920335941e", - "@created": "2018-07-10T18:34:30.379Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-ae290f99-dd16-41a4-8191-7dd7be154be6": { - "id": "asset-ae290f99-dd16-41a4-8191-7dd7be154be6", - "@created": "2018-07-10T18:37:50.932Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-565cd264-9196-4ebd-9d6e-f413f1db734d": { - "id": "asset-565cd264-9196-4ebd-9d6e-f413f1db734d", - "@created": "2018-07-10T18:38:37.796Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-6222f3e0-1dab-4aa9-a06c-63d7732cc5f4": { - "id": "asset-6222f3e0-1dab-4aa9-a06c-63d7732cc5f4", - "@created": "2018-07-10T18:39:47.394Z", - "type": "dataurl", - "value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADkAAAAcCAYAAADbeRcAAAAACXBIWXMAAAsSAAALEgHS3X78AAAD0ElEQVRYw92YMY/dRBSFv41WIqBI+2giBAVGcYWI4yKW6DIFPf4HOP/ANZV/gktK0yIK09Hh7ZDcGNeWeOmIhBRHAonONGfQPK+f37PXK20Y6cp+z57xnLnn3ntmLoZh4F1ofhCFwA5ourbul/S9uI8g/SDaAQlgZFfAK2APvNBr10AFFF1b798ZkAKXA98APwElUI1B6D0DxLISyI6BXQTSoYwna4C+a+tqA4AxUMg76SnvjABn8nzatXWxGKQfREYDxEAvytirBf3MrvzUR86YaCIPJl1blysXycijN4AeBalOuUDkArCfWc0YSPV+eu5kHYCma+tmg+RUjYFOgvSDKNOEs66t85W0K7u2Tk68aykfb0H5kUdD65QHEy8V8opZChBAHvSAUGPNtUzZsdoqeWmsUmNzA6QfRLni7FbUUR0zAprPeDF2J7NhyzT2IUgnwSRLi+0M0BhINPa4xaJ0vzVC0XRvv3s5Qp/dNvjHH5MnUyUEt9nY2brWGoULwHd+EP186WSlsGtrcwfUyYE3fhDtRl7bqQytAWLrtNE4oewK+E0lzlpx6VCnuAOAdG3d+0F0vdRzKkuhIzyMU5PfKis3ApJJlDSjCkHX1s2lQ52cu2uVJlzOqCjjAHK9sheYwt6fGcfGOs6Nyf6WsWAnO24e8BXwyA+iL4GH+u8x8Avwj+xvXf+SXclrz4CvnfHe+kGUnqGsrDDg4snT51b3VU6MHJuwpctUewX8KRCPdH3PGacHXgN/yB4DnwEvJ8bqjyVAiY1cc82maqxUVNq1dTj25EPnvpxJCo0T6C7NPtXzPfCjQDX6XQD5WOr5QbR3CvgSsVEq5ko/iA52II5gzw5knTrsurZOz0gGlQPWxst+ZuV3wBvgw3EsacUzZfZ+RYhYXW29a81zK4UFGaowe2eI35OadEIHh11bx0eel/JQfMt8kANfAO8Dn7iL9sCmWSmEdKbAVqLFEoCehMBc5k4Azw+iSp5ZU6Ysqz5QeSkF/IZ2zYDMfehQyu7TlpaZ8pQAd3SulWLJQi8axbYHfC6rgMoPosIPot3BVkvUsjuQXpIsWSPYtQOxYr8/s0/seD3X0UdzhJ5GLEEMKyZYlAPejf2ks9X6FfhIgr1ZSFGbRc3KhGLPboyytj3E8pzfNj+cVFFTIHdAC3wM/AB8e855i/qlsuJUpl4pNPo1G4gxXUPVtMapNfbkrLJ6UVR2hbGRKvle9XCzncwW7T+QTok48IJzfmOL/gun/7WKfjV3BnQvQCqOfgderjltu/dtGAaGYeDJ0+eevf+/2b9/hrMMA+Zz7QAAAABJRU5ErkJggg==" - }, - "asset-f8ac482e-0c7a-4cac-8bcf-6f4f55300081": { - "id": "asset-f8ac482e-0c7a-4cac-8bcf-6f4f55300081", - "@created": "2018-07-10T18:40:34.480Z", - "type": "dataurl", - "value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD8AAAAZCAYAAACGqvb0AAAACXBIWXMAAAsSAAALEgHS3X78AAADxklEQVRYw8WYz4rkVBTGf92IoCATBFEEMVK1Eqoqi6p1Z+HOhXmDrkeo2boxs5ql8Q3iG9QguE6ju4DGrEaIkNm5EUpwbWbz3eH27Zt00nbFA6GKqntzznf+n3PRdR1DtFzvQiAGzCdAAGyco38Dlb63ehLPuYfS95LB0NUI/kVTl0XfCy/6wC/Xuz1wkPA3QGG9FKBq6vJknY+kFIDIUtYGeAEcm7rMx6CUwvd6AoGawt82VgAcgbSpy3YQ/HK9M4dDIJXQp4eaS+9L9C6AfZ81dPYAfCNL50OWm6DIFLgGnjZ1mXnBi3khre55ZJI3ZcDB9QKL90kKah+ZdySj5k1dpj7wORA0dZlwJpIQhQAerd8LoD2H0j28o6Yu20tH89dyu7NRU5eVeGQWbxOjc/DOTAheWv8lwM1ju1uPELllCZTYsv+SWybQUVhvgQ/lEnNRpapgeFdzMJX1nyzXu9AGH1tlZA46WaVpbroBboFnZvCutWdXxOX/oXYl1ysLfGHicFbwy/UuULYNgEiCnZsS4IWV4HIgOTdvF+vFYrWNlP43wF/AwrnzyhMOhSdcWiexFANCtG6npzpfmAbEcyf2hE3o/OaeiYAnnnjfAK/eNDlinrpCOz2zic3IwyRwBPvUOfMH8A/wMfCelPqn/vtI9z8AfgfeBz507v+mJGknzMpTQewzra90G6xvOdaLXKuqNNyplWpVY0f7vmnPeE4AvCOAPwD/Wgp7KaG/BD6RAl46lttYljO8TIU62t3iCAoAfODHJKtcZzN9v9fdda9yh4ue/v7npi4PPf/7vC5Xa56ObJQ2TV0WtttH0mA4ADxWh2R689OE7D5qYLL678OEEdieRJMebzVnEykpunTd25NYzKVMDA5NXSbnAG7JEQOZQmtM13Zq6jKWJ/66XO/SeypN7pvqUiDWi2xLGAskU3p/6+7kEdnygOOUuxbPO6OxZvsKCJu6PLlNTgaERuPL9e5gCRBNBJ48RHjHAyL1HoUEZ4LnVEAlObD6iTcDlG+TE2vt9Avw2dDmZWBzkkmA/cQs3Bc2qSa/tC9ZDhggV7i+DXze1GU0tMaKgR9Vlr5u6vL5xL3bwcoNjzaiSi4TfumEZLhWeXwX+KKpy5/ugHc0vFfpy5RBM3VfVc9mNwG+0t4tPedOQCGZWrP50dOYBZZc18B3wvMt8OzWGksgjj1JIpYyYnVtZkV8ZX03u7E5lhF2YjNybSRL6zRDRjmtJxkmdF3HYrUNFqvtoes67nsWq224WG3jMWfnfMbKJaz7rut4DW0holiCTPaYAAAAAElFTkSuQmCC" - }, - "asset-2f64bd10-953d-4163-90e9-a55e9ca4c52a": { - "id": "asset-2f64bd10-953d-4163-90e9-a55e9ca4c52a", - "@created": "2018-07-13T13:12:49.516Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-3a26727a-b756-44be-a82c-273dd85bda09": { - "id": "asset-3a26727a-b756-44be-a82c-273dd85bda09", - "@created": "2018-07-13T13:12:56.611Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-93e415d8-82c6-47d4-8c55-e38df329b88b": { - "id": "asset-93e415d8-82c6-47d4-8c55-e38df329b88b", - "@created": "2018-07-13T13:13:02.894Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-aaa14d64-2c1c-47f2-95c0-21306ee18cba": { - "id": "asset-aaa14d64-2c1c-47f2-95c0-21306ee18cba", - "@created": "2018-07-13T13:14:32.348Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-960c8c6e-da72-412d-9d04-34a98cdb5760": { - "id": "asset-960c8c6e-da72-412d-9d04-34a98cdb5760", - "@created": "2018-07-13T13:14:42.533Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-8ae4b612-43a3-4846-8f0d-abb9785e95c3": { - "id": "asset-8ae4b612-43a3-4846-8f0d-abb9785e95c3", - "@created": "2018-07-13T13:15:19.432Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-b1602228-f014-402d-88cd-42821af09dcf": { - "id": "asset-b1602228-f014-402d-88cd-42821af09dcf", - "@created": "2018-08-21T18:29:08.616Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-18070a2a-cd01-410a-ba89-a4505e2fbc5b": { - "id": "asset-18070a2a-cd01-410a-ba89-a4505e2fbc5b", - "@created": "2018-09-06T19:41:55.368Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-803ec373-2608-4f6f-8cf9-0dbb2f6437ce": { - "id": "asset-803ec373-2608-4f6f-8cf9-0dbb2f6437ce", - "@created": "2018-09-06T19:42:19.366Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-466fdcbd-f265-4081-bbcc-367bfcfeaf4f": { - "id": "asset-466fdcbd-f265-4081-bbcc-367bfcfeaf4f", - "@created": "2018-09-06T19:43:02.342Z", - "type": "dataurl", - "value": "data:image/png;base64,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CiRdClkAAAAcaURPVAAAAAIAAAAAAAACyQAAACgAAALJAAACyQACUiJfkBKEAABAAElEQVR4AezdCZydWV0n/H9XUvuayr6vvdB729isza6AiDJuw7jMAOoroKMMigqDA6g4KoPOi7ijiIoivDqoL7I1Co3QG73vnU46+1qpVFJVqSXbnCdNQpKuSm7VfZ6qu3wPn/rUvc9ynnO+5zZPbt3fPeeS5z73uSdDIUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBHIVuCQL6N1+++25VqoyAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBQ7wKXJAAz6NX7q0D/CRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCB3gTMBvdGBp3KvXIUECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKAeBVp61oaAXj2OvD4TIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQKECAnqF8qqcAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBOpVQECvXkdevwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgUAEBvUJ5VU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC9SogoFevI6/fBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCogIBeobwqJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF6FRDQq9eR128CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQKFRAQK9QXpUTIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL0KCOjV68jrNwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgUKiCgVyivygkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgXgUE9Op15PWbAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAoVENArlFflBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCvAgJ69Try+k2AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEChQoI6BXKq3ICBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqFcBAb16HXn9JkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIFCBQT0CuVVOQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjUq4CAXr2OvH4TIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQKECAnqF8qqcAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBOpVQECvXkdevwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgUAEBvUJ5VU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC9SogoFevI6/fBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCogIBeobwqJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF6FRDQq9eR128CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQKFRAQK9QXpUTIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL0KCOjV68jrNwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgUKiCgVyivygkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgXgUE9Op15PWbAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAoVENArlFflBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCvAgJ69Try+k2AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEChQoI6BXKq3ICBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqFcBAb16HXn9JkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIFCBQT0CuVVOQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjUq4CAXr2OvH4TIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQKECAnqF8qqcAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBOpVQECvXkdevwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgUAEBvUJ5VU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC9SogoFevI6/fBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCogIBeobwqJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF6FRDQq9eR128CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQKFRAQK9QXpUTIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL0KCOjV68jrNwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgUKiCgVyivygkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgXgUE9Op15PWbAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAoVENArlFflBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCvAgJ69Try+k2AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEChQoI6BXKq3ICBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqFcBAb16HXn9JkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIFCBQT0CuVVOQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjUq4CAXr2OvH4TIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQKECAnqF8qqcAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBOpVQECvXkdevwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgUAEBvUJ5VU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC9SogoFevI6/fBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCogIBeobwqJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF6FRDQq9eR128CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQKFRAQK9QXpUTIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL0KCOjV68jrNwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgUKiCgVyivygkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgXgUE9Op15PWbAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAoVENArlFflBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCvAgJ69Try+k2AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEChQoI6BXKq3ICBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqFcBAb16HXn9JkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIFCBQT0CuVVOQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjUq4CAXr2OvH4TIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQKECAnqF8qqcAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBOpVQECvXkdevwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgUAEBvUJ5VU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC9SogoFevI6/fBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCogIBeobwqJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF6FRDQq9eR128CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQKFRAQK9QXpUTIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL0KCOjV68jrNwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgUKiCgVyivygkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgXgUE9Op15PWbAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAoVENArlFflBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCvAgJ69Try+k2AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEChQoI6BXKq3ICBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqFcBAb16HXn9JkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIFCBQT0CuVVOQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjUq4CAXr2OvH7XvMD49k1x4sjQtPrZuHBpzOldNKVzR+77Whw7sDfGn3jgzHlNl10bc+cvjtbrX3BmWykPZqrtJ0aGY3zbkxM2qeXy6ybcfrGNE9U5Hc+LXcd+AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACByhcQ0Kv8MdJCAtMSOPCH742jmx6b1rntr/6h6Hz591303CyMNvz1z8fIv/5TnBgbnfT4huaWaH3Z95RUZ1bJTLQ9u07W9sF/+Gj28Bll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ObtLWeZ2ooDeOZWc9yRrw/y3vPe8rZ4SIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjUgoCAXi2Moj4QKFGg3JDb6ctky9b2/+F7nxFgO73/Qr+zQNq8N7yj5KVtT9dVTtsnWpr3YkvWTuecrK0CeqdHzG8CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEBPa8BAnUkUE7I7XymLKQ3dMvfx5Gv/Mv5uyZ93v7qH4rOl3/fpPsvtKOctk90bimz4U00697FlrkV0LvQKNpHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKgvAQG9+hpvva1zgYmCatNZ4vZsxiyQNnr/12L0zlvP3nzmcUNzSzRdd1N0vuIHYk7vojPbp/qgnLZPJ2iXtW+ia14s2CegN9WRdTwBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoHYFBPRqd2z1jMCMC2ThtJMjQ3HswN5oXLE+Gto6omnl+hlvhwsSIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqAQBAb1KGAVtIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGaExDQq7kh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqAQBAb1KGAVtIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGaExDQq7kh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqAQBAb1KGAVtIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGaExDQq7kh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqAQBAb1KGAVtIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGaExDQq7kh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqAQBAb1KGAVtIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGaExDQq7kh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqAQBAb1KGAVtIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGaExDQq7kh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqAQBAb1KGAVtIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGaExDQq7kh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqAQBAb1KGAVtIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGaExDQq7kh1SECMy8wtvGhmb9ozldsvvTqnGtUHQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL0LCOjV+ytA/wnkILDnF16fQy2zW0Xby14bXd/1I7PbCFcnQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBCoKQEBvZoaTp0hMDsCAnqz4+6qBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEClS0goFfZ46N1BKpCQECvKoZJIwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBGZYQEBvhsFdjkAtCgjo1eKo6hMBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC5AgJ65Qo6nwCBENDzIiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDwTAEBvWea2EKAwBQFDv//fzXFMyrv8K7v/rHKa5QWESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEClCgjoVerIaBcBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVLWAgF5VD5/GEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEA9CowfPR4HD4/Fvv4jp7q/ckln9HQ21yOFPhMgQIAAgYoWENCr6OHROAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAg8C2Bw0Nj0Z+CeYPD49/a+M1H11y64BnbbCBAgAABAgRmV0BAb3b9XZ0AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECJQk8ODGvgset3pZZ3S1m0Xvgkh2EiBAgACBGRYQ0JthcJcjQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKlCJw4cTIaGi6JiwXzTtfV0dYYa5d3n37qNwECBAgQIFABAgJ6FTAImkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBM4W2N03HH0HR87eVNLjdcu7or2tqaRjHUSAAAECBAgULyCgV7yxKxAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgZIEDgyMxK79wyUdO9FBXR3NsXpp50S7bCNAgAABAgRmQUBAbxbQXZIAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECJwtcGT0aOxOwbwjo8fO3jytxxtWdkdrS+O0znUSAQIECBAgkK+AgF6+nmojQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJTEshmzMtmzsurmEUvL0n1ECBAgACB8gUE9Mo3VAMBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEJiywKHBsdi2Z3DK55VywrrlXdHe1lTKoY4hQIAAAQIEChQQ0CsQV9UECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQOB8gRMnTkY2a97Bw6Pn78rteUdbY6xd3p1bfSoiQIAAAQIEpicgoDc9N2cRIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEpCwwOj6dw3lCMHz0x5XOnesKaZV3R2W4Wvam6OZ4AAQIECOQpIKCXp6a6CBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAJAJ7DxyJff1HJtmb/+b21rmxbkVP/hWrkQABAgQIEChZQECvZCoHEiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBqQscO3Yitu8djKEjR6d+cplnrFrSGd2dzWXW4nQCBAgQIEBgugICetOVcx4BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIELiIwFBa0nbHvqE4mkJ6s1Fam+fEhlXzZuPSrkmAAAECBAgkAQE9LwMCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCAQN/BkdjdN1xAzVOrcsXijpjX1TK1kxxNgAABAgQI5CIgoJcLo0oIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMC3BHamWfP6D41+a8MsPmpumhOXrTaL3iwOgUsTIECAQB0LCOjV8eDrOgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjkK3AsLWW7fe9gDB05mm/FZda2bGF7zO9pLbMWpxMgQIAAAQJTFRDQm6qY4wkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwAQCI6NH48nthybYM/ubGuc2xBVre2e/IVpAgAABAgTqTEBAr84GXHcJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAIH+Bw0NjsXX3YP4V51jjkgXtsXCeWfRyJFUVAQIECBC4qICA3kWJHECAAAECBAgQIECAAAECBAgQIECAAAEC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AQQQQAABBBBAAAEEEEAAAQQQQAABBBCISwEC9OLysnPSCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACTgsQoOe0MO0jgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgjEpQABenF52TlpBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABpwUI0HNamPYRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQTiUoAAvbi87Jw0AggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIICA0wIE6DktTPsIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAJxKUCAXlxedk4aAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEDAaQEC9JwWpn0EEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIG4FCBALy4vOyeNAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgtAABek4L0z4CCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEBcChCgF5eXnZNGAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBwWoAAPaeFaR8BBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCAuBQjQi8vLzkkjgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgg4LUCAntPCtI8AAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIBCXAgToxeVl56QRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQScFiBAz2lh2kcAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEIhLAQL04vKyc9IIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAJOCxCg57Qw7SOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCMSlAAF6cXnZOWkEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAGnBQjQc1qY9hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBOJSgAC9uLzsnDQCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIDTAgToOS1M+wgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAnEpQIBeXF52ThoBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQMBpAQL0nBamfQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgbgUIEAvLi87J40AAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIOC0AAF6TgvTPgIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQFwKEKAXl5edk0YAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEHBagAA9p4VpHwEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIC4FCNCLy8vOSSOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCDgtQICe08K0jwACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggEJcCBOjF5WXnpBFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBJwWIEDPaWHaRwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQiEsBAvTi8rJz0ggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAk4LEKDntDDtI4AAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxKUAAXpxedk5aQQiT+DzQ4cjr1NR3qOZPbKj/AzoPgIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggEN0CBOhF9/Wj9wjEjMDX/vVhzJxLpJzIndMmyJTsbpHSHfqBAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgjEnQABenF3yTlhBCJTgAC98F8XAvTCb0qLCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIICAHQEC9OxoURcBBBwTIEAv/LQE6IXflBYRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAE7AgTo2dGiLgIIOCZAgF74aQnQC78pLSKAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAnYECNCzo0VdBBBwTIAAvfDTEqAXflNaRAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEE7AgQoGdHi7oIIOCYAAF64aclQC/8prSIAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgjYESBAz44WdR0XaKqplvo92z2Ok9QjRzpm9fRY52uhfm+hNB076rE5ZehYj2WrC2Z9ce0bTJv+2nO1a3zaOV/3/aL9OwF64b+CBOiF35QWEUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABOwIE6NnRoq7jArVb1kj5iw95HCchM0t6/uRZj3VmC8fLDsrhx38sTXW1Hpt7P/Ynj2WrC9UL35WqN39rWr3HnU9ZDhp0NWB2bq5t3p+JfXKly7mXSjCBgN5tRcsyAXrhv1IE6IXflBYRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAE7AgTo2dGiruMCvoLY0s6+UNLnXuD3+GXzHpX69Sta1Qk2QM9Xe8YBrPTHuyO+zs27nvty5znnSNfzvuW+Kma/E6AX/ktLgF74TWkRAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBCwI2AE6P1/AAAA//98HDkAAABAAElEQVTs3Qd4HNW58PFX27RFzZLcscEYbIqDDQQIPWCaSUIogZAekpB6Uy65aTfwhdwQUripQEiHS0kgBAihhRB6S+jFFAdMcbeaV1ptL/rOWSOhlbZKM7szu/95nmV3Zs6c8pvFo9195z1NIjKiHhILvqqfWBComUBszdMS/M338rY/879/Ls7OWXn3RZ96UAavvDDvvjn/e3Xe7cU2ZqJh6Tnn4wWLuOYtkO6zLii4P9+OYmPLV350W2DVadK68uTR1bp9PvGWO+t2bLUa2H+/bR/Zv2tGrZqnXQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAoOEFvB2LpEkpEKDX8G8FawAUC2JzL95Nuj5z7qSO6mC6vh99RTLBgUn79IapBOiFH7pdQtdfmre+0Y3FAgZHy4x/Lja28eUmvnY0e6Xryz8sGJw4sbxd1wnQM/7MEaBnvCk1IoAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAClQgQoFeJFmVNFygVxNb+wc+Lb8XBOf0I3Xm9hG/7U8628StTCdAbuOwCSax+fHw1k15Xmtku39gm1pEe6JFtqu3UpvU57U0sl7OzTlYI0DP+RBKgZ7wpNSKAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAApUIEKBXiRZlTRfIF8Q2vlFHR6d0f/kCcfgC2c06oK33/C+MLzLpdaUBevmmt/Us21dSLz0nmXhsrP5Kp7nNN7Z8gXf5xlQoe+BYZ+rgBQF6xp9EAvSMN6VGBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECgEgEC9CrRoqzpAvmC2CY26j/8eGl714ezm/svOVeSa1+cWCRnvdIAvXzT27aefIYkN6yV2CP35dRdyTS3+caWL0BPNzBxXATo5bCzUqYAAXplQlEMAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAwSYAAPZNgqXZqAvmC2PLV1PnF70py/csSuv7SfLtztlUaoDcxOE5XNus7v5P4mqdk8MoLc+ouFGCXU+iNlXxjK3R8zzc/mpOtjwC9fKJsKyVAgF4pIfYjgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAALmChCgZ64vtVcokC+ITU9rmwkO5NSkA9bSG17LCWLTBfT2iRn1KgnQKzW97Jb/Oj2nH7pvs87+Rc62Qiv5xpYvQG/opsslcu+tOdWMzxqYs6OOVpji1viTSYCe8abUiAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIVCJAgF4lWpQ1XaBQEFv86YcltWl90fa9+x8mzq45Er7tTznlKgnQC915/aTjxwfRDVx2gSRWP55Tv87m51mwOGdbvpV8Y9MBfs6uWWPF0/09k4IR9c5KptIdq8xmLwjQM/6EEaBnvCk1IoAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAClQgQoFeJFmVNF8gXxKYD5JqXLJeBn32zYPuOZq90n32xhB+6fVKAXSUBen0//sqkQMDxwXG6/onT6pab3S7f2AoOaNyO8QGC4zbX3UsC9Iw/pQToGW9KjQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQCUCBOhVokVZ0wXyBbGNBqjlm/p1tEOjZfJlwCs3QC/f9LaueQuk+6wLRpuRTDQsPed8fGxdvyh3mtt8Y8upKM+KzgrYcdpn8+ypv00E6Bl/TgnQM96UGhFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgUoECNCrRIuypgvkC2IbDb7TwXF9531OMvFYTj/ci3eTrs+cm902nQC9fMfquj1L9sppL/rwPyZNQ1vONLf5xpZT8YSV1pPPkMBBx07YWr+rBOgZf24J0DPelBoRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIFKBAjQq0SLsqYL5AtiGw3Q043nm2J2fHBcviC7cjPo5ZvettwBlzPNbb6x6Qx53uUHS7p/y6Spcxspe552JkCv3Hdb+eUI0CvfipIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIAZAgTomaFKnVMWyBfENj5AT1fcf8m5klz7YraNiYFxUw3Qyze9bSWDKGea21JjGz+u0bY7zvyGeJcuH12t62cC9Iw/vQToGW9KjQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQCUCBOhVokVZ0wVKBbHpDiTWr5WBn31THM1e6T77YnH4AmP9mmqAXr7jxiot88X4TH75Dik1tnxBgq55C6T7rAvyVVd32wjQM/6UEqBnvCk1IoAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAClQgQoFeJFmVNFygVxDbaAR1Q5+qaLb4VB49uyj7nC7QrZ4rbfNPbuhfvllP3+JWRaFhSm9aP3yQTs/nl7FQr5Yxt6KbLJXLvrTmHtp58hgQOOjZnWz2uEKBn/FklQM94U2pEAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQqESBArxItypouUE4QW7FOTCVAL1/mulJT1k7lmHLGllGBf33nfU4y8djYMPNlChzbWUcvCNAz/mQSoGe8KTUigAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAKVCBCgV4kWZU0XKCeIrVgnphKgl++YUtnwdB/yZd0rNs1tuWOban+KudhhHwF6xp8lAvSMN6VGBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECgEgEC9CrRoqzpAuUGsRXqSL7gtlJT3FYaaDfadr62igX2VTK2nvM+K5ngwGhT2ediwX85BW26QoCe8SeOAD3jTakRAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBCoRIAAvUq0KIsAAqYJEKBnPC0BesabUiMCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIFCJAAF6lWhRFgEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIEyBQjQKxOKYggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAghUIkCAXiValEUAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECgTAEC9MqEohgCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAClQgQoFeJFmURQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQKFOAAL0yoSiGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQCUCBOhVokVZBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBMoUIECvTCiKIYAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIFCJAAF6lWhRFgEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIEyBQjQKxOKYggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAghUIkCAXiValEUAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECgTAEC9MqEohgCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAClQgQoFeJFmURQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQKFOAAL0yoSiGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQCUCBOhVokVZBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBMoUIECvTCiKIYAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIFCJAAF6lWhRFgEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIEyBQjQKxOKYggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAghUIkCAXiValEUAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECgTAEC9MqEohgCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAClQgQoFeJFmURQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQKFOAAL0yoSiGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQCUCBOhVokVZBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBMoUIECvTCiKIYAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIFCJAAF6lWhRFgEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIEyBQjQKxOKYggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAghUIkCAXiValEUAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECgTAEC9MqEohgCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAClQgQoFeJFmURQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQKFOAAL0yoSiGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQCUCBOhVokVZBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBMoUIECvTCiKIYAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIFCJAAF6lWhRFgEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIEyBQjQKxOKYggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAghUIkCAXiValEUAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECgTAEC9MqEohgCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAClQgQoFeJFmURQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQKFOAAL0yoSiGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQCUCBOhVokVZBBAwTeDmjVtMq9sOFb9z/hw7dJM+IoAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIDAtgUxmRNLpEUml05J+47V+1tszI6PPkn2tVkXUf/Szfjm6NKkXTW/8x6Gem9SKfnao/+iHc/zD6RCXejidTdlyo3XwjAACCCCAQLUECNCrljTtIIBAUYETb7mz6P5633nREQfJDn5fvQ+T8SGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCNSxgA6ySyTT2x+pjCST6qGedTBe9jm1PQivVgQ6cM/lcohbBeu5XE5x69fq4XE733g4COKr1cmhXQQQQKCOBQjQq+OTy9AQsJMAAXoE6Nnp/UpfEUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIFGFtCBd7FESj3SElePRDKlnnUgXsb2LDpgr1kH7Hmc4lWP5uyzKxvYZ/vBMQAEEEAAgZoIEKBXE3YaRQCBiQIE6BGgN/E9wToCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEDtBWLxlESzj7TE4kn12D41be17Vt0e6Glyvc0qaK/ZJT718KuHDuJjQQABBBBAoJQAAXqlhNiPAAJVESBAjwC9qrzRaAQBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQKCgQEpNRxuJJdUjlX2OxtKSGRkpWL7RdzjVVLnZYD2vWwI+l7T4PY1OwvgRQAABBPIIEKCXB4VNCCBQfQEC9AjQq/67jhYRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgcYW0AF5w9GkhNUjoh56ylqW6Qn4vSq7ng7Y86uAPZ9HHI6m6VXI0QgggAACthcgQM/2p5ABIFAfAgToEaBXH+9kRoEAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIWFdAJ8MLRxIS0kF56jmqpqtlMVdAB+zpzHqtfrf4fW5zG6N2BBBAAAFLChCgZ8nTQqeKCWSiYUmsezlvEe/S5Xm3F9tYrL7xx5lZt3vmXHF2zhrfXMO9JkCPAL2Ge9MzYAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECgCgLJZEaGInEJhZMyrILymLG2CugFmtBT4ra+EazXGmgWvc6CAAIIIFD/AgTo1f85rrsRhh+6XULXX5p3XDP/++cVB7rF1jwtwd98L299Ezd69z9MWo96T9ltVFK3a94CaXnHB2UqgYAT+2nHdQL0CNCz4/uWPiOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACVhSIxVMyFFaZ8tQjEktZsYv0SQm0qKx6rQGPtKtgPbfbgQkCCCCAQJ0KEKBXpye2noc1cNkFklj9eN4hBladJq0rT867r9DGSoLodB2OZq+0nnqm+FYcXKjKse2V1q0P9B9+vLS968NjdTTKCwL0CNBrlPc640QAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEzBCIq+lqg+G4DA3HJcbUtWYQm1pnwOeSNhWo195CsJ6p0FSOAAII1ECAAL0aoNPk1AX0dLQ953y8YAU6C133WRcU3J9vx1SC6HSQXsenzxHPgsX5qhzbNpW69cFTCTQca9SmLwjQI0DPpm9duo0AAggggAACCCCAAAIIIIAAAggggAACCCCAAAII1EwgmcpIMLQ9KI9MeTU7DYY3rDPr6UC9jtZmcTiYBtdwYCpEAAEEqixAgF6VwWluegLFprcdrbnSaW6nGkTnXrybdH3m3NFm8z5PtW4dANj15R+WPZVu3sZttpEAPQL0bPaWpbsIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQM0EdFCefugpbFnqW0AH6emHngqXBQEEEEDAngIE6NnzvDVsr4tNbzuKUmn2uXxBdBPriD71oISu/Y1k4rHRZrLPnV/8btEseuXUnR7okW1q2t7UpvU5dU/sQ87OOlwhQI8AvTp8WzMkBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQMAwgVg8JQNDKjBvKCbpzIhh9VKRPQQ8bocK1PNKZ5tX3Oo1CwIIIICAfQQI0LPPuWr4nuab3tazbF9JvfRcTuBcpdPclhNEp/HzZe8rFURXbt06SK/3/C/knONyMvTlHGDzFQL0CNCz+VuY7iOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACpgjogLxt6jEcTZlSP5XaT6BNTX/b2UZWPfudOXqMAAKNKkCAXqOeeRuOO1+AXOvJZ0hyw1qJPXJfzogqmea23CC6fAGCRgXo6c73X3KuJNe+ODYOAvTGKBrixUVHEKDXECeaQSKAAAJ2FMikJT04IOmhbZIZDko6NCiZcEhG1EP/faQfEotKJqEyDcfjkknGRZJJkbT6sjCdlpGRjIwktk+z4fD6xNHeKa4ddpLmpSvEt8+hdhShzwgggAACFhHQ1yZ9jXrz+jT0xvVp+M3rk86Er65PI8lE9pG9PqXSkhlJi7xxfdLDcc6cLc65C6R5l7eIb+9DxOELWGSUdAMBBBBAwG4CmeHB7Oen9FBQXaP056eh7Y/IsIyoz08j+vNTPKquT7E3rk9vfH5KpSSjPn+Nvz45ZnSJa8588SzeU3zLDxTnjFl246C/CCCAAALTEEilMtI/uD0wL6lesyCQT8DrccqM9u1Z9RyOpnxF2IYAAgggYAEBAvQscBLoQnkCEwPY9FGzvvM7ia95SgavvDCnklKBc+MLlxugp6e5rbSdcuvW/en55kdzMgESoDf+LNX/awL06v8cM0IEEEDAygLpga2S7Nks6X796JGUyu6bCfZJZlAF5YWGTOu6I9Aqvre/Q1qPONG0NqgYAQQQQMC+AtkA8d5NkuzT16etkh7olbS+PgVVUN5gUA3MpOmcHE7xH3KMtJ3wEfvi0XMEEEAAAdMEdNBdqnezpPq2SKp/i2TU56f0tj4VNN6//fqkblQya/Hue4h0vO8/zKqeehFAAAEELCIQjSVVYF48mzHPIl2iGzYQ0MF5nSpQr7vdx/S3NjhfdBEBBBpPgAC9xjvnthxxqSlgt/zX6TnjcnR0yqyzf5GzrdBKOUF0OjPMgMpwl9q0Pqea9g9+XnwrDs7ZNn6lnLp1+aGbLpfIvbeOP1T8hx8vbe/6cM62el5hilsy6NXz+5uxIYAAAlYR0IF4iU2vSWrzOkltWS/prZuyPyqJytRQy8W142JpP+0z4p69Qy27QdsIIIAAAjUS0Jnwkhtfk+SW1yWtrk+prRsl06sCHnT2uxoujs4uaTvlk+JduryGvaBpBBBAAIFaCWRUxruU+vyU2Py6+vykPkONXp/Cw7Xq0li7rad9SgL7HzG2zgsEEEAAgfoQGI4kpC8Yk1B4+2wU9TGq8kfhaGoSHWTmVA+HQ7Kvm9S20YeuaXyCuBF1z9aI+o++dUs/ZzLqtXpOq2SDmUxGPev18tuvp5Iz2lSgXodXvM2uehoWY0EAAQRsLUCAnq1PX+N0PnTn9RK+7U85Ax6fJW/gsgsksfrxnP2dX/yueBYsztmWbyVfEJ0O8HN2vTldQHrDa5N+GCgnCLCsulWWGn33/8Slkml6Jx5rx3UC9AjQs+P7lj4jgAACVhZIb+uVxLp/S3LdWklueFXSm9Ztn+7Pop12BFqk44yviGenpRbtId1CAAEEEDBCQGcdSqx7ST1eltSGVyS18XWVrXXQiKpNq6P9A/+RnfbWtAaoGAEEEECg5gIjKig8/rr6/LT+ZfVYqwLz1PVpoK/m/SrWgcDx75XWI08qVoR9CCCAAAI2ERgajkt/MCrD0dreRGsWl9vlEP3wuJ3i0q+djjeem8TldIrTqYLy1EMH4hm96KA9/UipqL3sQ00VnEyPiJ4yWD9SqbQkkmm1rz4j+dpbmrOBen6f22ha6kMAAQQQqFCAAL0KwSheG4G+H39lUva68QFs4Ydul9D1l+Z0rtwMdPmC6HIqKrBSKnuePmyqdY8PPizQfN1tJkCPAL26e1MzIAQQQKDKAkkV5BB/9XlJvLpGUq+vVVMrTb4BoMpdqri5jJryNnH618U5Y1b2DlmX/rJOfTk3+ux2bf8ST99Jy4IAAgggYA+BZM9GSbzygiRfe1GSr78k6d6t9uj4hF7GTvmSOHba840fjtT1SV2LXK7t1yi3+kFJ/8ikf1BiQQABBBCwh0A62K+uT8+rz1AvqM9PL0367tkeoxCJr3y/yIojspmG9Gcn57jPUKPBEHobCwIIIICANQV0YF7vtqhEYvURmBfwuaTZox4qEK/Z48wG5HncDlMC74w+ozqITwfqxdUjkUhLLJlRz6m6OTetAY/MnOGTAIF6Rr91qA8BBBAoW4AAvbKpKFgrgXzT27rmLZDusy4Y65KegrbnnI+PresX5WS40+WmEkRnZvCfd//DpOO0z+quNdRCgB4Beg31hmewCCCAgAECSTUFYOKlZyS+9jlJvbJGMpGwAbXWvorYDksk9I4vFO2InuYi+2OT+rJP33mrv+jLfvGnX6sv/1gQQAABBGonoDO4xv79jCRfXq0CH15UAePbatcZA1tOtXfJtveeK+qXpYK16umY3OqaNJoZQl+jmtV69lldn8zIBlGwM+xAAAEEEMgRyISHJP7SsxJ/+VlJrn3BtgHjOYN6Y6X/vd+UTMfcfLuy2/SlK3ttUjc8ucd9fsp+jlJBFNwAVZCOHQgggIBpAkPhuPSpwLywjTPmtanMbL5mp3q4stOo6mtNvS46YC+qgvVicfUcT9l6CmIdqDdLBeqRUa9e362MCwEErCxAgJ6Vzw59ywrkm97WvXg38SzZK0co+vA/Jk0VW840t5UE6Omgv9Z3fkB8Kw7OabvQSiV16zpaTz5DAgcdW6i6ut5OgB4BenX9BmdwCCCAgBECibhEX3xC4mueksS/V0tmW78RtVqyjuDbPyDJpQdOuW9efYeu+qFJP+svCr3qi0IdHMGCAAIIIGCOQOzFJyWRvT49K6mtm8xpxAK1Dq84SqIHnDjlnowGQujrk7426R+ydFYJFgQQQAABcwQSr76obs5W16h/q+vTulfMacQCtUZ3eosMH/upKfdEB1To65FXf4bSn5+y1yl3sZj0KbfFgQgggECjC4QjCelRgXnDkaStKHRmPL/XrR7bn3UG8UZfdLY9nfkw+4gms4F7djLpaG3OZtTTn01ZEEAAAQSqI0CAXnWcaWUaAvmmty23unIy3eULossXAOjqml12YN5o//LVrTPkeZcfLOn+LZOm5W3U7HnaiwA9AvRG/7/hGQEEEEDgTYFsFqLVj0r8hcfVj0rPvbmjzl8luufL4CnfMHSUOuueT32JqIMh+DLRUFoqQwCBBhTIREISe+4xiT3/uCTXPCsjKoi8EZYRt0f6PvpDlbLfuB8wdNY9n1cH7L3xY5e6TpENthHeTYwRAQRMEUirrDbPPSLx559QgeNPSyY0ZEozVqx04D1fk3TXAkO7pj87jf8MxQ/4hvJSGQIINJhATGVd2zoQFT2lrR2WFjUNasCvHupZB+YVSSRuh+FUpY96itywCtQbfdhl2uLOdq/M7vQLQZdVeZvQCAIINLgAAXoN/gaw+vDzTW9bSZ/LmeY2XxBdYNVp0rry5Eqaylu2VN39l5yrplR4MefYjjO/Id6ly3O2NcIKAXoE6DXC+5wxIoAAAuUIpPo2S/SZf0pcBT6kXl9bziF1WWbg5K9KeuZC08em7xbVXzbqB1mMTOemAQQQsLFAJjSork8Pq+vTow0VND7xlA0e8UFJLHnbxM2Gr+vponSWioAOLlc/iLEggAACCBQQSCYkoj4/xZ79lyReeEpEBek14jK8YqXK8nqS6UNveSNYY/QzlOkN0gACCCBgc4F0OpMNzOsPRi09Ep09tcXvUQ939tFERN60z1c6PaIyJSYkpLIl6udkKjPtOs2qQJ/uWSpITz9YEEAAAQTMEyBAzzxbajZAIN/0tpVWW2qa21JBdJW2N758qbrzBSC65i2Q7rMuGF9NQ7wmQI8AvYZ4ozNIBBBAoIBAenBAok89KDH1w1IjB+WN5xk64ASJrzhm/CbTX+upnfQPTdkvI30ecbuZrsN0dBpAAAFLC4zEoxJR16f40w83dFDe+JMUWfJWCR/x0fGbTH+ts8AG9I9lKmBP/2hGQLnp5DSAAAI2EIg+/ZBE9fVp9RMimcYMyht/mhIzF8jgyV8bv8n01/rH/O2fn7ZfowgoN52cBhBAwGYCvWoq256BiOjMalZc9PdfrQGPtKnPGGTxNv8MRWPJbLBeKKxuLlBT41px8ajvQnWQ3ow2rxW7R58QQAAB2wsQoGf7U1jfA8g3va2efrbQMhINS2rT+pzdpaa5LRVEl1NZhSvl1D100+USuffWnJpbTz5DAgcdm7Ot3lcI0CNAr97f44wPAQQQmCQwMiKRx++T2JMPqOmXnp20u9E3RHZVARBHfrSmDL7m7XcPt+osEerLShYEEECgUQRiKkte9In7Jf7MYyIj1r3Lvxbnw4xp2Csdh/7RRAfqtQbUD2r+ZqabqhSQ8gggYFuBxNrnJfLkfZJ46hHJxCK2HYcZHc+43NL/8Z+YUXXZdbqc+vq0PdijVV2nnE4VwceCAAIINKCAnsZ2qwrMi8WtF0CuA/LaW1RQnnp2qn+3WWojkExmZDAcz055HI5aL1hPX89nd/mz0xvXRohWEUAAgfoUIECvPs9rXYwqX3a5UlPWTuWYcoLopgpaTt0ZFVTYd97nJBOPjTXjaPZK99kXi8MXGNtW7y8I0CNAr97f44wPAQQQGBVIvLZGBebdI4knHs65/o/u53m7QGz+Egm98wuW4dDZi1oDzeoLTLe0qS8ymerDMqeGjiCAgEECya0bJPrYPRJ74kHJDG4zqNb6qybtb5OBD51vmYHp7EU6WK9dZ75Q1yd+ZLPMqaEjCCBgkEB6KCiRx+6W+OP3S2rrJoNqrc9q+s64QEY8PssMbjRYTweBeNxOy/SLjiCAAAJmCeigqy39YQmG4mY1MaV69b/H7S3N2QfB01MiNPWgbLCeCuocVA+rZdbr6vDJHBWo51Dfi7IggAACCExfgAC96RtSg0kC+aa3LZUNT3clX9a9YtPclhNEN9Uhllv3VMc61X5Z8TgC9AjQs+L7kj4hgAAChgmk0xL+1z8k+ug9klr/qmHV1nNF8XmLZehd/2nJIeqvpFqzX2xuv+uYYD1LniY6hQACZQroKdajj9zFFLZleulivZ+6qILS1S2qf3xrU9eoDoL1qgtPawggYLhA7MWnJKKvT888Ynjd9Vph30e+LyPeFksOz+91Za9POqCcaRQteYroFAIITFNAT2e7tS8sVpnM1utxSker+lzQ6hW3ysDNYg+BWDyVDfDU7yerLG6XIxuk18G0t1Y5JfQDAQRsLECAno1PXr13vdJAu1GPSoPdyg2iG62/kudK6u4577OSCQ7kVF8ssDCnYB2sEKBHgF4dvI0ZAgIIIDBJIJuN6OE7JPbovWTLm6RTfEN00V4yfMwnixeywF6duWj7Xcg6c1GzBXpEFxBAAIHSAtlsRP/8uwrMu2fS59DSRzd2iWTHLAm+9//ZAmF0+ir9wxzB5LY4ZXQSAQRSKQk/fLtE/3W3pLZswKMigSYVQH5hRUfUqnDA5xrL5ORSP/qzIIAAAnYWiESTslkF5lkl89kMFUQ1o61ZAj63nVnpuxLQUyVvCyWyz1YA0d97zu32kxXXCieDPiCAgG0FCNCz7amj4wjUlwABegTo1dc7mtEggECjC8TWqGwPD/9dEqufaHSKKY9/eO+jJbr/u6d8fC0OdDmbpF3dmTyj1SM+L1+E1uIc0CYCCBQXSKx/WSIP/V0Fjt9XvCB7CwrEdlomoWM/XXC/FXdkg8nfuD7p6XBZEEAAAasJpAe2SviB2yX2r7u4sWmKJyfV3i3bTj93ikfX7jA9/W2HCiTRNz2xIIAAAnYT2KIC86yS6WzuzIB0quA8piK127uodH/1FLgDQzHpGYiULmxyCT2ryBz1XutWU9+yIIAAAghULkCAXuVmHIEAAggggAACCCCAQF6B6BP3S/jBv0nq9bV597OxfIFtqz4tqYXLyj/AYiX1FE46Y5G+c5kvRy12cugOAg0oEHvxSYk8eJskXnimAUdv7JCHDjhB4iuOMbbSKtbW7FZTXalACP3jHVmLqghPUwggkFcgse4liTxwm8SeeCjvfjaWLxBZup+E3/6R8g+wWEmX07H9+qQCypubnRbrHd1BAAEEcgWGI4ls1rxYPJ27o8prOqNZp/rbXmfOZmkMgWAoLgODUQlHUzUdcIvfLfNmtkizmkqZBQEEEECgfAEC9Mq3oiQCCCCAAAIIIIAAAnkFwipbXuT+2yTdsznvfjZWJpDxBqT/Iz+o7CCLltZZi3SQnv7ClKx6Fj1JdAuBOhaIPvOQhO+7VVKvvVzHo6zu0Prf9y3JtM2sbqMmtaazFXW2NwtZ9UwCploEECgokHh5tQzff4sknnuyYBl2VCYQPPZMSe60vLKDLFpa/+ivA8nb1Q1PLAgggIDVBKyQNa+z3Svd7T4Cmq325qhif8JqauWBwZjogL1aLjpzI9n0ankGaBsBBOwmQICe3c4Y/UUAAQQQQAABBBCwjED4gVsl9JfLLdOfeunI8D7HSHS/E+plOGPjaPG5ZYb6ElVn1mNBAAEEzBSIPvmADF51kZlNNGTd0UV7yfAxn6y7sftUpqJsMLn6kU8HlrMggAACZgnE1jwtkftuksSa1WY10ZD1JjvnSvDUb9bd2D0uR/bzU5f6DOVUGfZYEEAAgVoKRGNJ2dQblkisdpnLZnX6VTAU/ybW8n1gtbbjibT0BaPZYL1a9U1ncJyvsum53Vyra3UOaBcBBOwjQICefc4VPUUAAQQQQAABBBCwiICexjZ8782SGeizSI/qqxu9n/ipiNNVX4MaNxqPml5Q/8jUpb5UbSISYpwMLxFAYLoC0acflPA9N0lq/WvTrYrj8wj0n/oNyXTOz7OnPjY5nU0qo55PZeNg+tv6OKOMAgHrCGQz5t39FwLzTDolwaM/Jsmd9zGpdmtUS7Yoa5wHeoFAowr0bouKzpxXi0VPAa6D8rpn6JtpuJumFufADm2mUhnpVYF6feq9WovF6WiSebMC6qZkby2ap00EEEDANgIE6NnmVNFRBBBAAAEEEEAAgVoLRB69W8J336imst1S667UbfvbjvmEpBatqNvxTRzYTH33M4EQE1lYRwCBCgViLzwu4bv+IslXX6rwSIqXKzB0wAkSX3FMucVtXy4bCNGhps3yOG0/FgaAAAK1E0ise0mG77pBEqufqF0n6rzl8B4HSeTQ99f5KN8cnp6eXQeq+FV2chYEEEDAbAEd9LShZ1hC4YTZTU2q36VunumeoTPmkeV6Eg4bCgrUOlBPf46cP6ulYP/YgQACCDS6AAF6jf4OYPwIIIAAAggggAACJQVizz0qw3feIKl1r5QsS4GpC6SPOFUy+x4jqXRGMpmR7HMqNSKZkZGpV2qTI/UXrjPV3dAuNY0TCwIIIFCuQOL1NTL8j+sl8cLT5R5CuSkIpPc5QjJHvl/S6tqUVtcofZ1KpdX1Sa3X+6IzIMyc4RVvc/1mtq33c8j4EKiFQLp/i4TuuE5ij91fi+Ybps3MLm+R9ElfzF6bMpnt1yZ9jUqra1S9L3o6PR2o1+L31PtQGR8CCNRIYGg4Lht7wtm//avZBYfKRKa/H9IPMuZVU76+2tKBej0qm16/yqpX7cXX7MwG6fm8BNNX2572EEDA+gIE6Fn/HNFDBBBAAAEEEEAAgRoJJNa/LMN3/FkSzz9Vox40TrOtp3xMAgfmz0ykAyCS6oulZCqdfU4kM7L9kVLP6WyQRL1IdelAPfVwuwnUq5dzyjgQMEMgHeyV0O3XSuzR+8yonjrHCfhXvlvaVr1v3JY3X44Gk2evUep6lFDXKn19SqrXcfXQ2+tl6Whtzv5ISKBevZxRxoGASQLJhAz9/U8Suftmkxqg2lEB71sPlY7TPze6mvM8om5w0jc6jX1+yl6f1HVKX6uyj/q5PrX43dnrE4F6OW8BVhBAYJoCW/sj0jMQmWYtlR+up7GdpbLmOVX2PBYEjBBIJNLZQL1tQzEjqquoDp1JT2fUY0EAAQQQeFOAAL03LXiFAAIIIIAAAggggEBWIBMekqHbr5HYQ3ciYrKAZ5c9pOUdHxDPgsVTbklniIgnUhJTXzrph349HElOuT4rHLj9S1mf+lKWQD0rnA/6gICVBEJ/v0bCd9woMlI/P65byXe0L665O0jLqtPFu8dbRzdV/KwD+PQ1Kf7G9Ulfo2oxPVbFHS9yQEebV/1oyNS3RYjYhUDDCoQf/JuEVVbXTGioYQ2qNfDWUz8hgQOOmnJzOkG5/sE+Nu4zlM4UZedFZ9TT2aYCTH1r59NI3xGouYDOlr1+a/WntNV/Y8/u9InH7ay5AR2oT4FINJkN1Kv251GmvK3P9xOjQgCBqQsQoDd1O45EAAEEEEAAAQQQqEOB4ftvlsjt10kmVv0pAOqQM++QHP6AeJa8Rbz7Hibe3ffJW8aIjUmVxahvMCr6vuNoTAXtqS+j7LQ0qY7PVHdOz1Jf0jKtiZ3OHH1FwByB6JMPSOhvf5JMf485DVCrqPSlogPHfXsfIr59DjVNRE83tC0UF53hKKKuT9X+kcSIgekfWmZ3+pma3QhM6kDA5gKxl56V4b9dLanX19p8JNbuvnvREvEuP1AChxynOmpOZiV941MsnpRIPJ29PtkxaK+9pTn7+YmMr9Z+P9M7BKwoEI4kZEPPcDYjdrX61+JzyayuAMHF1QKnHRlUAfk9KkOkvnmsWovf65IFs1vF4yEAtVrmtIMAAtYVIEDPuueGniGAAAIIIIAAAghUUSD7w9Jtf5TUuleq2KoNm1LBC46WVnEE2tSjRRz+VmlSAXdNzSqIzOsXh6dZBTg0i8PtEfWrvTQ51ZcvTSoLnIo2c6jtzhnd4uyaU7OBR2NJCatgiHA0JXb5wcmlsujpID09/S0LAgg0nkByyzoJ3foHplsvdeodzu3XpzeuUdlrk19dp9S1qcnrU9cnNbXOuOuTONU1yrH9+iROtzjbZ4h79oJSrZi2X2fZC6tA8tGHXabHnaWC9PRDB5WzIIBAYwlkhgdl6NarJPYI060XP/Pqc1Dr9s9PTQH12SkQEIdv9Pqk/v1sbpYmdY1qUp+fmtTnp+3XJ/0ZSv3D6nCJs7Vt+/VJXbdqseibnsLRRPYzlM6+U80f9KczXgLJp6PHsQg0nkD/YEw2qeC8ai1ul0Nmd/llhsqcx4JALQR61RTOeipnlVS3astbdu2uWls0hAACCFhVgAA9q54Z+oUAAggggAACCCBQFYFMLCJDt1whsYfvrkp7dmhET+vn6JotLvVwds5Sj5ni7FCBde1dKiCvxQ5DKLuPOmBvWAXrDas7pa0+La6v2ZkNgmhTWSFYEECgMQT0dOuRO25ojMGWMUrnrLni7FbXp87Z6jqlrk0zZolLX5861PWppb2MGuxTRAfsZa9Nb1yj9HS5Vl30D4w6SE8HQ7AggEBjCIQfUtPZ3qqyuqrPUiwqjk5dk1xds8TRPUddo9Tnpxn6GqWvT+rR1llXRDqAfPtnp+2foVJqOkirLjrGcTSQ3Kp9pF8IIFB7gU29YekPVm8WjW5186UOznM4uMOl9me/sXugg/C39IclqLK7V2uZ2x2QbjUlPQsCCCDQqAIE6DXqmWfcCCCAAAIIIIAAAhJ57B4ZvuUPkgkNNayGd5+DxDV3R3HNWSBu9dA/JjXqoqca1NMMhiLJ7LNVsxfpAL05KhCiWQXssSCAQH0KxNY8JcM3XympzRvqc4BljMqz137inrtQXaMWZjMHuWbOK+Oo+i2ip9waUtenYXWdsmr2ooCaoktPexvwqyy6LAggUJcCyU2vSejmKyTx7+fqcnzlDMqzx4rt16Y56hqlP0PN3kFF6DXu3+X6hqehsLo+qeuUnrbdikuz25kNhmlv5UYnK54f+oRArQT0DTDrtoSy3/9Uow/6b+U5ajpbv89djeZoA4GyBfQMI69vDpVdfroF9Y1d82fV1w3g0zXheAQQaBwBAvQa51wzUgQQQAABBBBAAIE3BNLBfhn866WSeOaxhjLx7n2guBfukn14dthFTZ/UuD8klXPi9RROQyoQQj90JiOrLTNVEMQcddc1CwII1JFAOp29PkUf/EcdDar0UDzL9hX3jruKvjZ5FizOTklb+qjGLRGPq/dJOJ79MdGKwRB6qi59fXKpzHosCCBQPwKhf1wn4b9dWz8DKmMknqVvEZf6/OTRD3WNcrTWV7bWMggqKqIz8Qyp65P+/GTF7OStAU/2+uRtrs10wRVhUhgBBEwV0H9Pr9syVLUbX8gaZurppHKDBDb3haVvW3WySbb43bJwTpv6appMkgadPqpBAAGbCBCgZ5MTRTcRQAABBBBAAAEEjBEI//MOCf/1Sskkqpe+35ieV1aLa858cS/eXTyL1GPnPdTUSjMqq4DSOQI6M8TgcEI94pJQPzxZZfG4Hdk7sMkGYZUzQj8QmLpA7PlHJXTjFZLu75l6JTY4Uk8D6Fm0m7h33l2a1cPVPdcGvbZuF3UAub426awHUfVDo1UWPWWXDtLrUlN4sSCAgL0FEutflqEbL5PUay/beyAleu9obRP3oqXZz04edX1yz9upxBHsLiaQUlPh6uuTfoTVdO1WWvS0t3p6SRYEEGhMAT1zwnqVOS+tMuiZvejA4HlqSk+PhxtkzbamfmMEwupm5Vc2DBpTWYlavOr/Cx2kxwwhJaDYjQACdSVAgF5dnU4GgwACCCCAAAIIIFBIID0UlMG//E5lzXu0UBFbb9c/KHl2fYt4luwlzepBQJ55p1NP3xQMJWTbUMy8RiqsuUNN1zRHfenrJltRhXIUR8AaAoM3/E6iD95hjc4Y3AtHs1dcu+6ZvTbp6xMBeQYDj6tOB5Pr61NfsDpZD8Y1XfBli5rCa063X3xepvIqiMQOBCwsELrzegnf9icL93AaXWtyqM9P6mYm/flp173EPX/RNCrj0GICCRVMHlSBesFQ3DKZyZtVUIDOaKWDZ1gQQKBxBPT3OBu2DldlwPNmBrhZpSrSNGKGwNr1wapMXa8z6C2c0yotfq7HZpxH6kQAAesJEKBnvXNCjxBAAAEEEEAAAQQMFog++YCE/nKZZMLV+RLO4O4XrM41f6F4dt9bvLvvI54dlxYsxw5zBEZGRlSQnv6hKWaJrBCOJpWtSAVBkK3InPNNrQiYIZBY+5wM3fB7SW3ZaEb1NavT2T1LmnfbWzx77CPeJctr1o9GblhnLNLXKJ0hxAoL2YqscBboAwLlC6R6N8nQ9ermppeeK/8gG5TM3tS0+wppVp+ffLvvK+IieLjap03f7LRNBZMHLXKzU2e7NxuopzO/siCAQH0L9KqpO7eoKTzNXvTUnfNmtogOBGZBwM4CYXXNfmXjUFWGsEAF6embj1kQQACBehcgQK/ezzDjQwABBBBAAAEEGlwgeN2vJfbwXXWj4NppF/Eu20899icLkYXOqs5aNKACIQYGa59VjylULPTGoCsIFBEI3XGthG+/rkgJe+3SU6t7lr1VfOr65N5hsb06X8e9TSTT2UC9noFIzUfpa3bJXJVJJKCy6rEggIB1BcL/ujN7c5Mkk9btZAU9c3R0SrO6PnmXHSDNu+xZwZEUNVMgndY3O8VkcxWCZUqNQ2ch19n02gkMKEXFfgRsK6D/relTAXpmL3r6bH1jCgsC9SKg7k2WTb3DVfm+k6yT9fKuabxxpIe2lRx0pbMdFavTyLp0xyutr+RgKVBUgAC9ojzsRAABBBBAAAEEELCrQOL1NTL0599IavMGuw5hrN+ueQukefmB4lt+kArKmzO2nRfWE8hkRlSgnvqhqdf8u7KLjV4l08v+yEQ2vWJK7EOgNgLpYJ8MXvsrSax5tjYdMLBVR2e3eJe/TV2fDiQoz0BXs6qq5pRexcZANr1iOuxDoIYCGTUNqbo+xR69r4adMKZpRyAgnr0OEL/6/OTZZZkxlVKLaQJDKuurvtmp1llfZ7R5VdargJBNz7RTTcUI1ERgQ8+wbDP5ZkqdLW/+rBZuRKnJGabRagjoaerXbwmZ3hRBrqYT04AJAlv+6/SStc7536tLlhktoH/XGrjwW6Ork54rqSv+0rOy7VffnVTH+A3+lSdI26r3j9/EaxMFCNAzEZeqEUAAAQQQQAABBGojEL7/FgndeEVtGjewVd8hx4hvn0PFs3BXA2ulqmoJDKovrwYGozIcTVWryUnttLU0y3z1I5NLZYVgQQCB2gtEn3lYQn/+rWQitQ3ina6E962HiHfvQ8W7lOlrp2tZi+P19IL9g3HRARG1WvxeVzYIwuclm16tzgHtIjBeIPGaurnp2l9LauvG8Ztt99qzTE1du88h4tvrINv1nQ6LxOIp6QvGspn1auXhcTuyU1PqrOQsCCBgfwEdUKQDi8xcOlRw7w6zAtKk75RkQaCOBZLJjGzoCclwxNwsyzNn+GSOymzLgoBdBIZuvEwi9/+taHe7/vN74p6/qGiZ0Z2lZtzo+vIPxD13x9HiRZ+Hbr9GInfcULRM52fOEc9iMo0XRTJwJwF6BmJSFQIIIIAAAggggECNBTIZCV7zC4k9/kCNOzL15j1L9hTffkeIb+9Dpl4JR1pKIKwCIXrVD021ygjhdDapIL0Wpmyy1LuCzjSiwNCtV0nkrptsPfTWkz4qAXWNEk+zrcdB57cLWCEQQk8p2K1+gGFBAIHaCYQfuE1Naft/teuAAS0HVp0qfnV9crZ1GlAbVdRaQAcA9KkbnaoxHWWhseprk75GsSCAgH0FXts0ZPr3MEzJad/3Bz2fusAWNWV0r8lTRusZQfT/XywI2EEg9sITEvzdD4t2teXdH5SWQ99ZtMzozv6L/58kX/336Oqk55Z3fUBaDn/XpO35NvRf8m1Jrn0h366xbZVk5Bs7iBdTFiBAb8p0HIgAAggggAACCCBgJYHkxldk8Opf2HZKW98hx4r/bSvFPWehlVjpi4ECkVhS/cgUk8EaZSziyy0DTyZVIVCBQCY0qILHL5bEi89UcJR1inr3PUT8B6wUz867W6dT9MRQgUQirQLJoyrra8zQesutTGd71VlHnE6yvZZrRjkEjBIIXnuJxP51r1HVVbUezx4rstcn7577VbVdGqueQDo9ojLqbQ/Uy4yMVK/hN1rS2V71lJXeZlfV26ZBBBCYusCI+vdCB+eZmeWr2e2UHWa3iN9HNuipnymOtLOAnjVETx+dyZh3fe5s92avw3Z2ou8NIpBJy5avfqDoYD3L9pXOj36laBm9cyQela3fPKNoOc/SZdJ55tlFy4zuLDX9rs5A3vnRr44W57kKAgToVQGZJhBAAAEEEEAAAQTMFYg8fq8M/fEScxsxqfbs3VMHHivi4ks9k4gtV21UBer11ihQjx+ZLPd2oEN1LhB/abUMqsyumeCA7UbqP/okCajrk7Otw3Z9p8NTE0gkVaCeyoRQi0A9t5qKXQdBMKXg1M4dRyFQqUCqd5MEr75YUq+vrfTQmpf3HXy0+A86RtyzF9S8L3SgOgL6x399ferdFpEaxOllr086SIAFAQSsL1CN4Dx9c8kCFZzncDRZH4QeImCiQFzd6LVha0gisZRprczQU0ir/99YELC6wMCvvyOJfz9XtJvlZKqLPvtPGfy/nxatR++cc8EfRc2tXrRcYu1zMnDJd4qWyc6UcfBxRcuw01gBAvSM9aQ2BBBAAAEEEEAAgSoL2HHKQPeiJeI/+FjxrTi4ylo0ZyWBcFQH6kVNn3Il35j1l1v6Sy4WBBAwTyD84N8k3cw2gQAAQABJREFUdMNl5jVgQs2u2fPEp65PgYNU4DhLwwroH1p6BqISDFU/o97sLr/M6vQ3rD0DR6AaArHnHpXgpT+qRlOGthE47j0SOHiVOHxMd2YorI0qS6cz0qM+P9Vi6luy+NjojUJXG1YgG5y3cVCGo+YFC81Uf6fOUX+vsiCAwJsC67cOS3DIvM+OBOm9ac0r6woM33OjDN+sguaKLF1f/oG45+5YpIRI8LpfS+zhu4qW0Ts7PvF18e62omi50B3XSvj264qW6f76T8TVPbdoGXYaK0CAnrGe1IYAAggggAACCCBQLYF0Wgau+qkknnm0Wi1Oux2dftx/6DtLfniadkNUYCuBUDieDYQw847TfCBMeZtPhW0IGCMwdONlErn/b8ZUVoVaXAsWSeDQ48W3z6FVaI0m7CKgp2bXgXqhcKKqXSYrSVW5aazBBIbvvUmGb7rKNqN2dM2UwCGrstco23SajpouoDO+6uvTNhODAfINQmcj32F2qzR7nPl2sw0BBGoooLNrvrZJBedFkqb1ghsdTaOl4joQ6BmIyNb+iGkjIUjPNFoqNkgguelV6f/xN4rW1nriR7KfbYoVKjUl7eix/sNWSdsJHxldzfs88CuV1e+l6Wf1y1s5G6csQIDelOk4EAEEEEAAAQQQQKBWAtkpma76uaQ2vFarLlTUrmf3vaTl8BPEs8uyio6jcGMJ6CkF9RdayVSmagNv8bmzPzK53Y6qtUlDCNS1QDIhA1eq4PHnnrDFMF0Ld5bA298pvr0OskV/6WRtBIaGdSB5RKLxdNU6oIMf9I+gfq+7am3SEAL1LjB4w28l+uA/bDFMZ/cs8R/2DjK62uJs1a6TEZWRfKu6PpkZkJNvdAvntkq7muKSBQEErCPwqs6cZ1JwntvlkAVzWiWgvj9hQQCBwgLBUFzWbwkVLjDNPWSznSYgh5suUCq4rnmv/WTGh79csB/6N6++H5xVcP/EHaWmzC3VH+9BK6Xj5DMnVsu6yQIE6JkMTPUIIIAAAggggAACxgrE/v2MDP3hQskMm/eB36gee3bdU/xHvFu8S/YyqkrqqXMBfde3/pGpVz2quSya3yYtfk81m6QtBOpOIBs8roLzUhvXWX5srnkLJXDku5lq3fJnylod7AtGs1kRMhl1sarSQqaSKkHTTH0LJOMycMVPJPH8U5Yfp6OjUwWOv6tkZgnLD4QOVlVABwRs7Q9LIlm9G52Ykr2qp5jGECgq8NqmIdMyPuvMmQvntAk3NRY9BexEYExAB8+vU0F6Zt18zGwgY9S8sKBA8OqLJPbYA0V7ViyoLvzAbRL6y/8VPX78zpnnXCzO9q7xm8ZeJ159UQYuPndsPd+L9o/+p/iWHZBvF9tMFCBAz0RcqkYAAQQQQAABBBAwViDy2L0ydPUlxlZqQm2uhYukZeVJ4t1zfxNqp8pGEIgn0rKlLyxDVZxWcN7MgOgvulgQQKBygcTLqyV45c8sHzzu6OyWwMoTJXDAUZUPkiMQUALpdEa2qKmLdNbXai0zO/0yp8tfreZoB4G6Ekj3b5Ftl//Y8sHjjmav+FaeIK1HnlxX/gymugJ6aj2d8bVaS0ebVxaobK8sCCBQOwGdrUsH6ZqxtKlMmQtV5rymJjNqp04E6lcgqQLm120ZkkgsZcogZ87wyZzugCl1UykC0xGIPnG/DP7h4qJVdH3lAnHPXpC3zMClP6xoRo7W0z4pgf2PzFtX6M7rJHzbtXn3jW6cc/5lIh7v6CrPVRIgQK9K0DSDAAIIIIAAAgggMD2B0N03SviWP06vEpOPdsxQGR+OOkUFPqw0uSWqbxQBs6eHmOjYrb7kmsuXXBNZWEegqED0yQdk8KqLipap+U6PJxuY17qSwIean4s66cBwJJHNpmfWjy4TmTpam7NTsvMD6UQZ1hEoLKCzJgSv+KlkhoKFC1lgj//Q46TlmFPF4eOHVgucDtt3Ia6mY9+ssumFqnSjU8DnUkF6ZNey/RuHAdhSYGPPsGk3jTCVpi3fEnTaQgI667rOpGfW9VjfwKVv5GJBwEoCmeFB6Tn3U0W71HryGRI46Ni8ZUpNSTvxIO+Kt0nHB780cXN2feA350lizeq8+/RG985Lpeuz3y64nx3mCRCgZ54tNSOAAAIIIIAAAggYJDB08xUSuecWg2ozo5om8R/9bmk79nQzKqfOBhcYUfPebu6LSL+aWrAaS7u6S3wBd4lXg5o26kAg/MCtavqJyy09Eu+BR6rr03vF0dJu6X7SOXsK6ExFOmNRNRamGKuGMm3Ui0DsuUckePnPdNpLyw7Js2xfaT3uveKes9CyfaRj9hXYNhSTDVuHqzIAt8uRzbLl97mr0h6NIICAZGcc6N1mzncks1TQj57GmgUBBKYvsF5di4PqmmzGMn9Wi+hgWhYErCRQKsjOu+IAFVT3n5O6HH/5Odn2y+9M2l5qQ6Epc0v1I3Dce6T1qPeUqp79JggQoGcCKlUigAACCCCAAAIIGCcQvPYSif3rXuMqNLim5uUHSNvx7xNn1xyDa6Y6BHIFdLaiVzcO5W40aU0HQew4t01c6scmFgQQyC8QuuNaCd9+Xf6dFtjqXry7tK46XTw7LbVAb+hCPQvE4ikVSB6W4UjS9GFmgyDmtorfSxCE6dg0YFuByKN3y9A1v7Js/12z50tg1WniW3aAZftIx+pDQE/Lvqk3bNr0lxOV9FSY7SrjKwsCCJgroAPztqi/Pc1Y9IwCemYBFgQQME5AX4vNuul4ofpsqG80ZkHAKgJDt14lkbtuKtqdfEF1Q7f9QSJ3/rXocfl2dn7hO+JZuGvOrsRra2Tgom/lbJu40vmF/1HHLZm4mfUqCBCgVwVkmkAAAQQQQAABBBCYmsDA5T+SxDOPTu1gk49yzporLSowz7dsf5NbonoEcgV0EESfSXeKj2/J496eCcJHEMR4Fl4jkBUY+uvlErnvVstqtJ7ycQkceLRl+0fH6lNAX5v0NcrsRU9zq4Mg2vghxmxq6rehQPj+WyR04xWW7Xng2FOk9ehTLds/OlafAsFQXNarafaqscybGZCuDoJ7qmFNG40pYGZ2TLJxNeZ7ilFXR0BnXdfZ181Ydt6hXQJksTWDljqnIJB4ebUM/PK8okd2f+1H4po5P6dMqYx3OYXHrQRWnSqtK08Zt0UkdPdfJHzL1TnbJq7kCxKcWIZ1cwQI0DPHlVoRQAABBBBAAAEEpiOgpvQc+P33JPHCM9OpxbRj/StPkLZV7zetfipGoJRAtbLpORxNKpNeq7T4PaW6xH4EGkYgeN2vJfbwXZYcr3f/w6TtnR8Wh7/Fkv2jU/UvkM2m1zssw9GU6YPlR1TTiWnAZgKhu26Q8K3XWLLXnj2WS+s7PiTu2TtYsn90qv4FqplNj+kx6//9xAhrI2Dm9yALZrdIRxtTZdbmzNJqowjoAD0dqGf04nI6ZLEK0vN4nEZXTX0ITEmgVLBd63vUTbVve/Om2szwkPSc+8kpteVevJt0febcnGMHfnd+0d/VCk2zm1MJK6YJEKBnGi0VI4AAAggggAACCExJIJmQgd99XxIvPz+lw808yL1oibSe8CHxLMhNG25mm9SNQCGBERXIqqeJGBiMFSpi2HamazKMkopsLhC85mKJPXq/JUfR8bEvi3eP/SzZNzrVeAJmZkgYrzlHTUM2k2nIxpPwukEFhm6/RiJ33GDJ0U/8AcqSnaRTDSOgPztt7Bk2fbw6i57OpseCAALGCMQTaVm7PijpzIgxFY6rhe87xmHwEgGTBcyaotrX7JSdd+gQfaMxCwK1Fhi49AeSeO7Jgt3w7nOQdLz/C2P7o08+IINXXTS2PvGFZ8+9i9Y35/z/E/G8OdVzyQDB0z4pgf2PnNgM61USIECvStA0gwACCCCAAAIIIFBaYCQelYHfni/JV18qXbjKJQKrTlPpwk+ucqs0h0BpATOneBnfOpmKxmvwuhEFgn/4ucSeeMhyQ/cdfIy0n3iGiJ73kwUBCwmYmeVk/DDJVDReg9eNKDB02x8kcudfLTf05r32k7YTPybOthmW6xsdamyBeDwtG3tDEjY526vOxqWzcrEggMD0BDIqKO+VDUGJqv93jV70jAFtLW8GNRhdP/UhgMBkgb5tUdncF568Y5pb9P/L+v9pFgRqLRB+4FYJ/eXyot0YP8VsqZuBO844S4KX/rhgfXq/d8/9s/sT616SgZ+fU7Cs3jHz7IvF2dFVtAw7zRMgQM88W2pGAAEEEEAAAQQQqEBAB+f1/+a7knrt5QqOqk7Rri99V9w7LK5OY7SCwBQEEupu8o09IdOnFNRZIHQ2CBYEGk0geOVPJfbUPy037I6Pf0W8u+9ruX7RIQRGBfQPqjpTUTAUH91kynO3yqI3V2XTY0Gg0QSGbr1KInfdZLlht77nE2rapqMs1y86hMB4AR0coIMEzFwIFjBTl7obReC1TUMSCicMHy7BeYaTUiECZQuYFaTXrb6znEsG27LPAwXNEUj2bJT+H365aOXdX/+puLrnZMsUy3jn2X25dH74LNnyjY8UrM938FHSftInsvuH77lRhm/+Y8Gyesf44MCiBdlpigABeqawUikCCCCAAAIIIIBARQKJuArOO89ymfP8K0+QtlXvr2goFEaglgKb1ZS3fUFzf2RiOsFanmHaroVA8KqfSezJh2vRdME2vfsdJh0nqy/f3J6CZdiBgJUEzPoBZvwYu9rVdIKzCNIbb8Lr+hYYulVlzrvLWpnzPEvfIu3q+uTsml3f+IyubgQGVQD5BhVIrgPKzVpaAx7ZaV6bWdVTLwJ1LWDWdxxMa1vXb5uGHFyqf4uktq6XkVRKnDNmiWeB9W80N2u6W24ubsj/BSw36GJBd7qzraeeKYEDVkpy8+vS/6OvFex/y7s/KC2HvlP6LzlXkmtfLFhuNOhu4Pffl8TzTxUs5z9slbSdUDjYr+CB7DBMgAA9wyipCAEEEEAAAQQQQGBKAum09P/qO5J8pfAHjCnVO82DOj7xdfHutmKatXA4AtUXCA7Fsj8yjZj3G5PM7vKLnlKQBYF6FwhefZHEHnvAUsNsPe2TEtj/SEv1ic4gUI5AOJKQDVuHJZHKlFN8SmU6272ip2RnQaDeBYZuv0Yid9xgqWEGjjtVWo86xVJ9ojMIlCMQV9nIN2wNSSSWKqf4lMq0+N0qSK9dmpqmdDgHIdCQAgODsWwmZqMHr6ee1lNQsyBgd4HYi09K6IZLJT3QJzIy+TOWo6VV3It3l5Yj3m3ZmWF6BiKytT9i+Kl4y67dhtdJhQhUIhC87lcSe/jugod49z1EOt73HzJ8719l+KY/FCzX9ZULxD17gYTuvF7Ct/2pYLmZ3/ipuklqjpQKDOz4+NfUTBx7F6yHHeYLEKBnvjEtIIAAAggggAACCBQRGFCZ8xJrVhcpUd1d3hUHSPt7Pi1NXqbxrK48rRkpEIunsj8yReNpI6vNqYsgvRwOVupQIPjnX0rsn/dYZmTunZdK+6mfFNfM+ZbpEx1BoFKBdDoj61WQnhnTlI32hSC9UQme61Wg1I8z1R63s3uWtJ3ySWnedVm1m6Y9BAwV0Jn0tqmAILMWgvTMkqXeehQIR5PyyoZBw4emb+TQfyuyIGBngeH7bpbI7X+WTLyya5bv4KOlec/9xLtkL0sNf4uacl5n0zN62X1Rp7hcDqOrpT4EyhKIPvOwDF7+s6Jldda7Ur+NjWbGS6x/WQZ+dnbB+lpPPkM8C3eR/p9+s2AZvWPOD1UwoIP/L4oimbyTAD2TgakeAQTKE7jy1fXlFaQUAiYIfHDRAhNqpUoEEChHYOCyH0pi9RPlFK1KmZZ3vV9aDj+hKm3RCAJmC4yoFHrrtwzL4HDctKbmqEx6M8mkZ5ovFddOYOjGyyRy/99q14EJLTMFxQQQVm0vYNZ0ZaMwBOmNSvBcbwLD998iwzdeYZlhNS8/QDpO+4w0NRPsYJmTQkemJWD2lOw6SG/R/PZp9ZGDEahXgcSrL0rs+cckuW6txHq3inNoIDvU+NydJTVzoSQWLpPU/N2mPPy53QHpnsHNuFMG5EBLCAz86n8k8dLz0+6Ld79DVbDeW8W35/5ihfSum3rC0j9obJAe19xpv02oYBoCI7GobD37jKI16Kx3vd/7UsEy3gMOl45TPzO2v1h2PM+yfcWz824y/NerxspPfOFZukw6zywc5DexPOvmCBCgZ44rtSKAQIUCJ95yZ4VHUBwB4wTes8cSIUjPOE9qQqBcgeAfL5TY4w+WW9zUco4ZXdJ+2qdV1oe3mNoOlSNQCwGz7kQdHQtfco9K8FwvAkO3X62mDfyLNYbjcknbqWeKf9/DrdEfeoGAgQL9wahs6g0bWGNuVV0dPpk3M5C7kTUEbCwQfuQuCf3p15YZQeD490rrkSdZpj90BAGjBIbUDU4622smM2JUlTn1tAY8arrbtpxtrCDQyALRpx+U8D03SWr9ayUZkp1zJLL8KEkseVvJsuMLzFI3FupZAFgQsLNA30++JqmNrxs+BD2bTPOKg8W3TAXr1XBZvyUkwZCxNxnroFz9vSULArUQKBZQp/vjO2yVRO+7rWDX2j/0BfEtP2hsf/Cqn0nsyYfH1ie+8Czbp2gyDJJTTBSrzToBerVxp1UEEJggQIDeBBBWqypAgF5VuWkMgazA4A2/l+iDf7eEhme3vaTj9P8QRwtfkFvihNAJUwQG1FRNG9WUTWYtOgBCB0KwIGB3geH7bip6t2k1x+eat0DaT/+suOctqmaztIVAVQX0VLf6h5i0SUEQ/CBT1dNJYyYKRFf/SwYv+4mJLZRftaOlVdre+2nx7r5v+QdREgGbCcTiqez1KZZIm9Lz9pZmWTi31ZS6qRQB2wikUxK8+uKiwQaFxhJd9BYJH/ERGXGXzuBKZuVCimy3k8DA778nieefNr3LOnu/762Hq+8hdjK9rXwNvLpxUIYjyXy7ytrWlIyLc/O/xbltizhi6nvQpiZpnzVLWndaJN5d9lTrTO1ZFiSFDBEI/f1aCf/9uoJ1uWbPl9TWjQX3z/rO78ThezPANPLo3TJ0za8Kli+1o+us79fs/+1SfWuk/QToNdLZZqwIWFiAAD0Ln5wG6BoBeg1wkhmipQRKfTCpZmf9hx0nbSd8tJpN0hYCNRPQQRDrVBCEWZkgdpjdIjPaSn85XjMAGkaghEDksXtl6OpLSpSqzu7m5fvLjPd/QcTpqk6DtIJADQXMDoIgY0oNTy5NGyKQeOUFGfjVeSJpcwKFKumka6dd1PXp8+LsnF3JYZRFwJYC6fSI+vw0NK1AgWID15+d9GcoFgQaUSATCcnAb78nqXWvTHn4yc65MrjqszLSMqNgHW0qGHZHgmEL+rDDHgLRpx6UwSsvrGpn3TsvFd9+R4h/v7dXtV39neUrG4ISjVf2d69rwwvie+5e8b62unB/XW7xqu9a/AcdK54dlxQuxx4EDBJIvLZGBi761pRrm/O/V+ccm1ZTv/f+z2dztlWyMrG+So6lrHECBOgZZ0lNCCAwDQEC9KaBx6HTFiBAb9qEVIBA2QLhh26X0PWXll3ezIKtJ31UAgcfZ2YT1I2A5QR0EMS6zSGJJyv7oqvcgegvvvUX4CwI2E0g9uJTEvzt9y3Rbf+R75K24z9gib7QCQSqJZANgtisgiCiU8+WUKyvTMdeTId9VhZI9W2WgYvPlUxosObd9O57sHS87/M17wcdQKDaAnq62+BQzJRmmY7dFFYqtYFA/y++JclX1ky7p4nu+TJ40ldFHM5Jdfm9Ltl5h3aVQKtp0j42IGAngZ5vf6qmfwv6j3inBA48Rt2gMasqbAmVvXatCtJLqUD5UkuTypIXeOBq8a19qlTRnP3et71dOk4+M++/HTkFWUFgmgKlprktVL3/6JOk7dj3Tto91fq8+x0qHe/93KT62FB9AQL0qm9OiwggkEeAAL08KGyqmgABelWjpqEGF4g996gEL/1RzRUc/oC0ve8/1JRMe9e8L3QAgVoIpFIZeV0FQURiKVOa11+AB3xuU+qmUgTMEEhufl22/eLbkolGzKi+ojpb3/MJCbztqIqOoTAC9SSgg8gHh+OmDIlMr6awUqmJAiPxmPRffI6kNq03sZXyqvYffaL6gej08gpTCoE6FNjcF5a+bVFTRkamV1NYqdTCAoM3/F6iD/7dsB5GdjtAwod/KKc+t8shi3foELeb6SxzYFixnUD08Xtl8I+XWKLfOtO//8BjpVlPFWvyMhxJyKsbh4q24ux5Vdr+8XtxhbYVLVdop2veApnxkS+Ls2tOoSJsR2DaAtuu+LHEn36k4no6P3eueBbtNum4oZsul8i9t07aXmpD+/s/J759Di1VjP1VECBArwrINIEAAqUFCNArbUQJ8wQI0DPPlpoRGBVIbnhF+n9xrkgiMbqpJs+u2fOl/UNfEvecBTVpn0YRsIrAyMiICtILiZ721ujF5WxSd6l3SLNn8h3sRrdFfQhMVyATHZb+C/+fpHs2TbeqaR3v8Pml7QOfF+9uBI9PC5KD60JgY8+wDAyak6lop3lt0hrw1IUTg6h/gYHffU8SLzxd84ESPF7zU0AHLCLQMxCRrf3m3NAxb2ZAdDY9FgTqXSC6+l8yeNlPDB/mtnd+XlLzl47Vu/P8Ngn4+ZtvDIQXthXo/cEXJd271VL9dy9aIv5DjhPf8oNM7dc2lb12g8pim29x9q2TjpsvFEd8esHzzpmzpfMz3xZnW0e+ZtiGwLQFwv/8h4T+/NuK6yk0HW1szdMS/M33Kq5v1rm/EkdLe8XHcYDxAgToGW9KjdMUyETDklj3ck4t7plzy06dm1i/VjKR3Au2d+nynPrKXcnXl9Fjy61T/0M5cSk1nnzHeBbuIg5fYGJVdbNOgF7dnEpbDoQAPVueNjptI4FMJCT9F52tgh9q+2WCZ5c9pOPDZ4nD32IjPbqKgLkCZmUq8qrgPB2k51TBeiwIWFlg4DfnSWLN6pp2UX8h3PHh/xT33J1q2g8aR8BKAmZlKnKoKc523qFNfF4yvVrpfNOXyQLB634tsYfvmryjiluaPM3q5qYvqMzj+1axVZpCwNoC/cGobOoNm9LJhXNbpb2l2ZS6qRQBKwjozLC9F5wlmeCA4d2J7biHhI77bLZesiYbzkuFNRKYaiBOtbqrM9D5Dz1e/PsdYVqTW1RgfK8KkM9dRqTjT+eJe5sxvzV4luwpnZ88J7cJ1hAwSCC9rVd6v/v5imrz7PVW6fzwfxU8ZirT3BYK+CvYCDtMEyBAzzRaKp6qQL4/OBwdnTLr7F+UrDI90CP9P/qqZNQf+uOXqf6jE37odgldf+n4qsZez/zvn5cVNBi683oJ3/anseP0C/fi3aTrM+fmbBtdyddmueMfrcOOzwTo2fGs1U+fCdCrn3PJSKwpYIXgB52Cf8aHzrImEL1CoMYC+m5UfVeq0UuL3y2L5nNnntGu1GecgBWCH1w77SIz1Jdu3K1t3HmlpvoR0FmKdLYioxePmupMT3nmUlOfsSBgRYHhe26U4Zv/WNOu6e8idfC4Z+GuNe0HjSNgRYFtKsvrBpXt1Yxl8Q7t4vcRRG6GLXXWXiD4p19I7JH7TOtI34fOl+75s2VOd/0mujANj4otKTDwy29L4uUXLNm38Z1yzpon/re/QwL7rxy/2bDXegaQoeH4WH2+h66VlmfvHVs34kXg+PdK65EnGVEVdSAwSaDSgLrWUz4mgQOPmVTP6IaB354viRefGV0t+ew/8gRpO/79JctRoDoCBOhVx5lWKhDIF6CnDw+sOk1aV55ctKaByy6QxOrHJ5WZaoBeofrK7Y8up7Pw9Z33uUlBg4UC/HrO++ykO4g6zvyGlJuxb9LgbbKBAD2bnKg67SYBenV6YhmWJQSC1/9GYg/dWdO+eA88QjpO+VRN+0DjCFhdwKzpBGe0eUXfvc6CgNUEhu+9SYZvuqqm3fLstpd0nvFVEaerpv2gcQSsLGDWdIItPpcsUkF6LAhYTcCsqf8qGadrzg4y4wwVPN41p5LDKItAQwkE1Q1O6wtMuzcdCLcKHl+8oEP0MwsC9SQQfeYhGbz856YOKb7qDNlx5bGmtkHlCFRLIPrsP2Xw/35areYMaUf/Dek/4gTx73uYIfWNVpLJjMja9UGJJdLiCAel68qzR3cZ+tx11vfFPW8nQ+ukMgS0wOBfLpXoA7eXjVEohmS0guH71Heafy3/O80Znz5HmnfZc/RwnmssQIBejU8AzU8WKBSgp0sW+wcp+tSDMnjlhZMrVFumEqCnA+t6zvl43vr0Rp26t/usCwruH78jXxY97/6HScdp21Nuj5bNlz2vWLa90ePq4ZkAvXo4i/YdAwF69j139NzaAuH7b5HQjVfUtJP+w4+Xtnd9uKZ9oHEE7CJgVpDerE6/zO7y24WBfjaAQOyFxyX4u/I+y5nFQWZXs2Sptx4FerdFZUuf8dMJdqgg8gUEkdfjW8a2Y0r2bJD+HxaeyqgaA3PtuDgbPO5oIQtyNbxpw94CwVBc1m8JGT6IgAoi35kgcsNdqbCGAsmE9PzgS5MSUxjdI+9hq6TjhI8YXS31IVATgb6ffUNS61+tSdvTbdS1cGdpWXmiePfcf7pVjR0fjSXl5fWD4nviVml59Nax7Ua+8Oyyu3R++ltGVkldCGQFKv0eslRcS3LLOun/X3XDb5lLqfrKrIZiBgkQoGcQJNUYJ1AsQK9QsFo2S92PvlLwD/yp/MOTL1hu4iiLBQxOLJsvM97E4/OVaYTsedqKAL2J7xjWqylAgF41tWmrUQRi/35Ggr8+v6bD9R99orQde3pN+0DjCNhNwKwgPR0AoQMhWBCotUB6oEd6z/9CTbvhfeuh0nH652raBxpHwG4CZgXp6QByHUjOgoAVBGr9Q2z2R8mPfV3E02wFDvqAgC0EzArSIxO5LU4/nSxToFqza3j3PlA6PvDFMntFMQSsKxB59G4ZuuZX1u1gmT3zLF0mLUe9RzyLdivziOLFtqnstaFfniOenvXFC05jb8sJH5CWw941jRo4FIE8AumUbPnaB/8/e+cB3kaVvf03kizLkiXLconTeyO00BaW3ntn6T2BQAg9EEpCElIh9ITQIX9677DUpS2wdAgJ6b05LrJsFcuSrHyj8BlsR2WkKZqR3tnnWWvuPfeU3xWxpTn3nDgT2w8V7XsESk6+ePuJTiNi2+aah+/2Z/eOTut5mz0CTNDLHntaTkAgWYJebEnJuVeiaNd9O6yOV6GuvUAmCXrJ2tu26RbTdrdNNl7CX/sqeqnm2/Tk6k8m6OXqzuojLibo6WOf6KV+CES9jYg9XIp63Flz2nbUv2A/7NSs2adhEtAzgQ1Cq6bYl15yXwN7laDIUiC3WuojgbQI1M+bhPCqpWmtkVPYsvdBcJ52mZwqqYsE8oaAUu1ue1XZ4bQzISlv3kgaDdTz0jwEf/gya97FHqC6Rt4CGNhWM2ubQMO6JaBUu1smkev2LUHH2xFI9byvnajkl4U774nS86+XrIcKSCDbBGrvuBqttVuy7YZs9mOHFO1HnQ6js0KazmgU1TeeI+jYKk1PstUmEyrG3wNjaWUyKc6RQNoE3I9MRWj5opTrnBePg2WHPVLKeV4WPj9+n/rzo/2kC2Db7+iU+iigHgEm6KnHmpZEEkj1B7vB6UL59bNhKLJt0yimAkK6CXrx2tuad9wdEeEfzmjL3w8r02lzG3O27p4bENnUMbO/rYpevOp5bXMi0elajAl6ut4+3TvPBD3dbyED0BgB9xMzEFq8IGte2Y45A/ZDTs6afRomgVwgsL7aB4/377975Ypp+IAy4blvF7nUUQ8JpEWg8Y0n0Pz1x2mtkVPYss8hcJ56qZwqqYsE8o7AlvoAYol6cl+DejthKTTJrZb6SEAUAd9X78L31rOiZJUQMg/dCa5RtyqhmjpJIG8IuBuDiFUjl/vq080ORzGTyOXmSn3qEai750bhmdg6VQzyMJQqmGlEYQK+L96G753nFbaSHfW2I0+F/fB/ZWw8UrcZdbOuzXi92IVmIdnXxWRfsbgoJ5KA97M34X/vxZTSVbOeAUypD7g3//o1Gp+dk1JfuZBwaqronlKOAuoRYIKeeqxpSSSBVAl6MTXWA4+B4/jzt2msf2gywiuXJNWeboJevGp29lMuQnjDyu2ykdNJoosXW6yKXkHPAfC+/lSHGNrH2GEiR2+YoJejG6uTsJigp5ONopu6IND07xcQ+PStrPmaTnXbrDlJwySgEwJrN3vR5GuR1dvYw6XYQyZeJKA2gWy3iLHsfbBQOW+02mHTHgnkJIHNtX7UeZplja2o0IgBvUrRhTnksnKlstQEQqsWwz1vSmpBhSS2Vc67ZIJC2qmWBPKLQL3wu2mT8DtK7mtIn1KYzUa51VIfCShOwPvJa/B/8IridtoMFB93FooPOrHtlj9JQHcEtgoFYrbceqHu/E7HYWNlNxQffSaKdvpHOsu2yYY3rkL9vULFZxWukvOEbn67dOzmp4JZmiABEsgDAkzQy4NN1luI8ZLY4sXguno6wutXbJfYFk823QS9eEl/lVOfQMvSX7fLRk43ESCe7lhVwPZtAA2FFpRPePCvKoHxYsq1MSbo5dqO6iseJujpa7/orXYJBBd9D89T92TNQdsRwim8IzI/hZc1x2mYBDRMYPXGRvgCYVk9rHRZEWvXxIsE1CIQrl6P+vtuBiIRtUx2sGPZ8wA4zxjTYYw3JEAC0ggo0Y7dabegV1WxNMe4mgTSIRAJo1bottFaU53OKtlkzQOHwTV6ItCFbW1lg0pFeU9AiXbsVotJSCJ35j1bAtAXgdb6atTOjFW6UrAVZSckrrFTYO47pNMob0lAPwSa3n0Ggc/f04/DEjy1jNgb9uPOg7GkTLSW8JYNqJ89TrS8FEFjeSUqbnpAigquJQESIIG4BJigFxcLB7NJIF6CXucEtph/BQOGonXDmg4tZ9vGO1fUSydBL17L3Jitsssnx9SjetyZ2362/V/Mt8oJ89puU/4MrV8J9/3J20akm/SX0qgOBJigp4NNymEXmaCXw5vL0FQjEPU2Cq3cb0TsZzYu6yHHw3HMOdkwTZskkNMEotGtWLWhEc0t8iY2sVVTTr9tNBdc3dwJiKxZkRW/LLvuDee512TFNo2SQK4TUKLSa7dyG8pLi3IdHePTCAHPC3MQ/OnrrHhj6jsQ5bHkvAK2zszKBtBoThPYXCdUem2Qt9Krq8SCHpVMIs/pN06OBdfwzD1o+e17VaNK5zmgqo7RGAmIIBCpqxbat+bZdwdmM+zHnAXbfkeLICSk+7Y0CxUGLxIlK4eQ9bAT4TjqLDlUUQcJkAAJ/EWACXp/oeALrRCIl6AXS1hr+e1bRDatT+pmrF2ssawK/n+/3EEunT/MvZ++vt369glz7vmzEVr4Uwf9sWp+5l4DOowlu/G8PG+7Vrlt8rGEv/LrZ+dV9bxY7EzQa3sH8Gc2CDBBLxvUaTPXCLjn3yn8fvw5K2EV7Xs4Sk4emRXbNEoC+UAgFG7dlqQXjkRlC9dk7IJBvUthMrFii2xQqSgugaZ3nkbgi/fjzik9aN5hV7guvklpM9RPAnlLYKtQkGX1Rg/8zfImkffvWQJbUUHecmXg6hDwf/sRvK89qY6xTlZM3XoKlfNug6HY0WmGtyRAAnIRWF/thcfbIpe6bXp6di1GqcMiq04qIwElCAT/+AGeJ+9WQnVCnbZjzoD9kJMTznOCBLROwPP8Awj+/I3W3VTEP/OQnWA/8QIUVPZMqb9zEZ2UCyQKlI+/G6aKHhK1cDkJkAAJ/E2ACXp/s+ArjRBIlKBXOHiXpJXn2trC+r/5cLsEu3QS9OqE1hKdEwErbnkARlflNkIx/d7Xn+pAy3rgMXAcf36HsWQ38ar0tcnbT7kItn8e2XabNz+ZoJc3W63JQJmgp8ltoVM6IuD74h343nkuKx5bdt8XzrOuzIptGiWBfCIQaA5jldDuNpYMIddlt5nRtzsfDMvFk3q2J5DN1usF/QajbMwUoW1gl+0d4wgJkIBsBCJC8viqDR60hOVLIi80G4Ukcqfwny//+5Vto6ioA4HwFqH1+t1CAne0tcO4Gjexg8Fll08SDjh3VcMcbZBAXhNYLXx+8gXCsjGI/VqKHXKK/Z7iRQJaJhDvGZvS/qbzDFBpX6ifBNIl0LJiERoenpruspyTLz7xXBTvf1zSuJremo/AVx8klZFz0rzznnCdf72cKqmLBEggzwkwQS/P3wBaDD9Rgp790FOQrPpBW5W7eBXwxP5xHi9xztS9F8qvm/0XqmizHzUTO1bpSbfNbUxZPD8z0fOXYzp/wQQ9nW+gzt1ngp7ON5DuZ5VAeMNK1N+XvHW7Ug6ah+0C18iblVJPvSRAAp0INPpasG6zt9OotNuuZVZUuqzSlHA1CcQhEA0GUHfXOEQ97jizyg6ZuvaAa8wkGGxMQFWWNLWTwJ8EmoNCEvmGJkRlzCKPVSiKVSriRQJKEKh/aDLCK5cooTqpToO5EM7LJwpdQAYmleMkCZCAPARaW7duSyIPhuRLxrUVmdC/p1MeB6mFBBQg4PvqXfjeelYBzYlVOi8eB8sOeyQW4AwJaJxA/bxJCK9aqnEv1XEv9n1/rFNOW9GczlbDG1eh/t5bOg8reu8ceSMsw3ZT1AaVkwAJ5A8BJujlz17rJtJkCXqx5Li6aVcg2hLsEE/BgKHC6c/J28biJb6JTdCLtzam2zx45w72mr/9ZLsHPem2uU0WZwdjeXLDBL082WiNhskEPY1uDN3SBYG6uRMQWbNCdV9Nvfqh/IrbARPbj6kOnwbzmkBdQzM21/llZdC/hwM2q1lWnVRGAp4X5iD409eqgzAU21EqJOeJac2iunM0SAI5TKBJSCJfK3MSeY/KYrhK2Eowh982WQnN+/Er8H/4WlZs8+FiVrDTaJ4TCLZEsHJDI6JR+UqRV5QWoarcludkGb4WCWxtaUbt9LGIBuT9ziBZrNYDjobjhAuSiXCOBDRNIPDDZ2h66RFN+5gN5xxnjIZ1z4PjmvY8ex+Cv/4v7pwSg6be/VF+1QwlVFMnCZBAHhJggl4ebrrWQ06VuBavxWz75Lh4SXZiE/SklN5Ot81tqji1vk9y+8cEPbmJUl86BJiglw4typLA3wSaPngRgU/e/HtApVeGklKUjZ0CY+mf7edVMkszJEAC/5/Apho/6hubZeNhEVo0DRRaNbGToGxI815R4Mcv0PTiQ1nh4LpsAswDd8yKbRolgXwnIHcSeazF7WCh1a2ZrQTz/a0lW/yhNUvhnjtJNn3pKLL/6xLY/nFoOksoSwIkIBMBJZLI+3Z3wG7jISeZtohqZCKQrAOWTCa2UyP22d92CzlAAhohUDNdKErTUK8Rb7TlhmWvA+A8bTRg6NjavbXRjdqpY1R11n7aKNj2PkxVmzRGAiSQmwSYoJeb+6rrqMQkrrVvBdE5MS7TBL147W3TAZlue1oxcaZjX++yTNDT+w7q238m6Ol7/+h9dgiEVi+B+8HJWTDeBa4rJsHcb2gWbNMkCZBAG4HVGxvhC4TbbiX/LBMqFHUXKhXxIgGpBKK+RtTNvh5Rv0+qqrTXO868HNY9Dkx7HReQAAnIR2BjjQ/uxo5dF6RoL7YWoF+PEikquJYE/iJQ98AtiKxb9de9Wi9sR5wC+xGnq2WOdkiABOIQqBUqkVfLWIncXGDA4D6xQ05d4ljjEAmoT6C1vhq1M69R1bBz9K2wDNpJVZs0RgJyEmj64AXh8PtbcqrMOV2mrt3hOO3S7Z4F+L/9CN7XnlQtXoOrDJW3PKiaPRoiARLIXQJM0MvdvdVtZGIS10LrV8J9/60wFFpQPuFBGIr+LumeaYJevHXpQmxfyS/VWjFxptKRS/NM0Mul3dRfLEzQ09+e0ePsE8jWw6WSs8agaPcDsg+AHpBAnhOIRKJCqyYPQuGobCT6dLPDUVwomz4qyk8CnufuR/CXb1UP3nbkqbAf/i/V7dIgCZDA9gRWC60Efc3yJZHH2gjG2gnyIgEpBJo+fAmBj9+QoiKjtZY99ofzzCsyWstFJEAC8hLYsMWHhib5kshjbdhj7dh5kYAWCHhemofgD1+q5krnwh2qGaYhEpCJQKR2E+ruuE4mbbmvxn7iebDtf2yHQN1P3YHQol86jCl5YzvmDNgPOVlJE9RNAiSQBwSYoJcHm6y3EMUmrsUS6kxlXVG0674dQoyXaCemzHW89rYFAxJX59na7Edk0/oOttP5UCA2zg4GcviGCXo5vLk6CI0JejrYJLqoKQLej1+B/8PXVPeJlR9UR06DJJCUgD8QwqqNTUll0pk0mwwYJFSBMBhYBSIdbpT9m0DzL/9F43Nz/x5Q6ZVlj/2E5IexKlmjGRIggVQEwkLy+Ir1HkRa5UsiHyS0urUUmlKZ5jwJxCUQWr9COGg8Ie6ckoOmfoNRfsXtSpqgbhIggTQJrBR+PwWCkTRXJRbvLRxyKuEhp8SAOKMKgfCGVai/7xZVbMWMGCurUHHjfarZoyESUIKA++m7EVrwgxKq4+o0D9wBoRV/xJ3Ty+C2lren/93aVu3KnbFiQZUThSp6ZotekNFPEiABDRJggp4GNyXfXZKauJZJgl689rapWtZmsqb93kqNs72uXHjNBL1c2EX9xsAEPf3uHT1Xn0B40xrU33OT6oYtI/aB85yrVbdLgyRAAskJ1HmasbnWn1wojVlWgUgDFkU7Egi3oGbWNYg2NnQcV/jO1GcAyq+crrAVqicBEkiXgNcfwppN8iWRs9VtujtA+fYE6h+ajPDKJe2HFH9tsDtQdtV0GEsrFLdFAyRAAuIJtIRasWKdB9GtW8UvSiJZIBxyirW65SGnJJA4pTgBtRONnBddD8vwPRWPiwZIQCkCzQu/Q+P8e5VSv53ewl32Qul5QrW+1gj8P36O4I9fIrx62XZyehiIfQfjPGssTOXdtrnr++Jt+N55XjXXrYeeCMfRZ6lmj4ZIgARyjwAT9HJvT3UfkdTEtUwS9OKtEVMNL17VPbFtbqXGqfuN7hQAE/Q6AeGtqgSYoKcqbhrTOQH3o1MRWrZI1ShMPXqj/OpZEL5xVtUujZEACYgjIHerpr7d7bDb2OpWHH1KtRFofONxNH/9SdutKj8NRVa4rpoGU0V3VezRCAmQQHoEatwBbKkPpLcoiXQ3odVtOVvdJiHEqXgEfF+9B99bz8SbUnTMOWo8LENHKGqDykmABDIj4PG2YH21N7PFcVbxkFMcKBxSjUBozVK4505SzR6rl6uGmoYUJFA3+zpEtmxS0EJH1WXj7kRBVe8Og+ENK+H/7hMEv/2sw7gebgxWGxxnjYFl2O7b3K2bOwGRNSvUcb2gAJUT5sFgs6tjj1ZIgARyjgAT9HJuS/UfkNTEtXjJdqla3GaaaBfPlpjEvtguSY1T/zvdMQIm6HXkwTt1CTBBT13etKZfAv7/fQzvq0+oG4DRiLKrp6Oge1917dIaCZCAaAKx4g8r1jUgKFSDkOMqNBu3VYGQQxd15AeBlhWL0PDwVNWDLbngGhTttLfqdmmQBEhAPIFYFb1YNT25riF9S2EuMMqljnpynEBrkxu1QnVXhOR7D4pBVnzcWSg+6EQxopQhARLIEoFYFfJYNXK5rr7dHcIhJ7Nc6qiHBEQTcM+/E6GFP4uWlyLYxVyI8pvuh9HhlKKGa0kgqwS8H78C/4evqeZD0b6Ho+TkkQntRYMB+L/9CP73Xkwoo9UJ+0kXwLbf0Qit/APuh25XzU3rwcfBcey5qtmjIRIggdwiwAS93NpPRkMCuiXABD3dbl1OOM4EvZzYRgahMIHYh/W6mVcj6pfvlLcYlx1nXAbrngeJEaUMCZBAFgkEmsNYuaFRNg8qhApFVUKlIl4kIIZA3ZxbEVm7UoyobDLWw06C46gzZdNHRSRAAsoQiESiWLzaLZtyR3Eh+nRjtQTZgOa4Is8LcxD86WtVo7SM2AfOc65W1SaNkQAJZEZg5XoPAsFIZos7rbIIh5wGCa1ueZGAmgRCq5fA/eBk1UwWn3AOig84XjV7NEQCchOI1GxE3Z3Xy602ob5YUmvFrXOEam+OhDLtJwJC+9umFx9uP6T519aDjoXjuPPgef1RBL/5jzr+mkyonPgQq+ipQ5tWSCDnCDBBL+e2lAGRAAmQAAmQAAmQgPwEPK8/JnzI/VR+xUk0pjrhl2Qpp0iABLJAoLahGdV1ftksD+xVgiJLgWz6qCg3Cfi+eldoHfisqsGZh+0M18hbVLVJYyRAApkTaPK1YO1m+Q6Z9Kqyw2lnK/bMdyQ/VgYX/wzPE3eqGqyxsgoV1wo2C1hFS1XwNEYCGRIItkSwfJ0nw9XbL6t0WdG1zLr9BEdIQCEC7vmzhep5PymkvaNaU69+KL96ZsdB3pGAzgioWXEyhsZ2zBmwH3Jy2pSCi76H/8v3EV65JO212VgQO6DiEKoEbisu0Czf95LJYrEecjwcx5yTTIRzJEACJBCXABP04mLhIAmQAAmQAAmQAAmQQBuB0JqlcM+d1Haryk9T7wEov2q6KrZohARIQD4CcrYSLLYWoF+PEvmco6acIxCr6lo38ypEg/K1BxMDqeK2eUJbJZcYUcqQAAlohICcrQTNJgMG93WhSxeNBEc3NEmg7r7xiGxYq6pvrjG3wdx/B1Vt0hgJkIA0AvVCm9tNQrtbua7BQhW9QqGaHi8SUJpAaP0KuO+foLSZv/Q7R46HZdiIv+75ggT0RiDw05doemGeam4bK7qiYvz9kuzFDpz4P39HSNRbLEmPGovNg4bDPGgn+N5Xp1WvIVadcNIj6FJoUSM82iABEsghAkzQy6HNZCgkQAIkQAIkQAIkoAQB9yO3I7T8DyVUJ9RZdt1MFHTvl3CeEyRAAtokEA5HsWSNfK0Ee1QWw1XCL7u0udvZ9yob1V1Lzr8aRTvvk/3g6QEJkEDaBH5fXpf2mkQL2Io9ERmOxwhko7qr7dgzYT/4JG4ACZCADgmsE6q8NgrVXuW42IpdDorUIYaA5/kHEPz5GzGikmUKd9kLpeddJ1kPFZBA1giEQ6iZdTWijQ2quVBy9hgU7XaALPZiFfV8n76JyLpVsuhTSompey+gtRWRLZuUMtFBr+2o02A/7LQOY7whARIggVQEmKCXihDnSYAESIAESIAESCCPCah9ui+G2n7SBbDtd3QeU2foJKBvAg1NQWzY4pMlCJNQpWiIUAXCYGCZIlmA5pCS0LrlcD8wUdWIrPsdCcdJF6lqk8ZIgATkIxBoDmPlhkbZFA7q7YSl0CSbPirKDQJRoa1W3QyhuqtK7bVi1Mw77ArXxTflBkBGQQJ5SCASiWLxavkOOfXuZkdJMVux5+FbSbWQI7WbUHeHeglzZTfchYKuPVWLj4ZIQG4CjW88juavP5FbbUJ9sWpyrtHyf18S+OEzNL30SEK7+TZhsDtQOenRfAub8ZIACUgkwAQ9iQC5nARIgARIgARIgARymUDtrKvQWlejWojmnfeA6/xxqtmjIRIgAWUIrK/2wuOVpwpEeWkRupXblHGUWnVLwP3EDIQWL1DV/6q71GmVompQNEYCeUZgS30ANe6ALFHbbWb07e6QRReV5A6BpreeQuCrD1UNqGLCXBid5arapDESIAF5CXiEQ07rZTrkFGtxG2t1y4sElCLQ+MYTQrLRx0qp76DXuv9RcJx4YYcx3pCAnggEly2A59EZqrrsGjsF5r5DFLPp/fQ1+P/9imL69aTYfrJQaGBfFhrQ057RVxLINgEm6GV7B2ifBEiABEiABEiABDRKwPufN+B//yVVvauc9AgM9hJVbdIYCZCA/ATkrgIRe8AUe9DEiwRiBJoXfofG+feqCsN1xWSY+w1V1SaNkQAJKENAzla3fYQqRbF2grxIIEYgvGU96mffoCoMxxmjYd3zYFVt0hgJkIAyBOQ85FQlHHCKtWPnRQJyE4gGfKi5bZTcauPq62IuRCwJ3WC1x53nIAnogUDdPTcgsmm9aq5a9j4YztNGK26vtckN779fRPCHLxW3pWUDpq7dUX7DPVp2kb6RAAlojAAT9DS2IXSHBEiABEiABEiABLRAYFtrpmlXINoSVM0dx1ljYN39ANXs0RAJkICyBORsdRtr0RRr1cSLBGIE6u4bj8iGtarBsB5+MhxHnqGaPRoiARJQloBfaHW7SqZWt0WFRgzszSpFyu6YfrR7nr0PwV//p5rDlhH7wHnO1arZoyESIAFlCch5yMnQpQuG9iuF0WhQ1mlqzzsC3k+EylkfqFM5y3bkqbAf/q+8Y8yAc4dA07+fR+DTt1ULyCAktZbf8gAMxeodfg8u/x2eR6arFqMWDZVccA2Kdtpbi67RJxIgAQ0SYIKeBjeFLpEACZAACZAACZBAtgk0vfM0Al+8r5obfLikGmoaIgFVCazZ1ASvPySLzX49HCi2mmXRRSX6JeD/7hN4X3lc1QDY2lZV3DRGAqoQ2FznR11Dsyy2ulfYUOZklSJZYOpYSWjVYrjnTVE1gsrJQvVxFR/AqhocjZFAnhJwNwaxscYnS/Sx302x31G8SEBOAtXjzpRTXUJdBrsDlRMfBgxMMk0IiROaJhBauxTuOZNU9bH4+HNQfODxqtpsM+b7/C343n2h7TavfpoHDYdr9MS8ipnBkgAJZE6ACXqZs+NKEiABEiABEiABEshJAq0NtaidfqWqsbG1raq4aYwEVCMQCrVi6doGWezZikzo39Mpiy4q0S+BmplXIlpfq1oAbG2rGmoaIgFVCWzdCixcUSeLTZPJgKF9XRCKFfHKYwLux6cjtOR31Qiwta1qqGmIBFQnsHpjI3yBsCx2BwtVXguFaq+8SEAOAoGfvkTTC/PkUJVSR/HxZwuJRieklKMACWiVQN2cWxFZu1I190w9+6D8mjtUsxfPUKRuM2KH/kOLfok3ndNjZddMR0HPATkdI4MjARKQhwAT9OThSC0kQAIkQAIkQAIkkDMEPK89iuC3/1EtHvtpo2Db+zDV7NEQCZCAugRq3AFsqQ/IYrR3lR0l9kJZdFGJ/gj4vnoXvreeVc1x60HHwnHcearZoyESIAF1CTR6W7Cu2iuL0a5lVlS6rLLoohL9EQgu/gWeJ9R7IGrecXe4LrxBf6DoMQmQgCgCwZYIlq/ziJJNJeQUPjv1Ej5D8SIBOQjUP3gbwquXyaEqqQ6Dw4nK24TqebxIQKcEvB+9DP9Hr6vqvXPUeFiGjlDVZiJj/m8+gPf1+Ymmc3LcsvfBcJ42OidjY1AkQALyEmCCnrw8qY0ESIAESIAESIAEdE0gUrsJdXdcp1oM5qE7wzXqFtXs0RAJkEB2CKxY14DmllbJxouE6g8DhSoQvPKTQM3tlyHaJM/DylQEjRVdUTH+/lRinCcBEtA5gbWbvWjytUiOIlY9b1i/MhiNLKMnGaYOFdQ/NBnhlUtU87zi5vtgLKtSzR4NkQAJqE+gui6A2gZ5DjkN6FkCa1GB+kHQYk4RCK1bDvcD6rRwzGabzpzaNAaTFQLZaG1r2WM/OM8cm5V4ExndVk3v9ScQWrYwkUjOjXed/hS6FBblXFwMiARIQF4CTNCTlye1kQAJkAAJkAAJkICuCXheeQjB775QLYay6+9AQbc+qtmjIRIggewQ8PpbsGaTPFWKelYWo7TEkp1AaDVrBHyfvwXfuy+oZr/kgmtQtNPeqtmjIRIggewQaBFasS+TqRV7eWkRupXbshMIrWaNQPCPH+F58i7V7NuOOQP2Q05WzR4NkQAJZIdArBX7srVuhMJRyQ7YbWb07e6QrIcK8puA59VHEPzfZ6pAqLrrRVXs0AgJKEGgetyZSqhNrNNsRsVN98Po0OZhVu8nr8H/wSuJ/c+hmeITz4aVpY8AAEAASURBVEXx/sflUEQMhQRIQAkCTNBTgip1kgAJkAAJkAAJkIAOCahdPc966IlwHH2WDknRZRIggUwIrBOqFDXKUKWo0GzE4D7a/OIxEy5cI46Aml9yF+6yF0rPU6+arDgC2pYKb1qD1sZ6IPY0mZd6BAoKYe7WG4biEvVs5qClWBv2WDt2Oa5h/VwwmQxyqKIOnRConzcJ4VVLVfHW1KM3yq+9UxVbNEICchLw/ueNbYmlsYf09sNOlVN1TuvyNAWxfotPlhj793DAZjXLootK8pBAJIzqiSOBcEjx4G1H/wv2Q/nvhOKgaUARAk3vP4fAf95RRHcipXpICgutWAj3w9MShZAz46buvVB+3eyciYeBkAAJKEOACXrKcKVWEiABEiABEiABEtAdATVPwxrKKlB58xzdMaLDJEACmROQs0pRD6GKnotV9DLfDJ2t9H35DnxvP6ea1+U33QdTOVsHigEee+Duf/8lMaKUUZCAeehOKD7kFJj7D1PQSu6qjuWVLl3jRjgivUpRuVOoolfBKnq5+27pGFlw8c/wPKFewpxz5I2wDNutoxO8IwENE/B/+xG8bz0NRCJ/e2k0ovjYs1B8ACvM/A0l8avVGxvhC4QTC4icYRU9kaAoFpfAtv+WX3sy7pzcg1Uz5gNmVsyXmyv1KU8guGwBPI/OUN5QOwumvgNRPlYniW+hIBpeeggtv33XLoLce+kac5vwuXyH3AuMEalCIOpvQsuSX9CyejEim9cj6q5D1Nv4l+3YMzVTWSVMPfrBPGBHWIbu+tccX+iHABP09LNX9JQESIAESIAESIAEFCPQ6qlF7bQrFdPfWXHJ2VegaLf9Ow/zngRIIMcJbK7zo66hWZYodxpULoseKtE+gZrpVyDaIFRnU+GyHn4yHEeeoYIlnZtojcD9+AyElv+h80Byy309VE/QKnF3YxAba+SpUsQqelrdZfn9cj86FaFli+RXHEdj4a7/QOm518aZ4RAJaJNApG4T6mZdLzgXv7pu2TXTUdBzgDad15BX/uYwVm34+8GsFNdYRU8KvfxeWzd3AiJrVigOwXrQsXAcd57idmiABGQnEI2i+sazZVebSqHriskw9xuaSkxT87l+yM+y14Fwnn65ppjTGe0TCC79FYFvP0Zo4U9pOxtrC99aXw1jGQ8apw0vSwuYoJcl8DRLAiRAAiRAAiRAAloi0PT2/yHw5b9Vcck8aDhcoyeqYotGSIAEtEUgGt2KJavdaBV+Sr16di1GqYMn66Vy1Pp6//8+hvfVJ1Rx0+AqQ+UtD6piS+9G3E/OQuiPX/UeRk76X3LelSjaZd+cjE3poFau9yAQbFflKUODFaVFqCpnFb0M8elmWWjVH3DPu101f8tvuleo7tpNNXs0RAJSCbgfnoLQisUJ1RQIVX/K9FL1J2EU6kysr/bC422RbIxV9CQjzEsF4U1rUH/PTarEXjFhLoxOHsRTBTaNyEpAza40bY5b9z8KjhMvbLvV1c/gHz/C8+RduvJZtLNmM6qmPgUIFYN5kUAqAqH1K+D74EWEli5MJZpyftu/CceeA5gKUspSILsEmKCXXf60TgIkQAIkQAIkQAJZJxBt9qNmymVC2xnpbVPEBKPH031i4qIMCZCAOAK1QgW9aqGSntTLUmjEoN6lUtVwvcYJ1N01DpHqDap4aT/9Utj2OkQVW3o2EvjxczS9+LCeQ8h532MnqHmlT6DJ34K1m7zpL4yzYof+ZcIzmS5xZjiUKwTcT9+N0IIfVAnHevBxcBx7riq2aIQE5CJQM2V0h5ZcnfUabMWonPJ452HexyHQEmrFsrUNcWbSHxrQqwRWCx/cpk8uf1c0vfsMAp+/pzgAy+77wnmWep09FA+IBvKGQPPPX6HxeXUP+sXaXFaOvx8wGHTLOVJXLVTavUa3/idz3HHGaFj3PDiZCOdIAN5PX4f/3y/LSsLgKofjlJFC69sRsuqlMnkJMEFPXp7URgIkQAIkQAIkQAK6I+D95DX4P3hFFb8te+wH55ljVbFFIyRAAtolsHSNG6FwVLKDvavsKLEXStZDBdok0Pz7t2j8P+FLZxUuk1DFpZxVXESRrp83GeFVS0TJUig7BEouuBZFO/0jO8Z1bnX1xkb4AtIPrXQts6LSZdU5DbqfiEB4y3rUz74h0bSs49uSmCYID30L+PeOrGCpTHECNZMvQdSXOOnZUGRD5VR1qiQrHqwKBjbV+lHvaZZsySl8duolfIbiRQJiCdRMG4Ooxy1WPGM519gpMPcdkvF6LiSBbBBo9dShdpr633OXnH81inbeJxshy26z4Zl70fLbd7LrzaZC82Che9Cl7B6UzT3Qum3PC3MQ/Olrxdy0n3QBbPsdrZh+KpZGgAl60vhxNQmQAAmQAAmQAAnonkDN1MsRbZTnNHYqGGzNlIoQ50kgPwi4G4PYWOOTHKytyIT+PZ2S9VCBNgm4H75daI32hyrOOUfeAMuw3VWxpXcj1ePO1HsIOe+/9cBj4Dj+/JyPU4kA/c1hrNrQKFm1yWjAsP4uyXqoQJsEPK8/huA3n6riXPHx56D4wONVsUUjJCAngZrbRiIa8CdUaSi0oHL6/ITznOhIIBKJYvFqeZKkhvQphdnM1nsdCfMuHoHgkl/heXxWvClZxwr6DUbZFeq1jZfVeSrLawLuJ2YgtHiBqgxysdpk09tPI/Dl+6pyVNpYhXDAxugsU9oM9euQgHv+bIQW/qS458XHny18jjxBcTs0kD4BJuilz4wrSIAESIAESIAESCBnCAR++AxNLz2iSjxF+x+JkhMvUsUWjZAACWifwHKhTVNQaNck9erfwwGb1SxVDddrjEBo7VK450xSxSvz0J3hGnWLKrZywQgT9LS/i7n40EZN6ms3e9Hka5FssnulDWUlRZL1UIG2CESb/aiZfCnQKv1vmFSRGcsrUXHTA6nEOE8CmiSw5ebzsTUcSuyb0YiqO55LPM+Z7QhU1/lR2yC9il6ZswjdK2zb6ecACXQm4HlpHoI/fNl5WPZ7x5mXwbrHQbLrpUISUJKAmh1p2uIw2Gwov+FeGIodbUM589P3+VvwvftCzsTD5Kic2UpZA1Hr92qb044zLxd+vx7YdsufGiHABD2NbATdIAESIAESIAESIIFsEKibcysia1cqb1r48r1ywjwY7CXK26IFEiABXRBoaApiwxbpVfRKigvRuxvbNOli09Nw0vPigwj++FUaKzIXdY2ZBHP/YZkryKOV0YAPNbeNyqOI9RkqE/Sk7VtAqKK3UoYqepZCIwb1LpXmDFdrjoD3szfhf+9FVfyynzYKtr0PU8UWjZCAnATEtvwrH38PTBXd5TSd07paW/+sord1q7Qwu3QBduhfBoNBeMGLBJIQqJlwMaLBQBIJeaaq7lLn96o83lILCQDB5b/D88h01VE4zhgN654Hq25XLYP+7/8D78uPqmVOUTum3gNQfpX67xFFg6JySQR8X70L31vPStKRyeKyG2ajoGuvTJZyjUIEmKCnEFiqJQESIAESIAESIAGtEwit/APuh9RpIWE9+Dg4jj1X60joHwmQgMoElglV9FpkqKLHNk0qb5zC5qK+RqE60WiFrfyp3rzj7nBdeIMqtnLBCBP09LGLTNCTvk9yVdHr090Oh61QukPUoBkCtbOuQmtdjeL+mLr2ECqk3K24HRogASUIiH3Abj/lItj+eaQSLuSsTrmq6FWV21BRyiqvOftGkSGw5oXfoXH+vTJoSq7CeuAxcBx/fnIhzpKAhghsbQmi9t4bEVXh78H2YZt33hOu869vP5STr5sXfIvGp+/Pidh4ECEntlGWIFrrq1E76zpga1S0vqL9joS572AYXZWIej0wWGwI12xEeOUiBH/9n2g95sHD4bp0omh5CipPgAl6yjOmBRIgARIgARIgARLQJAHPC3MQ/Olr5X0rKEDlxIdgsBYrb4sWSIAEdEXA3RjExhrpVfTKhYdL3YSHTLxyg4D309fh//fLqgTjGjtF+MJriCq2csEIE/T0sYtM0JO+T36hit4qGaro2W1m9O2eey2opBPWpwa1khVidHK9Qoo+3wH0WiwB91N3ILTol5TifGCYEtF2ApHIn1X0tptIc6CwwIjBfVnlNU1seSWu1neGZePuREFV77xiy2D1TcDz7L1Ccsx3qgZhsBSh7Ma7YXS4VLWbLWPBxT/D88Sd2TIvm13bMWfAfsjJsumjIv0S8Dx/P4I/fysqAMueB8B5xpiksrHv5nzCd6eBL95PKtc2WXL2FSjabf+2W/7MMgEm6GV5A2ieBEiABEiABEiABLJBIOpvQs2kS1Uxzep5qmCmERLQLYHfl9dJ9t0otGfaYUCZZD1UoA0CalUnMu+4m1A970ZtBK0TL5igp4+NYoKePPu0emMjfIGwZGWD+5Si0GyUrIcKsk/A/eQshP74VXFHjJXdUXHjPYrboQESUILAtgohM68RrbpsnNB2q4ptt0QDEwQ31fpR72lOZ0lc2T7dhCqvxazyGhcOB6FGe9uC/kNRNmYyaZOAbgj4vngbvneeV91f+78uge0fh6puN5sGg8sWwPPojGy6INm2qXd/oc2tvmOQDIEKEN68FvV3j09JomDAMJSeew0M9pKUsm0CsWTWpmfuRzTU0jYU96epR2+UX6v/pNe4welwkAl6Otw0ukwCJEACJEACJEACUgn4Pn8LvndfkKpG1PrKSY+k9cFClFIKkQAJ5AyBuoZmbK7zS46nR2UxXCUWyXqoILsEgot/Ek5Kz1bFCdeYSTD3H6aKrVwxwgQ9fewkE/Tk2SevP4Q1m5okK2OVV8kINaGgtX4LamderYov9tNGwrb34arYohESkJuA5/XHEPzmU9FqLXsJVUJOT14lRLSyPBEMhVuxdE2D5GhZ5VUywpxVoNZnMvtpo4Tfd4flLEcGllsEQisWwv3wNNWDKtxlL5SeJ7TGzMMruPx3eB6ZruvIK259AMbSSl3HQOelEWh84wk0f/1xUiWmXv1QPnYqYDQllYs3KTaZ1XnpzbAM3iWeCo6pTIAJeioDpzkSIAESIAESIAES0AKBurvGIVK9QXFXivY7AiUnXay4HRogARLQL4GtW7di4Yp6yQHYikzo39MpWQ8VZJeA++m7EVrwg+JOmIfsCNclExS3k2sGmKCnjx1lgp58+7RyvQeBYESSQqNRqPLan1VeJUHUwOKmD15E4JM3VfGk6q4XVbFDIyQgN4HQuuVwPzAxbbU8NJE2Mqzf4oOnKZj+wk4rhghVXs2s8tqJCm89rz2C4LefKQvCaETV1CcBM6s4Kgua2uUgEG32o+6+mxCtr5VDXVo68v3ge3DZb0IlvZlpMdOSsP3E82Db/1gtuURfVCZQM+VSRL3JD/6VXTsDBT36Z+yZ97M34X8v+WdIyz8OhPNfl2dsgwvlI8AEPflYUhMJkAAJkAAJkAAJ6IJAaOUiuB8STuSocFXcfB+MZVUqWKIJEiABPROoFiro1QqV9KReA3uVoMhSIFUN12eJQNTXiJrJo1Wx7hx5AyzDdlfFVi4ZyTRBL3YauGiPA3MJhSqxREPBlF+yxnOECXrxqGQ21iAkP2wQkiCkXr26FsPpYJVXqRyzub5mxlhE3XWKu1B8/NkoPvAExe3QAAkoQaBu7gRE1qxIW7WpZ1+UXzMr7XX5vKA5GMaK9Y2SEVS4rKgqs0rWQwW5RaBm2hhEPW5Fg7KM2BvOc8S3w1bUGSongRQE3PPvRGjhzymk5J8uOfsKFO22v/yKdaYx+MeP8Dx5l868/tNd8+DhcF2a/uEFXQZLp7cjEFq7DO45t2033n6gaN/DUXLyyPZDGb2uHndm0nUGpwuVE+YlleGkOgSYoKcOZ1ohARIgARIgARIgAc0Q8LzyEILffaG4P5bd/gnn2VcpbocGSIAE9E8gHI5iyRrpDwDKnEXoXmHTP5A8jcD3xTvwvfOc4tGbegkPga/mQ+BMQGeaoGcZsY/wAE6d1pCZxKXVNVFfk5C0emna7jFBL21kSRf8vlx6UlaxtQD9epQktcNJ7RIILv5FaL9+hyoOVs16BjDxsIEqsGlEVgLptrbtbJytbjsTSX2/emMjfIFwasEkEgUmA4b2cyWR4FS+Eci0Ema6nJwXXQfL8L3SXUZ5ElCdQNOHLyHw8Ruq2+XvxY7Im3/5Lxqfm9txUCd3XafPR5dCHtbSyXbJ6qbvq3fhe+vZpDrLrpuFgu59k8qImfR+/Ar8H76WVLRiwlwYneVJZTipPAEm6CnPmBZIgARIgARIgARIQDsEhFaSNbdeiGioRXGfXGOnwNx3iOJ2aIAESCA3CKyv9sLjlfZvE9sI6vu9EGsZE9mwRvEg7KdfCttehyhuJxcNMEFP3V1lgp66vBNZq3EHsKU+kGha9DjbCIpGpTlBz/MPIPjzN4r7ZT3oWDiOO09xOzRAAnITaPr38wh8+rZktdYDj4Hj+PMl68kXBY2+Fqzb7JUcbp9udjiK2WZUMsgcUeD96GX4P3pd0WgMVhsqb39CURtUTgJyEGj+7Rs0PvOAHKrS0mEsr0TFuLt5aKMTNf/XH8D7xvxOo9q/LTnvKhTt8k/tO0oPZSfgeeVhoVDG5wn1GkrLUHnrgwnn05kIrV8B9/0Tki5xjhoPy9ARSWU4qTwBJugpz5gWSIAESIAESIAESEAzBJp//hKNzytfyrpgwFCUXT5ZM3HTERIgAe0T8DeHsWqD9DZNvavsKLHzAZP2d7yjh+GNq1B/7y0dBxW6q7rrRYU0575aJuipu8dM0FOXdyJrkUgUi1dLr/JaKbQR7Mo2gokwa3c8Ekb1hIuASERxHytueQBGV6XidmiABOQk0PjGE2j++mPZVFr2PhjO00bLpi/XFclR5bVESM7rLSTp8SKBGIG6ObcisnalojBYGUxRvFQuE4HwlvVoEJJd1Djk3tll56ibhCSaXTsP814gkK2KhlLg8988KfT0vdb9+HSElvyeMAjzsF3gGnlzwvm0JqKtqL7xnKRL7KeNgm3vw5LKcFJ5AkzQU54xLZAACZAACZAACZCAZgi4n5yF0B+/Ku5PyTljUTRiP8Xt0AAJkEBuEZDjAZPDZkaf7o7cApMH0TS9+wwCn7+neKTWw0+G48gzFLeTqwaYoKfuzjJBT13eyazJUeW10GzE4D6lycxwToMEAj98hqaXHlHcM/POe8F1/nWK26EBEpCLQHjzGjQJVWzCq5aIUmkoq0C0vlaUrKnvQJScdBEKeg4QJZ/PQrVClddqGaq87tC/DLFq5Lzym0DU70XNpEsUh+AceQMsw3ZX3A4NkEDGBLZGUXf/zUKF/7UZq8h0ofWQE+A45uxMl+fFOs8rDwlVyb7QTawGpwuVE5QvmKAbIHnkaN3cCYisWZEwYrmTN6vHnZnQVmyi+LizUHzQiUllOKk8ASboKc+YFkiABEiABEiABEhAEwTU+qItFiyrE2liy+kECeiOQH1jEJtqfJL93qG/S3jAZJCshwrUI1Az80rRD22leFUxcR6MJS4pKvJ6LRP01N1+JuipyzuZNX8ghFUbm5KJiJrr37MEtqICUbIU0gYB9xMzEFq8QHFnnJfeAsvgnRW3QwMkIJVAa5MH/i/eRuCL90Wrij2YLrtyKurnTRH+3qsRva5ovyNRfPAJwt9uZaLX5JugXFVee1QWw1ViyTd8jLcTgeZf/ovG5+Z2GpX31mCxonLak/IqpTYSkJmA57n7EPzlfzJrTa2uoN9glF1xe2pBSsD9yFSEli/SDYmy6+9AQbc+uvGXjspDoO4BoSrtusRVaeWuHJ0qQc927JmwH3ySPMFRS8YEmKCXMTouJAESIAESIAESIAF9EfB/+xG8ryn/JRirE+nrfUFvSUBLBKLRrVi0sl6yS90rbChzFknWQwXqEAit+gPuecp/CV24y14oPY/ViaTsKhP0pNBLfy0T9NJnpuQKOaq8xn43xX5H8dIHgai/SagkdKkqzvKAkyqYaSRDAluDzQgu/w0tC74TEha+TVuL85KbYRmyC0IrF8H90NS011t2/QcKd94bhYN2hqGI/4Z2BihHlddiawH69SjprJr3eUZAjapUlhH7wHnO1XlGluHqiUDWWqgajSi7bhYKuvbSE66s+Rr1NSKW/BR112XNh3QMF59wDooPOD6dJZTNAQLuR24XEkn/SBiJeec9hCrq4xLOpzuRKkHPfvKFsO17VLpqKS8zASboyQyU6kiABEiABEiABEhAqwTcjwony5Ypf7Ks4tY5MJZWaBUD/SIBEtA4gQ1bfGhoCkryslioTtRPqFLESx8EGt98Es3//UhxZ52jxsMydITidnLZABP01N1dJuipyzuVtbqGZmyu86cSSzpvEqq7DhOqvPLSBwG1DjjxgZ0+3g/54OVW4WF3w6uPorVmA7YKB2cQjQKhFkR93ozDt582Era9D/9rvdS20QabHTAXokusWrahC4yVPVBy8si8rrLn9YewZlPTX4wzfTG0rwsFBaxCnim/XFhXM/OqtKpcZhJzyTljUTRiv0yWcg0JKE4g8OMXaHrxIcXtxDNgP22U8PvysHhTHEtAILRqsXDYc0qCWW0Nm3fYFa6Lb9KWU/RGcQKe5x9A8OdvEtoxVfVE+bi7Es6nMxGp3YS6O5IfSi658FoU7fiPdNRSVgECTNBTACpVkgAJkAAJkAAJkIDWCGT6gDfdOMzDR8B10fh0l1GeBEiABP4i4G8OY9WGxr/uM30xtJ/wgMnEB0yZ8lNzXc30KxBtkF45MZXPrE6UilDqeSbopWYkp0Smf79Zdt8XzrOulNMV6hIIyNVGsF8PB4qtZjLVAQH3Y9MQWrpQcU8rb38cBmux4nZogARSEai+4WwImXmpxETPF594Lor3Py6ufKoKH3EXJRzsgqq7Xkg4mw8TclR57SZUeC1nFfJ8eLvEjbG1fgtqZypf2a7rtKfQxcJq93E3gYNZJRBavQTuBydnxQfLXgfAefqYrNjWu1H/Nx/C+/pTmg/DIPy7Vyn8+8crvwh4P3kV/g9eTRp0xW0PwegoTSojZlLMfwtlN8xmlU4xMBWWYYKewoCpngRIgARIgARIgAS0QMD/v0/gffVxxV0pOf9qFO28j+J2aIAESCC3CSxb24CWUKukINnmVhI+1RaH1iyFe+4kxe3ZjjwN9sNPU9xOrhtggp66O8wEPXV5i7G2drMXTb4WMaIJZVwlFvSoZDJWQkAamYg2+1EzcaTi3lh23RvOc69R3A4NkEAqAtU3niNUzJP293d7G/ZTL4ZtnyPaD3V47f/+P/C+/GiHMUk3XQyomjkfMOVnAnR1fQC17oAkhLYiE/r3dErSwcX6JSD7f5NxUJgHDoPrMuU/+8UxzSESSEqgtbEe9XMmIupxJ5VTYtJU1QPl180WqsLygGmmfD2vPozg/z7PdLlq61xXTYW59yDV7NFQ9gkEl/wKz+OzkjpiO/ZM2A8+KamMmMn6B29DePWyhKJMEk2IRvUJJuipjpwGSYAESIAESIAESEB9Au4nZyH0x6+KG2Z1IsUR0wAJ5AWBGuHh0hbhIZOUq9gqtLntwTa3UhiqsbbpvWcR+OxdxU1V3PIAjK5Kxe3kuoFME/QMThdMvfvnOh7544u0Cn+//ZK2XlbQSxuZ6AWN3hasq8681WPMUKy6a6zKKy9tEwj8+LnQ4uxhxZ10jrwBlmG7K26HBkggGYGmN59E4L8fJRMRPWewO+A4/TLhfb1byjXBZQvQ9PLDsiVEWPY6UKhAdHlKu7ko0NLSimXrGiSHNkz4/WRiFXLJHPWowPPigwj++JWirsuVhKCok1SelwTq5k5AZM2KrMTuGjsF5r5DsmI7l4zKW5lXGTLFx52F4oNOVEY5tWqTQGsrqm85HxB+Jru6Tp+PLoWWZCJJ55oXfIvGp+9PKmPecTe4LrwxqQwn1SHABD11ONMKCZAACZAACZAACWSPQCQsfBC4QDgNL1+rmnjBFO17BEpOvjjeFMdIgARIIC0Csep5sSp6Uq8d+rtgNPIUslSOSq6vm309Ils2KmkC5kHD4Ro9UVEb+aI80wS9fOGjlTiZoKfsTvyxsh6t0a2SjPTvWQJbUYEkHVysLAH303cjtOAHRY0YSlyonDhPURt5pzwcQrh2I1ob6tDqbwJagtgq/M/oLEfhgOFCK2F73iERE7D7kdsRWv6HGNGkMrEqQK7Rt8FgL0kq134yGvDC/dAURDZvaD+c0WtT34EoHzsto7W5sGjleg8CwYikULoLFV7LhEqvvPKPQO0dV6O1douigZddOxMFPfopaoPKSSBdAg3P3IOW375Pd5ks8sUnnie0gj9WFl35riS0fiXc99+qaQzm4UKC1EVMkNL0JingnJjPlZbd94PzrLEZWY96G1EzZXTKtY6zxsC6+wEp5SigPAEm6CnPmBZIgAREEJi7dKUIKYqQQPYJjB0yIPtO0AMSSJNA8+//Q+P/3ZfmqvTFeeIvfWZcQQIkkJiAHA+YenYtRqmDD5gSU87uTLhmI+rvvF5xJ+z/ugS2fxyquJ18MMAEPX3sMhP0lN2nDVt8aGgKSjJSXlqEbuU2STq4WFkCNcIBp2hIWjvjVB5aDzgajhOEg1S8MicQCqJ50Y9oWb4A4TXL0VqzOakuy94Ho+T4CyRVqEhqQKeTnhfnCpWz/iuL9+bBw1FyxhgYS8pS6mttakDjSw8itHRhSlkxAoU774nS85X/21KML9mQqWtoxuY6vyTTdpsZfbs7JOngYv0RiP23WHu7stUnY4m7lZMe0R8cepzTBJremo/AVx9kJUZ+ZpMfu++rd+F761n5FcukMVZluHLSozJpoxq9EAgu/hmeJ+5M6W4mnw2jvka4588WVQGUna9SboFqAkzQUw01DZEACSQjcNJ7nyab5hwJaIbAm8fy4a5mNoOOiCbgefkhBL//QrR8JoLGyipU3Kh8EmAmvnENCZCAPgnI8YDJUVyIPt1YKUWr7wDfl+/A9/ZzCrvXBV2nPyk8iC9S2E5+qGeCnj72mQ97lN0nrz+ENZuEylwSLovZiEF9SiVo4FIlCQSX/ArP47OUNLFNt+uq22HuPVhxO7lqoOGZe9ESq3K4Nb1K8cbKbnCNuhlGV2Wuokk7rnDtJtTfcV3a6xItMJSUwnnu1TD3G5pIBKE1S+F59n7Z2tvGDLmung5zr/w9WBsOR7FkjTshc7ETwweUwWDoIlaccjlAQI2DvZYRe8N5zjU5QIsh5AoB72dvwv/ei1kJx1TVE+XX3QEYjFmxn8tG3fPvRGjhz5oNsXz83TBV9NCsf3RMGQJ1cycKSXTLUyo3Dx8Bx3HnCe+R7illmxd+h8b596aUiwnYjv4X7IeeKkqWQsoTYIKe8oxpgQRIQAQBJuiJgEQRTRBggp4mtoFOpEmgZtoYWb/0jmfeeugJcBx9drwpjpEACeiBQLRVc18MhoQHTEslPmAydOmC4QNTV+/Qwxbloo/uR6citGyRoqGZd9wdrgtvUNRGPilngp4+dpsJesrv0x+rhDa3rdLa3A4WEvQKhUQ9XtojoEY1FR5wymzfY0kk/i/eFVUlIpkFU58BKL9yejKRvJyrHnemrHE7R90Ey9Bdt9MZXLYAnkdnbDcuZYBVQf6kt2qDB/5maW1uYwecYgedeOUPgaZ3nkbgi/cVDdh+2kjY9j5cURtUTgJiCfi//w+8L2erklkX/HlIY5BYdymXBoFWTx1qp2XWKjQNMxmLOs64DNY9D8p4PRfqk0BwqXAA7DHxB8Ase+wHy07/gLnvEBhsf1c2bq2vRnD57wj+/DXCq5aIhsG/k0WjUkWQCXqqYKYREiCBVASYoJeKEOe1QoAJelrZCfohlkB442rU33uzWPGM5cqumYGCnv0zXp/pwuafv0LzD58jtPzvBI/Yw5ai3faDbd+jM1XLdSSQFwSizX74Pn8LLb9/L7QDq94Ws8FWjIJBw2H751Ew9x+WdQ5ytLnt18OBYqs567HQgU4EWiOovun8tKvedNKS8tZx1hhYdz8gpRwFxBFggp44TtmWYoKe8jsgR5vbbhU2lDtZ3VP53UrfQt3s6xDZsin9hWmssB5yPBzHnJPGivwWDW9aA+/7zyG05HfZQFgPPg6OY8+VTV8uKPJ/8xECn7+NVm8jEA7LEpLr8ttgHrDDX7pCq5fA/eDkv+4lvSgogKHYAdsBx8C2/7GSVOXK4lqhzW21xDa3rhILelQW5woSxiGCQP28ScKD/qUiJDMXKR9/j6iKQJlb4EoSEEcguOgHeJ66W5ywAlL200YJyaqHKaCZKtsI+L/9CN7Xnmy71dRPyz8PhfOUSzTlE51Rh4Dn9ccQ/Eb9boLOi66HZfie6gRJK6IIMEFPFCYKkQAJKE2ACXpKE6Z+uQgwQU8uktSjFgHfZ2/B994LiprLSvWHaBTup+8WStb/lDA2U9+BKD33Ghid5QllOEEC+UoguPhneJ64M2n4WnhwXOMOYEt9IKmfqSbLS4vQrdyWSozzKhMILv5JeA/OVthqF1TNeAowWxS2kz/qmaCnj702D9wBrstu04ezOvWyydeCtZu9kry328zo2/3v0/CSlHGxbARaG2pQO/0q2fQlUuS6eqrQipOVUxLxaT/uE1rQ+RRqQeccNV6o8DaivTm+7kQgGgwgvGEVWpYvQODTtzvNpr412B0ou3LatpbCsao29Q9MQLTJk3phJ4lYQqV50M7bWtgaivi3fSc8f92GQq1Yurbhr/tMXphNBgzp58pkKdfolIDc1TPjYWD1nnhUOKY2AVmTxDNwvmjfI1By8sUZrOSSdAm4n5iJ0OLf0l2mijz/PVQFsyaN1D1wCyLrVqnmW/FxZ6H4oBNVs0dD4ggwQU8cJ0qRAAkoTIAJegoDpnrZCDBBTzaUVKQSAfej04T2gQsVtWY96Fg4jjtPURudlbsfnyFUT1jQeXi7e1NVT5QL1f1gYvWs7eBwIG8JpPOFZLbbVwdbIli+Lv0HeO03t6jQiIG9S9sP8bUGCKjRPtC8wy5wXax8FVkN4FTNhdD6lXDff6tq9mgoMwKGUhcqb52X2WKuEkVgq9DddtHKOsR+ZnoJXdgxfEA5Yj95aYeA/7tP4H3lcUUdMpZVoOLmOYrayAnlkTDcz9+P0IIfFQ2naubTQAE/L4qFHFzyCwJfvit8z/B3FftUawv6D0HZmClwP3w7Qiv+SCX+13zBgKGwHXgsLDuw6sdfUES8WLGuAc0trSIkE4sMFj4/FQqfo3jlPoFw9TrU33WjooEW7rwXSs+/TlEbVE4CqQio8V5P5oN54DDhENWkZCKck5FAeMsG1M8eJ6NG+VQxQU8+lnrT1NpQKxwGu1IVt1mtURXMGRlhgl5G2LhIKwRa3TUI127u4I5lyC4d7uPdxFtn7j0Q8U7fxVp/hdat6KAmkWx7oc7rUq0JLu2YyW+wFm87EdheZy6/ZoJeLu9ubsXGBL3c2s98iKb6JqFlTySiaKiuMZNUbYXp++Id+N55TnRM/DAiGhUF84RAuqfjXWOnwNx3SNboLFvTgJawtAdMw4QKECahEgQv7RCou+cGRDatV9Qh+6kXw7bPEYrayDflTe8+I7S+ey/fwtZlvBW3zoGxtEKXvuvF6TWbmuD1hyS5yzbskvApstjz3H0I/vI/RXS3KWX1lDYSiX/GHl41/N9diGxYm1hIphnLngfAecYYmbTlj5rmn7+C951nEPU2iQq6oN9ghFcvEyUb+47edvy5sO11sCh5CnUkUF0XQG2DtCrkbMPekWku3wV+/AJNLz6kaIjFJ56L4v2PU9QGlZNAMgKxCq6108YmE1F0zuBwouzq6TCWlClqh8o7EvB+9DL8H73ecVADd2XXzkBBj/4a8IQuZINApHYTPPOFzzlbNilmnp9vFEMri2Im6MmCkUqyRcD76evw//vlDubFZJ7HW+e85GbES+6LJc55HpvZwUYi2fZCndeZuvdC+XWJWzh1flAaOyFYdvnk9ipz+jUT9HJ6e3MqOCbo5dR25nwwoRULhRPq0xSNM9aupnLSo4ra6Ky8ZsZYRN11nYeT3ldOexIGizWpDCdJIB8IZNJW1LLbP+E8W/lWb4n4b6r1o97TnGha1HivrsVwOtjmVBQsFYSivkbUTB6tuKWKifOEL8DZnktO0J0/t8qpm7rkJWA97CQ4jjpTXqXU1oGAuzGIjTW+DmPp3lQIbdir2IY9XWyKytfcfllG7TfTccp5yU3Cd5C7prMk72TV/n3jOPNyWPc4MO84Sw24VWhV2/jinLSq6aWyGUvkc559JZPMU4FKMu9vDmPVhsYkEqmn2IY9NaNckVCjsrnrytth7jM4V5AxDp0RiAa8qLntkqx6LeaZclYdzGHjtXdei9aajoV+sh2u/fRLhEMIh2bbDdrPIoFYkSfPSw8itPBn2b2wHXkq7If/S3a9VCgfASboyceSmrJAIF6inVYT9GJ4bEefDvuhp8Ql1fmLJyboxcXEQRLIOgEm6GV9C+hAGgTUOCVm2X0/OM9S7wRiuGYj6u+8Pg0Kf4o6L7oOluF7pb2OC0gg1whk8uV7NhJx23OPVSeKVSmScpUKyXk9hSQ9Xtog0LzgGzQ+/YCizph69UP51R0PWilqMA+UB374DE0vPZIHkeZOiGK+H8mdaNWPJByOYskatyTDVosJA3o5JengYvkIqNEKy2AuROWM/5PP6RzTFPU2ov6hyVl5kFoxYS6MzvIcI6pOOA3P3IOW376XbMw8fARcF42XrIcKgD9W1qM1mnkfdqOhC3YYwEpP+fBeSrf1dCZM+DdpJtS4RhYCkTDqHp6CyJqOXdJk0S1Sif2k82Hb7xiR0hSTm0Dzb8L3T88o+/1Tuj6zmna6xHJX3v/Ve/B/+CqiQWkH02OETL37w3HM2TAP3DF3geVIZEzQy5GNzNcw9JagF9unRCclmKD3ab6+jRm3zggwQU9nG5bn7qrxJVvJ2VegaLf9VSPduUKtWMP8MkQsKcrlOgH303chtODHtMOsuuNZwGhKe50cC7Zu3YqFK+olqSosMGJw31JJOrhYPgKNbzyB5q8/lk9hHE3WQ0+A4+iz48xwKFMCnT+zZqqH69QjUHLOWBSN2E89g3loafnaBgRD0tqwDxcSIAxCIgSv7BPwf/sRvK89qagj5h13g+vCGxW1oWfl9fMmIbxqaVZCMO+wK1wX35QV27lg1P34dISW/J5xKPl2WD1jUCIXrtvsRaOvRaR0fLGBvUpQZCmIP8nRnCFQM+VS0a2qMw2aCXqZkuM6qQTcj0xFaPkiqWoyXs9ErIzRybrQ/fgM4W+UBbLqlKKMf/NIoZd7a2PV9Hyfv4XAp29nFJypZx9Y9z0K1j0Pzmg9F6lPgAl66jOnRRkJ6DFBz+B0ofz62TAU2TqQ6PywI99+QbPFbYe3A280TIAJehreHLq2HYHOv1u2E5BhoHLKozDYHDJoEqci0wQ927Fnwn7wSeKMUIoEcphApl9KZTNBL7Ydqzc2whcIS9qZoX1dKCgwSNLBxfIQUOP3k+vy22AesIM8DlMLQuuWwf3AbSShMwLmQcPhGj1RZ17ry1052rD37e5ArJUgr+wT8Dz/AII/f6OoI/ZTLoLtn0cqakOvyj2vP4bgN9k9wFt8/NkoPvAEvSLMqt+xFoJ194xH1JN+ZVFDsR1l190Bo8OV1Rhyybgcbdi7CS3Yy4VW7Lxyl0CsamnNlNGKBmjZ5xA4T71UURtUTgLxCLifmInQ4t/iTakyZh66M1yjblHFFo0kJ6C17zOy3akkOS3OZpNA84Jv0bL4Z4TXLENr7Zb4rhiNMPXos+07T8vwPWHuOyS+HEc1S4AJeprdGjomhoAeE/RicZl33F04LXtDhxA7P6Rigl4HPLwhAc0QYIKeZraCjqQgoMYHz2y0DwytWQr33Ekpot9+2vLPQ+E85ZLtJzhCAnlGoPPfnGLDz/aJ91p3ANX1AbHuxpXrVWWH014Yd46DKhIIBVF9y4WKGjQUWlA5fb6iNvJNueeVhxH87vN8Czsn4i27bhYKuvfNiVi0GESTUJ1orVClSMpV6bKia5lVigqulYlAzcwrEa2vlUlbfDXlN90LU3m3+JN5PNr8y3/R+NxcTRAou2Y6CnoO0IQvenOieeF3aJx/b9pus+Jr2shSLggJ1V2XClVepVyO4kL06WaXooJrNU4gtGIh3A9PU9RL+2kjYdv7cEVtUDkJdCbgnn8nQgt/7jys2r2xshvKrpy2XaEW1Rygoe0IeF6ah+APX243nq2BysmPwFBcki3ztKsHAuEWhBtqsdXvg7nf0G0HZ43FThhdlXrwnj4mIcAEvSRwOKV9AnpN0IuR7XxitvPDUiboaf/9Rw/zkwAT9PJz3/UYte+rd+F7S2hJqeBlPehYOI47T0EL26tuddegdsZV20+IGMl2gpEIFylCAooSiNRtRt2sa9O2EasAXTlhXtrr5FwQaA5j5YZGSSrLnEXoXtGxirUkhVycEYHgsgXwPDojo7ViF7FFnVhS4uS2tjRjy60XiROOI9V1+vw4o+KGvB+9jMAX7ycVTle//+sP4Hv/RVl1Bn79Gt5XHkuqs2LCgxk/oAku/y2jhIeYQ0X7Ho6Sk0cm9Y2TmROIRrdi0UppbdiLiwrQrycfzmS+C/KsbG1qQO3tl8ujLIEWQ1kFKm+ek2A2j4cjYdTMvArRRmnJRHIS5GfHzGm6588WkiJ+Eq2AFYZEo0pbcOkaN0LhaNrr2i/YaVB5+1u+zjECsb+LvW/MVzQq11VTYe49SFEbVE4C7Qm4n74LoQU/th9S97XZjLIrpqCgRz917dJaUgKt9dWonXlNUhk1J9n1QU3atEUC2iLABD1t7Qe9SZOAnhP0YlUdyq6/869MZyboZbeFRZpvPYrnMQEm6OXx5ussdM+z9yL463eKeu0cNR6WoSMUtRFPefX4c4DW1nhTScfiVbBNuoCTJJBjBDJt26aVgyO/L6+TtCNWiwkDejkl6eBi6QS8n7wK/wevSleUREPx8ecI7emOTyLBqXQI+L58B763n0tnyV+y9pMvhG3fo/66T/dF0/vPIfCfd5IuSzeJQkw86eoM/PQlml5InshceftjMFgzr0LT+TuDpFA6TVbdIeyf0AaFlzIEVq73IBCMZKzc0KULhg8sy3g9F8pDINPKX+lYt+x5AJxnjElnSV7INr3zdMpkbLVBWA8+Do5jz1XbbE7YC60Vqt7PEV/1vnT0rSgctFNOxK61INZv8cHTFJTk1pA+pTCb+TeEJIgaXtz4xpNo/vojRT2smvUMYCpQ1AaVk0AbAffTdwvJeT+03WblZ8mF16Fox72yYptGkxNQ49+85B78PWs/Vaguus/hfw/wFQmQQN4QYIJe3mx1bgaq5wS92I6YuvdC+XWzt21O5y/btfIgVK13zknvMUFPLda0I40AE/Sk8eNq9QjUzBIqENTVKGqwaubTQIFZURvxlNfddxMiG9bEm0o5xqSNlIgokIsEhIRWz+uPZdye0rr/UXCceGHWyaze2AhfICzJjx2FBIguQiIEr+wRcD91B0KLflHUAdfV02DuNVBRG/mkvPNn1XRil/pAjgl6f9MWk1j4t3THV50r+Hec5Z1UAptr/ajzNEtSM6i3E5ZCkyQdXCyNgJh/b6RZABxnXAbrngdJVZNT61s9daidNlaWmGJJdbE2isayrmj68EUEPn5Tkl7nSOFA2jD1D6RJcloji+sfnIjw6uWivEk3KV6UUgptI+BuDGJjjU8SjV5VxXDaLZJ0cLF2Cbgfm4bQ0oWKOWis6IqK8fcrpp+KSaA9AS0k59lPPB+2/Y9p7xZfa4hAa2M9aqdeoQmPrAccA8cJ52vCFzpBAiSgLgEm6KnLm9ZkJqD3BL0YDtvRp8N+6Cno/NCDCXoyv1mojgRkIsAEPZlAUo2iBKIBL2puu0RRG6be/VF+lbItChMF0PTWfAS++iDRtKhxx5mXwzpiP1aTEUWLQnol0NrkRqyqk/+95K0cU8VXcuG1wunff6QSU3y+xh3AlvqAJDsDhBaCVqGVIK/sEaiZerniLez4oFe+/Q0u+RWex2dlpLBo38OE1qqjMlrbtkhMwky6+y0m0S1dnWpU0IsGA6iZcHEbmrR/phtT2gbyeEGjrwXrNnslEehRWQxXCRMgJEGUuNj9yFSEli+SqCX58oqb79+WPJZcKr9mm97+PwS+/LekoAt33lN4wHkBjM6OrTjr501CeNVSSbqzdShNktMaWOz76l343no2pSe2Y4TvxQ85JaUcBTIj0BJqxbK10lpHlzmL0L3ClpkDXKV5ArXC4d5WBQ/3moePgOui8ZrnQAf1TyDd9upKRMzqu0pQlV+nVqromYfvJvz7eKP8AVIjCZCA5gkwQU/zW0QHkxHQW4JeLOkuvHLJdiG5rp4O9/23dhhngl4HHLwhAc0QYIKeZraCjiQhEFz6GzyPzUwiIX0qmxW1gssWwPOoPMmBBf2HwFjVEwVde8LgKEVrQy1M3fpKBySThi5dDOhSUIAuRTYYbXYYbA6ZNFNNJgRamxoQ9XuxtaUZW8NhbN0aTa6mrVLbVkFM6aJtQpW8rUE/ol4PwjUbEfz2P8l9S2O26g7h4Zox+1V9fIEQVm9sSsPz7UW7CQ+XyoWHTLyyQyD231Dt7Zcratw8eEe4Lp2gqI18Ut4gtAhqybBFUNm1M1HQo58kXEzQ64jP88pDQjXULzoOirxzXT4R5gHDRUpTLB0CkUgUi1e701mynWwsOS+WpMcrewRqJo0S/s6TVmkqlfdMlO1EqDWC6vHS2si2HXzupHnbbbh6Hervkvbgk22J45FNPRbesgH1s8elFIx9J27uNSClHAUyJ/D78rrMFwsrrRYTBvRyStLBxdolUH3j2UA0xfcaEtxnwpIEeFwqmoAaVfpTOWPZfV84z7oylRjnNUCg1V2D2hlXZd0TU1UPlI+7O+t+0AESIAH1CTBBT33mtCgjAb0l6MW+NIpd/n+/3IGCwelC1NPxy1wm6HVAxBsS0AwBJuhpZivoSBIC3s/elFwxK4n6bVMl512Fol3+mUpMsfmaGWMRdUv7olkx55RUbCqA0VUGY0U3IZGw97aHGea+Q5m4JzPz1vpqtKxZJrRSXolI9QZE6jYj2hCrPBDLtMuvy7LbP+E8O/tfXMWoR6NbsWhlvaQNcDos6NWVCRCSIEpYHFz8EzxPzJagIfVS2xEnw37EGakFKZGSQKtHaP8yLbP2L+aBO8B12W0pbaQSYIJeR0KhtcvgnpMZVz406shS7jupCRBFQnvbgUKbW17ZIRA7pFM7XdmHqmahypvr/OuzE6BGrfq//xTelx/L2LviE89D8f7HJl3v/+/78L75dFKZVJPbqq/vcWAqMc53IlA9/hxAOESU8BIOo1XNfj7hNCfkIbBmUxO8/lDGygzCobPhA8syXs+F2iWgxu8+++mXwrbXIdqFQM/0TUD4HeN+cqaibZrFADIPHi4cEpwoRpQyGiHgeWkegj98mVVvDIUWVE6fn1UfaJwESCA7BJiglx3utCoTAT0m6MXa2dbdcwMim9YnpcAEvaR4OEkCWSPABL2soafhNAh4nrsfwV++TWNF+qIVEx+EsSR7X9LG+xsg/ShyZ4WpRx+Yh+wMy457wtx7cO4EpmIkscSh4KIfhdZmCxGtr1XRsrZNaa3ikvQECKOQAFGqbeg57J0a/3Y7R42HZeiIHKaoXmhNH76EwMdvZGSw5OwrULTb/hmtbb+ICXrtafz5unrcmdsPihypnPwIDMUlIqUplg6BWIvbWKvbTK9Y0d0dB3Zsz5mpLq5Ln0Bw0ffwPHVP+gvTWFF8/NkoPvCENFbkvqj78RkILVmQUaDWA4+B4/jzRa11P30XQgt+FCWbSKhiwtztWugmkuX4nwRqbhuJaMCfEAcfTCdEI+tEjTuALfUBSToH9ylFodkoSQcXa49Ay4pFaHh4qqKOua6YDHO/oYraoPL8JBBt9qPhyTsQXr0sqwBMPXqjbMwUdClkp4asbkSaxsPCgez6+zp2tUtThSzilVMe5aF7WUhSCQnoiwAT9PS1X/S2E4F4D3jEtIuIt855yc2wDNmlkwUgXpvARLLtF8db19Z2IVZCt/7uGxFtCbZf0uE1E/Q64OANCWiGABP0NLMVdCQJgbq7xm2r+pVERPKUmN+3ko0kUxAJo2bqmG3tRpOJ5eOcsbIbLLvtB6twStkotO3llZhA7AuZwA+fo/nrjxML5fGMedgucI28WVME1m/xwdOU+G9oMc7GEiDaug+LkaeMfAQanrkXLb99J5/COJoqb38MBqs9zgyH0iUgJRFMrr8TmKC3/a75v/+PUHHq0e0nRIzYjjkd9kNOESFJkXQJ1DY0o7oucSKKGH2DhAp6FqGSHi/1CXg/fhX+D19V1LBrzCSY+w9T1IaulMfa294kJNhtjWbkdjq/Z6LeRtRMGZ2RnbZF5h12hevim9pu+VMEgZrJlyDq8yaUNBRZUTn1yYTznJCHQKx6XqyKnpSrd5UdJfZCKSq4VoMEAj9+jqYXH1bUs4rbHha+l2KFYEUh56Hy1kY3Gp66Q+h6sTbr0Vfccr/Q6aRr1v2gA+kTcD82Xai++Hv6C2VcUXbNdBT0HCCjRqoiARLQAwEm6Olhl+hjQgJN7zyNwBfvd5gX8wVNOgl66ci2dyRZgl5Mzv/Nh/C+/lT7JR1eM0GvAw7ekIBmCDBBTzNbQUeSEKi+8exYL8gkEtKmzMNHwHXReGlKZFjt//oDeN+YL4Om3FVh2X0/2PY/mh/2O21xrEpK4L8fCtXyFnWa4W17Alr8oqje04xNtUyAaL9Penpdd9f1QgL5RkVdFvN5UFEHckR5869fo/HZORlFYz30RDiOPiujtZ0XMUGvM5E/77WQPBnfs/wd9QVCWL1RWgJELyEBwskEiKy8iRqeuUdIIP9eUdtVM4U2qwVmRW3oSXm8703F+u8ceSMs/4+984Bvonzj+I+0TTOaNE0HZW8QQRRRnKigoqKgoiKK4kBFUXGCgrgQXLgVB4ri3ooLFzhRHIiCDBllj9KRpk2Tpkka/u/Vf7GlSXp57y65uzz3+fBJcvc+4/2+IU3ufvc8vQ8WO7x+nJS/aw2BqApiAwlxjyV3X4GwJ/rnosFiRcH0ueKc0ShuAqFQGGs2ubjtBcN8pwWFuRZJPshYfQQ8C5k4/QvlxOmtjJlofe/L6ps4ZaRpAsHd2+Ce9xDqSncnfR7O62bA2KF70vOgBPgI1Kz8FZXzHuUzlskq++IbYe47UCZv5IYIEAGtECCBnlZWKoXzFKrNCT8WLEecxL7sNFWSR2oVK+aCTKSTQNFaI5Q/cxeCRf80WQGpFfQanLnmzUJg5R8NL5s8kkCvCQ56QQRUQ4AEeqpZCkokCgHhREX5rElRjsqz2zp0JGxDR8njTKKXWH9LJbrWlbnpoMNgPX4kMtp00tW84p2Mf/VSVH8zH6HNG+I1TbnxYr5TJwOKtyaIjdsrJYUmAYQkfJKMiyePYQLyOkk+Yhln9jsUOWNvijWEjokk4JpzDwLr+ETM+bc9gbScApGRYg8jgV5kPpFuVow8svlexyU3wtSHLgI0JyNtT13dHqzeWC7JCQkgJOGTZJwSFcglEZLf2LPwfSYMeTdux+mduyPvmhlx2wkG7vfnwL/kGy7bBiM13sDSkJvaHsseuyVmdaP01u2QN+lhtaWty3z+Xl8maV42qxGd29ol+SBj9RGQ4zMx1qyE7g75k5MrfomVHx3THoHApn/gfuWRmOLvRM1KzDXiROVCcfgJlN4/EXVlJfwOJFrazrgI1qNPkeiFzIkAEdAaARLoaW3FUixfoXpdzTcf17eCNWSaYD31PKTlFtZTCKw0FbreAABAAElEQVRb3qx6XnrbDsi7cVaLlATRX+m9E5uNE1rQNi4n61vyVTMBnZBHwcx5zWz33RFJBNjQ4rZhbLjGi7IZV0dsdUsCvQZK9EgE1EWABHrqWg/KpjmBmhVLUPnK480PyLhHTRd2w34fXE9OQ2j3ThlnqF9XlkEnw34qE8ikZ+h3khFmFizZDs+CN9j3umURjtKufQmYDjocjguu33e3Kl6Hw3uwqkiaAKKAVYBoTRUgEr6eoZIdKHtQWfGc9ZRzYDv+rITPTW8Bg7u2oPxhvkq5xr4D4LxYvhsFSKAX+d0l5f8TtWmMzFSOvVIFEPasTHRqY5MjFfIRJ4HiWy4AWMtVpTZTf/bdaow6v1spNeeW/LpfexT+v+Jve287k13IPIrzQuaePSieJL3Cq1pvZGmJeaKP16z4mZ2beCJqWPu542E5dHDU43RAPgKbdlSi2hfkdpiZkYaenXO47clQnQRcrEVoYNWfiiVn7NkHzituV8w/OU4tAv5Vv8P9kjpE3dljJ8Lc78jUWgCdztaziN0w8nn8N4zIhcMyZDjsw9h5etqIABFIKQIk0Eup5dbOZOuFaw9PQtgdX/n1fQVwsWYcqTJerPENx0wDj4Fj1ISGl1EfxQj0BONI44T9JNATKNBGBNRHgAR66lsTyqgpgUT8sJSzMk7T7PleCeKrijn3xv29gS+a9q0MDidsIy5ImZNJnm8+hHfB29pfuATNwNjrADgvvy1B0fjCkACCj1uyrYTW0u6XHlE0Dce4Sazl3QBFY6SC88r5L6GGtQHn2XjaDsaKQwK96HRcc+9DYM3y6ANiHMm79VGk57WJMYIO8RDYvLMKHm+Ax7TeJtPIBBCdSADBDZDTsK68GKX3KSuesw47F7YhZ3JmqE+zslk3ct1klT/lcXbzdmtuKLXrV6LiOb4KfA1BLYNPYzc9MVEnbS0ScL81G/6lPzYbp+Ybgpolq4MdxWVelFbUSJpJ3+55aNVKkgsyVhmBssenILRtk2JZib2OplgC5Fg3BLy/LoLn3edVMR/bqCtgHThEFblQEtIJ1FVVoHT6VdIdcXowHToIjnOv5rQmMyJABLRKgAR6Wl25FMhbqJ7n/fwd0TMVLjbn3TQLBrNVlI1QRa/84ckRq9dFcyBUz8ubNltUjEjCu2gCwkjtaUigF20VaD8RSC4BEugllz9Fb5mA+62n2AnwxS0PlDBCjRUDgru3w/3yI6groUp6YpfWdOTxcIy8XOxwTY5zPcdaNK7na9GoyQlLTFruylcS04lqLlUAYWICiB4kgIjKV6kD1d99hOpP31TKfb3f/NueZK1V8xWNoXvn4TCKJ5/PPU25vyOQQC/6UtT8/QsqX34s+oAYRyzHnQr7aRfGGEGHeAjIIYA4oEceT2iykUDAv2YZ3HMflOChZVMSkDdnVDL1IoQDtc0PxNgjtqtJDBf1h6q+fAu+r+e3NCzmcce4W9hNAf1jjqGD/xIIbPgb1Yvmwzn+drievRvW40Ygcz9il8j3R0WVH9t3V0sKKQjIBSE5bfohUDJzAsIV8RXIiGf2lhPOgP3k0fGY0Fgi0IyAZyGrcPZF8iqcNU7IdvqFsA46tfEueq4DAq55Dyat44pxv35wXjZVBxRpCkSACMRDgAR68dCisQkn4H7nafh/+6HFuII4z3HRTTB26Nbi2MYDAtuK4H72HlEivXhjxCPQE3Iqe2QSQju37U2PBHp7UdATIqAqAiTQU9VyUDIRCJQ9xdq9bt4Q4Yg8u9I7dkXexHvlcSazF6HdrfudZxBY8bvMnvXrTljP7NETkFHQXleTrPn7VyZaeFRXc1J6MpbjR8B+Cr8oR+n8GvvfxSpAlEmoANGKlX7o2z23sUt6ngAC7veehf+X7xSNJLc4TNFkVercu+QreN5/kSu7rOHnI+vYEVy20YxIoBeNzL/7i2/mv+hJ/19is+U5KocAohdrIWhkrQRpSxwB74+fwfPRq4oGJAF5c7zFNwutZvc0PxBjj8GahYK7X4gxQvyh8qfvRHDjWvEGEUYW3vcKa4FijHCEdhEBdRGo8QexYVulpKSEFuxCK3ba9ENgNxNK74lTKB3P7G0jL4H1yJPiMaGxRKAJAfcHz8P/86Im+5L1gqohJ4u88nFrVixB5SuPKx8oQoT0Dp2Rd939EY7QLiJABPRMgAR6el5dncyt5q+f4Pn09Yht64Q7J40HDoR9+EWiqtpFQiK006365GUElv8WUagnxDAPGVH/Y0JsdT4hTrwCvX3FgiTQi7RatI8IJJ8ACfSSvwaUQWwCJXePR9gj7cRrrAimQ46GY/Q1sYYk/ZgUcUHSk09SAnqq6pGIKl1JWiZFwqa364SsU8fA1LOfIv6VcOqq9GNHibQKEL27OJGeblAiPfIZhYDruemsouXqKEel76YTm9IZCh6kCL4K7pnL/bs8WvYk0ItG5t/9UipK2M+9EpZDj4sdgI7GRcDHBBBFEgUQXdrakWUlwU9c4CUOrpz/Imvr/ZVEL7HNSRDbnA/P3xuDxYqC6XObO+PYEyzeivKHJnNY/mdiOvQY1pZswn876BkRUCmBcHgPVhWVS8quTZ4VeTlmST7IWEUEggEUTxmraELZF98Ac9/DFI1BznVKIFgL12uPIbDqT1VM0HLimbCfdK4qcqEklCHA871UjkwMzjwUTH1KDlfkgwgQAQ0RIIGehhYr1VMVWtIGS3chuL0I6bmt0cqcBVOvA2XFIojkwr7q+hgZ7bvBYMmKuyqfrAmlkLMzPlPHnTAphJymykmABHqc4MgsMQRCQRTfqmy7smjt2hMzQfFR9vhr4Fn0PnzffireKMVH2s8dzy7UD9Y0hapPXoHv+wWankMik7edeTGsR52cyJCyxPLWBLFxuzQhctf22bCaM2TJh5yII1By30SEy0vEDeYYZep/BBxjruOwJJMGAoGNa+B6+u6Gl3E9mgYykcIo+UUKJNCLvQx1VW6UTr8y9qAoRzO69ETu1dOjHKXdPATq6vZg9UZpAoi2BVbkZpMAgoc/r43rpQcUvQCc3rYD8m6cxZuebu14LoTKWUFPAOtdvACe+awKnoTNPvoqWA45VoIHMiUCiSHwzyYXgqEwdzDhb5PwN4o2fRCoqyxH6T1XKzoZ59V3wdhlP0VjkHP9EQju3o7yWTerZmKWIcNhHzZGNflQIsoQcL8/B/4l3yjjPIZXg8mMghkvxRhBh4gAEdAjARLo6XFVaU5EQIMErv/tLw1mTSmnIoHHBh6UitOmOWuEQKh0B8oeuEnRbLPHXgdzvyMUjSGrcyZa9P66CDV/Lla09a+sOSfRmZZbkKip9UUSl7DF0Ma+A2A+5BhN38keYheW1rALTFK2Dq2z4LCbpLgg2zgJFN/CTmrX1cVpJX64dehI2IaOEm9AI5sRcL/1FPxLFzfbL2aH85q7YezcS8zQuMaQQK9lXO7XH4f/zyUtD4wwwjnxHhg79ohwhHbxEhAEeoJQj3fLZ9WJClmVItoSR6Ds4ZsR2rVdsYDGfofCOVbZ32iKJa+gYy6BngJVRlyvPITAiqWSZpo/7SmkOfIk+SBjIqA0gY3b3fDWhLjD2Fh1186syitt+iAQ3LUF5Q/fouhk8m55BOn5bRWNQc71RcC/eincLz6kmklZjh3GurcpW2lSNZNN8URq169ExXMzkkKhcNabQKtWSYlNQYkAEUgOARLoJYc7RSUCRIAIEAEiQASIgOwEIrVXlztI7o33IaNtF7ndJsRfXUUp/OtWILhlLfy//ZCQmFoMYjv7MlgPP0FTqVd+OBc1P32tqZwTmazpyOOR2a0PzL0PBoz6EKWt2lCO8B5+AUTrXAsKnJZELkNKx6qrqmBVvq5SlIH9vAmwDDhG0Rh6dh72VqHkziu4p6hU+0bvz1/C80H0O8p5WhtX//AJqj9+PeZc451PoGgVXM/cE9WnIdOEgpnzoh6XckDKxQTT4YPhOHu8lPBkuw+BDVvdqKnlF0A4bJnoUGjbxyu9VJJAyR3jWDcNr2IhLINPg/3UCxTzr1XHPAK99I5dkTfxXlmnHPZUouRuaZ+Dxv0PgvPSW2XNi5wRAbkJbNtdDXeVn9utyZiGHp1yuO3JUF0EAkWr2XdXZSspF9z9PAxW+k6jrpVXbzbVP36K6o9eU02ClkEnw376xarJhxJRngDPd1M5siqYzj4rLfRZKQdL8kEEtEKABHpaWSnKkwgQASJABIgAESACLRDw/vYNPO/MaWGUtMMFM16EwaR9UYvvjx9Q9ebTccPIPv9qmA8eFLcdj4H3xwUIB2uxx+9DuLoS4YpyhEp3IeyWVjlMTC6OcZNg6j1AzNCkj6n6/E34Fn2keB5pBW2QllcIg8NZf5K5FRO6tTIYlIkbQXjmX/ErQls3xh0v//bZSMvOjdtO7Qbrt1TAH+CvxubMNqFdQZbap6mb/AJb18P1xO2KzkepCm6KJq0i555v58P72VtcGdnOYcLuw5QRdgt//0pmXAOwiriRtqwRY5B1zPBIh6LuU0KgJwQrffBG1JXsjBjXdMQQOM7iF0BGdNpop5SLCa1nzkMrJiCkTR4CW3Z5UFVdy+3MYkpHtw4ObnsyjJNAoBbFUy+K0yi+4bazxsF6xInxGaXAaJ7PLWOP/eEcf4fsdGr++gmVrz0pyW/W8PORdewIST7ImAgoSWB3uQ8lLh93iDRDK+zfTX+/K7mBaNwwEZXKqCqUxt8kCUxfbR0xzEefhOwzLkkgAQqlBgKVH77Abv5emPBU8qc+gTRnQcLjUkAiQASSR4AEesljT5GJABEgAkSACBABIiArAc/X78L75fuy+mzszGCxomD63Ma7NPtcCwK9aHAFsULtpjWoXbsc/l++jTZM8n4ttCNpqbKSFAjpbdrD2Ls/Mnv0Q6bQtjHDKMWdZFv3u8/C/+t3cfvRq0Bv045KVPsiC3bEQKIWTWIoyTem5u9fUfnyo/I5jOAp/45nkGanqh4R0IjaxSOUaHAcb7W5Brt4HiPlZ+p/BBxjrovHTf1YpQR6gvNIeWZ06Yncq5WtUOJd/Dk881+Om4VgkHX6BcgadBqXLRk1J7CrzIuyiprmB0TuMaYb0KuLU+RoGiaVQKhsF8ruv0Gqm5j2jsunwNTrwJhjUvFgpM/LljgoJdAT4rrfnwP/km9aSiHmceuwUbANGRlzDB0kAskiUMGq521nVfSkbH2YQM/AhHq0aZ9AzbIfUfnGbMUmYjBmouBevu+miiVFjlVHoK6yHJVvPoXAhjWqyc0y6CRWOY/EeapZkAQm4l+3HO459yUw4r+hcm+6HxltOic8LgUkAkQgeQRIoJc89hSZCBABIkAEiAARIAKyEpDjokKshATBUt5ND8UaopljWhbo7QtZuPPZx6onBlYu2/eQ5NeFs94AKxMn2Y8SDmo3rELFs9HbCfLGTG/dFvbRE2Ds0J3XhSJ2JNBrilW4uCRcZOLdzJlp6N6RxFy8/OK18/7ExEMfKniBJi0NhQ/Eblkab86pNN6/+ne4X3yYa8qWY06BfYSy1aeExII7NsH760LUFW9HK0sWTH0PheWQ47hyVlKgV1fpgnfxAoS2FdULu409D0iM+I1VGCy+9UIuHoJRIkSW3MlpzLDMXYNdpfztUlsx3UPf7nkam7V2001Ei7+8yQ8jvaCddiEplLnaBHpgFayLJ50nebamI0+AY+Rlkv2QAyIgN4FqXwCbdlRJctuLtbg1sla3tGmfgHfJ1/C8r9wNuAZbNgrufE77oGgGihHw//MX3C/cr5h/HseJ+m3LkxvZJIYAz/dTqZlRNwipBMmeCGiPAAn0tLdmlDERIAJEgAgQASJABCIScM17UBGRVkMw43794LxsasNLTT/qSaDXsBDBHRtR/c1HqF3+a8MuyY+mgw6D4wJlq4rwJin3SRPLcaci67gRMGRl86akqB0J9JrildqiKT3NgN5dqUJRU6rKvar6grWiXviRYgEMOU4U3BZ/23LFEtKYY9dL7PvDKj6Rd+6kWcho3UFTM1ZSoJdMEFJaQ1GFL/lWrpK1t93K2txK2fbvmou0NKbUo01xAnK0Nm0pycJ75wFGaiO9Lyee7/JKVtAT8qtdvxIVz83YN9W4Xxv79IfzwhuB9Iy4bcmACChFoDZQh3VbKiS579o+G1Yzva8lQVSJsZjvw1JSTcsrQP6tT0hxQbY6JlD93Ueo/vRNVc3QMvg02E+9QFU5UTKJJ+B+7VH4/5LvvLqYGTiuYNW2e1K1bTGsaAwR0AsBEujpZSVpHkSACBABIkAEiEDKEyh7ahpCmzcoxsE08Bg4Rk1QzH8iHetRoNfAz89a31YveB2hHVsbdkl6tJ0xFtajh0nyIbex+80n4f/jJ1ncGvsdAvuwMUjPayOLP6WckECvKVlXpR87SqS1aDqgB1UoakpVuVfu91iL5l++UyxAeqduyLt2pmL+9ey4rrwYpfddzzVF434HMOH+bVy2yTQSc0FSixXlBKF++aN8N1JkHjgQOYKYhDbJBHw1QRRtr5TkpyerUJRJFYokMRRr7P3xM3g+elXs8LjHGUxmFMx4KW67VDBQo0BP4F715VvwfT1fliXIn/IY0nILZfFFToiAVALh8B6sKiqX5KZjoQ3ZtkxJPshYHQQ8i96H9/N3FUtGTx04FIOUio5DIbjfmQ3/siWqmr3lhDNgP3m0qnKiZJJDwPf7t6h6O7HVPx2X3ARTn0OTM2GKSgSIQFIIkEAvKdgpKBEgAkSACBABIkAE5CdQ+sB1qCvdLb/j/3u0nHA6O2Ehve2PYgnG4VjPAr0GDFWfvgrfd581vOR/ZK0j81lrLrVcXKpZ9iMq35jNP58Gy7R02EZeDOthJzTsUfUjCfSaLk8Vq1C0RXKFIierUKTOFs5NZ6v9V655s1iF1z8Um4ix78FwXjxZMf96dly14DX4vvmUa4rZY6+Dud8RXLbJNNKrQE9gWv7M3QgWreHCm3/700jLpsqiXPAaGQWCdVi7mSoUNUKi6qdKV3hNy2+N/FseVzWDZCWnVoGewKP86TsR3LhWFjQ5V96OzO59ZPFFToiAVAIrN5Szbs57uN20zbci12HmtidD9RCo+oKJkRfKI0aONKv0jl2RN/HeSIdoX4oSCGxei6p3n0No905VEbCeMgq240eqKidKJnkE6qoqUDr9qoQmkH3htTAfeFRCY1IwIkAEkkuABHrJ5U/RiQARIAJEgAgQASIgG4GSOy9D2CutolSsZNRYSS1WvrGOpYJAT5h/zfKfUPnqk7FQiDpm7DuAiV8miRqr6KC6EErum4iw2yUpjHA3d/Z51yCjbWdJfhJpTAK9prR9flahaBtVKGpKRb2vymffgeCmdYolaDp8MBxnj1fMv54d8wgkGnhoscqckLueBXq+ZT+g6g2+ds/WoSNhGzqqYXnpkZOALBWK2rAKRVlUoYhzCeIyc38wB/6fv4nLJp7BGV16IPfqe+IxSZmxPH9/lG5x2wA/WLwV5Q/JJ/y3nzcBlgHHNLinRyKQNAL/bHIhGApzx2+da0GB08JtT4bqIVD1GbtJ51u+m3TEzCKjay/kTrhbzFAakwIElK5YzIsw6/QLkDXoNF5zstMpgbKHb0Zo1/aEzS6bfU800/fEhPGmQERADQRIoKeGVaAciAARIAJEgAgQASIgA4HiSecDe/hPtraUQvYF7I6ug/RxR1eqCPSENQ1sXQ/XE7e3tLwtHs+++AaY+x7W4jglB8hRFdDYsw9yLpqEVpkmJVOV3TcJ9JoilaNCUbf22bCYM5o6pleKECh76CaEinco4ltwqqcKr4pBiuDY98f3qHrzmQhHWt5lPeks2E48p+WBKhyhZ4GegJtH9NKwTFoVXTbkr5bHlRvKWIUi/mzaFWTBma2t7yn8s02uZcWrj6J2+a+KJUEVXqOj5fmsSpRAT8jau3gBPPNfiT6BOI9Yh50L25Az47Si4URAXgIbtlagpraO26lQPU+ookeb9glUffwyfD98rthEjD36wDle+nkoxRIkxwkhsKe2BpXvsZsh/lRXS1th8rZzLtNMR42ELBYF2Uugcv6LqFn81d7XSj+xnT4W1kHDlA5D/okAEVARARLoqWgxKBUiQASIABEgAkSACPAS2OOvwe5pl/Cai7JzXDEVpp79RI1V+6BUEugJa1G7YRUqnpVWvSO9XSfk3fBA0pa2zlWC0nsnSopv7H0gnOOmSPKRLGMS6DUlX1e3B6s3ljfdGeerzm3tsFmNcVrRcB4CJfdchXCltJaPseLSne+x6EQ/JqWFX/4dzyDNnhPduYqP6F2gV/X5G/At+phrBai9Dhe2ZkZSKxQV5lmRn0MtBJuBVWCH6/kZCKxdqYDnf12aBh4Dx6gJivnXsmO1C/QEtq5XHkJgxVLZMJuPOgHZZ14mm79YjoQWbcLvp3q1sKEVWqWlAxlGGIwmdqOSGQZLVixzOqZTApt2VKLaF+SencNuQofW9N7hBqgiQ6UFKMZeB8B5+W0qmjGlkmgC/n/+QtWHcxEuL0106Bbj0W+eFhGl9ICav39B5cuPJYyB+ZhTkD3iooTFo0BEgAgknwAJ9JK/BpQBESACRIAIEAEiQAQkE6irLEfpPVdL9hPLQe71M5HRvlusIZo5lmoCPWFhgjs3ofwRaeI0++irYDnkWNHrHCrbxdrRlqPOV4U9gQDQil0cYheF0rKykZaThzRHnmhf7vfZXbdL+FuQab3FCgn0mr9V/l5f1nxnHHs6FNrgsFELwTiQcQ8tYQLyMBOSK7XZR1/JPpuOU8q9Lv0Gtxeh/DG+i2amgw6H44LrNctF7wK9OtduJmi/jmt9jL36soup07hsyeg/Auu3VMAf4K9QlM/aBxayNoK0KU+g7MnbENpSpFggy7HDYB8+VjH/WnasBYFe2OdByR2Xy4q5vqriBTcA6cpUcfYtZdVx3xJXHddgtqJVVhYMNgfSsp0wOPORlluIjPy2SG/dnkR8sq68Opxt3eVBZXUtdzLCzU3CTU60aZ9AJRNO1fz0tWITMfbux26OnKqYf3KsbgJSbhhScmYG1knDPvYGmHodqGQY8q1xAuHqKpTcdUXCZmE65Gg4Rl+TsHgUKPEEqr54K2ZQ+8mjYx6P52AiY8WTF41tSoAEek150CsiQASIABEgAkSACGiSQHD3NpTPmqRo7vlTHmcn7FsrGiNRzlNRoCew9a/5E+65/FXw0tt1ZFX0Hoy6TP41y1gVkuUIbFmL0M5tQF3si9PCybE0Vpkvo2tvmPbrD2PnXhF9SxWgGpy5yLv2XnbxKTuify3sJIFe81VaVVSOcJi/hyC1EGzOVKk9Srdgd1xyE0x9DlUqfV36lSJ61npFXb0L9IQ3rGveLARW/sH13s29+UFkFHbksiWjfwkUbXPD5w9x46AWgtzo4jYsm3UjQrt3xm0n1sB68jmwnXCW2OEpNU4LAj1hQeS4ySnSwuZPeaxeDBfpGO8+91tPwb90Ma95MzsDE+0Jv/8yOnT7t619kN1wxarw0aZdAtt3V6Oiys89gSxzOrq0d3Dbk6F6CFR++AIT6C1ULCEtdy9QDEoKOA7u3IzKD+YitHm96mZryMmFY+yNMLK/abQRgZYIlD54A+pKdrU0TJbjWr8BUhYIOnYS9rhRcveVMWdo7L4/nFfeEXNMSwdDpTtR9sCNLQ1D4UOxxYItOqABshAggZ4sGMkJESACRIAIEAEiQASSSyCwdT1cT9yuaBIFd82BIUsfd0unqkBPeINUf/cRqj99k/u94hg3CabeA/baB4u3wrfka9T++TPCPu/e/TxP0vIKYBowCNbDhzYR01UteB2+bz7hcVlv4xg/DaYefbnt1WBIAr3mq0AtBJszUeWeQC2KpyrbriPnytuR2b2PKqevyqSCbE2m8K+J1k/opYJAz7/mDybIn8X19rMMOgn20y/hsiWjfwlIbSGYw1oItqcWggl5O5XMvBrhinLFYtnOGAvr0cMU869lx1oR6AmMQ2XFKLtf/sqxzqtuh7GbPN9fpAjv43kfpXfuDmOPA1j1oYOi3lwVjz8am1gCu0q9KHPzV7U2Z6aje0cS6CV21ZSJRgI9Zbimstfq7z9B9SevqxJBeofOyBl7E+vkka/K/Cgp9RFwvz0b/t9/TEhipkMGsQp6ynZFSshEKEhEAmIEeoKh7axLYT1iaEQfYnaKvUlT6+fzxLDQwhgS6GlhlShHIkAEiAARIAJEgAi0QCCwYSVcz85oYZS0w4X3v6pYKx5pmcVvncoCPYGWa+59CKxZHj84ZlHfluniyQju2gLvog/g/+tXLj8tGVkGnYwsVnHEYLWxO82uQNhT1ZJJxOPWoSNhGzoq4jEt7SSBXvPVWsdaCNZKaCHYmrUPLGBtBGlTlkAi2oM4r5vB7oTvruxEdOTd++MCeD56hWtGttOZ2GSQtsUmqSDQExaXR/zS8KYonMWE/KwtPW18BLawFoJVEloI2rMy0amNjS84WcVFoOSuyxGu9sRlE89g+7njYTl0cDwmKTOW5zPK2INVlxgvrboEN+BQAK5XH0Vg1Z/cLiIZZp8/AeaDj4l0SPS+2vUrUfGcsucCIiVjsDtg7HMwTAccDlPPfpGG0D6VEdhd7kOJy8edlcmYhh6dcrjtyVA9BEigp5610HomodIdqJo/j3XT+FuVU6mv5sjEeVQBVpXLo9qkvD9/Cc8HLyUkP8vR7Aa5M+gGuYTATkIQsQI9IbWCe+bCYLbGnWXNXz+h8rUnRdmRQE8UJsUHkUBPccQUgAgQASJABIgAESACyhMQWou650ZvPSpHBnr6Ap/qAj3hBFrZA+wEFedmOvJ4+H9exGkt3kxogWvsdyj3XYvprH1u3g38LX3FZ6r8SBLoNWe8YWsFampjt1FubvXfnvwcMwrz4j/x8Z8HeiaGQJ27DKUzrhEzlHtM7qSHkNG6Pbd9qhnyiCIaGBXe9zK7uJHZ8FKTj6ki0JNSMdd29jhWzfZETa6vGpLeVuyB21PLnYrNakTntvqoWs0NIUGGJazCa5hVelVqy77wWpgPPEop95r2y/O3KKkCvf/Tdn/wvOy/g6zDzoVtyJnc6+l+4wn4l/3MbS+HocGZB1P/o2AdOFj21r1y5Ec+/iVQWlGD4jL+qvfGDAN6dXYSTh0QIIGeDhZRBVMQ87sqmWmaDjsWjnOuSmYKFFujBILbi1D+2G0JyT7r1POQNfj0hMSiIIknEI9Az3TEYDjOGh93kvH8rtLT9b24QanIgAR6KloMSoUIEAEiQASIABEgArwEav7+BZUvP8ZrLspOT1/gU12gJyx41edvwrfoI1Frr9VB+7bj1eo8hLxJoNd89Yq2ueHzh5ofELkn12FG23wS6InExT0sVLaLtYW7gdtejGH+bU+wdjUFYoam/Bj/uhVwz7mXi4PpiCHsZOEVXLZqMhJTQVAP33nCvmqU3HEZN3o9MOCevETDHSXVcFX6ub1kWTLQpV02tz0ZiidQfMsYoI5f7N9SJMelN8O0/yEtDUvJ4/FcSGoApAaBnpCLh1UR937+TkNasjyajzoB2WfyfWbzsJQl6ShOjH0HwHLkSVRVLwqfZO4W2tsKbW55t/R0A3p3IYEeLz812ZFAT02rob1cgjs3wfPJqwisX63a5K1Dz2TdNM5VbX6UmPoJJOr7lfWUUbAdP1L9QChDLgLxCPSEAM4rp8HYva/oWFWfvQbft5+KHk/neUSjUnQgCfQUxUvOiQARIAJEgAgQASKQGAI1fy5G5etPKRpMT1/gSaDH3irBAIqnjFX0PZNM58ZeB8B5eWLudkzEPEmg15zypu2VqK4JNj8gco8z24R2BVkiR9MwXgLB4q0of2gyr7kou/w7nkGandptiYHlfu0x1pr8FzFDm43JvX4mMtp3a7ZfazsCRavgeuaeqGmnd+yKvIl8IsaoTpN0wP3206wK7Q9c0Z1X3wVjl/24bFPdaCcTP5QzEQTvZjWno2t7B6852cVBQOkLb47Lp8DU68A4MkqdoTzs1SLQE1bJt/R7VL31jKwLZux7MJwX3gikpcfll4dlXAE4B2d07QXrccNJpMrJTwkzQTwuiMh5t7S0Vti/ay6vOdmpiAAJ9FS0GBpLxfPVO/B+9YGqs7aNuoJVdB2i6hwpOfUTKHt0MkI7tiqeqPWks2A78RzF41CA5BCIV6AnZCn2Glxw+0ZW6XFqXBMT6zsupzQ4bgIk0IsbGRkQASJABIgAESACREB9BHx/sAsEb8p7gWDfWerpCzwJ9P5d3aov3oJv4fx9l1oXrx2X3QrTfgfpYi7CJEig13wpN+1gAj0fv0Avx25C+9Yk0GtOVt49wR2bUP7oFHmd7uOt4O45MFipHeQ+WJq9rKuqQOl0vhY/wkX23Al3N/Op1R2u5+5hFR9WRUw/+/wJMB98TMRjWtsZ2PQPXLPv4krbdMggOEZfzWWb6kZCdSKhShHvZjGlo1sHEujx8hNtF65D8WRWQU/BLefK25HZvY+CEbTrmkdUpiaBnkA+sGElXM/OkH0R8qc8ztrEthbtl4elaOcyDDT27IOsE86GsWtvGbyRCykEKqr82L6bX6BnMLRCn24k0JOyBmqxJYGeWlZCO3n4//kT7hceUH3CjvG3wdTjANXnSQmqn4D7rdnwL/1R8UQtJ5wB+8mjFY9DAZJDgEeglzV8DLKOHd5iwq457LzWusjntaIZ6+n6XrQ5amE/CfS0sEqUIxEgAkSACBABIkAEWiDg+/1bVL39XAujpB3W0xd4Euj9+16QItaQ9m5S3lpP71eBFgn0mr9nNu+sgscbaH5A5B4S6IkEJXFYYNsGuB6fJtFLbPOCe+bCYKZ2xbEpsZZ8X78L75fvtzQs4nH7eVfBMuDYiMe0uDPsrYL7tcebifSyTj0PWYNP1+KUouYsRbhRMP15GCy2qL7pQGQCu8qYQK+CBHqR6ahobyiI4lsvVDQh59V3skqUJEqKBJnns0ltAj1hXqGyXSi7/4ZIU5S0z3nVHTB221+UDx6WohzLPMg08FjYh50PQxa18JYZrWh3UgV6QqADeuSJjkcD1UuABHrqXRu1ZRaurkTVgtfh/42vKnei5pPeuTtyxkxEWk5BokJSHJ0TqP7+E1R/8rris7QMGc6+Hyl705Dik6AAUQnwCPQEZ/m3z0ZadvSbIry/LoLn3eejxo12QG/XS6LNU+37SaCn9hWi/IgAESACRIAIEAEiIIIA75dyEa73DtHTF3gS6O1dVrjmPYjAymX/7dDBM7F3mmlpqiTQa75aUgV6DlZBrwNV0GsOVuY9ga3r4Xridpm9NnXXesZLaGUyN91Jr5oRkHIBX0/fARqDEdrdGrv1gXCjQ2avg3TZKtn7y0J43nuh8bRFP9ejYFH05CUMLGYCvVIJAj1zZjq6d6QKehKWQJxpoBbFUy8SN5ZzlPOau2Hs3IvTWt9mPH+T1CjQq1+lYACuVx9FYPWfsi5a9vlXs4qug1r0ycOyRacKDTCYLLCeOhrWI4YqFIHcxiLgZhX0tkmooCf4JoFeLMLaOUYCPe2sVTIz9f74GTwfvZrMFETFNg04Co7zrhU1lgYRAbEE/Gv/gvv5+8UO5x5nOXYY7MPHctuToboJ8Ar0TAcfCcf5EyNObk9tDXbfdknEYy3t1Ou5vZbmrbbjJNBT24pQPkSACBABIkAEiAAR4CCgdAU9Q04uCm6bzZGZOk1IoPffuvCy+M+D+p7lT3sKaQ593dlPAr3m7zMS6DVnosY9we1FKH/sNkVTK7z3ZcCYqWgMrTuvWbEEla88zjUNy5DT2B3dF3DZkpEKCOzZg+JJ53EnQidw40dHAr34mSXFggR6ScHeEJRHVKZagd7/J+X+4Hn4f17UMEVZHgUxm23wGTF98bCM6TABB419D0b2yMuYMN6ZgGgUooEACfQaSNAjCfToPRCLgH/dClR/+TZCW4piDVPFMevJ58B2wlmqyIWS0BeBuspylN5zteKTsgw6CfbT+cRWiidHASQT4BXoCYEdl94E0/6HNstByt9wOr/TDGdSdpBALynYKSgRIAJEgAgQASJABOQl4F/zB9xzZ8nrtJG39A6dkXed8neNNQrZ4lP/6qUIbF5bXwbe/c7TLY5vPKCubDeCG9c23iXqudgqBqKcqWRQ2FeNkjsuU0k20tNIb9cJeTc8IN2RyjzwCvQyDzwMrTLjEy4ZMi3IaN8V5oOOBNLSVUbiv3Q27ahEtS/43444n1GL2ziBcQ6vc5ehdMY1nNYtmxmYMK9AEOjRFpOA64WZCPzzd8wx0Q7mT3kMabmF0Q7Tfg0QqPpoHnw/fsGVqePSm9lJ4UO4bFPViFrcamTlE9Li9i7W4nY/jQBJbJo8ojK1C/QEgp5FH8D7+TuywjQfdSKyzxwX1ScPy6jOEnjAYM2C7axxMPc7IoFRUzsUtbhN7fVvPHspF/cb+4n23Nj7QDjHTYl2mParlEBdRSk8TJjnX7pYpRn+l5Yh0wTbuePpb8h/SOiZAgQS8R3LfNQJ7Huefs7LK7AMmnYpRaAnTHxfQV2gaDVcz0znZrKvP25HZCiJAAn0JOEjYyJABIgAESACRIAIqINAnWs3Su+9TrFkTAOOZu0ClBNYxJO4f9XvcL/0cDwmso3Vo0BPgFP26C0I7dgiG6dkOtLrnYe8Aj2pa2E7/UJYB50q1Y0i9iTQUwSrIk5LbrsY4Vq/Ir7T2zMB+fXqEpArMlEJToO7t6F81iQuD8Y+B8N5yWQuWzJSD4FgMXsPPMT5HmBVjpwX03sgntXcVepFmbsmHpMmYy2mdHTrQC1um0BR4kVdHYpvGaOE570+c668HZnd++x9TU/+I8BzwVMLAj1hhr6l36PqrWf+m6wMz4x9B8B54Q0Rb57hYSlDSrK5sJxwOuwn81d6lS2RFHAkVaBnMLRCn265KUBK/1MkgZ7+1zjeGXq+ehverz8C9oTjNU34+PSOXZF97gRktG6f8NgUMLUIJOI7lumIwXCcNT61wKbQbKUK9KxDR8I2dNReYlLfkyTQ24syqU9IoJdU/BScCBABIkAEiAARIALyESi571qEy0vlc9jIk+2cy2E97PhGe5Lz1LvkK3jefzE5wVlUvQr03O89C/8v3yWNq5yBs8dcA3P/o+V0qQpfyRLoCZNXq+hx03ZWQa+Gv4KeM9uEdgVZqlhfvSfhmnsfAmuWKzJNyzGnwD7iIkV868Vp5ccvo+aHz7mmE62lBpczMkoqAdfzMxBYu5Irh/wpj7Mqiq25bFPRaCcT6JVLEOhZzeno2p4Eeol470i9wNFSjo7Lp8DU68CWhqXkcR72WhHoCQtau34lKp6bIfva5k9ln8fOpp/HPCwNZgvCNT7Z8+N1aOp/OBxjruc1JzuRBFyVfuwoqRY5uvmwtLRW2L8rCfSak9HeHhLoaW/NlMrY+8tCeBd+gLDbpVQIWf2aBh4Dx6gJsvokZ0QgGgHXKw8hsGJptMOy7Kf3tCwYVetEqkBPmFju5IeQUdAe1T9+iuqPXpM0VxLoScInmzEJ9GRDSY6IABEgAkSACBABIpBcAlWfvQbft5/Kn0QrAwqmPw+D2Sq/7zg8Brauh+uJ2+OwkH+oXgV63h8XwPPRK7IDSytog4yu+yGd3dWalpXNbsQNI1xVgdCuLQhsWM2eu2WPmXvTA8ho00l2v8l2mEyBnjB329njYD38xGRjaBK/aJsbPn+oyb54XuQ6zGibn9zPtXjy1fJY3+/foertZxWZgvOau2Hs3EsR33pxynPhvmHudPKugYT2H2uW/4zKV5/gmohlyHDYhylbaYwrMZUaCeIHQQTBu2VZMtClXTavOdnFQaC+gh6rpKfURi2io5Pl+dukJYGeMPNQ2U6U3X9jdAicR5wT7oCx6/57rblYdt8fzivvqPexp7YGofLdCJXuhFBxtf632sple/0n6omxZx/kXDQJrVjbQtqUISCIxwUROe+Wnm5A7y5OXnOyUxEBEuipaDGSlIp/1W+oXvghQts2JSmD+MOqucND/LMhCy0QqPrkFfi+X6BoqqZDWNei0eroWqToRFPUuRwCPSPrapA98nKUTr9KMkU6xycZoSwOSKAnC0ZyQgSIABEgAkSACBCB5BOoqyhF6cxrZU/EfNSJyD5znOx+43XoeulBBFYl/kJB4zz1KtDzr/kD7rmzGk9V0vPMAw9jbVGHtSiaEU4Ier//DMGNayXFa2xceO/LgDGz8S5dPHe/+RT8fyxO2lwMDicKpj2dtPiRAm/YWoGaWv6L6vk5ZhTmkUAvElsl9ilR5VW4kOu8IrnCbSVYyenT++tCeN59gcul9dTRsA0+g8uWjNRJgEfE0TATOpHbQKLlx23FHrg9tS0PjDLCZjWic1t7lKO0W04CJVMvQjjAv1Yt5ZJ94USYDzyypWEpeZzn80hrAr36hQ3WwvXqowis/kvWdW5cNZyLZSOBXrTEhPMLtUWr2Y1VK+Ff+mO0YbLvz7/jGaTZc2T3Sw6B0ooaFJfxC/SMGQb06kwCPT28l0igp4dV5JtDoGgVqr/5kLuyNl9UaVZp+a2Rfc74JuJ0aR7JmgiII+D96Qt4PpwnbjDnKFP/I1gV4es4rclM7QTkEOgJc8zo0hPBTetiTlc4d99SNVQ6rxMTYcIOkkAvYagpEBEgAkSACBABIkAElCdQ9cVb8C2cL2uggrvnwGBN7kXCsN+HkmmXyjovHmd6FegFd2xC+aNTeJA0s3FcciNMfQY22x9rh/fHz1gFv1djDRF9TK8/NMtm34nQJvmEjKKBNhqotjZt67ZUoDbAL9ArcFrQOtfSaIb0VEkCvj9+QNWb8oo8qXpeyyvGc9G+wasa/v435EKP8hDwfPUOvF99wOXMft4EWAYcw2WbakZbdnlQVc0v+rJnZaJTG1uqYUvKfEvuuhzhao9ise3njofl0MGK+deyY56/T5oU6P1/kdzvz4F/yTeyLlmDkJ6LpQiB3r7JBrashf/v3+r/hctL9z0s2+v0Nu2Rc/k0JtJzyOaTHP1LYHc5O6/i8nHjyDSmoWcnEk9yA1SRIQn0VLQYCUpF6EpS/c18BFb+kaCI8oQxHXQYa2nLqkYZqbqqPETJSzwE/KuXwv3iQ/GYxD0288CByLlQ/orLcSdCBooQECPQE9oc+3/7QXJ8Y79DWmzJrNfrJpLhJdgBCfQSDJzCEQEiQASIABEgAkRAaQKuZ6fXtw+VI072BdfCfNBRcriS5COweS1cT90pyYccxnoV6MlRfTG9bQfkXDIZaTn5XKj961bAPY+d9AgEuOwbjPT6Q7PsoZsQKt7RMM2kPGYNH4OsY4cnJXakoP9sciEYCkc6JGqfUD1PqKJHW+IIuN99Bv5fv5cloPWUc2A7/ixZfOnViZS/ndRmRZ/viroqF2uLMoFrchnd9kPuVXdx2aaa0aYdlaj2BbmnnWM3oX3rLG57MhRPoGTmBIQrXOIN4hxpO2MsrEcPi9MqNYZzicp6sLas4/9ty8pLqeqjl+BfvQx7PFX1LgxZNmSdMhrm/kfzuhRt51n4PrxfvCt6vJiB5qOGouanr8QMbTLGyCHQa+zAv3Y5/L9/C/9fvzTeLdvz9Pad6tfaYKZq17JBZY52sfa2ZazNLe9mMaWjWwcSTvLyU5MdCfTUtBrK5hLcXgTvdx+zz+tflQ2kgPesEewc1DHqOQelwBTJpcoJBHeyG9ofkeeG9mhTNfYdAOfFk6Idpv0aJyBGoCfcEO9+/j5JM7UMGY6wrxr+X76N6Uev101iTlqFB0mgp8JFoZSIABEgAkSACBABIiCFQNhbhbLnZiC8c6sUNzANGw3HkDMk+ZDLuF68Nedeudxx+9GtQK/KzS7YX8nNRTDMn/YU0hx5knz4//kT7hcekORDrz80Sx+8AXUluySxkWpsPfls2E44W6ob2exXFZUjHN7D7a9dQRac2XQXNjdATkPXPNaufOUyTut/zQwDh6Bg1BWSfKSCsfudp7nvwnVOuJO1EOqdCphSbo4VrNVi7XK+C3S5189ERvtuKccs3gkXbXPD5w/Fa7Z3fK7DjLb5JErZC0TBJ2WzbkRo907FIpCYPDraRAv0av5czFq+Px+1pXEroxFZZ1wMK/uOoeTmW/odqt56VskQonxLFeg1BBFu9PL+8Bl8P37RsEu2x4xuvZkwPPk36ck2IRU42l5SjYpKP3cmWeYMdGmfzW1PhuohQAI99ayFUpkEtq6D9/tP2ff+35QKoZhfoZKq/azLYezcS7EY5JgIiCEQrq5EyV3jxQzlHmPs0x/OS27htidDdRMQK9ATZiFFpCdcD3G/9xwJ9NT9dtibHQn09qKgJ0SACBABIkAEiAAR0A+BWo8HO196BOata7gmVXnMaHQceirMpgwue7mNQiU7UPbgTXK7jdufffSVsBxyXNx2ajeoq2QVde7hq6gjzM0xbhJMvQfIMk3PNx/Cu+Btbl96FeiVPToZoR3SRLfcUP9vqLY2bX+vL5M0pQ6FNjhsmZJ8kDEfgY0vPg7L6iVcxp4BJyOPCchzSFwZk1+4xouS28fFHBProF4/S2PNOVWO+dcth3vOfVzTNR15PBwjL+eyTSWj9awFu19CC/Z81oK9kFqwJ+QtU/bkbQhtKVIsluW4U2E/7ULF/GvZcSIFer5lP6DqjadF4bKedBZsJ54jaizvIP/6v+F+biavuSx2cgn0GpIJle1ENROCyN3G13TQ4XBccH1DGHqUSGAra8FeKaEFu81qROe2dolZkLkaCJBATw2roEwOgQ0rUb14geSb4pTJrmWvpiOGwHEW3YzXMikakSgCxZPPB7s7WLFwxt794Bw3VTH/5Di5BMQK9Ey9DgTvTbbZF06E+cAjSaCX3KWOKzoJ9OLCRYOJABEgAkSACBABIqANAnV1e7B6Y3l9ss5XbkEau1AvZvN37gvvwNMRzmmDLuzEaxY7AauWrWTm1awF1b9zSlZOtjMvgvWoU5IVXrG4UgSQpoOPhOP8ibLmxnPBriEBvYpKyp+5C8GifxqmmZTH/KlPIM1ZkJTY+wZt/Bm37zGxr4WLS8JFJtoST2DNRhdCdWHkvDMd6RUlohIIFHaG95DhCLXrBWpP3DKy6u8/RvUnb7Q8MMII21mXwnrE0AhHaJdeCEj6O3vfK0AGfXbGei9QC/ZYdNR1zDVnBgLrViqWlOmwY+E45yrF/GvZMc/nkJGzxW3x1LFAICAal/WUUbAdP1L0eJ6BodKdKHvgRh5TWWzkFug1JBXYsg6eBW+y3y18Nwo2+Gn8aDl+BOynsIvjtEkmILUFu8NmQodCasEueSFU4IAEeipYBJlTqPn7V/gWfyHr56/MKcZ0Z7BYYWOVbM0HD4o5jg4SgUQTKLn7CoQ9VYqFNfbsA+cVtyvmnxwnl0A8Aj2eio3GfofAOfbm+klSBb3krnU80UmgFw8tGksEiAARIAJEgAgQAY0Q2MO6Pq7c0FBdag+Mqxcjc8tyGHdvgaG2psksgjkFqG23HwI9BqKuoPPeY2qrLuX5dj68n721N79kPLGceCbsJ52bjNCKxqxdtwIVnC2ElWh35/1lITzvvcA1ZxLocWFr0ch00GGsesUNLY5L1IBAsA5rN1dICteNtWeysDZNtCWewDpWXar2/9WlMor+QObGZTAWb0Kar+lJz5DNiUDb7qjtNgChDn32JpqfY64X6e3dQU+aEeARPjQ4KXyQCfsMhoaX9KhDAt4fP4Pno1e5ZmY7YyysRw/jsk0VI+E7uPBdnHejFuy85OK3q3j1EUVbvxn7HgznxZPjTywFLHj+TvEI9Nzvz+Gq6pYQcWWgFq7XHkVg9V8JX3GlBHoNE6n+/hN2o8DrDS8lP2aPuQbm/kdL9pPqDjZsdaOmllqwp/r7QPiSUvH646j96xfFUBh7H8gqQk1RzD85/o+Ad8lX8Lz/4n87NPhM+L6UfeZlSMt2ajB7SlnvBMoeugmh4h2KTTOjW2/kXnWnYv7JcXIJxCPQEzL1sgqonvnspkiRW96tjyI9r039aBLoiYSmgmEk0FPBIlAKRIAIEAEiQASIABFQgsDqonLUhZtfHWzlr8YeUxZaeVzYY3VEvQjfJt+KPIdZidS4fbqeuweB9au47aUamg49Bo5z+VvBSo2vlL1n4fvwfvFu3O4N2TkouP2ZuO1aNGAXq4qnXtTisEgD8m+fzU7q5UY6pOl9Jfddi3B5aVLmIKxz7nUzkWZXz8lSnz+Iom2Vknj07JSDTGOaJB9kzEegaJsbPn/zi4OtAjUQ/kahVSuEzax9VnrkKl1Ce9v2BVS9Ixp9/5plcM99MNrhmPvNR5+E7DMuiTmGDuqAQMDP/s5ezD0RvYrhuYE0Mgyz796r2HdwKVvHNjZkZ1ELdikMxdryirfE+k/v3AN519wjdnhKjUuUQK9kxgSE3S4utsYefeAYMxGGrGwue7FGSr8PI+WhtEBPiBncsRGV781BaNvmSCnEtc+QaULujfcjLbcwLjsa3JSA1AqvBawFe2tqwd4UqgZehX3VqF23HLVFqxDaugGhnduBPcq1axSQkEBP2TdGXVUFvD9/Cd/C+coGUto7uynMNnwMrINOVToS+ScC3ATKn74TwY1rue3FGKa3aY/0Tt2R2bUPMnv2U/y7p5icaIw8BOIV6AlRy2ffgeCmdS0mYD35bNhOOHvvOBLo7UWh+ick0FP9ElGCRIAIEAEiQASIABHgI7B2swuBIP9Jt3x28rVQbSdfhSoDrNJFYM1yPigSrdI7d2cX2WZI9KI+84pXHkbtit/jTsy4Xz84L5sat50Yg5K7x7MWAvELsOwXXgvLgUeJCaGdMXV1KL5lTFLyTStoyy5MXouMdl2SEj9a0KrqWmzZ5Yl2WNT+/bs6kZZGVcJEwZJ50OadVfB4xbea2ze80JpYaFFMW2QCrnmzEFj5R+SDLezNvekBZLTp1MIoOqwHAu73n2NVpb7lmopj/G0w9TiAy1bvRnJUeO3KKrxaqcJrQt4qVV+8yS5uf6RYrLT81si/5XHF/GvZcaIEesW3XgiEgpJQOSdOh7FjT0k+WjL2LHyP3TD1XkvDZDueCIFeQ7LuN5+C/4/FDS+5H6kFHDe6vYarNpQjLKHEa1t2E2euym7i3Ds5etKEwB5/DXzLfkAta3saWL+6ybFEvCCBnjKUAxvXwPfrQvaZ+pMyARLoVfhMt7EbwzIK2icwKoUiAvETcM17kJ1fWRa/oQSLjK69YOp3WH3LZ4PFJsETmSabAI9AL7DpH7hm39Vi6vveOEkCvRaRqWYACfRUsxSUCBEgAkSACBABIkAE5CUQrUKR2Cg5dlahqLU6KxR5f12Emt+/RWjzBrHTkWWcwZiJgntflsWXmpyUPXwzQrvYXdRxbpbjR8B+yvlxWokbXvbEVHZ390ZxgxuNMh9zMrJHXNxoj/afBraug+uJOxI6kbSCNjAdfDS7E++shMYVG8xV6ceOElZpTcJ2QI88CdZkKoXA9t3VqKjyc7uwmNLRrQOrAEtbMwJ1FSUonTmx2X4xO+jCtxhK+hkT2LYBrsencU3I1P9wJt6+nstW70a+GlbhdXv8Nxg05kIVXhvTUPa5lHbPYjIzmMwomPGSmKEpNyZhAr2bR8vCNhEtVn3s923V28/Jkm9LThIp0BNyqfr8DfgWfdxSWi0ezxp+PrKOHdHiOBrQnIAsFV4LWYVXG1V4bU5XPXsCW9fDt+Trf0WxYf4bdqXOiAR6Ugk2smfr6P2NnQP97Tt2jqyo0QHtPs1iVfOyjh2u3QlQ5ilFwP3WbPiX/pi0OZsGHAXL4SfC2GW/pOVAgfkJ8Aj0hGiVH85FzU9fRw3sGDcJpt4DmhwngV4THKp+QQI9VS8PJUcEiAARIAJEgAgQAX4CUisUZVky0KWdsu18+Gf3sA/DIwAAQABJREFUf0vhhCNriSC0d4h3q5gzE6Hi+EVpzutmwNihe7zhVD1+N2snu4dVJ4x3s4+5Bpb+R8drJmo8b1W/9C69kHf13aJiaGVQ9fefoPqT1+NO13TYcbCddG7cdmnsYjKMprjtEmmw2+VDSbmPO2Q6q5zXm1XQoy05BIrZ2pWyNeTdMtIN2K8LrV8kflWfs2pQi/iqQWVfcC3MB+msAmkkSLRvLwGxrVP2GjR6kn/Hs6z1OQllGyGpf1rJKrxupQqv+2JR7euav35C5WtPKppf4b3zVP+9SlEAUZxrTaAnTMN6yijYjh8ZZUby7K5dtwIVc+6Vx1kML4kW6AmpeL75EN4Fb8fIStyh/CmPUatbcaiajKoN1GHdlvjPmzR2QhVeG9NQ13Ohslr19x8jsOpPVSQmtAh3jr9dFbloNQlBbFnzx/eoXboY4Vr+m9vUNH9j736wD78I6QXt1JQW5UIEohIIez1wzZmB0I4tUcck6oCx1wGwHjcCmVTJPlHIZYnDK9ADu05TzK7XRNoE0abjvGubHSKBXjMkqt1BAj3VLg0lRgSIABEgAkSACBABaQSE6lJClSnezZyZhu4dc3jNVW/nfou12mEnuuLdEnFhJt6cpIwPbF4L11N3xu3CYMtGwZ3KVXioc+1G6b3XxZ9XpgkFM+fFbadmA9cLMxH45++4U7SNugLWgUPittOCgdQKbHr/fFP7Gpa7a7Cz1CspTaqAGBkfj+ChwdO+7TEa9tOjfgn4ln6Hqree5Zqg9eSzWZXVs7ls9WxUxj7fdkn4fGvVCujbnSq8Juo9EihaBdcz9ygaLu+Wh5GeTxei94XM8/fK2GN/JviIr6o0T5x9c2382nTYsXCcc1XjXbI/D5XuQNkDN8nut7HDZAj0hPhyiPSM/QbCOfbGxtOh5yIIVPsC2LSjSsTI6EN6dcqB0ZgWfQAdSTgB4byJ5/O34P9zScJjxw7YCtahZ8I2dFTsYXS0CYGwr5qJ8n5AzZ+LuTpKNHGmshe2kZfCeuRQlWVF6RCB6ATqv7Ms/BAIBKIPSsIRY79DYT95NAldk8CeJyS3QI8F8/72DTzvzGkWNv+Op9nNks5m+0mg1wyJaneQQE+1S0OJEQEiQASIABEgAkRAGoESVp1ot4QKU2mGVti/W660JFRs7V28AJ75r8SdYXqnbsi7dmbcdmo1qPrsNfi+/TTu9Ix9B8B58aS47eIxKLnrcoSrPfGY1I+NVOY9bicqMQj7WaW4aZdyZZN70wPIaNOJy1btRpt2VKLaF+RO02Y1onNbO7c9GUojIEeFqd6sgl46q6RH238Eapb9iMo3Zv+3I45nlhPPhJ2j4mYcIWioSglIEa+QqLP5ou4q86Ksoqb5AZF7qEKoSFAyDQuV7mRCKGWFPo7Lp8DU60CZMtaPG57PHjUI9IQVEPJwjLkOhqxs5RYk4Ifr1UcRWLNckRjJEugJk5Gj3a3j0pth2v8QRdjo1WlFlR/CTU5Stj7s/JCBnSeiTR0Eqr/7CNVCVcoktrJtiURaQRvYhl/QrA1fS3apdrxmxRIIVX0DK5bqbupCpSf7aRfCYKPK27pbXJ1OyM+qGVd/+ipCO7epeoZ0w5yql2dvclIEeoIT1/MzEFi7cq+/rBGsRfgxkVuEk0BvLybVPyGBnuqXiBIkAqlBYMbfa1Jjojqe5bQDeut4djQ1IqBNAkL1PKGKnpRNzydgg9s3ovyxqVx4cm9+EBmFHbls1WbEc3FMmEPW8PORdewIRafjeukBrhYtpoOPhOP8iYrmlijn3p+/hOeDl+IOZ7BYUTB9btx2WjEQ2jMJbZp4t5xsE9oXZPGak51EAj5/EEXbKiV56dYhGxZThiQfejN2PTsdgQ2ruaaVP2020hz6FeVzQUkRI16hvoAn+6LrYT7g8BQhJW6aW1h72yrW5pZ3s5jS0a0DXcDk5Re3XYzWQXH7imJgO3scrIefGOVo6u7m+Q2iFoFew6o5J06HsWPPhpeKPIq50MYTOJkCPSFf99uz4f/9R57U623SO3RB3nX3cdunoqFw86ZwEyfvpvcbOHm5JMOurrwYle89j8D6VckIzxXTMuhk2E+/mMtWr0b+f/6C/+8l8P/6vS6nWC/OPPU8mPoM1OX8aFL6JCDlt3EyiGR06Qn72Zcjo3WHZISnmCIISBXoBXew61eP/nf9KtZNkmJ+N8SyFzEdGiITARLoyQSS3BABIiCNwBmfLZLmgKyTTmD+qccnPQdKgAgQgaYE5Ghh0qOjA6bM9KaOdfSKt0KbedBJyD79Es2TqPn7F1S+/BjXPHKvn4mM9t24bMUaVf/wCao/fl3s8CbjhPa7QhterW88Fy+FORv7HswqHE7W+vSj5r9qQznCe/ZEPd7Sgda5FhQ4LS0No+MKEQiFwlizySXJe4dCGxy2TEk+9GQc3LGJnbSbwjWlTNYiJWessq30uBIjo4QQCJXtQtn9N3DFMu7XD87L/jtZzOVEZ0ZF29zw+UPcs8rOykTHNjZuezKMn0DJ7eMQrpHWdj1WVMuQ02AfdkGsISl5jOc7rtoEesLCZY+5Bub+Ryu6hp6F78H7xXuyxki2QE+YTNlT0xDavIF7XrZRV8A6cAi3faoZCtXzhCp6vJuJtbbtwVrc0pZcAjXLf0blq08kNwnO6Omdu8Mx+mqk57Xh9KB9M/9aJspb+Sv8S77V/mRizMBywhn1LThjDKFDREBVBOrcZah8aza74VGbhWTs510Fy4BjVcWUkvmXgFSBnuClQTjqvHIajN37RkVLAr2oaFR3gAR6qlsSSogIpCYBEuhpf91JoKf9NaQZ6I+AUF1KqDIlZevELhDa2YVCvW7u1x+H/88lXNMruGcuDGYrl61ajMqfuRvBovhPPhiynSi4/WnFpxHcvR3ls27mimM5fgTsp5zPZasWI/+aZXDPfZArHdtZl8J6xFAuW7UbySHuat86Czl2k9qnquv8Vq4vA7/EEiCRZdO3R+WHL6Dmp4VNd4p85bjsVpj2O0jkaBqmRwK8FWsFFrmTH0JGQXs9YuGa0+qN5air4/90y88xozBP298vucAl0ajs4ZsR2rVdsQyMTATtJBF0M756EegJE7OeMgq240c2m6OcO3y/f4uqt5+TzaUaBHpSfusJINIKCpE/me9mM9lAasjRxu1ueGtC3BnbrEZ0bmvntidD6QQ8iz6A9/N3pDtKogeh0r/9/GvYb4/+ScwigaFZ++Ga1b+jdtUfrGroDwkMnJxQxj4HwzbsPKrmlRz8FJWTQKBoFdyvP4lwlZvTgzrMLCcyYexJo9WRDGWxl4AcAr29zlp4QgK9FgCp6DAJ9FS0GJQKEUhlAiTQ0/7qk0BP+2tIM9AfgT2sutRKVmVKytaGXSDMYxcK9brV/PUTKl97kmt6liHDWTWMMVy2ajDyr14K94sPcaViOvJ4OEZezmUbrxHPxbuGGAV3Pw+DVbtVaMqfuYsJKP9pmE5cj/l3PIM0uz4rHHhrgti4vTIuHvsO7to+G1YztUfdl0siX6/bzNoUByW0KWYCS0FoSRsjEAqh+NYLuFFQiwtudLox9K/6De6XHuGaj+WYYbCPGMtlqzcjQZgnCPSkbG3zrch16Pe7txQ2Stm6XrwfgdV/KeUe6e06Iu8GvhsuFEtKBY55vuOrsYJeA0rTYcfCcc5VDS8VefSvWwH3nHtl8a0GgZ4wEe+Sr+F5fy73nGyjLmdV9KijhxiA/7Dq1UFWxZp3c2ab0K6Avnvz8pNqVzn/JdQs/lKqG9XY67naU11lOYSbLWv/+ROBlctUw1zJRNIKWiPrpFEwH3iUkmHINxGQnUDNiiWofEWoSsp/g5XsSUlwaDp8MBxnj5fggUzlJkACPbmJ6sMfCfT0sY40CyKgeQIk0NP8EoIEetpfQ5qBPgnQSdgW1pWJGIsnndfCoOiH86c8hrTcwugDVHyk7IkpCG3dxJVhSyXVuZxGMfJ8/S68X74f5Wjs3eajTkT2meNiD1Lp0ZplP6Lyjdlc2Rl79IFz/O1ctlowElozCS2apGz7dXEiI90gxQXZSiSwaUclqn1Bbi8WUzq6dXBw2+vJ0PvTF/B8OI9rSlkjxiDrmOFctmSkLwI8YpkGAiTy/JeEzx9E0TZpAvIurDpRFqtSRFviCFR++CKrQPqVogHp/0hzvDyfOWoW6AkzFL6DO8ZMhCEru/mEZdoTKtmBsgelt6VXi0BPwCKlimt62w7Iu3GWTHT16yYc3oNVRdIE5Hq/eVPNq+9+91n4f/1OzSly5WY7+zJYDz+By1ZtRrXrV6J23V8IrPsboR1b1JaecvmkpcF64pmwnXC2cjHIMxFQiEDNsh/YeVflu8MolH5Ut6aDj4Tj/IlRj9OBxBIggV5ieWslGgn0tLJSlCcR0DkBEuhpf4FJoKf9NaQZ6JOA1DYmVnM6urbXtwDC/e4z7GTn91xvAGO/Q1jLKr4WrFwBZTKq/u4jVH/6Jpc34c7Y/MmPc9nyGNWVF6P0vut5TOttnBPugLHr/tz2STEMBVHywHUIV7i4wtvPHQ/LoYO5bLVgtKvMi7KKGu5UW7Vqhb7dc7ntyVAeAjtKquGq9EtydkCPPEn2ejHmETk0zL31zJfQKpOqdTXwSOVHzzcfwrvgbS4EtnNYBaPDqIKRHALyXp1yYDSmca0DGfER8P74GTwfvcpnLNIqf9qTSHPkixydGsN4/napXaDXsHLOidNh7Niz4aXsj3tq/ah47REE1qzg9m3s0x/OS27htpfTMMhEh+USRIeOS2+Caf9D5UxJd75qmIB8g0QBeac2NtizMnXHRu0Tcn/wPPw/L1J7mtz52UdfCcshx3HbJ8swsG0DhLaYgQ3s3z/8n8XJyl+OuKaBx8B20rlIy6ZzK3LwJB+JJVCz/GdUvipUztPnZjpkEByjr9bn5DQ2KxLoaWzBEpQuCfQSBJrCKE+gzlWCYOmuJoFMvQ5s8jrSi0h2xo7dYTBbmw0P13gR2Lqhyf5oYxsGRbLJyG+DNGdBwxB6ZARIoKf9twEJ9LS/hjQDfRIQqkwJFwulbHoXQAQ2/QPX7Lu4EdnOGgfrESdy2yfaMLhzE8ofmcId1jrsXNiGnMltz2PomnsfuwC1nMdUk23FpIhGDRYrCqbzt4nigpxgo807q+DxBrijmpjwoQcTQNCWXAKCyFIQW0rZerNKiOkpXgmxll0Uqnj2Hi6MpsOOY+34ruSyJSP9EQhXV6Hkriu4J0YVwoBi9plWKkFALsDX+/du7jeYgoZCGzr3XGVb0DrGTYap98EKzkJ7rvUs0BNWI3vMNTD3P1rRhXG/9xz8v3zLFcNywumwn8xfSZ4raAyjqgWvw/fNJzFGRD9k3P8gOC+9NfoAOgI3Oye0TWIF8p7s91MmCcgT+m6q+vwN+BZ9nNCYyQjmGDeJ/Y0ckIzQ4mLWhRDYvBa17F9w8z+SxNHiAqp7lLFXX2SdeA6MnXupO1HKjghEIRDYsBKuZ2dEOaqf3ZZBJ8N++sX6mZBGZ0ICPY0unMJpk0BPYcDkPnEEPIs+gPfzd5oEFHOCOJKd4/IpiCTu869dDvfz9zWJEW1sw6BINtZTRsF2/MiGIfTICJBAT/tvAxLoaX8NaQb6JCBcJBQuFkrZUkEAUT77DgQ3rePD1MqA3OvuQUb7bnz2CbYqe5y1tt3G19oWhjQU3PUcDJashGbtX70U7hcf4o5pOnwwHGeP57ZPpKH3l6/heY9fYGcZfBrsp16QyJQTHuvv9WWSYgqVH4QKELQll4AgshTEllK2ru3ssFpSuxWk+40n4F/2MxdGpSv8cCVFRkkl4H7zSfj/+IkrB+c1d6f8hTqpAnJB+CAIIGhLLIFQWTHK7uev1iwmW+upo2EbfIaYoSkzRu8CPWEhE3H+1/P1u/B++X7c75vcG+5FRruucdspZsAqiBffeiG3+/ypj7Ob4Vtz2+vdUA4Bed/ueWCFyGlLEAGp5wUSlKYsYQwmM3KunY6M1h1k8SfVidBKXKiQF9y6HjU/LZTqTjf26e06wnrCSJgPOFw3c6KJpB4BoWBP+ZPTEPZIOxelFXJZp1+ArEGnaSVd3ebpW/pdzLnJWUk2kbFiTooOxiRAAr2YeOiglghEEtqRQE87K0gCPe2sVbRMSaAXjQztJwLJJVDlrcWWnR5JSXRhAogsnQsgpJa2Tytog9yrp8NgVbfox/364/D/uYT7/WA+eiiyz7iU216KoSRhIQucddp5yDrudCkpKG7rX/833M/NlBQn/46nkWZ3SvKhZuNweA9WFZVLSjHfaUFhrkWSDzKWTiAQrMPazRWSHLXJtyLPkbrtWcOeSpTczSc+zujSg/3d4qu8J2nRyFjVBAJFq+F6ZjpXjkKbK8eoCVy2ejGSLCC3GtGprV0vODQ1j+JbxgB1dYrlbOp/BBxjrlPMvxYdp4JAT1gX02HHsmq1Vym6RN7fvoHnnTmiY6j187r6u49Q/emboufReKD1pLNgYxWdaItMQLKAPMOAnp31+xszMrXk7RWqtbmeujN5CSQhcnqHzsi77v7ERt6zB8FdWxDcuRmhHZvrH4NF/yQ2Bw1EMzjzYB1yOqyHa6dziAawUopJIlD+9J0IblybpOjJCeu4YipMPfslJzhFJQJEICIBEuhFxEI7tUiABHpaXLX/ciaB3n8stPqMBHpaXTnKW+8EAgEmgNgiUQCRxwQQOfoXQJQ9MRWhrRu53xIZXXoi98o7gLR0bh9KGlbOfxE1i7+SFCJ/2lNIc+RJ8sFrXPPXT6h87Ule83o72zmXw3rY8ZJ8KGUs3KHtenyaJPfmo09iAspLJPlQu7GvJoii7ZWS0uxQmAWHzSTJBxnLQ2DlhjKw6yLcW47dhPatE1vRkztZBQw9i95nVeTf5fJsP3c8LIcO5rIlI30T4BHNNBApuOdFGMypKYCuq9uD1RslCshzmIA8LzX5NbyHkvVY9tBNCBXvUDS8mJuIFU1AZc55PmuMPfaHczz7vRXHxhMnDveihhp79GECzYkwZGWLGs8zyL+OdX2Zc1+Lphld90PuVUz4o8ZSaOxLYfEkvra76a3bIm/SIy3OP1UHSBWQ25iAvDMJyBP29lHD51bCJtsokOmIIXCcdUWjPfI8DddUI1S66///dqC+Qt6KpfI417EXg80Oy3HDkXXscB3PkqaWSgSqPn4Fvh8WpNKU98618N55gJHOg+4FQk+IQJIJkEAvyQtA4eUjQAI9+VgmwxMJ9JJBXd6YJNCTlyd5IwJyEli1oRxhCQoIhy0THQrVXRlODl7+Vb/B/ZK0k/oZ3XrDeektaJWprh+9VfNfgm/xl5IwWY47FfbT+NsOSQr+f2M57nS0nXMZE+mdIEc6svkIbFkH15PxXWxsFjwjAwVTn4LBptyFv2Yxk7Cj3F2DnaXS2nb36OiAKVOdQtokIE1qyA1b3aipDUnK4YAeyRENS0paJmMpF+9IKCLTIujQjffnL+H54CWumWUNH5OyF/G8vgA27pDWKkn4vi1876Yt8QQqXnkEtSt+UzRw4f2vAOmp3Za9MWCev2FaFeg1zFvp1vKhsl2o+vBFBNb+3RCyyaP5qBOQfeZlTfap7YXnq7fh/epDrrScE++BsWMPLls9G4VCYazZ5JI0xXx2w2Yhu3GTNuUJVH74Qkq3Vc2+cCLMBx4ZF+i6qgrUVZbX/wtXlKGO/QtVlCLwN4nw4gLZaLD1lHNgG3wGYEhrtJeeEgHtEvCvWQb33Ae1OwGJmZsOHQTHuVdL9ELmRIAIyEWABHpykSQ/SSdAAr2kL4GkBEigJwmfKoxJoKeKZaAkiEBEAkXb3PD5SQAREc4+O13zHkRg5bJ99sb3Mr1dJzguvB7peW3iM1RotPvNJ+H/4ydJ3oU7ZwXxFzKSe1ExsGElXM/OkDQXwdg67FzYhpwp2Y8cDuQQhv47p1FsTiO5U/J89zFqfv4Ke6qr0MqYCWPv/uzkzQRuf0oZbt9djYoqvyT3fbvnqbJoiKRJadSY1pN/4WpW/orKeY9yOVCD4JorcTJKDAHW5rO+3SdntFQVf5ZW1KC4jATknG+bpJt5vn4X3i/fVzQP54Q7YezaW9EYWnKudoGeY9wt7ELuA7IjzR5zDcz9j5bdb2OHQnvMWlZRr85Vwqq7pyG9sAPMfQYizVnQeJgqn9dVuVE6/Uqu3CyDT4P91Au4bPVs5PEGILS4lbKRgFwKPfG2/rV/wf38/eINdDjSYLHCMng49oSC2BMMAIEAwqHafx+F1+xf4J8VOpy5OqZkPelsJsw7nd1QkKGOhCgLIiATgdIHb0BdyS6ZvGnTTfZFN8B8wGHaTJ6yJgI6I0ACPZ0taCpPhwR62l59Euhpe/2E7Emgp/01pBnol4AcAog+3XJhMLTSL6T/zyy4ezvKZ90seZ7CSUWhnar5gMMl++J1ENy9DZXvPofQ5g28Lvba2UZdAevAIXtfJ/OJ+73n4P/lW8kpmA5hdw+ewy7+sItWydo833wI74K3JYdPb9cReTdIuxM00kVSQ24+CqZIaysseXL7OJDansmUmYYeHXP28Uovk0WgjFVE3CWxImK3DtmwmFLvAoLrxfsQWL2ca+nybnkE6fltuWzJKDUIVLIKTDU/fcU1Wce4yTD1PpjLVstG24o9cHvYBWTOTfiW3TeFK4JyYpPNrGblb0z0LK2SdkvJpHKFyUhsIn33jDSu8b5EVtATxMbBkh0of/CmxinI8tx6Crux5nj+G2tkSULFTtyvPQb/X7/EnWFaQRvkT+a7eSHuYBoyKHH5sLvcJynjnp1ykGlM3u9mSclryLjssVsR2r5ZQxlTqnohUH8T67Ejknp+TC8saR7qI1D15dvwfc1XnVd9s+HPiL4n8bMjSyIgNwES6MlNlPwljQAJ9JKGXpbAJNCTBWNSnZBAL6n4KTgRiElAjpaQXdvZYbUkt3pazEnKeNDz7Xx4P3tLFo/mo4Yie8RFCT/J5V28AJ5PXgdYFRypm7HvADgvniTVjXz2AT9KHrwRYbe0Nj1CQmkFhbANH5twIUGodCeqPp6HwBp57vx2XjkNxu59uRj7V/8B94uzotqa+h8Bx5jroh5P5IFweA9WFZVLCpkqLbslQUqgsbcmiI3bKyVFbJtvRa7DLMmH1oyFz5CyB27kStu4/0GsFfutXLZklDoEgjs3o/wRvveJsd8hcI6VfrOD1mhLFZCbWev17qwFO23JIVBXUYLSmRMVDZ7ZbyByxvJ9diuaWJKca0GgV4+mLgTX648hsELeVommw45lNwtdlST66g7rX8N+n8yN/vskVva5kx9CRkH7WENS7phQPU+oose7GVq1Qp/uubzmZCeSgPenL+D5cJ7I0TSMCMhDwHb6hbAOOlUeZ+SFCKiQQF2lC6UzrgH2hFWYXeJTyjrtPGQdx6pk0kYEiEBSCZBAL6n4KbicBEigJyfNxPsigV7imcsdkQR6chMlf0RAPgI+JoAokiiAaJ1rQYHTIl9SKvfken4GAmtXypKlweGEdejZCalAV7t+JapZi67gxrWy5C44yb/jaaTZnbL5k8ORXG1hG3IxDTgaNrZGabmFDbuUefwfe+cB30aR/fGf1axqy3KJ03sPEBIIhAChHeVoB0fvvXdIqKHXBLjQjk5ogYOjXo4S6lEC/KkB0nt1HBdZlqxiNf9nDE4cR1bZnV2tpDefTz7W7s689+Y7iizv/uY9Jpj0fvKG0J2b1v2PRMkhJ0qO1/3kHQgvX9jteJ3Fhqo7nu32upoXWgJhrN7oleWyJxNzVRSYmEsWMIUHk+hSGmDvf19C4H/vSRpcegYrazKGyppIgldgg1L9fkiGo/LGR6Avq0zWJa+uRaNxLF4tb+NAWakZfarsecUl1yZTd8s5iPtbFA27UEtAJ4KaMwK9P4P3znkRgS/eTzQVyedMQ0ezjTCXQWcvlWwjXwdKeX9wFvYjT4F9r8PyFYukeckVkFvNBgzuSwJySfAzGFR350VCNiFm4JK6FigBQ98BsE46GNZd9ilQAjTtQiLQ/PYzLDP8J4U05aRz1dnsqLr5CbZj3ZC0H10kAkRAWQIk0FOWL1lXkQAJ9FSErYArEugpAFVlkyTQUxk4uSMCGRBoa2vDghXysk45bCYM6FWSgdfc7hrzNPyxw07wNJQqFRta+isC8z5g5Q7nC43YedY1MI/aRahNUca8789G4LM5osy12zFP3A82dqPSWN1PqN2oezOCP38F/4dvCLVrGjOOZTecKstmw4yrEN1ck9SGVh4miyjPNLgPK4dqKbxyqEkXOMsXl61tQmtYXrbPHQqsLKTUh9Z8qbXy/znLbztynwaB4C9fo3n2o2n03L6L9YC/oeTgE7a/kKdnvC2tWLvJJ2t2vZk4z8VEetSyR0COKDXdqCtveBh6V1W63fO6n5TfZWqXuO26AEpluHJddjtM/YZ1dVfQx563nkbom08zZkCZgrdFxr9j8+/achrPVM0zVlNTjoD/6w/ge+cF5RyQZSLACJhG7MiEeQexChLjiQcRKAgCMS/Lnnf7RQUx10wm2V7Ser+jMhlCfYkAERBMgAR6goGSuewRIIFe9tiL8EwCPREUs2uDBHrZ5U/eiUAqAivWeRBsjabqlvR6oQkgQot+ZKU/70/KROpFy14Hw7LDbjANGinVBCJ1GxBa8D38778u2UaygfYjToZ978OTdcn6Nfes+xBe+IvwOHg2i+KdJsIyelfoHBIzWsRjCLL3UOuv3yH0y7fCY+QGq+9+nt1llfcwv376lYjVbUoan1YEPas3NqMlEEkaa6qLY1h5piJWpomadgisr/XB42uVFdCIAS4YjTpZNnJlcOCHz+F97UlJ4doOOQ6O/Y+WNJYGFSYBKQKaDlJa+d3REY+SPzfV+9HgCcpyMaRvKSxmEpDLgihzsPe9lxH4/L8yrSQfXnLChSxjzeTknQrkqpTPl2wL9PjShBb/wsqv3id8lUpPvgSWnfcUbjdXDYaWzIfnmXslhV9Iv39SAWryhrBhs7zMoH172OEskfc3Z6o4C/16On+TFzojmr9UAkUw77Y3bBMPgrHPIKlGaBwRyEkCSmzszkkQCYKm70oJoNApIqAiARLoqQibXClLgAR6yvJV2joJ9JQmrLx9Eugpz5g8EAE5BDbWtcDdHJJjAkP7OWEuLqwU6P6v3oPv3ZdkcUs2mKeWNwwc1n6jzFDdFwZXD1ZOtgy8rGh7uvl4HPHWAOItzYg21iNavwHRDasRXrsc8Ya6ZKZlXbNMOgClR50jy4Yag9taQ2h8bBqiNesVc2fo0x+GfkNg7DUQxsperGRfBXQ2B4qK+UMKJvSKhBELtiDmaUSsoRaRTWsRWbcSkdXLACbSU6qVX3Uvi2mAbPN1d1+CuLshqZ3q+19l17MvapNbnsnCPr+GsM8xatoi0MhELTVM3CKn9a12wOkolmMiZ8ZKETR0TK7qlieli447jNDPgiLg/fBfCHzyjqQ5F5LYZOV6DwIh6RthdEw4PpoJyKlll0Dw9+/Q/MJMRYMwT9gbzuMokweHLOX3mRYEejz2SN1GNE6/mr8U2khIvy1OKe8RbqH8qnva/3bb1lphHnFxHhfpyWnD+5fBZNLLMUFjkxBQcmNoErfbXOL3n3RV1ezvBCd0BgOi7L5GvH4zuxcl772zjRM6UJWArqwclt32hW33A1kZ9cKphqIqZHKmeQJ1t52HuM+b1TgN1X3A/z8Wsc3VbbFo+/39eD37jPXLE8/LnVTpqZfCstMkuWZoPBEgAhIJkEBPIjgapj0CJNDT3ppkEhEJ9DKhpc2+JNDT5rpQVESgg4CIndO8rAkvb1Jozfvhq+zh9LsFM23TqJ3gOuv6nJkvv3nsfuJ2xD3unIlZbqClp1/BMjDuLtdM+/i6G89kN96TZ/0RJQaUE3AgFMHK9c1yTKC8lJVnqqLyTLIgKjA4yNZ2hcy15WUheXnIfG/hdcvgfvhmSdM0j9sDzpMukzSWBhUugZinAfV3XiIJgBQhjSRHWR4Uj7dh4cpGWVHYWen1gawEO7XsElCjDJa+ogqV1z2c3YlqxLsU8ZWUzxUpfjiilJlF2ENW9+yZCP/2o1Ci5t0mw3nshUJt5qoxqdnSHcedC9uE/XN12kLjXrrGjXAkLstmoVVSkAVLwmD3iw+yz5HvJYyUP8S6/5HtlR26zawWjaDlmw/RuuAHRFaxDYjUNE/ANGw0LBP2g2UsCW80v1gUoKIEgr/OQ/NLjyjqozvj/N6LeSz7N3zsH5vvE3SMbFqD0O+sKs5HbyW4qvwp05hxcJ0xVXlH5IEIEIGEBEiglxALncxFAiTQy8VV2xozCfS2ssjVVyTQy9WVo7gLhUA4HMPStU2ypltiL0b/ng5ZNnJ1sHfOiwh88X6uhp923Pxmnuu8aWn310rHSM1qND19L9sZKU/ApZX5JItDZGm0SO06NN6f+oaM/chTYd/r0GRhKX6t3h1AbWNAlp++1aw8k4PKM8mCqNBgudkRi1lWj2Esu0e+N8+/n0Do//4naZplF0xD8ZDRksbSoMIm4H7xfskCFC0IvJVePa+/FWtrfLLcVLqsqC63yrJBg8UQSCezsFxPldfPhL68Wq6ZnB8vRTinKYHenyugxN+JpqGj4Tz5Mpb1qLCFuy1fzkHLf2Zn/F637nMoSg47NeNx+TYgHGH3gNbIvAdkM6F/L8q+pdh7IxxC7Q1nKGa+O8P2w06EfZ8ju7uc8DzftOH7+N/sb5EvEl6nk9kjoLPZYB63F8uYtx+M1f2yFwh5JgIaIuB+fgbCC35SNSLz+D3hOPCYjL/n8+o9/g/fSLl5WvRkqMKCaKJkjwikT4AEeumzop4aJ5DohkjK3Y5sTomEfc5zr2fq9p22m3EmfTsGh5b+Cs/T93Qctv+kkgXb4Gg/IIHe9kxy7QwJ9HJtxSjeQiQgVwCh1xVh1ODCLb/lfe9lBD7/b96+dUwjeea861gl0+yXMpUCOVKzBk2zZiDeJC+LjRTfao0pPekiWMbtLcwdv8Hun/tmSnvGwSNRfuEtKfsp2WH1xma0BCKyXIwY4ILRqJNlgwYrQ4DWNzXXNpbpcjPLeCm1pfO3sVTbNC6/CYSW/ALPM/dJmqRl0l9QetTZksbmyqBNrER3AyvVLacNYOIHBxNBUMs+Ac/shxD65VtFA3H8/SzYJh6oqI9cMJ4vAj3O2j/vQ/jefl44dtdlt8PUb5hwu7liMLxuOcscnPnmMdPoneE689pcmaZicbqbQ9hYJ6+EXnWFDZVlhVdFQbFF6WI4+POXaH7ln13OKnfI/653Hnd+xuKRzhEFF3yP5ucf7HyKXmeJAN9gax4/Gdbx4u4RZWkq5JYIiCXAshzXXnuKWJsprJWewkrGyshcGWtuRDPbkBle8nsKT+Iu098k4liSJSKQKQES6GVKjPpnlUDMXQffJ2/AOvEgmPoO3iaWhgenIFqzfptz6TyESCSgs07+K0oOP20bW/yg8fFbEVm5ZJvz3Yn5Ojolsk8CvQ46W3+SQG8ri1x9RQK9XF05iruQCKyv9cHja5U15cGs/JaVleEq1Ob7/B343/tX3k3fPH4SnCdemvPz4t8Vm158ANENa3N+Ll0n4DzrGphH7dL1tKzjTB6Mll95N4y9B8nyJ3VwWxuwcEUD2A/JzcSEecOZQI+aNgnUsQyJm2VmSOQlbnmp23xtUrPIcB6Oo86AbdLB+YqG5qUCgUx+X3QNp/q+l7st7dO1by4eL2cZqkMsU7WcNpptgNGxjTDUsk/A/81c+N6apWggpjHjWUmpKYr6yAXjUj5XtJhBr4N1aDETMz8rTczcYSPRz9KTL4Fl5z0TXcr/c/E4aqeeJGme6TwTkGQ4hwaJuP8zpG8pLObCvf+j9HKrIQrvmIN554ksM+flHYeyfkbqNqBx+jWybNBgaQT0lT1QzEpnclGeoaKnNCM0igjkOYHQwu/hmaWekFjk/VLP6/9E6PsvVVkh2tCgCmZyQgQSEiCBXkIsdFKLBHj2uuBn/2FpXkPQFZthO/TELbt9wst+3a7snKFXX1RcNSPlVPiD3Pq7L9uuHxfRGftsFQEGvv1ou5S4PI6qu57fbmznE4kEesbBI2AatmPnblte6yw22PY4aMtxobwggV7urzQJ9HJ/DWkG+U9AxA7qHqz8VhUrw1XILfjL12ie/WjeILDufyRKDjkxb+aDaATuVx6SXI5PayAMPXqj9KRLmDhuoNDQ/F9/AN87L6Rt0zx2NzhPuTLt/iI7+vxhrKnxyjJZVmJGnx52WTZosHIE/MEIVm2QV6La6ShG32qHckFm2bIUIUNHyNX3MoGUwdBxSD+JQMYEWr5gZQbnZF5mkDtyHH1m3t7jiETiWLLGnTHPzgOsZgMG93V2PkWvs0ggUrsejfcrK55L515iFhGo5lrK7zUtC/Q4uEjdRiZauVo4w0Le6C3lfcIXgAR6wKJVjYjFpG9x4sJxLiCnphyButsvQNzrUc7Bn5ZNY8YxYfhUoX6i9TVouO8qoTbJWPcEzLvvA+vYPWEaMqb7TnSFCBCBdgLN7zyH4NcfqUKj/Kp7YOwl9n6t5+WZCM3/TvH4dWYLqu5UdmOS4pMgB0QgRwmQQC9HF66Qwo4HWbmQB6Yg7snspmcmNy8SZcZLh7F5wt4sLfhFSbsmEuglG8DFe+UX3pqsS15eI4Fe7i8rCfRyfw1pBvlPoJVl91jGsnzIafQQ8Q96kZrVaHzwejkoNTE2nzMy+D56Hf6P3tIEZ6lBmMfuDufx7LumUWzZuxh7CFDPHgZk2kpPvwKWHXbPdJjs/jWsfGCjzPKBfZk4z8lEetS0S2DhikbEebpEiS2fy7CHlsxnJUbvlUTGMukAVmL0HEljaRAR6CAQDwVQd9NZHYcZ/8xXoYSIzS+8dCAvIUhNOwTqbjsfcZ880Xiq2TjPuwHmbjbuphqbL9elCK+0LtBrXxtWVs09e6bwzULm3SbDeeyF+bL8ac/D/ew9CC/+Ne3+HR3Lpz4AY1XvjsOC+xlgm19Wytz8wkuv8xLs1JQhoJbATV9RhYorp6OIJZoQ3ZTKHCo6zly1x7MeFu+0OyxjdsvVKVDcRCArBBpmXscqq6xR3HfpaZfDsuNE8X7YfbH2ioGbNoi33cVi+RV3bZOoqMtlOiQCREAhAiTQUwgsmRVLgGfP83/wetpGdU4XKq6eAZ6NLp3Gs+g1PjC1PTtfOv15H77jteKmx1L6IIFeekRJoJceJy33IoGelleHYiMCWwksXe1GOBrfekLCq5EDXSwRj07CyPwb4n13FgJfzc25iZlG7tgu2NC7qnIu9kwCDi2dD9+7zyNWV5vJsOz31evhOPwU2PY8RJFY3M/di/Ci+ZJsV057DPpSdTMpcGExFxjLaSPY55aRPrfkIFR87OqNzWgJRGT5GcTKsNvysAy7m5XuDv/2gyQ25VeyHd2CM3BKCoQG5TwBz78fR+j/vpA0D9eF02AaPFrSWC0PWrvJB29Lq6wQB/Yugd0qVogvKyAaDM/L/2BZK/5PURKWPQ9C6d/OVNSH1o3nrUDvT/DeOS9uV+1F7pqYho5mJSovg85eKtdUzoz3/odx/PL9jOMtPeMqJmqZkPG4fBlQ2xhAvTsgazo9mXi8gonIqSlDIPjzV2h+5TFljHey6jzzaphH79rpjNiXXna/JfDVh2KNFrA1vkmzeIcJf4h+iooKmARNnQhIJMDEbbVTTwba5D37SOWdZ7V0HnNBqm6Sr4eW/w7Pk3dJHp/uQMffz4Jt4oHpdqd+RIAICCJAAj1BIMmM8gTSrb3OxXnO06+Gqe/W8rTpRBdevxKeJ+5IS6SXiQ8S6KVDHyCBXnqctNyLBHpaXh2KjQhsJbBhcwuavKGtJyS84mUieblIan8Q4CKwlvdeQbRmneaR6CxW2A4+DrZJB2s+VpEBSn2wIzKGdG2ZxoxH6eGnQl9ene6QjPp53noaoW8+zWhM586GAUNQcd5NgEmdz4DWVpb5c528zJ9mkx5D+5d1nga91iCBhqYgNjX4ZUXGHyLyh4n51GKeRtTfebGkKZmGjILrgpsljaVBRCAeaEE84ENbaxBtkQgitevge+NZSWDM4ybBedKlksZqdRBP+LlwZSPaZGT+5I9dRw+pAD1/1dYq+7/7WPJ7Pd2Z8IxGldc9nG73vOyX7wI9vmj+eR/C9/bzwtfPddntMPUbJtyuFg36/+8T+P79TMah2Q89AfZ9/5bxuHwZsIL9/RRkf0fJaUP7OWEuNsgxQWOTEPC+9zICn/83SQ/5l0yjxsJ11nXyDSWxIDfLchLTBXFJZ3fANHIsikfvQpnyCmLFaZJKE4jUrGEVb5T93ONzqLz5cehLlL3PqMqmIaq4oPRbkuwTgYQESKCXEAud1CqB4Px58P13dsJytzyjnWmnCSg5/PSUWe26mx8vp+ud8wLCv36fUKjHfVj2OwK2PQ5K2wcJ9Lqjve15EuhtyyMXj0igl4urRjEXIoFmXyvW1fpkTb3EXoz+PR2ybOTj4JYv5iDw6TvsYbY8gYlSbCyT/gLHQcdBZy3MtYtsWAnfR/+WnDlOqXXpsGvo2Qe2v/xdmfIIfzqRk/2oI07+09B/MMpOuQL6ssrOpxV5zTM/8AwQclqFk4m2KvNLtCWHh1bHhlqjWL7OIyu8YibGHJZnYkzv3NcQ+PhtSVxKT7oIlnF7SxpLgwqHQHj9CkTYhkUuwIvXbUK0qR7xxnrhAKpufTKvsj7xzHk8g56cZrcaMbB34WTCksNKzbEx92bU33254i4LvaRUIQj0+JtIqRKQpadcCsvYSYq/T7PtILx6CdyP3ZpxGOZd94LzeGkbHDJ2prEBYZZ5fCnLQC6n8czjPAM5NeUIuJ+fgfCCn5RzwCw7z70O5uFjFfXBjXv/8wLLdPmB4n7yxYG+qieKR4yFedR4mIaMyZdp0TyIgCYIBH+dh+aXHlE0FvPu+7Lseecr6oMbD69ZCvejtyjqh2dndp0/TVEfZJwIEIHtCZBAb3smdCYHCPCStJH6TeAPWg3lPVBksbM/NnYSGjnPqMd3jHMfxj6D2cNse8ZZ+YQGlOfGSKCX+wtMAr3cX0OaQWEQiMXasGhVo6zJ8iwfowdTto+EECOt8H3+LoJfz9WMUM88YW/Y9jkSxqreCUMutJN880TgyzkIL12giakbqnvDstdfYdttf8XiiWxchea3ZyG6ZrlQH2o8GFy53oNAKCor7oG9WPlAG5UPlAVRpcFL17Ay7BF5pUjyLduHFAFDouUyDd8BOrbDW1fibM/QaazuCxMvfaunzCiJeOXzOX4/JbTwB7Sy34eRVUvRFpZXojVdVrZDjoNj/6PT7a75fiKyUlP5QO0uc/30KxFjglUlm3X/I1ByyElKutC0bSm/30xDWWbY8zPLDCvFDwdXff+/hPGL1G1E4/SrhdnrMJRvn6sd8+r8M+73ou6W8zqfSvu1yDVM26kGOorISs0rJvDKCdSUI9Dwj6mIblS2CoNa/wf487PGmTcqByvXLev1TIg3CqYRO7FnmDvDQPfmcn1FKX4NE/B9/g7874n7Dpdoqq4Lb4Zp8KhEl4Sfa5hxNaKbNwq322FQX9kDldc+1HFIP4kAEVCJAAn0VAJNbogAEUhO4Ob5C5N3oKuaJ3D72NGaj5ECJAJE4A8CqzZ44A/KE7z0Yxn0SlkmPWrdEIjH4f9mLoI/fK74TddEEegcpTDvyoR5LOuv3lmRqEvBnwuvXYrAd58g9NM3QFxe+R8pME0jdoCFifIsO+wuZXhaY2IsC5L/y/8i8NXctPrzTroyF+JN7rT7m8aMg33yETANHJH2mHQ7RphQawkTbMlpOqYoHj2kXI4JGqsigY11LXA3h2R57FFuRZXLKsuGVgbzDPLNLyu7+9vQqy8MA4aheOBIFA9hIj72+4Na/hFoaw0h8OP/EPxlnnCxdia01HpQnElMUvsuZhteomzji5zGM37yzJ/UtEeg+Z3n2IabjxQNzNCjFyqmPKioDy0blyKcy1WBXvs6xKJwz56J8G8/Cl0W826T4Tz2QqE2tWZMynuFzyGffudksiZ0vycTWtnrW3fb+Yj7mhULgG/UdB53kWL2uxpWej5d/Wn92NC7HxPwjIFp2A4wD2OJRXQ6rYdM8RGBvCDgfXdWRvdAM520zmxB1Z2zMh0muX/zO7PakwBINpBiIK8aWHXX8yl60WUiQAREEyCBnmiiZI8IEAEiQASIABEgAhonIKJkpNNRjL7VhVkqNdPl5Snpg/O/QevCH5nwSV72wlS+zTvvjuKdJsIyZrdUXen6nwTaWoMI/Pw1Wn//DuFlym4YMPTpj+IxE2DdeVJ7BivhixAJg2fo4O+51qW/sHK+v2bkgt9ocl1+F5rfeBqRlYszGmvoNwjFrERL8aBRMPTsCx3LcC23icj+QCW55a6CuuNFlIy0FOsxpF+ZuoEr5M391B2Kfy51Dd3QdyDL7jAWltG7skzyg7pepuMcIxBlvxP88z5AcN4nmojceeZVMI+eoIlY5ATR4g9jdY1Xjol2YV6+leSWBURjg5UqS9p1mq7L72TVOoZ0PV0Qx1JEVzkt0PtzVb1zXkTgi/eFrjEvT+Y8+bK8KiPeGZCU9wofX4gCPREbnDi70YPLmZ6IlU6gphiB2utOAaLyNs4mC85x1BmwTTo4WReh19zP3o3w4t+E2swlY3zTk3HgcJjY/ZBiJszT2UtyKXyKlQjkDQHPq4+wjdjzFJuPcdBwlF90m2L2uxoO/vQFml99vOtpocfV981mlRVo05hQqGSMCKQgQAK9FIDoMhEgAkSACBABIkAE8o1AqDWK5es8sqZVxLNSsZu2vNwttfQJRDasQuuK3xFevQTRdatk7Zjmu9z0vfvDyDIfmVjWI/OwHdMPhHomJBAPBZiwbT7CqxYhwsrBRmvWA23Sy23yUgHGvoNhHDSyfde03lWV0K/Uk94PXkHo20+FlVPuEE7EvG40Pnoz4u4GqaFtHWcysV3jY+A6Y+rWc2m+ElHetneVHa5Sc5oeqVu2CbSxZFQLVzaA/5TT8qHMbWTTWjQ+cK0cDELG2g48Gtbxk5mouIcQe2REHQLRhlq0fPoWQj98qY7DNL2YRo2F66zr0uyt3W4iyttWlFnAS9xS0y6BzTecrngJaOvkv6Lk8NO0C0HByKSIrvJBoMeR+ud9CN/bzwun67rsdpj6DRNuN9sGGx69iWV/XZFxGIUo0BOxwcluNWJgb8qonPEbLpMBLIN/7dSTMxmRcV/n2VNhHjku43FSB3jeehqhbz6VOjznxpmGjISh/1CYBjBR3oARbIMifafLuUWkgPOSgPv56Qgv+FmxuZnHT4LzxEsVs9/VcHj1YrgfU1YQWHX7M9BZ5W+y7ho7HRMBItA9ARLodc+GrhABIkAEiAARIAJEIG8JLFvbhNawvLKePIMez6RHTTqBmNeD6OYNiDbWItbcgHhLM9oCfrSxTGiIsfXhZTCMRujMVuhsJdCXutpFEsaq3spkYJM+lfwcyVRCkdq1iNZvQsxdhzhbr7jfhzjLuodohM2ZqYj0BuhMZhSxmxk6hxP6sgoYKqph7NEPRSwjnVLN/fwMdtPpJ2HmHcedB9uE/bbYi9SsRuOD1285lvtCV16JquvTL9UZZp9PS9nnlNw2cqALBgP7f0QtZwis3eQDz6Qnp/ESt7zUbS43pUuZZMqGC6usux8A86hdMh1K/VUm4P3wVQQ+eVdlr+m7q7huZvvvyfRHaK/nopWNiMXlKYkH9S6BzWrS3uQooi0E3C/cj/DvYsuRbjH+5wud04Wqm/7Z9XRBHEsR6Bn6D0LpMednxEeq2F1pcZdSWRpLT7kUlrGTMmKk9c7uZ+9hmbkyywzO56T0GmqRm4gNTr0qbSh3Kvd3rBa5qR5TuBW1TASuZHNdclu7eExJH51te9+fjcBnczqfypvXvFytoc9AtvlyCBNBD4Gx18C8mRtNhAjkGwGls3laJv0FpUedrRo2NTZuVt3yRPv9bNUmRY6IABEACfToTUAEiAARIAJEgAgQgQIksKnBD767Wk5z2EwY0IvKNshhSGOJgBQCosVzJSdcCOsuk7cLJVKzBk0vPIh4Y91216ScsO55IEr+dlZaQ+vcAWxuDKTVt7tOdosBA/s4u7tM5zVKoMkbAs9OJacVG/UYNiC3y9zW3XMp+79XLweDImMNfQbANvkwWHbeUxH7ZFQegYYHp/yR/VWeGUVH2488Ffa9DlXUh5LGm5mAeB0TEstpBr0OIwe55JigsSoQCPzwObyvPam4J+fZ17IsRzsr7kdrDqQI9NScgxrirggrQ944/Wrh07IdchwrsThauN1sGWz5+N8IL12QsftCK9nGN2DyjZhy2wi2wclIG5zkYkw+PhxiAr0zkveReVVtgZ6P/T/1z31TZtTZHc6z4Omr2WbYnqxcbc8BMLK/e0y9B/+xcTa7oZF3IkAE0iSgdAY9tbNfR2rXofH+zCuSpImrvVvlzU9AX0L3TjNhRn2JgFwCJNCTS5DGEwEiQASIABEgAkQgBwkEghGs3NAsO3LKTiUbIRkgAhkT8PzrUYR+/DrjcV0H6FhGxpLjL0haHplneWx+9RGEly/sOjzjY32ZC5U3ppclZjl7uBSSmeWzJ8v+UEHZHzJep2wPiMXasGhVo+wwBvUphc1ilG0nKwZYBtXaa5UteyV3XsaBQ2H7y7FJPz/k+qDx6RNo+eo9tLz7UvoDstjTvMf+cB59bhYjkOdaRJZPXnqdl2Cnpm0C8UAL6m4+R/EgzeP2gPOkyxT3ozUHJND7c0ViUbhnz0T4N2WzNWpt/dWIp9BKtvHNTXyTk5xmYxucBtEGJzkI0xubhwI9/3efwPfGM+nNXwO9jINHQl9ZDUNVL/aPC/L6sooV5RqIjEIgAkRADgGly23bjzgZ9r0PlxNiRmNJoJcRLupMBHKGAAn0cmapKFAiQASIABEgAkSACIglsHSNG+FIXJbRnhVMAFNG5U9kQaTBRCBDAmJKNhTBfugJsO97ZErv4RUL4HlpJivvKy+rmc5qQ9Xtz6b052cC4lUCBMQjBrDsD0Yqb5sSuAY7rKnxwudnpb5ltJwWwOSAQK9jaczj94Tj0FNox3UHkCz89LzxBELf/S8LnqW5NE/cD86/nydtcJZHxWJxJiB2y45iIMtAbWeZqKlpn4D7qTsQXiZ/k0KqmVbd8Rx0ltwuzZ5qjl2vk0BvWyLeOS8i8MX7256kI1kEKm96FHpnhSwbuTSY7u/k0GrloUAvvG453A9P08Qi8PLx/J+ebUjknwF6VyX71wP68h4wllcDer0m4qQgiAAREE/A/+3H8L2Z+r6jVM/O825QdZMiCfSkrhSNIwLaJkACPW2vD0VHBIgAESACRIAIEAHFCIgoc2sp1mNIv9wuI6gYYDJMBBQi4J37GgIfvy3EeqpMRv55H8L39vNCfBn69EfFFfeltLWxrgXu5lDKfsk6UHnbZHS0f01EmVs+yzFDylFUVKT9CSeIUOvCha4hO445B7bdD+h6mo6VJBCNwP38DISX/KakF+G21c46IHICDZ4gNtX7ZZmk8ray8Kk+2P/NXPjemqW431wv/SwFkNZ/z6lR4rYrN5Hfu7vaLsTjyusfahfkFMLcW9jGltVsg4vcRhuc5BJMc3weCvT4zOtuPRfxFl+aEDLrZhgwtF1wV2S2QFdsQftPix06ewmKbCXQO0rZPyc7Ls3MMPUmAkQgrwjEGmtRf88VisypyGRCj7teALvJpIj9REZJoJeICp0jArlPgAR6ub+GNAMiQASIABEgAkSACEgiEAixMrfr5Ze5HczKCFpztYygJHI0iAhkn0DtDacBYXkZxjpmYdpxV7hOu7rjcMtP3z8LtDcAAEAASURBVCdvwP/hG1uO5b5wnj0F5pHjk5ppa2vDghXyy5v2YuVty6m8bVLWWr4Yj7dh4Ur574M+rIRkGSslmYut+e1nEZz3cU6Fbh67O0qOOgs69pCMmrIE4n4fE+dNR3T1cmUdKWC9YuoDrJRYbwUsK2/y9+UNsp3kdHZP2bPPPQPxlmYmODhflcCzIQhTZWLdOCGBXmIwocW/wPNs6g0tiUfT2c4Eqme8qupD9M6+1X69vtYHj69Vlls7u6czkN3boaYCgTwV6DW/8xyCX38kHKCh3yBUXHa3cLtkkAgQgfwk4H7iNoRXLBY+OfOEveE87iLhdpMZJIFeMjr5cc39jDK/31zn3JAfgPJ0FiTQy9OFpWkRASJABIgAESACRCAdAsvXNiEUjqXTtds+XPzARRDUiAARUJdA7fWnApGIEKddRXq+z96G//3XhNhmT8Zg3etAlBx5Zkp7PHMez6Ant40c6ILBQOVt5XLM5vi1m3zwtsh70GizGDCojzOb05DsO9qwCQ33Xil5fDYHlp5yKSxjJ2UzBICVCY556tk/N2ItTe3ZPOIhP9pCQbSFW9EWZQLnKPv+0xb/4+G9jn1e6A3QGYuB4mLozFaWmcPGsnA4oLc7WQnfMlYiqxzQZb8kVqxxM8sKcHl2+Ur0bh4/Cc4TL5U4OrvDRJVfH8TEDzba2JLdxczQu/uZu1imyt8zHJV5d+f5N8I8dIfMB+boCBLodb9wkbqNaJy+/eaZ7kfQlUQECkX0Kqr8ei92T6c8Rze2JFp/TZ/LU4FezM2+o94t/jtq6cmXwLLznppeUgqOCBAB7RAILfoBnuceEB5Q+dX3wdizv3C7yQySQC8Znfy4ptTfRIXyPThX3wUk0MvVlaO4iQARIAJEgAgQASIggECdO4DNjQHZlkYPLodOp16Kd9kBkwEikCcEvP95AZH1K9tFJm3RKOKhAOKNLMMPF51k2CyT/oLSo85G4Mf/wfuvJzIc/Ud3ndPFsmcxwa7BCNOQMYg3NcB+yAkwlFWmZU9EdiKHzYQBvSiDV1rANdypmWUBWceygchtQ/qWwmI2yjWTlfH+bz+C783nsuJbrlPTjhNQetgp0Luq5JpKPp494AxvXIPIprWIbl6PWF0NwssXJR8j86px0HDoq3rB2KMPDD0HwNirP3RWdTYqhFcsgPuJO2XOIHvDc/km8YbNLeDlt+W0YqMewwaUyTFBY7NAwP/9Z/C9/pTins1jd4PzlNwUZkuBo9TDKCmxJBqT9c+rWBTu2TMR/u3HROHRuTQIVN3xLHQWWxo9c7tLfVMQtQ3yyq9zAqMGlUOvp3s6qrwb8lSgx9n5Pv43/HPfFIbRNHpnuM68Vpg9MkQEiEBhEPC8PBOh+d8Jm6x138NQcugpwuyla4gEeumSyt1+Sv1NlPW/ZXJ3SVSJnAR6qmAmJ0SACBABIkAEiAAR0CaBMMuet5Rl0ZPberJykhVUTlIuRhpPBMQQiMcRXPQjgj9/mfFDPetfjkLg0/8A8fQzaxr6D4Zll31g2WECyzYlvSxSIMjKbm+QX3a7b7UDTgfLgkUt5wksWtXIEqG1yZpHrpeTVEsYIgtyksH8RrZ9nyOZcNeRpFf6l/gN6vCqxYisXcbEyauYIG9T+oMV7skzkZr6DYGp/3CYBo4Q7s0/7wP43n5BuN3uDJpG7gRdiZOJG+woMrHPVJZlsI0JRtDainjQj7ivKe2sYqbhO8B58uWqCRm7m5PU86KyE1W5rOhRbpUaBo3LFoFIK2pvPCuj70ZSQ6288RHo09zUINWHVsYp9TBKxPwM1X1Qcc39IkzJtuGd8yICX7wv204hGqi49kEYKnvl/dRFbHAqsRejf08x39XyHriICeaxQI/jcc+6D+GFv8gmpXNVoOLSu6BzSL/HIDsIMkAEiEBOEmhrDaLx4RvZJr4a2fGbho6G6/xpsu1IMUACPSnUcmuMUn8TkUBP2+8DEuhpe30oOiJABIgAESACRIAIKE5g9cZmtATkl8ncYWiF4rGSAyJABDIjENm4Cr65ryO8aH6aA3nWhPQFUaWnX8GEebunaTt5t/W1LfD45GUn0rNMnqNYRk9q+UGgpt6PRk9Q9mTyISOI77O3EF76OyIrF7fzMA4eiSKWrVJntqDIaEaRwfBHqVYm0I1HWWngYBDxgI+NWSCbnwgDlkkHwDJ+MhOwDU3fXFsbwquXoHXNEkTWLM3gcyx9F0r2NA0dBeOgUSgePAom9lNq4wxa+Of4CuUyA/LsJMWstKZp0EiWEXBgZqGycsLhmtWI1LAshjUsmyH/uXrZH1kGe/dD8U4TYRmzW2Y2NdZbVMbpYf3LUGzKfplkjeHNiXA8sx9C6JdvFY81W9k5FJ9YAgfuJ+9gGU8XJriS/VPmXfaE84RLsh/InxH4533IBNrPayaeXAmk8ubH20vU50q8UuL0trRi7Sb5Gae5OI+L9KipRCDPBXpgf4+0l4dfJv0znmfmLztrSubfS1VaQnJDBIiA9glE62vQ9Nx9iNVvlhysceAwuM65HkXFFsk25AwkgZ4cerkxlgR6ubFOoqMkgZ5oomSPCBABIkAEiAARIAI5RoCX6+Jlu+Q2uqkrlyCNJwLKEWj56j20vPuSMAfmifvC+ffzhdmLRuNYvNot2145y+TZi2X0pJYfBIKhCFasl59VsbrChsqy7NxQ1cpKtAVaEG2qY+KpdYhsWInIuuWIrl+jenj6qmqYmBDMyIR6BlYmVu9wssxsTFwYCSHW3IRIwybENq1DyZFnQKkblapP+k+HfOe9cdAIFA8aDRMT7aVqvJxt4P8+YaIgcaV5OvvkDxssE/aDdedJ7WXJO1+j19sSEJGdyG41YmBvygCzLdncOQot/gmeZ2eoEnD19NnsczH/hZx+9vnm+/czqjDN1Inz7KkwjxyX6TBF+4cW/8Leg/cp6iOfjHNxT9VN/8ynKSWci4jNlkaDDiMGuhLap5MKEch3gd6f2DxvPoXQt59lDJF/Zy49/kLonbQJOGN4NIAIEIFtCMRbmuF5/XFJm/3Mu+4N5/EXbWNP7QMS6KlNXH1/St33ogx66q9lJh5JoJcJLepLBIgAESACRIAIEIE8JMAS1ICXEYzH08+alQgDPXhMRIXOEQHtEAixsree5x9kJdrisoKyHXIsHPv/XZaNroNrGwOodwe6ns74eEjfUljMxozH0QDtEli53oNAiJXVlNkoy+v2AOOhAFqXzUfr4vkI/fDl9h3ojOIE+E1/fXkVK/3KysoVFbVnPYxt3ojQz98o5ts0ZCSskw9j4pPxivnIJ8MetpFlvYCNLH162FFWYs4nNAU3l7q7Lka8qVHxeduPOBn2vQ9X3I8WHDQ8Og3RNcu1EMqWGExjxsN1xpQtx1p6EanbiMbpV2spJM3GUgjZKEVtZOGbWPhmFmoqEigQgR4nygXu/s/eQWR16s96XXklbHsfCtukg1VcDHJFBIhAIRDw/9+nCHwxB7G62pTTNfQbBNu+RwirFpLSYZIOJNBLAidPLpFAL08WMsNpkEAvQ2DUnQgQASJABIgAESAC+UhAVBlBEsfk47uD5pRPBEKLfoDnuQckT8n6l6NQctDxkscnGshFwgtWNCS6lNE5q9mAwX1ZNi5qeUWAl7jlv6Pktr5MHOMkcUxSjMHfvkXwxy8k7S5PapguaoZA6UkXwzJuL83EkwuBiBAJU/n1XFjp1DF6P3gVgU/fTd1RQI9CyXgQc2+G++m7ZZUeE4B7iwnDgCEoP/cmVsZMw2LaWBTu2TMR/u3HLXHTi20J6MrKUTWF/b1j0vA6bhuypCNeBYFXQ5DbqPy6XIISxheQQK+DTnjtsnaxXnTdCsTc9Yg11EFX5oKutBzG3gNQPGIsbR7pgKXWT/b7BPxmDM/aq9Op5ZX8CCYQa9yMwPyvEVm1GDG2kaSt9c/fC3o9DGwjmGHAcFjZ33+Gyl6yPUc2b0hpw9ijT8o+2ewQWjIf4aXzWVWBVYh5WLICxoyLgw1l7F+/we2fQ6aBI7IZ4ja+SaC3DY68PCCBXl4ua8pJkUAvJSLqQASIABEgAkSACBCB/Ccgave101GMvtWO/AdGMyQCOUyghe0abZnDyqdl2Ew7ToDrtKsyHJW6ewMTYG0SIMDqXWWHqzS/H8Slppl/PXh2V57llT87kNNIwJk+PX6Tn5ceDHw2J/1B1FPTBExjxqH06POgLyERcyYL1eIPY3WNN5MhCftWsPLrPan8ekI2uXQyykpwN9x7pSohO449F7bd9lfFV7adxFkJdu+7sxD6aV5WQ7FMOgClR52T1Rgyce6d8yLLBPN+JkMKoq/OaoPzzCnQ0sN1JcBHInEsWeOWbZqqIMhGKMlAW2sQm288U9LYdAe5LrkNJibMoVa4BMLrVyBSsxYxJqqKNtYi3liHeIsXcS7gikS2A6Pj4nSrlYkmXTBUVENf2RPG6n4w9hkEPRNSUtMWAS4u498FIkt/B8+Mn6zxtTUMHoGSI05na9szWddur9VPv5Jln9vU7fWOC85zroOZCW6piSGgjkDvcXafoExMwGQlYwKpBHq86oJp8KiM7Vp32SfjMTRAPQIk0FOPNXkiAkSACBABIkAEiICmCaze0IyW4PY3aTINenj/MphMbAcmNSJABDRLwP3UHQgvW5hRfFW3PAmdozSjMel0XsoeLoXZQyY5jWcnGjmonFeIpJaHBDbWtcDdLD9DyIBeDjhsxXlISJkpxbxNaPn0LQTnfayMA7KqCgHzxH3h/Pv5qvjKNydrmDjPx0R6ctuwfmUoLqbvxnI5amG8+9l7EF78q+KhGKp7o+Ia6RmPFQ9QAQcxdx1Cy35lmZXqgLi874Vph8ezy7AH1cXDd85JAXOAZb31/uvxtKeb7x15eeLSw09jpeN75PtU2zc38U1Oclu/ng6U2um7sVyOmY6P+32ou+XcTIdl1L/8irvbhVUZDaLOOU0gsmEly1L4M1qX/srKx68QPhfzuD1gGrYTzKPGQ2e1C7ffnUH303ep972guyBEnmfZCl3n3ijLYuuKhWh+9VHEm5sysqNzlMBx1Jmw7Dgxo3G+j/8N/9w3U44x7bALXKdfk7IfdUifgBobhCpveBh6V1X6QVFPoQRSCfQKaeOWULAaN0YCPY0vEIVHBIgAESACRIAIEAG1CHh8rVhf65Ptjmew4pmsqBEBIqBdAuE1S+F+9Ja0A7QdeiIc+x6Zdv90OzYx0dUGJr6S2yrKWHaiCptcMzReowRCrVEsX+eRHR1lCZGGkJek4rvzlXjQIy0iGpUuAesBf0PJwSek2536dSIQYJtWVrLNK3Kbw2bCgF4lcs3QeI0QCP7+HZpfmKlKNCUnXADKfKAK6px3El6xAOGa1VvL2uX8jLadAN8wEGeZgoz9hiCybjl0znImqHT90YntztGx18WDRkrOCrStN+0fxWJxll1afvY8k1GH4QP+5Kj9aedVhDGvB/W3X6DonMqnzICxR19FfZDx7BOINTci8P1nCP7wBeLuBtUCMo3YEZZdJsMydpKiPtXINqnoBLoxXnrGlbCM2a2bq8lP83t5nlkzEPdLu4+mM1vhOOH8tP1HNq9H44wpyYNiV3UsUzsXBm/5/ZxyBHVIh0DM04D6Oy9Jp6vkPhXXPiikBLLkAAp8IAn0CvMNQAK9wlx3mjURIAJEgAgQASJABBISWLLajUhUfsaCEexGr5Hd8KVGBIiAdgm4n7kb4SW/pRVg9X0vA3pDWn0z6bR8bRNC4VgmQxL2HcYydxZT5s6EbPLl5OqNLMtrQH6W14G9S2C3mvIFi6rz8H32Nvzvv6aqT3ImnYD98JNhn3y4dAMFPnLtJh+8La2yKfRn2YlKKDuRbI5aMlB3z6WsTFy94iEZevZBxdX3K+6HHBABIpBbBGobA6h3Jy9nmM6Mqtnmpkq2yYma+gTivmbU3aZsduPya6a3lydVf3bkUQ0CvOyl/4s5CP3wlRruuvXBM7JZ9v4rHJOPYAot8feA20KsHPRNypaD7nZyCl6QKtCL+71omHkd4k3yRNq8Mkb5ZXdCX1aZcpYN91+NaO3GlP0cx50H24T9UvajDpkR4Jml6+++LLNBGfauvP6hgsg+nCEW1bqTQE811JpyRAI9TS0HBUMEiAARIAJEgAgQgewSqGM3ejezG75yW7nTgl6VlM1KLkcaTwSUJBD8+Us0v/LPlC7ME/aG87iLUvbLtEOTl2XP2yxt129nX1z4wAUQ1PKbABfKcMGM3EZZ9OQRjGxcBe87zyOyepk8QzRaUQLV9/9LUfv5bjwQYtnz1svPnmdmwvGhTEBOLb8I+D57i4mVX1dlUvSwUxXM5IQI5AyBWKwNi9mmyra2NlkxF7HRIwexTIR6/oqa6gTCIdTecIaibl2X3wlT3yGK+iDj6hOIB/3wffgqgvM+Ud95Eo86qw22A4+Bbc9DkvTK/BIJ9LZl5nnrGYS+EbP2xTvthrJTr9zWQZcj3//ehf+/r3Y5u/2hadRYuM66bvsLdEY2gcimtWh84FrZdpIZqLr1Sejspcm60DUFCZBAT0G4GjZNAj0NLw6FRgSIABEgAkSACBABtQm03/Bd1Qh5t3v/iJqy6Km9euSPCGRGgN/crZt2dspBpaddDsuOE1P2y7SDqOx5lBEtU/K525/eM9pZO98nb8D/4RvaCYgi2ULAdcltMA0YvuWYXmROQFT2PL5ZhW9aoZZfBOKBFtTdeh4Ql591PBUZfWUPVF77UKpudJ0IEIECISAqe155KdtQWUUbKrP5tkn1QF5ubK6LboGJlX6mlj8Egj9/xTZYPqbpCRn6DULFZXcLi5EEeltR8u+fDTOuQtzn3XqyyytdsRlgYkmw8u8IBhBn/7prXFRZftV90DsrEnaJ1tfA/dgtiLck3ySZSTa+hI7oZFIC4bVL4X7klqR95F6svudFwEhVJuRylDo+1fcB0467wtQvfcG9fZ8jpYZC41QkQAI9FWGTKyJABIgAESACRIAI5AKBmno/Gj1B2aG6Ss3oXWWXbYcMEAEioByButvOS3qDj3uuvPmf0Je4hAbhbg5hY5387Hk2iwGD+jiFxkbGtEuA/27iv6PkNsqiJ5fgH+MjG1bB98ErCC9dIMYgWZFFwDRmHJwnXAKd2SrLTqEP9gcjWLVBfvY8A8tKNGJgefvzsUJnmo/z97z5FELffqbK1OxHngL7Xoep4oucEAEioF0C0WgcS9bw7HnyYxzGsrsWsyyv1LJHINUDebmROc+8GubRu8o1Q+M1QqD57Wc0lzUvGRrHkafBttdfk3VJ6xoJ9LZiCv7+LZpf6H7ThqFHb5Qcey7bqDWifVB08wZ457yI8JLfthrp8spx5KlsnQ7tcvaPw4YHrkF004aE1zqfdBx1BmyTDu58il4LJBBa9hs8T4kTvSYKjbLvJ6Ki3jnR3we4oM912tXqTYA8SSJAAj1J2GgQESACRIAIEAEiQATyl0A4HMPStU1CJkg3foVgJCNEQDECdfdehnhDXVL7StysWbamCa2RWFK/6VzsV+1AqaM4na7UJ08ILF7lRjQmP2sRL4vMyyNTk08g+Nu38H/+H0TXr5ZvTKAF4+AR0JdXQV9RDUNZFYpsJdCzTAFFxRYUmYpRpDew7AI65rENbfw9FYsgzkqO8QdBPMNo3O9lAmYPYk0NiLEMAuFlCwVGJ9aU/dATYN/3b2KNFqi1NTVe+Pxh2bOvclnRo5zEkrJBatSAGuWmOqauc5Sg6kaWMcdg7DhFP4kAEShAApvYJpUGARspnexvp77sbyhq2SUg+oF819k4jj4Ttj0O6nqajnONQFsc7mfvTSqy0uqULHsehNK/nSkrPBLobcXneeNJhL77fOuJTq90JU5UsGx425UpDbei7rbzEW8Ndeq99aVpzHi4zpiy9cSfr/xfvQffuy9td77rCUPPPqi4+v6up+lYIIHg/HlofvkRgRa3N6XEPd/tvdCZ7giI/j5AAr3uSGvrPAn0tLUeFA0RIAJEgAgQASJABDRBYP3mFni8if+AzyRAuvmbCS3qSwTUJ1A//UrE6jYldSz6Zk1DUxCbGvxJfaZz0cyyPgxl2R+oFRaBOncAmxu7L9WSLg2r2YDBfSn7Yrq80unHhXqBeXMRWbkkne7C+hj6DoSh7yCY+g6BkZX+MFb2AnQKZYWJhBGp24go+xepXYfImuVsvouFzSVTQ+adJ8Jx8PFMiFid6VDqn4AAF+ZxgZ6INmpQOfQsix61/CXgfn4Gwgt+UmWC1v2OQMlfT1LFFzkhAkRAewREbqIc3KcUVgsJfrO9yqIfyHedj/WAv6Hk4BO6nqbjHCPQ+Pitqv9tJRKRecLecB53kWSTJNDbis791B3dbhgzj5sE50mXbu3c6RXPohf44v1OZ7a+5H9HV1x+z9YT7FXMvRmNj0xLWWmDbyBxXXwbDBU9txlPB2IJ+D55E/4P/y3WaBdrou/5djFPhykIiP4+QAK9FMA1cpkEehpZCAqDCBABIkAEiAARIAJaIhAMRbBivfzyXnxOdANYSytLsRCBbQmkLFthMKD63pe3HSTjKB5vay/NFIvJr83ES2jzUtrUCosAfw8tXNkoZNJ9ethRVkLvISEwOxkJr1uO4E9fKFaGyTRqLIwDR6B44EiY+g9jWfCyL4KKbFiJ8JqlTLC3DKH533WiocxL0467wL734ayE0XBlHBSo1ZXrPQiEorJnX1FmQc8Km2w7ZEDbBFpXLETTE3eoFmTl9Q8xMW4P1fyRIyJABLRDQNQGSofNhAG9SrQzsQKORPQD+a4ozbtNhvPYC7uepuMcItD04oNo/e37HIo4cahyMumRQG8rU/eL9yP8249bT3R6lWwjh2/ua/B//Han3ltf6iqqUHXdw1tPsFfuZ+5OK2Oj7bCT4NjniG3G0oF4Ap5/PYbQj1+JN9zJIgn0OsHIwkvR3wdIoJeFRZTgkgR6EqDRECJABIgAESACRIAIFAKBdZt8aG5plT1Vu9WIgb1LZdshA0SACIgn4Hntnwj98GW3hnXllai6Xlw5hVqWOa+eZdAT0XYYWiHCDNnIQQI8gx7PpCe3mYw6DB/gkmuGxichEFr6K7vB/wvCqxYhunFdkp7dXzJP3A/G3ixDHs+O12tA9x01dIVn1wsz8U7rqoXdPkjJNFyd0wXz2ImwTGA8qnpnOpz6pyDQxDJHb2AZpEW0kQNdMBh4+WRq+U7A/eTtCC9fpMo0zeMmsuwol6vii5wQASKgHQKBYAQrN4jZPDmwdwnsVpN2JlfAkbhffIB9R/xBMQLGwSNRfuEtitknw8oS8H30OvwfvaWsExWtO/52Omx7HpKxRxLobUXmfvpOhJcu2Hqi0yvTjhPgOu2qTme2vmx++5luN851zaDn/+5j+N54duvgbl4Zqnuj4poHurlKp0USaHxsGiKrl4s0uY0t48BhKL/49m3O0YG6BEigpy5vrXgjgZ5WVoLiIAJEgAgQASJABIiAxgiIzKLXr9qBUkexxmZI4RABIsAJ1F53KhCNJIRRcsIFsO6yT8JrmZ4UWZqpF8ueV07Z8zJdgrzpzzMwLlolJotej3IrqlzWvGGj6Ymwz5lwzRpE62sQa2pAW4sX8TAT7PKEmkYjdMUW6Oyl0DvLYdlpD01PJdPgeKmg8NrlaM8u+NXctIebhoyCgd00Nw8bCxPLGkhNOQJL17gRjsRlOyh3WtCrkrLnyQaZIwZCi3+C59kZqkXrPOc6mEeMVc0fOSICRCD7BFZvbEZLIPHfaplERxsnM6GlfF/vey8j8Pl/FXVEWZEUxauYcZ6V2/1o/okry6++D8ae/TPiRgK9rbg8bz2F0DefbT3R6RUvN1t+6Z3Qu6o6nQXiLc1o+Mf1iDe7tznfccCzsrtOu6b9MOZpQOPDNyLuTS4I19lYFYKLb2Ubxvp0mKGfChIQLd7qGqp5933hPOb8rqfpWEUCoteYMuipuHgyXJFATwY8GkoEiAARIAJEgAgQgXwnICqLXrFJj2H9y/IdF82PCOQkgdal8+F54R9oC3fOmFkE694Ho+SI04XNaX2tDx5fZx/STBcb2efJAPo8kUYvf0aJyqLHq6MO7+9i+jDKdpU/747cmEnc14yY142Y3wdEQmiLx1FkMEFnc8BQVgmdw5kbE8mDKEV9nnAUI1j2PCNlz8uDd0X6U1A6s0XnSAx9BqDiins7n6LXRIAI5DEBjy+E9bVisrtS9jxtvVH8//cJfP9+RtGgKqc9Bn1puaI+yLh4Ag2P3oTomhXiDWfZomnYaLjOm5ZRFCTQ24ortPB7eGY9uPVEl1d6Vq629MRLYOo9EGA3OXhGd8/sRxCr29Sl59ZDx1FnwDbp4PYT7ln3Ibzwl60Xu3llO+gYOP5yTDdX6bRQApFW1F4v7p5sotjsR54C+16HJbpE51QiQAI9lUBrzA0J9DS2IBQOESACRIAIEAEiQAS0REBkFj3KUqSllaVYiMD2BPxfvQfbXofC++GrKDn4xO07yDjj84expsYrw8LWob1Z9jwXZc/bCqRAX8XjbVi82g3+U24rKzGjTw+7XDM0nggQgRwkIDK7a0WZBT0rKHteDr4NZIWc6oGpLOMJBtsPOxH2fY5McIVOEQEikG8ERGV3ddhMGNCrJN/w5PR8wisWwP3EnYrOwXn2FJhHjlfUBxkXSyD46zw0v/SIWKPMGs+UxrNxG6r7w1jeA3qWtRymrVVO4oEWtnGoCdGGGkQ2rkF4xUJEVy8THofzzKtgHj0hbbsk0NuKKh4KoOG+K8E3eSVrPJseb3Ff8vtvOpsN5VfNYCJeFwI/fQHvq48nM9t+TV/VE5VT/5GyH3UQQyC8egncj90qxlg3VpznXg/z8J26uUqn1SCQSqBnGrEjDL3Szz5a8teT1QibfMgkQAI9mQBpOBEgAkSACBABIkAE8p0A37HNd26LaCMGUJYiERzJBhHINQIr1jUh2BqTHbaZZeMcStk4ZXPMFwN17gB45isRjbKKiKBINohA7hEQlS2aZ+McybLn6fWUjTP33gXyI2587GZEFHiQ3V1klTc8vF0Zs+760nkiQARyk4DI7K6D+5TCajHmJog8jTrW3Ij6Oy5WdHa2Q46FY/+/K+qDjIslIDJ7nqH/YNj2PASWnfeUFGQ86Efw5y/h//oDxOvrJNnoOsg4cCjKL76j6+luj0mgty2a5nefR/CrD7c9KfHIPG4POE+6rF2Y2fjQDawMblNKS1LKFKc0Sh26JeCd+xoCH7/d7XURFyqn/bNdpCnCFtmQRiCVQM9x7Lmw7ba/NOM0SrMESKCn2aWhwIgAESACRIAIEAEioA0CreEYlq1N/Yd6OtE6HcXoW+1Ipyv1IQJEIE8I1DcFUdvgFzIb/vnBP0eoEQFOoI0lz+OZRSLRuGwglmIDhvSjkqKyQZIBIpBDBLwtrVi7ySck4iqXFTxbNLXCJBBa/BM8z85QbfI8E47rtGtU80eOiAARUJdAqDWK5es8QpzSPRghGBUxkuqhvFynptE7w3XmtXLN0HiVCEQ2r0fjjClCvJWefIlkYV6iADyvPIzQz98kupTxuUxEXnIFesZBIzKOT+kBRXo9XOdnVuq3IyYummz4x7WIuxs6Tkn6qStxovzyu9uFWe4XH0D4tx9S2rHufwRKDjkpZT/qII5Aw6PTWLnr5eIMJrBUff+/EpylU2oSSPVdgAR6aq6Ger5IoKcea/JEBIgAESACRIAIEIGcJVBT70ejJygk/v49HSixk8BGCEwyQgQ0TiAciTEBlRiBr81iwKA+JKDS+JKrHh7/3cR/R4lo1aw0ZSUrUUmNCBCBwiCwjP1+amW/p+Q2g74II1j2vCKeRo9awRJwP3UHwssWqjb/khMvhHX8ZNX8kSMiQATUI7CmxgufPyzE4VC2AcXMNqJQ0x6BVA/lRURM4gsRFNWx4fv0Lfg/eF2WM0Pvfig7cyr0zgpZdhINjtSsQdNz0xH3uBNdTvuc9S9HoeSg49PqL1egl4/v//D6FfDwdUhRwrY7wDqrDaUnXYriEWMR/O0bNL/4cHddt5zXV1Wjcso/wP7Y2XKOXihLQO57P93o8vH/SLpz10q/VN8FSKCnlZUSGwcJ9MTyJGtEgAgQASJABIgAEchLAlGWnWgJy1LEsxWJaGOGVNDf9SJAkg0ioHECPDMRz1Akog3oVQKHzSTCFNnIMwLLWZbXEMv2KqINZyWUTayUMjUiQATymwDP7MozvIpoPSttqHCSuFcEy1y20bpiIZqeSL9sm4i5Vt3+NHRWyk4ugiXZIAJaIdDUHMKGuhYh4ZSXWtCryibEFhkRT8D93L0IL5ov3nAni66LboFp0MhOZ+ilVgk0Pn4bIisXSw5P56pAxRX3su8Fdsk2Ug2M1G1E4/SrU3VLet3Qpz+L876kfTouyhUp5av4KLx2GTyvPIJ4Y30HqrR+8sx5pcedz8R5OyPe0oyGmdenJbgsv+IuGPsMTssHdRJDIPj7d2h+YaYYY91YMe+6F5zHX9zNVTqtFgES6KlFWlt+SKCnrfWgaIgAESACRIAIEAEioFkCde4ANjcGhMTHH2Lyh5nUiAARyF8CTV72cGmzmIdLPOsmz75JjQgkItDsa8W6WjFlKrkIlItBqREBIpC/BALBCFZuaBYyQTMT9A5lwl5qRIATaHrpQbT++r1qMMzjJ8F54qWq+SNHRIAIKEsgFotj0Sp52ak6IuRZXUcMKIPBoOs4RT81RsD7/mwEPpujaFTWfQ5FyWGnKuqDjIshUHfjGYi3hiQbc55/I8xDd5A8Pt2B/u8/g+/1p9Ltvn2/Ih2qZ7yy/fkEZ0iglwDKn6fivmbwz5Dwwp8QDySvKKCzWGEcNgYlh5+2JbuiZ/ZDCP3ybfcO/rxi2fsQlB5xesp+1EEsAc9bTyP0zadijXaxZj/sRNj3ObLLWTpUmwAJ9NQmrg1/JNDTxjpQFESACBABIkAEiAARyAkCS1kWvXAkLiTWQb1LYLNSNiwhMMkIEdAYAZEPl/jUqDSTxhZYg+Gs3tiMlkBESGS9q+xwlZqF2CIjRIAIaI/A78sbhAXVj4nHS5mInBoR4AQim9ai8YFrVYVBpW5VxU3OiICiBNbXtsDjky7Q6Rxcj3IrqlzWzqfotcYIBBf8H5qfZ2UjFWz6iipUXpe6hKWCIZDpNAhwsVXdbeen0TNxF9Ow0XCdNy3xRQXO8lh5zFJb+ZQZMPbom3I4CfRSIkKs2Y0Qy7bWumIB4u56xIN8Y30bdGYrdGUVMLIMmo4uIqzWRT+xcsUzUhrXV/ZA5TUPAHoqk54SluAOqURbItw5z54C88jxIkyRDRkElFrryhseht5VJSMyGqokARLoKUmXbBMBIkAEiAARIAJEIM8IeFhGrPWCMmJxNDsMrcgzQjQdIkAEOIH1LJuZh2U1E9Eo46YIivlvIxBiGbHWS39I0JXQiAEuGI2UcaQrFzomArlOQGRGaMq4mevvBmXib377OQTnfaSM8W6sVt78T+hLXN1cpdNEgAjkAgH+txP/G0pEK2bZXYdRdlcRKBW1IVeUlW5wrgunwTR4dLrdqV8WCITXr4D7oZske3YcfSZsexwkeXymAz2v/ROhH77MdNiW/s5zroWZlVlN1Uigl4pQ5tfjQT8aHpyKeFNjysGuS2+Hqf+wlP2og1gCkQ0r0TjzRrFGE1irnPYY9KXlCa7QKTUJkEBPTdra8UUCPe2sBUVCBIgAESACRIAIEIGcICAyS1FFGSt1W0GlbnNi4SlIIpAmAZFCXoNeh+GsNJNOV5Smd+pWyAQ21rXA3Swm6wiVVS7kdxLNPV8JiBbyUnbXfH2nyJtXPOBDw12XsTJ1QXmGMhhtGj0OrjOnZjCCuhIBIqAlAqKzj/erZtldHZTdVUtr3F0sDTOuQnRzTXeXhZw377o3nMdfJMQWGVGGQGjpr/A8fY9k42qVt+0I0PfR6/B/9FbHYcY/S0++BJad90w5jgR6KRFl3CFdcaV5j/3hPPrcjO3TAPkEvO/MQuDrufINpbBQff+/UvSgy2oQIIGeGpS154MEetpbE4qICBABIkAEiAARIAKaJhBkWYpWCMxSNKBXCXgGEmpEgAjkPoFoNI7Fq93CJkKlRoWhLAhDsVgbeCn2WLxNyHx7VdpQ7rQIsUVGiAARyD4BkaVtaZNJ9tdTyxG0fDEHLXNmqxqi/bATYe9SwkzVAMgZESACkgmIzD5O2V0lL0NWBja//QzLuvqJ4r6r7ngWOkv2N8eG1y1DtG4TK8PpQxF00JU4Yajux8qd9lGcgdYdyBFpOM+eykpVjlNtit4PXkXg03cl+0tXGEQCPcmIEw5sXf47mp68K+G1zid15ZWoupqVwDWZO5/Oq9eRjauYOHojYn5ehaEIenspDOxzyNhrQHbnGYui9tpTFI/Buv8RKDnkJMX9kIPUBOR89iezTiVuk9HJ/jUS6GV/DSgCIkAEGIEpP/5GHIhAQgIzdtkx4Xk6SQSIQHYJbKpnKfE94rJCjB5cThmysruk5J0ICCGwdpMP3hYxpW3tFgMG9nEKiYuMFA6BRva7qYb9jhLVKEOWKJJkhwhkl8CmBvbdtUnMd1ej4Y/srkVFlN01u6uqbe8ND05BtGa9qkG6Lr4VpoEjVPVJzogAEZBHgGd/5lmgRTX67iqKpDp2Qgt/gGfWA4o7sx1yLBz7/11xP4kchFcvQeC7jxH+/UfEw4nvFeicLpjHToRtr78WZMlFuRn07IefDPvkwxPhV+Rc04sPoPW3HyTbpgx6ktFJHtjWGkI9+24ab6xPacN1wU0wDRmTsl+udYjUrIH/27kIs/du3J/4967OUYLiHSfAusfBWREOt3zJNvn8R/lNPq6LboFp0MhcW8K8jJcEenm5rCknRQK9lIioAxEgAmoQ+Nt7n6rhhnzkIIFzxo7GYb2rczByCpkI5DeBOMtOtGxtEyIsW5aIVlZiRp8edhGmyAYRIAJZIsCFD1wAIaoN7lsKq9koyhzZKSACqzd40BKMCpmxjQlFB5FQVAhLMkIEskXA62/F2hqfMPd92XdWJ/vuSo0IJCMQWvQjPM/dn6yL8GuGHr1RcdV0QK8XbpsMEgEiIJ5AazjWfl9FlOUqlxU9yq2izJEdNQjEYixb0slqeEL1jFdZoij1NhfEQwHwUo2hH7/KaH62g5mY8IDsiAkzClRgZy4canzwOskWDQOGouKSOySPz3Rg3Q2ndyu2TMeW66KbmThoVMqulEEvJaK0O3jefAqhbz9L2b+7ktixpnrEvE2I+TztNvQOJ/QlZdCXVaa0qYUO3neeY2VjP8ooFOvkv6Lk8NMyGiO3s1Jira5xpZvFsus4OhZPQKk1pwx64tdKpEUS6ImkSbaIABGQTIAEepLR5f1AEujl/RLTBHOYgMcbwvrNiXecSZkWlbKUQo3GEAFtEAiw0tcrBZa+ptKB2ljXXI1CdCn2yjILqiuyXxIqV9eD4iYC2SQQi8WxaJW40utUOjCbq5l7vj2zH0Lol29VDdw8fhKcJ16qqk9yRgSIgDQCq9imEr+gTSVmkx5D+5dJC4RGZZWAe9Z9CC/8RfEYbAcfw4RvxyjuhzsIr1+B5tkPI9ZQJ8mfadRYuE6/hgnODZLG59ygSBi118sTAqlV5lZEhq+q25+GzupIuUwk0EuJKK0O4TVL4X70lpR9dWXl7Rs9OsphxzwNaPnfHISXzkebtxnxVp4Bs+1PO6xIdXExYLOjePQuLIPjYdA7K1L6ULtDzF2HppceRHT9Gkmuufi17LSr2sWIkgxkMKjli/+gZc4rGYyQ1tW880Q4T75c2mAaJZwACfSEI80JgyTQy4lloiCJQP4TIIFe/q+x1BmSQE8qORpHBNQhILKcJY+YyrGos27khQiIJNDG7s+tXN+EYGtMiNli4x8Pl1Tc3C8kbjKiLQK1LJtjvaBylnxm/Xs6UGJnN6CpEQEikFMERH9XHc7EDyYmgqBGBNIhwB9s1t93JRCJpNNdWB/7EazU3d7qlboTFjgZIgIFREBk6XWObUCvEnARObXcI+D//jP4Xn9K+cCNRlRe/xATmrgU9RXZuBpNT96JeEBedn3j4JEovzC1qEjRyahovGHGVYhurpHlseqWJ6FzlMqykWxwZMNKNM68MVmXlNf0VdWonDozZT/eQa5Az7zb5LT8bNOJ3YgqYsLQImMxiqw26Gwl7f9n9OVVMFb0AnS6bbpr/iAaQf39V6clli07awqKR41vn5Lv0zcR/OpDxFvSy0Kusztg2evgrJXSTrQOsWY33E/chlj95kSX0z5n6NkHLvZZlI6oNG2jXTryjKN1N53V5awyhyUnXgTr+L2VMU5WMyZAAr2MkeXFABLo5cUy0iSIQO4TIIFe7q+hUjMggZ5SZMkuERBDIByJs5IsbnCBjohmNRswuK9ThCmyQQSIgEoENrBMmk0so6aoRkIoUSTJznJWij3ESoeJaAZ9EYb0LYPRmGM35EVMnmwQgRwlUO8OoLYxICx6nkmTZ9SkRgQyISAi00wm/jr6Os+7HuZhO3Uc0k8iQAQ0RKDZ14p1temJHtIJ21VqBq9IQC03CcSDftRNO1uV4M3j9oDzpMuU89UWR8P9U5jQbKMQH+Zd9oLzhIuF2NK6Ee/7sxH4bI6sMA3VfVB21lToXVWy7CQazMV5Tc/eh7jPm+hy2ues+x+BkkNOSqu/XIFeWk4y7KRzVcDUbzAM/YbkxGaI5ndnMaHd3JSz7JxVzTN7JssA/V3KMdt3KIJ5591YdrYrtr+UhTONj9+KyMolQjybRuwI1zk3CLGVyEi6JYgTjc30XNVtT7ULTzMdR/2VIRDZvF4Rw8YefRWxS0bFECCBnhiOZIUIEAGZBEigJxNgHg8ngV4eLy5NLW8INHqCqKmXtzO2Mwy6udyZBr0mAtomIPr/f1mJGX160MMlba967kTn84expkbeA4TOs7VbjRjYW7mMBJ190WsiQATkERD+/99iwMA+tIlE3qoU7ujGx25GZPUyVQHoSpwov/xu6EuVzZSk6qTIGRHIAwJhtnlk+XoP4nExuxyNBh2GseyuOl1RHtAp3Cm4n5+O8IKfVQFQevIlsOy8pyK+vO/MQuDr1GKgTJyXnnopLDtNymRITvaN1KxB44PXCYlddIYs/7cfwffmc0JiK59yP4w9+qRlS4sCva6B61iJV9MOu7L36B4oHrpD18tZPealpt0P3ZQyBp3ThYor7oHOXgoRQjHzHvvBefR5Kf0q2cH32dvwv/+aUBf2I0+Ffa9DhdrkxkKLfoTnufuF201k0DR0NFznT0t0ic4RASKgIgES6KkIm1xJJ8B3EYXXrUhowDw8892gvO58pH7TNvZMbMeDzmLb5hw/SOS7u77bDU5wIjh/HqKNmxFe9tuWq6ZhO8JQ3gPFw8cmjGFLxzx+QQK9PF5cmVMjgZ5MgDScCKhEgAsg+INQUa1XlQ3lpZShRBRPskMElCDgD0awakOzMNP0cEkYSjLUiQAXkHMhqahWwbJn9WRZtKgRASKgXQLRaBwrmPghwn6KakP7OWEuNogyR3YKjEB43TK4H75Z9VkbB49g5QFvVd0vOSQCRKB7Aqs2eOAPRrvvkOGVftUOlDqKMxxF3bVGIPjbN2h+8WHVwqq86VHonRVC/cUaa1F/j/jMWby8ZMXV6ohXhAKRYMz99J0IL10gYeT2QwwDhsC296Gw7Dhx+4tpngn+8jX8X8xBdMPaNEck71a8024oO/XK5J06Xc0FgV6ncKGrrIJtz0Ngm3RI59PZeR2Po37GlWmVd+0QwbayZ9ZNs2YAkYi8mFk5bZ7JMWuCxXAr6m47H/FWcZU+OBCdowRVtzwlj02X0XG/Dw3/uBZxj7vLFWUOHcedB9uE/ZQxTlaJABFImwAJ9NJGRR2zScD/zVz43pqVMITKGx7OOGWz79O34P/g9W3sOc9lpR8SiP1CS3+F5+l70uq7TadOB1zkx+cQ/Ow/Sb8U6IrNMO00ASWHn15wQj0S6HV6w9DLbQiQQG8bHHRABDRLgO8CX7auSVipWz7RQX1KYbMYNTtnCowIFDKBWOwP8QMvcy2q9evJHi7Z6eGSKJ5k5w8CvAT7cvb7qVVQqVtulWd55NkeqREBIqBNAqs3NqMlIPPBUqepVZdbUemydjpDL4lA5gS8H76KwCfvZj5Q5gjzhMlwHnehTCs0nAgQAREENta1wN0sTjBA2cdFrIp2bNTdfgHiXo8qAZmGjILrArHCce97LyPw+X8Vid95zrUwj9hZEdtaMhpevQTux24VHpJ5wt4wDR4NY9/BMFb2BooSZNyMxxCp24jI+pUIr1yI0I9fC4+jfCrLnleVXvY87jzXBHodwLiQy3bgsbBN/EvHKdV/ev/7EgL/ey+lX9OOu8B12jXt/RoevhHRdStTjkmng6H/YFRcelc6XYX38X/9PnzvvCjcLjcoWuDmfu5ehBfNVyTWREarp7/ClIa6RJfoHBEgAioSIIGeirDJlXQC7udnsBTfPyU0YDvkODj2Pzrhte5OqinQC7MvtJ4XHshIAc+FeiWnXZlQMNjdnHL9PAn0cn0FlYufBHrKsSXLREA0AdGlLk1GHQazUmIGVrKFGhEgAtoiIDprJpW21tb65ls0LYEwVm/0Cp3WYCYit5KIXChTMkYERBAQnTWTSluLWBWy0UGgYea1wrLQdNhM56ft4GPgOOCYdLpSHyJABBQi0NAUxKYGvzDr/H7J0H5U2lYYUA0Y8n7AhNyfqifk5qIt53EXCZt5w4yrEN1cI8xeZ0PmPfZnJTPP7Xwqb19732Vlgr8SWyZYC7Dsh58M++TDMwolVwV6HZPkWQxLjz4bxl4DO06p8jOycTUa/3F9Sl+60jKUX3439CVlaC+x/AgrfZokex6fj7HfUKacbGNCzhWIrklc9a7DcfnV98HYs3/HoWo/3U/egfDyhYr4M40eB9eZU4XYbn77GQTnfSLEVjpGLJMOROlRZ6XTlfoQASKgMAES6CkMmMzLJ8Czz9VNO7tbQ4ZefVFxFUu7m0FTS6DXLs574o6kWfOShe04+kzY9jgoWZe8uUYCvbxZSuETIYGecKRkkAgoSmDtJh+8La3CfNBDUWEoyRAREEZAtPih2KRvf7iUaBO3sKDJUMETqGUPROvZg1FRzWTUY0jfUuj1JCIXxZTsEAG5BERvFuG5RYb2LwP/PUWNCIggEF69mGXGuU2EqYxtlBx/Aay77pPxOBpABIiAfAI+fxh8g5PINqBXCRw2k0iTZCvLBGLNjai/42JVo7DudTBKjjxDts9Uz/DkOjD07oeKK6fLNZMz4xsevoFlMluVM/GmCtS8KxODHp+5GDTXBXodXBxHn8Ge8x7ccaj4z/rpVyBWV5vST8nx57Pvhvu29/POfQ2Bj9/udoztryxRzn7bJspJ9Jy9swHbgUfBceDxnU+p8rruxjMkP5NPFaCoMrfe92cj8NmcVO6EXi+fMgPGHn2F2iRjRIAISCNAAj1p3GiUigSSlbftCCPTMreJvjiILnHL/yhpuPPibr8I8Cx5+j4DEGus6za7Hu/jvGAaTCz1dL43Eujl+wpLnx8J9KSzo5FEIBsEeNnLZWs9iLKfohpl1hJFkuwQAfkEGjws80O9uMwPPKKBvUtgt9LDJfmrQxZSEVi53oNAKJqqW9rXSUSeNirqSAQUJ+DztzLxg0+on95VdvDvodSIgEgC3rn/Yg9A3xFpMm1bznOvY9U6xqbdnzoSASIgn0BrawwrN3gQi7fJN/anhYoyC3pW2ITZI0PaIeB57Z8I/fClqgGJyKoU2bASjTNvVCxundmCqjtnKWZfa4Zj3ibU354f5emLd5qAslOvkoQ4XwR6fPLWfQ9DyaGnSOKQyaBUQrsOW6ZRY+E667qOQyQrtaqv6onKqf/Y0rfzi/rpVzIx4KbOp7a87urj/9k7D/g2iuyPP6tZ3bJc4lQSAgQIkHD0GupRjsDRjtDhKCGhQ6hHIBBCDb23o/9pOTpHDTl67y0BEtLjuMiyevd/RsGJbKuspN3V7uo3H8RKOzNv3nxnnbG8v31vbYWEb1L+bmq7crKEIxANmvUI1bB796UWKdOB5/IpM5VxrjY4DwIgIB8BCPTkY42RSiSQL71tr8li09zKIdDL5bd1wv5k22lf0rube92npKeNQt98SOF3X14r6OPiPMseBxadvnetUZW9gUBPZQsmo7sQ6MkIG0OBgEgEeAQ9HklPzDKowUrNbquYJmELBECgSAJS/Gzzn2v+840CAnIQiEQT9NtSr6hD1TvNNGyQXVSbMAYCIFAcAf6zvXB5N6VEFD+4HGYa3oKf7eJWAq2FEui463JK/PGr0OaitdOZrVQ/ZToZh8qbak20CcAQCKiMAN+XuDgvwkR6YhWr2UCjh7vEMgc7CiOQTjN58zrRjFzumbfcgVxHn13ycNHffqCu+2aV3F9Ix5bZTwtpppk2yc5W8jx4LSXbV6t2Ttad9yHn308s2X8tCfQ4BOuu+5HzwONL5lGoY7x1KXXOLpx+Veeoo4azriZ9fdNakx13sKiNS7JHbbTuMZGc+x+9tm3mm3yR4AzrjabGM6X9dyHTF/4+0b6SOq4vTRDa31auz03T7yZ9nTtXdd7zlRBhc4fcU68g0/qb5PUNlSAAAvIRgEBPPtYYqQQC2UJjmzbbihIsf3wqGllrsdg0t1IL9HhqW89tA58YKpSytjclrnn7Pci+16Gks1TPk3AQ6K29nPGmHwEI9PoBwUcQUAmBVSyVYIeIqQT5tLkAggshUEAABOQnEI7E2c0lH/X0iBf5AdHH5F9HjEjk6Y7QiraAqCggNBUVJ4yBQFEEePRmLs6LxsQTP9TyFNYjXKTT1RTlCxqDgFAC8VVLqPMmLsAQ7/cqoWPrGpqo4bTL+9yUFdoX7UAABIoj8MeKbgqE4sV1KtB6Q7Y/mWsNBVqhWs0EvE/eRpFvPpF9CobhI6nusMklibhlEejd+BRRTXX9btYTDVPXU3dS7MevZL8eyhlQV+8mx8RjybLFDuWYIa0J9DiMYoPNFAOw48bzKLF6ZcEujoNPZEFk9unTLl9aXNs+h5Jj78P7tO/94H/7WQq++Xzvxz5HfXMLi7x3a59zUn+Ity2nzhumSTpMKQK9+Opl1P3cfZRY/LukvmUzbtpkHLlPuiRbFc6BAAhUiAAEehUCj2GFEciW3paL3HjI7MjnfUN9F5PmVmqBnvdZFoq8n39Cf/HiosRqEub1XgkQ6PWSwLE/AQj0+hPBZxBQD4FF7EnxYFi8VIJ85qOGsFSYNqTCVM9VAE+1QCAeT9GiFV6KsaNYRa+voQ2H15PRqBPLJOyAgGACy1cHqMu37oEvwR3zNEQqzDxwUAUCEhL4g/2+GRD59831Wep1G1KvS7hqMM0JBD96nfwvPFoRGIahI8h92hVV+ffHigDHoFVJAL9vVuWyizLpNSLui0SxVYoR+8SjyD7hwKK6Rn//ibrunVlUn2Ibt9zwJJFOX2w3TbT3PHQNxX75XlVzsR94NNl3nViWz1oU6HEgrn9OI/OmW5fFpn/nbPe8+7fhnw2Dh1Hj+bMHVHkeuJpiC34ccJ6fMG28OblPHhiQhtfl7TeG9Tslez/eV4oiNIpgOWM3XX4v6Z3CI9l6n7yVia4/LWfIsvq6p17OoudtWpYNdAYBEBCXAAR64vKENZEJdN4zg+IL5/ex2jzzIYou+Ja6n7ijz3mhAjjeKdsvK65TLiHzmHF9bPIPkQXfkfeBa/ucz9W2t1Hb1VMp5fX0fiSerrbxsrvwh6+1RAa+gUBvIBOcWUMAAj1cCSCgXgIxFsnkt2VeUdON8Ugm/KapxWxULxh4DgIqIsDTMvHID6GIuGLb9Qayd/A0AABAAElEQVQ7yGmvVREJuKolAjwQ5MJlXRQWMd0Y5zOCXdd1uK61dKlgLgonsHSVn7oDUVG9bGm0UVO9RVSbMAYCuQhUKkoS98c4aqN0JD3SIxJXrvXBeRAolUAryyjQLnJGAXedmfgDISjVQcA75z6KfDqvopO1H3QM2Xc5QJAPsT/mk+euGYLaltqo5drH2OZVXQ/shn/4lIn5H6GUz1sqtor245G7XEeeSTpraf92aVWgp2PirmZ2v1gswWm8bQV1sZ+/VNCfd711Dic1nHEV6RtaBrTzvfIYhd7774DzvSfqT76Iajfesvdj+hid/zV1PXhDn3OZH6y7/Y2cBxybeUry9/EVf1DnLdJGi2uecT/p7M6Cc4kt+oUCbz1Lsd9/KdhWqgbm8duR65hzpTIPuyAAAiUSgECvRHDoJj2BpKeN2q85q89AxtEbU8OUGelzrdMm9anTudzsl5q7+5zL9UFqgV5/33haXvcJFwxwh0fLiy0tHNKW/wJrGj56QH8tnYBAT0urKe5cINATlyesgYDcBLr9UVramv8PBMX6ZDLoaNSwOjKx9GMoIAAC0hKQIi0T0oFKu2awLowAT9v8+7JuYY2LaDWKicjtiLxVBDE0BYHSCPBU1TxltZjF5ail4S0OMU3CFgjkJxCLUvvNF1Cyoy1/O4lqTRuNJfep0yWyDrMgUJ0E2j0hau0MiTp5q9lAo4cLj9Yj6uAwVhECSV8XtV81pSJjZw7K72vZJ0wk06iNM08PeB9b+ht5bpd2P+GBO6op85TvtScoNO/VAazVeKLpkluzisIKzUWrAj0+b+vuB5Dzb8cUQiCovmP2NEq0Li/Y1nbAUeTYLXt0zPTP8J0ziFLJnHbMO+xBlj8j/4V//pIin7ybsy2vcJ81k0wjNszbRuzK2NJf2b9Fl4ttto+95pn/Zv8WWfucy/wQW7yAgu+/StHvv8g8XZH3jRfeRIbmoRUZG4OCAAjkJgCBXm42qKkwgWwiuswoeZ5HbqTYj1/18dJ99ixBQrZstnNFxSs2gh4X3bVNP6mPX5l+Z1Zks51Z3/s+U5jYe05rRwj0tLai4s0HAj3xWMISCFSKAP/jNP8jtZjFXKtnkfTqSK9HekwxucIWCGQSkCIykYOlqB7JUlWjgIASCPA0tzz9mNhlg+F1iPQqNlTYA4EMAlJEJjKb9LTBCBfV1NRkjIS3ICA9ATnSAuabBY9u4z5J2kgj+cZHHQhoiUCnN0wr24OiT2mj9eqplu1TKNVFINs9rEoRMK4/hizb7EbWv+xC2SKvxlcups6bL5bUveYr7iWdozqEqt5n7qLIFx9IylNO47r6Bmo4cyZLC+ouatieaJhW/+vEovqop3ENrbmm68py2f/eKxR8haV/LlAMLUOpcdpNeVu1XXcWpUR6aETX2EzNF9+edzwpKmMLfyLPPTOlML3WZst1j7NcwQMz+4S/fp/Cn8+raMS8tU6yN9Y9DyLnfkdmnsJ7EAABhRCAQE8hCwE3BhLoYE+QJlYu61PRdOntpHc3p88FP36T/M8/3KfeOmF/ck48rs+5bB+yfbkRS6DHx+sfQQ8CvWyr0PccBHp9eeDTOgIQ6K1jgXcgoGYCS1b6yBeMiToF/hT5KCbS42lvUUAABMQlwEVLXLwkdtl0/QYmrMXPrNhcYa90AqvYTdQOdjNV7LLRCHYjlYnJUUAABMQlsJo9+NEm8oMf3EMIa8VdJ1grjkCA3VwNCLi5WpxV4a1Nm44n9z+lFVYI9wYtQUCdBKR68GMEi+xaxyK8olQngY5bLqLEiiWKmnztuO3IPHZrqh0znnS2NZGHE+0rqeP68yT1s+nS29i9wUGSjqEE497n7qHIZ+8pwRVRfTCMWJ8az7qmaJuee69kQd1yR3XrNdj/r0w9vRUCj739e3pYz1iEUqEgpbwegb1La2bd+2By7nNEaZ1Zr2RnK3XeeTml/L68NnQ2O9WfPoOMzcPytgt9+R75nr4nbxtBlTU6ck6aTNatJghqLmajyC9fk/eh3Gl3yx+rhlpmP5U2k4qEKPrrtxT96WuKfPVh+aZFtGAYNIQaL7hZRIswBQIgICYBCPTEpAlbohHIlt7WMGQ4NZ5349oxskWqE5rmVm6BXq4IeIigt3Y5CQK9dSzwri8BCPT68sAnEFArgVSqh35a2Cm6+3aLgUYykR6inYiOFgarmIAUaQM5ztEsNbXVMvAp0ypGjakrhMBiJiL3iywi51Mbw6KdmBDtRCGrDDe0QKC9K0w8ep7YZfggO7mcZrHNwh4IFEXA+9Qd7ObeR0X1EbMxIumJSRO2qo1Atz9KS1v9ok97UIOVmt250+iJPiAMKo5A7PcfyXPv1YrzK9Mhyy77kqFhEPlffDTztOjvG86/noyD1xPdrpIM+t+ZQ8E35ijJJVF9se78V3L+/Z+i2pTaWNLnofiKxRT74xeK/vglJdtWiTakzlHHoujdV7K9jptYattVAlLb7ns4OfY6VNA4nkduYJnrvhbUNlcjnhrbfcIFuaolPR/+7mPqflzCyH0GA1m335N4SuDE0kWSzqUc466TLyLzxluWYwJ9QQAEJCQAgZ6EcGG6dALZBHRc5GbaaIs+RsOfvDPgKQYhaW6z2Rczgl6h6H+9k4gtW0j+V1k43H4lvnB+nzOV/IWmjyMSfoBAT0K4KjcNgZ7KFxDug0AGgXAkTr8v6844I85bu9XIUmZykZ449mAFBKqZAE/JxFMziV2GMfFDPcQPYmOFPZEIJJM9tHCZl6Lxwk/mFzvkmJFMpGdEJL1iuaE9CPQn0MHEeaskEOdx4QMXQKCAQMUJsIgtHbdeXNFISaaNxq5Jd6s3VBwHHAABtRCQSpznYlHzhrPoeSgg4PvvkxR695WqB+FmEcBMozbWLIfYwp9Zas6rNDu/3om5T7uMTBts1vtRdcfYkgUU+vANinzziSi+u6deQab1NynaVvCjN8j/wiMF+xUdSY1FD+x88DqKL+p7j7rgQH82SAerOekSIlNlIr8GP5tL/uceEOquJttZd92PnAcer8m5YVIgoBUCEOhpZSU1No9sAjehUxSS5rYYgV4xbXt9zNZHqMguW1S9XClye8fTwhECPS2sojRzgEBPGq6wCgKVIiDVH68h0qvUimJcLRGQSpwH8YOWrhLtzoWLyBcu7yae0UbsApGe2ERhr9oISCXOg/ih2q4k5c833rqUOmdfWFFHjaM2ovoTLySd1V5RPzA4CKiBQHeARc5bJX7kPKvZQKOHu9SAAD7KRKDzrssp/sevMo2mzGFc/5xG5k23VqZzInjVccuFTKS/VARL60zoGpqoduPxZBo5hgxDR5KxaSjlfbq5J0WJ9lUU+vhNZqSGIgu+oVR72zqDIrwzjNyAGs9QdlRIIdOMLPg2nQ425S/vQXTrXgeRc98jhQy5tk2yq506b7+MpbYtPHZJkScTcfL+5wGKfPH+2jGFvDFvsyu5Dj2FyFC5zBmB916mwCv/J8RdTbYxDB9FjWdfq8m5YVIgoCUCEOhpaTU1Mpds6W2LmZqQNLfZRHC5hH2d98yg/hHtckXb6/UzW/pdXmfelv2C8o+pvc0GHHlEPe+9MykVjfSpa7r0dtK7m/uc09oHCPS0tqLizQcCPfFYwhIIKIVAe1eIpScLie7OGpGeE+luRScLg9VAQKq0ti6HmUV+wA3eariGtDBHqUTknA3S3WrhCsEcKkFAqrS2NouB1h8G8UMl1hRj5icQ/v4T6n7stvyNJK41DB1B9Sw1mb6+SeKRYB4E1EtAqt8bjQYdjWb7k9GoUy8ceC46gUT7Suq4/jzR7arJoHPSFLJuPUFNLgv2Nfj5PPI/W3qq0/4DWXbai6zb7E7GYaP7VxX9Ob5yMYU+f5fCH75VdN9cHVwnXUDmTbbKVa2a80lvB7VffUZZ/vIHIxpOLy5yov/t5yj45n8Kjmvdk4n/9itO/JdpNLbsdwq89Rwlli2iVDBIxAScfUqNjnQ2GxlGjCb73oeRafgGfaor8cH3+v9RaO7LlRhaEWO2zH5aEX7ACRAAgfwEINDLzwe1FSCQLfpcsW4USnObSwTII9Vl/tIa+uQtiv34VZ/hdbVmap71SJ9z2T7kmgcXEJrHbc/S9Y5b260nHKDor99R5POBTyQUEvWtNaLyNxDoqXwBJXQfAj0J4cI0CFSQwMo2lkazW/w0mvxm63qD60ivR77bCi4vhlYZgeWrA9Tl6/uAiBhTsFuMNGpYnRimYAMEZCMgVaQuPoENR7jIXIu0gbItJgZSPYE2T4hWd4r/UIeJiR64OI+LIFBAQIkE/O++QMH/PlNR13TuRqo//jwyDl2/on5gcBBQIgH+3Yl/h5KirM++P9nY9ygUEOhPIPzdx9T9+O39T1fNZ/uBR5N914manG/HjedRYvXKsufGI5g59ptEeqe7bFv9DSR9HvK/9iRFvvqof1XRn01jtyT3iRcV3U+JHWJLfyPP7dNLdk1ntlDz1Q8X1Z8LA4UUvatRSLOCbVKhAIusuILiKxZTKuBNt9fZ2XepoaPI0DREUVGXvXPuo8in8wrOSYsNnEdMTgtztTg3zAkEtEYAAj2tragG5pMtvS3PW5+r9ISDlFi5rE91rmh4mY2yRcbLrM/1vhjBXLa55LKb7TwXAzacf4Pmo+fxuUOgl+0KwDlOAAI9XAcgoF0CS1gqGB9LCSN2sTDxw8ghTjLgpqvYaGFPgwSWtfrJ6xf/57DWpGeRH7hYFuIHDV42mp/SqvYgdXjFF5FzcKOH15HVjJuumr+IMMGyCbR2BIlHzxO71LBnOPj+ZMHPodhoYU9kAt7n7qXIZ/8T2Wpx5vhNY+cxZ5OZpcdDAQEQWEOAP2jIHziUooxocVCdo1YK07CpEQL+uf+h4OvPaWQ2xU3DuscB5Nz/mOI6qaB1bNEv5Ln7yrI9dRx2Mtm236tsO4UMBD54lQIvPVGoWcH65ivvZ9HXnAXbqaFB9wsPUfijt0t2tfmqBxUlcit5Igro6HnkxgFBdxTgluQuWPc8kEVLPErycTAACICAOAQg0BOHI6yIRCBbZLtCKWtL6cPd5f06b7pwQDrZfFPhgrnGy+4incWWr9naOp7q1sNS5PYXEK5tkOcNH8t12nQWFrj8MNR5hlFMFQR6ilkKxTkCgZ7ilgQOgYBoBHp6iBYt91IokhDNZq8hLg5ab7CT+BEFBEBgIAH+87dklY/8wdjAyjLP6HU1LDJRHSKFlckR3StLQCrxKp/VqKFOsltNlZ0gRgcBBROQKtIyn/J6gx3ktEP8oODlh2sZBDwPXE2xBT9mnKnMW0TkqAx3jKo8AlKlXeczHdxko0aXRXmThkeKI+B9/gGKfDxXcX5J7RCPDuc6YqrUw8hu3/fyoxR6//WyxnUecRqLnLVbWTaK6eyf9yIFXysvlabzSJayeKsJxQyr2LaxxQvIc+cVJfvXMO0GMraMKLk/Oq4j0HHnZZRY/Pu6E1Xwzrz1LuSadHoVzBRTBAHtEIBATztrqYmZZEsLKyQaXrZIdYXS3HJgsWULyXvvTEEiPS4UdB1/fkmCOd8rj1Hovf8KXqNyxhI8iMIaQqCnsAVRkDsQ6CloMeAKCEhAIJFI0aIV3RSNJUW3bmCRu/hNWCvSw4jOFgbVTYD/3C1t9VEwLL44lpOB+Ejd1we8X0fgD7Y/BULxdSdEfDecRUhxIUKKiERhSisEpBTHDm22k7vOrBVUmEcVEEg/+HvXFZRoXV7x2dr2OZQcex9ecT/gAAhUioBUkV35fJrdVhrUYK3U1DCuCgl0PX4LRb/7TIWel+6yaczm5D7lX6UbUGjP9hvOpWTbqpK9M++wB7kOPbXk/qV27GS/n8T/WFBqdzJvN4Fch08pub/SOrZOm1SyS+6pV5Bp/U1K7o+O6wi0XXsmpTrb153Q+DvT2L+wdNEXanyWmB4IaI8ABHraW1NVz6hUoV2pwj4Oi/+xy/fKoxT77vOsQj0eyc6yx4Fk23EfwZHzsi0Cj9jnf2dOznF4H8OQ4WRhYaj5WNVWINCrthUXPl8I9ISzQksQUCuBaDSZFuklkinRp8DTmPE0MYiUIjpaGFQpAf7zxsV5EQlEsRzJCCaKrUNkIpVeHXC7P4FUqoe4SE+KSK98rCEsUkoDIqX0x47PVUqA/7zxyK5SiWJbGm3UVI/IRFV6eal62vG25dTFUt+lAv6Kz8O8LYte9A/tRS+qOFg4oHgCy1cHqMsXkcRPLhznAnIUECiWgOeRG1gqx6+L7aba9obBw6jx/Nmq9T+r46kUtV5YXlrKpktuJX1DS1bzUp4M//ApdT96a8lDaG09yxHouU65hMxjxpXMEh3XEWi95FiiuDQPWa4bRRnvtCpaVgZdeAEC0hKAQE9avrCuMgI8ol4qFKD48oVkHDaadFZ7SRHzCk07cxyeLpf/Am1sGkx6d3Ohrpqth0BPs0tb9sQg0CsbIQyAgCoIhMJxJoLwUYrn3ZSgDGlmIog63JSVAC1MqohAIBRj4jw/JZPS/JwNYzeW6hGZSEVXBFwVQkDKSK98/KZ6K7U0ImKKkLVAG+0S4JGU0+JxJiKXoiAykRRUYVNOAtHff6Ku+2YR9Yj/QFOx8zCuP4ZcR51JeldjsV3RHgRUR4CLx/n3J38wJonvLoeZhrdAnCcJ3Cox6nnkRibS+6oqZquz2qj5qoc0NddE+0rquP68kuekbx5MTRfeUnL/sjrGY9R6yXFlmWiZnT9NbtLXVZJ9vbO+pH7ldCpLoHfyxWTeeHw5w6MvI5AKdFPbjMlVwcK0yRbkPunSqpgrJgkCWiQAgZ4WVxVzAgEVErjpl99U6DVcloPA+ZtsKMcwGAMEQEABBLh4iIv0pCpNLG1MC9LGSIUXdhVOgEd84JEfpCqDWSSwRkQCkwov7FaYQIyJh3g69jhLDy1Fwc1ZKajCploISC0e53sT36NQQEDtBMLff0Ldj92miGnoHHXkPGIKbiYrYjXghFQEuHh8GYs8HpZIPM6j/K/Hoo+jgEC5BLxP3UGRrz4q14wq+g+a9TDV1Grn4dvYkgXkueOKktmbttiG3MedX3L/cjuWI0rjY+cT6Hmff4AiH88tyUXLTntT3cEnldS31E7lsHBPmU6m0WNLHRr9/iQQW/Y7eW67TPM8Kv1zr3nAmCAIyEAAAj0ZIGMIEAABEAABEAABEAABYQR8gShLbyZd+iaXo5Y9oY4/ggtbDbTSCoHVnSFq84Qkmw7SBkqGFoYVRCASTaRF5FKkY+fTtFkMbH9yktGgU9Cs4QoISEvA0x2hFW3SiceRNlDa9YN1+QkEP32H/HMelH/gHCPaJx5F9gkH5qjFaRBQLwEeMW8ZjzzOIuhJUexWI40aWieFadisUgK+lx+l0Puva372DeddR8YhIzUzz9iiX8jD0tiXWsx/2ZFFtT2r1O5l9ytHlMYHzyfQ637hIQp/9HZJPpq3m0Cuw6eU1LeUTsmuNmqfVfo6aO26LoWhGH3C331E3Y/fIYYpxdow77gHuQ45VbH+wTEQAAFhBCDQE8YJrUAABEAABEAABEAABGQi0O2PptPISDWc1cxEEIMcZDLppRoCdkFAEQR4xujlq/3kZT9TUpVBLColTx2IAgLVQCAcYenYV/okSxPNxXnDB9nJZjVVA07MscoJtHYEqb0rLBmFeqeZhrGfJxQQ0BqBwHuvUOCVJxUzrbQ44B/sJrjBqBif4AgIlEOg0xumle3Bckzk7cvFeSOH1FFNTd5mqASBogkEPniVAi89UXQ/NXWoO/4csmy+vZpczutruRG/DMNHUePZ1+YdQ8pKKQV6vv8+SaF3XynJfcPIDanxjJkl9S2lU/CTt8j/n3+X0jXdp3nGfaSzQ7RdMsA/O/rnPk/B158t14xi+9v2P4IcexysWP/gGAiAgHACEOgJZ4WWIAACIAACIAACIAACMhGQWqSn19Wkb9rytDIoIKBFAlGWimkZE+eFWdQvqQrEeVKRhV0lEwgxkd5ilo5dqogqfO5Dmu3UUGdWMgb4BgIlE0gme9L7E49OJFWBOE8qsrCrFAL+t5+j4Jv/UYo7pG8eTHWHnUqm9TdRjE9wBARKIcCjuvLorlKVNeI8JxPnQZ0nFeNqtxuZ/w35nrufUt1dmkRh+9skcuz+d83MLdHRSh3XnVPWfCol7or88jV5H7qhZN91Fhs1z3woZ//A++yBhJdLfyBh0KxHWDpkeb5Td9x8ASVWLss5l7wVJhO1XPNY3iaoFEbA+8zdFPnifWGNVdRKZ3eQ8/BTyDx2WxV5DVdBAATyEYBALx8d1IEACIAACIAACIAACFSMgNQiPT4xCIwqtrwYWEICPGLeitUBSvEQehIV/OxIBBZmVUEgLdKTMJIeh4DUnKq4FOBkkQSC4Xh6f4rGk0X2FN4c4jzhrNBS3QR8r/8fhea+rKhJaE04oSi4cEZSAjG2L/HI48GwdA83QZwn6RLCeAaBVKCbvHPup9iPX2Wc1cZb8za7kuuIqdqYDJ9FPEatlxxX1nysex5Izv2OKstGKZ09D86i2PwfSuma7mMYNIQaL7g5Z//w959Q92O35awvVGHb5zBy7H1YoWZl1wc//C/5XyxdYFfpKIhlA1CQgY47L6PE4t8V5FH5rpg2GZd+CEZf11C+MVgAARBQDAEI9BSzFHAEBEAABEAABEAABECgP4HuAEt3u8rf/7Son+tYFD2eAk3HouqhgIDaCUidMpDzgThP7VcJ/BeDAE93u3ilnxLJlBjmstqwWQw0tNlBtUjJnpUPTqqLgNQpAzkNCFvVdU3A2/IJ+F59nEL/e618QyJaMG06nuoOOZn0rkYRrcIUCEhHgP/NgT/cJGV0ZIfNROsN5pHzpJsHLINAfwLlCof621PCZ8N6o6nxzFlKcEU0H9quPJVSfl9Z9txTr5A1im3w07fJPyd39Dshk6kdty3VH3tezqbx1qXUOfvCnPVCKlynXEzmMeOFNC2pTWTBd+R9oLwUw9Zd9yfngeWJNEtyXoOdyk25rCwkNWSfeBTZJ0xUllvwpmwCwY/eIP8Lj2S14z7zKjKtt1HWumwnhfwb1HzFvaRzuLJ1x7kKEoBAr4LwMTQIgAAIgAAIgAAIgEBhAjwF2mIWqUjKYjLqaBhLKWizmqQcBrZBQDICsXiKVrT5KRCKSzYGNzy40UaN9RZJx4BxEFALgQhLIb1klY/4z5+UZTgTkbuc8qTnkXIesF2dBHpYNNflbUHy+qRLGcjJNrgsNKTJVp2QMeuqJuB75TEKvfdfxTFwHjGZrNvsrji/4BAIZBJo7QhRe1co85To753sgcD1BjtEtwuDICCEQNKzmrqZmDv2/ZdCmquiTcvsp1Xhp1AnPQ9fT7GfvhHaPGs7ndVG9af+i4zD1s9aL+bJ8A+fUvejt5ZtUkjU3daLjiZKlhd5u+74c8iy+fZl+9vfQPi7j6n78dv7ny76s+vki8i88ZZF90OHvgSSvi5qv2pK35Mq/WQauyU5/nYMGZuHqnQGcDsfgXwCPd6vmD0OAr18pJVdB4GestcH3oEACIAACIAACIAACDACwRAT6bFIeqmUdCk7OWhEBsPlpkYCPKXtslZpI01yLkOZiJVHJ0IBARBYRyAWS6ZFehF2lLI01DHxUTPER1Iyhm3xCfCUtouWd4tvuJ/FJreVWhqs/c7iIwhUDwElRtLj9M1b7kDOg04gnb2uehYDM1UFAf7724q2AAXYPiVlcTlqaXgLxHlSMoZtYQTKTRcqbBR5WjX96w7S1zfJM5gMowTef4UCLz8pykh1R59Bli13FsVWNiOB916mwCv/l62q6HPuM69kkaLG5O3XefcVFF+0IG8bIZXmHXYnx56HihLdN+nzkv/tZyjyyTwhQxdsU4wYp6CxKm4QWfAti2Z4neoJSP0zrHpAGphAIYGeZed9qO7vJwqaKQR6gjApshEEeopcFjgFAiAAAiAAAiAAAiDQnwBPJ7iEifTiCWkjFfH0M0Ob7GRkUfVQQEDpBPiNJU+3tFGJOAN+Y4nfYEIBARAYSCDB9iUeSS8USQysFPnM6GF1ZLUYRbYKcyAgPoE2T4hWd0oblYh7zYV5XKCHAgLVTsD3+v9RaO7LisSAaHqKXJaqdaqLRXRdzlLaSl2Qdl1qwrBfCoHgB69RcN4rlGIiI7UW14nnkXnstmp1f4DfifaV1HF97lSvAzoUOMFTx9r3OJiMQ0cVaCm8OvLr9xR46zlKLP5NeKcCLYUI08QUBHJ3asdtR+bxO5CFR6wzFvf3rdgf8yn09ftMmPdugZkJr7bstBfVHXyy8A5omZNAYN5LFHjtqZz1Sq7Q2R1k3e0Asu92kJLdhG8iESgk0OPD1B13Nlm22KHgiBDoFUSk2AYQ6Cl2aeAYCIAACIAACIAACIBAfwLpSEWtPopEpY1UxMcdxlIK1iOlYP8lwGeFEOBRJRetkDb1M5+qrqaGRrCUTFy4igICIJCbAE/jyUXkPC271AXRXqUmDPvlEIiyqEQr21lUIolTrnMfEdm1nJVCXy0S8L89h4JvzlHk1Eyb/YWcBxxLhsbBivQPTmmfQDLZk96fePRxqQsiu0pNGPbLJRB47xUKffQGpTyd5ZqSvb9174PJuc8Rso8r5YAdd17GxG+/izqEacOxVLvlTmTZdGsWydZZtO2kp43CP31OkS/fp8SKpUX3z9fBOmF/ck48Ll+TdF2yq53aZ51ZsF2pDcxb70L6xkGkr2sgnc1BOhPLGFGjo1Q8RqlANyU6WymxcglLQfx1qUPk7ddw/nVkHDwybxtUCiPgfeJWinz7qbDGCmmlq6sny05/JceEA4n0eoV4BTekJiBEoMd9aJ5xX8Eo5BDoSb1a0tmHQE86trAMAiAAAiAAAiAAAiAgAQH+h/WlTKQnx41fHjFsSJONfU9GND0JlhImSyTQyiIStbPIRFIXo0FH6zFxnsWMaF1Ss4Z97RBYxiKyeFlkFqmLnUXRG8z2J3OtQeqhYB8EBBPo9IaZ+CEouH05Dbl4vM5eXOSLcsZDXxBQCwEuugi8Ik6qPCnmbNv/H+TY4xApTMMmCOQk0M1EeUtb/TnrxawY3GijxnqLmCZhCwQkIxD68j0Kf/YOxf8QLzKaZM7+adi06Xhy//NiqYeR1X74mw+p+8k7JR3TvPXOpG8awtK8MjGalYnRai0Ub19BRiacT0XDlAz4iAvikm0rKPrd55L60njxLYIF+55HbqTYj19J6k8ljJvHb0+uY86pxNCaHLN12iTVzMuw3miybLsH2bbbUzU+w1HxCAgV6Jm22Jrcx03LOzAEennxKLoSAj1FLw+cAwEQAAEQAAEQAAEQyEVgGfsDuxxPv/PxEU0v1yrgvJwE5Iqax+dkNRtoRIsTqZ7lXGCMpRkCrR1Bau8KyzKfFnYTuAk3gWVhjUFyE+BR81ax616OCJJcPD6CpV1Hqufc64EaEAgysYX/uQcVC8IwZDjZ95tE5k22UqyPcEwbBPjDfXx/4mlt5SjD2f7EH/JDAQG1EYgvX0jdc+6nxPIlqnBdSHpUVUwkw8mOG8+jxOqVGWe0+da8za7kOmKq4MnFFv1CnruvFNxeLQ0bLphNxkHD1OKuov1MhQPUNl35qYJ5NGn77n8n03obKZonnJOWgFCBHvfCftAxZN/lgJwOQaCXE43iKyDQU/wSwUEQAAEQAAEQAAEQAIFcBOQUQThZlJYhTAhhNCKaXq71wHlpCLDMmdTaGaQOmQQ//Fof0WKnGpbeFgUEQKA0AnJGErNZDMSFelZEuyxtsdCrLAJcjMp/H5OjcPE4Fz+YjEgBJAdvjKFuAuHvP6Hux+8g6kkpdiK147Ylx76TyMAi+qCAgNgEuChvOYtsLEfh4nG+P9lYhGMUEFArgcAHr1LgpSdU4X7TpbeT3t2sCl+FOhlh6WS9D98stLk62+l01HTJbaSvbyrKf+9Td1Dkq4+K6qPkxrZ9DiXH3ocr2UVV+RaZ/w15H7xe8T43XHAjE2UOV7yfcFBaAsUI9LgnDedeQ8ah62d1CgK9rFhUcRICPVUsE5wEARAAARAAARAAARDIRUBOEQT3ASlrcq0EzktBQM50TNz/BpclndZZirnAJghUGwFfIErLWgOU4ipbGQqPpDeowcbEtTIMhiGqnkAwHE8L80KRhCwsIB6XBTMG0RiB2MKfyfvErZTy+xQ9M+tufyPnX9mNapNZ0X7COXUQ4FFdWztDxH8Pk6NAPC4HZYwhB4Hwtx9R9xNM2K2CUnfU6WT5yy4q8LQ4F73P3UORz94rrpOKWheKBpVrKkmflzqvP4el4pUnGmouP8Q4b9pgE3KfdoUYpmDjTwK+N5+h0NsvKJ5H84z7SGevU7yfcFBaAsUK9Lg3uaLGQqAn7VpJaR0CPSnpwjYIgAAIgAAIgAAIgIAsBHhKtcUr5bvxxP8IP6jBSnarSZb5YZDqIxDj6QJlvLHECQ9psqUFetVHGzMGAekIRKIJJtLzU4T9TMtRTCzKKxfpIb2aHLSrcwyeLnA1i+ra2S3fDTIuPuVRIlFAAASKJxBvW8Ei6d1CiVXLi+8sYw+dlUWC3eNAsu92kIyjYiitEWjzhNgeFZJtWvz3rWGDHHg4QjbiGEhKAmpKJWrecU9yHXKKlDgqZrtj9jRKtCp7zy4FjnnLHch19NmldE33CX/HBKQ8MrCKi66unhrOvpb0TpeKZ6E81z33zaTYbz8pz7F+HuUSWfVrho8aJ1CKQM86YX9yTjxuABkI9AYgUc0JCPRUs1RwFARAAARAAARAAARAIB8BLmhasKQrXxPR6+qdZmphQj0DS2mDAgJiEeA3lfjNJTnLyCFOctggOJWTOcaqHgKpVA8tYynW5Irkwsnyn2e+P5lrDdUDGjOVnACPWrya7U9cpCdXGdpsJ3cdomrJxRvjaJNAKhJikfRuodj8HxQ/QV1DE9l2m0i2Hf6qeF/hoHIIdLNoefw7FI+eJ1dpdlvTD+3JNR7GAQGpCSQ6WqnjunOkHkYU+4bBw6jx/Nmi2FKakWRnK3Xeebnio98Ww80wcgNqPOPqYrpkbeuf+x8Kvv5c1jqln9SZrVQ/ZTpLVTlK6a6qzr/WaZNU4TMEeqpYJsmdLEWgx51y/fN8Mm+6TR//INDrg0NVHyDQU9VywVkQAAEQAAEQAAEQAIFCBLgIwuuTL6oLTyXI/zjPXyggUA6BLnbdcmFeLJ4qx0xRfW0WQzrqg8moL6ofGoMACBRPgKdba5dZfMvTVg9i+5Nej7y3xa8YevQS4JGK+f4kVzpbPi6PBsmjEtksxl43cAQBECiTgHfOfRT5dF6ZVuTprm8eTNYJB5Btuz3lGRCjqJJAOBJnwvEw8X1KzjK8xYFoxXICx1iyEEj6uqj9qimyjCXGIM0z7mfpIp1imFKcjfiqJdT17+sp1eVRnG/FOmQctSG5T76UamotxXbN2t73+lMUmvtS1jqlntQ5nFR/0kVkHDZaqS6q1q/YH/PJc9cMVfgPgZ4qlklyJ0sV6HHHmmc+RDrLuswCEOhJvlySDQCBnmRoYRgEQAAEQAAEQAAEQKBSBDq6wrSqIyjr8PxGMhfp8ah6KCBQDIEAFz50hSgYThTTrey2PCIRj0yEAgIgIB8Brz9KK5iQPNUjXwQyna6G7U8WaqqHkFy+ldbGSFz40NYVkTX6IyfHI0AOZ+I8CEu1cR1hFsoi4J/3IgVfe1pZTuXxRt/cQtad9yPbjvvkaYWqaiMQZw808e9PHhnTrXPGFhaZeNggOyIUV9sFVyXzTYUD1Db9ZNXMtu7Ys8gybkfV+Fuso0lPG3U9OpsSK5YW21Ux7U2b/YXcx51PpBP3gdDA+69Q4OUnFTPPfI4Y1htN9ceeS3pXY75mqCuRgP8dFlXxDXVEVYRAr8RF1li3cgR65vHbk+uYdZFuIdBT78UBgZ561w6egwAIgAAIgAAIgAAI5CEQCMXSIohYQr5oZNwdq9nARBAWctpr83iHKhAgFomICR8qEPGBs0fKQFyBIFA5Ajz92vLVflmjkfHZciE5F+khXWjl1l4tI8fiyfT+xCO7yl2QMlBu4hivGgmEf/iUuh+9VXVTt/1tEjl22o9taPiepbrFE8lhnmK9nQnz2tkDeXIX/iAeF+ehgIBmCSTi1HrxsaqZnnmH3cl16GTV+Fuqo2qKfps5R+teB5Fz3yMzT4n6PvLrd+S9/1pRbYptzDphf3JOPE5ss7CXQcBz75UU+/2XjDPKfGtcfww1TL1Smc7BK1kJlCPQ4446DjmBPbi0b9pnCPRkXTpRB4NAT1ScMAYCIAACIAACIAACIKAkAvwP+MvbArJHfuEM7Cx1aCMTQvAoMCggkEkgEk2kbyrxSFpyF0utPi3Os5iRMlBu9hgPBPoTWNkepE6v/DeYzSZ9WkjuQsTX/ktS9Z95RKJ2dk1W4ro06HU0dJCNnDYIb6r+QgQAWQjEVy+j7qfvosSyxbKMJ+Yg1l33I+uOfyVD42AxzcKWggmkUj3UwfYnLszj7+UueLhJbuIYr1IEWqdNqtTQRY+rb2ympotvL7qfWjuoZW0MQ4ZT43k3yobZ998nKfTuK7KNJ2Qgw9ARZD/gWDJvuLmQ5mhTKoG0qJgLIOX/vaBYl00bjSX3qdOL7Yb2GiRQrkCPI2mYdgMZW0YQBHrqvUAg0FPv2sFzEAABEAABEAABEAABgQT4H/JbZU552+ua3WqkRpcFQr1eIFV85KkCO7wRqoQwj2NHStsqvvgwdcUS8LIIZSuYUK8SN5u5YLeB7U9Iza7Yy0M2xyopzOOT5A8zDGMp1w0GnWxzxkAgAAJrCHiZSC/y5QeqxGHabCuybr8XmTfeUpX+w+nCBHqFeR3s+3yyAsI8Hh1/SJON8HBT4bVCC20QUIsIrJd2w4U3kbF5aO9HzR8D/3uJQnNfplQ4qLi56hx1ZNv7kIqkpE92tRNnE/74XabVkjeLSuZC6Jqaybb7wWTbdvfM03gvEYHIT1+Q9+GbJLIurlnT2C3JfeJF4hqFNVUSEEOgZxy1ETWcfhUEeqq8AtY4DYGeihcProMACIAACIAACIAACAgnEArHaWV7gMLRpPBOIra0sYh6XAhRh9S3IlJVh6kgu/a4MM8XkD9iHiek19WkbywhWpY6rhd4WX0EeDrRFSzaayAUr8jkeUQ9vj8h9W1F8Fd0UJ5umUck8nTLn8q2d+ItjbZ0RMfezziCAAjITyDwwasUeOkJ+QcWcUT7AUeSdevdSGevE9EqTFWKQCKRog62N7V7QpVyIf2Q3WAmzkMBgWoioDaBnv3Ao8m+68RqWqL0XIMf/pdCH79FybbWis/d0DKMLDvtQ7Yd9q64L6lQgEJfzKPIF+9RonW5bP6YNh1PFibKs2y2nWxjYiAi73/up8gnTJSpglK7xTZUf9z5KvAULkpNQAyBHvfRuseBZBo9lrwP5E/13XzFvaRzuKSeFuwXSQACvSKBoTkIgAAIgAAIgAAIgIC6CVQqpWAmNaTIyaSh3fdckNfJbixVSnTDyfKoREOb7GQ0IiqRdq80zEwrBPhN6NbOyt2I5hxbGqxpsZ6OCXtRtEuAC8c7mXC8u0LCcU6WRyXiwgcrUq5r90LDzFRFILboZ+qec78ibvaXA87EboBat9qFzGO3LccM+laIQJQ9TNfRXVnhuJFFc+VR85x4sK5CVwGGrSQBtQn0TBuytJGTqzdtZOyP+RT5/hMKffCm7JeNdcL+ZN58OzKNHCP72EIGTLSvpOj8byi68CeK/fi1kC5FtTFt9heqHbMlWTbfFg8HFEVOvMZts06nVFeneAYltGT+y47kOuosCUeAabUQECLQM++4J0U+nltwSrb9/kHB15/N2w4Cvbx4KlYJgV7F0GNgEAABEAABEAABEACBShHgwiku1IuzJ/MrWZrdTAhRZ0ZKt0ougshj9/T0pCMR8eur0oULH3h6ZRQQAAH1EAixVNir2L8foUiiok6nI+o5a8lca6ioHxhcXAI8xbqHCR+C4cpeX031FuKR81BAAAQURiAeI++c+yjy1UcKc6x4d3QOJ9VusT1Zxu9IplEbF28APWQl4A/G0t+hfOxYycIjjg9h+5NejwcVKrkOGLtyBNQm0OOkmq/+N+nM1spBU8jI8dZlFPv9B4ovXkCxxb9RyusR1TMuMDIOH021m/yFDI2DRbUth7Fkt4fiK5dQomMFJTtWU9LbwcRd7BVkf7uLRigVGfigHP9dQmdjr8bm9JwNg4aTceSGZGyqnrTKcqxNKWPElv1OntsuK6VrRfqYt5tArsOnVGRsDKosAkIEei2znyax9mMI9JS1/r3eQKDXSwJHEAABEAABEAABEACBqiKQSvWkRXpdvsqldesF7nLUkpsJIWxWU+8pHFVGIBJNUJcvmk4VWGnX7VYji/pgp1qWthIFBEBAnQRWs0h6bRVM69ZLjUfhrGf7E9Kz9xJR35E/jMB/1+HXVKWLpVafFubZ8ftOpZcC44NAXgLBj98k/4uPEaWSeduppVLf0Ey1m21N5s22hVhPQYvGv4/z/UkJDzYZ9DoW1dVKLodZQYTgCgjIT0AsQYCcnjsnTWEpzifIOaQqxuqJhqmm1kLhbz6kRFcbpbq7KBXopp6gn4nRwkSJOEsDu4IMg5jYzGigGpOZauyOtCBN76wnfX1TOnU8MfE+GfG3SlUsehU56XvjKQq985JqZmzZaS+qO/hk1fgLR6UjIFSgxyOkeu6aUbYjEOiVjVASAxDoSYIVRkEABEAABEAABEAABNRCgEfTW9URpFi8stH0enkNZk/sczGEnt0kQFE+AX5TiUckqmQa215KNSzQA49IhKh5vURwBAF1E1BKNL1eijzqaz0TlJsg/u1Fougj//2myx8jflRCQdQ8JawCfAAB4QTiq5eR7/mHKL5wvvBOKmipc7nJtMl4MrMIQOZNtiLiv0CjyEqAp1nnDzYp4UE5PvF6FjWPfwdH1DxZLwMMplACahTomTbbitwnXKBQonALBEBACgIds6cxgelyKUxLYtO8za7kOmKqJLZhVF0EhAr0+Kz8c58vmMK20Owh0CtEqDL1EOhVhjtGBQEQAAEQAAEQAAEQUBABlpWUWplIr8PLniJVSHHaa5kQwkT8iKIsAvym0po0gZWPvthLhl8ngxutZDIial4vExxBQCsE2rvC6T1KKfPhUTp55Ff+qoGwQSnLkvaDR3Pl+xO/ZpRSbBYDtTTYyGoxKsUl+AECIFAEAf/bz1Hwzf8U0UNFTQ0GMm04lkwbbU61G25BxpYRKnJeXa7G2cNwXf4IdbM9KhJTRmTGWva9qYV9f8L3bXVdS/BWWgJqFOiRTkctsx5mUd7wtzNprw5YBwFlEIivXEydN1+sDGcEemEevx25jjlXYGs00zKBYgR6nIPnwWsoNv/7kpFAoFcyOkk7QqAnKV4YBwEQAAEQAAEQAAEQUBOBEBNe8Wh6oUhCMW4b9DXpmwYuuwkpcCu4Klz00B2IpW8qRePKuKnEcZgMOhrEIj5woQwKCICAdgnE2M3sVSxFqVKioXHSXJvHU9/Wsf0JN7crd+3F2J7E9yd+bSjp95d0VFcmzGust1QODkYGARAQhUBs8QLyvfwoJZYuEsWeUo3o6lh0vfXHkHH9Tck0ehMyNg9Tqquq8CuZTK35/sT2JyVEG8+EhqiumTTwHgTWEVClQI+575x02pp0rOumgncgAAIaJaC29LZ8GUxjtyT3iRdpdEUwrWIIFCvQS3a1U/usM4sZok9bCPT64FDMBwj0FLMUcAQEQAAEQAAEQAAEQEApBDpZJL1WJoRIpVhoPQUVIxNjcRGE02Yku9WkIM+06Uo4EidfkL3YTSWlRHrIJM1FDzwqEQJYZVLBexDQNgEeeaa1Uzlp2Xtp63RrxOR1bH9y2Hhkvd4aHKUgwAWb3UHlifJ65+ri6QIbrGRgv7eggAAIaIeA781nKPT2C9qZkICZmDbdkowjNiDj8A3INGI06Sx2Ab2qt0kikWLfn9hDTQoU5fFV4VGAW9j+ZDEjqmv1XqWYeT4CahXomTYZR+6TLsk3NdSBAAhohED7DedQsq1VVbPhEZvdk6erymc4Kw2BYgV63IvQV++R76l7SnIIAr2SsEneCQI9yRFjABAAARAAARAAARAAATUS4E/8c5Gep1s5aUwzOepZZD0HE+k5bOzFjvwzSnkEeKrjQChG/lCc/MEoxVgqJiUWvub8xpK51qBE9+ATCICADARWs/2pzROSYaTih+DiPC7Sc7Cb4PzfKy4uRymfAI/y62P7U4DtT+GociK5Zs7MajbQILeV7GzdUUAABLRJIL58IfleeZziC+drc4ICZmXabCsyDlmPDINHkHHQcDI0DxXQS7tNeKRxLsrj36OCYeVEos8kbjKyqONsf+ICchQQAIFcBHqoddqRuSoVf77p8ntJ73Qp3k84CAIgUDqB2KJfyHP3laUbqFBPw8gNqPGMqys0OoZVEoFSBHrcf+9z91Dks/eKngoEekUjk6UDBHqyYMYgIAACIAACIAACIAACaiXAb4ivZiIIpaXl6c/TZjGko+rZLUaysheKMAL8hlKArTFfX35TiYv0lFrMJj01M2EeTymJAgIgAAI8tSkX6nlZVD0lF0utPp2i3cH2JhsT7dUgvJ6g5eLry/emINuj/Gx/SiaVu0EZ9DpqdluowYV0toIWF41AQAMEgh+8RoHXn6WemLL3ILlQ65tbSN84iPRudmxoIoO7mfSuRtLXNZDOXieXG7KMw6PkZX5/irPPSi7NTJg3iH2HQgEBEChAIBah1ktPKNBIudX2iUeTfcJE5ToIz0AABMom4P3P/RT55N2y7chtwDB0BDWee4Pcw2I8BRIoVaDH0jxR64VHFT0jCPSKRiZLBwj0ZMGMQUAABEAABEAABEAABNROgKcVbOsKUUShUWv68+VRi2xcDMGi2fAUPtBDrCHEBXlc7BCKrDkq/YYS95pHR2yutxJPaYsCAiAAAv0JBJl4q60rrHghea/fdiYot1r4HsWObH/i6XFRiHja2iBLrc6jDwXDMcVGce2/Vk1M+NDM9iesY38y+AwC2ieQ9HWR/7UnKfLVh9qfbDkz1OvTIj2d3UE6G3/ZqcbKXmZr+qUzmanGxNLDG1n0UYOBavQsSnaNnojtjzr2voYJ/IyDhpXjQVl9uSCPf38Kpr8/xVTzfbieRcvjUfOMLHoeCgiAQGECqUA3tc2YXLihQltAAKPQhYFbICAiAbWm4eYIWmY/LSIJmFIrgZIFemzCsd9/JM+9xUVihEBPmVcKBHrKXBd4BQIgAAIgAAIgAAIgoFACnd4wtTMhhBqEXf0RNrLINhYm2LOy1KgmFo1N64XfTOrsDrNp1jBB3pooeWqbM4QPalsx+AsClSPAheTtTEiu1PSn+ci468xMrMcE5Wx/qob03TwaXpcvQikWtjXMBA88NaDaCl8zLh6H8EFtKwd/QUB8ApH531DgzWcosWyx+MZhcQ0BnZ5Mo8dQ7bgdyLb93pJRSaV6mAAvQSH24vuT0qP0ZgPhZNHGm+vN6YfUstXjHAiAQHYCya52ap91ZvZKlZx1nz6DTKM2Vom3cBMEQKAYAqEv/ke+Z+4tpoui2kKgp6jlqJgz5Qj0uNP+t56l4FvPC/YfAj3BqGRtCIGerLgxGAiAAAiAAAiAAAiAgFYItLO0t1yol2Q3MdRaePQic62ReOpU/qplLz1LU6e2wm8kRWMJirDoQ+kXT1vL0gKqufA0gTwikcGgvvVQM3f4DgJaIODpjlAHE+pF48pOOVeINY98Y2bpcdfsUQZV/nvYwwR4UbY38Vfv/qRGMV7mWrkctdTE9qdqEFJmzhvvQQAEChPgaW+Dbz9PqVCwcGO0KIuA84jTyLrNbmXZ4JFbI39+h+L7lBrFeJkA7FZjen+yW1kkQhQQAIGiCcRXL6fOG6cV3U9JHczbTSDX4VOU5BJ8AQEQEIlA5z0zKL5wvkjW5DcDgZ78zJU4YrkCPT4nz30zKfbbT4KmB4GeIEyyN4JAT3bkGBAEQAAEQAAEQAAEQEArBLgwrINF1FvdGdLKlMjA0qmajCxCQ++LCcR4dByjQc9euoqksOOcE8lUOmphPJ6kGIuMF2PCk3g8kRagqDGaYa4Lhkck4sIHzh8FBEAABMohwCO+rmzXjkiCp1CtZfuRyciiwKaPa/YlvjfxPYqnA5e7MP0d8Wit8UQyvUet2Z/YPsX3qvRL3SLJTJ6ISJRJA+9BAARyEUhFQhR46zkKvf96riY4LxKBQkKUPvsT++6UuUdxQZ5Wit1ipEb2/clhgzBPK2uKeVSGQPS3H6jrvlmVGVzEUQfNephqai0iWoQpEACBShOIr1hEnbdcWmk3yhq/5YYniVhEZJTqJiCGQC/RsYo6rjtXEEgI9ARhkr0RBHqyI8eAIAACIAACIAACIAACWiTQxiLqaUmol2uNdDU1LIoRe7FIezzanp4JJviRCye4NoIfa1ibNUeeXJa92P9CkWQ6fSGPJsRjDnJRA3/PxXfsv/SRRyNMv5gYL5l+rRHmqTlKYS6O/c83cGGem6UKRMS8/mjwGQRAoEwCnSyiXieL+BplgjEtF77X8L1pzf60Zp9K701sX+LH9IvvT6wd36d4e75JsXdpLHxP4oXvSem9KmNv4nvVuj0qyUTjf+5P7Kj1wiPmNbqQKlDr64z5gYDYBOJtK1g0vTkU+eYTsU3DXgaBno3GU/LvZ7DvTuw7Ffv+xB9q6t2jMppp8i2PmNfIoo5DmKfJ5cWkKkAg+Plc8j/7QAVGFndI+4FHk33XieIahTUQAIGKEvA+/wBFPp5bUR/KHbzpkltJ39BSrhn0VzkBMQR6HEHwM7ZnP1d4z4ZAT5kXDAR6ylwXeAUCIAACIAACIAACIKBCAvzePo9Y1NkdTkd4U+EU4LLMBHi0hyZ2YwmpbGUGj+FAoAoJdPmYUM8boTBLA44CAoUI8BTDXJiHVLaFSKEeBEAgH4HYH/Mp8O4LFPvlu3zNUFcGgeDYnSm086QyLKirK4/o2lhXSzakslXXwsFbxRPwvfE0hd55UfF+CnEQqSSFUEIbEFAHgZ4oy1zzrxPV4WweL12T/0XmDTfP0wJV1UBALIEeZ+V9+k6KfPlhXmwQ6OXFU7FKCPQqhh4DgwAIgAAIgAAIgAAIaJkAhBBaXt3y5saj5DUwUR6PmscjOqGAAAiAgJwEfIEoE5JHKBCKyzksxlIBAb4n8b2poc6STm+vApfhIgiAgEoIRBZ8S6F5L1Ps959V4rG63PT+9WSKjxqvLqeL9BbC8SKBoTkIFEnA+9QdFPnqoyJ7Fdfc0DKUEq0riutUQuu6E84ly2bbldATXUAABJRGwP+/lyj46lNKc6tofxz/OJVs2+5RdD900BYBMQV6FI9R6yXH5QUEgV5ePBWrhECvYugxMAiAAAiAAAiAAAiAQDUQCARj1OmLEhdEoFQ3AZvFQG4WkcjFXiggAAIgUGkC4UicCfWixAXlKNVNwGzSU31amGdOp/+tbhqYPQiAgJQEIr98TaH3XmFCvV+kHKbqbMcahlD3YZdqbt78wSYuzOPicUQc19zyYkIKI9B59xUUX7RAMq9Mm21FxmHrU/CN5yQbo9ewacOx5J48vfcjjiAAAiom0DpNG1GCrXsfTM59jlDxSsB1MQiIKtBjDkXmf0veB6/L6RoEejnRVLQCAr2K4sfgIAACvQT+/trc3rc4ZiHw4t/2zHIWp0AABEAABNREIBZLkoeJILgQIpFkuXBRqoYAv6nkdtaS1WKsmjljoiAAAuohkEymyMMi6nUxMXk0nlSP4/C0bAI8TSDfnxw2U9m2YAAEQAAEiiGQjqj3wWsUm/9DMd3QNg8B776TKb6eqoarXQAAQABJREFUNlKn2dmDTfw7FB5syrPgqAIBkQm0XXM6pTydIltdZ866y75k23V/ap911rqTEr5znz6DTKM2lnAEmAYBEJCaQOjL/5Hv6XulHoZ0NhulgkFJxzFvvTO5Jp0h6RgwrnwCYgv0+Ix9r/8fhea+nHXyEOhlxVLxkxDoVXwJ4AAIgAAnAIFe/usAAr38fFALAiAAAmoj4OVCPX8U6QXVtnBF+Gup1advKNU7zKTXI41tEejQFARAoIIE/CzqqwdRXyu4AtIPbTLqyMX2Jh7R1cjeo4AACIBAJQnE/phPwQ9fp+h3n1XSDU2MHRqzLQV3y5/mSskT1bM061yQx4Xj5lqDkl2FbyCgSQJSR6myH3QM2Xc5gDwPzpJFnF07bjuqP/ZcTa4VJgUC1UKg49aLKbF8seTTtey0N8UX/ixpCm7j6I2pYcoMyeeCAUAABJRPAAI95a8RPASBqiAAgV7+ZYZALz8f1IIACICAWglEWVQ9LxPqef0RisVTap0G/P6TAL+pVOeopXr2QrQ8XBYgAAJqJpBIpNbuT+EoouqpeS17fXexvYm/EC2vlwiOIAACSiKQaF/BhHpvUvjzeUTxuJJcU40vCVcTdR1xhWr87XWU70u9e1TvORxBAATkJZD0dlD71dJGdqo74VyybLYdhb/5kLqfvFOWCTacfz0ZB68ny1gYBARAQFwC4R8+pe5HbxXXaA5r7rNnUeCNpym2QNrIzi2zn87hAU6DAAhUEwEI9KpptTFXEFAwAQj08i8OBHr5+aAWBEAABLRAIBCKUXeAvZhgL5lCClw1rSlPEeiym9LiPDX5DV9BAARAQAiBcCROXrY/+dj+FGPCPRT1ELBbjVTH9ygmzNMxETkKCIAACCidQE80QsFP36bwZ3Mp2daqdHcV5l8NtU++Q2E+ZXfHajas3Z8MBkRzzU4JZ0FAPgKxRT+T5+6rJB2w4dxryTh0VHqMtitPpZTfJ+l43Lh5611YSsnTJR8HA4AACIhPoOPO6ZRY/Jv4hvtZNIzcgBrPuJq8c+6jyKfsQREJCwR6EsKFaRBQEQEI9FS0WHAVBLRMAAK9/KsLgV5+PqgFARAAAa0R8AWi1B2Mk58dIdZT5urySA91XJTHhA8QPShzjeAVCICA+ASCXEzO9ie+T8Uh1hMfsAgW7RYDceE4358gehABKEyAAAhUjEDk5y8pxCLqxX78qmI+qG3gjuOvpx6zTZFuW1jaWuef359qTXpF+ginQKBaCYS+fI98T98j6fSbr3qQdFZ7egzfa09QaN6rko7Xa7zhghvJOGh470ccQQAEVEAg8tMX5H34Jlk8dRx+Ctm225P8816k4GvSRrhruvxu0jvdsswLg4AACCiXAAR6yl0beAYCVUUAAr38yw2BXn4+qAUBEAABLRPwB1nUIvbiR4ghKrfSXITnZKI8h83IjhDlVW4lMDIIgIBSCATDTKjH9qYAe0VYynaUyhHgonG+R/EXRHmVWweMDAIgIA0Bnnox9MU8inz9ISXbV0sziEasdpx4I/WYLIqZjY2Jxh3suxPfnyDKU8yywBEQGECg+8WHKczSjEtZMiNHJTpaqeO6c6Qcbq1t89Y7syh60qbvXTsY3oAACIhCoPOu6RT/Q/roeTqrjZqveijtsxwpdeuOP4csm28vCiMYAQEQUC8BCPTUu3ZV7XnS00ahbz6k2K/fpznUWGxkHD6aajcaRyZ2LKakwkGKLf29mC5kbBpMendzzj5CbZrHjMtpo9oqINDLv+IQ6OXng1oQAAEQqBYCPM2gj0Uu4ulwQ5FEtUy7YvM0s8gOdusaUR4/ooAACIAACGQnEGUCPS4k97P9KRCKZ2+Es6IRMLF0gDYmdnCwFLYOtj8hkqtoaGEIBEBA4QQi7G/BEfY34eh3n1FPLKpwb+V1L2UwUudJt8g7aL/R9Pqa9L7EU6xzUZ5ej/S1/RDhIwgokkDH7ZdSYukiSX3LFOjxgTyP3ChbhNSGc69h6XXXl3R+MA4CICAOgfD3H1P3Y7eLY6yAFeuE/ck58bh0q3jrUuqcfWGBHuVVZ45XniX0BgEQUDMBCPTUvHpV6DsXvnmfuTvvL+7G0RuT64ipeQV0megiC74j7wPXZp4q+N623z/IsechOdsVY9O87a7k2Oswwf7mHFTlFRDo5V9ACPTy80EtCIAACFQjgWQylRZBBFgEoyATQ0TjiF5U7nVgYDeQ+M0km8WYPpqMSL1ULlP0BwEQqD4CPT09a/YntjcFwzEKR7E/lXsVcAFeem/6c38yszSBKCAAAiBQ1QRSKQp/+xGFv/+E/Z3466pG0Tv5WNMw6j7k4t6Psh3tbG+yse9Q/GhlLxQQAAGVEUgmqPWiYyR12rTxFuQ++dI+Y0Tmf0PeB6/vc06qD6YttiH3cedLZR52QQAERCTQcctFlFixRESLuU01XXIr6Rta1jRIJan1wqNzNxahxjByA2o842oRLMEECICAmglAoKfm1asy37k4z3PPDEqsXFZw5rpaM7lOmy4oml4xYrregcUU6HGb3F+e594yfqfeIaruCIFe/iWHQC8/H9SCAAiAAAgQxeNMsMeEEMFwgrp8ESARSMDlqCWr2ZAWPkDwIBAamoEACIBAEQTSgnIuJmf7U4gdw1FEgBWCj6et5aI8nh7QaobgQQgztAEBEKhOAqlIiAn1PqXoj59T7OfvGISeqgQRGLcHhbfP/UC5WFD4A018X+L7k81iopoasSzDDgiAQCUIxBb+xO67zZR0aPMOe5Dr0FMHjNFxKxPiLJdHiOOafBmZN9xsgA84AQIgoBwCwU/fIf+cB2VxqHaLban+uPP6jNV+w9mUbFvd55zYH/pHExXbPuyBAAgonwAEespfI3j4J4FiQ15z0VvjZXeRjqW/zVeUINDj/hUjKsw3H7XWQaCXf+Ug0MvPB7UgAAIgAAIDCXBBBE+Dy19cDBFmxwQ7V62FRx+y1OrZi99QWiN2MBqRcqlarwfMGwRAoHIEUqketifF1+xRLLpeJBqnGBOZV2vhugYL25e4SLx3f6plKdZRQAAEQAAESiDA0t6Gf/qCoj9/RbEF31MqFCzBiDq7eA69kJKNI0R13sz2IwsT4/HvUXyP4u9RQAAEtEXAP/d5Cr7+rKSTchx0LNl2+duAMYKfzSX/cw8MOC/FCZ55q2HKDClMwyYIgIBIBNpmnU6prk6RrOU3457CgvyMHtunUbE6hD6dBX5wn3ElmUaOEdgazUAABLRIAAI9La6qBueU9LRR+zVnDZgZF7Xph42k5PLFlIoOjBTD08e6/jF1QL/ME0oR6HGfqvlLAgR6mVflwPcQ6A1kgjMgAAIgAALFE4gnUkwIsUawF40xUUQsQfzIshFqqtSy1LQmfjOJiR34TSUueoDYQVNLjMmAAAhojAAXlXMxeYQL9ti+FGX7Ez9yMZ+WitGgS+9HfF9Kix74kb1QQAAEQAAEpCEQ+/1H4mkUY7/9wNKlLZVmEAVYjYzcjPz7nFayJwa9Lr0v1a7dn9Z8h6pBeLySmaIjCKiFgOff17Hoo99K6m49y3ZVu0FfIUzvgG1XT6WU19P7UdKj88ipZN1qV0nHgHEQAIHSCPjfepaCbz1fWuciexnXZ4LdqTMG9JLDB/vEo8g+4cABY+MECIBA9RCAQK961lrVMw1+/Cb5n3+4zxz6i+/6P+nD650Tjy8pgh7vax6XO92ssWkw6d3NffzJ/JBN9Nc/LW7424/STwf1Fxa6z54lKDVv5nhaeA+BXv5VhEAvPx/UggAIgAAIlEcgFudiiCSLYMSOLIoRP8YT7MXeJxUojtCxG0U8+h0XOpi4GI+9atnnWqMhLczDfaTyrgf0BgEQAAGlEODCci7W4xH2omxv4sf4n3tUIqk88R7ff9J7k0HP9im+P/G96c+jyUA8misKCIAACIBAZQgkfV0U/fV74qK92KJfKOXpqIwjEozaefgllHIPzWt5zXcn/h1qzfen9B7FHmbi36H0euxPeeGhEgQ0TKBtximUCvglnWHzzIdy3qfzz3uRgq89Len4vcZ1jc3UfPHtvR9xBAEQUAiBpLedBek5m9gTerJ4VHf8OWTZfPsBY0VYFGbvwzcNOC/mCdNmW5H7hAvENAlbIAACKiMAgZ7KFqxa3e0vvuMcXKdcQuYx4/og4e1i7A8ttj0OHlDXp2HGByFiuozmgt4KtZlNeNhfyCdoQA00gkAv/yJCoJefD2pBAARAAASkI8CjFyWYQIIL9rgYIs6iHCXZkafL5cck++MJb7P2xcLxcU1fDzvmi8zHRQw8IgM/csEdFy3o2YsfdTpd+iaRgb3n0RwM7IaRgYnx+Ht+Qwk3kKRbb1gGARAAAbUQ4PsMF/Cl9yi2J/Ej36e4sJxH5OP7VHpv4vtSep9aszelCu1PDEB6f2JZ0Hv3J35M71FsH+JHvg+t3Z/Se9OaPYrvVSggAAIgAALqIJDsXE3RRT9T7I9fKL74N0q2rVKH4/28jOw+iWjLPdjexPaizD3KwB5q+vP7E/anftDwEQRAIE0g3racOm+YJikNPRPFNeUTxSXi1HrxsZL6kGncuvfB5NzniMxTeA8CIFBhAt6n7qDIVx/J4oVh6HrUeO71WcdK+jzUflX+rHxZOxZxUud0UfPl9xbRA01BAAS0RgACPa2tqEbnk03wZhgynNxTZvR58iYVDvb5LARHNtvliuSE2uT+tk0/qY+b5Y7dx5iKPkCgl3+xINDLzwe1IAACIAACyiWwRqTXkxY7cDEFkz2kRXnK9RiegQAIgAAIVAOB3v1p3VyxP61jgXcgAAIgUH0EUiE/xZb8RvFlv1N8+SKWEncJpbq7FA3Ctu9h5NjrMEX7COdAAASUSyD4+VzyP/uApA7WjtuO6o89N+8YvjefodDbL+RtI2Zl40U3k6FpiJgmYQsEQKBEApFfviHvQ9kFcyWazNvNOWkKWbeekLNN28wpkv/+13TJbaRvGJTTB1SAAAhomwAEetpeX83MLpuQjU9OV2sm07htqXajcWQZnzslbT4Q2cR0xtEbk2mjLbJ201lsZNtxn6x1vSez2cwmvONpbrufuKO3W/qYrV2fBhr9AIFe/oWFQC8/H9SCAAiAAAiAAAiAAAiAAAiAAAiAAAiAAAiAgJgEUv5uiq38gxKrllCidRklVq+gVFsrpaJhMYcpyZbjsJPItv3eJfVFJxAAARDgBLzP3kORz9+TFIb9wKPJvuvEvGP0RMK0+rIT87YRsxIpJsWkCVsgUB6BjpsvpMTKpeUZEdjb0DKMGqfNztva88iNFPvxq7xtyq10HjmVrFvtWq4Z9AcBEFApAQj0VLpw1ei275XHKPTef3NOvVesZx63k+D0ttxYNjFdzkFYBRfvNbDIfflKNpv9hXdcdOi5Zwb7xWNZH1N1x5xZstiwjyGVfYBAL/+CQaCXnw9qQQAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQEAOAjwFWrJtJcU7WinZyV6eNkp6OynVxV6+buYCjxwuTTGP355cx5wjjXFYBQEQqCoCrdNYimyJi/vMq8i03kYFR/G98TSF3nmxYDuxGtQddTpZ/rKLWOZgBwRAoAQC/nfmUPCNOSX0LK2L84jJZN1m97ydA/NeosBrT+VtU26leZtdyXWEtKl0y/UR/UEABKQjAIGedGxhWQICnUzQFl84v6BlLqLjm5ve3VywbTYxXb5OpQr0dC43C1m7zp/k8sXsactIn6F4m+bL7u5zrlo+QKCXf6Uh0MvPB7UgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgoAQCye5OSnZ7KBXwUpJF4UsFfdQTCFAqvOZFLFoU/7twD3/Fo0SJBFE8Tj2pJPUkk0T89WfROV1kGDSUPTS+KVnG7YC0jL1gcAQBECiLQJxFBu286aKybAjp3DL7aSHN2L+HYWqfOZVS7N9HuUrLNY8SmWrlGg7jgAAIZBCIty6lztkXZpyR9q1hyHBqPO/GgoPE/phPnrtmFGxXbgOh/zaWOw76gwAIKI8ABHrKWxN4VIBA8OM3KcjU6/3Fbf278Yh6rtOmk2n46P5VfT7LJdDrM2iOD9UaPY/jgEAvx0Xx52kI9PLzQS0IgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgEBhAnJErjJtOJbck6cXdubPFnL4lOmMefvdyXXY5MxTeA8CICATAc/9V1Ps1x9lGo2o7ugzyLLlzoLGkyW66JTLycQevkABARCoPgIQ6FXfmmtmxuFvP6Lor9+lN/CU15N1XqVGu8tq7M+TUtjkpq0T9ifnxOPyDa3pOgj08i8vBHr5+aAWBEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABECgMIGOWy6ixIolhRuW0cK272Hk2Osw4RZSKWqbOYVSLPKoXMV14nlkHrutXMNhHBAAAUYg8MGrFHjpCdlYGEZuQI1nXC14PM+9V1Hs958Fty+loXXnfcj59xNL6Yo+IAACKicAgZ7KFxDuryEQW7aQQp+8SZHP3x+AxH32rLxR9LJF0LPt9w9y7HnIAFtCT2SzmasvT2vrOOBosozfKVeTqjgPgV7+ZYZALz8f1IIACIAACIAACIAACIAACIAACIAACIAACIAACIAACIAACOQnEF+1mKW3vTh/IxFq3WdcSaaRY4qyFPzgNfK/9HhRfcpt3HLtY0RGU7lm0B8EQEAAgXjbcuq8YZqAluI1cf1zGpk33VqwQTmieerq6ql5+j2CfUJDEAAB7RCAQE87a1kVM+HCt+C7L1D9CReQzmIbMGf/3Ocp+Pqzfc47DjmRbDvu0+dc5odsYjopBHo88p5poy0yhyZDw6CqF+b1AoFAr5dE9iMEetm54CwIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgIAwAr7XnqDQvFeFNS6jVcvsp0vq3XHjeZRYvbKkvqV0Mm87gVz/mFJKV/QBARAokoDnPhad7jdpo9NlumTadBy5/3lJ5qmC72NLfiXPHZcXbFduA9dJF5B5k63KNYP+IAACKiMAgZ7KFqxa3U162ogr1nsj5Jm33ZX9wjx1AA6e9rb7iTv6nFeKQK9c0V+fSWnwAwR6+RcVAr38fFALAiAAAiAAAiAAAiAAAiAAAiAAAiAAAiAAAiAAAiAAAiCQn0DrtEn5G4hQa9piG3Ifd35JlrLd5yvJUBGd6o6cSpatdi2iB5qCAAgUS0COyHT9fXKfNZNMIzbsf7rg57YrT2Xptn0F25XTwDx+O3Idc245JtAXBEBAhQQg0FPholWby1yc13nThZSKRvpMnUeks+6wN9VY7OnzPeEAi673IiVWLuvTznXKJWQeM67PucwP2SLoZYt2l9nHOGx00TYh0MskOPA9BHoDmWSegUAvkwbegwAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIFEMg/MOn1P3orcV0Kamt4/BTyLbdniX15Z0898+k2K8/ldy/lI5N/7qD9PVNpXRFHxAAgQIEYgt/Is89Mwu0ErfavP3u5DpscklGvU/dSZGvPiypbzGdmq+4j3SOumK6oC0IgIDKCUCgp/IFrBb3O++ZQfGF84uerq7WTM2zHsnbL5tAL28HVllIbJfNZqE+hcbUej0EevlXGAK9/HxQCwIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgkJuA58FrKDb/+9wNRKopV3QSW7yAPHdeIZI3wsyYxmxG7lMuE9YYrUAABIQTSCSo/eYLKNm2SnifMlvWmEzUdMntTPzmKslS+LuPqfvx20vqW0wn276Hk2OvQ4vpgrYgAAIqJwCBnsoXsFrczxVFr9D8hYjisonpyrWbzaYQXwqNq+V6CPTyry4Eevn5oBYEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQCA7gfiqJSxb1UXZK0U8axy1ETWcflXZFr3/uZ8in7xbtp1iDFj3+js595U+BXAxPqEtCKidgPepO1g0uo9knYbtb0eSY/eDSh8zEafWf51AlEyWbkNAT119AzX/6y4BLdEEBEBAKwQg0NPKSlbBPGLLFpL30Zso5fUImq11wv7knHhcwbbZxHSFOhUS22WzWahPoTG1Xg+BXv4VhkAvPx/UggAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIZCfgnXMfRT6dl71SxLP2A48m+64Ty7aYCvqp47qzKRUOlW2rGAOuE88j89hti+mCtiAAAjkIBD54jQIvPZ6jVprThiHDqfG8G8s27nl0NsV++LJsO4UMOI+YTNZtdi/UDPUgAAIaIQCBnkYWslqmkQoHKfjxmxT+5J2cQj3j6I3JtsfBZB4zThCWbGK6Qh0Lie2y2SzUp9CYWq+HQC//CkOgl58PakEABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABAYSSHZ7qH3m1IEVEpxpuuxO0rsaRbEc/PB18r/4qCi2hBrR2ezUcM41pK9vFtoF7UAABLIQiC38iTz3zMxSI+0p10kXkHmTrcoeJPzNh9T95J1l2ylkwDB0BDWee0OhZqgHARDQCAEI9DSykNU4DR5RLxUKUHz5QjI0DKIai51MIzYgncVWjThUP2cI9PIvIQR6+fmgFgRAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAYCAB30uPUOiDNwZWiHzGtMEm5D7tClGtdt59BcUXLRDVZiFjxvXHUMPUKws1Qz0IgEAOAqmgjzpuu5RSno4cLaQ5bd56Z3JNOkMc46kUrb7sROqJRcWxl8dK3TFnkmX8TnlaoAoEQEArBCDQ08pKYh4goHICDy1crPIZSOv+SaNHSjsArIMACIAACIAACIAACIAACIAACIAACIAACIAACIAACIAACGiKQNLbQe1XiyRYKUDGcdhJZNt+7wKtiquOLVlAnjvEFf0J8cC8w+7kOnSykKZoAwIg0I+A58FZFJv/Q7+z0n7UmS3UeNGtpHPUiTaQ95m7KPLFB6LZy2eoZfbT+apRBwIgoBECEOhpZCExDRAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARDoJeCdcx9FPp3X+1G6o15PLTP/TWSqFX0M36uPU+h/r4lut5BB+8SjyT5hYqFmqAcBEMgg0P3Cvyn80VsZZ+R56zjkRLLtuI+og0V+/Z68918jqs1cxpxHTCbrNrvnqsZ5EAABjRCAQE8jC4lpgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAnEFv2G3lumy4LDPPWu7DUkqdLNlbHjedRYvVKyeznMlx3/Dlk2Xz7XNU4DwIgkEEg8MGrFHjpiYwz8rw1bbwFuU++VJLB2m84h5JtrZLY7m8UUfT6E8FnENAeAQj0tLemmBEIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgAAIgEAVE/A8cDXFFvwoC4H606ZT7QZjJRsrMv8b+n/2zgO8qeoN42+zmjYdoYuNyBIEQUQQQUQFcYuK4t7rL24FN+4JbhG34p4oiqIiQxFkiwwFRARkCKUt6UiTpmn6PzeYkrQ3yU2bcW/65nl47r3nfOf7vvO7IbfJfe93bK8/ETP/QR0bTcgZcy9M7bsENWEHCZAA4Fi9CKVvPxt/FDod8sZNhCG/bUxil8/+HPZvP4mJ7/pOLceNQuaxZ9Vv5jEJkEASEaBAL4lOJqdCAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiTQvAnYl8xB+SevxgWCod1+yLsp9uK5smlvoXL+93GZk38QXW4+cq99APqsHP9m7pMACfxHwLVlPUpeeghwu+POJGPkBcgYcnLM4nrKS1H4wNUx81/fcd7tTwuxYZv6zTwmARJIEgIU6CXJieQ0SIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEmjcBT2UFCu+9Im4QMs+4FJZBx8UlXqKWujXs1xl5Yx4E9Pq4zJNBSEArBGqKd6F48gPwlJbEPWVTD7G07eWxWdrWfzK2D1+Ac/kC/6aY7Zt69kXOpbfHzD8dkwAJJJYABXqJ5c/oJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJBAVArYPJwkxyfyo+FLipNWTHykxi4qNc8Nq2F55JCq+InViOvBg5Fx2R6TDaE8CSUvA47CLynn3w71ja9znmGJKRd7YCdDntIx5bNemdSh58f6Yx/EFyDzjEiF6Pt53yC0JkEASEaBAL4lOJqdCAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiTQPAlULv0RZR+/HLfJpw87FVknnBe3eFKgsu8+QuWsaXGN6QtmPmQQrOfd4DvklgSaL4HaWhQLcV713+sTwiDzrCthOWxY3GJ757pxXXziiUqdubc8AWPLdvGJxygkQAJxI0CBXtxQMxAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJRJ+Ae/cOFD1xS/Qdh/CYf+/L0GdZQ1jEpiuuYpl6UzAffjSso66u18pDEmheBEreeAyutSsTMmnzoUNgPefauMZ2rF6I0refi1tM4/7dkHutWFabLxIggaQiQIFeUp1OToYESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESKC5ESiaNB7uzRviNu20wcci+/TL4xbPP5AkRix+5g7Uulz+zXHbTz/iOGSddmnc4jEQCaiJQMk7T8K1allCUtIXtEL+LRMBgzHu8YuevQPubZvjFjdt8AjxGXtZ3OIxEAmQQOwJUKAXe8aMQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIxIWD77GU4F/0YE9/BnObf/QL0LfKDdce8vXKZWM73o/gt51t/QulDT0TWKRfVb+YxCSQ1Adt7z8D52+KEzTHnmvEwde6ZkPiOFfNR+v6kuMbOPP0SWAYfH9eYDEYCJBA7AhToxY4tPZMACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZBAzAiUz/4c9m8/iZl/OcfpR4wQFeQSX9mp9Is34Fjwg1yKcWmjSC8umBlEJQT2CHFeVQLFeRknn4uMo0YmlEbRc3fCvXVTXHOwXj4O5h794hqTwUiABGJDgAK92HClVxIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARKIGQH7ktko/+S1mPmXdWwwoODuF6HLzJbtjndj0aR7xNK+f8U7bF289CFiuduRXO62Dgh3kpJAyTtPiWVtlyZsbua+A2E9/6aExfcFdqxZjNIpz/gO47bNufFhmNp3iVs8BiIBEogNAQr0YsOVXkmABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEggJgQcq35B6TvPx8R3KKeWEacjc8TZoUzi2ufevQMlz90Dj7MyrnH9g5kPPwbWUVf5N3GfBJKGQMlbT8D1+4qEzcfQqh3ybnoMMBgTloN/4JLXHoZr/Rr/prjs593+NAz5beISi0FIgARiQ4ACvdhwpVcSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESiDoB5+9LYHvr6aj7DedQ1yJHVM+bHM4s7v2O1YtQ+vazcY/rH9DcbzCs517v38R9EtA0gdoqJ/a8NQGuv/5I6Dxyb3oExnadE5qDf3DX5vUomXSff1Pc9vPveg76nJZxi8dAJEAC0SVAgV50edIbCZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACcSEgGPVQlE577mY+A7nNOvsq5He/+hwZgnpL581FfbvPk1IbF9QU8++yLl4HKDT+Zq4JQFNEqixFWHP20/CvXVzQvPPOvcapPcbmtAc5ILbpr4C58K5cl0xb8u7/SlRSa9tzOMwAAmQQPQJUKAXfab0SAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAJRJWBfPBvln74WVZ9KnZm69UTOVeOVmifEzvbhJDiXz09IbF9QQ8cuaHHRWOizrL4mbklAUwSqt/2NPe8+A0/x7oTmnT58JLKOPzehOQQL7qksR9FjN8HjsAcziWl7zvUPwrRft5jGoHMSIIHoE6BAL/pM6ZEESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEokagfNZnokLcZ1HzF6mj3JsfhbFtp0iHxd2++MXxqN60Ie5x/QPq81vCesGNmuDlnzf3ScC5djnK3nsBHrG8bSJf5r6Hw3r+jYlMIWxs+y/fo/zzt8Laxcog++KbkHbQwFi5p18SIIEYEKBALwZQ6ZIESIAESIAESIAESIAESIAESIAESIAESIAE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GI778TeEJz76ofBvvvvv0jEnnBRWn3RaiP8HJz8ECBAgQIAAAQIECBAg0L+AgF7/xlogQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgQEKCOgNcNINmQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgT6FxDQ699YCwQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAwQAEBvQFOuiETIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQP8CAnr9G2uBAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAYoIKA3wEk3ZAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDoX0BAr39jLRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAAAUE9AY46YZMgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAv0LCOj1b6wFAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEBiggIDeACfdkAkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgfwEBvf6NtUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECAxQQ0BvgpBsyAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECPQvIKDXv7EWCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGCAAgJ6A5x0QyZAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACB/gUE9Po31gIBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIDFBAQG+Ak27IBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQINC/gIBe/8ZaIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEBCgjoDXDSDZkAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE+hcQ0OvfWAsECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgMEABAb0BTrohEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgED/AgJ6/RtrgQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQGKCCgN8BJN2QCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQ6F9AQK9/Yy0QIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwAAFBPQGOOmGTGASBX78r26ZxG7p05QJfPRHL5yyHusuAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgMMsCAnqzPLvGRmCKBAT0pmiyJrirAnoTPDm6RoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEBiggoDfASTdkApMoIKA3ibMyfX0S0Ju+OdNjAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAwywICerM8u8ZGYIoEBPSmaLImuKsCehM8ObpGgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQGKCCgN8BJN2QCkyggoDeJszJ9fRLQm74502MCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIDDLAgJ6szy7xkZgigQE9KZosia4qwJ6Ezw5ukaAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAYoIKA3wEmf9CEf3rc3HPj6/QvdXP3s08OKtesX9osb+7/yxZFDK9Y9I6zesnXkWJudfV+4PRza8Vg48E9fWii2+nlnh5XHPyusfdEFC8eabhT7F8vVjSle07VcLDuNPwJ60zhrk9dnAb3JmxM9IkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECQxYQ0Bvy7E/o2GMwbdcHfmOhdytP3hJO+KXrFvaLG4/+8k+OHFq19Yxw/FuuGTlWtxNDgXs/fXPY98mPhcPf3l96+Ypj14S1r/yxsOHCi0uvKZ7YecN14cA9d445lQBHAABAAElEQVQcPu61P18Z9jvw4Law871XjZRZsWkubH77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AAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECAxcQ0Bv4DTCJw28S0Ithucff/d+Sj7ptEtCL406tZBePx7Dc2pf+UFh16ta4e+Tn4EPbwr7P/O2iEF082SVIt/3dlyfr+k5r3/nvze/6YOPQX77ctG4L6E3rzE1WvwX0Jms+9IYAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECAxdQEBv6HfABI6/SUAvdjt1XTzeNKAXr338t68Mhx55MG52+qlaca+qwt03/XF48taPl17S9HG7pRVM4QkBvSmctAnssoDeBE6KLhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgQELCOgNePIndeip4N36V10aNlx48aIup4JubQJ6cSW+nddf0ymkF9t55mVXdlrlLvWY2/zguqzKly8/jdsCetM4a5PXZwG9yZsTPSJAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAkMWENAb8uxP6NjbBPTiEIqr4LUJ6MXyMaT3L3/7l5Ur2sXr8j9lgcH8NXXbVY+5HdrjbaOVgF7dHeN8EwEBvSZKriFAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgSWS0BAb7mktdNYoG1AL65Gt+v97wqHv73/SBttA3pZx2K7+794e9h/x23ZoZHXFceuCavPOT9s+KGfCMfMbR4512UntfpfrGeIj7eN4xbQiwp+liogoLdUQeUJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBcQoI6I1TU10zIxDDev+671/CoR2PhVWnbg0r1j0jrN6ydWbGN4kDEdCbxFmZvj4J6E3fnOkxAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBCYZQEBvVmeXWMjMEUCf/foN6eot7o6qQI/+D0nTmrX9IsAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAYoICA3gAn3ZAJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoH8BAb3+jbVAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgMUENAb4KQbMgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAj0LyCg17+xFggQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBggAICegOcdEMmQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgf4FBPT6N9YCAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECAxQQEBvgJNuyAQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQv4CAXv/GWiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBAQoI6A1w0g2ZAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBPoXENDr31gLBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIDBAAQG9AU66IRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA/wICev0ba4EAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEBiggoDfASTdkAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEOhfQECvf2MtECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMAABQT0BjjphkyAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC/QsI6PVvrAUCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQGKCAgN4AJ92QCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKB/AQG9/o21QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIDFBDQG+CkGzIBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQI9C8goNe/sRYIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAYIACAnoDnHRDJkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIH+BQT0+jfWAgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgMUEBAb4CTbsgECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAg0L+AgF7/xlogQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgQEKCOgNcNINmQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgT6FxDQ699YCwQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAwQAEBvQFOuiETIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQP8CAnr9G2uBAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAYoIKA3wEk3ZAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDoX0BAr39jLRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAAAUE9AY46YZMgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAv0LCOj1b6wFAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEBiggIDeACfdkAkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgfwEBvf6NtUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECAxQQ0BvgpBsyAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECPQvIKDXv7EWCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGCAAgJ6A5x0QyZAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACB/gUE9Po31gIBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIDFBAQG+Ak27IBCZR4Mf/6pZJ7JY+EWgt8NEfvbB1GQUIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACB2RQQ0JvNeTUqAlMnIKA3dVOmwyUCAnol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CBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAqH0IJAAAAVFJREFUAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCQjoVek4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEOgoI6HWEU4wAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFQJCOhV6ThHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6CgjodYRTjAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVAkI6FXpOEeAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDoKCOh1hFOMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUCcSA3v8HLMnJsGUNNCMAAAAASUVORK5CYII=" - }, - "asset-e644a484-4097-40b9-a08e-7250ba963059": { - "id": "asset-e644a484-4097-40b9-a08e-7250ba963059", - "@created": "2018-09-06T19:44:43.075Z", - "type": "dataurl", - "value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABDgAAAQ4CAYAAADsEGyPAAAACXBIWXMAAAsSAAALEgHS3X78AAAgAElEQVR4nOzdTXIbZ7Yu6nVOnP7OO4INR2S/pBEYGkFR3ewUOQJTI5A0AlEjINxBV6wRCB6BUX1EGHsEN88I7m3kRwuS+AOAQH75ZT5PhMNV3vWzYpdJJN5cP/8rAIBJaZt6FhGznb/04z+PiPhHRFQP/NtfPfLXz20dEe0Df30bEf/z1L+2Wm5WZ6sKABiM/5W7AADgZdqm3g0d5unP/xVdGBE//PWp26Y/IroQ5D87/3id/vG6Wm4eClMAgAETcADAgLVNPU//8P7P950VVXwfYHAeq/TndUT83/gWkLTVcrN++N8CAOQg4ACAjH4IMO67LoQX5bjv/LjvBrn/59tqudlmrAsAJkfAAQBnlkKM+9Div6Pbd5FrlwX92qY/1tHtChF+AMCZCDgA4ERSkDFLf/waDy/vhHvr6MKP/8S34MPYCwAcScABAAdKSz1fhSCD89gNPlah4wMA9iLgAIBHtE19P1byKrrlnvf/GPp2v9tjHanjQ7cHAHxPwAEA8V2YMY9vYcYsY0mwj1UIPQAgIgQcAExUGjOZh84MxmcVXejxR3ShxzZrNQDQEwEHAKOXujPm0YUYv6Z/DFOxje8Dj1XWagDgTAQcAIxO29Sz6EKM+zBjlq8aGKRVpMAjIlbVctPmLQcAXk7AAUDxdsZNfg27M+AY6/gWegg8ACiSgAOA4ux0aPwz/bnKWA6MkcADgOIIOAAYvLRD4yKMnEAu64j4d3RhxypzLQDwIAEHAIPUNvU8vnVouHACw3IXXXfHnSstAAyFgAOAQUhjJ7tdGsZOoAzb6MZZ/l0tN3d5SwFgygQcAGSjSwNGSXcHAFkIOADozQ+7NC5ClwaM3f2y0t+r5WaduRYARk7AAcBZ/TB6cpG3GiCjNrruDqMsAJyFgAOAk9sJNf4VRk+An7WR9nZEN8riDC0ALybgAOAk2qZ+Fd0uDaEGcKi7EHYA8EICDgCOljo1LqMLNWY5awFGQ9gBwFEEHAAcxPgJ0CNhBwB7E3AA8Kx0/eQyhBpAHhaUAvAsAQcAD9o56frPcP0EGI77sOOz07MA7BJwAPCdtqnn0XVqXERElbcagCdtI+L3iFhUy802bykA5CbgAOB+r8Zv0YUas6zFABxnFV3YYV8HwEQJOAAmamcE5V/RnXcFGIP7EZbfq+VmlbkWAHok4ACYmLapX8W3bg0jKMCYbSPic3QjLLo6AEZOwAEwATvdGr+FKyjANC1CVwfAqAk4AEZMtwbAT7ahqwNglAQcACOjWwNgb4vQ1QEwGgIOgJHYuYRyGbo1AA6xjYiP4QILQNEEHACFa5v6vltjnrkUgNK10XV1fK6Wm23eUgA4lIADoEBpDOUyumBjlrUYgHG6iy7oWOUuBID9CDgACmIMBaB324j4WC03i8x1APAMAQdAAdqmnkfEv6ILNgDoXxvd9ZUbezoAhknAATBgbVNfRhdszPNWAsCORXRdHdvMdQCwQ8ABMDA7Z17fh/0aAENmTwfAgAg4AAYiBRvX0e3YsF8DoByr6IKOu9yFAEyZgAMgs7Q49DIEGwCl24aFpADZCDgAMknBxvuwOBRgbLYh6ADonYADoGeCDYDJ2EZ3eWXh8grA+Qk4AHoi2ACYLCdmAXog4AA4M8EGAImgA+CMBBwAZyLYAOARgg6AMxBwAJyYYAOAPbXRnZf9kLsQgDEQcACciGADgCNtw9UVgBcTcAC8UNvUVXTBxnXuWgAo2jYEHQBHE3AAHCkFG9cR8VtEVJnLAWA8thHxrlpu7nIXAlASAQfAEdqm/hCCDQDOaxVdR8cqcx0ARRBwABygberL6MZRZnkrAWBCVhFxVS0328x1AAyagANgD21TzyPiU0S8ylwKANO1iG50xWlZgAcIOACekC6j3EbEPG8lABAR6bRsRNwIOgC+J+AAeEBaIPopnHwFYJi24eIKwHcEHAA/sEAUgIKsoxtbWeUuBCA3AQdA0jb1RXRdG7PMpQDAoe6iCzq2uQsByEXAAUxe29Svogs25plLgSFaPfDX2oj4T481/PrAX6vC0l94yMewnwOYKAEHMFlpz8b7iLjOXQucWRtdG3tEN7f/Pw/89YiIbclvf9O1o3s/BiC7Icnuvw7GaBv2cwATJOAAJqlt6svoujbs2aBkuwHFH+nP2/RHmMl/Wgo570OQV9H9Pvjv6MbUdIgwBqvoxlbWz/0LAcZAwAFMSnrD+yl8caEcq/g2EnIfaLS+sPTjhxBkHhH/Fd/CEL9HKMVNdB0dxlaAURNwAJPg7CsDt4pvIcY2/bH2ZWT42qaeRdfxcR96/Jr++SxXTfCINrpujkXuQgDORcABjJ5xFAZkFd92YKyi8J0XPC11jN13evwj/XmWsSSIMLYCjJiAAxgt11HIaBvdKMl/0p/XggzupeBjFt9Cj/vuD+iTayvA6Ag4gNFJ4yjX0V1IgXNbpz/uuzKMlnCwNOpyH3b8GkIP+rGNiCsLiYGxEHAAo5LejN6GNnDOYxvfOjNWIczgjB4IPeY562HU7qILOvw+A4om4ABGIXVt3EbERe5aGJVVdIHGH2HMhAFIo3fz6MZb5iHM5XTa6C6t3OQuBOBYAg6geJaIciL3J1j/iIiVlm1KsNPlcd/h4XQtL7WKrptjm7kOgIMJOIBipQf729C2zXHa6B7k7wMNFwUoXupmm4fAg5f7WC03H3IXAXAIAQdQpLap75eI6trgEKuI+HcINJgIgQcvtI6um8PvS6AIAg6gKLo2ONA6Uqhh5AT+Djwu4lvgMctZD8XQzQEUQcABFEPXBntoo7sG8EdE3LkIAE/bWVr6zxAc8zTdHMDgCTiAwdO1wTPW0Y2d3HnwhuPtjLPchx2zjOUwXLo5gMEScACDpmuDR9zFt10a28y1wCil7o5/hd0d/Ew3BzBIAg5gkHRt8IP70ZN/V8vNXe5iYGrS7+SLMMrC93RzAIMi4AAGR9cGyTa+LQgVasBA7Cwq/Wf6M9OmmwMYDAEHMBjpofk2PDBP2Ta6To3fPSzD8Ak7SNroujluchcCTJuAAxiEtqkvogs3dG1Mz/34yWehBpRL2EF0XXdvXbACchFwAFmlB+L3EXGduxZ6ZacGjNhO2PFbWFA6NW10Iyt+twO9E3AA2aQN/V/CKcIpuQ81FrkLAfqxs6D0t/D7fkoWEfFONwfQJwEHkEXb1B+i69xg/NYR8XtELDzowrTtnJ69DCOJU7CNbmTF+CHQCwEH0KvUtvwlnBkcu21826uxzVsKMERp99K/wr6OKXhnASnQBwEH0BuLRCfh/gKK2WtgLyn4vgwjLGO3CgtIgTMTcAC9aJv6U1gkOlbbiPgcEXe6NYCXSCMsv0XX1SEMH582upBjlbsQYJwEHMBZpeVyX8IW/TFaRNetscpcBzAyrrCM3sdqufmQuwhgfAQcwNkYSRmlbXQLQ2+0GQN9aJt6Ht8WkzIe6+i6Oba5CwHGQ8ABnIWRlNFZRbcw1G4NIAu7OkapjYgrny3AqQg4gJMykjIqbXRLQz96wwYMSeoQ/C1c5BoLIyvASQg4gJMxkjIa2+iWhi6MoQBDlkL192F8ZQxW4coK8EICDuAkjKSMwiqMoQAFSuMr19Ht6pjlrYYXcGUFeBEBB/Ai6aHyS2gTLtkiumBjnbsQgJdqm/oyuq6OWd5KeIF31XJzk7sIoDwCDuBobVO/ioivYSSlRG18Cza2eUsBOL10feV9COBLdRfdAlIjK8DeBBzAUdIbstvcdXCwNrr9Gs68ApPgzGzR1tGFHDoMgb0IOICDtU19Gx4US7ONiI8RcSfYAKbIQtJiOSUL7E3AAewt7dv4Gk7AlmQb3fm9ReY6AAZhJ+i4CCOWJXFKFniWgAPYi30bxdmGYAPgUTuXV34Ln22lsJcDeJKAA3iWfRtF2YZgA2Bvgo7i2MsBPErAATzJvo1ibEOwAXA0QUdR2oh4Wy03q9yFAMMi4AAelB70voTzekO3DcEGwMkIOopy5fMP2CXgAH6S9m3chmWiQ7YNwQbA2aSg41PoYhy6RbXcXOUuAhgGAQfwnbap59F1bnhrNUxtRLwTbAD0w3nZIqyiG1mxfBQmTsAB/M0y0UFrI+JzRNx4gAPoXwo6PkV3XpbhsXwUEHAAHctEB+1jCDYABiF1Or4PO6qGyPJRmDgBB0xcmjG+DW+khmgR3Z6NbeY6APhBCjpuI2KWtxIeYPkoTJSAAyYshRtfwzLRoVlFt2dDmy3AwKXxzk9hd9XQ3FTLzbvcRQD9EnDARKVLKV/DA9mQbKN767TKXAcAB3BadrBcWIGJEXDABLmUMjhtdKMoN7kLAeB4Lq4M0joi3thjBdMg4ICJcSllcG6iCzc8eAGMhEWkg7OObvnoNnchwHkJOGBC2qb+EN0DF/mtohtH2WauA4AzsZ9jUNroOjnst4IRE3DARDgDOxjb6BaI3uUuBIDz29nP4QVDfs7IwsgJOGDknIEdlI/RbXU3jgIwMWk/x20YWxkCZ2RhpAQcMGLOwA7GKoyjABARbVNfRDe2MstcytQJOWCEBBwwUsKNQdiGcRQAfpA+o99HN7pCPs7IwsgIOGCE2qZ+FV24YalZPsZRAHhS+rz+FMZWchJywIgIOGBkhBvZraLr2rClHYC9tE19v4TUZ3cei+g+u72UgMIJOGBEhBtZtRHxsVpubnIXAkB5LAXPbh3dGVkhBxRMwAEj0Tb1ZXQPRvTvLro3P9vchQBQNktIsxJyQOEEHDACwo1s2ui2sFsiCsDJWEKalZADCibggMIJN7K5iy7c8AAEwFm0TT2P7jN+lreSydlGxFv7tKA8Ag4omHAji210wcYqcx0ATEDq5rhfQkp/2ug6OYQcUBABBxSqbeoP4WGnbzfRLRLVtQFAr9Ii8duIeJW7lgkRckBhBBxQoLapbyPiMncdE7INXRsADEDb1J/Cbo4+CTmgIAIOKIxwo3d2bQAwKHZz9E7IAYUQcEBBhBu9ciEFgMFyaaV3Qg4ogIADCiHc6JWuDQCKkLo5vkRElbmUKRBywMAJOKAAwo3etNEtEb3JXQgA7Ct1c9xGxEXuWiZAyAEDJuCAgRNu9GYd3c37be5CAOAY6Xz8p9DNcW5CDhgoAQcMmHCjNx+r5eZD7iIA4KXapp5FN7LinOx5CTlggAQcMFDCjV5sw/lXAEaobeoP0S0h5XyEHDAwAg4YIOFGLywSBWDUnJPthZADBkTAAQMj3OjFO4tEAZgCC0h7IeSAgRBwwIAIN85uHV3XhgcQACalberr6BaQch5CDhgAAQcMhHDj7BbRdW4YSQFgktqmfhXdAtJZ5lLGSsgBmQk4YADSWbfb3HWMVBtdsLHIXQgA5GZk5eyEHJCRgAMyE26c1TYi3nrIAIDvGVk5KyEHZCLggIyEG2flSgoAPCGNrHyNiCp3LSO0jYjXnkOgXwIOyES4cVaupADAHtLIypeImGcuZYzW0XVyCDmgJwIOyKBt6ovoHiY4rTa6kZRV7kIAoCRtU3+KiOvcdYyQkAN6JOCAnmkHPRsPEADwAukFzG14Rjk1zyjQk/+duwCYEuHG2Syq5cacKwC8QLXc3EXEm+i+kHM6r8JCV+iFDg7oiXDjbK6cgAWA03FK9mwW1XJzlbsIGDMBB/QgPSh8jS7B5zScYAOAM2qb+kNEvM9cxtgIOeCMBBxwZsKNszDLCgA9SFffPoUO1FPSfQpnYgcHnN+XEG6c0iKEGwDQi/RF/E1EbPNWMiq3KTgCTkwHB5xR29S3EXGZu44R+VgtNx9yFwEAU6Mj9SzeOG0PpyXggDMRbpxUGxHvtHMCQF6eb07KPjE4MQEHnEFqO7zNXcdI+PAHgAGxfPSk2oh4XS0329yFwBgIOODEhBsnZZkoAAyQ5aMn5XkHTsSSUTihtqlfRfdhz8vdhQ97ABikneWjPqdf7lV0+02AF9LBASeSwo2v4U3GKbgRDwAFaJt6Fi7GnYrnH3ghAQecgM3iJ+U2PAAUxHPQSd1Uy8273EVAqYyowGn4UD8N4QYAFKZabtpquXkdEYvctYzAddpvAhxBBwe8kHNpJ+FSCgCMgOeik3lTLTer3EVAaXRwwAukM2mXeasonnADAEYi7ZCwR+LlvqT9bsABdHDAkZyDPQln0QBghDwnnYTnJDiQDg44gnOwJ+FDGwBGyhnZk3A+Fg4k4IAD7WwKdw72eIsQbgDAqKUdEkKOl3mV9poAezCiAgdwBu0k3HgHgAlJna9fImKWuZSSuTQHe9DBAYf5FMKNlxBuAMDEpEXir6MbT+U4t21Tz3MXAUMn4IA9tU19HS6mvMRH4QYATFMaS30TQo6XcFkFnmFEBfbQNvVFdK2VHEdbJQBg3PflLGmHJ+jggGekpNxyp+MJNwCAiPiuk2OVuZRSeS6FJ+jggCd4y/Biwg0A4EHpOshl7joK9bFabj7kLgKGRgcHPO02hBvHEm4AAI9Ku7kWueso1Ps0Qg3sEHDAI9qm/hARPjiOI9wAAJ4l5HiRW0tH4XtGVOABlooerY1u8ZUN6QDA3oyrHM3SUdgh4IAftE09i4g/I6LKXEpphBsAFCt9/s9+/OvVcrPqu5apEnIc7a5abt7mLgKGQMABOywVPZpwA4BipLb+i4j4R3Sf+bM9/m2riNhGxB8RsaqWm+15qps2IcfR3lXLzU3uIiA3AQfs8KF6FOEGAIOXQo3fogs2TtGluY0u9BB4nJjnsaO90XHE1Ak4IGmb+jLcFT+UcAOAQUuf77/F+bsz15ECj2q5uTvzf9foCTmO0kbEL/ZxMGUCDoi/3+p8DXs3DiHcAGCw2qaeR/fiYpbjvz66sOPf0e1H8IXzCEKOo6yq5eZN7iIgFwEHk5f2bvwZeR6ASvbWGyoAhiZ9rt/GsE69ryPi9+jCjm3mWooi5DjKx2q5+ZC7CMhBwMHktU39JYb1EFSCq2q5WeQuAgB2pa6NLzHsjsz7UZbfdUHuR8hxFC+imCQBB5PWNvV1RHzKXUdhhBsADE7b1B8i4n3mMg61jYi7EHY8S8hxsDYiXusYYmoEHExW2rvxZ+46CiPcAGBwRvLldxvdGMvCl9KHtU39NSLmuesoyLpabl7nLgL6JOBgkuzdOIpwA4DBGUm48aP7nR0LC0q/Sc9vX+P8F3HG5KZabt7lLgL6IuBgkuzdOJhwA4DBGWm48aO7iPi3z+GOkOMob6rlZpW7COiDgIPJsXfjYItqubnKXQQA7Jrg53kbXdjxeer7OoQcB2sj4hfdQEyBgINJSXs3vsawt6sPiXADgMGxRyu2EfE5JjzCYtz4YKtquXmTuwg4NwEHkyHtP5hwA4DB8cX2J/dXWCZ3EtSLq4O9q5abm9xFwDkJOJiMtqk/RcR17joKYes2AIPk8/xR25jgFRYhx8FeT33EiXETcDAJbVNfRMSX3HUUYh3dMqpJtrwCMFxtU88i4q/cdRTgflfHKnchfWibeh5dyMHzttGFHJ7zGKX/nbsAOLeU7N/mrqMQwg0Ahszn+X4uIuJr29R/tU19ncZ6RisFOcZq9zOLaS3nZWJ0cDBq9m4cpI0u3NC2CMDgeEv/IvcXWD6OeXylberLEILt6+0U97Ywfjo4GLvbEG7sQ7gBwNC9z11AwaqIuIyIv9qm/prCotGplptFRCwyl1GK27F39jBNOjgYLXs3DiLFB2CwdG+cxTYiPkbE3dhGU9umvo0u0OFpTscyOgIORiktIfszbNTex1V64wEAg9Q29deImOeuY6TaiPgcETdjCjrapv4zdPHuw+lYRsWICmN1G8KNfdwINwAYstS9Mc9cxphV0Y3//L9tU9+ml0Rj8Ca65ek87X1ayA+joIOD0Wmb+jpsh97HolpubBwHYNB0b2SxiIjfSz8zq6N3b67oMRoCDkbFB9ne1tVy8zp3EQDwFFcxsltFd3lllbmOo6XuhK/h2fA5d9Vy8zZ3EfBSRlQYmy/hA+w52+jaNgFg6FxOyWseEV9LvrySLsS9y11HAS5SFzQUTQcHo9E29YfwIPQc52ABKILujUHaRtfRschcx8E8J+6ljYjX1XKzzV0IHEvAwSik9sM/c9dRgDclt5kCMB1tU/8VEbPcdfCgbRQYdDgfuxenYymaERXGwhue510JNwAoQeremGUug8fNIuK2beq/0v9WRUjL1XWxPm1uVIWS6eCgeFoO9+JiCgBFaJu6iq4rc5a5FPa3jUI6Ovz9tRejKhRLBwdFS6Mpwo2nrYQbABTkOnz5LM0suo6OwS8jTadQ30b3JZ6HVaE7mkIJOCjdp9wFDNw2ug9xABi89Hb9t9x1cLR5FHB1xWWVvRhVoUgCDoqVfunOc9cxYG1EvE1vKgCgBNfh3PsYzONb0DHLXMuD0jjNx9x1DNz7of7vB4+xg4MipV+2f4aHoKe8rZabu9xFAMA+UvfGX+GzfYwW0e3o2Gau4ydtU3+JiIvcdQyYqyoURQcHpboND0BP+SjcAKAwn8Jn+1hdRsRfbVN/SEHWkLis8rR5SZdyQAcHxUm/ZC0+etxdtdzYuwFAMVJn5l+566AXbUR8rpabD7kLuZeW1n8NAdtj2oj4xdgzJdDBQVFS6m+x6OO20b2JAICSuIg2HVV0ux3+apt6EKMhaemo56fHuapCMQQclMZoyuMsFQWgOOnt+WXuOujdLCK+pEWkr3IXk0Z7b3LXMWAXQ76MA/eMqFCM9Ev1a+46BuwqbQQHgGK0Tf01XEWjW0T6LveLGn8/PmkbEa9z/28ET9HBQRHSaIrWuMcthBsAlCa9vJhnLoNhuIy0iDRvGfE2uq5YfjaL7pQzDJaAg1JcR/dLlZ+tq+XG3CgAJbJXi127+znmWQrouhOcRX3c+yGMFMFjBBwMXtqsbvnYw9ro3jQAQFHSVTRflHjILCK+tk39JT0H9iotHX3X939vQQSTDJaAgxIYTXncVbXcbHMXAQBH8PKC51xExJ85xlaq5eYmIu76/u8txDwFlDA4Ag4GLf3ynGcuY6hu0sZvAChK+sI6y1sFhcg5tnIV3WJNfvYp7ciDQXFFhcFKvzT/CmdhH7KulpvXuYsAgEP5fOeF7qLrYO1lEWjaN/FnH/9dBbqplhujPAyKDg6G7H14+HmIvRsAlMznOy9xEd21lV6uedjH8aRrC0cZGh0cDJK0/ElvjaYAUKK0MPKv3HUwGquIeJdCiLNqm/pLdOEK31tVy42rMwyGDg6Gynbmh9m7AUDJfL5zSvPobwmpfRwPs3CUQdHBweCkX5Iup/zM3g0AipUWRH7NXQejtY1uN8fqXP8F/h5+VBsRv/S1FwWeooODQUmLx5yN+1kb3ZsDACiVz3fOaRYRX9umPtt1jxSefDzHf3bhPL8zGAIOhuY6nI17yMc+5ksB4BycfadH19GNrczP8R9eLTcfIsIz2c+u044dyErAwWCkX4rS35/dVcvNTe4iAOAFfL7Tp1mct5vjbXTdtXzPiDnZCTgYEovHfmY0BYCipQWQs7xVMFFn6eaolpttOB37kHnb1C7NkJUlowyCpU2PenPOZVkAcE7p7flf0c3oQ0430Y38nqzzwunYB22r5eaX3EUwXTo4GArdGz+7EW4AULhPIdxgGO67OV6d8D/T6difzXo62wsPEnCQXVo8dsoPmzFYhy3dABQsfZG8zF0H7JhFF3J8OMV/WOoGMUr8s9/OdckGniPgIKv0y0/3xs+u3BIHoHA+3xmq921T/3mKqx+p29Yy+O95vicbAQe5XYfW1R85CQtA0dKiwXnuOuAJr6Lr5rg8wX/WxzCq8qNLZ2PJwZJRskm/9P4MAceudbXcvM5dBAC8RNvUf4XLKZTjLl7YPWth/oNW1XLzJncRTIsODnJ6H8KNH5njBKBozsJSoIt44TnZNKpif9r35qc+0QvPEXCQhcVjDzKaAkDRUnfmb7nrgCPMIuLrSxaQVsvNh+gWxfPN+9wFMC0CDnKxeOh76/ShCAAl051J6d63Tf31BVdAdON+b36iPSewFwEHvUutavPMZQyND0MAipY+3y8zlwGnMI+Iv44Zr0jduEZVvqeLg94IOMhB98b3jKYAMAY+3xmTKo4cWUldudvTllO0WdvU17mLYBpcUaFXqUXtNncdA+JqCgDF8/nOyK0i4u0hV1ZcVflJGxG/vORSDexDBwd906L2PaMpABQt7SrQvcGYzePAkZV0VeXmTPWUqIoIXRycnYCD3qS3O7PMZQzJjdEUAEbAYtFv7iLibUQsMtfB6d2PrBzyJf1jGFXZ9dsLlrfCXoyo0Iv0y+zPEHDc20bEa216AJQsnX3/M3cdA/JLtdxsI/5+9rmI7mzuq5xFcXJ3EXG1z3OcUZWffHQ5kHPSwUFfrkO4sWuvD0UAGDijKd8s7sONiIhquWmr5WaRdm39Et24gs/+cbiIrpvj2eAqjarcnb2icrxvm3qWuwjGS8DB2aU3GL/lrmNA7tKHHQAUK42ezjOXMRRtRLx77P9YLTfbarl5Vy03/090+7dWfRXG2byKLuS42ONfexXCrV128nE2Ag76cB1mc++1YbEoAIWzWPQnn/ftzExdHW9CV8cYVBHx5blTsunvjY99FFSIS10cnIuAg7PSvfGTd0ZTABgBi0W/aeOIaxn3XR3RBR1XEWHxeLnet0395akFmtVycxM6d3bp4uAsLBnlrFKi7RdYZ5Xe2ABAsSwW/clVtdwsTvEflBZS/isiLk/xn0fv1hHxdncXyy4/Oz/55bH/X8GxdHBwNro3fvLobC4AFMRoyjfbU4UbEd1Cymq5uQrjK6V6FRF/PrZ8tFpu1mFUZZeXoJycgINzsnvjm5v0oQYAxbJY9Cdn2av1wPjK9hz/PZxFFV3IcfnI//0m/O95zy4OTs6ICmeRujf+CgFHRPch9truDQBK5rP9J72OnqYvzP8KAVNJblJQ9Z10eeVLhnqGaJG6luAkdHBwLro3vrFYFIAxsH5lTroAACAASURBVFj0e72Onu5cX3kTllWW4rpt6tsfl49Wy81d+N/wni4OTkrAwcnZvfGdVfoQA4BipeWX17nrGJBFrtHTtKfjTUS8johFjho4yGVEfH3gwoquhW/s4uBkBBycg+6NbywWBWAMLBb9po0BLIqslpv1zkLSReZyeNpPy0fT9ZDsfx8NhC4OTkbAwUnp3viOxaIAFK9t6uvovqDR+Tyk05ZpIamgY/hm0XVy7P4suZTzjS4OTkLAwanp3ugM4u0OALxEeqvqi8c32+i+lA6OoKMI311YSTvadPt2dHFwEgIOTkb3xncsFgVgDD6FFxe7Pg79813QUYTbnZBjERaO3hOm8mICDk7pIjwERUSs04cVABQrLRa9yF3HgKxK+nwXdAzebdvU97ttdP12Lh5YxgoHEXBwSlLXjlZDAIqWvmTc5q5jYIr8EroTdDgvOzzXbVPfVsvNKoRQEd2LUteaeJH/lbsAxiG12XkQirirlpu3uYsAgJdIb5Z90fhmkUKC4qXOnPcRMc9bCTsWEfE5Ir6Gbug2In4Z+igYw6WDg1PRvdHRvQFA0dKVB+HGN6NaHF4tN6tquXkTEVfRLU0lv8voXhQu8pYxCLo4eBEBBy/WNvVFdKevpu5mSGfjAOBIOjK/N6izsKdSLTeLarn5JbqXM96W5/cq7Ly596/cBVAuAQen4HLKyN7uADBNbVNfR/dFi842BnoW9lSq5eYmukWknmPym+UuYCBm91dm4FACDl4kzXHOM5cxBJ/NCgJQsrapZ2Hk9EeDPwt7CtVy01bLzYfogo67zOVAhN9FHEnAwUvp3ojYpocCACjZbVhwuKuos7CnkC6uvI3u4so6dz1M2iy9SIWDCDg4WnrTY1ZQSycAhUv7tOa56xiYyS4OT4tIX4f9HOSli4ODCTh4Cb90ItZTe7sDwLi0TV2FxaI/WlTLzeQ7GHb2cywyl8I0zdNVJ9ibgIOjpIch3RsTfrsDwGgYTfleGz7f/5b2c1yFsRXyMA7PQQQcHOs6PAytquVmlbsIADhWmnH3wuJ7k1gseihjK2RymcbiYS8CDo7lPrXdGwAUzGjKg9ZpLINH7IytuLZCXy5zF0A5BBwcLN2lnmUuIzfdGwCU7n34PP+R0ZQ9pLGV+2sr28zlMH6/pUAWniXg4Bhm4SKuchcAAMdKoynXuesYmIWXF4dJ//96HRG6Xjgnu//Ym4CDg6QHoqlvM15Uy802dxEAcAyjKQ9qw+jpUVI3x7vogg5LSDkX1xvZi4CDQ9m94QEIgLIZTfnZZy8vXqZabtZpCannJM5hll60wpMEHOwtbTC+zFxGbro3ACiW0ZQHbavl5kPuIsYi/f9SNwfnYEyeZwk4OMRl7gIGwFsJAEpmNOVn9mqdmG4OzuTCyVieI+DgEFMfT9G9AUCx2qb+EEZTfnRnsej56ObgDC5zF8CwCTjYi9OwEeEtBACFapv6VVjS96M2nIU9O90cnJgxFZ4k4GBfujd0bwBQLqMpP/vos70/qZvjTURs81ZC4ar04hUeJODgWWnWbZ65jNy8dQCgSG1Tfwon3n+0rpabm9xFTE0aB3odEYu8lVC4qb945QkCDvYx9VYw3RsAFMnVlEcZTcmkWm7aarm5ioi30Y0JwaHmlo3yGAEHT2qbugrLfHRvAFCc9BluNOVnC4tF86uWm7voujlWmUuhTFN/AcsjBBw85yIiqtxFZHSnewOAQr0PC8J/ZLHogFTLzbZabt6El0kc7jKFuPAdAQfPmXo6+jl3AQBwKKMpj3pXLTfGIgZmZwGp/23YVxXdi1j4joCDR6XZtikvJVtpYQWgNEZTHrWqlptF7iJ4WHrm+iWMrLA/y0b5iYCDp0y9e0O7JAAl+hRGUx5iNGXg0gJSIyvsy7JRfiLg4CmXuQvIaK17A4DStE19EdP+/H7Mx2q5Wecugv0YWeEAU38hyw8EHDyoberLmPZyUbs3ACiK0ZRHbSPiJncRHMbICnu6zF0AwyLg4DH/zF1ARlszugAU6Dam/XLiMVcWi5ZpZ2RFQMVjqtS5BhEh4OABaZZtyr8ozH0CUJS2qa9j2p/dj7kzclq+arl5FxFXYWSFh1k2yt8EHDzkMncBGbURcZe7CADYV3ox8T53HQPURvelmBFI3bVvohs5gl0Xlo1yT8DBQ6acgn7WxgpAYYymPOydz/RxSYtiX4e9HPxMBxsRIeDgB21Tz2Pap+UWuQsAgH21Tf0hIuZ5qxiklX1a42QvB49wTYWIEHDwsyl3byyq5WabuwgA2Efb1K/CaMpDjKZMwM5eDoiImKXfiUycgIMfTbm9y2lYAIqQTsJ+yV3HQH32wmIaUpfO67B8lM6UX9SSCDj4W9vUlzHdGd5VmusEgBJ8immPlD5mXS03H3IXQX929nJ4juMydwHkJ+Bg1z9zF5DR77kLAIB9tE19ER7kH2NkYYJSx86bsHx06qr0+5EJE3AQEX+3uk71F8LWIjIASpBOId7mrmOgbnRjTtfO8tFF7lrIasovbAkBB99c5i4gI90bAJTCSdiHbSPiY+4iyK9abq4i4l3uOsjmMr24ZaIEHNyb8lIeZ8YAGDwnYZ90VS03Fk0SERHVcnMTxpWmbKpd6YSAg/i73XWqZ5UWHogAGDonYZ90Uy03q9xFMCwurEyaMZUJE3AQMe2U03gKAIPmJOyTtmE0hUeknSxvQsgxNRfGVKZLwEHEdMdTtt74AFCA23AS9jHvdGLyFGdkJ2vKL3AnTcAxcRMfT/HGB4BBa5v6MjyoP+auWm7uchfB8O2ckRVyTMdvuQsgDwEHU/3hbyPCQxEAg5X2bnzKXcdAtWGJJAdInT5Cjul4lV7kMjECDqb6VuhOSysAQ5Xmx52EfZyrKRxsJ+RYZC6Ffkz1e86kCTgmLL0ZmuWuI5PPuQsAgCe8j+mOkD7HaApHq5abtlpurkLIMQVT3TM4aQKOaZvqD/02LZwCgMFpm/oiIq5z1zFQRlM4CSHHJBhTmSABx7RNtW1L9wYAg5Qexm9z1zFgRlM4GSHHJEz1+85kCTgmKj1AzTKXkcsidwEA8IgvYe/GY4ymcHJCjtGbasf6ZAk4pmuqaebCmx8Ahqht6k9h78ZjjKZwNkKOUXuVljYzEQKO6Zpqmvnv3AUAwI/s3XiW0RTOSsgxalN9sTtJAo4JSuMpU3xDtNXaCsDQpKtm9m48zmgKvRByjNY/cxdAfwQc0zTVFNPDEQCDklqnb8Pejcdsw2gKPRJyjNKFMZXpEHBM01RTTNdTABgaezeeZjSF3gk5RmmqL3gnR8AxMSm9nOeuI4N1tdxscxcBAPfapr6MiMvMZQzZTbXcrHIXwTQJOUZnqi94J0fAMT1TTS9/z10AANxLezc+5a5jwLYR8TF3EUybkGNU5rkLoB8CjumZanq5yF0AAETYu7EnoykMgpBjNKp0rYqRE3BMzzx3ARnceUgCYEBuw96Np3w0msKQpJBjlbsOXuzX3AVwfgKOCUmp5RTfFv07dwEAEBHRNvV1THdcdB/rarn5kLsIeMDbiFjnLoIX8bt3AgQc0zLV1NJ5WACya5t6HvZuPMdJWAYpdQO/CSFHyWZp/xEjJuCYlimmlgvjKQDklvZufMldx8C9q5YbXx4ZrJ2Qw7Nluea5C+C8BBwTkdLKWe46MjCeAsAQfI1pjonua1UtNze5i4DnCDmKN9WDC5Mh4JiOee4CMmir5cZ4CgBZtU1tqejT2jCaQkFSp5GQo0zz1FHHSAk4pmOKaaVwA4Cs2qa+jIjLzGUM3VW13GxzFwGHSCHHu9x1cJQpju1PhoBjAlJKOc9dRwbGUwDIJo2H3uauY+AWui0pVbXcLEL3UYmmenhhEgQc0zDPXUAGxlMAyCa9XPiau46B24Y34BQuhRyLzGVwGB0cIybgmIYpppTCDQByslT0eVcunTEG1XJzFZ49S1I5FzteAo5pmGJKaTwFgCwsFd3Lx2q5WeUuAk7oKiKcOS7HPHcBnIeAY+Tapp7F9M7DGk8BIAtLRfeyrpabD7mLgFNyPrY4UzzAMAkCjvGb5y4gg1XuAgCYHktF99JGxNvcRcA57IQcDN88dwGch4Bj/KaYThpPAaBXloru7Z2TsIxZOh/rskoB2qae4hj/6Ak4xm+eu4AMjKcA0JudcMNS0act0sUJGLX09/lN7jp41hQPMYyegGPEUqvs1B627mxkB6Bnn8JS0edsw0lYJqRabt6Fsemhm+cugNMTcIzbPHcBGfyRuwAApqNt6uuwVHQfb72AYILeRhfuMUyvUgceIyLgGLcp7t8wngJAL9L89qfcdRTgXdpLAJOSQr234bLKkM1zF8BpCTjGbZ67gJ6tLS4DoA8upuxtVS03dhEwWSncM541XPZwjIyAY6Tapp7nriED11MAOLvU0vwlprfn6lBOwkJYOjpwLqmMjIBjvOa5C8jAeAoAffgaEbPcRRTA3g1I0tJRo1rDM2ubepa7CE5HwDFeU2u3as33AnBubVPfhosp+/hYLTer3EXAwNjHMUzz3AVwOgKO8ZrnLqBnujcAOCsXU/a2qpabD7mLgKFJu+KuctfBT6b2YnjUBBwjNNH9G87DAnA2bVNfhosp+7B3A55QLTd3YR/H0OjKGxEBxzjNcxeQgQ4OAM4iXUwRbuzH3g14hn0cg/MqLY9mBAQc4/SP3AX0bO1hCoBzSMvnvoaLKfuwdwP2Zx/HsMxzF8BpCDjGaZ67gJ45DwvAyTkHexB7N+AA9nEMjj0cIyHgGJnURju1B7FV7gIAGKUvYTZ7H/ZuwBHSPo5F7jqIiOm9IB4tAcf4zHMX0LNWOywAp5bOwc5z11EIezfgeO8iYpu7CITZYyHgGJ+p7d9Y5S4AgHFxDvYg9m7AC6Rw0KjKAEz0EuXoCDjGZ567gJ45DwvAyTgHexB7N+AEUkj4MXcdTO571CgJOEYkLUOb5a6jZ6vcBQAwDmmP1W3uOgph7wacUAoLnY7Na2qd8KMk4BiXee4CeratlhsfBAC8WAo3vuauoyBv7N2AkzOqktc8dwG8nIBjXKa2HGeVuwAAyucc7MHeecEAp5d+royq5FO1TT3LXQQvI+AYl6ndb7Z/A4AXSeHG15jeiOexFtVyc5O7CBgroyrZzXMXwMsIOMZFBwcAHOZLTO/z81jr6E5aAudlVCUfezgKJ+AYiTQ7PKXW2m213GxzFwFAudqmvg1v6/bVRsSVvRtwfkZVshJ4F07AMR5T+2Fc5S4AgHKlcOMydx0FubJ3A/pjVCWbee4CeBkBx3hMrZ3K/g0AjtI29WUINw5xUy03d7mLgAkyqpJB6oynUAKO8ZjaD6JEG4CDpXDjNncdBVlVy429G5BB6pqy1Ld/89wFcDwBx3jMcxfQo1abLACHapt6HsKNQ2wj4m3uImDiPkb3s0h/ptYZPyoCjhGYYBvVKncBAJQlfVZ+yV1HQdqIeGupKOSVfgaNqvRrat+tRkXAMQ5T+yH8T+4CAChHCje+xrSujb3UO92SMAzVcrOKCHtw+jO171ajIuAYh6m1Ua1yFwBAGdqmrkK4cahFtdwschcBfOdddJ1V9CCNNFIgAcc4TCplTCk2ADxJuHGUdbXcaIeHgamWm21EfM5dx4RM6vvVmAg4xmGeu4AerXIXAMDw7YQbHlL3t42IN7mLAB5WLTcfwsLRvvx37gI4joCjcBNcMGoeGIAnCTeOYqkolEGHVT98fhRKwFG+We4CembBKADPuQ0Pp4eyVBQKYOFob+a5C+A4Ao7yTe0BbpW7AACGq23q24i4yF1HYW4sFYWiWDjagwl2yo+CgKN8v+YuoEdtWrAEAD9J4cZl7joKc1ctN+9yFwHsz8LR3sxyF8DhBBzlm+UuoEdaZwF4kHDjKOswzw+lugkLR89NB0eBBBzlm+UuoEd/5C4AgOERbhyljYgrS0WhTOln92PuOkZuSp3yoyHgKFjb1PPcNfRMBwcA32mb+jKEG8d4a6kolC3tzvFzfD6z3AVwOAFH2Wa5C+iZX+AA/C2FG7e56yjQVbrEAJTPDp3zmeUugMMJOMo2y11AjywYBeBvwo2jLVxMgfFIYeUqcxmjNcGO+eIJOMo2pbkw3RsARIRw4wVW1XJjqSiMjy6O85nlLoDDCDjKNstdQI8sGAVAuHG8dUS8zV0EcHppn84idx0jNctdAIcRcJRtlruAHm1zFwBAXsKNo7mYAuPnosp5TKljfhQEHIWa4DyYERWACRNuvIiLKTByaVfdInMZYzTLXQCHEXCUq8pdQJ88mAFMl3DjRVxMgen4GF3HFqczy10AhxFwlOtV7gJ6JNwAmCjhxou4mAITkro4PueuY2zapp7S967iCTjK9Y/cBfRIwAEwQcKNF7lzMQUm6SZ0cZzapDrnSyfgKNeUftD+J3cBAPRLuPEi64gQbsAEpWXCujhOa567APYn4CjXPHcBPVrlLgCA/gg3XqSNiDcupsCk6eI4rf/KXQD7E3AUqG3qKXVvRDgRCzAZwo0XEW4AujhOzw6Oggg4yjSpH7K0MAmAkRNuvJhzsMA9XRynM8tdAPsTcJRplruAHq1yFwDA+Qk3Xsw5WOBvqYvjLncdIzHLXQD7E3CUaZa7gB5JngFGTrjxYjfOwQIP+Ji7gLFwKrYcAo4yTelE7H9yFwDA+Qg3XmxRLTfvchcBDE8a815kLmMsprYDsVgCjjJN6QfMLDHASAk3XmxdLTfOwQJP0cVxGjo4CiHgKNM8dwE9MqICMEJtU1+HcOMl1hHxJncRwLDp4jiZKb1gLpqAg0GzMA1gfNqmvo2IT7nrKJhzsMAhfs9dwAj8mrsA9iPgKEzb1PPcNfRom7sAAE4rhRuXuesomHADOEh6YbjKXAb0QsDBkG1zFwDA6Qg3TuJNtdzYTwUcShfHy8xzF8B+BBzlmecuoEce4ABGQrhxElfCDeAY6ZT0NnMZcHYCDobs/+YuAICXaZu6apv6awg3XuoqfUEBONbn3AWUrG1ql1QKIOAozz9yF9Ajb6kACtY2dRURX2Na3YfncCPcAE5gES4UvoRLKgUQcJRnSj9YfgEDFGon3PDG62UW1XLzLncRQPnScuK73HUUzOdZAQQc5ZnlLqAvTsQClCm18Qo3Xu6uWm6uchcBjMrH3AUUbEovmosl4CjPLHcBAPAY4cbJrCNCuAGcVLXcbMPJ2GP9d+4CeJ6AoyCp3XcqVrkLAOAwO+HGlD6vzmEd3TlYo5rAOVg2epxZ7gJ4noCjLN6GATBIbVNfhnDjFLYh3ADOqFpu7sLJ2GP4fCuAgIOh+iN3AQDsJ4Ubt+Hh76XaiHgr3AB68HvuAgrkZXMBBBxl8UMFwKC0Tf0hunCDl2mj69xwIh3owyJ3AXAOAo6yTOnNmAc8gIFrm/o2It7nrmMEhBtAr9KyUSdjD5R2TTFg/yd3ARzkv3IX0CPtuQADlZZe30bERe5aRuJKuAFk8Hv4PX6oKb1wLpIOjrJMKTHc5i4AgJ+lcONreCg+lau08A+gV5aNMkYCDgYptc0BMCA7Z2CnFLif01W13CxyFwFMmoD1MPPcBfA0AUdZZrkLAGCahBsnJ9wAhuBz7gLglAQcZZnlLqAnq9wFAPBNOgP7Ncwen8o74QYwBKlr2g6g/U1pJ2KRBBwAwKNSuHEbwo1TWVTLzU3uIgB26OLYny7GgRNwFKJt6lnuGnq0zV0AAH+fgb3NXceILKrl5ip3EQA/sIeD0RBwlGOWu4Ae/U/uAgCmrG3qqm3qLxFxmbuWERFuAINULTdtCDn2pZtx4AQcAMDfnIE9C+EGMHS/5y6gEEZUBk7AUY4ppYUWHQFkkC6l/BUe4E5JuAEMXrXc3EVEm7sOeCkBRzmm9LDplytAz1xKOQvhBlASYyoUT8ABABPXNvWHcCnl1IQbQGn+nbuAEkzs+ENxBBwMkREVgB6kZaK3EfE+dy0js46Id7mLADiEMZW9zXIXwOMEHOX479wF9CVtcgbgjHaWiV5mLmVs1hHxxmcZUChjKhRNwFGOWe4CABgHy0TPRrgBlM6YCkUTcDA029wFAIyZZaJnI9wAimdMZS+z3AXwOAEHQ7PNXQDAWLVN/SksEz0H4QYwJsZUnjbLXQCP+z+5C2BvHkYBOErat3EbERe5axkh4QYwNv8O+5kolA6OcpiTBuBgad/G1xBunINwAxgdYyqUTMDB0GxzFwAwFm1TX0QXbgjJT0+4AYyZMRWKJOBgaP4ndwEAY9A29YeI+BJGHM9BuAGM3R+5CxiwX3MXwOPs4ACAEbFv4+xWEfFWuAGM3F10nyVQFB0cADAS9m2c3aJabnRuAKOXfs8ZU6E4Ao4CtE09z10DAMPWNvVl2LdxTotqubnKXQRAj4ypUBwBB0OzzV0AQGnapv4UXSuxfRvnIdwApkgHB8Wxg4Oh2eYuAKAUad+Gro3zEm4Ak1QtN9u2qbcRMctcCuxNBwcAFCiNL/4Vwo1zEm4AU6eL42fz3AXwOAEHABQmnYD9GkZSzkm4AWAPB4UxogIAhUgjKV/C26Nzu6mWm3e5iwDIrVpu7tqmzl0G7E0HBwAUIJ2A/TOEG+d2JdwA+M4qdwGwLwFHGcxXA0xY29TX0YUbs8yljN1VtdwschcBMDD/zl0A7MuIShmmNGO9zl0AwFCkkZTbiLjIXcsECDcAHrbKXQDsSwcHg1ItN23uGgCGYOdKinDjvNoQbgA8qlpu1tH9roTBE3AAwMC4ktKbNiLeCDcAnrXKXQDsw4gKAAyEKym9ug83jEYCPO+P0FFIAXRwAMAAtE19Ed1IyjxzKVMg3AA4zCp3AUPSNvUsdw08TMABABm1TV21Tf0pus4NIynnt46IX4QbAPuzh+Mns9wF8DABBwBk0jb1q+h2bVznrmUi1tF1bnhIBzjcKncB8BwBBwBk0Db1dUT8GRGvctcyEasQbgC8xB+5C4DnWDIKAD2ySDSLRbXcXOUuAqBwq9wFwHN0cABATywSzUK4AXAC9nBQAh0cAHBmqWvjfdi10berarlZ5C4CYETWIaRnwHRwAMAZtU09j27XhnCjX8INgNOzh4NBE3AAwJm0Tf0huisps6yFTEsb3TLRRe5CAEZolbsAeIoRFQA4sXT+9TZcSOnbfbixzl0IwEj5/cqg6eAAgBNKXRvOv/ZvHRGvhRsA55NObfs9y2Dp4ACAE9C1kdU6us4N2/0Bzm8dPusYKB0cAPBCujayWlTLzWvhBkBvLBplsHRwAMCRdG1kd1MtN+9yFwEwMUZUGCwdHABwBF0b2V0JNwD6Z9cRQ6aDAwAOoGsjuzYi3lbLzSp3IQATtoqIeeYa4Cc6OABgT7o2srs/A7vKXQjAxOniYJB0cADAM9qmnkfEpxBs5ORSCsBw/Cd3AfAQAQcAPKJt6ioi3kfEde5aJm4REe+EGwCDsc1dQGbz6MZ0GBgBBwA8IHVt3EbELG8lk+dSCsDAVMvNqm3q3GXATwQcALAjdW3cRsRF7lqIq2q5WeQuAoAHrcPoJgNjySgAJG1TX0fEXyHcyK2NiNfCDYBBs2iUwdHBAcDkpdOvn8LJuyFYR3cGdpu7EACe9D+5C4AfCTgAmKw0jnId3SJR8ruLbizFMlGA4VuFz08GRsABwCS1TX0RXdfGLHMpdCwTBSjLNncB8CMBBwCT0jb1LLpgw56N4bBMFKAw1XKzdUmFobFkFIDJaJv6Q0T8GcKNobBMFKBsq9wFwC4dHACMXtvU8+hOv87yVsKOdUS8sW8DoGjb3AXALgEHAKNlHGWwFtVyc5W7CABezCUVBkXAAcDouI4yaPZtAIzHKnzWMiACDgBGpW3qy+getmZ5K+EHbUS8rZabVe5CADgZY4YMioADgFFom/pVdOMo88yl8LN1dOHGNnchAJxOtdysXVJhSAQcABQtjaN8iojLzKXwMPs2AMZtHRGvchcBEQIOAAqWzr7+FhFV3kp4hH0bAOM3xTGVf+QugIcJOAAojj0bg9dGdwJ2nbsQAM7uj5jeeKgXKwMl4ACgGG1Tz6MLNuZ5K+EJq+j2bUzxjR4AkJGAA4DBa5t6Ft2ejYvMpfC0m2q5eZe7CAB6tQqnYhkIAQcAg5UWiL6PiOvctfCkNrp9G3e5CwGgdzr2GAwBBwCDk4KN67BAtAROwAJMmFOxDMn/zl0AAOxKC0T/jK5zQ7gxbIvololuM9cBQF66OBgEHRwADILLKEVpI+KdE7AAJOuwAJwBEHAAkJXLKMVZR7dvwwlYAO7p4GAQBBwAZCHYKNIius4ND7IA7PpPuHTGAAg4AOiVYKNIRlIAgMETcADQi7apZ9EFG5d5K+FARlIAeM4qus94yErAAcBZCTaKtggjKQBAIQQcAJyFYKNobXRdG3e5CwGgCLr8GAQBBwAnJdgo3joi3lbLzTZ3IQCUoVpu2rapc5cBAg4ATkOwMQofq+XmQ+4iAChSGxFV7iJ6MstdAA8TcADwIm1Tv4qI30KwUbI2uq6NVe5CACjWOqZzIW2WuwAeJuAA4CjOvY7GXXT7NiwSBQCKJuAA4CCCjdFooxtJucldCACjMKUODgZKwAHAXtqmvoyIf4WHlzFYR9e1Yes9AKfyf3MXAAIOAJ6Ugo33Yd50LG6q5eZd7iIAAE5NwAHAT9qmriLiOrqOjVneajiRbXRdG6vMdQAwTroCyU7AAcDf0qnX+4soUzn1NgUWiQJwbj5jyE7AAYBTr+PVRhds3OUuBADg3AQcA5Xeos6iW+b3a85agPFqm/oiumBjnrkUTm8VEW91bQDQEyMqZPe/chfA37Pur+JbmPEqJtoaXi03/p6EM0u/cy6jCzZmWYvhHJx/BSCLtqn/v9w19Gyd/vhPRKxcJ8tPB0cmbVPPI+Kf0YUar7IWA0yC/RqTsIpuJGWbuQ4AmIJXsfNdrm3qNrrP4j9C4JGFt+U9SW9ML6ILNS4ylzNYOjjgE8TNSQAAIABJREFU9FKg+lv43TNmujYAyK5t6v83vETZtY0u8Pi3fVj98GXyjIQahxNwwGns/P55H8ZQxm4VujYAGIC2qb+GvV6PaaO7aibsOCMjKmeQlvb9M1wjAHqWxlDeRxdueIMybro2AKAc9zvQLtum3kYXdnz2guK0BBwnkt6WXkfEv8LbUqBnbVNfRvf7Z563EnqyCl0bAFCqWXTfHa/bpl5FxO/VcrPIWdBYCDheaOdt6WXeSoCpsTR0knRtAMC4zCNi3jb1+4j4PSJunHg/noDjSGlp3/vwthTomW6NyVqFrg0Ahu2P8HxyrFl03y9/a5v6cwg6jmKh44EEG+dlySg8TLfGpOnaAGDw0gsYy81P6ya6ZwBBx558mdxT+nLxKVxDObdfvJ2Eb3RrTN5dRLzzexGAofIC+OzaiNDRsScBxzPS8tBPYcdGnySVTFrb1K+i69ZwCWW62ujGUZyRA2CQ0gvg2xBs9EVH5x4EHE9om/o6ujTSF4z++QFmUtJDwkV0wcYsazHktoiua0PIC8DgpBfA76O7AkL/1tE9J6xyFzJEAo4HpLentxHxKnctxDq6t5jr3IXAOaQRlH+G8TcittH9vltlrgMAHtQ29UV03e2zzKXghciDBBw7pJGD9rFabj7kLgJOIc2q/iuMoPDNxzBbC8BApe9Jt+GFzNAYaf2BgCNJXzhuQxo5ZLo5KFbqDLsPNWZ5q2FAVtG9ffF7DYBBSl0bt+GlzJDdRfc9afIvSgQcEdE29YfoOjcog24OimCvBk9oows2FrkLAYCH6Noojm6OmHjAkb58fAm7Nkq0iu4HeJu5DvjOTqjxr/C7hYctwswsAAOmu71oN9Vy8y53EblMNuDQajUKUkoGQajBnmw9B2DwdLePwjoi3k7xZfAkA462qT+FRaJjYmSF3gk1OEAbEZ/9ngJgyIykjM4kXwZPKuBIP7RfImKeuRROz2Idzk6owRHuouva2OYuBAAek5ah34bnmzGa1MvgyQQcfmgnYbKtWJxP+t1xERH/DL8/2N82utB1lbkOAHhS2rfxJYzuj9kiJrL/axIBR/qC8jX80E5BGxFvnFzkJdIH/T/DSVcOZxwFgGK0TX0Z3Utgxm8d3fekUYccow840g/tpxBuTEkbXSfHKnchlCGNr11ExK/pz35fcIxFdG2g28x1AMCzLBOdpNF3vI864JBITt5VtdwschfBMKXOrnl0nRrzrMVQOtdRAChK29S3EXGZuw6yGHXH+2gDDuEGiZCDiPi7S2Me3wKNWcZyGIc2umBjkbsQANiXcIMYccgxyoBDuMEPhBwTpUuDM7qJbhxl1HOsAIyLcIMdoww5RhdwCDd4hJBjAtIZ13nYpcH5rKL7fbLNXAcAHES4wQNGF3KMKuAQbvAMIcfI7Iyd/Jr+7Iwr57INZ18BKJRwgyeMKuQYTcAh3GBPQo6CCTTIwJ4NAIom3GAPowk5RhFwtE09j4ivueugCKP54Z0CgQaZfYyIG3s2AChV29TXEfEpdx0UYR3d96Sin3uKDzjSEsGvYdae/Qk5Birt0HgVAg3yWkS3QHSbuQ4AOJoOd45QfMhRdMCR3u7+FcINDreNiNcl//COwc6Vk3+E063kt4puHEX4CUDR0jPWn7nroEh31XLzNncRxyo24Ejhxtfwhpfjravl5nXuIqZipztjt0MDhmAbFogCMBLpmevP8BKY491Uy8273EUco+SAw7IcTmFRLTdXuYsYmxRA7nZnvArdGQzPNrpRlEXmOgDgJLwE5oSKPM5QZMBhWQ4nVuQP71AIMyhQGxGfq+XmQ+5CAOCUvATmhIrcW1hcwGGejDMo8oc3hx/GTIQZlKaNiM/hMgoAI+QlMGewjcL2FhYVcKQ3xX+GL1Sc3jYK++E9p52ujFcR8d/xrUMDSrWIboGon3EARsdLYM6oqKWj/yd3AQe6DeEG5zGLLvGe1D6O1JExi++DjFdhKRXjsQgnXwEYsfRi6kvuOhiti7apL0sZ6S+mg8MdZ3rytlpu7nIXcUo73Riz9Mc/ogsw5tmKgvNbhGADgAmwd4MetNF1u29zF/KcIgIOp47oURsRv5TWxp7aEu+DjCqEGEzXXXSjKNvchQDAubVNfRG6N+jHulpuXucu4jmljKjchnCDflTR/f02mDmznQ6MiG+BxX2AYZwEOqvoOjZWmesAgF6kZ0Qd7vTlVdvUH4Z+hW7wHRy2AZPJ2UdV2qae7/zT+3/8X/EtzBBewPNWIdgAYIKMppDB4EdVBh1wpFTyr/Alj/49OaryQzhxbxY/L8H99Zn/O3CcVQg2AJio9Cz6NXcdTNKqWm7e5C7iMUMPOKSS/P/s3U+SFEe2N+yja3f+5V1Bp8xy3mgFSlbQMM2JihUAKwBWAKygSpOcUr0CUitQaZ5myl7BjbuC9xuEJxRQ/yszjkf485hhUqsRcQRVkR6/OH4c4LJNCDYAaFy3WvwdXpyR50Wtp6pUG3BIJQG45CwifhdsANC6brV4GxFvksugbdUezFDzkFFzNwA4C8e9AkBEfDld8mV2HTRvFhGvIuJtch0/+K/sAq7SrRYn8XXQIgDtOYv+zcAL4QYAfPEmzCekDm9K4FaV6jo4ymBRLVcA7eki4jx0bADAD7rV4kmYT0hd3kTEi+wiLquxg+NVGJgD0JIuIt6Fjg0AuIkt/NTm5JrTJdNU1cFRujfsKQNowy4iPkbEWY1DqgCgFuUhcplcBlzlTfSn3FWhqoAj+u4Ne8oApm0X/TaUs+Q6AGAsbOGnVstutVjWctJdNQGH7g2AydtEH2xskusAgNHQvcEIVNPFUdMMDt0bANN0FhG/zNbbp8INALg3L4Gp3bKWE1Wq6eCIiN+yCwDgYLr4Ol9jl1wLAIxSeWh8ll0H3EEVJ6pU0cHRrRYn4eQUgCnYRf/h9vNsvX0r3ACARzF7g7E4qaGLo5YODm1XAOO2iYiPs/X2PLsQAJiCMqNQ9wZjchIRbzMLSO/g6FaLJxHxJLuOidpkFwBMWhf9fI2fy3wN4QYAHM5JmFF4DF1EXGQXMVHpjQs1dHCk/yaM2EX0IcZ/yt9fzNbb7rqfXFqG5tEHSv+IfhqzcAm4r118na9x7T0HAHgUz0kPt4mIP6Jfs+xuG3J+6TlpGV+fk+bHKm7CZt1qcTJbb8+yCvgp68IRX9qu/g7J5F11EXEe/Tfr+SEeLC61vv0rtMABNzuPfhvKJrsQAJiycjTs5+w6RmTfVfrHoTpKLw14/S28FL6P89l6+zzr4tkBx0lEnGbWMBIX0b8tPUiocZ1LYcebkFgCPaehAMDAutXiNPotKtzsPCJ+P/Y22RJ2nETfVePl/O1+zlo3Zgccn6Nv/+Fqm4h4l/G2tKTGb8KfD7RqE/2C4Sy5DgBoTrda/G94kL7JWfTPSbuhL1xe0nshfLPXs/X2Q8aF0wKOkoL9nXX9yu0i4kUNbeDdavEsIt6Hb2Bowb6986NuDQDIocv9RpvoH57Th4R2q8Xb0NFxnYvZevtLxoUzA45X0T848613s/X2bXYRl5WtK6/COdwwVZvQrQEAVehWi09hNt73uuhfAFd1Ylt5TjoNf15XSdmmkhlw/BmGtVx2Ef03bXoaeZ1ypO+n0M0BU6BbAwAq1K0W/y+7hspsIuJ5zSe3la6b96Gb47KUbSopAUdJuv4349qVOo8+3Kj2m3ZPSgmjN8gwLgDg/sr28E/ZdVSkuu7265SXwafhJf5eyjaV/xr6goWH46/ezdbbqhPJy2brbVeO/UkZGgM8yC4iXkffKvhcuAEA1fpXdgGV2G9JeZtdyF2VTvyn0XecEPGkzN0c1H8PfcHCN27vxVj3vM/W29fdavFXGIAEteqi79b4WPPWNwDgG8vsAirQRcTTMa5fykvrp475/WIZ/ZbowWRtUXHs0YjDjctMeYbqnEfEv6dwfwGAlpQtDn9m15FstOHG94QcERFxXrr/BzP4FpXyjSvcmMjDR/nveJddBzTuIvotKP9TtqCcJdcDANzfMruACkwi3IiImK23L6J/8dSy5dAXzJjBsUy4Zk3OpvbwUfbGnSWXAa3ZRT8L5+fZevvLbL39MJZZPgDAlX7NLiBZ1SdKPtCL6F9EtWpWGhwGkxFwtPyNuylJ3uSU/66Wv3lhCF30ocYvs/X259l6+9oRrwAwGcvsAhJ9mNpL4IgvMzmeR7+Ga9VyyItlDBldJlyzBvsv7il7Hv2+wda3IMEh7YeF/tvpJwAwTY1v49/M1tvX2UUcy2y93XWrxYto9/jffw55sUE7OMoxMa1+476Yevt4eZM8yQ4VGFgX/bav57P19n9m6+0L4QYATNqgbfwV6aKB54eyjvuQXUeS5ZAXG3qLSqvfuOetPJyU/85Ndh0wQkINAGjXoG+5K/Kuoe2276KfodaaebdaDNbkMPQWlRYDji760w1a8iIi/s4uAkbA9hMAIKLN56SL2XrbTFfDbL3tutXiXUScZteS4EkM9BJ86A6OFgeMfmwolYyIL1tVHB0LV9OpAQB8b5ldQILWXgJHGaS6SS4jw3KoC+ngOK79iQct+hARL6PdmStw2S6+dmpscksBAGpS5hS2ZtPwmuhdtBdo/WOoCw0dcLT2sPtx6oNFr1NasM4i4lV2LZDkIiL+Hf0MHkcoAwDXmWcXkKDZbu/ZervpVouLaOvl/3yoCw0WcHSrxXKoa1XkLLuAZB9DwEFbziPij+hDjV1yLQDAOCyzCxjYruHujb2P0dYsjuVQFxqyg6O17o3mH3DKmc/nEfEsuxY4kl30+yj/HX2rZZMdWwDAo/x/2QUM7GN2Adlm6+1Zt1q8j/aekY9uyICjpRaciIjfswuoxL9DwMG02HoCABxSa89JZ9kFVOI8Ik6yixhKt1osh+jcGTLgaCmZ7JyK8MV5tNV+xfTsou/S2G890aUBAPAw1lJf/R4NBRxD0cFxHJvsAmpRho3apsLYbOLrthNdGgDAMS2zCxjQH9kF1KIMG+2inW0qyxjgOXnoU1Ra4Rv3W3+EgIO6XUTp0tB9BQBwNJvsAiqzCc9JBzVkwDEf8FrZNtkFVMYbcGqzC8NBAYBk3WrRytv7iH4bv+eCb7X0IniQkRUCjiPwjfut0n6VXQZt28XXORqb1k84AgCq0dI2fs9IP2rp92SQr3VbVA5vk11ApS6irRs4uXYh0AAAqIlt/D9qKeAYhIDj8HbZBVTKFgCO6csMjYi4EGgAAFTH88B3yoEMLQ0aPToBx+H9J7uASv0RbU2I5rg2Ubozog80fGACANRNt8LVLsJz0sEMEnB0q4WtCcBDXZQff4VjWwGAaZlnFwBTMlQHR0stN7vsAmDEuui7Mv4K3RkAwPTNswsYkDVd2wwZHalddgGVckPje130nRl/lL+anQEAMFG6cK/VyhaVQZoeBBwMxQ2tbbvyQ5gBAABf/V92AVMi4AAObRN9mPGfsM0EAOAmu+wCYEoEHMBDXUT/ofzX/u+1HgIA3MsuuwCYEgEHcJtN9PMyBBkAADyEbl4GIeBgELP1dtOtFtllcL1dfJ2RsR/+uTMnAwDgqFp5adTKfyfJBBwMaRdtHYVVm035qxADAKACs/W261aLLgY6YSLRLrsA2iDgYEgXIeA4ll35sd9KElECjdl6u8koCACAO9lExLPsIo7sj+wCaIOAgyH9EdO/eR/aLr4m3hfRHyO1776IcEIJAMDYtbBGtkWFQQg4GNJ5RLzPLiLRRXw7YOlykr2Lr0GGbSMAAO3YZBdwZAbUMxgBB4OZrbe7brXYxXS3qZxFxO/l7zs3cgAAbjNbby8mvkY+zy6Adgg4GNrHmG4Xx0ehBgAAD/B7RLzJLuJIfr/9p8Bh/Fd2ATRnqgnuhXADAIAHOssu4EiskRmUgINBldkSZ8llHMPH7AIAABgna2Q4DAEHGd5lF3Bgu9l6e5ZdBAAAo2aNDI8k4GBwE0yoX2cXAADAuFkjw+MJOMjyOr49MnWsNrP1dqpzRQAAGJY1MjyCgIMUs/W2i4gX2XU80hT+GwAAqERZI4+988EamTQCDtKUVPcsu45HeF1aCQEA4CDK3Ioxdz9YI5NGwEG21xExxqOjzgxNAgDgSF6ENTLcm4CDVKUN72mMa6/hZrbearsDAOAoyhr5eYxrjXxujUw2AQfpRhZyXET/YQMAAEdTtnmMaY0s3CCdgIMqzNbbi6j/Br6JiKclkAEAgKOyRob7EXBQjXID/znq3G94Nltv3bgBABhUWSP/EtbIcCsBB1W5tF3lLLmUvS4iXthPCABAlkvbVc5yK/nCGpkqCTiozmy97crNMnuw0ib6druzxBoAAMAaGe5AwEG1ZuvtefRbVt4NfOl9Iv20tAQCAEAVLq2RPwx86V1YI1M5AQdVK0n12+hv4mdx3LR6FxGvI+JniTQAALUqa+TXMewa+RdrZGr339kFwF2UfYcvutXidUQ8i4iXEfHkQL/8eUT8XtJwAAAYBWtk+JaAg1EpQ0jPIuKsWy1m0d/I/xn9jXx5h1+ii34C9R8RceGGDQDA2F2zRv41IuZhjUxDBByM1qUb+Te61WJ5xU/v7BUEAGDqLocd+39WQo+rOjuskZkUAQeTM1tvN9k1AABALUroscmuA47NkFEAAABg9AQcAAAAwOgJOAAAAIDRE3AAAAAAoyfgAAAAAEZPwAEAAACMnoADAAAAGD0BBwAAADB6Ag4AAABg9AQcAAAAwOgJOAAAAIDRE3AAAAAAoyfgOLxZdgEAAACMwq/ZBUyJgOPwnmQXAAAAABW5GOIigwQcs/V2M8R1AAAAgOp0Q1xEBwcAAAAwegKOw/tndgEAAACMwjK7gCkRcByeIaMAAAAwsCEDjkGGigAAAEDtutWipZfjfwxxkSEDjkGGilRgmV0AAAAA1XMC54HZogIAAACM3pABx27Aa6XqVgtJHAAAADdZZhcwoEFGVgwZcPxnwGtla2kvFQAAANxkkJEVtqgchw4OAAAAbvJrdgFT4xSV49DBAQAAwE2aeW6crbebIa7jFJXjkMQBAABwE53/BybgOI5mkjgAAADup1st5tk1DGg31IUGCzhm621LW1QkcQAAAFxnnl3AgHZDXWjoIaPNdHE4KhYAAIBrLLMLGNBuqAsNHXDo4gAAAKB1/8guYED/GepCOjiOZ55dAAAAAFVq6YX4bqgLDR1w/DXw9TI5SQUAAICrCDiOYOiAYzfw9TK19AULAADAHXSrxTK7hoENNqpCwHE8M4NGAQAA+E5Tz4mz9XawURWGjB5XU1+4AAAA3KqlcQabIS82aMBRkpuWBo229IULAADA7Vp6ET7o8//QHRwRbXVxLLMLAAAAoA7dajGPtk7cHPSgEQHHcc271WKWXQQAAABVWGYXMLBBn/8zAo7/JFwz07PsAgAAAKhCa2MMdkNeTAfH8bX2BQwAAMDVltkFDGm23k6+g6O1gGOZXQAAAAC5utXiSbQ1f2Mz9AUHDzjKSSq7oa+baF6+kAEAAGjXMruAge2GvmBGB0eELg4AAADa8q/sAgY26AkqEXkBx+D/ocl+yy4AAACAHOV0zWV2HQMbvLEhK+DYJF03yxPHxQIAADSrudM1Z+vtZuhr2qIynOa+oAEAAIiI9ranpDzzpwQcDQ4ajWjvCxoAAKB5pZu/tRfem4yLZnVwRLS3TeWZbSoAAADNaS3ciEiau5kZcLQ2aDQi4iS7AAAAAAbVYjf/JuOiOjiG5TQVAACARnSrxTza6+DYzdbbXcaF0wKO2Xp7ERFd1vWTPOlWiyfZRQAAADCI1sKNiMRDRTI7OCJ0cQAAADBdL7MLSPBH1oWzA460//BEJ4aNAgAATFu3WiwjYp5cRoZN1oWzA45N8vUztHhEEAAAQGta7N7flXEUKf4768IR/RyObrXoon/ob8nLiDjLLmLKSlr6jdl6uxm+EgAAqEMZeDn//h9nPpBOVfm9PkkuI8Mm8+KpAUdxHu39wT/pVoulB+7HuzSV+J8R8aT8uO7n7v/2ovz4KyLOsyb8AgDAsZQXfsv4uk6e3/BzI/oDIPbr5D8iYjNbb1s7FOKQTrILSJI6huKnzItHRHSrxUlEnGbXkWAzW2+fZhcxRiXUeBl9sDE/wC+5i4jfI+JM2AEAwFiVUOO36NfJh+iSP4+If0f/UlDYcUdl5uLf0d5OhYiInzOfqWoIOGYR8b/ZdSRJ/cMfm3LD3gcbx3IeER911wAAMBblpfGbON5Ayy76LfYfPb/crlst3kb/59Gai9l6+0tmAekBR0REt1r8GTdsLZiws9l6+yK7iNqVjo3T6FvshrKJiBdu4AAA1KpbLZ5FxPsY9qSOdxHxQUfH1Rrv3vgwW29fZxaQfYrK3r+zC0hyUh7euUZJP/+OYcONKNf7u1wfAACq0a0W8261+BwRn2L4Y0jfRL9OdjLk1V5Fm+FGRL/tP1UtHRxPIuLP7DqSnM/W2+fZRdSmfE2cRh2dPRfRd3OYLg0AQKoSLJxGHQ/RZxHxWjdHr/HujW623v5PdhFVdHCUB8dddh1Jnl11pGnLyk37c9QRbkT0dXyWUgMAkKlbLd5H37VRywP0SfTr5FrqydZy98Z5dgERlQQcRRW/IUlaHEBzpTIgqaab9t4sIj6V+gAAYFDdanEa/QN0bZ5Ev2WllpeTKUrI8zK7jkRVjJ2oKeBIPS832VJ3wGiODD4VcgAAMKQSbpxk13GDWfSdHC2HHO+jvpe0Q+lm620VDQvVBBzlN6TlvVvvW27tGkm4sSfkAABgECMIN/b2Icc8u5ChlWDnJLuORFWEGxEVBRxFNb8xCeZRZ8vZ0V0aKDomp40n1AAAHFk50e8kt4p72W/rbu3F7fvsApJVsT0lor6AI/1YmWRvWks8y83vc3YdD2SgEgAAR1G2sI9xVt8YX14+WLdavIqIZXYdiarZnhJRWcAxW2830e5pKnvN3AyKWo64eohZtPfnBQDAkZWXaGNeZz4rD/6TVl5OjzGEOqRqwo2IygKOoqrfoATLFm4GEV9S6bEPV31mQCwAAAc25peAe28a6HZuebDoXjXbUyLqDDha36YS0d8MJj3fYQKp9GVND4gFAOBwutViGeN/CRjRP/hPdjZFeSk9hT+nx9jVtD0losKAY7beXkTERXYdyab08H+dVzGdtHMejQ6IBQDg4Ka05eFkijMGbU35oqpwI6LCgKPQxRHxpFstJpl4lm6Hl9l1HNhLXRwAADxG6d5YJpdxaFMMAj7FdF7WPsbH7AK+V2vAcZZdQCVeTXS+w0lM74YwCy1qAAA8zhTDgEl1cZSX0JMeJ3BHm9l6u8su4ntVBhyz9bYLIcfe6QTncUyte2Nvih9IAAAMoIQAy+QyjmUS6/9utTgJW9P3qtx1UWXAUVT5G5ZgFn3IMYmOhxLWzLPrOJL5BMMoAACGMYkQ4Bqj73Qu6/xJjhB4gC4qnL8RUXHAMVtvNxGxSy6jFk+i3+c1Bb9lF3Bko795AwCQYpldwBGN+kVgedn8Oaa3zf6hzsqui+pUG3AU77ILqMiyWy2mcLLKMruAI/tXdgEAAIxL2Z4y2gDgjkb5IlC4caXqhovu1R5wnEff/kLvpFst3mYX8VDl5jD1G/fU//sAADi8ZXYBA/g1u4AH+hzW+JdVOVx0r+qAw7DRK70pw23GqIkbQzneCwAA7uqf2QUMYHTPAqWDfnR1H1nVuyyqDjiKattfEp2ONORo5ebQyn8nAACH0cL6cTam42JLuHGSXUdldmVWZrWqDzhK+8tZchk1GmPI0cq+tVb+OwEAOIx5dgEDmWcXcBfCjWtV3b0RMYKAo3Bk7NVOu9ViTOcwj3Xf3X210GIIAMDhzLMLoJ8Z2K0Wn0K4cZVutt6eZRdxm1EEHKUNZpNcRq3eT+R0lSnRwQEAAD9aZhdwnUunpYzytJcBjGJ0xCgCjqL6dphEJ91q8al8UwIAAHBH3WrxJJyWcpMuIj5kF3EXowk4dHHc6llEfB7T4B4AAIBM5QRE4cbNPpYTTqs3moCj0MVxsycR8adjSgEAAG7WrRZvow83dMJfbzTdGxEjCzh0cdzJLPpOjrfJdQAAAFTn0jDRN9m1jMBoujciRhZwFLo47uZNt1rYsgIAAFCUbve/wzDRuxhV90bECAMOXRz3sox+y8qYjpIFAAA4qNK18T5sSbmPUXVvRIww4Ch0cdzdLPqjZHVzAAAAzSldG39GhBe/d7eLkXVvRIw04ChdHOfZdYzMMiL+7laLt46TBQCAOngJeTzdajEvszY+R8Q8uZyxeTe27o2IkQYcxevsAkbqTfTbVk6yCwEAAJp68N4McZGyHeVt9F0bZm3c32623p5lF/EQow04ZuvtLkbYMlOJeUSclm0ry+RaAAAADqK8yP0z+he7Otcf5kV2AQ812oCjeBf9ZFceZhn9kbKCjsN6kl0AAAC0pFstTrrV4u+IOI22umIObVNGQozSqAOOsifIVpXHW8bXoOOYLVx/HPHXromkGAAAjqxsRXkl2Dio0XZvRET8d3YBjzVbb8+61eJleGt+CMuIWHarxS4iPkbE2RgHywAAANNVBrO+jIiT8HLxkN6VURCjNeoOjktGnTJVaB4R76M/deW0Wy2ERwAAQKputXhWTkX5O/ojX4Ubh7OLCcy4HH0HR0TEbL296FaLD+Fc40ObRZ+Knlzq6jgfe6oHAACMQ3nZ+lvo1ji211Po3p9EwFG8i/4IoHlyHVM1j76r4323WlxExO8h7AAAgMfSLf2dS6GG57thnM/W2/PsIg5hMgHHbL3tutXidUR8yq6lAU/Kj/els+M8Iv6YyjfFIXSrxWwKCSgAAEfXUlfCxVX/sFstZtGHGb+Wv7b0e5KtiwmNfJhMwBERMVtvz7vV4jz6bwqGMY9+a9CrbrWIiNhEf1rKJiIuGn7IfxL97wEAABBfTsHcBxrL6AONZehiyfRiSs9skwqbCIfTAAAgAElEQVQ4ihfRf5NI/XIsy483ERFlO8tFRPwVfToIAAA0qAwIfRK2ndRiMltT9iYXcJStKi/CVpVa7LezAAAAbdNpX49JbU3Zm8oxsd8oKdToj7gBAAAm75/ZBdCkSW1N2ZtkwFG8i/4sX8igawUAgLuwtZ6hnU1ta8reZAOOkkY9z66DZvmgAgAAarOLiNfZRRzLZAOOiIjZensRE/7DAwAAgHt4PsWtKXuTDjgiImbr7YeImGT7DQAAMHrL7AJoxuvSBDBZkw84ihdhHgfD+jW7AAAAgOKsvPyftCYCjkvzOCbbigMAAABXaGZ0QxMBR4R5HAAAQF261WKeXQOT18VEj4S9SjMBR0TEbL09i4jJt+VQBcfEAgBwm3l2AUzei6nP3bisqYAjImK23r4OQ0c5PsfEAgAAmV7P1tumnn2bCziKF9HvQwIAAMgyzy6AyWpiqOj3mgw4DB1lCN1qscyuAQCAqs2zC2CSNrP19kV2ERmaDDgiImbr7S4inoaQAwAAgGm4iP5lfpOaDTgivpys0uwfPkdnDgcAADf5NbsAJmUXEU9bOTHlKk0HHBERs/V2E/1MDjg0J6kAAABD6CLiecvhRoSAIyK+HB8r5AAAAIY0zy6ASeii79xo/iANAUch5OAI/pldAAAAVZtnF8DoCTcuEXBcIuTgwMzgAADgSt1qYa3IYwk3viPg+I6QgwOaZxcAAEC1zGvjMYQbVxBwXEHIwYHMswsAAAAmR7hxDQHHNYQcHEK3WsyzawAAoErL7AIYJeHGDQQcNxBycADz7AIAAIBJEG7cQsBxi0shR9PnCfNg8+wCAACo0q/ZBTAqFyHcuJWA4w5KyPE0hBzc3zy7AAAAYNSEG3ck4Lij8sX0NCJ2yaUwLv/ILgAAgCotswtgFM6jDze8bL8DAcc9lJDjl+gTNLiLeXYBAADUpVstZtk1MApns/X2uXDj7gQc9zRbb7vZevtLRJxl18IoON8cAIDvWSNymxez9daBF/ck4Hig8sX2OrsOqiedBwDge/PsAqhWFxG/lDmQ3JOA4xFm6+2HMHyUW3SrxTK7BgAAqjLPLoAqXUQfbhiJ8EACjkearbebMJeDm+niAADgsn9mF0B1zmbr7S+z9XaXXciYCTgOYLbe7spcjg/ZtVAleywBALjMCzD2ujBv42AEHAc0W29fR8TzsGWFbzkqFgCAy5bZBVCF/ZaUs+xCpkLAcWCz9fY8In6OiE1yKdRjnl0AAAB16FaLeXYNVOGdLSmHJ+A4gnKU7NPoT1nRzcEyuwAAAKoxzy6AVLuIeDpbb98m1zFJAo4jKqes/BK6OZonqQcAoFhmF0CaD9FvSdlkFzJV/51dwNSVlqOn3WrxKiLehIFCrZpHn9YCANA289nas4t+kOgmuY7J08ExkEvdHOfZtZBimV0AAABVmGcXwKDeha6NwejgGFDp5njerRbPIuJ9uLm1RFIPAECEF1+t2ETftbFLrqMpOjgSlJNWfok+zaMNT7ILAAAgl7lsTdhFxPPZevtUuDE8AUeSctLK2+iPlD3LrYYBCDgAALAmnK4uvm5HMZYgiYAj2Wy93c3W2xcR8TSctjJp3WrhAw0AoG3Wg9N0Fn2w8Xa23nbZxbTMDI5KlKEzm261WEbEaZjPMUVPIuIiuwgAANL8M7sADuo8Il7bilIPAUdlStDxc7danER/rOw8sx4Oap5dAAAAqXRwTMMmIt45GaU+P2UXwM0EHZOyma23T7OLAABgeN1qMYuI/82ug0c5j4iPgo16mcFRudl6ezZbb3+OiOdhRsfYSewBANplLTheZxHx82y9fS7cqJsOjpEpMzp+i4iT3Ep4oJ/t0QMAaE+3WryNvjObceiiDzY+Wr+PhxkcI3NpGOm7iHgZfdAxy6yJe3kS/dnYAAC0xYDRcdhFf9zruRNRxkfAMVIlRXwdEa/LnI7fImKZWBJ38yT6vXsAALTFFpW6nUXE77agjJstKhPSrRbz0NVRO4NGAQAaY8BotS4i4veIONOtMQ0CjonqVov/l10DV5utt77vAAAaUubofc6ug2/8MltvL7KL4LCcogID61YL7YkAAG1ZZhfAt4Qb0yTgmK5ddgFcS8ABANCWX7ML4Bu77AI4DgHHdO2yC+BaPuAAANriBVdddtkFcBwCDhjeMrsAAACGUbYnOwAABiDgmC57yuo1L5O0AQCYPt0b9fGsNFECjun6v+wCuNEyuwAAAAZhe3J9PCtNlIADcvigAwBowzK7AGiFgGO6tF3VTasiAMDEdavFPCLmyWXwI89KEyXgmK4uuwButMwuAACAo/NSq06elSZKwAFJutVimV0DAABHZVsyDEjAAXmW2QUAAHBUy+wCuJIOjokScEzUbL3dZNfArST6AAAT1a0Ws7BFpUqz9dYMjokScECeZXYBAAAczbPsAqA1Ag5I1K0WPvgAAKZJty4MTMABuXzwAQBM0zK7AGiNgGPa7C2r3zK7AAAADqtbLeYRMU8ug6t5RpowAce0mQ5cvydlABUAANOxzC6Aa3lGmjABB+QzhwMAYFr+lV0AtEjAAfnM4QAAmJZldgHQIgEH5NPBAQAwEd1q8SQibEGGBAIOyDcrH4QAAIyfl1eQRMAxbSYEj8cyuwAAAA7C/I26eUaaMAHHtP1fdgHc2W/ZBQAA8DjldDyduXXzjDRhAg6og+NiAQDGz/YUSCTggHr4QAQAGDfbUyCRgAPq4bhYAIBxW2YXAC0TcEA9dHAAAIxUt1o8C8fDQioBB9RjVj4YAQAYH9tTIJmAA+pimwoAwDgtswuA1gk4oC46OAAARqZbLZ5ExDy7DmidgAPqMi8fkAAAjMdv2QUAAg6okQ9IAIBx0YULFRBwQH18QAIAjITtKVAPAQfUxzYVAIDx0H0LlRBwQJ18UAIAjIPuW6iEgAPq5IMSAKBytqdAXQQcUCfbVAAA6qfrFioi4IB6+cAEAKibrluoiIAD6uUDEwCgUranQH0EHFAv21QAAOql2xYqI+CAur3MLgAAgCvptoXKCDim7dfsAng0H5wAAJXpVotnYXvKWHlGmjABB9RtVj5AAQCox7+yCwB+JOCA+tnfCQBQiW61mIUuW6iSgAPq96x8kAIAkO9ZRFibQYUEHDAO3hIAANTB9hSolIBj2iTL0+E0FQCAZN1qMQ8vnqBaAo5pe5JdAAfzpFst/HkCAOQ6yS6AR1tmF8DxCDhgPAwbBQDIZT0GFRNwwHicZBcAANCqbrVYRsQ8uQzgBgIOGI9Zt1qcZBcBANAo3RtQOQHHRJWEmenxwQoAMLButZiFbtrJ8Kw0XQIOGJdlmd4NAMBwTrILAG4n4IDxcWQsAMCwrL9gBAQc0zXPLoCjOckuAACgFYaLTtI8uwCOQ8AxXfPsAjgaw0YBAIZjBtr0zLML4DgEHDBOPmgBAI6szD47SS4DuCMBx3T9I7sAjmrZrRZPsosAAJi4k+wCOArPShMl4JiueXYBHJ1hVwAAx6Vrdprm2QVwHAIOpuAiu4Akz8qZ7AAAHFiZeTZPLgO4BwHHdLWyfeEiIn7PLiLJLLRNAgAci+6N6WrlWak5Ao7pauXNfhcRZ9lFJLJNBQDgwMrRsMvkMjieVp6VmiPgmKAy7bkZs/W2i4jz7DqSzB0ZCwBwcLo3Jq61Z6ZWCDimaZ5dwID28zf+nVpFLh/AAAAH4mjYZsyzC+DwBBzT1FLL1f9FRMzW27Pot6u0aFnaKAEAeLyT7AIYREvPTM0QcExTS0NzLocarW5TidDFAQDwaOWEupZnnG2yCxhQS89MzRBwMHaXj4ht9TSViIgT+wgBAB7tJNp9s99FxLvsIuAxBBzT9Gt2ARlm6+0mInbJZWR6k10AAMDItdy9cZZdwMCafGaaOgHHNLWUOl98978/plRRh5PSVgkAwD2Vk+nmyWVk+j1+XFtPmXXzBAk4pqmZ/WTliNjLWp7DERHxKrsAAICRarkb9mK23l5csbaesmaemVoi4JiYxt7g777/B7P1dhdthxwvG/saAAB4tG61eBZtd29c7oLeZRUxNOvm6RFwTE9LSeTumn/e8rDRWejiAAC4r5Znb0R8+4Jwl1VEgpaenZog4JieeXYBA7qyhW623p5f9/81ovUPaACAO+tWi2VELJPLyHT23daUltbR8+wCOCwBx/TMswsY0F83/H9nQxVRoVkZkgUAwO1anr0R8WP3801r7KmZZxfAYQk4puef2QUM6KZ0ueXTVCJ8UAMA3Er3Ruxm6+3mu3/WUgdHS89OTRBwTM88u4ABXXuMVRk2uhmskvrMdXEAANyq9ZdCV70UbOmo2Hl2ARyWgGN6WhqUc1u6rIsDAIAr6d6ILq7e1t1SB0dLz05NEHBMSLdaNPUNOltvb0yXy7DR3TDVVEkXBwDA9Vp/GXT+3XDRiLh9jT01rT1DTZ2AY1rm2QUMaHfHn9fykbERPrgBAH6geyMibu523g1VRAXm2QVwOAKOaWkpfdzd8eedHbGGMdDFAQDwo9ZfAl3c0qmxG6qQCrT0DDV5Ao5paWkK8J1a58qw0bOjVlK/1j/AAQC+0L0REbfPqtsNUUQlWnqGmjwBx7S0lD7+3z1+buvbVObdavE2uwgAgEq0/vKnm623Z7f8nP8MUUglWnqGmjwBx7TMswsY0OauP7Gc7d3UsKQrvOxWi1l2EQAAmXRvRMTdThrcHLuIisyzC+BwBBwTUW7WLbnv8VWtHxk7i4hX2UUAACRrvXsj4m7bt1s6KrbFZ6nJEnBMR1OtVfc9vqq04TV1o76CLg4AoFll8PoyuYxsZ2VG3Y1aOyo2GnuWmjIBx3S0NBznoTdcXRy6OACAduneuN9supZCjpaepSZNwDEdLaWOuwf+e2cHrGGs3nSrxTy7CACAIZXujXlyGdk2ZTbdXe2OVEeNWnqWmjQBx3S09E3510P+JUfGfuHtBQDQjLJF9312HRW478mCD1pzj1RLz1KTJuCYgAaH4jymXa71bSoRESfdauEmDgC04lX0W3VbtrvD0bDfa2mLSovPVJMk4JiGZXYBA9s99F8sA5M2B6tkvLzFAAAmr2zNfZldRwUe8pJvd+giKrfMLoDHE3BMQ1NDcQ4w1fndQQoZt6WUGgBowJvQvdHFA7ZpN3iSSlPPVFMl4JiGZXYBA3r0jbYMV9o9upLxO80uAADgWMqW3JPsOirwcbbedg/8d1sKOZbZBfB4Ao6RK213LaXSh7rJ6uKImHerhWNjAYCpsiW3d/aIf7elgGPmtMHxE3CM3zK7gIH95xC/SBmytDvErzVyb8pkcQCAyehWi2fR3jr5KmflJMGHOsjae0SW2QXwOAKO8fs1u4CBbQ74azlRpe/+cWwsADA1ujd6j+1a3hyiiBFp7dlqcgQc47fMLmBgh2yTO4t+6FLrXjk2FgCYim61eBsR89wqqvDY7o2ItraoRLT3bDU5Ao4RK3vE5sllDGn3iAFJPyi/li6OnrccAMDoORb2G49e55b18u7xpYzG3ByOcRNwjNsyu4CBHSNB/hC6OCL6Y2OfZRcBAPBIjoXtbQ54zKsuDkZDwDFure0R++vQv6Aujm+8N3AUABirbrVYhmNh9w55YuDB1+CVa+0Za1IEHOPW2hv3zZF+XV0cvXlEODYWABgrW257m9l6uznkr3fAX2sMltkF8HACjpEqQyFbe9t+lPY4XRzfeGPfIQAwNt1q8SoiDE3vHbJ7I6K9LSpzA/jHS8AxXsvsAgZ2ccgBo1c4O+KvPTan2QUAANxVeTnj2Pveobs39i8DWws5ltkF8DACjvH6V3YBAzvqTbUcoXV2zGuMiIGjAMCYvI/2Opuvc+jujb3WAo7WnrUmQ8AxQmUQ5DK7joH9McA1jvWBMEanBo4CALUrg0W9mOkdvHvjkiHW4jVZWguPk4BjnJbZBSQ4emqsi+Mbs9DqCQBUrDyA2lr71TFf1rXWwRHR5jPX6Ak4xqm1lqnugOd43+Z1OFFl71V5KwIAUKM30Z8Cx3G7N6KsxVtbI7f2zDUJAo5xaq0NbzPUhZyo8gNvRQCA6pRTLhxv/9UQW603A1yjJq09c02CgGNkGj0e9q+Br/ch2kuorzPvVou32UUAAHzHS5ivjtq9ccnQa/JsM8fFjo+AY3x+yy4gwWbIi+ni+MEbN3cAoBbl5Yu1yVdDDcrfDHSdmrT47DVqAo7xaa5VaqBE+nu6OL7lLQkAkK5bLeYR8TK7jooM1b2RtSbP1tyz19gJOEakvEWfZ9cxsE3GRXVx/OBJt1rY5woAZDuN9rZr3+TFwNfbDHy9bHOdzOMi4BiXFlukMs/c1sXxrTflrQkAwODKy5Zldh0VOZutt7uBr5m5Ns/S4jPYaAk4xqXFFqlN1oVLF8frrOtXyFnzAECK8pLlTXYdlRlq9sZlm4RrZmvxGWy0BBwj0ej2lC57r99svT2LiF1mDZVZ2qoCACSwNeVbHxK6N/ZzOFrrcLZNZUQEHOPRYmvUJruAIiMdr5lTVQCAwdia8oMuctenm8RrZ2nxWWyUBBzjcZJdQIIq9viVLo5Nchk1sVUFABhEealia8q3Ppat1FmqWKMP7CS7AO5GwDEC3WrxLNpsyTvPLuASXRzfelLOoAcAOCZbU761i34Qfqaa1uhDmZVnMion4BiHf2UXkGCXsa/wOmW/YYs385vYqgIAHE15mWKt8a13yd0bUdbou8wakrT4TDY6Ao7KdavFLNpsidpkF3AFJ6r86LR8jQIAHIytKVe6KFuna7DJLiDBiXVv/QQc9TvJLiDJv7ML+F5Jq7NbAmtj8QEAHFR5iPyUXUeFanrZVt1afSAn2QVwMwFH/Vqd2LvJLuAa76K9o7Fu88qeRADggN5HxDy7iMpsypbpWmyyC0jS6rPZaAg4KlZa81rcd3ievbfwOqUuA0d/ZKsKAPBo5aXJSXYdFXqRXcBlZU3c4ny6J2bQ1U3AUbeX2QUkqfroqdl6+yHaHKx0E62kAMCjdKvFPBxFf5UPNQ3fv6TqNfsRtfqMNgoCjko1PFw0YhxpcFUpeiWW3WrxKrsIAGC0HAn7o5q7h8ewZj8Gw0YrJuCo10l2AUkuKk2ov1H2QG6Sy6jRe217AMB9lSNhl7lVVCn9WNjrlDX7RXYdSU6yC+BqAo56tdr6NKaJzLo4rvZJqg0A3FW3WizDqWxXuShbo2u2yS4gSavPatUTcFSoDFeaZ9eRZDStbiW1rrVlMNM87J8FAO7AkbA3qulY2Ov8nl1AkrlTBOsk4KhTq4ngbrbejq3N7UM4NvYqz8zjAADu4FOYu3GV88qOhb1SWbvvsutI0uozW9UEHJUpLXrL5DKyjKZ7Y6/siRxDup7BPA4A4FrmblxrbOvL0a3hD2RZnt2oiICjPr9lF5BolC1us/X2LNrdf3gb8zgAgB+Yu3Gjj2MYun/JKNfwB9Lys1uVBBwVKWd/nySXkWWM21MuG1PKPqR5mMcBAFxi7saNdrP19m12EffR+DaVk/IMRyUEHHVpOcUedWtbubHXPuU6y7PSggoAEBHxOczduM5YT+kb9Vr+kVp+hquOgKMSjXdvREyjte1dtJte3+aNPYoAQLdavI8IM7qudjaGwaLXmMJa/qF0cVREwFGPlpO/sW9PiQgDR+/gk5s/ALSrWy1OIsIpa1cb9Tqy8W0qEW0/y1VFwFEB3RvTSXxn6+15GDh6nVkYOgoATSonq73PrqNi78rLsjGbzJr+AXRxVELAUYfWE7+z7AIO7EX0KTw/srgBgMZcGirqJcfVNrP1dgqz3M6yC0jW+jNdFQQcyXRvxMXIjsG6VfnveZddR8VOutVCeyoAtONT9CercbXRbk25rKyBR7/t/BF0cVRAwJGv9aTvY3YBx1BS+JZv8Ld5b+goAExfGSq6zK6jYu+mMIvukkmu7e+h9We7dAKORGUv4kl2HcmmfKTUWI/5GoqhowAwYYaK3mo3W2/fZhdxYFNe29/FSXnGI4mAI1frswjOJjBM6VoljbdV5XqGjgLARJWHvNPsOio3uZdhZW1/ll1Hstaf8VIJOJKU9vxlchnZ/p1dwAA+RNtHZt3G4gcAJqZ0aH7OrqNyH2br7Sa7iCNpYY1/k6Wt2HkEHHlaf6jblSNVJ62k2JNL5w/sWdmfCwCMnBNT7mQXE+7yLWv8XXYdyVp/1ksj4EhQTpCYZ9eRrJlzsks6P4Wjv47pVdmnCwCM22n0HZpc78WUt2kXzaz1rzF3amAOAcfASqptum57e/PehST7Nqfa+QBgvLrV4jQinmXXUbmzCW9Nuewsu4AKvDFrbngCjuG9Dy175+Wc7GbYqnJnn0yeBoDxKZ2YJ8ll1K6LiNfZRQyhrPUnvx39FrMwcHRwAo4BlbfTJ8ll1KDJljVbVe7EySoAMDLdavEszBy4ixa2plzW5Jr/Oyc6lIcl4BiWBK+R4aI3sFXldvOI+CzkAID6OQ72zj60tgY2bPQLz4ADEnAMpFst3oaBSxERH7MLyGSryp1ZLAFA5S4dB+ulxM12MeFTU27R9Nq/eFKeBRmAgGMA5eb/MruOCnRh4JCtKnf3rAwrAwAq4zjYe2lta8plZ9E/A7TuZXkm5MgEHMM4DTf/iH64qBtc711EXGQXMQInEm8AqEsJNz6H7uS7+NDIqSlXKmv/prbmXGMWupMHIeA4snL+8TK7jkq02pr3A1tV7uVNmcwOANThNIQbd3ER1r8Rfg/2luXZkCMScBxRaUN6k11HJTatHQ17m9l660Pv7k6FHACQr2wffZZdx0i0vDXli/IMsEkuoxZvbFU5LgHHcdma8pUH+SvM1tu3YavKXZ2WSe0AQIISbpxk1zES78rLLHqeBXq2qhyZgONIytyAZW4V1bhoee/hHTwPw5fu6rOQAwCGVzopT5LLGItNeYlFUZ4FBD69pRlzxyPgOILyAGZryleOh7pBadt7nV3HSMxCyAEAgyrhhrfOd2PO2vU8E3z1xnr2OH7KLmBqylTpPyNinlxKLXaz9fbn7CLGoFstPoU9rXfVRcRTrZ8AcFzCjXt7MVtvz7KLqFW3WvwdnpP2dhHxizkth6WD4/BOwzftZfbb3d2L6G903G4W/UwOM24A4EiEG/d2Jty4lWeDr+bh++vgBBwHVI798Qb+q52b/N05OvbenkS/XUXIAQAHVtrnPXzd3S5sOb5VeTbYJZdRk2eOjj0sAceBlA+B99l1VOb37ALGpgxgkmzfnZADAA6srGs/Z9cxMs9tNbgzzwjfem8ex+EIOA6gPFx9yq6jMl1EfMguYozK1O1NchljIuQAgAO5FG74XL271+aC3cuHcILg9z5Zyx6GgOMwPoW5G9/7KMV+FEfH3o+QAwAeSbjxIOez9dZLvXsozwhOVPnWPLwwPwgBxyN1q8VpRCyz66iM7o1HKjf+59l1jIyQAwAeSLjxILswP+2hdHH8aFmeLXkEAccjlMnSJ8ll1Ej3xgGUeRyCovsRcgDAPQk3HszcjQfSxXGtk/KMyQMJOB6oWy2WYbL0VXbhofxgZuvt6zCP476EHABwR8KNBzN34/E+hBNVrnJanjV5AAHHA5QPAnukrvZOkn1w5nHcn5ADAG4h3HgwczcOoDwzOD3wap+crPIwP2UXMDblgenv8EFwld1svf05u4gpKimu49ru7yIingrdAOBbwo0H20XEL9YWh9OtFn+HAxuu0kXEz77W7kcHxz2UcMMHwfUksEdS5nH4/b0/nRwA8B3hxqOYu3F41rhXm4V17L3p4LijS+GGVqGrbWbr7dPsIqauWy0+RcSz7DpGSCcHAMSXrtBPIdx4iBez9fYsu4gp6laLz+FkyutYx96DDo67+xTCjZtIXofxIgxjegidHAA0r5zOoHPjYc6EG0flWeJ65j/eg4DjDsp5xMvsOiq2KVsoOLKS3Bo6+jBPIuJvA5sAaFEJN5wA+DAXEfE6u4gpK88Sm+QyarYsz6TcQsBxi/KFdJJdR+VeZBfQknIkmQ/Zh9nvZRRyANAM4cajdGHuxlA8U9zsRMhxOwHHDYQbd/Jhtt7usotoTWmRdDzZwwg5AGhGt1q8DeHGYzy31h1G+X22vr2ZkOMWAo5rCDfuxNnViWbr7evQyvdQ+5DjJLsQADiWsp59k13HiL22DXtw78JW7NsIOW4g4LiCcOPOXmvXS/c8DB19qFlEnAo5AJgi69lHO5utt7oJBlaeLWzFvp2Q4xqOib3EUbD3cjFbb3/JLgJn2R/Ia4sYAKagrGc/hQH5j+FYzmTdavFneCa7C1+r39HBUQg37k2yWglDRw/ivRQcgLG7tJ5dJpcyZl14YKyBte3dPIl+27UXnYWAIyK61WIewo37+GA/Yl3K0FHzUB7npFstTn1AADBGpaPTW+/HE25UoDxr6K69m33IMc8upAbNBxw+DO7NYNFKzdbbtxFxllzG2J2EFByAkbm0XXWeXMrYvSidsdTBwNG7exIRfzolsPGAowwXNLvgfl5Itav2Ovq9eDzcPgVv/gMCgPqV9eyfYT37WB9KRyyVKM8cL7LrGJH9KYHPsgvJ1OyQ0W61eBUR77PrGJnNbL19ml0ENyvdB3+Hhc5j7ffgCowAqJL17MGczdZbD9KV6lYLc2Xur9kB+s11cHSrxawME/RhcD8S1JEoaffT0NL3WLPoW/1OsgsBgO9Zzx6MYe31exHWtff1vtXZck11cJTBK5/CvI2HaDYFHKvyYO5kkMN4V2acAEAqx8AeVBcRP9t+XT/dSg92ERHPZ+vtLruQoTQTcHSrxTL6D4PmUqwDsDVlpHwYHNRZ9EGfRRAAKcp8qNPwsu4QbEUdGVtVHqyLPuTYZBcyhCa2qHSrxdswTPShbE0ZsdJ1c5Zdx0SchBNWAEhSXtZ9DuHGoTgxZXxsVXmY/fDRt8l1DGLSHRxa+A7C1pQJ6FaLTxHR9ETlA/LGB4BB6cg8uBdOTGDhpiAAABnrSURBVBkn3wuPtom+m2OyQdFkOzjK8Th/h3DjMTbCjcl4EY6PPZR9Cn6SXQgA02eY6ME5DnbEyrPJJruOEVtGxN9TPkp2ch0cpWvjTUS8yq5l5LqI+KWlgTRTV743/oyIeXIpU/Jhtt6avA7AwZXPbVtSDstxsBNQDo74M4wfeKwP0Q/Sn1Q3x6QCjrI38TQ8wB3C89l6e55dBIdVhpOZR3NYm5h4qx8Aw/J5fRSG5k9I6UD4lF3HBOyi37K1Sa7jYCYRcOjaOLjz2Xr7PLsIjsOi6Sh20YcctgEB8ChmDBzFRfTzs7yMmBAz5g5qMt0co5/BUbo2/gzhxqHswqkpk1Yewv0ZH9Y8Iv40lwOAh+pWi5l5G0ch3JiuF9E/u/B4r6Jfyy6zC3ms0XZwlK6N05DaHdov3kK3oTyMn2bXMUFn0Z8+ZCEFwJ2U7srTMG/j0Jx8NnHle+fP7Dom5jz6bSujXMuOsoOjtO79HcKNQ3vtA6AdZYK4To7DO4n+lJV5ch0AjECZJWCY6OEJNxpQ/nwNfD+sZ9GftDLKHRKj6uAoLTPvwwfAMZi70ajSDnuSXccEddGn34b1AnClbrV4H7ZZH4uu5IaYx3E0F9G/BN9kF3JXowg4ypvQ9+GL9lh20X8IjLINiccTchyVo2QB+EZZ234KL+2O5UXpVKURZXzBn+E0zWM5jz7o2GUXcpuqA47yhfoq+hNSOB4JN0KO47qI/pSVXXYhAOQqW1JOw2lmxyLcaJR5HIN4F/3Lu2pfjFcZcFwKNl6Gm/+x+RDgi261+BwRy+w6JqqLPvk+yy4EgOGV9e2bsCXlmKxrG2eI/iC6iPgYlQYd1QUc3WrxNgQbQzmbrbeGTPJFWXwZdHZcZ+GUFYCmOCVlEK9n6+2H7CLIpyt5MF1EfJytt2+zC7msioBDx0aKi9l6+0t2EdRHyDGIXfRbVmwNA5i4chLBm7DGPSYv7fhGt1r8GdayQ9lFxO9RSUdHasAh2EjTRcTPNXwBUichx2De1ZZ6A3AY5bP0NAzJPzbhBj8o339/h2fMIVWxdSUl4CiTo19G3zrki25YzgTnToQcg9lEv2d4l1wHAAdikOhghBtcq2wN+xy+D4fWRb8l+2PG+nbQgKNbLZYR8VvYE5XJ8CXuTMgxGANIASbAINFBCTe4laGj6c4i4vfZersZ6oJHDzjKjf5Z9B0bHpJyaYfn3oQcgzqPPoS0fQxgZMqLvNOImOdW0gThBndWDrF4k1xG6y6i375yfux17tECjtIS9DL6cENbUD4fBDxYCTn+DIu2IXTRhxzn2YUAcDfdavE+dG0MxZqWe3OySjW66F/ofTzWyISDBhy6NarlxBQezT7GwenmAKic418HJ9zgwZysUp2jdHUcJOAog5R+C1Oia3QR/VBRD0k8mpBjcLo5ACp06SRAbe/DEW7wKLZdV+08+lkdj17zPirgKENb3oS29Vo5DpaDK6cgfQofDkPSzQFQCbM2Ugg3OAjHx1ZvF/3cyLOH/gIPCjjc2EfBcbAcjQQ8hZNWABI5ISWNcIOD0pE8CrvoX+5t7vsv3ivgKDf207AVpXbCDY5OyJFmE/0Nf5dcB0Azynbs9+Hl3tCEGxyFkGM07t3FfOeAo3wRfAo39jH4RbjBEIQcabrop0+/zS4EYMq83Esl3OCoyvPtn9l1cKtdRDy/6/PtnQKOMmvj9OE1MaAXWtgZkpAj1UX021Y22YUATE23WuyHiHrDOzzhBoPwnDsqd3rOvTXg8Ic+KsINUgg50n2IfiCTIaQAj1Te6r6PiGVyKa36MFtvX2cXQTs8747Krc+7NwYc/rBHRbhBKiFHOkNIAR7BENEqWM+SwnPvqNx4n7g24PCHPCo+DKhCWRy+j4iT5FJatok+6DCHB+COyrr3fdiOksl6llSef0fl2vvFlQGHgSuj4sOA6nSrxWkIObLZtgJwC9tRqmE9SxWEHKNy5cEaPwQc5Q3s3yHBHgMfBlRLyFGFLvqQ40N2IQA10XFYjS769ex5diGwJ+QYjS4ifv7+Zd5/XfETT0O4MQbCDapWpp+/y66jcbOIeN+tFn93q8UyuxiAGnSrxdvoX+adpBZCFxFPhRvUpjxjOcWnfvtjvL/xTQdHt1o8i4hPQ1XEg0i6GRUpeFU20d8/dsl1AAyurHPfR8Q8uRS+hhvmRVGtcs/w8r9+zy8/G38fcPwdbvo182HAKAk5qmM+B9CM0sH2JszZqMVF9A8ku+xC4DZlTs/nEHLUbDdbb3/e/48vAYcHkOoJNxg1HxDV6SLiY0R8EHQAU9StFvPog42T3Eq45CL69azPHUbDGnYUvoxvuDyD401OLdzB/sNAuMFola/fp9E/WJNvFv19/88ScANMQrdazLrV4n2Ys1Gb8xBuMEKX1rCexer1Jcv4KUL3RuUk3UxKmVz/OSKeZNfCN3YR8dp8H2CsyufLq4h4Gd601uasDB+H0bKGrd6L2Xp7tu/g+C21FK4j6WZyytezFLw+84j41K0Wn524AoxNt1q8ir5j400IN2rzWrjBFFxaw3oZVKffIiJ+KvsT/86thStIupm8brU4De3DtdpEP4h0k1wHwLVKF/KbMCS/Vl/2xcOUWMNW6+f/ChOla/RCuEELytf5u+w6uNIyIj7r6ABq1K0WJ+X0v9MQbtSoi4hfhBtMVVnDel6rz/KnbrX4FBHPsishIvoPgxf2wNMac4BGYRM6OoBkOjZG4SL69aytqExet1o8i34Na2tcHc5/6laL/w1/IDXwYUDTHME1GpsQdAADE2yMhuH4NKesYU/D8NEadD91q8X/y66C2ETEcx8GtM4HxKhsQtABHJlgY1TMj6NZ5YSVT2H8QzoBR753s/X2bXYRUAsfEKOziYjf7bMGDsVxr6P0erbefsguArJ1q8Xb6ENZkgg48pi3ATcwnXp0dtEHtmfJdQAjVU72OwnBxphYz8J3zOXIJeDIcRH9lpRddiFQMyHHKO0i4veI+GDbHXAXJdh4E+73Y7OLfj1rfhx8p9zXPoVt14MTcAzvw2y9fZ1dBNSsfCichm0qY9ZFxHn0XR275FqACpUjqN+Ee/1Y/SLcgOuV7XbvQ3g7KAHHcLTwwS0u7bu2d3FaziPio4GkQITBoRPzLnTswY1sWRmWgGMYtqTALcrN/31Y8E7ZLvrF8LnFMLTFfI1J20U/ZNRLPLiGLSvDEXAMo4uIs+jfYO5yS4G62I7SJPdEaETZhvIyIp4ll8LxbaLvVt4l1wFVcTLUsAQcwzuLflFvzyJNKzf7N9Hf8GnXJvp7ojd/MBHl/n4S/WJ+nloMGT5EP39Jpx5NuzRA+VkINgYj4MizCYt6GlXOCJdic9ku+tNXzrz9g3Eq3Rq/hYF69J16H2fr7dvsQmBoOtdyCTjy7cKedBphsBx3dB4R/56tt2fZhQA3063BLXbRd3OcJdcBR1fWuS/DnI1UAo56OFKRyTJAlAfaz+r43bY+qEu5r/8W3lByN7swiJQJMkC5Pj91q8WfIWWqzSZsX2ECSovemzBAlMe7iK9bWHS7QYJutXgSX7egWMjzEJvoX+ZtkuuARxHyVuvip261eB+G/NVqF/akM0KCDY7sPCL+Hbb2wdGVt5PPwhYUDmsTgg5G5lK3xm/hflirDz+V9OlTdiXc6jz6Nm1dHVSr7D38LQQbDGO/te/f7o1wOGWuxj7U0OXLMW2iX9+eJdcB19KtMSrPf4qI6FaL/w2thmOx35P+UVcHtTA8lAoIO+ARLoUa/wqLeIa3C8NIqUjp1tifhDJPLYa76mbr7f/sAw7bVMbpIiI+hjZtEpTF8KvQpkd9hB1wB0INKrSLfnv2B2tbhqZ7bfQ+zNbb1/uAYx4Rf+fWwyPZwsIgyv3iTfQfADq/qN2XsCMiNhbMtO7STI1/he2E1MvpggymbEH5V/TzNRivn2fr7e6n/f/qVovP4YNuCry55CjKzf9luE8wbpfDjl1yLTCIcvrJfgHvrSRjswmnC3Jgl0INL+ymYTNbb59GRFwOOJYR8TmrIo5C2MGjmBbNxF3E19NYLrKLgUMpbdbL+NqlMU8sBw5lF04X5BEcdT1pT/enMv10+Z92q8VpaM2ZKmEHd2ZaNA3a3yP/CN0djFBZuC/D1hPaYGs2d6JTowlns/X2xf5/fB9wzKKfxeEPf9rsSecHUm34xkX0bdF/WEBTo9Jht4yIX0OXBu3any74u048In7oYBNqTF8X/eyNL8+zP/3wM/rjHk8HLIp8+7eW595atsUWFLizTXzt7tjklkKLLi3a94GGWRrwrV3YwtKkS8OTfw3dx6158f3x0j8EHBG2qjRuFyXw8NZymi61Mf8WFsjwUJsQeHBEZcH+JAQa8BAX0YcdXt5NVNl6sg805rnVkOSbrSl71wUcs+gHjvowZRNft7Jo/RupS9tPfAjAcXzZ0hIRFxbU3Nel8PmfYcsJHNIuvs7ssJYdKXOG+M5F9INFfxi1cGXAEWEeB1fq4tu3lj4kKlW+fy8n276PYVi76D98/4r+vnlh3hF7l7ozLndoAMd3eaD0uftyvS4FGvt7pLUsez/M3bjs2oAj4ssX1ufwBcXV9oHHX6FNO1056nmfauu+gvpclB//CaFHM64IM56EdRXUYn9cuHVssrKOXcbXLjb3Sa7SRd+5ce2L9hsDjogvH8yfwgMTd7OJS28ttWkfR+nQ+D7ZBsZnV378Ef29c6c7brzKAn0e/QJ9H2pYpMN4bMJ8paO7dArU/l65TCyH8biIiOe3PV/eGnBEfHmY+hS++Li/Lvovxj+itGxbvN9f6aZ6El9TbYEjTNtF9PfMv0LwUZVLAfO8/Pj10t8D07Kfr/RXWMM+yKU17Dx0sfFwm+jDjVs7X+8UcOx1q8XbiHjzoJLgW5voF+/7Vu2dbo9eeQP4JCL+EVJt4Fu7+Drf4/+iv3+GN42HdUWI8Y/yVwtzYBNfu5V37r+90pUxj37d+o9Lfw+P9W623r6960++V8AR8eXh6zS8qeA4Lr+13O1/TC38uPQhsF8sewMIHMKm/PWP8teL6DvpJncffYzyRnEWX++7/198vR/rkAPuaxdftxvuu5cnd9+9tH7d//hn9PfNZVJJTNsuIl7cN0S8d8AR8eXNxmn0pzPAUHblRxd9ABLxdTHf1dI2eOnNX8TXBfM+ybZ4BrJtyl8v30v3C/K9UQ1AvbTo3lte+vtfy1/df4EM+6B533m3Kz8iKrrXXgp+I77eQ/fr1/0PGMp59OHGvb8/HhRw7HWrxbPogw7tmtRm893//uOqn1R8v7Dfu6kVef+2b8/CGZiy/QL9sssByTH9esU/s1UEmJrv77M3rV03N/x/yxv+v33HxZ57KbXpog82zh/6Czwq4IjQzQEAAAA8yoO7Ni57dMCx160Wr6IfQCoFBAAAAG7TRT9I9MMhfrGDBRwRujkAAACAOzlI18ZlBw049szmAAAAAK7w6Fkb1/mvQ/+CERGl0J8j4uwYvz4AAAAwOmcR8fMxwo2II3VwXNatFsvouznmx74WAAAAUJ1d9F0bm2Ne5OgBR8SX2Rz7IaQALXod/ba9l2H7HgAA7Xg3W2/fDnGhQQKOvW61mEffzbEc8roAiXYR8Xy23l5EfAl830fESWJNAAyni4iP0Q/T+xS6moF2bKLv2tgNdcFBA449Q0iBRlw7GbpbLZ5EH3Qshy4KgMF8iP7NZRfhxEGgGUcbInqblIAj4ssN/k30W1cApub1Xc7zNqcIYJI2ccNby261eBV9yA0wNd8Eu0NLCzj2bFsBJuYi+kXtxX3+pW61OIl+sauzDWC8LqIPuDe3/cTSyXcaEU+OXRTAADYx8HaUq6QHHHtl28r78BYTGK9HJdaXBjIbRAowLrvo7/9n9/mXdDQDE7CLPtgdfDvKVaoJOPa61eJtWNwD43LQfYYGkQKMRhd9sHHrlsQbfxHz6YDx6SLi41Cno9xVdQFHhMU9MCrXDhJ9rLKF7024FwLUZn8yyodD3f/L+vdT2LYN1O8s+q6NlDkbN6ky4NhzygBQsYO8tbvThdwLAWryLg4YbHyvDCB9E7o5gPpsog827jVrbkhVBxx7ThkAKrOJhCFK5V74JgQdABnO/v/27uY4bhsM4/jTQdyB97B3qwOxg+i8FykVKB14UkHsCkxdcpY7oDqg7znAHdAd5AAgxFIr7QeXxNf/N6OxkvGMcXr5zoMXgGywbZb+h7iEH0BijGzv20Vex1FZBByee2Xgswg6AMSx2tTGu4sg6ACANbVaKdiYYpoDQGRGF1ygHFNWAYfEKwMAoumUwNNXIYIOAFhUq0jBRohpDgARXP2eobVkF3B4BB0AVpLE1MZ7CDoA4KpaJRBsTDHNAWAF2QYbXrYBh8crAwAWtNgLKUsg6ACAWVolGGyE3AbfN0l3sdcCoDitEq+Bp8g+4PAIOgBckZG9Ifo59kIu4YKOR9EAA8Axg2xT/zWnpn7Ybe9kX9faRF4KgPy1KiDY8IoJODyCDgAzfZEt8llMbbyHeggAb8p+DNtNc3yWPbINAOdqVVCw4RUXcHg09gDO1Cnxd70vFdTDO3F2G0DdjGyw0eYabEwNu+2N7DRHE3kpAPLQqsBgwys24PAIOgAcMcgGG23shSyNy5kBVMwos6cOzzXstg+yQQf1HcAhrQoONrziAw6PoAPAAX8p4/HkOVwj/Fmc3wZQtk62oe8ir2MVHFsBcECrCoINr5qAw2NUG4Bsw/tHLYX+Pby8AqBQrSpq6Kdcv/tN1HagVoPsa4DV1cHqAg6PUW2gSkY22OgiryM5hL8ACmAkPanSybxDXIj9TUzrAbXI/gLluaoNODwXdDzIBh2bqIsBsJRq7tmYi5oIIEOdpCdq/Nu4nwMonlFhFyhfqvqAI+SK/6Okm8hLAXAd1afYcwy77Z1sTWwiLwUApvz49dcSX79aAtPLQJF62TrYxl5IKgg4DuBMOlCEL7LnDgk2ZnLHVx5lJztoigHEZMQu5Swu6PhbXLwP5KxTRRcon4OA4x2cSQey1KrCC5XW4ibd7kUADGBdrewxlC7yOorBC4NAdqq9OPQcBBwn4Ew6kIVWFPzVMNUBYAVGTGssjqADSJ4RtfBkBBxn4kw6kJxWBBtRuamO32Wn3QBgDu7WiISgA0hOJ1sLn2MvJCcEHBdi9xKIrhXBRlJcXfQh8CbqYgDkppN94vWZHcq4CDqAqAbZHvcrPe5lCDhmcsdXfEPP6yvA8loRbCRv2G1vZOsidxgBeIuRDTVaanp6CDqAVfWyx1AIeWci4LgiGnpgMf65V5rgDLmjfffiCAsAjqBkh6llYDHUwwUQcCwgmOrgpQFgHiO7u/eFNDt/1EagWr6J/85Z8ny5Gv6nbA3fxF0NkLVOHMlbDAHHwoLU+058DIBT9bJpdht7IVhGcF/HvTjeB5TKhxpt7IXgutzl0hzPBk5nNE5rmLhLKRsBx4rcmLZ/aYARP+C1VtLTh3/+7SKvAysi7ACK8izpu9iZrMKw2zaytfsh7kqAJDG9FgEBRwTBmDbPKgJcMocAYQeQnUF23JpQo2Kudj/ITnWwiYfaEfRGRMARGc08KtbJTmu0kdeBRBEGA8liVxJvcsdXuGsJtek13qthIq+lagQcCSHsQAWMOH+IC7iwoxHH/IBYjGz9fuK2f5yCe+hQAUKNBBFwJIqwA4XxTTE7fbgK9yy33yGkRgLL6DSOWZu4S0HOeC4cBSHUSBwBRwYIO5Ap/wFoOX+IJbka2chOdzRiugO4lNEYanTUblybm8Z7ED0t8kKokRECjsxMGnlScKTGiAtDEZm71b+RrZM00MD7niW9iMYdKwsuJr0XR1iQHn9RaEdtzAsBR8YmZ9Ib8XFAHEacy0aigjp5K86BA5Kd0HiRbdq7uEsBrODYIXUasRgxwVYEAo6CuI+Df3GAXUssqdf4CgqhBrIRTMHdimAYdfD12ocaNO1IGmEHVtRrvGeIfrYQBByFYroDC+jEZXMoTBB4fBIXlqIMnVyYIakn0EDOuIcOV2bElEbxCDgqwSV8uMCg/bPZfARQvCAcvtE45QGkatAYaPQcOUHJXH2+03jkkF4Wx/gayV0aFSHgqJQb/2s0NvB8JCCNjTKjeoAT1MtPssEHu4iIpZMdqf4hmnVULjiaTRgNLwx9O3rZOhFwQBLn0ivG2WzgTG4XcRp6bCIuCWXq3Y+fzqBRB94wuVC6EUF0LYz2+1gTczFIAwEHDjowpn0jpjxK0GlsmAk0gCsJQo8bMemB8wwaw4wfIswAZpsEHj6QRt58rXxxf9LH4iACDpzMjQKGzXsTdUE4xmh/96+LuhqgQq5ubjSGxRsx7VGzTrY2//S/s+MIrGPYbRvtb9xtYq4HR3Ui+MUFCDgwizva4oMPmvd4jIJz2eLmfCBprtH2Ux+f3O9NxCXhevwuoxFBBpAsjhsmw7gfP5nRUy8xBwEHFuGa9437Ifi4nnCU+afGDwFhBlAAFxpvNB4LJPxI0zTE6CUNTMoBeZscN/wY/M4x7fmMxiDDyAa/XbzloFQEHFiVG9f2zfpvGj8anFXf18s20C8KQg2CDKBuLjyWxsDDByAbESJfk6/BRjbA8HV4YEwaqM8k+Pggu3lH//qar529pF+yE2zUTayKgAPJCD4e4Qfj1v25UTnNuy/8kg0wpOCDQIgB4FJBHZX2dx1vg7/WrLmmhIS118gGF9JYf8VuIoBzHelfS5r+MO5Hon9Fwgg4kJ1gCkR6HXzcTv76kul62Cx7RmPTLNnk2i6ExhlAYib1VHodfnzU4XB57ab9/xDiwP//Ffy30diASzTdABIRTOBJ+7X2UJ1dssYeqqcvwe9GYx1l+gLZ+Q+wWxlZ+wpOJAAAAABJRU5ErkJggg==" - }, - "asset-7e4f7119-b2d8-4527-9bd8-887cb25974e7": { - "id": "asset-7e4f7119-b2d8-4527-9bd8-887cb25974e7", - "@created": "2018-09-06T19:44:52.474Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-e79711e8-d9da-45e1-a234-9efe226a444d": { - "id": "asset-e79711e8-d9da-45e1-a234-9efe226a444d", - "@created": "2018-09-06T20:01:04.447Z", - "type": "dataurl", - "value": "data:image/png;base64,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQJ7/B75mKmIfIcbtAAAAAElFTkSuQmCC" - }, - "asset-9493e336-1b11-4e61-bad2-716c46194550": { - "id": "asset-9493e336-1b11-4e61-bad2-716c46194550", - "@created": "2018-09-06T20:01:22.463Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-23f2bfe9-e58c-4a56-98c6-fad59eecdf74": { - "id": "asset-23f2bfe9-e58c-4a56-98c6-fad59eecdf74", - "@created": "2018-09-06T20:01:50.445Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-86d05b5e-1a4b-4979-95e9-7071b9923470": { - "id": "asset-86d05b5e-1a4b-4979-95e9-7071b9923470", - "@created": "2018-09-06T20:17:48.355Z", - "type": "dataurl", - "value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABDgAAAQ4CAYAAADsEGyPAAAACXBIWXMAAAsSAAALEgHS3X78AAAgAElEQVR4nOzdS3JT2bY27Pdk7PpZXwu2MkL1bVqQogXbVFVJ0wKgBUALgBbgrKiKswUoW4B3XRGp04KzTgv+v7Cmwdxl6zLX5XkiHGSSYI+ULHmtd445ZgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAvf1X7QKSpF3Oz5I0SRY/+GPrJG2z2lyfoiYAAACmoV3OF+nuSc++90eSXCfZNqvN9kRlcUdVAo4SaPye7ptncY9PsU7yZ5K1wAMAAIC7KIHGv9Pdj34v1PjuX08XdvyZ5Erg0R8nCzja5XyW5EmS8ySzA37qbZI3SS6b1aY94OcFAABgJG7dk16k69Y4lOskf8Q9aXVHDzjKN9HzdN9ER/1SSa6SvJSgAQAAkHzcQfA83WL7Ub9UusX314KOOo4WcLTLeZPkVY4fbHz1pZO8aVabFyf+ugAAAPSEe9LpOUrA0S7n50ne5rBtP3e1TfLIjA4AAIBpaZfzi3ThRs170uskj92Tns7BA452OX+b0ydkP/JScgYAADB+Fbs2fuRZs9q8rl3EFBws4CjfSO9z9wm0p3CZ7pvKPigAAIAR6vs9abPaPK5dxNgdJODo+TfSjeskD4UcAAAA41IGib5P3S0pP3OVbsuKe9Ij+WXfTzCQcCPp6ntf6gUAAGAEBhJuJN0pLu9rFzFmewUcAwo3bpwleVe7CAAAAPZX7knfpf/hxo2zMreSI9i3g+NdhhNu3Fj4hgIAABiF90lmtYu4o4t2OX9Ru4gxunfAUZ6QxaEKObGLcpQtAAAAA9Qu568yvAX3G8/dkx7evYaMtsv5IsPfO9QmedCsNtvahQAAALC7Ed2T/mro6OHct4NjDFs8bs5HBgAAYCDK3A33pHzlzgFH2ZoyO3QhlZyX5A8AAIBheJrx3JNeuCc9nDsFHCUpe3KkWmoZQ/IHAAAweiO9J31eu4CxuGsHx9MM5/idXc0MdwEAABiEMd6TLnRxHMZdA47fj1JFfWNLAAEAAEZlpN0bN8b6/3VSOwccpcthdrxSqlq0y/msdhEAAAB813nG171x49w96f7u0sEx1u6NGxIzAACA/vp37QKOzOiEPd0l4Bj7g72oXQAAAABfK9tTxn5POvamgqPbKeCYyMCTMy1BAAAAvbSoXcAJnJUgh3vatYNjccwiemRRuwAAAAC+8lvtAk7krHYBQ7ZrwDGVb6Z/1S4AAACAr0zlxn9Ru4Ah2zXgmB2ziB6ZyosGAABgSBa1CzgRi+57EHB8bla7AAAAAD6Z2FyKKf2/HtxPA46JDd6c1S4AAACAz0yp035K/68Ht0sHx+zYRQAAAAA6OPax6xYVAAAAgN4ScAAAAACDJ+AAAAAABk/A8YWJDVUFAADoO3Mp2ImA42uz2gUAAADwkZNF2MkuAUd79CoAAAAA9vDTgKNZba5PUUiPSAcBAAD645+1Czihqd1/H5QtKl+zvwsAAKA/ZrULOCE7KPYg4Pjab7ULAAAA4CNd9uxk14BjSimSFw8AAEAPlFMuddmzk10DjintA2ocFQsAANALi9oFnNhftQsYMltUvu28dgEAAADk37ULYDh0cHzb77ULAAAAYHIdHNvaBQzZrgHH/x21iv45s00FAACgnnY5v8j05m9saxcwZLsGHNtjFtFTT2oXAAAAMGFT7Kzf1i5gyAQc33fRLudTSwsBAACqa5fzRaa3PSXNarOtXcOQmcHxfU2S57WLAAAAmKBXtQuoYIr33Qe1U8DRrDZtkvbItfTR05IcAgAAcALtcv40yVntOiqY4j33Qd3lmNippklvbVUBAAA4vnY5P8t0O+n/ql3A0Ak4fm6W5G3tIgAAAMasLCy/y/ROTrkx1Xvug7lLwPGfo1XRf+ftci7kAAAAOIISbrxPt8A8VdvaBQydDo7dXQg5AAAADutWuDHFuRs32ma1mfo99952DjjKgz31oScX7XL+wUwOAACA/ZWZGx8y7XAj0VBwEHfp4Eg86En3wvvb6SoAAAD3V05L+ZBpb0u5YcDoAdw14PCgd5ok79vl/JVuDgAAgN21y/msXc7fJ3lVu5YeWdcuYAz+6y5/uHQtvD9OKYPVJnnWrDaXtQsBAADoq7I4/DTTPQb2u5rV5k735nzbnR/Edjn/30z32J4f2SZ5KegAAAD45Faw8STuJb9l3aw2D2sXMQb/uMffWSc5P3AdYzBL8rZdzp8neZPkslltpj6UFQAAmKh2OZ8luYhg42f+rF3AWNyng+MiieNSf65NcpXkj2a1WVeuBQAA4CTa5fw8ye+xML6rB46IPYz7BByzJH8fvpRR26YLO/4UdgAAAGNStqAskvw7XaihW2N322a1+bV2EWNxr0Em7XLunOL7a9Nt8/kr3V4rSR0AADAo5QCKRZLfyq/cz+tmtXlWu4ixuM8MjiT5IwKO+2rSpZrnSdIu522S63SBx3WS62a12VarDgAA4JZ2OT9Ld//3r/LrompB4/JH7QLG5L4dHLPYpnJs63TdHv8pv950elwbXgoAABxK2WJys4C9KL/+lm5x1sL28diecmD3Pmu3Xc7fR3LXB+tb/3yz100AQl/chHS3//0mrGtt0QJgyEqL/o3FF//5t9NVAncmuOgH21MObJ+A4yJOUwEOY1s+vuxa2tqyBUANpSX/ZnBi8imwuPl9gH396lr3sPYJOJp021S8wQPHdp0u9PgrJQxxIhEA+7rVln+W5J/l11n5ADimdbPaPKxdxNjcO+BIknY5f5vk4jClANzZdbrA4z/ptmuZUQPAN5UZcl8OSpxVLAmYtsfNanNZu4ix2TfgmMWwUaBfrsvHf+IoZoDJKvMxztJtLRFmAH3SNqvN/6tdxBjtFXAkho0Cvdem6+74KwIPgNEqgcYiXaCxqFkLwE+8bFabF7WLGKNDBByLJO/3LwXgJG4Cjz/TBR7bqtUAcC9lCOgiyb8j0ACGo003XNS26iPYO+BIknY5/xDHDAHDtE1yleRPg0sB+qsMBF3kU6Axq1gOwH1dNqvN49pFjNWhAo6LODIWGL42JexI190hWQeoqIQa5+lCjfPK5QAcgqNhj+ggAUeStMv535GkA+NyE3ZcCTsATqMMsT9P8nt0CAPjonvjyA4ZcCxiFgcwXpfptrFc1S4EYGx0agAToXvjyA4WcCROVAEmoU0XdvzhRBaA/bTL+U2ocVG5FIBjc3LKCRw64FhEFwcwHddJ/kjXbmgLC8AOyhaUJ+k6NWZViwE4DSennMhBA44kaZfzt5HCA9Nzma6rY125DoBeKt0aT6LbF5ieZ81q87p2EVNwjICjSfJ3kubQnxtgAK6TvGlWm8vahQDUVq4Ln6YbGDqrWw1AFdfNavOgdhFTcfCAI0na5fxpklfH+NwAA9EmeZNu+8q2ci0AJ9Uu52fpujUuKpcCUNtDHb6nc5SAI0na5fxDHO0FkHTbV14KOoCxK/PYnsc2FIAked2sNs9qFzElxww4zpJ8ONbnBxigdbqgY125DoCDapfzi3QdGxa3ADrbJA8MFj2towUcSdIu5y/SpfgAfLKOoAMYgRJsPI/5GgBfsjWlgqMGHEnSLufvo00R4FvWEXQAAyTYAPghW1MqOUXAMUu3VcWpKgDfto6gAxgAwQbATzk1paKjBxzJx3PP353iawEM2DrJY8NIgb4pw0PfRrAB8CNturkb29qFTNVJAo7EPA6AO7iMU1eAHnAqCsCdPGpWm6vaRUzZyQKOJGmX83dJzk/5NQEGqk3yJt0eTtO3gZMqW4yfJ7moWwnAYLxsVpsXtYuYulMHHE2S93GEGMCu2iTPmtXmsnYhwPiVa7Wn6Y58NT8NYDeXzWrzuHYRnDjgSAwdBbindbqg47p2IcA4lZlpr2LOBsBdXKc7ElbHbQ+cPOBIknY5P0vXySHkALib1+laIP0QBQ6iLD69jTkbAHcl3OiZKgFH8nFo1ftaXx9gwGxbAQ7CEHiAe3NiSg9VCziSj2epv61ZA8CAreNYWeAeHPsKsJc2XeeGrcM9UzXgSIQcAHtq021ZeV27EKD/yhDR5+kGiQJwd8KNHqsecCRCDoADuE7XzeGHLfBNujYA9ibc6LleBByJkAPgQJ7p5gBu07UBcBDCjQHoTcCROF0F4EDWMZsDiK4NgAO5TvLItVX//VK7gNtKGvYwXToGwP0sknwonXHARJUTUt5HuAGwj5ujYLe1C+HnetXBcaO0Ur5Pcla7FoCBu0rXzSE4holol/NZkndxHQWwr8t0239dRw1ELwOO5GPI8SrJReVSAIZum66t0p5RGLnSufUqtvsC7Otls9q8qF0Ed9PbgONGu5w/TfeDGoD9GEAKI2VhCOBg2nTdr1e1C+Hueh9wJB8HZL2L1QiAfdmyAiNThrS/jS0pAPsyTHTgBhFwJB9XJt4mOa9dC8DAbWPLCoxCu5yfp7s+sggEsJ/XzWrzrHYR7GcwAceNsmXlefwgB9hHm27LymXtQoD7aZfzV0me1q4DYOC26bpb15Xr4AAGF3AkH6eDv013FCIA92e1AgamdLW+i+sggH29TjdM1NbdkRhkwHFDNwfAQazTbVnxwx16rszbeJdkVrkUgCHbRtfGKP1Su4B9lNMAHqQbmgfA/SySvC83TkBPlXkb7yPcANjHyyQPhBvjNOgOjtvKSStv44c+wH216To51rULAT7XLucX6a5zALifdbqujW3lOjii0QQcN8oFwKvYtgJwX48NH4X+aJfzt0kuatcBMFDb2I4yGaMLOJKPw7eeJnkSQQfAfbxsVpsXtYuAKSvXM2+TnNeuBWCAtumuZy4r18EJjTLguCHoANjLZbPaPK5dBExRuYZ5n8RsHIC72UawMVmjDjhuCDoA7u0qXVunE1bgRNrlfJbupBThBsDuthFsTN4kAo4bJeg4T3e07KxuNQCDcZ3koZADjq+cZvQ+FmQAdrVO8qZZbZysybQCjtvKUWu/x75WgF0IOeDIhBsAO2vTdZm+aVab69rF0B+TDThulDbQi3Rhx6xmLQA9J+SAIxFuAOzkOsmbJFeuR/iWyQcct5Wujn+n6+pwgQHwtW2SR1ZL4HCEGwA/tE3XrfGH6w9+RsDxHe1yfpEu7FjEBQfAbW26Tg4XGbCncr3xtnYdAD1zswXlT7M1uAsBxw5udXYsYhsLQCLkgL0JNwA+s41ODfYk4Lij0ka6yKfAA2CqhBxwT8INgLTpTkD5K91MjW3VahgFAcee2uV8kS7o+C0CD2B6hBxwR2Wx5EPtOgBO7HagsXbtwDEIOA7sVofHv5KclQ+AMXO6CuzIQFFgQtbprhH+ky7Q2FathkkQcJxAu5z/f7VrADgyIQf8hHADmIh1s9o8rF0E0/RL7QIAGIWzJO/b5dyNG3yDcAMAju8ftQtgdC6T/E/tIqjuX/l0Ed/EVq2puLmBe1C7EOiTEvwJN6Zlfeuft3FthHl9cBICDg7tj2a1Wdcugn4qK5hNuuOWZ/kUhCyqFcWhnbXL+dtmtXlcuxDoA+HGKLXptuVt0wUX1+X3tmYM8D3tcv4irnfg6AQcwMn8aFp2u5zP0oUei3wa0js7QVkc3kW7nEfIwdTdCjd0sQ3XdT4NSbxOcm3WEEB/CTiAXiirXtvcaustNwc3JxNp7RyWi3Y5/0+z2ryuXQhU9CrCjSG5fYTltY5UgOERcAC9VVbJ1vk89FhE4DEUr9rlvG1Wm8vahcCptcv52yQXtevgh24HGusfdRkCMAwCDmBQyoraOvnY4bFI8u8k57HHvY9etcv5tRsHpqRdzi8i3OirbZKrJH/q0AAYHwEHMFilw+OqfDwuQ0x/Txd2zCqWxidNuuNjHxi+xxSULrO3tevgM9dJ/khy5X0IYNwEHMBolC6B6yTPStjxJDo7+qBJ8q5dzh8azseYlfedd7XrIEnXqfFHkkuhBsB0CDiAUSphx+N0nR3n+dTZQR1n6Va1H9UuBI6hbJl7G4FqTTddfW9siwOYpl9qFwBwbM1qc9WsNo+S/JrkZbqVPU7vvF3OX9QuAo7kbZyYUstNoP1rs9o8Fm4ATJcODmAySpvyiyQvyhDA3+MkllN7XoaOXtUuBA6lBHc6xE7vMskfhoUCcEMHBzBJzWpz2aw2D5M8THeRzOm8bZfzWe0i4BDKFrjnteuYkDbJ63zq1lhXrgeAHhFwAJPWrDbrZrV5nG77ymXlcqbiZuioWQUMWgnqnJhyGm26LYa/NqvNM4NDAfgWAQdAuu0rgo6TOkvyqnYRsKd3MVT02G4HGy+cxATAjwg4AG4RdJzURZmFAoPTLuevYqjoMQk2ALgzAQfAN9wKOh4kWVcuZ8xetcu5m0QGpczdeFq7jhG7jGADgHtwigrAD5TjBh+2y/ki3V77WdWCxqdJ97g+qF0I7MLcjaNaJ3lsvgYA96WDA2AHZRjpr0mepWud5nDOSrs/DMHbmLtxaNskj5rV5qFwA4B9CDgA7qBZbV6nm89xVbuWkXlaumSgt9rl/EWSRd0qRudls9r82qw23lMB2JuAA+COmtWmbVabR0keplt55DAcHUtvlVkxz2vXMSLrlDkblesAYEQEHAD31Kw263SzI15XLmUsbuZxQK+U4O1d7TpGok3yzHYUAI5BwAGwh9LN8Sy6OQ7lvJxQAX3yPAYMH8I6yYOy1Q8ADk7AAXAAujkO6q2tKvRFmQ3jSNj96NoA4CQEHAAHcqub41GctLIPW1XohRK0+V7cz3WSh7o2ADgFAQfAgZXTAH5N147N/diqQh/YmrKf181q86BZba5rFwLANAg4AI6gdHM8TPKydi0DZqsK1ZRTU2xNuZ82yaPS0QYAJyPgADiicgTiw9iych9NHMtJPbam3M/NlpSr2oUAMD0CDoAjuzWAVJv23T0tQx7hZNrl/EWSs8plDNFVunDDex0AVQg4AE6gnBzwMMll3UoG6VXtApiOdjmfJXlSu44BetmsNo+a1Ua3GgDVCDgATqTM5Xgccznu6qysqMMpvEq3PYrdtEkel+14AFCVgAPgxMqNwOPadQzMk7KyDkdTtkM5vWd3bbotKZe1CwGARMABUEW5ITB8dHcGjnIKBovu7maYqHkbAPSGgAOgkjJ8VMixuwsDRzmWsg1qVreKwRBuANBLAg6AisoNwsMk28qlDIUuDg6uXc6bGCy6q5twQzALQO8IOAAqKyGHY2R3s2iX84vaRTA6Bovu5rJZbR4INwDoKwEHQA+UG4aHEXLs4nlZcYe9leG1F5XLGILLcgoUAPSWgAOgJ4QcO5sleVq7CEbDYNGfE24AMAgCDoAeEXLs7IkuDvZVhtYuKpfRd8INAAZDwAHQM0KOnTTRxcH+DK39MeEGAIMi4ADooVshh2F+3/ekzE+AO9O98VPXSZ7VLgIA7kLAAdBTQo6famIFnvvzvfN9joIFYJAEHAA9Vo6QFXJ834UuDu6qHDW8qFxGXwk3ABgsAQdAz5WQwz7477MSz135nvm2Nslj4QYAQ/WP2gUA8HPNanPVLueP40jLb7lol/OXzWqzrV3IqZQTZM5u/dasfOziOp93BF1P6Ya2Xc7Ps/tjNSVtus4Nw40BGCwBB8BANKvNZbuc/5bkonYtPfQ8I+pyaZfzs3QzRhZJ/jufwozFkb7ezT+uy69/3fr3dmQ3vU9qF9BTz0b2PAMwQQIOgAFpVpvHZebEonIpfXPeLufPhtaJcKsTY5Hkn+Wfz370d45s8cWvz5OPAch1+fhPuq6P9WlL25+TU77rZbPaXNYuAgD2JeAAGJ5HST5Em/1tTZKnSV5UruOHboVTv6V+mHFXn9V7K/RYpws91gPYJmT2xteumtXmRe0iAOAQBBwAA9OsNm27nD9K8j7djT2dJ+1y/rpPXRylQ2OR5N/l11nFco7hy9Bjm+Qq3RaXdc+ei0V0b3zJAGMARkXAATBAzWpz3S7nz2Lo6G1Nuvkkr2sWUbo0zvMp1JiSWbpOmqdJ0i7nN2HHVQ+6O36v/PX7xokpAIyOgANgoAwd/aYnqRBw3Ao1fs+wtp0c23n5eNUu59dJ/khyeeqb6vL8XJzyaw6AoaIAjM4vtQsA4P6a1eZxujZzOrN2Ob84xRdql/OmXc4v2uX8fZK/k7yKcONHztI9Rv/bLufvTvU8FU5O+dyloaIAjJEODoDhexzzOG77PcnlsT55OcL1SbrOBI/5/ZynO/nmVbrn6s2xtrCUOSgXx/jcA3Wd5FntIgDgGHRwAAxcaTN/WbuOHlmUEOKgbnVrfEh3wyzc2N/N6Td/t8v5+yN1dQiiPmfuBgCjpYMDYASa1eZ1mcdxXruWnniSA5wOUVb/n6brCpnt+/n4oUW6cOp5kjc53KwOR8N+8tLcDQDGTAcHwHg8TncyAt32h3uv2pf5Gi/SzdZ4HuHGKc3Szer4u13OX+z5PC7iubuxblabF7WLAIBjEnAAjERZ7d67a2Ek7jV34RvBhq0N9TTpnoN9gg5Hw3a8NwAwCQIOgBFpVpurJFe16+iJnW9uBRu9dq+gw3DRz7w81hBXAOgTAQfA+Niq0jnbZdhou5w/jWBjCG6Cjg87DiPd5c9MwXWz2ryuXQQAnIKAA2BkylYVp6p0nnzvP7TL+aJdzv9ON+9BsDEcsyRv2+X8Q5mx8T3ffe4nxtYUACZDwAEwQmXFdl27jh746lSZdjmftcv5uyTvYwDlkJ0led8u5+++3LZSOndmVarql9dOTQFgSgQcAOP1rHYBPdDc3s5Q5mx8iON0x+Q83XyOp7d+T/dGso1OLgAmRsABMFJl5dbe++Tf7XJ+1i7nH2LOxlg1SV61y/n70r0hwOoGi5rFA8CkCDgAxu1lDBw9T9e18dOBowzeIt1zPfUQa92sNpe1iwCAUxNwAIyYgaMwSV7zAEySgANg5MrA0W3tOoCTuGxWm3XtIgCgBgEHwDRY0YVp8FoHYLIEHAATUPbjryuXARzXZbPabGsXAQC1CDgApsPKLoxXG0dDAzBxAg6AiSj78teVywCO441jYQGYOgEHwLTo4oDxaZO8rl0EANQm4ACYEF0cMEpXujcAQMABMEV/1C4AOCidWQAQAQfA5JQTVbaVywAOw8kpAFAIOACmyYovjMOb2gUAQF8IOACm6SrdYEJguNbNanNduwgA6AsBB8AElYGEl7XrAPaiewMAbhFwAEyXmyMYrm2z2lzVLgIA+kTAATBRZTChGyQYJqchAcAXBBwA0+YmCYbpsnYBANA3Ag6ACSst7tvadQB3cuVoWAD4moADANtUYFh0XgHANwg4AHCzBMPRGi4KAN8m4ACYuGa1uU5yXbsOYCfCDQD4DgEHAIkuDhgKxzsDwHcIOABIrArDEGxLxxUA8A0CDgBSTmRw4wT9JogEgB8QcABwwzYV6DevUQD4AQEHADesDkN/tbanAMCPCTgASPJxm8q2chnAtwkgAeAnBBwA3OYmCvrpz9oFAEDfCTgAuO2v2gUA37SuXQAA9N0/TvFF2uW8SXJ2ioDTpRwAACAASURBVK8FwP01q81Vu5zXLgP43HWz2rS1iwDYUdMu54vaRZyYOUk9cZSAo13Oz5P8li7UWBzjawBwNOt474Y+sT0FGJKzJO9rF3FqZYHounz8lWRd5ptxQgcLOEqo8e8kF4f6nABU8VcEHNAn69oFALCTs/JxkSTtcn6d7ojvS514p7H3DI52Ob9ol/O/k7yLcANgDNa1CwA+aVabde0aALiXsySvkvzdLudv2+V8Vrme0bt3wNEu5+cl2HibZHawigCoys0U9Mq6dgEA7K1J1wzwd7ucvygzKjmCOwcc7XI+a5fz9+k6NmYHrwiAPljXLgBI0u3lBmA8nif5UEY8cGB3CjjKk/Ah9mYDjJ2bKugHRzcDjM8sybt2OX9Vu5Cx2TngKA/+u3TtNQCMm5sq6AdhI8B4PW2X8w+2rBzOTgFHu5y/TfL0yLUA0B9uqqC+1hGDAKN3lm7LylntQsbgpwFHCTcujl8KAH1RbqocZwZ1CRoBpmGW5L2QY38/DDiEGwCT5uYK6rJVDGA6mnQhh+0qe/huwNEu5y8i3ACYMgHHMK2/88HweA0CTIuQY0//+NZvtsv5It3xNQBM1//ULoBv2qa78f1P+bVtVpv1rn+5XDSdpbuIOkvyr/Lr7MB1sr9t7QIAOLmzJK+SPK5dyBB9FXCUC593FWoBoF+sHvfDdboOjL+SrJvVZq/ZKOXvr8u/Xt38fvn5v0jyW5LzCDyqa1Ybr0GAabpol/M/m9Xm6ud/lNu+1cHxKo6CBUDAUdN1kj+SXJ3qFI0SfFyVj2ftcj5LF3T8nm41idPa1i4AgKretsv53gsbU/NZwFG2plxUqQSAXmlWm7ZdzmuXMSVtksskb/pwNGip4XWS1yXseJLuGsEiyGlsaxcAQFVNbFW5sy+HjJq7AcBt69oFTMA2yeNmtfl/zWrzrA/hxpea1WbbrDbPkvya7kJrW7eiSdBBBcBFWWRgRx87OEr3xqJaJQAwLdskL5vV5rJyHTsrbbKXSS7b5fwi3cLIrGJJY/Z/tQsAoBeeRxfHzm53cOjeAOBLf9UuYIS26To2fh1SuPGlZrW5bFabm44O+4MPTwcHAIkujjv5JUnKA7aoWgkAjN/LJA+GHGx8qfy//JpuXgeHIzQC4MZF7QKG4qaD40nVKgDoK6vIh3GdLth4McZp6M1q05YZHQ/je+ZQtrULAKA3fq9dwFDcBByLmkUA0Fujuxmv4GWz2jxoVpvR3/g3q826WW0eRDfH3vo4bBaAambtcu7I9h38UraneLAA4LDaJA+b1eZF7UJOrXRzPIqADAAO5bx2AUPwS3RvAPB9o+86OJLrJL82q826diG1NKvNVZIH8T10H9vaBQDQO7/VLmAIfknyr9pFANBPY5wXcQKXZUvK5B+7ss3iYZKryqUMzbZ2AQD0jl0XO/glHigAOJTLZrVxVv0tZQDpoySXtWsBgAFrHBf7cwIOADiMx8KN7yuPzWXtOgBgwGa1C+i7X5I0tYsAoNe2tQsYgMfNanNZu4i+KyGHE1YA4H5mtQvou19+/kcAmLht7QJ67plwY3flhJXL2nX0nMGsAHzLrHYBfSfgAID7u2xWGx0Jd2S7yk/9X+0CAGCIBBwAcD8Giu6hPHbr2nUAAOMh4ACAu7tO8qx2ESPwKLZjAAAHIuAAgLtpkzxqVpu2diFDVx7Dx+keUwCAvQg4AOBuHjerzbZ2EWPRrDa6YQBgN+vaBfTdL9EaCgC7et2sNle1ixibcgqNxxUA2MsvcfwfAOxim+Rl7SJGzFYVAPiBZrVZ166h735J8p/aRQDAADw2d+N4bs3jIPnv2gUA0Dvb2gUMwS+xjweAHzurXUAPXFo1Ob6y/Wddu44e8JoD4Evr2gUMwS8u2DiwWe0CgINrahdQWRtbU05JFwcAfO2v2gUMwc0pKgZ7cSiz2gUAHNgbp6acTnmsBUrA2PxWuwAGzz37Dm4Cjj+rVgEA/dQmeV27iAl6HQNHAeDGlTlgu/kl+Xg8mwcMgM+0y/nUt6e8cUFxeuUxf1O7jorM4ADgNg0JO/rl1j9P+UKCw/ln7QKAg5ryjZbujbqm3MUx9WARxsjrmvvaloYEdnA74LisVQSjMqtdAMCB6N6oqDz29hsDYzHlBQP2Yy7VHXwMOAz1AuAbZrULqOiydgFM97qkXc7dDAGge+OOfvni36fcDsphLGoXABzUrHYBlVw5OaW+8hysK5dRi3Z2GAmBJXt4VruAofks4CjtoM6fB+DGf9cuoJI/ahfAR1N9Lma1CwAORmDJfayb1cZWzTv6soMj5UH0QHJvUmoYlSm+nlsXFL0y1ediVrsA4GBmtQtgcDQe3NNXAUfxOMn2hHUwLlJqGI8pvp6nekPdSxMeNjrV7ikYo1ntAhicx7bK3s83A45yMfEo5nFwP1Nc8YWxmuLr2Vnz/TPF52SKrz0Yq3/WLoBBeamT9P6+18GRZrW5TvLwhLUwHlNc8YXRaZfzWe0aanBR0UtTfE5mtQsADmZWuwAG47JZbV7ULmLIvhtwJB9DjsfRycHd/Fa7AOAgZrULqGBduwC+VjpLr2vXcWKz2gUAB7OoXQCDcNmsNuZu7OmHAUeSlHN3H0bIwe5mtQsADmKKLfJ/1S6A71rXLuDU2uV8UbsGYD/tcq6zmV28Fm4cxk8DjuSz7SpTWz3hfma1CwAOYop7hte1C+C7phg+zWoXAOxtiosF3M3jZrV5VruIsdgp4Eg+CzleH68cxsKqE4zCFC/KBPn9NcXnZla7AGBvi9oF0FvXSR6UHRMcyM4BR9LtgS3p0sM4RpYfm+KNEYzNonYBJ7Ytsx7ooXJc3tSeHzOtYPim2A3Jz71sVpsHpYmAA7pTwHGjWW3WzWrza5KXmd7FBrv5V+0CgPtrl/MphpTb2gXwU1O7EJzi6xDGxuuY2y6T/OqklOO5V8BxozwxvyZ5FheGfM6bOQzbFF/DU5zxMDRTCziaqR7XDCMyxZ+nfK7Np2DjcelI5Ej+se8nKO28r5O8Lit+vyc5j32jU+fNHIZtil1YOhL77/9qF1DBIt2FMTAwZtJNWptucPmfSa5sgT2dvQOO28oeouskz8qKw1n5+FeSpny48Z2IdjlfNKvNunYdwL0sahdQwdS6A4ZoW7uACqYYNsJYLGoXwNG1+XT9cJ3kf5Kszdao56ABx22l9Wab5OpYX2No2uX8f9OFPFOxiCMXYaiE0fTRtnYBFSxqFwDc29QCynWz2jysXQTTttcMDu5sakne1N7UYRQm3FKrfZQ+OmuX8yktjsCYLGoXcGJmWVGdgOO0trULOLFF7QKAe1nULqAG7aT02KJ2AcDdlNmEUwsnt7ULAAHHaf2ndgEn1kz0qEkYun/XLgC+Y6oh1G+1CwDubFG7gAq2tQsAAcdpTfHC7Lx2AcDuSiv81ILJm0nn9FyZQr/O9LYTLWoXANzZ5IJJhwvQBwKO05piwDG5N3cYuEXtAip4YyjacJTnamo/T8/K6XTAcExtkW9buwBIBBwnVVaetrXrOLGF4WgwKFPcnjK1m+UxmOJztqhdALCbdjmfWriRTPN9mR4ScJzetnYBFUzxTR6GalG7gApclA3P1GZaJdMMH2GoptjBPMX3ZXpIwHF6Uzw+aYpv8jA4ZSjwrHYdJ9Y2q822dhHc2RRDqUXtAoCdTXFxb127AEgEHDVM8aJsim/yMES/1y6ggim+Jw/eRI/0bSba9g6DMtHFgsTPU3pCwHF669oFVOCiDIZhiq/TKXbVjcW6dgEV2KYC/TfFxYJtmTUI1Qk4Tmyig0YTF2XQa1acGKApPndTDCFhaKb4Ol3XLgBuCDjqcFEG9M0UV5wSF2VDNsXuGx2R0GMTXiwwYJTeEHDU4aIM6Jspvj611A7bFBcLEh2R0GcWC6AyAUcd69oFVOKiDHpowitO69oFcH/l9Jtt5TJqOG+X86Z2EcA3TXGxYKqDn+kpAUcF5U1giquGFy7KoJee1C6gkil2043NunYBFTSZ6E0U9Fm7nC9isQCqE3DUs65dQCUuyqB/pvq6XNcugL1NNaSaahs89NlUX5dTfR+mpwQc9Uz1zWCqK8XQS+1yfpFuRXhqtmWLA8O2rl1AJYt2OZ/VLgLolA7li9p1VLKuXQDcJuCoZ127gErOyn5/oB+muuK0rl0A+5vwHI7EggH0yUXtAippm9VmXbsIuE3AUcmE53AkLsqgF0rYuKhdRyVT7aIbo3XtAiq5qF0A8NFUr23XtQuALwk46lrXLqASw0ahH6Z6QZZM9/13jP6sXUAlTdliBlQ04eGiicUCekjAUddUL8qS5GntAmDKSsg41eGi1+ZvjMq6dgEVTTmkhL6Y8utwXbsA+JKAo6517QIqmuq+f+iLp5nmcNFk2u+9o9OsNm2S69p1VHJWVo+BCsqw36kuFmzLlnvoFQFHRWUFcapvDDOttVDVlEPGKXfPjdWUn9PntQuACZvy629duwD4FgFHfevaBVQ05R8KUE0JF2eVy6jFxPdxuqpdQEWOjIUKJn40bDLtYJkeE3DU90ftAiqatcv5VNv6oKYph4vr2gVweKVNelu7joqm/JqGWiY9T65ZbaYcLNNjAo7KJn5cbDLtwUxwchPv3kisOI3ZlC+2L3RxwOmU7o0pX8NO+f2WnhNw9MOU3yQWBqTBSU19pXfK77djN/XjCqf+2oZTmvKg7sRiAT0m4OiHqb9JuCiDE9C9katy4gYjVNqlp/z86uKAE9C9kcRiAT0m4OgBF2VZOFEFTmLqYeLUw+QpmPpF99Rf43AKU+/esFhArwk4+sNFGXA0ujeSeJ+dgqmHWBftcn5WuwgYq9IlNfVr1qm/z9JzAo7+mPqbxUwXBxxHaad9VbuOyqw4TYCOyCRe63BMUw83EosF9JyAoydclCVJXpUbMeCwpt5OmwiRp2TqF9+Gd8MRlO6oi9p1VGaxgN4TcPTL1C/Kmkz8THE4tNJOO/VhaIn31yn5o3YBPfC2dgEwQrqjLBYwAAKOfnlTu4AeeG4KPBzUq+jeuLTiNB3NarNOsq1cRm2zdjm3YAAH0i7n50kWteuorI3FAgZAwNEjzWpzHRdliZUnOIjSpn5eu44esOI0PS7CuwWDqYebsDdzrD6yPYVBEHD0j9babv+wmzLYn7AwacuMI6ZFR2TXueWmDPb3NE4hS9yjMBACjv65rF1ATxg4Cntol/MXcUGWeE+dpGa12Sa5rl1HD1wYOAr3VwaLOjkl2Zbtf9B7Ao6eKRdlVhu7GzM/UOAeyhwbr5+Olfzp8tx33lowgHvTBdXRvcFgCDj6yX7xzlMrT3AvtqZ01iU0Zpocv96ZReAJd1YG9S5q19ETl7ULgF0JOHqoWW0u46LshuQc7sAF2WesOE1YGYanI7LztLTaAzvQCfmZK4sFDImAo7+01nbO2uVcyAE7cEH2mbaExUybn6Wf2KoCu3sbR6zfsFjAoAg4+uuydgE9YqsK7OZdXJDduKxdAPWV49fXtevoCcMSYQdlSPeibhW9sXUSGUMj4Ogpw0a/YuUJfqBckGlB/8TKPTesPn5iwQB+wKkpX/GzlMERcPSbN5VPZjE4Eb6p3LC4IPvEfmE+KluVtpXL6JN3Fgzga+V14Vrzkza6IRkgAUePlfOmt5XL6JPzdjm/qF0E9IkLsm8SDvMlXRyfNOm2swGfexWdkLddlWHNMCgCjv57WbuAnnllEjx85m26Dic61yUchtte1y6gZxZlWxuQpCygXVQuo2/cgzBIAo6e01r7lSbmcUCSj0fCnteuo2d0b/CVsgp5WbuOnnluHgd8nLvhxL7P2erJYAk4hkFr7efOoiWfiSs3Ji7IPrd1NCw/YDXya+ZxMGm3tnl6HXzOYgGDJeAYhtfpBv3wybn2WqaqXc5nsYf+W1yQ8V1lNfKychl90yR5X7sIqOhtzN340tpWT4ZMwDEApbXWhfvXnrfLufZ8JqWsNr2L1aYv2YLALnREfu2sXc51RTI57XL+KrZ5fot7DgZNwDEcBqR921tDR5kYq03f9sa0d36mrEquK5fRRxdlpg9MQhkq6nv+a9tmtbmqXQTsQ8AxEAakfVeT5L09xEyB1abvaiMEZndmcXzbK0exMwVlYUzX0rd5f2TwBBzD4k3n24QcjJ7Vph/SvcHOdHH8kKPYGbXy/W3uzLcZ1M0oCDgGxIC0HzqLoYuMVAk3rDZ9m+4N7sOCwbfdLBgIORgdM6x+yvsioyDgGJ6XcaLK9ywMSmNsyo2G42C/T/cGd6aL44eaOD6WkSnfz++TzCqX0le6NxgNAcfAlC4O042/70LIwVjcaqV1o/FtujfYh9XK75vF1k9G4la4oTPp+57VLgAORcAxTK+ji+NHhBwMnnBjJ7o3uLfSxeG0gO87i5CDcRBu/NjaySmMiYBjgMoFvS6OH7tol/MXtYuA+xBu7GQb3Rvsz6rljwk5GLSy4CXc+DHdbIyKgGO4dHH83HNH3jE0wo2dvdS9wb4M796JkINBKuHGRe06em5dutlgNAQcA1Uu7K08/dxb21UYCuHGzgxD45AM7/45IQeDItzYmXsJRkfAMWDlAn9buYwhMJOD3hNu3Mnj2gUwHoZ370zIQe+1y3nTLucfItzYxWWz2lzXLgIOTcAxfC70dyPkoLeEG3einZZjeB0LBrsQctBbTku5E53gjJaAY+DKhf66chlDIeSgd9rl/DzCjbsQ6nJwZdunQXu7OUvyoQSz0AvCjTtzChmj9V+1C2B/7XI+S/J37ToG5DrJQ2/s1FaG4Arddve6WW2sOHE07XL+Psmidh0D0ab7WarFnap0Qd7Ztlltfq1dBByLgGMkypGozyuXMSTXSR6Vvddwcu1y/irJ09p1DEib5FfBJMdUbpQ+1K5jQNokzwz9pZZ2OV8keRfhxl08tNXzbsrPhvMk/0oyy9edQut02xz/SreVdnu66viSgGMkSmveh3QvOnZj9YmTK6/VVzEA7a4eu4niFISP9/KsWW1e1y6CadEFeS9XzWrzqHYRQ1Cu1y6SPMnd76/W6bYBXR22KnYh4BiRspf/Xe06BsiNEydhj/C9rZvV5mHtIpiG8jr9O1aE7+oyXdChy4qjE0TeS5vkge6Cnyvh2avs/3NgneSljpnTEnCMTLucv0vXQsXd2NvPUdkjvJdfXZBxSlaG782MK46qBJDvYlbOfbxsVpsXtYvosyN+f3nsT0jAMTJl4OiHuIm6j3W6uRwuzDiodjl/mm4lgLtzUUAVBo7eW5vuZ+m6diGMS1koeBfbse/julltHtQuos9O8P11la5r3H3GkTkmdmTKKqej7u5nkeTvMrAK9tYu5005mli4cT9b4QYVPU53s87dNEnel+HncBClq8qsufvTpfwDt7psZ0f8Mufp3hstQh+ZgGOEyqCvde06BsqFGQdx64flReVShuxx7QKYrrJg8KZ2HQP2vF3OXcyzl7JQ8C62jO3jtY6q77u1LeUU71Vnseh1dAKO8ZLU7ufmwmxWuxCGp2xJ+RDDRPfhgozqSgeRk7bubxGdkdzTrWObzZa7v210dv/Mqbc9XZTrRI5EwDFS5ehTb2j7WST5UE6ngZ9ql/NZ2bcvnd/PNt6/6A+dRPu56Yx8pZuDXZVOWltS9mfmww+UrU+LCl/6uUXU4zFkdOTa5dwq8mEYDMQPlSDsbQz4PYSHujfok3Kz9bxyGWOwTfezdF25DnqqdG28jWvXQ3BC4A/04Ejwy2a1EaAfgQ6O8TMk7TDO07XZ6ubgM6Vr411Ot39z7GxNoXfKVpV15TLGYBbdHHzHra4N4cb+ttEJ+TMXqXvddqGL4zgEHCNnq8pBNUnetcv5O29IJJ/N2hB8HYb3K/rMgsHhPE23BXRRuxDqa5fzRek41iV1OI90Hf/Uk9oFpB81jI4tKhNR5gIsatcxIm2Sl+XEGiamtNC+itfUoT0ooSz0Ugk1zdg5LFtAJ6p08TxPF3hxOC8dsf5jtwbY1rZtVptfaxcxNjo4puNRrDwdUpPkVbucW4GakHJc3at0PxQXlcsZm2fCDfquhNpXtesYmZstoC8q18EJleGOf0e4cWhr4cZO+tJ5OythCwck4JiIsjJikM3hnaXbT2zbysiVlVsXY8ex1g3FgDxOt7+dw2nSnSrgSNmRu7UdxVDuw3Otv7t/1S7gFgHHgQk4JqRZba6SuIk4jpsVKIPTRqZdzs/b5fzv/7+9u0ly6sraBfxWxe1/546g0hHqG0bgZAQFXXUgR2AYAWYEwAhS7qhLegSIESD3FWHVCO6pEXy3cbaMjDMhfyTt8/M8EUTa6TS5jEHa591rr52uLd3/28Nr03WYwSDYMDiqs3SbBh8FHeOyN5D7YzzQHctFs9xsaxcxEGe1C9hzVruAsTGDY4JcHXt0bZL36W6DcCxooMri+nUcRTk2V8IySK6OPYlFunkC28p1cE+lu/V1uhsrOB5Xwt5BO5/9b+0a9lw1y42NngMScExQebP5HLvRxyboGCDBxkkZhMagGeB9MosIOgZFsHFS62a5eVy7iCHpWcCxapabJ7WLGBNHVCaoLBC01x7fbjr4H+189oujK/1WzgV/TNc+e165nCkwCI0xeBbzOE7hRbr30kvzrvqtHEW5TDez6kXlcqbAMU/4ig6OCdNee3Jtul2o93ah+qNMcn8dZyBPaZvuSlidTQxej64bnJJVuo6OVeU6KEr34/MINU7tWZmxxx3o4Bg3AcfEaa+tZpHkV4uzOko3zct0i7GzutVMTptu7oYrYRmNEpRe1q5jgtbpNg0WtQuZqvJ7/3msJWtwzPOeBBzjJuCYuPKg9zke8mrZJnmTbsCQ3ewjs8PUCxceRhij0pb/onYdE6VD8oTKMaEXsUlQk8GUDyDgGDcBB7v22o8xdLS2RXR1HFxZiD1N8nMsxGoz5Z1Rc0tZL6yS/BobBwdXujX+ne49lXrW6Toh/f6+h7LZ9bF2HXsMiT0wAQdJknY+e5rkQ+06SNJ1dVylCzu08d9D6Ux6GguxPrFDwejpiuyVNt176W9mFNxfWR/u3ktthNXnmOcD9TDgSLPceCY/IL+Y/Kmdz14meVu7Dv5iG2HHrQg1es1uE5OhK7KXhB13INTotSc6fR9GwDF+fjH5C2eIe22brvXWAq0oDxLn6RZi51WL4SZ2m5gcXZG9d5Xkt3SdZdvKtVS3t0HwU4QafWaG1QH09BbJH7wWHY6Ag79xs8pgrJJ8SrdAW9Ut5TTKPI3zdIuw82gDH4LHwg2myM0qg7HOX99PR99pVgKN83x5LzU3pv/MsDqQngYcOnMOSMDB35Q3vo/xhjc0q3QLtHVGskgrbYSPkvwYgcYQ2W1i0nRFDtIu8Pg93fC/wQe0ZXPgUQQaQ7VolpuL2kWMRU83cl81y8272kWMhYCDa5WQ449oUxyybbqF2u/l47avC7Xy++1RvoQZZ+nfmw93I9yACDlGYpUv76fbPu+0lo2Bs/Ljp3Tvq9Zyw+WGjQNr57M/0r8NszfNcvNL7SLGQsDBjQxKG61tvoQf/y0f23SLtu0xvuFegJF8WWz9WD6eH+N7UpXdJtjj+thRalM2D5L8J1/eW3PMAKSszZp8CTH+tffXZ8f6vlRhQPcRtPPZ/9au4RpumjsgAQffJOSYrN3Cbd823SLuOv+Tvy/em2s+x/gJN+Arjn5O2uqaz336xtfvwv99ujCmZ5tuhpVw44D6eINK0TbLzf+tXcRYCDj4LoPSgFsSbsANhBzALbl97Eja+exlkre167iBm1QO5J+1C6D/yjl6Dy3At6yTmPAONyg7sc/SPbwAXEe4cVw/1i7gG4TfByLg4FaEHMA3OCcMt1B2555EyAH8nXDj+M5rF/ANP9UuYCwEHNyakAO4hnAD7qA8vAg5gH3CjSMr1yWfVS7jW85rFzAWAg7uRMgB7BFuwD0IOYA9wo3TOK9dwHc8KrOaeCABB3cm5AAi3IAHEXIAEW6c0r9rF3ALT2sXMAYCDu5FyAGTJtyAAxBywKQJN07rvHYBtzCEEKb3BBzcm5ADJkm4AQck5IBJEm6cUDufPU0yhOMf57ULGAMBBw8i5IBJEW7AEQg5YFKEG6c3lM6Ipp3PXtQuYugEHDyYkAMm4SrCDTia8rDzOF2QCIyTcOPEyuDOIc22GEoY01sCDg6ihBx2n2CcFs1y80y4AcfVLDfbdO+lHn5gfHZdkP58n9ZQjqfsPHWbysMIODiYZrlZRcgBY7NolhsdWnAiJUgUcsC4CDfqeV67gHt4UbuAIftH7QIYn3Y+e5TkQ5KzyqUAD/OqWW7e1S4Cpqqdzy5joQtDZ35VJe18dpbkj9p13MO2WW5+qF3EUOng4OCcI4ZRuBBuQF2le2pRuw7g3hbNcvNYuFHN69oF3NNZufmFexBwcBR7LbZXtWsB7qRN8rjM1QEqKyGHY2IwPO8c8axngMNFv/Zz7QKGSsDB0TTLTdssN89i9wmGYhtnhKF3SuD4LGZcwVBcNMvNq9pFTNzLDGu46NfO2/nsvHYRQyTg4OjsPsEgrNN1bgg3oIea5eYqXWfktnIpwM10QfZA6d4YQwfEUI/YVCXg4CRcIwu95owwDIAZV9BrNgr6Y+jdGzu6OO7BLSqcVJlm/CHJo8qlAJ0LO00wPG5YgV65Svd+aqOgstK98UfGEXAkyapZbp7ULmJIdHBwUs1ys03XybGoWwlMnjZaGDDHP6E33jTLzTPhRm+8zXjCjUQXx53p4KCadj57me5FCDitdbphohZjMHDtfPYoXWfkWeVSYGraJM+a5WZVuxA65fXwc+06jmDbLDc/1C5iKHRwUE2z3LxLd5bYQxaczjvzNmA89uZyrCqXAlOym7exql0IfzHWjdOzdj77pXYRQ6GDg+rKWbkPSc4rlwJj1qY7H3xVuxDgOMoC2NR9OK53roDtnwl0hu+OFm9rF9J3pHzEYwAAFl1JREFUAg56YwIvTFDLOl0b7bZ2IcBxlbPal3FkBQ7NRkFPlUsMPmdcszeuY+DoLTiiQm/sHVnZVi4FxuRNOZKyrV0IcHylZf5xulsdgMNYJflBuNFblxl/uJF0A0df1i6i73Rw0DvlyMrbuP4OHmKbbqdpVbkOoJJ2PnuR8d0oAKf2qmzC0UMT7ABv0w2KX9cupK8EHPRWO589zXQSWTikRboFmUGiMHGldfsy5lzBXa3TbRR4kOypEd+a8j1uw/sGAQe9Vro5LpM8rV0LDIDzwcC1DCCFO3nTLDe/1C6Cm5VnhM+Z7ryhRbPcXNQuoo8EHAyCbg74rqt04YY0H7hW2e28TPKodi3QU7o2BqKdzz7EBuhFs9wsahfRNwIOBkM3B1xrm+44iq4N4FbKmfXXsWkA+3RtDEQ7n71NYthm54l5a38l4GBwSjfH20y3JQ123qVbkOnaAO7EbA74k66NASnDky9r19Ejho5+RcDBIJVujteR3jJN63RdG6vahQDD5qYVJqxNt0nghpSBKJucH2rX0UPbJI9teHUEHAxaOU/8NnagmAaLMeDgbBowQYu4bWxQypr/Y4SxN3GzSiHgYBTsQDEBi1iMAUdk04AJ0AE5QMKNWxNyRMDBiJQdqN3gNBiLVbqujVXlOoCJKJsGr2PWFeOhA3KghBt3NvmQQ8DB6JTBaW/jthWGbZtuMbaoXAcwQXubBj/HgwXDZiD3QLXz2Xm6mRteg+5m0iGHgIPRKi+Kr6PVlmFpk7xP8m6qb0xAf5RNg9dJXtStBO5skS7Y2Faug3twW8qDbZM8m+LtKgIORs+1sgyIXSagl3RHMiCrONo5aO189jLd6w0PM8krZAUcTIYzxfTYInaZgAHQHUmPrSLYGLRyNO5tdIwd2sWUjjwLOJgcQQc9sohgAxggQQc9sopgY/BKl9iHJI8qlzJWi2a5uahdxCkIOJgsQQcVLSLYAEZA0EFFqwg2RqEcJ7+MYaLHtk43l2Nbu5BjEnAweYIOTqRNF2y8H/sbCzA95SrHn6O1nONbRbAxCuVIyut0NzZxGqO/MlnAAYVdKI7ErSjAZOzduvI0dmM5rEV0P45GWXdfxgZjLat0szm2les4OAEHfMUuFAeyTtetsahdCMCplZ3Zl0mexwMM97fbJFiM8UFsigwS7ZVRdnMIOOAGFmfc0yLJr1pnATrlKOjz6JDk9mwSjFC5/vV1xtHdtc14ng/WSV6NZe0q4IBbKMOPnqdruYWvbZP8GjtMADdyfIXvaJNcpQs21rWL4XDKOvptxhMIJMnjdK9lr2sXckBX6YKObe1CHkLAAXdQFmcvoquDzlW6bo2r2oUADEXpkNxtHJzXrYYeWKc7hnJlVtW4jHi+3ZtmufklSdr57HPGd7XtIgOedyPggHsqL9q7rg47UdOxzpduDQsxgAewcTBZ23zZJNCtMTLlWNrPGd+Df5KsmuXmye5vymvY54zzWWCRAR67FnDAA+3tRP07jrCM1TZf2ma3dUsBGKe9Id82DsZpdwTlN52P4zORsLJN8sPXG1zlCM6HOiWdxKBm4gg44ICEHaOyjd0lgCrKA8PuvVTYMVxCjRGb4Lr3yU3dDO189jbd5QRjNog5OQIOOJKvXvTPY4E2BOskv6U7B9zbF26AKSlHQncPUGdVi+E2tklWEWqM0gRDjZ1X37tOtZ3PPmZ880Zusk0Xdnzq259zAQecSNmN+ikWaH3SpizC0p2p3FatBoBvKsdYzvNl84B+sEEwUiXQOE+3hj3POOdqfM+iWW4uvvdF5dfqc6a5zr9K8inJuvbMDgEHVFDOKe4Cj/Po7jildb7sLK3qlgLAfX314GXz4LS26d5LP8XtJ6NRuqWadCHGj+XjWcWS+mCd7mjKrX6PlxD2Y6zt1+XHf9K9VmxPtZEo4IAe2NuREngc3i7Q+JSuS8MiDGCEyubBeb68l57Vq2Z0tvnre+m2ZjF8X/nz8CjXd1z8K3/983F+/IoGaZvk8V3XjhMYOvoQbbq1+c46yX+v+bpVum6QO6/bBRzQQyXweJRukXbTmxN/tzty8nu6BdiqajUAVLPX4bF7Pz2vWc/ArNI9eOxazrdVq+FWyvrxeXQ0HUKbrnPjXkeuylW5lwetaJrWSX5N1ym2vc2/IOCAgShtg7uWwbNYqG3Tvej9Xj5agAHwTXsbCGf5sokw5a7J3W7qn++nZmgMT1kjvo614aE8KNz48yeZxs0qp7RIN+z1m10dAg4YsNJ+eJbuDW3Xbji2xdo63RvNp3ShxlZnBgCHUjo9dsHHv/IlADmrV9XBbfNlY+C/OfGZeI6j/N59HQ/Rh3bRLDeLQ/xE7Xx2meTFIX4uknTPBG++daONgANGqqT5yZc0/6fy8Sz9WrStysfdomubL0HGtkpFAJA/Oz52AUiTL5sJu8/1xW4zoE3XibHrzGh1ZIxT+b15mX79PhyDg4UbO0KOo7jxZhsBB0zY3sJt5/yaL/sxd+sIuW5Y0Lb8SJLowABgLPY6QHau66T8n9ztQXSb7vaBr632v8ZGwDS5qeNoDh5u7Ag5juLaG24EHAAAAANQjid/jnDj0I4WbuwIOY5i1Sw3T/Y/8c9alQAAAHA7pVvoQ4Qbh3b0cCNJypGKo3+fiTkvw1z/JOAAAADov9cxc+PQThJu7Ag5juLl3uxBAQcAAECflaMpbks5nN1VsItTf+MSctx4Cwj3crn7CwEHAABAv739/pdwS7twY1WrgGa5eZXk2ltAuJezdj57kQg4AAAAeqt0bzytXcdIrJM87sP1yaV75Fm6wIWHe50IOAAAAPpMuHEYq3SdG9vKdfypWW6ukjyJkOMQztr57JGAAwAAoL+e1y5gBN41y82TZrnpXZBQukl+SNddwsM8FXAAAAD0l5tT7q9Nd1PKq9qFfEuz3LTNcvM4ho8+1E8CDgAAgB7av/6SO1un0k0p97U3fLR3nSYD4YgKAABATzW1CxioRbpwY3DHPkog8ySOrNxH839qVwAAAMC1HE+5m92RlKvahTxECWYet/PZ2yQva9czJDo4AAAAGIP3Qw83vvImOjnuRMABAADQT2Yx3M3rdj772M5nZ7ULeagyf+WP6OK5EwEHAABAP9m9v7vzJJ/b+exp7ULuq53PfknyMWaw3JmAAwAAoJ90cNxPk+RDmWExGO181rTz2cckr2vXMlDbf9SuAAAAgOu189n/i538h1gledYsN70Oi9r57FF0bTzUQgcHAABAf61qFzBw5+mOrPR2lkU7n71I8jnCjYf6JOAAAADor99qFzACZ0k+liChV9r57DLJZe06RuLKERUAAIAec0zloF41y8272kW081mTLtgY7DDUnlk0y82FDg4AAIB+e1+7gBF5W7omqinhxscINw7pTeIWFQAAgL57l2Rbu4gReVEr5NgbJtrbmSADtGiWm22SOKICAADQc+18dp7uwZjDWeWEN6y4KeUo2iQ/7P4f6uAAAADouWa5WaXr5OBwztMNHz164CDcOJon+wGVgAMAAGAAmuXmVZJF7TpG5lGOHHIIN47mollu1vufcEQFAABgQMr8iBe16xiZdb7qBjgE4cbRXDTLzeLrT+rgAAAAGJBmublI8qp2HSPzKMmHQ/6Ewo2jaJM8vi7cSAQcAAAAg9MsN++SPE43KJPDOD/U7SrlyMuHCDcOaZFuoOj6pi9wRAUAAGDA2vnsRZLn6YZm8nCL0iVzLyXccBXs4SySvNldBfstAg4AAIARaOezsyRPk/w73cO17oH7e1W6ZO6snc8+R7jxENt0nUmfklzdZS6KgAMAAGDEyiyI68KO8/LxX0nOIhT52rWDLL/FANi/2ZYf6yT/3fv7v33dbTo0vkfAAQAAQJI/j1c8Kj9+TBeCnFUsqaY23c0qN858+MsXz2e/JHl9zIJ6bp2u8+L3JOvb/rodkoADAACAG5WjL+dJfkp3BGZKXR5tusGW3zwm0c5nT3PgW1gGYJvkKt1RktWhr9i9DwEHAAAAt9bOZ+fp5ny8yDTCjnWz3Dy+6R9O7DrYdZJf083G2Fau5W8EHAAAANxL6VzYhR1j9q5Zbl59/cmJ3JjSprvJ5Ncax07uQsABAADAg5QH/Zfprqs9q1vN0Txrlpur/U+MfKjoOsn7uw5arUnAAQAAwMG089mLdMM2z+pWcnBtkse7oxnlv/OyZkFHskryplluVpXruDMBBwAAAAc30qBj3Sw3j8vg1c8Z19yNVQYabOwIOAAAADiadj57mS7oGEsY8Cbd3JGxzN1YJ3k15GBjR8ABAADAUZUZHa/TzemgH9p0HRvvahdyKAIOAAAATqJcqXqZ8XQ/DNVVkotmuWlrF3JIAg4AAABOqp3PfknX0cFptelug1nVLuQYBBwAAACcnG6Okxtl18Y+AQcAAABVlNkcb5O8qFzK2L0a06yNmwg4AAAAqKpcKXtZu44R2qY7krKuXcgpCDgAAACorhxZ+ZjxXCdb2zrJkzEfSfmagAMAAIBeaOezsyQfYi7HQy2a5eaidhGnJuAAAACgN8pcjo8RctzXJMONRMABAABAzwg57u2iWW4WtYuo5Z+1CwAAAIB9ZW7EkySLyqUMyaTDjUQHBwAAAD3Wzmefo5PjeyYfbiQ6OAAAAOi3J+luBOF6b4QbHR0cAAAA9JqZHDea7EDR6wg4AAAA6L1yheznJE3lUvriqlluntUuok8cUQEAAKD3muVmm+64Ct2RHZ0bXxFwAAAAMAjNcuPBPmnTDRVtaxfSNwIOAAAABqMM1FxULqOmixL08BUBBwAAAEPzKtO8WeVds9xc1S6irwwZBQAAYHDa+exRuqGjU7FulpvHtYvoMx0cAAAADE45pvGqdh0nNPXZI98l4AAAAGCQmuXmXZJV7TpO4I25G98n4AAAAGDIxt7FsW6Wm19qFzEEAg4AAAAGq3Q2vKldxxGNPcA5GAEHAAAAQ/cuybZ2EUewaJabVe0ihkLAAQAAwKA1y02b8XVxjPG/6agEHAAAAAxes9wskoxpEOf7ZrnZ1i5iSAQcAAAAjMVY5lW06Y7dcAcCDgAAAEahzKtYVS7jEN6XYzfcgYADAACAMXlfu4AH0r1xTwIOAAAARqNZbq4y7BtVFro37kfAAQAAwNgM+faRoXegVCPgAAAAYGyu0h31GJorN6fcn4ADAACAUSlHPK5q13EPv9YuYMgEHAAAAIzR0I56bMv8EO5JwAEAAMDoNMvNOsMaNirceCABBwAAAGM1pC4Ox1MeSMABAADAWA2lK2JbOk54AAEHAAAAo1RuJNlWLuM2hhLE9JqAAwAAgDEbQnjwW+0CxkDAAQAAwJh9ql3Ad7TNcrOqXcQYCDgAAAAYrQFcvbqqXcBYCDgAAAAYu1XtAr7h99oFjIWAAwAAgLHr8zGVVe0CxkLAAQAAwNj19gpW8zcOR8ABAADA2PU14OhrXYMk4AAAAGDUmuVmW7uGG2xrFzAmAg4AAACmYFW7gGsYMHpAAg4AAACmYFu7gGs4onJAAg4AAACm4D+1C7hGW7uAMRFwAAAAMAV9DBN0cByQgAMAAIAp6F2Y0Cw3fQxdBkvAAQAAAKcn3DgwAQcAAABTsK1dwFd611EydAIOAAAARq9Zbra1a+C4BBwAAADA4Ak4AAAAgMETcAAAAACDJ+AAAAAABk/AAQAAwFT06WpWt6gcmIADAACAqehTqPDf2gWMjYADAACAqdjWLmBPn8KWURBwAAAAMBWfahewZ1W7gLERcAAAADAVV7ULKNbNctOneSCjIOAAAABgEkqo0IeQ433tAsZIwAEAAMCU1A4X+hKyjI6AAwAAgMlolptV6s6/eON4ynEIOAAAAJiai0rfd90sN+8qfe/RE3AAAAAwKc1ys03y6sTftk29YGUSBBwAAABMTumkWJzwW75qlpv1Cb/f5PyjdgEAAABQSzufXSZ5ceRvc9EsN4sjf4/J08EBAADAZDXLzUWSY83FaJM8E26chg4OAAAAJq+dz54muUzSHOinXKXr3Nge6OfjOwQcAAAAkKSdz5okL5P8nPsHHdt0V8EuDlQWtyTgAAAAgD0l6HiR5HmSR7f8166S/NosN1fHqotvE3AAAADADUrY8SjJ+TX/eJtk2yw3qxOWBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH9/8BS8cNlOF3xjoAAAAASUVORK5CYII=" - }, - "asset-fdfc9cc7-2c6a-44fe-b9be-c4ff115c92c1": { - "id": "asset-fdfc9cc7-2c6a-44fe-b9be-c4ff115c92c1", - "@created": "2018-09-06T20:18:11.818Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - }, - "asset-58ae3445-4001-45e7-9603-19ec8d41e64e": { - "id": "asset-58ae3445-4001-45e7-9603-19ec8d41e64e", - "@created": "2018-09-06T20:18:30.635Z", - "type": "dataurl", - "value": "data:image/png;base64,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" - } - } - } - } -] diff --git a/x-pack/plugins/canvas/server/sample_data/flights_saved_objects.json b/x-pack/plugins/canvas/server/sample_data/flights_saved_objects.json deleted file mode 100644 index a93d34bce5098..0000000000000 --- a/x-pack/plugins/canvas/server/sample_data/flights_saved_objects.json +++ /dev/null @@ -1,512 +0,0 @@ -[ - { - "id": "workpad-a474e74b-aedc-47c3-894a-db77e62c41e0", - "type": "canvas-workpad", - "updated_at": "2018-10-22T14:17:04.040Z", - "version": 1, - "migrationVersion": { - "canvas-workpad": "7.0.0" - }, - "attributes": { - "name": "[Flights] Overview", - "width": 1280, - "height": 720, - "page": 0, - "pages": [ - { - "id": "page-261eb6da-4ab2-400d-b1be-b72cbbcf58ff", - "style": { "background": "#f4f4f4" }, - "transition": { "name": "" }, - "elements": [ - { - "id": "element-5929e53d-4dad-49a5-a432-8de3b1d05b82", - "position": { - "left": 855.5, - "top": 185.312409153891, - "width": 407, - "height": 140.250363384436, - "angle": 0 - }, - "expression": "\nshape \"square\" fill=\"#FFFFFF\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-60c9ac53-47a7-4ec2-a975-9d10bbe038bb", - "position": { - "left": 855.5, - "top": 26, - "width": 407, - "height": 140.250363384436, - "angle": 0 - }, - "expression": "\nshape \"square\" fill=\"#FFFFFF\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-f573cae3-0d2b-4265-9a6f-314c865c4e5c", - "position": { - "left": 423.5251242870414, - "top": 26, - "width": 407, - "height": 140.250363384436, - "angle": 0 - }, - "expression": "\nshape \"square\" fill=\"#FFFFFF\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-0f5b4a1f-8107-4f84-a12f-755b41dd1ca9", - "position": { - "left": 1035, - "top": 50.5, - "width": 197, - "height": 99, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| essql\nquery=\"SELECT COUNT(DISTINCT OriginAirportID) as total_airports\nFROM kibana_sample_data_flights\"\n| math \"total_airports\"\n| metric \"AIRPORTS\"\nmetricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=60 align=\"right\" color=\"#43988F\" weight=\"normal\" underline=false italic=false}\nlabelFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"right\" color=\"#43988F\" weight=\"normal\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-096136f5-279d-4d29-a784-1bd33243db29", - "position": { - "left": 443.5, - "top": 275.250363384436, - "width": 131, - "height": 33, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| demodata\n| markdown \"### LONGEST FLIGHT\"\nfont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=10 align=\"left\" color=\"#FFFFFF\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-3d1e17df-6310-4968-8323-f0bcabf593e3", - "position": { - "left": 1042.5, - "top": 211.84415880749052, - "width": 191, - "height": 92.812409153891, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| essql\nquery=\"SELECT MAX(DistanceMiles) as max_distance\nFROM kibana_sample_data_flights\nWHERE DistanceMiles > 0\"\n| math \"max_distance\"\n| formatNumber \"00.0a\"\n| metric \"MILES\"\nmetricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=60 align=\"right\" color=\"#EFB341\" weight=\"normal\" underline=false italic=false}\nlabelFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"right\" color=\"#EFB341\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-3604ef7b-8f10-4a5f-a4b9-f123e32960dd", - "position": { - "left": 1036, - "top": -51, - "width": 246, - "height": 50, - "angle": 0 - }, - "expression": "\ntimefilterControl compact=true column=\"timestamp\"\n| render\n", - "filter": "timefilter from=\"now-24h\" to=now column=timestamp" - }, - { - "id": "element-08333e7c-2986-4ee7-b07c-8c07be09c751", - "position": { - "left": -1, - "top": 386.250363384436, - "width": 1283, - "height": 358, - "angle": 0 - }, - "expression": "\nimage mode=\"cover\" dataurl={asset \"asset-2da3aba1-6e0f-4a79-879e-0ab3cfa170d6\"}\n| render\n" - }, - { - "id": "element-90336033-8ca4-4bf5-ad20-94162aec28b6", - "position": { - "left": 26, - "top": 26, - "width": 375.5, - "height": 672.125545076654, - "angle": 0 - }, - "expression": "\nshape \"square\" fill=\"#FFFFFF\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-e0ff80ac-8372-421f-918e-fd9f257b2f32", - "position": { - "left": -27, - "top": -1, - "width": 462, - "height": 699.125545076654, - "angle": 0 - }, - "expression": "\nimage mode=\"contain\" dataurl={asset \"asset-9e41d208-ec45-472d-a118-e2e2c811291b\"}\n| render\n" - }, - { - "id": "element-0d68f8e7-dc04-4358-b459-127c42e274b4", - "position": { - "left": 26, - "top": 145, - "width": 375.5, - "height": 153.375181692218, - "angle": 0 - }, - "expression": "\nshape \"circle\" fill=\"rgba(255,255,255,0)\" border=\"#48A8E0\" borderWidth=2 maintainAspect=true\n| render\n" - }, - { - "id": "element-f56821a4-4fd8-4de1-8bb7-6722c9ee5334", - "position": { - "left": 26, - "top": 56, - "width": 375.5, - "height": 44, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| demodata\n| markdown \"TIME IN AIR\"\nfont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=36 align=\"center\" color=\"#48A8E0\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-210b8adc-c5fa-412b-b280-146863fc9230", - "position": { - "left": 26, - "top": 330.562772538327, - "width": 375.5, - "height": 153.375181692218, - "angle": 0 - }, - "expression": "\nshape \"circle\" fill=\"rgba(255,255,255,0)\" border=\"#48A8E0\" borderWidth=2 maintainAspect=true\n| render\n", - "filter": null - }, - { - "id": "element-002f28e5-a132-4cbb-b1cb-f13f1cdeaac2", - "position": { - "left": 26, - "top": 509.562772538327, - "width": 375.5, - "height": 153.375181692218, - "angle": 0 - }, - "expression": "\nshape \"circle\" fill=\"rgba(255,255,255,0)\" border=\"#48A8E0\" borderWidth=2 maintainAspect=true\n| render\n", - "filter": null - }, - { - "id": "element-8a1248fa-2c2e-4be4-9e2b-95198279144d", - "position": { - "left": 26, - "top": 366.062772538327, - "width": 375.5, - "height": 65, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| essql\nquery=\"SELECT FLOOR((SUM(FlightTimeMin) % 1440) / 60) as total_hours\nFROM kibana_sample_data_flights\"\n| math \"total_hours\"\n| formatNumber \"00\"\n| metric\nmetricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"center\" color=\"#48A8E0\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-2b890a9d-2f4d-4c4d-8275-ac371190d486", - "position": { - "left": 173.25, - "top": 232.000363384436, - "width": 81, - "height": 39, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| demodata\n| markdown \"DAYS\"\nfont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"center\" color=\"#48A8E0\" weight=\"normal\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-b253908c-b8bd-4ea1-a35f-eae5eb1ae63a", - "position": { - "left": 26, - "top": 179.750363384436, - "width": 375.5, - "height": 65, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| essql\nquery=\"SELECT FLOOR(SUM(FlightTimeMin)/1440) as total_days\nFROM kibana_sample_data_flights\"\n| math \"total_days\"\n| formatNumber \"00a\"\n| metric\nmetricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"center\" color=\"#48A8E0\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-9fb07d44-c181-4d03-a431-492d1977a79c", - "position": { - "left": 26, - "top": 550.750363384436, - "width": 375.5, - "height": 54, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| essql\nquery=\"SELECT ((SUM(FlightTimeMin) % 1440) / 60 ) as total_minutes\nFROM kibana_sample_data_flights\"\n| math \"total_minutes\"\n| formatNumber \"00\"\n| metric\nmetricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"center\" color=\"#48A8E0\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-60733afe-abce-4449-b0dd-5310d8ffffce", - "position": { - "left": 163.75, - "top": 416.9379542305451, - "width": 100, - "height": 39, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| demodata\n| markdown \"HOURS\"\nfont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"center\" color=\"#48A8E0\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-b7f3b9e3-2cb2-49e7-8768-b41afe0b49b1", - "position": { - "left": 173.25, - "top": 599.750363384436, - "width": 81, - "height": 39, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| demodata\n| markdown \"MINS\"\nfont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"center\" color=\"#48A8E0\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-526d29d1-8d5e-4c15-a5c2-fa23edf580ac", - "position": { - "left": 423.5251242870414, - "top": 185.312409153891, - "width": 407, - "height": 140.250363384436, - "angle": 0 - }, - "expression": "\nshape \"square\" fill=\"#FFFFFF\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-1d11f5a4-95a3-4a50-9191-6beb61bb8fbc", - "position": { - "left": 855.5, - "top": 343.687590846109, - "width": 407, - "height": 140.250363384436, - "angle": 0 - }, - "expression": "\nshape \"square\" fill=\"#FFFFFF\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-cfe6524e-b201-439a-974c-037406b760f6", - "position": { - "left": 616.5251242870414, - "top": 50.5, - "width": 187, - "height": 99, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| essql query=\"SELECT COUNT(*) as total_flights\nFROM kibana_sample_data_flights\"\n| math \"total_flights\"\n| formatNumber \"0a]\"\n| metric \"FLIGHTS\"\nmetricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=60 align=\"right\" color=\"#4184A5\" weight=\"normal\" underline=false italic=false}\nlabelFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"right\" color=\"#4184A5\" weight=\"normal\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-e162c0b4-9393-43f9-8324-0263f40b4b85", - "position": { - "left": 439.52512428704136, - "top": 40.687590846109, - "width": 78.47487571295858, - "height": 59.312409153891, - "angle": 0 - }, - "expression": "\nimage mode=\"contain\" dataurl={asset \"asset-520a03a1-f522-4a18-ad4a-b84e87e4dc44\"}\n| render\n" - }, - { - "id": "element-0c37705e-004f-49c6-abda-9847b762c9f2", - "position": { - "left": 603.5251242870414, - "top": 211.84415880749054, - "width": 200, - "height": 100, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| essql\nquery=\"SELECT MIN(DistanceMiles) as min_distance\nFROM kibana_sample_data_flights\nWHERE DistanceMiles > 0\"\n| math \"min_distance\"\n| formatNumber \"00.0a\"\n| metric \"MILES\"\nmetricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=60 align=\"right\" color=\"#7EA030\" weight=\"normal\" underline=false italic=false}\nlabelFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"right\" color=\"#7EA030\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-dd0f8a2e-1142-4140-bedb-913cae044204", - "position": { - "left": 439.52512428704136, - "top": 205.68795423054502, - "width": 78.47487571295858, - "height": 45.812409153891, - "angle": 0 - }, - "expression": "\nimage mode=\"contain\" dataurl={asset \"asset-08aa2e8f-6c3b-428f-82de-581004292cf0\"}\n| render\n" - }, - { - "id": "element-a81c83c7-8b61-4a1f-8da5-3270821c0089", - "position": { - "left": 435, - "top": 267.875181692218, - "width": 237, - "height": 30.5, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| demodata\n| markdown \"SHORTEST FLIGHT\"\nfont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"left\" color=\"#7EA030\" weight=\"normal\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-79393fba-8da9-4884-a280-e2a87e163f1a", - "position": { - "left": 870.7876864305622, - "top": 40.687590846109, - "width": 78.47487571295858, - "height": 59.312409153891, - "angle": 0 - }, - "expression": "\nimage mode=\"contain\" dataurl={asset \"asset-11a8022c-c1ac-4bbd-857a-db95fb8ca452\"}\n| render\n" - }, - { - "id": "element-ec914936-fc84-4915-82f7-1ca6b37ddc03", - "position": { - "left": 870.7876864305622, - "top": 262.500363384436, - "width": 237, - "height": 30.5, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| demodata\n| markdown \"LONGEST FLIGHT\"\nfont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"left\" color=\"#EFB341\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-8aae2d27-7a8c-4851-9b9c-a66e5b1dda9f", - "position": { - "left": 870.7876864305622, - "top": 198.93795423054502, - "width": 78.47487571295858, - "height": 59.312409153891, - "angle": 0 - }, - "expression": "\nimage mode=\"contain\" dataurl={asset \"asset-e73f53c5-fdcc-4232-bd6f-85a06281cf6c\"}\n| render\n", - "filter": null - }, - { - "id": "element-bca09809-6f73-4363-9732-5c86bb28f2f9", - "position": { - "left": 423.5251242870414, - "top": 343.687590846109, - "width": 407, - "height": 140.250363384436, - "angle": 0 - }, - "expression": "\nshape \"square\" fill=\"#FFFFFF\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-b6e7d5e1-3221-4274-ac97-5e0387d090c0", - "position": { - "left": 1033.5, - "top": 365.46897711527254, - "width": 200, - "height": 96.687590846109, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| essql\nquery=\"SELECT COUNT(*) as total_cancellations\nFROM kibana_sample_data_flights\nWHERE Cancelled = true\"\n| math \"total_cancellations\"\n| formatNumber \"0a\"\n| metric \"CANCELLATIONS\"\nmetricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=60 align=\"right\" color=\"#D88734\" weight=\"normal\" underline=false italic=false}\nlabelFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"right\" color=\"#D88734\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-7ac04e37-e7aa-42cf-9afe-314ebd6de9d6", - "position": { - "left": 870.7876864305622, - "top": 364.4379542305451, - "width": 78.47487571295858, - "height": 59.312409153891, - "angle": 0 - }, - "expression": "\nimage mode=\"contain\" dataurl={asset \"asset-63a49130-fb96-4576-ac31-d86c934234d1\"}\n| render\n", - "filter": null - }, - { - "id": "element-0cf4194e-d460-40a1-a023-775f1946eb16", - "position": { - "left": 600.5251242870414, - "top": 364.4379542305451, - "width": 206, - "height": 105, - "angle": 0 - }, - "expression": "\nkibana\n| selectFilter\n| essql\nquery=\"SELECT COUNT(DISTINCT OriginCountry) as total_countries\nFROM kibana_sample_data_flights\"\n| math \"total_countries\"\n| metric \"COUNTRIES\"\nmetricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=60 align=\"right\" color=\"#CB3072\" weight=\"normal\" underline=false italic=false}\nlabelFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=24 align=\"right\" color=\"#CB3072\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-41734b58-e7aa-4888-980c-677420b1c736", - "position": { - "left": 439.52512428704136, - "top": 362.06277253832695, - "width": 78.47487571295858, - "height": 59.312409153891, - "angle": 0 - }, - "expression": "\nimage mode=\"contain\" dataurl={asset \"asset-4843e3bb-6cb0-43b7-b076-deea9a901fc6\"}\n| render\n", - "filter": null - } - ] - } - ], - "colors": [ - "#37988d", - "#c19628", - "#b83c6f", - "#3f9939", - "#1785b0", - "#ca5f35", - "#45bdb0", - "#f2bc33", - "#e74b8b", - "#4fbf48", - "#1ea6dc", - "#fd7643", - "#72cec3", - "#f5cc5d", - "#ec77a8", - "#7acf74", - "#4cbce4", - "#fd986f", - "#a1ded7", - "#f8dd91", - "#f2a4c5", - "#a6dfa2", - "#86d2ed", - "#fdba9f", - "#000000", - "#444444", - "#777777", - "#BBBBBB", - "rgba(255,255,255,0)" - ], - "@timestamp": "2018-10-31T17:32:39.068Z", - "@created": "2018-10-31T17:25:59.027Z", - "assets": { - "asset-2da3aba1-6e0f-4a79-879e-0ab3cfa170d6": { - "id": "asset-2da3aba1-6e0f-4a79-879e-0ab3cfa170d6", - "@created": "2018-10-13T16:17:38.860Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTUyNC4wOCAzNTUuMTkiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO30uY2xzLTJ7Y2xpcC1wYXRoOnVybCgjY2xpcC1wYXRoKTt9LmNscy0xMCwuY2xzLTMsLmNscy00LC5jbHMtNSwuY2xzLTYsLmNscy03e3N0cm9rZTojYWRlZmZmO30uY2xzLTEwLC5jbHMtMywuY2xzLTQsLmNscy01LC5jbHMtNiwuY2xzLTcsLmNscy04LC5jbHMtOXtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9LmNscy0ze2ZpbGw6dXJsKCNsaW5lYXItZ3JhZGllbnQpO30uY2xzLTR7ZmlsbDp1cmwoI2xpbmVhci1ncmFkaWVudC0yKTt9LmNscy01e2ZpbGw6dXJsKCNsaW5lYXItZ3JhZGllbnQtMyk7fS5jbHMtNntmaWxsOiMzMWM4ZmE7fS5jbHMtNywuY2xzLTl7ZmlsbDojMDBhOWU1O30uY2xzLTEwLC5jbHMtOHtmaWxsOiNmZmY7fS5jbHMtOCwuY2xzLTl7c3Ryb2tlOiMzMWM4ZmE7fTwvc3R5bGU+PGNsaXBQYXRoIGlkPSJjbGlwLXBhdGgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTI2NC43KSI+PHJlY3QgY2xhc3M9ImNscy0xIiB4PSIxMjEuODciIHdpZHRoPSIxMzIyLjc4IiBoZWlnaHQ9IjU5NS45Ii8+PC9jbGlwUGF0aD48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhci1ncmFkaWVudCIgeDE9IjcyNS43MSIgeTE9IjExMS42NSIgeDI9IjcyNS43MSIgeTI9IjQ3OS4xMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2FkZWZmZiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzMxYzhmYSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtMiIgeDE9Ijc2Mi4wNCIgeTE9IjMwMy43NyIgeDI9Ijc2Mi4wNCIgeTI9IjkwNS4zMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzMxYzhmYSIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwNzhhMCIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtMyIgeDE9IjkzNS4zIiB5MT0iMzA0LjUiIHgyPSI5MzUuMyIgeTI9IjU3OS42NiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2FkZWZmZiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwYTllNSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjx0aXRsZT5BaXJwb3J0IElsbHVzdHJhdGlvbjwvdGl0bGU+PGcgaWQ9IkxheWVyXzIiIGRhdGEtbmFtZT0iTGF5ZXIgMiI+PGcgaWQ9IkxheWVyXzQiIGRhdGEtbmFtZT0iTGF5ZXIgNCI+PGcgY2xhc3M9ImNscy0yIj48cmVjdCBjbGFzcz0iY2xzLTMiIHg9IjMuMzciIHk9IjE2NS40OSIgd2lkdGg9IjE0NDQuNjkiIGhlaWdodD0iMTg5LjIiLz48cGF0aCBjbGFzcz0iY2xzLTQiIGQ9Ik0xLjA5LDM4NnM3Ny44OS04MS42NSw5NS4wNi03Niw0NC44OSw5LDcwLDEzLjk0LDM4LjI5LDE2LjQxLDU2Ljc4LDE3LjI3LDIzLjc3LTM2Ljg0LDYyLjA2LTMxLjIxLDU2Ljc4LTEuODIsOTEuMTEtLjU3LDU5LjQyLDI0LjM4LDEwNS42NCwyNC4zOFM2MjMsMjk3LjM5LDY3MS44NiwyOTcuMzlzMTgzLjU0LDM0LjcsMjA3LjMxLDM0LjcsNDMuNzktNDQuNjIsNjIuMTctNDQuNjJTOTg4LjQ2LDMwNCwxMDAyLjQ3LDMwNHMxMDMuNDEtMzUuNDEsMTIzLjQyLTM3LjU0LDU2LjEzLTEuMTcsODYuOTIsMCw0MCwyMSw2My44MSwxOS4zNiw0Mi4zMi0xMiw2My40MS0xMS43NywxMjQuMDktMi44MywxNDYuNTQtMy44LDM3LDE4Ljg3LDM3LDE4Ljg3VjUxNlMxMzQuNDQsNDkyLjQyLDk4Ljc5LDUwNHMtNjMuMzgsNy40Mi03Ny45MSwxMlMuNSw1MjAuNTEuNSw1MjAuNTFaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIC0yNjQuNykiLz48cGF0aCBjbGFzcz0iY2xzLTUiIGQ9Ik02MjcuMDcsNDQ4LjE1bDMyLjEsODMuNDVoNTUwLjQ4bDMxLjMtNzMsNy42LThjLTM3LjE3LTEzLjgtNzUuNCw0LjI1LTEzNC44NiwxNC44N1M5OTUuODIsNDA4LjEyLDkwNC41LDM5NC4zMXMtMTU2LjA5LDMyLjkyLTIwMS43NSw0My41NC04MC43LDAtODAuNywwWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMjY0LjcpIi8+PHBvbHlnb24gY2xhc3M9ImNscy02IiBwb2ludHM9IjUxOS41NyAyNTcuMDEgNDM0LjU3IDI1Ny4wMSA0MzQuNTcgMTQxLjk4IDUxOS41NyAxMzguNjYgNTE5LjU3IDI1Ny4wMSIvPjxwb2x5Z29uIGNsYXNzPSJjbHMtNyIgcG9pbnRzPSI1MTkuNTcgMjU3LjAxIDYzOS4yNSAyNTcuMDEgNjM5LjI1IDE0MS45OCA1MTkuNTcgMTM4LjY2IDUxOS41NyAyNTcuMDEiLz48cG9seWdvbiBjbGFzcz0iY2xzLTYiIHBvaW50cz0iMTQzMy41OSAxMTIuOTUgMTQwOC4zNSAxMTIuOTUgMTQwMy42NiA4OC40MyAxNDMzLjU5IDg1Ljk4IDE0MzMuNTkgMTEyLjk1Ii8+PHBvbHlnb24gY2xhc3M9ImNscy03IiBwb2ludHM9IjE0MzMuNTkgMTEyLjk1IDE0NDMuNDcgMTEyLjk1IDE0NDguMDYgODguNDMgMTQzMy41OSA4NS45OCAxNDMzLjU5IDExMi45NSIvPjxwb2x5Z29uIGNsYXNzPSJjbHMtNiIgcG9pbnRzPSIxMzk2Ljk1IDI3NS44MyAxMjI3LjY3IDI3NS44MyAxMjI3LjY3IDE2MC4wMiAxMzk2Ljk1IDE1NS40MiAxMzk2Ljk1IDI3NS44MyIvPjxwb2x5Z29uIGNsYXNzPSJjbHMtNyIgcG9pbnRzPSIxMzk3LjIgMjc1LjgzIDE0MTYuNCAyNzUuODMgMTQxNi40IDE2MC4wMiAxMzk3LjIgMTU1LjQyIDEzOTcuMiAyNzUuODMiLz48cG9seWdvbiBjbGFzcz0iY2xzLTciIHBvaW50cz0iMTQzNC42OCAyODIuNDIgMTQxMS45NiAyODIuNDIgMTQxMS45NiAxMzEuNDYgMTQzNC42OCAxMzAuNjIgMTQzNC42OCAyODIuNDIiLz48cG9seWdvbiBjbGFzcz0iY2xzLTciIHBvaW50cz0iMTQ0Ny44NyAyNzkuNzUgMTQzMy44NSAyODIuNDIgMTQzMy44NSAxMzAuNiAxNDQ3Ljg3IDEzMS40NiAxNDQ3Ljg3IDI3OS43NSIvPjxwb2x5Z29uIGNsYXNzPSJjbHMtNiIgcG9pbnRzPSIxNDMzLjg1IDEzOC40MyAxMzk4Ljk1IDEzOS4yNSAxMzk4Ljk1IDEwOC44OSAxNDMzLjg1IDEwOC4wNyAxNDMzLjg1IDEzOC40MyIvPjxwb2x5Z29uIGNsYXNzPSJjbHMtNyIgcG9pbnRzPSIxNDUzLjc4IDEzOC45NiAxNDMzLjg1IDEzOC4yNSAxNDMzLjg1IDEwOC4wNyAxNDUzLjc4IDEwOC42MiAxNDUzLjc4IDEzOC45NiIvPjxwb2x5Z29uIGNsYXNzPSJjbHMtNiIgcG9pbnRzPSIxMzc2LjcxIDI4Mi40MiAxMjEzLjA5IDI4Mi40MiAxMjEzLjA5IDE5MC42OSAxMzc2LjcxIDE4OC4wNSAxMzc2LjcxIDI4Mi40MiIvPjxwb2x5Z29uIGNsYXNzPSJjbHMtNyIgcG9pbnRzPSIxMzc2LjcxIDI4Mi40MiAxMzg5Ljg2IDI3OS41MiAxMzg5Ljg2IDE4Ny43OSAxMzc2LjcxIDE4OC4wNSAxMzc2LjcxIDI4Mi40MiIvPjxlbGxpcHNlIGNsYXNzPSJjbHMtNyIgY3g9IjEyNDEuMjQiIGN5PSIxNTAuMjciIHJ4PSI5LjczIiByeT0iOS40NiIvPjxwYXRoIGNsYXNzPSJjbHMtNiIgZD0iTTYzMC41MSw1NDQuMjZINDI4LjE3VjQ3MEg2MzYuNmMyMC41MSwwLDk3LjQxLDI2Ljc5LDg5LjUsNTAuNTNTNjMwLjUxLDU0NC4yNiw2MzAuNTEsNTQ0LjI2WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMjY0LjcpIi8+PGxpbmUgY2xhc3M9ImNscy04IiB4MT0iNjQyLjA4IiB5MT0iMjg2LjM1IiB4Mj0iNjQyLjA4IiB5Mj0iMzAzLjg0Ii8+PHJlY3QgY2xhc3M9ImNscy03IiB4PSI2MzQuNzciIHk9IjI2OC42IiB3aWR0aD0iMTQuNjEiIGhlaWdodD0iMjAuNyIgcng9IjQuMTMiIHJ5PSI0LjEzIi8+PGNpcmNsZSBjbGFzcz0iY2xzLTkiIGN4PSI2NDEuNDkiIGN5PSIzMTIuODgiIHI9IjEyLjUyIi8+PHBhdGggY2xhc3M9ImNscy03IiBkPSJNNDYwLjQ2LDU1My4yOGw1NS4zMywxM2MzLjI5Ljc4LDYuMzgtMi4xLDYuMzgtNS45NFY1MzJjMC0zLjc0LTIuOTQtNi42LTYuMTgtNmwtNTUuMjQsMTAuNGMtMy41NC42Ny02LjE4LDQuMTEtNi4yOSw4LjJoMEM0NTQuMzUsNTQ4Ljc4LDQ1Ni44OCw1NTIuNDQsNDYwLjQ2LDU1My4yOFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTI2NC43KSIvPjxyZWN0IGNsYXNzPSJjbHMtNyIgeD0iNDIwLjQyIiB5PSIyNTAuNjkiIHdpZHRoPSI5MC4xOCIgaGVpZ2h0PSIxMi43OCIgcng9IjMuNjEiIHJ5PSIzLjYxIi8+PGxpbmUgY2xhc3M9ImNscy0xMCIgeDE9IjQ0OS41MSIgeTE9IjI2My40NyIgeDI9IjQ1OC4zMSIgeTI9IjI3Mi42OCIvPjxwYXRoIGNsYXNzPSJjbHMtNyIgZD0iTTcwNy40OCw0OTQuNzdoLTI1LjdBMjYuNTIsMjYuNTIsMCwwLDEsNjY2LDQ4OS41NGwtOC4yMy02LjExYTEuNzcsMS43NywwLDAsMSwxLTMuMTloMTguNjZTNzA5LjM3LDQ5NC43Nyw3MDcuNDgsNDk0Ljc3WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMjY0LjcpIi8+PHJlY3QgY2xhc3M9ImNscy02IiB4PSI0NDEuMTIiIHk9IjIyNC41NCIgd2lkdGg9IjguMDciIGhlaWdodD0iMTIuNDEiIHJ4PSIzLjciIHJ5PSIzLjciLz48cmVjdCBjbGFzcz0iY2xzLTYiIHg9IjQ1OC42NiIgeT0iMjI0LjU0IiB3aWR0aD0iOC4wNyIgaGVpZ2h0PSIxMi40MSIgcng9IjMuNyIgcnk9IjMuNyIvPjxyZWN0IGNsYXNzPSJjbHMtNiIgeD0iNDc2LjIxIiB5PSIyMjQuNTQiIHdpZHRoPSI4LjA3IiBoZWlnaHQ9IjEyLjQxIiByeD0iMy43IiByeT0iMy43Ii8+PHJlY3QgY2xhc3M9ImNscy02IiB4PSI0OTMuNzUiIHk9IjIyNC41NCIgd2lkdGg9IjguMDciIGhlaWdodD0iMTIuNDEiIHJ4PSIzLjciIHJ5PSIzLjciLz48cmVjdCBjbGFzcz0iY2xzLTYiIHg9IjUxMS4yOSIgeT0iMjI0LjU0IiB3aWR0aD0iOC4wNyIgaGVpZ2h0PSIxMi40MSIgcng9IjMuNyIgcnk9IjMuNyIvPjxyZWN0IGNsYXNzPSJjbHMtNiIgeD0iNTI4Ljg0IiB5PSIyMjQuNTQiIHdpZHRoPSI4LjA3IiBoZWlnaHQ9IjEyLjQxIiByeD0iMy43IiByeT0iMy43Ii8+PHJlY3QgY2xhc3M9ImNscy02IiB4PSI1NDYuMzgiIHk9IjIyNC41NCIgd2lkdGg9IjguMDciIGhlaWdodD0iMTIuNDEiIHJ4PSIzLjciIHJ5PSIzLjciLz48cmVjdCBjbGFzcz0iY2xzLTYiIHg9IjU2My45MyIgeT0iMjI0LjU0IiB3aWR0aD0iOC4wNyIgaGVpZ2h0PSIxMi40MSIgcng9IjMuNyIgcnk9IjMuNyIvPjxyZWN0IGNsYXNzPSJjbHMtNiIgeD0iNTgxLjQ3IiB5PSIyMjQuNTQiIHdpZHRoPSI4LjA3IiBoZWlnaHQ9IjEyLjQxIiByeD0iMy43IiByeT0iMy43Ii8+PHJlY3QgY2xhc3M9ImNscy02IiB4PSI1OTkuMDIiIHk9IjIyNC41NCIgd2lkdGg9IjguMDciIGhlaWdodD0iMTIuNDEiIHJ4PSIzLjciIHJ5PSIzLjciLz48cmVjdCBjbGFzcz0iY2xzLTYiIHg9IjYxOS4zNSIgeT0iMjI0LjU0IiB3aWR0aD0iMTcuNDgiIGhlaWdodD0iMjYuNDQiLz48Y2lyY2xlIGNsYXNzPSJjbHMtNyIgY3g9IjEyMjUuNDYiIGN5PSIyODYuMjQiIHI9IjEzLjY5Ii8+PHBhdGggY2xhc3M9ImNscy03IiBkPSJNMTM1Mi4yOSw1NTEuODJIMTE3Ni45MVY1MjIuNjhsMTY5LjI3LDE4LjJhNi44NCw2Ljg0LDAsMCwxLDYuMTEsNi44WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMjY0LjcpIi8+PGNpcmNsZSBjbGFzcz0iY2xzLTciIGN4PSIxMTAwLjE3IiBjeT0iMjg2LjI0IiByPSIxMy42OSIvPjxwYXRoIGNsYXNzPSJjbHMtNyIgZD0iTTk3My4zNCw1NTEuODJoMTc1LjM4VjUyMi42OGwtMTY5LjI3LDE4LjJhNi44NCw2Ljg0LDAsMCwwLTYuMTEsNi44WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMjY0LjcpIi8+PHJlY3QgY2xhc3M9ImNscy02IiB4PSIxMTU5LjQ0IiB5PSIyMDguNTYiIHdpZHRoPSIxMy4wNyIgaGVpZ2h0PSI1NC41NSIgcng9IjEuOTEiIHJ5PSIxLjkxIi8+PGNpcmNsZSBjbGFzcz0iY2xzLTYiIGN4PSIxMTY1LjY5IiBjeT0iMjY3LjU0IiByPSIzMi4zOSIvPjxyZWN0IGNsYXNzPSJjbHMtNyIgeD0iMTEyNC44MiIgeT0iMjk5LjkyIiB3aWR0aD0iMTIuMjQiIGhlaWdodD0iMjEuMTkiIHJ4PSIxLjc5IiByeT0iMS43OSIvPjxsaW5lIGNsYXNzPSJjbHMtMTAiIHgxPSIxMTMwLjk0IiB5MT0iMjg3LjEyIiB4Mj0iMTEzMC45NCIgeTI9IjI5OS45MiIvPjxyZWN0IGNsYXNzPSJjbHMtNyIgeD0iMTE1OS44NSIgeT0iMzEyLjczIiB3aWR0aD0iMTIuMjQiIGhlaWdodD0iMjEuMTkiIHJ4PSIxLjc5IiByeT0iMS43OSIvPjxsaW5lIGNsYXNzPSJjbHMtMTAiIHgxPSIxMTY1Ljk3IiB5MT0iMjk5LjkyIiB4Mj0iMTE2NS45NyIgeTI9IjMxMi43MyIvPjxyZWN0IGNsYXNzPSJjbHMtNyIgeD0iMTE5OC4wOCIgeT0iMjk5LjE5IiB3aWR0aD0iMTIuMjQiIGhlaWdodD0iMjEuMTkiIHJ4PSIxLjc5IiByeT0iMS43OSIvPjxsaW5lIGNsYXNzPSJjbHMtMTAiIHgxPSIxMjA0LjIiIHkxPSIyODYuMzkiIHgyPSIxMjA0LjIiIHkyPSIyOTkuMTkiLz48Y2lyY2xlIGNsYXNzPSJjbHMtNyIgY3g9IjExNjUuNjkiIGN5PSIyNzYuODkiIHI9IjkuMzUiLz48cGF0aCBjbGFzcz0iY2xzLTciIGQ9Ik0xMTg1LDUyNi42M2gtMzguNWExLjc5LDEuNzksMCwwLDEtMS42Mi0yLjU1bDQtOC40MWExLjc4LDEuNzgsMCwwLDEsMS42Mi0xaDMxLjE2YTEuOCwxLjgsMCwwLDEsMS42NywxLjEzbDMuMzYsOC40MUExLjc5LDEuNzksMCwwLDEsMTE4NSw1MjYuNjNaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIC0yNjQuNykiLz48L2c+PC9nPjwvZz48L3N2Zz4=" - }, - "asset-9e41d208-ec45-472d-a118-e2e2c811291b": { - "id": "asset-9e41d208-ec45-472d-a118-e2e2c811291b", - "@created": "2018-10-13T16:33:38.197Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNDU5LjQ0IDI5NS45NSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOm5vbmU7fS5jbHMtMntjbGlwLXBhdGg6dXJsKCNjbGlwLXBhdGgpO30uY2xzLTN7b3BhY2l0eTowLjQ7fS5jbHMtNHtmaWxsOiNhZGVmZmY7fTwvc3R5bGU+PGNsaXBQYXRoIGlkPSJjbGlwLXBhdGgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTUzKSI+PHJlY3QgY2xhc3M9ImNscy0xIiB4PSIyOC4yIiB3aWR0aD0iNDY0LjQ5IiBoZWlnaHQ9IjM4OC4yNiIvPjwvY2xpcFBhdGg+PC9kZWZzPjx0aXRsZT5DbG91ZHM8L3RpdGxlPjxnIGlkPSJMYXllcl8yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxnIGlkPSJMYXllcl8xLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMSI+PGcgY2xhc3M9ImNscy0yIj48ZyBjbGFzcz0iY2xzLTMiPjxwYXRoIGNsYXNzPSJjbHMtNCIgZD0iTTE3NS42NSwzMzUuN2ExNiwxNiwwLDAsMC02LDEuMTUsMjIuMSwyMi4xLDAsMCwwLTM2LjE3LTYuNiwzNC44NywzNC44NywwLDEsMC02OS40NCw2LjM1QTE2LDE2LDAsMCwwLDQzLDM0OUgxOTEuNDRBMTYsMTYsMCwwLDAsMTc1LjY1LDMzNS43WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtNTMpIi8+PC9nPjxnIGNsYXNzPSJjbHMtMyI+PHBhdGggY2xhc3M9ImNscy00IiBkPSJNMzM2LDE2N2ExMi4zNCwxMi4zNCwwLDAsMSw0LjU2Ljg4LDE2Ljg4LDE2Ljg4LDAsMCwxLDI3LjYxLTUsMjYuNjEsMjYuNjEsMCwwLDEsNDkuNjktMTEuMDksMjAuMzEsMjAuMzEsMCwwLDEsNC4xNi0uNDMsMjAuMDgsMjAuMDgsMCwwLDEsMTkuODMsMTYuOTMsMTIuMjUsMTIuMjUsMCwwLDEsMTcuNjIsMTAuMzlIMzIzLjc1QTEyLjIzLDEyLjIzLDAsMCwxLDMzNiwxNjdaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIC01MykiLz48L2c+PGcgY2xhc3M9ImNscy0zIj48cGF0aCBjbGFzcz0iY2xzLTQiIGQ9Ik0xNDAuNjQsOTMuNDVhMTMuNzYsMTMuNzYsMCwwLDAtNS4xMSwxLDE5LDE5LDAsMCwwLTE0LjE5LTExLjEzLDMzLjk0LDMzLjk0LDAsMCwwLTY3LjY4LDMuNjNjMCwuNDUsMCwuODksMCwxLjMzYTE4LjkyLDE4LjkyLDAsMCwwLTMxLjI1LDguNSwxMy43LDEzLjcsMCwwLDAtMjIuNDQsOEgxNTQuMTRBMTMuNzIsMTMuNzIsMCwwLDAsMTQwLjY0LDkzLjQ1WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtNTMpIi8+PC9nPjwvZz48L2c+PC9nPjwvc3ZnPg==" - }, - "asset-520a03a1-f522-4a18-ad4a-b84e87e4dc44": { - "id": "asset-520a03a1-f522-4a18-ad4a-b84e87e4dc44", - "@created": "2018-10-13T16:39:42.089Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1Ni4zMSA1Ni4zMSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiNmZmY7c3Ryb2tlOiMwMDc4YTA7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjJweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPlBsYW5lIEljb248L3RpdGxlPjxnIGlkPSJMYXllcl8yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxnIGlkPSJMYXllcl8xLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMSI+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNDkuNTEsNDguOTMsNDEuMjYsMjIuNTIsNTMuNzYsMTBhNS4yOSw1LjI5LDAsMCwwLTcuNDgtNy40N2wtMTIuNSwxMi41TDcuMzgsNi43OUEuNy43LDAsMCwwLDYuNjksN0wxLjIsMTIuNDVhLjcuNywwLDAsMCwwLDFMMTkuODUsMjlsLTcuMjQsNy4yNC03Ljc0LS42YS43MS43MSwwLDAsMC0uNTMuMkwxLjIxLDM5YS42Ny42NywwLDAsMCwuMDgsMUw5LjQ1LDQ2bC4wNywwYy4xMS4xMy4yMi4yNi4zNC4zOHMuMjUuMjMuMzguMzRhLjM2LjM2LDAsMCwwLDAsLjA3TDE2LjMzLDU1YS42OC42OCwwLDAsMCwxLC4wN0wyMC40OSw1MmEuNjcuNjcsMCwwLDAsLjE5LS41NGwtLjU5LTcuNzQsNy4yNC03LjI0TDQyLjg1LDU1LjA2YS42OC42OCwwLDAsMCwxLDBsNS41LTUuNUEuNjYuNjYsMCwwLDAsNDkuNTEsNDguOTNaIi8+PC9nPjwvZz48L3N2Zz4=" - }, - "asset-08aa2e8f-6c3b-428f-82de-581004292cf0": { - "id": "asset-08aa2e8f-6c3b-428f-82de-581004292cf0", - "@created": "2018-10-13T16:42:03.959Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MC44MyAyMi4zNiI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOm5vbmU7c3Ryb2tlOiM3NGEzMDA7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjJweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPlNob3J0IGxlbmd0aCBJY29uPC90aXRsZT48ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIj48ZyBpZD0iTGF5ZXJfMS0yIiBkYXRhLW5hbWU9IkxheWVyIDEiPjxsaW5lIGNsYXNzPSJjbHMtMSIgeDE9IjEiIHgyPSIxIiB5Mj0iMjIuMzYiLz48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSI0OS44MyIgeDI9IjQ5LjgzIiB5Mj0iMjIuMzYiLz48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSI1LjY5IiB5MT0iMTEuMTgiIHgyPSIxMC4xNSIgeTI9IjExLjE4Ii8+PGxpbmUgY2xhc3M9ImNscy0xIiB4MT0iMTcuMTciIHkxPSIxMS4xOCIgeDI9IjIxLjYzIiB5Mj0iMTEuMTgiLz48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSIyOC42NSIgeTE9IjExLjE4IiB4Mj0iMzMuMTEiIHkyPSIxMS4xOCIvPjxsaW5lIGNsYXNzPSJjbHMtMSIgeDE9IjQwLjEzIiB5MT0iMTEuMTgiIHgyPSI0NC41OSIgeTI9IjExLjE4Ii8+PC9nPjwvZz48L3N2Zz4=" - }, - "asset-11a8022c-c1ac-4bbd-857a-db95fb8ca452": { - "id": "asset-11a8022c-c1ac-4bbd-857a-db95fb8ca452", - "@created": "2018-10-13T16:44:44.648Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzOC4zOSA1Ny41NyI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiNmZmY7c3Ryb2tlOiMwMTliOGY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjJweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPkxvY2F0aW9uIEljb248L3RpdGxlPjxnIGlkPSJMYXllcl8yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxnIGlkPSJMYXllcl8xLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMSI+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMTkuMTksMUExOC4xOSwxOC4xOSwwLDAsMCwyLjk0LDI3LjM2aDBhMTkuNTEsMTkuNTEsMCwwLDAsMSwxLjc4TDE5LjE5LDU1LjU3LDM0LjM4LDI5LjIxQTE4LjE5LDE4LjE5LDAsMCwwLDE5LjE5LDFabTAsMjMuMjlhNS41Myw1LjUzLDAsMSwxLDUuNTMtNS41M0E1LjUzLDUuNTMsMCwwLDEsMTkuMTksMjQuMjlaIi8+PC9nPjwvZz48L3N2Zz4=" - }, - "asset-e73f53c5-fdcc-4232-bd6f-85a06281cf6c": { - "id": "asset-e73f53c5-fdcc-4232-bd6f-85a06281cf6c", - "@created": "2018-10-13T16:49:36.056Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3Ny40NiAyMi4zNiI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOm5vbmU7c3Ryb2tlOiNmOWIxMTA7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjJweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPkxvbmcgbGVuZ3RoIEljb248L3RpdGxlPjxnIGlkPSJMYXllcl8yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxnIGlkPSJMYXllcl8xLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMSI+PGxpbmUgY2xhc3M9ImNscy0xIiB4MT0iMSIgeDI9IjEiIHkyPSIyMi4zNiIvPjxsaW5lIGNsYXNzPSJjbHMtMSIgeDE9IjUuNjkiIHkxPSIxMS4xOCIgeDI9IjEwLjE1IiB5Mj0iMTEuMTgiLz48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSIxNy4xNyIgeTE9IjExLjE4IiB4Mj0iMjEuNjMiIHkyPSIxMS4xOCIvPjxsaW5lIGNsYXNzPSJjbHMtMSIgeDE9IjI4LjY1IiB5MT0iMTEuMTgiIHgyPSIzMy4xMSIgeTI9IjExLjE4Ii8+PGxpbmUgY2xhc3M9ImNscy0xIiB4MT0iNDAuMTMiIHkxPSIxMS4xOCIgeDI9IjQ0LjU5IiB5Mj0iMTEuMTgiLz48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSI1MS42MSIgeTE9IjExLjE4IiB4Mj0iNTYuMDgiIHkyPSIxMS4xOCIvPjxsaW5lIGNsYXNzPSJjbHMtMSIgeDE9IjYzLjA5IiB5MT0iMTEuMTgiIHgyPSI2Ny41NiIgeTI9IjExLjE4Ii8+PHBvbHlsaW5lIGNsYXNzPSJjbHMtMSIgcG9pbnRzPSI2OS41NyA1LjIyIDc2LjA1IDExLjcgNjkuNTcgMTguMTgiLz48L2c+PC9nPjwvc3ZnPg==" - }, - "asset-63a49130-fb96-4576-ac31-d86c934234d1": { - "id": "asset-63a49130-fb96-4576-ac31-d86c934234d1", - "@created": "2018-10-13T16:51:32.983Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMC43NiAzMC43NiI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOm5vbmU7c3Ryb2tlOiNmZTk5MDA7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjJweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPlggSWNvbjwvdGl0bGU+PGcgaWQ9IkxheWVyXzIiIGRhdGEtbmFtZT0iTGF5ZXIgMiI+PGcgaWQ9IkxheWVyXzEtMiIgZGF0YS1uYW1lPSJMYXllciAxIj48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSIzMC4wNSIgeTE9IjAuNzEiIHgyPSIwLjcxIiB5Mj0iMzAuMDUiLz48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSIwLjcxIiB5MT0iMC43MSIgeDI9IjMwLjA1IiB5Mj0iMzAuMDUiLz48L2c+PC9nPjwvc3ZnPg==" - }, - "asset-4843e3bb-6cb0-43b7-b076-deea9a901fc6": { - "id": "asset-4843e3bb-6cb0-43b7-b076-deea9a901fc6", - "@created": "2018-10-13T16:52:44.303Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NC42MiA1MS4wMyI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiNmZmY7fS5jbHMtMSwuY2xzLTJ7c3Ryb2tlOiNmMzY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjJweDt9LmNscy0ye2ZpbGw6bm9uZTt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPkZsYWcgSWNvbjwvdGl0bGU+PGcgaWQ9IkxheWVyXzIiIGRhdGEtbmFtZT0iTGF5ZXIgMiI+PGcgaWQ9IkxheWVyXzEtMiIgZGF0YS1uYW1lPSJMYXllciAxIj48cG9seWdvbiBjbGFzcz0iY2xzLTEiIHBvaW50cz0iNDIuOTMgMjguMTUgMSAyOC4xNSAxIDEgNDIuOTMgMSAzNS40NyAxNC41OCA0Mi45MyAyOC4xNSIvPjxsaW5lIGNsYXNzPSJjbHMtMiIgeDE9IjEiIHkxPSIxIiB4Mj0iMSIgeTI9IjUxLjAzIi8+PC9nPjwvZz48L3N2Zz4=" - } - } - } - } -] diff --git a/x-pack/plugins/canvas/server/sample_data/index.ts b/x-pack/plugins/canvas/server/sample_data/index.ts deleted file mode 100644 index 1cbb1d0aaee6a..0000000000000 --- a/x-pack/plugins/canvas/server/sample_data/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// @ts-ignore this file is too large for TypeScript, so it is excluded from our project config -import ecommerceSavedObjects from './ecommerce_saved_objects.json'; -// @ts-ignore this file is too large for TypeScript, so it is excluded from our project config -import flightsSavedObjects from './flights_saved_objects.json'; -// @ts-ignore this file is too large for TypeScript, so it is excluded from our project config -import webLogsSavedObjects from './web_logs_saved_objects.json'; -import { loadSampleData } from './load_sample_data'; - -export { loadSampleData, ecommerceSavedObjects, flightsSavedObjects, webLogsSavedObjects }; diff --git a/x-pack/plugins/canvas/server/sample_data/load_sample_data.ts b/x-pack/plugins/canvas/server/sample_data/load_sample_data.ts deleted file mode 100644 index da219146a3609..0000000000000 --- a/x-pack/plugins/canvas/server/sample_data/load_sample_data.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SampleDataRegistrySetup } from '@kbn/home-plugin/server'; -import { CANVAS as label } from '../../i18n'; -import { ecommerceSavedObjects, flightsSavedObjects, webLogsSavedObjects } from '.'; - -export function loadSampleData( - addSavedObjectsToSampleDataset: SampleDataRegistrySetup['addSavedObjectsToSampleDataset'], - addAppLinksToSampleDataset: SampleDataRegistrySetup['addAppLinksToSampleDataset'] -) { - const now = new Date(); - const nowTimestamp = now.toISOString(); - - // @ts-expect-error: untyped local - function updateCanvasWorkpadTimestamps(savedObjects) { - // @ts-expect-error: untyped local - return savedObjects.map((savedObject) => { - if (savedObject.type === 'canvas-workpad') { - savedObject.attributes['@timestamp'] = nowTimestamp; - savedObject.attributes['@created'] = nowTimestamp; - } - - return savedObject; - }); - } - const getPath = (objectId: string) => `/app/canvas#/workpad/${objectId}`; - - addSavedObjectsToSampleDataset('ecommerce', updateCanvasWorkpadTimestamps(ecommerceSavedObjects)); - addAppLinksToSampleDataset('ecommerce', [ - { - sampleObject: { - type: 'canvas-workpad', - id: 'workpad-e08b9bdb-ec14-4339-94c4-063bddfd610e', - }, - getPath, - icon: 'canvasApp', - label, - }, - ]); - - addSavedObjectsToSampleDataset('flights', updateCanvasWorkpadTimestamps(flightsSavedObjects)); - addAppLinksToSampleDataset('flights', [ - { - sampleObject: { - type: 'canvas-workpad', - id: 'workpad-a474e74b-aedc-47c3-894a-db77e62c41e0', - }, - getPath, - icon: 'canvasApp', - label, - }, - ]); - - addSavedObjectsToSampleDataset('logs', updateCanvasWorkpadTimestamps(webLogsSavedObjects)); - addAppLinksToSampleDataset('logs', [ - { - sampleObject: { - type: 'canvas-workpad', - id: 'workpad-ad72a4e9-b422-480c-be6d-a64a0b79541d', - }, - getPath, - icon: 'canvasApp', - label, - }, - ]); -} diff --git a/x-pack/plugins/canvas/server/sample_data/web_logs_saved_objects.json b/x-pack/plugins/canvas/server/sample_data/web_logs_saved_objects.json deleted file mode 100644 index 8c49935a4514d..0000000000000 --- a/x-pack/plugins/canvas/server/sample_data/web_logs_saved_objects.json +++ /dev/null @@ -1,757 +0,0 @@ -[ - { - "id": "workpad-ad72a4e9-b422-480c-be6d-a64a0b79541d", - "type": "canvas-workpad", - "updated_at": "2018-10-22T12:41:57.071Z", - "version": 1, - "migrationVersion": { - "canvas-workpad": "7.0.0" - }, - "attributes": { - "name": "[Logs] Web Traffic", - "width": 1280, - "height": 720, - "page": 0, - "pages": [ - { - "id": "page-e125ca0b-f6b2-437c-bc4c-918c468fbd9f", - "style": { - "background": "#000000" - }, - "transition": { - "name": "" - }, - "elements": [ - { - "id": "element-950e478d-39be-4630-9ebe-d46578951025", - "position": { - "left": 249, - "top": 574.3671875, - "width": 1013.5, - "height": 131.2578125, - "angle": 0 - }, - "expression": "shape \"square\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=false\n| render\n" - }, - { - "id": "element-f6d67bd9-7edf-4a4c-944e-019eb2a89e46", - "position": { - "left": 249, - "top": 426.5, - "width": 1013.5, - "height": 131.2578125, - "angle": 0 - }, - "expression": "shape \"square\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=false\n| render\n" - }, - { - "id": "element-fa296ebc-3ede-44f1-a027-f9aa0a8ba58b", - "position": { - "left": 249, - "top": 275.87109375, - "width": 1013.5, - "height": 131.2578125, - "angle": 0 - }, - "expression": "shape \"square\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=false\n| render\n" - }, - { - "id": "element-21844047-2818-4071-bb9b-59cc68139c5f", - "position": { - "left": 589, - "top": 110.7578125, - "width": 318, - "height": 148.3046875, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#414143\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-a2136689-36d7-4f61-a9c7-5e4e3c89f2ca", - "position": { - "left": 924.5, - "top": 109.28515625, - "width": 318, - "height": 148.3046875, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#414143\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-2e02449b-433e-47c4-84ab-6f702619e21a", - "position": { - "left": 249, - "top": 109.6328125, - "width": 318, - "height": 148.3046875, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#414143\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-0f10bedf-728c-4207-96b8-bbb3021a91f1", - "position": { - "left": 245, - "top": 12, - "width": 1017.5, - "height": 65.90625, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#221F20\" border=\"#777777\" borderWidth=0 maintainAspect=false\n| render\n", - "filter": null - }, - { - "id": "element-4130544d-054a-4600-928a-39f1423788c6", - "position": { - "left": 13.5, - "top": 12, - "width": 211, - "height": 693.625, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#221F20\" border=\"#777777\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-57ffa8a7-f3f3-45bf-a35a-025a7647b8e7", - "position": { - "left": 19.25, - "top": 88.5625, - "width": 109, - "height": 7.25, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#CFD0D2\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=false\n| render\n" - }, - { - "id": "element-4562db88-edbe-45b2-86aa-c549f2e25c98", - "position": { - "left": 671.5, - "top": 303.2421875, - "width": 574, - "height": 89.13671875, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#221F20\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=false\n| render\n" - }, - { - "id": "element-6556fa13-4557-47bc-bb9f-08a525604e13", - "position": { - "left": 56.25, - "top": 13.625, - "width": 168.25, - "height": 149, - "angle": 0 - }, - "expression": "shape \"circle\" fill=\"#221F20\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=true\n| render\n" - }, - { - "id": "element-671589a9-54b6-46a1-b5e7-363b9d539795", - "position": { - "left": 258, - "top": 24.8125, - "width": 28, - "height": 36, - "angle": 0 - }, - "expression": "filters \n| essql\n query=\"SELECT host, response.keyword AS response\n FROM kibana_sample_data_logs\n WHERE host='artifacts.elastic.co'\n ORDER BY timestamp DESC\n LIMIT 1\"\n| alterColumn \"response\" type=\"number\" \n| getCell \"response\" \n| image mode=\"contain\" \n dataurl={\n asset {\n if {compare lt to=400} \n then=\"asset-0a807073-d056-4c7b-9bf4-225b71e47243\" \n else=\"asset-1343672d-7c02-4402-929e-0f8fef69cddd\"\n }\n } \n| render\n" - }, - { - "id": "element-d98c4bb0-f9ae-4e4a-838d-572b6919a3a2", - "position": { - "left": 20.375, - "top": 68, - "width": 60.25, - "height": 27.8125, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| demodata\n| markdown \"5XX\"\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=18 align=\"left\" color=\"#CFD0D2\" weight=\"normal\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-11de34da-7783-4d09-b22f-4ec1f8c957ea", - "position": { - "left": 573, - "top": 459.5, - "width": 79, - "height": 82, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT SUM(bytes) as total_bytes, host\n FROM kibana_sample_data_logs\n GROUP BY host\"\n| pointseries color=\"host\" size=\"total_bytes\"\n| pie hole=60 labels=false legend=false palette={palette \"#346822\" \"#57993F\" \"#C3F99C\" \"#6CBD38\" gradient=true}\n| render\n" - }, - { - "id": "element-a2e808f6-1b2e-4f84-931e-6c38424c5480", - "position": { - "left": 289.5, - "top": 29.4375, - "width": 165, - "height": 26.75, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT host\n FROM kibana_sample_data_logs\n WHERE host='artifacts.elastic.co'\n ORDER BY timestamp DESC\n LIMIT 1\"\n| markdown {getCell \"host\"}\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=12 align=\"left\" color=\"#CFD0D2\" size=18 weight=\"lighter\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-bc35a3fe-c896-4898-a7f3-e5778958d6b0", - "position": { - "left": 265, - "top": 436.25, - "width": 302, - "height": 110, - "angle": 0, - "parent": null - }, - "expression": "kibana\n| selectFilter\n| essql \n query=\"SELECT SUM(bytes) as total_bytes\n FROM kibana_sample_data_logs\"\n| math \"total_bytes\"\n| formatNumber \"0.00b\"\n| metric \"BYTES TRANSFERRED\"\n metricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"left\" color=\"#FFFFFF\" weight=\"normal\" underline=false italic=false}\n labelFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=30 align=\"left\" color=\"#FFFFFF\" weight=\"lighter\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-a684991f-f179-4fcc-b474-5ed71b0a6f3e", - "position": { - "left": 264.5, - "top": 586.5, - "width": 290.5, - "height": 104, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql \n query=\"SELECT COUNT(timestamp) as total_visitors\n FROM kibana_sample_data_logs\"\n| math \"total_visitors\"\n| metric \"TOTAL VISITORS\"\n metricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"left\" color=\"#FFFFFF\" weight=\"normal\" underline=false italic=false}\n labelFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=30 align=\"left\" color=\"#FFFFFF\" weight=\"lighter\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-a8a8fa93-8e08-4e9f-b3e4-f4014543fe1f", - "position": { - "left": 515.5, - "top": 29.4375, - "width": 147, - "height": 25.75, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql \n query=\"SELECT host\n FROM kibana_sample_data_logs\n WHERE host='www.elastic.co'\"\n| markdown {getCell \"host\"}\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=12 align=\"left\" color=\"#CFD0D2\" size=18 weight=\"lighter\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-38b281b2-ab5e-41ee-aa3e-e48bc3f778df", - "position": { - "left": 719, - "top": 28.625, - "width": 247, - "height": 26.75, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT host \n FROM kibana_sample_data_logs\n WHERE host='cdn.elastic-elastic-elastic.org'\"\n| markdown {getCell \"host\"}\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=12 align=\"left\" color=\"#CFD0D2\" size=18 weight=\"lighter\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-b481bf28-15d3-4f0b-b67b-e268c68bfe9c", - "position": { - "left": 1040.5, - "top": 28.8125, - "width": 209, - "height": 27.375, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT host\n FROM kibana_sample_data_logs\n WHERE host='elastic-elastic-elastic.org'\"\n| markdown {getCell \"host\"}\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=12 align=\"left\" color=\"#CFD0D2\" size=18 weight=\"lighter\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-ebb18e7a-ec51-4072-8453-58fbb883584b", - "position": { - "left": 677.5, - "top": 451.77734375, - "width": 578, - "height": 90.5, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT SUM(bytes) as total_bytes, HOUR_OF_DAY(timestamp) as hour, host\n FROM kibana_sample_data_logs\n GROUP BY host, HOUR_OF_DAY(timestamp)\n ORDER BY HOUR_OF_DAY(timestamp) DESC\"\n| pointseries x=\"hour\" y=\"total_bytes\" color=\"host\"\n| plot defaultStyle={seriesStyle bars=0 lines=3 points=0} legend=false xaxis=false yaxis=false palette={palette \"#346822\" \"#57993F\" \"#C3F99C\" \"#6CBD38\" gradient=true}\n| render containerStyle={containerStyle backgroundColor=\"#221F20\"}\n" - }, - { - "id": "element-05a065b5-5f01-4502-9f91-fdfc3de1b456", - "position": { - "left": 677.5, - "top": 594.875, - "width": 578, - "height": 87.25, - "angle": 0, - "parent": null - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT COUNT(timestamp) as total_visitors, HOUR_OF_DAY(timestamp) as hour, host\n FROM kibana_sample_data_logs\n GROUP BY host, HOUR_OF_DAY(timestamp)\n ORDER BY HOUR_OF_DAY(timestamp) DESC\"\n| pointseries x=\"hour\" y=\"total_visitors\" color=\"host\"\n| plot defaultStyle={seriesStyle bars=0 lines=3 points=0} legend=false xaxis=false yaxis=false palette={palette \"#C83C5C\" \"#D56F79\" \"#F6C4C5\" \"#F1A3A6\" gradient=true}\n| render containerStyle={containerStyle backgroundColor=\"#221F20\"}\n" - }, - { - "id": "element-ce1da927-2d4f-413e-85e9-4fd1106b5207", - "position": { - "left": 573, - "top": 604.5, - "width": 79, - "height": 82, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT COUNT(timestamp) as total_visitors, host\n FROM kibana_sample_data_logs\n GROUP BY host\"\n| pointseries color=\"host\" size=\"total_visitors\"\n| pie hole=60 labels=false legend=false palette={palette \"#C83C5C\" \"#D56F79\" \"#F6C4C5\" \"#F1A3A6\" gradient=true}\n| render\n", - "filter": null - }, - { - "id": "element-acccadaf-3ce8-4ca6-8205-4529d42c1eef", - "position": { - "left": 677, - "top": 290.62109375, - "width": 562, - "height": 101.7578125, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\nquery=\"SELECT COUNT(timestamp) as total_errors, timestamp\nFROM kibana_sample_data_logs\nWHERE tags LIKE '%warning%'\nGROUP BY timestamp\nORDER BY timestamp DESC\"\n| pointseries x=\"timestamp\" y=\"total_errors\"\n| plot defaultStyle={seriesStyle bars=\"1\" lines=\"0\" points=0 color=\"#E9782F\"} legend=false xaxis=false yaxis=false\n| render\n" - }, - { - "id": "element-1ae8ea70-993a-4503-916a-ce98717054f6", - "position": { - "left": 680.5, - "top": 290.62109375, - "width": 562, - "height": 101.7578125, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT COUNT(timestamp) as total_errors, timestamp\n FROM kibana_sample_data_logs\n WHERE tags LIKE '%error%'\n GROUP BY timestamp\n ORDER BY timestamp DESC\"\n| pointseries x=\"timestamp\" y=\"total_errors\"\n| plot defaultStyle={seriesStyle bars=\"1\" lines=\"0\" points=0 color=\"#F2C242\"} legend=false xaxis=false yaxis=false\n| render\n" - }, - { - "id": "element-70a2bca6-de31-4bee-81b1-b18528820645", - "position": { - "left": 264.5, - "top": 287.4375, - "width": 215, - "height": 104.94140625, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT COUNT(timestamp) as total_errors\n FROM kibana_sample_data_logs\n WHERE tags LIKE '%warning%' OR tags LIKE '%error%'\"\n| math \"total_errors\"\n| metric \"TOTAL ISSUES\"\n metricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"left\" color=\"#FFFFFF\" weight=\"normal\" underline=false italic=false}\n labelFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=30 align=\"left\" color=\"#FFFFFF\" weight=\"lighter\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-5b36cc1b-e0d6-4ddc-bf16-849fc41e1f16", - "position": { - "left": 562.5, - "top": 294.1953125, - "width": 100, - "height": 98.18359375, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT COUNT(timestamp) as total_errors\n FROM kibana_sample_data_logs\n WHERE tags LIKE '%warning%' OR tags LIKE '%error%'\"\n| math \"clamp(sum(total_errors / 100),0,1)\"\n| revealImage origin=\"bottom\" image={asset \"asset-a1e77720-eb0b-42a0-a1c0-a159035e4f26\"} emptyImage={asset \"asset-d2cca77f-ba40-4acb-beff-38fab19c7b65\"}\n| render\n" - }, - { - "id": "element-9d5e9c4b-a7f5-459b-ab15-cfcd1d1d00c9", - "position": { - "left": 319.5, - "top": 120.17578125, - "width": 239, - "height": 39.68359375, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| demodata\n| markdown \"MACHINE\"\nfont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=30 align=\"left\" color=\"#FFFFFF\" weight=\"lighter\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-d575ce4e-4aa5-4c54-993a-ca56890e434f", - "position": { - "left": 259.5, - "top": 171.69140625, - "width": 295.5, - "height": 80.12109375, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| esdocs index=\"kibana_sample_data_logs\" sort=\"timestamp, desc\" fields=\"machine.os, machine.ram\" count=1\n| markdown \"**OS:** \" {getCell \"machine.os\"} \"\\\n **RAM:** \" {getCell \"machine.ram\" | formatNumber \"00.0b\"}\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=20 align=\"left\" color=\"#FFFFFF\" weight=\"lighter\" underline=false italic=false}\n| render containerStyle={containerStyle padding=\"5px\"}\n" - }, - { - "id": "element-6f777a39-f934-4263-94ea-4f1d48f3849c", - "position": { - "left": 604.75, - "top": 171.69140625, - "width": 298, - "height": 83.74609375, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| esdocs index=\"kibana_sample_data_logs\" sort=\"timestamp, desc\" fields=\"request\" count=1\n| markdown {getCell \"request\"}\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=20 align=\"left\" color=\"#FFFFFF\" weight=\"lighter\" underline=false italic=false}\n| render containerStyle={containerStyle padding=\"5px\"}\n" - }, - { - "id": "element-7bfcdb0f-3533-4e50-a94a-f0487f374bff", - "position": { - "left": 941.5, - "top": 171.69140625, - "width": 284, - "height": 80.12109375, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| esdocs index=\"kibana_sample_data_logs\" sort=\"timestamp, desc\" fields=\"geo.src, geo.dest\" count=1\n| markdown \"**ORIGIN COUNTRY:** \" {getCell \"geo.src\"} \"\\\n **DESTINATION:** \" {getCell \"geo.dest\"}\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=20 align=\"left\" color=\"#FFFFFF\" weight=\"lighter\" underline=false italic=false}\n| render containerStyle={containerStyle padding=\"5px\"}\n" - }, - { - "id": "element-db2d0540-f734-421e-a9a5-7f6e9eef0bd7", - "position": { - "left": 987.5, - "top": -51, - "width": 285, - "height": 50, - "angle": 0, - "parent": null - }, - "expression": "timefilterControl compact=true column=\"timestamp\"\n| render\n", - "filter": "timefilter from=\"now-24h\" to=now column=timestamp" - }, - { - "id": "element-a29b5f31-3204-4174-a511-5869648ccae0", - "position": { - "left": 73.75, - "top": 34.2578125, - "width": 133.25, - "height": 108.609375, - "angle": 0 - }, - "expression": "shape \"circle\" fill=\"#C83C5B\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=true\n| render\n" - }, - { - "id": "element-c509ce21-e729-4aa5-b892-f4be441cde26", - "position": { - "left": 94.875, - "top": 64, - "width": 91, - "height": 49.125, - "angle": 0 - }, - "expression": "filters \n| essql \n query=\"SELECT COUNT(*) as response_code\n FROM kibana_sample_data_logs\n WHERE response >= 500\"\n| math \"response_code\"\n| metric\n metricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"center\" color=\"#FFFFFF\" weight=\"bold\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-d27ad090-4e58-4d9c-aef7-ccb8ca043758", - "position": { - "left": 20.375, - "top": 612.625, - "width": 109, - "height": 7.25, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#CFD0D2\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=false\n| render\n" - }, - { - "id": "element-99baa692-12dc-4d8d-9d78-05cb1aa7f7a8", - "position": { - "left": 21.1875, - "top": 436.25, - "width": 109, - "height": 7.25, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#CFD0D2\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=false\n| render\n" - }, - { - "id": "element-f0412810-61fb-4ab8-ba9f-a69ba344d4d7", - "position": { - "left": 20.25, - "top": 251.8125, - "width": 109, - "height": 7.25, - "angle": 0 - }, - "expression": "shape \"square\" fill=\"#CFD0D2\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=false\n| render\n" - }, - { - "id": "element-42587f38-4f6e-4a23-9ade-d0f23449efba", - "position": { - "left": 56.25, - "top": 183.4375, - "width": 168.25, - "height": 149, - "angle": 0 - }, - "expression": "shape \"circle\" fill=\"#221F20\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=true\n| render\n" - }, - { - "id": "element-40d243ea-088c-4e17-b797-c47c8b94e282", - "position": { - "left": 56.25, - "top": 369, - "width": 168.25, - "height": 149, - "angle": 0 - }, - "expression": "shape \"circle\" fill=\"#221F20\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=true\n| render\n" - }, - { - "id": "element-349aaa30-c164-4b95-b5aa-891a43e7b693", - "position": { - "left": 56.25, - "top": 541.5, - "width": 168.25, - "height": 149, - "angle": 0 - }, - "expression": "shape \"circle\" fill=\"#221F20\" border=\"#CFD0D2\" borderWidth=2 maintainAspect=true\n| render\n" - }, - { - "id": "element-e92c89d9-4ddd-499c-8367-94271da02b3d", - "position": { - "left": 73.75, - "top": 203.6328125, - "width": 133.25, - "height": 108.609375, - "angle": 0 - }, - "expression": "shape \"circle\" fill=\"#E9782F\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=true\n| render\n" - }, - { - "id": "element-f827824d-fc40-4905-937d-060e9748acce", - "position": { - "left": 74.75, - "top": 389.1953125, - "width": 133.25, - "height": 108.609375, - "angle": 0 - }, - "expression": "shape \"circle\" fill=\"#F2C242\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=true\n| render\n" - }, - { - "id": "element-f7e459a0-613e-43f4-9ced-d5f4ae6f3c47", - "position": { - "left": 74.75, - "top": 561.9453125, - "width": 133.25, - "height": 108.609375, - "angle": 0 - }, - "expression": "shape \"circle\" fill=\"#6CBD38\" border=\"rgba(255,255,255,0)\" borderWidth=0 maintainAspect=true\n| render\n" - }, - { - "id": "element-f5760f24-d9cb-42e8-ae60-13c60335f049", - "position": { - "left": 21.1875, - "top": 590.1875, - "width": 61.375, - "height": 25.8125, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| demodata\n| markdown \"2XX\"\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=18 align=\"left\" color=\"#CFD0D2\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-5e9998b3-7c27-4f4a-8f61-6b857339e07e", - "position": { - "left": 21.1875, - "top": 413.59375, - "width": 50.625, - "height": 26.28125, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| demodata\n| markdown \"3XX\"\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=18 align=\"left\" color=\"#CFD0D2\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-744e0e58-e1be-4919-a9fb-eaa46c5d8aaa", - "position": { - "left": 19.25, - "top": 228.4375, - "width": 54.5, - "height": 30.625, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| demodata\n| markdown \"4XX\"\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=18 align=\"left\" color=\"#CFD0D2\" weight=\"normal\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-9f7bea99-8c0c-49b1-b8a3-9af26eb0466d", - "position": { - "left": 94.875, - "top": 228.4375, - "width": 91, - "height": 59, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql \n query=\"SELECT COUNT(*) as response_code\n FROM kibana_sample_data_logs\n WHERE response >= 400 AND response < 500\"\n| math \"unique(response_code)\"\n| metric\n metricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"center\" color=\"#FFFFFF\" weight=\"bold\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-607512ac-3d83-4d36-87c1-d5f13502f084", - "position": { - "left": 97.5, - "top": 418.25, - "width": 88.375, - "height": 59, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT COUNT(*) as response_code\n FROM kibana_sample_data_logs\n WHERE response >= 300 AND response < 400\"\n| math \"response_code\"\n| metric\n metricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"center\" color=\"#FFFFFF\" weight=\"bold\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-3cc56225-d739-4279-97f2-5c179fb013a5", - "position": { - "left": 94.875, - "top": 590.1875, - "width": 91, - "height": 59, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| essql\n query=\"SELECT COUNT(*) as response_code\n FROM kibana_sample_data_logs\n WHERE response >= 200 AND response < 300\"\n| math \"response_code\"\n| formatNumber \"0a\"\n| metric\n metricFont={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=48 align=\"center\" color=\"#FFFFFF\" weight=\"bold\" underline=false italic=false}\n| render\n" - }, - { - "id": "element-f7d5956f-287d-4ac6-bcfb-fca6f8ebe63e", - "position": { - "left": 479.5, - "top": 24, - "width": 28, - "height": 36, - "angle": 0 - }, - "expression": "filters \n| essql\n query=\"SELECT host, response.keyword AS response\n FROM kibana_sample_data_logs\n WHERE host='www.elastic.co'\n ORDER BY timestamp DESC\n LIMIT 1\"\n| alterColumn \"response\" type=\"number\" \n| image mode=\"contain\" \n dataurl={\n asset {\n if {getCell \"response\" | compare lt to=400} \n then=\"asset-0a807073-d056-4c7b-9bf4-225b71e47243\" \n else=\"asset-1343672d-7c02-4402-929e-0f8fef69cddd\"\n }\n } \n| render\n", - "filter": null - }, - { - "id": "element-254cc607-c924-49f4-a7f7-737480b4a056", - "position": { - "left": 682.5, - "top": 24.5, - "width": 28, - "height": 36, - "angle": 0 - }, - "expression": "filters \n| essql\n query=\"SELECT host, response.keyword AS response\n FROM kibana_sample_data_logs\n WHERE host='cdn.elastic-elastic-elastic.org'\n ORDER BY timestamp DESC\n LIMIT 1\"\n| alterColumn \"response\" type=\"number\" \n| image mode=\"contain\" \n dataurl={\n asset {\n if {getCell \"response\" | compare lt to=400} then=\"asset-0a807073-d056-4c7b-9bf4-225b71e47243\" else=\"asset-1343672d-7c02-4402-929e-0f8fef69cddd\"\n }\n } \n| render\n", - "filter": null - }, - { - "id": "element-96aa263d-8222-4adc-94ff-2277a1f55dff", - "position": { - "left": 1001.5, - "top": 24, - "width": 28, - "height": 36, - "angle": 0 - }, - "expression": "filters \n| essql\n query=\"SELECT host, response.keyword AS response\n FROM kibana_sample_data_logs\n WHERE host='elastic-elastic-elastic.org'\n ORDER BY timestamp DESC\n LIMIT 1\"\n| alterColumn \"response\" type=\"number\" \n| image mode=\"contain\" \n dataurl={\n asset {\n if {getCell \"response\" | compare lt to=400} then=\"asset-0a807073-d056-4c7b-9bf4-225b71e47243\" else=\"asset-1343672d-7c02-4402-929e-0f8fef69cddd\"\n }\n } \n| render\n", - "filter": null - }, - { - "id": "element-618ced11-d0da-4603-ae0b-77a5bb35e6c4", - "position": { - "left": 263.25, - "top": 128.658203125, - "width": 45, - "height": 28.25, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-e9118351-dcc5-4a27-a7fc-f15eb308999b\"}\n| render\n" - }, - { - "id": "element-0f3c5e51-24b8-421e-b151-0c0229f80550", - "position": { - "left": 658.5, - "top": 119.525390625, - "width": 220, - "height": 37.3828125, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| demodata\n| markdown \"REQUEST\"\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=30 align=\"left\" color=\"#FFFFFF\" weight=\"lighter\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-98d5f63a-ef33-415a-a1ec-44a5564c239f", - "position": { - "left": 996.5, - "top": 117.525390625, - "width": 220, - "height": 43.68359375, - "angle": 0 - }, - "expression": "kibana\n| selectFilter\n| demodata\n| markdown \"GEO\"\n font={font family=\"'Open Sans', Helvetica, Arial, sans-serif\" size=30 align=\"left\" color=\"#FFFFFF\" weight=\"lighter\" underline=false italic=false}\n| render\n", - "filter": null - }, - { - "id": "element-88f2579a-50af-4330-baaf-e751092588a3", - "position": { - "left": 604.75, - "top": 129.30859375, - "width": 45, - "height": 28.25, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-c2128a19-e5ba-450c-99c0-a68abbdfa684\"}\n| render\n", - "filter": null - }, - { - "id": "element-eed60428-2b80-4558-8bcc-40b516fa63d4", - "position": { - "left": 942.5, - "top": 124.7421875, - "width": 45, - "height": 29.25, - "angle": 0 - }, - "expression": "image mode=\"contain\" dataurl={asset \"asset-86622ebc-32db-40fa-8310-262c85a10979\"}\n| render\n", - "filter": null - } - ], - "groups": [] - } - ], - "colors": [ - "#37988d", - "#c19628", - "#b83c6f", - "#3f9939", - "#1785b0", - "#ca5f35", - "#45bdb0", - "#f2bc33", - "#e74b8b", - "#4fbf48", - "#1ea6dc", - "#fd7643", - "#72cec3", - "#f5cc5d", - "#ec77a8", - "#7acf74", - "#4cbce4", - "#fd986f", - "#a1ded7", - "#f8dd91", - "#f2a4c5", - "#a6dfa2", - "#86d2ed", - "#fdba9f", - "#000000", - "#444444", - "#777777", - "#BBBBBB", - "#FFFFFF", - "rgba(255,255,255,0)" - ], - "@timestamp": "2019-06-03T20:54:03.958Z", - "@created": "2019-06-03T20:46:16.137Z", - "assets": { - "asset-a1e77720-eb0b-42a0-a1c0-a159035e4f26": { - "id": "asset-a1e77720-eb0b-42a0-a1c0-a159035e4f26", - "@created": "2018-10-13T10:48:32.499Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MS41MyA4Ny4yOSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiNkOTI4NTk7fS5jbHMtMntmaWxsOiNmOTcxMDA7fS5jbHMtM3tmaWxsOiNmOWMxMDA7fTwvc3R5bGU+PC9kZWZzPjx0aXRsZT5GaXJlIENvbG9yPC90aXRsZT48ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIj48ZyBpZD0iTGF5ZXJfMi0yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTMwLjc3LDBoMFM2MS41MywyNy43MSw2MS41Myw1Ni41M2MwLDE5LjI3LTEzLjc3LDMwLjc3LTMwLjc3LDMwLjc3aDBBMzAuOCwzMC44LDAsMCwxLDAsNTYuNTNDMCwyOC42OCwzMC43NywwLDMwLjc3LDBaIi8+PHBhdGggY2xhc3M9ImNscy0yIiBkPSJNMzAuNzcsMjBoMHMyMy43LDIxLjM0LDIzLjcsNDMuNTRjMCwxNC44NC0xMC42MSwyMy43LTIzLjcsMjMuN2gwYTIzLjczLDIzLjczLDAsMCwxLTIzLjctMjMuN0M3LjA3LDQyLjE0LDMwLjc3LDIwLDMwLjc3LDIwWiIvPjxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTMwLjc3LDUyLjA3aDBTNDMuMTgsNjMuMjUsNDMuMTgsNzQuODhjMCw3Ljc3LTUuNTYsMTIuNDItMTIuNDIsMTIuNDJoMEExMi40MywxMi40MywwLDAsMSwxOC4zNSw3NC44OEMxOC4zNSw2My42NCwzMC43Nyw1Mi4wNywzMC43Nyw1Mi4wN1oiLz48L2c+PC9nPjwvc3ZnPg==" - }, - "asset-d2cca77f-ba40-4acb-beff-38fab19c7b65": { - "id": "asset-d2cca77f-ba40-4acb-beff-38fab19c7b65", - "@created": "2018-10-13T10:48:37.615Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MS41MyA4Ny4yOSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiM2ZDZlNzE7fS5jbHMtMntmaWxsOiM5Mzk1OTg7fS5jbHMtM3tmaWxsOiNiY2JlYzA7fTwvc3R5bGU+PC9kZWZzPjx0aXRsZT5GaXJlIEdyYXk8L3RpdGxlPjxnIGlkPSJMYXllcl8yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxnIGlkPSJMYXllcl8yLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMiI+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMzAuNzcsMGgwQTEyNi4yNSwxMjYuMjUsMCwwLDEsNDguMzIsMjAuNTNjNi45MSwxMC4xMywxMy4yMiwyMi45NSwxMy4yMiwzNiwwLDE5LjI3LTEzLjc3LDMwLjc3LTMwLjc3LDMwLjc3aDBBMzAuOCwzMC44LDAsMCwxLDAsNTYuNTNDMCwyOC42OCwzMC43NywwLDMwLjc3LDBaIi8+PHBhdGggY2xhc3M9ImNscy0yIiBkPSJNMzAuNzcsMjBoMHMyMy43LDIxLjM0LDIzLjcsNDMuNTRjMCwxNC44NC0xMC42MSwyMy43LTIzLjcsMjMuN2gwYTIzLjczLDIzLjczLDAsMCwxLTIzLjctMjMuN0M3LjA3LDQyLjE0LDMwLjc3LDIwLDMwLjc3LDIwWiIvPjxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTMwLjc3LDUyLjA3aDBTNDMuMTgsNjMuMjUsNDMuMTgsNzQuODhjMCw3Ljc3LTUuNTYsMTIuNDItMTIuNDIsMTIuNDJoMEExMi40MywxMi40MywwLDAsMSwxOC4zNSw3NC44OEMxOC4zNSw2My42NCwzMC43Nyw1Mi4wNywzMC43Nyw1Mi4wN1oiLz48L2c+PC9nPjwvc3ZnPg==" - }, - "asset-1343672d-7c02-4402-929e-0f8fef69cddd": { - "id": "asset-1343672d-7c02-4402-929e-0f8fef69cddd", - "@created": "2018-10-13T14:50:42.520Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNC44NiAyNC44NiI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiNkOTI4NTk7fS5jbHMtMntmaWxsOm5vbmU7c3Ryb2tlOiNmZmY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjNweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPlBpbmsgWDwvdGl0bGU+PGcgaWQ9IkxheWVyXzIiIGRhdGEtbmFtZT0iTGF5ZXIgMiI+PGcgaWQ9IkxheWVyXzItMiIgZGF0YS1uYW1lPSJMYXllciAyIj48Y2lyY2xlIGNsYXNzPSJjbHMtMSIgY3g9IjEyLjQzIiBjeT0iMTIuNDMiIHI9IjEyLjQzIi8+PGxpbmUgY2xhc3M9ImNscy0yIiB4MT0iMTYuNzYiIHkxPSI4LjA5IiB4Mj0iOC4wOSIgeTI9IjE2Ljc2Ii8+PGxpbmUgY2xhc3M9ImNscy0yIiB4MT0iOC4wOSIgeTE9IjguMDkiIHgyPSIxNi43NiIgeTI9IjE2Ljc2Ii8+PC9nPjwvZz48L3N2Zz4=" - }, - "asset-0a807073-d056-4c7b-9bf4-225b71e47243": { - "id": "asset-0a807073-d056-4c7b-9bf4-225b71e47243", - "@created": "2018-10-13T14:50:49.318Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNC44NiAyNC44NiI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiM0OGMxMDA7fS5jbHMtMntmaWxsOm5vbmU7c3Ryb2tlOiNmZmY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjNweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPkdyZWVuIGNoZWNrPC90aXRsZT48ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIj48ZyBpZD0iTGF5ZXJfMi0yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxjaXJjbGUgY2xhc3M9ImNscy0xIiBjeD0iMTIuNDMiIGN5PSIxMi40MyIgcj0iMTIuNDMiLz48bGluZSBjbGFzcz0iY2xzLTIiIHgxPSIxOC43NCIgeTE9IjguNTMiIHgyPSIxMC4wNyIgeTI9IjE3LjIiLz48bGluZSBjbGFzcz0iY2xzLTIiIHgxPSI2LjgzIiB5MT0iMTIuMzUiIHgyPSIxMS45MyIgeTI9IjE3LjQ1Ii8+PC9nPjwvZz48L3N2Zz4=" - }, - "asset-86622ebc-32db-40fa-8310-262c85a10979": { - "id": "asset-86622ebc-32db-40fa-8310-262c85a10979", - "@created": "2018-10-13T15:01:15.036Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNy45NCAyOS43Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6IzQxNDA0MjtzdHJva2U6I2ZmZjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2Utd2lkdGg6MnB4O308L3N0eWxlPjwvZGVmcz48dGl0bGU+R2VvIEljb248L3RpdGxlPjxnIGlkPSJMYXllcl8yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxnIGlkPSJMYXllcl8yLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMiI+PHJlY3QgY2xhc3M9ImNscy0xIiB4PSIxIiB5PSI3LjM1IiB3aWR0aD0iMzUuOTQiIGhlaWdodD0iMjEuMzYiLz48cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0yMy41OCwxOS43aDBTMTcsMTMuNzYsMTcsNy41OUE2LjMsNi4zLDAsMCwxLDIzLjU4LDFoMGE2LjYsNi42LDAsMCwxLDYuNTksNi41OUMzMC4xOCwxMy41NiwyMy41OCwxOS43LDIzLjU4LDE5LjdaIi8+PC9nPjwvZz48L3N2Zz4=" - }, - "asset-c2128a19-e5ba-450c-99c0-a68abbdfa684": { - "id": "asset-c2128a19-e5ba-450c-99c0-a68abbdfa684", - "@created": "2018-10-13T15:02:05.173Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMS44MyAyNi4zOSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiM0MTQwNDI7c3Ryb2tlOiNmZmY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjJweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPlJlcXVlc3QgSWNvbjwvdGl0bGU+PGcgaWQ9IkxheWVyXzIiIGRhdGEtbmFtZT0iTGF5ZXIgMiI+PGcgaWQ9IkxheWVyXzItMiIgZGF0YS1uYW1lPSJMYXllciAyIj48cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0zMC44MywxSDFWMjUuMjNhLjE2LjE2LDAsMCwwLC4yOC4xMkw3LjY2LDE5SDMwLjgzWiIvPjwvZz48L2c+PC9zdmc+" - }, - "asset-e9118351-dcc5-4a27-a7fc-f15eb308999b": { - "id": "asset-e9118351-dcc5-4a27-a7fc-f15eb308999b", - "@created": "2018-10-13T15:02:24.299Z", - "type": "dataurl", - "value": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MC44MSAyNS4zMSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiM0MTQwNDI7c3Ryb2tlOiNmZmY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjJweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPk1hY2hpbmUgSWNvbjwvdGl0bGU+PGcgaWQ9IkxheWVyXzIiIGRhdGEtbmFtZT0iTGF5ZXIgMiI+PGcgaWQ9IkxheWVyXzItMiIgZGF0YS1uYW1lPSJMYXllciAyIj48cmVjdCBjbGFzcz0iY2xzLTEiIHg9IjUuMTgiIHk9IjEiIHdpZHRoPSIyOS44MyIgaGVpZ2h0PSIxNy45NiIvPjxsaW5lIGNsYXNzPSJjbHMtMSIgeTE9IjI0LjMxIiB4Mj0iNDAuODEiIHkyPSIyNC4zMSIvPjwvZz48L2c+PC9zdmc+" - } - }, - "css": ".canvasPage {\n\n}" - } - } -] \ No newline at end of file diff --git a/x-pack/plugins/cases/common/schema/index.test.ts b/x-pack/plugins/cases/common/schema/index.test.ts index ae1146b594dbb..64eb2ad393fcb 100644 --- a/x-pack/plugins/cases/common/schema/index.test.ts +++ b/x-pack/plugins/cases/common/schema/index.test.ts @@ -13,6 +13,7 @@ import { limitedStringSchema, NonEmptyString, paginationSchema, + limitedNumberAsIntegerSchema, } from '.'; import { MAX_DOCS_PER_PAGE } from '../constants'; @@ -319,4 +320,69 @@ describe('schema', () => { `); }); }); + + describe('limitedNumberAsIntegerSchema', () => { + it('works correctly the number is safe integer', () => { + expect(PathReporter.report(limitedNumberAsIntegerSchema({ fieldName: 'foo' }).decode(1))) + .toMatchInlineSnapshot(` + Array [ + "No errors!", + ] + `); + }); + + it('fails when given a number that is lower than the minimum', () => { + expect( + PathReporter.report( + limitedNumberAsIntegerSchema({ fieldName: 'foo' }).decode(Number.MIN_SAFE_INTEGER - 1) + ) + ).toMatchInlineSnapshot(` + Array [ + "The foo field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.", + ] + `); + }); + + it('fails when given a number that is higher than the maximum', () => { + expect( + PathReporter.report( + limitedNumberAsIntegerSchema({ fieldName: 'foo' }).decode(Number.MAX_SAFE_INTEGER + 1) + ) + ).toMatchInlineSnapshot(` + Array [ + "The foo field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.", + ] + `); + }); + + it('fails when given a null instead of a number', () => { + expect(PathReporter.report(limitedNumberAsIntegerSchema({ fieldName: 'foo' }).decode(null))) + .toMatchInlineSnapshot(` + Array [ + "Invalid value null supplied to : LimitedNumberAsInteger", + ] + `); + }); + + it('fails when given a string instead of a number', () => { + expect( + PathReporter.report( + limitedNumberAsIntegerSchema({ fieldName: 'foo' }).decode('some string') + ) + ).toMatchInlineSnapshot(` + Array [ + "Invalid value \\"some string\\" supplied to : LimitedNumberAsInteger", + ] + `); + }); + + it('fails when given a float number instead of an safe integer number', () => { + expect(PathReporter.report(limitedNumberAsIntegerSchema({ fieldName: 'foo' }).decode(1.2))) + .toMatchInlineSnapshot(` + Array [ + "The foo field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.", + ] + `); + }); + }); }); diff --git a/x-pack/plugins/cases/common/schema/index.ts b/x-pack/plugins/cases/common/schema/index.ts index b38d499c8c04c..0bcbdcfb2c480 100644 --- a/x-pack/plugins/cases/common/schema/index.ts +++ b/x-pack/plugins/cases/common/schema/index.ts @@ -154,6 +154,24 @@ export const limitedNumberSchema = ({ fieldName, min, max }: LimitedSchemaType) rt.identity ); +export const limitedNumberAsIntegerSchema = ({ fieldName }: { fieldName: string }) => + new rt.Type( + 'LimitedNumberAsInteger', + rt.number.is, + (input, context) => + either.chain(rt.number.validate(input, context), (s) => { + if (!Number.isSafeInteger(s)) { + return rt.failure( + input, + context, + `The ${fieldName} field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.` + ); + } + return rt.success(s); + }), + rt.identity + ); + export interface RegexStringSchemaType { codec: rt.Type; pattern: string; diff --git a/x-pack/plugins/cases/common/types/api/case/v1.test.ts b/x-pack/plugins/cases/common/types/api/case/v1.test.ts index a509bdee36525..baf9626d3562e 100644 --- a/x-pack/plugins/cases/common/types/api/case/v1.test.ts +++ b/x-pack/plugins/cases/common/types/api/case/v1.test.ts @@ -114,10 +114,15 @@ const basicCase: Case = { value: true, }, { - key: 'second_custom_field_key', + key: 'third_custom_field_key', type: CustomFieldTypes.TEXT, value: 'www.example.com', }, + { + key: 'fourth_custom_field_key', + type: CustomFieldTypes.NUMBER, + value: 3, + }, ], }; @@ -149,6 +154,11 @@ describe('CasePostRequestRt', () => { type: CustomFieldTypes.TOGGLE, value: true, }, + { + key: 'third_custom_field_key', + type: CustomFieldTypes.NUMBER, + value: 3, + }, ], }; @@ -322,6 +332,44 @@ describe('CasePostRequestRt', () => { ); }); + it(`throws an error when a number customFields is more than ${Number.MAX_SAFE_INTEGER}`, () => { + expect( + PathReporter.report( + CasePostRequestRt.decode({ + ...defaultRequest, + customFields: [ + { + key: 'first_custom_field_key', + type: CustomFieldTypes.NUMBER, + value: Number.MAX_SAFE_INTEGER + 1, + }, + ], + }) + ) + ).toContain( + `The value field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.` + ); + }); + + it(`throws an error when a number customFields is less than ${Number.MIN_SAFE_INTEGER}`, () => { + expect( + PathReporter.report( + CasePostRequestRt.decode({ + ...defaultRequest, + customFields: [ + { + key: 'first_custom_field_key', + type: CustomFieldTypes.NUMBER, + value: Number.MIN_SAFE_INTEGER - 1, + }, + ], + }) + ) + ).toContain( + `The value field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.` + ); + }); + it('throws an error when a text customField is an empty string', () => { expect( PathReporter.report( @@ -665,6 +713,11 @@ describe('CasePatchRequestRt', () => { type: 'toggle', value: true, }, + { + key: 'third_custom_field_key', + type: 'number', + value: 123, + }, ], }; diff --git a/x-pack/plugins/cases/common/types/api/case/v1.ts b/x-pack/plugins/cases/common/types/api/case/v1.ts index 7a45f92fa4668..f66df68169e5b 100644 --- a/x-pack/plugins/cases/common/types/api/case/v1.ts +++ b/x-pack/plugins/cases/common/types/api/case/v1.ts @@ -29,7 +29,11 @@ import { NonEmptyString, paginationSchema, } from '../../../schema'; -import { CaseCustomFieldToggleRt, CustomFieldTextTypeRt } from '../../domain'; +import { + CaseCustomFieldToggleRt, + CustomFieldTextTypeRt, + CustomFieldNumberTypeRt, +} from '../../domain'; import { CaseRt, CaseSettingsRt, @@ -41,7 +45,10 @@ import { import { CaseConnectorRt } from '../../domain/connector/v1'; import { CaseUserProfileRt, UserRt } from '../../domain/user/v1'; import { CasesStatusResponseRt } from '../stats/v1'; -import { CaseCustomFieldTextWithValidationValueRt } from '../custom_field/v1'; +import { + CaseCustomFieldTextWithValidationValueRt, + CaseCustomFieldNumberWithValidationValueRt, +} from '../custom_field/v1'; const CaseCustomFieldTextWithValidationRt = rt.strict({ key: rt.string, @@ -49,7 +56,17 @@ const CaseCustomFieldTextWithValidationRt = rt.strict({ value: rt.union([CaseCustomFieldTextWithValidationValueRt('value'), rt.null]), }); -const CustomFieldRt = rt.union([CaseCustomFieldTextWithValidationRt, CaseCustomFieldToggleRt]); +const CaseCustomFieldNumberWithValidationRt = rt.strict({ + key: rt.string, + type: CustomFieldNumberTypeRt, + value: rt.union([CaseCustomFieldNumberWithValidationValueRt({ fieldName: 'value' }), rt.null]), +}); + +const CustomFieldRt = rt.union([ + CaseCustomFieldTextWithValidationRt, + CaseCustomFieldToggleRt, + CaseCustomFieldNumberWithValidationRt, +]); export const CaseRequestCustomFieldsRt = limitedArraySchema({ codec: CustomFieldRt, diff --git a/x-pack/plugins/cases/common/types/api/configure/v1.test.ts b/x-pack/plugins/cases/common/types/api/configure/v1.test.ts index c16dfbc60eaf7..64baf7b2e46f4 100644 --- a/x-pack/plugins/cases/common/types/api/configure/v1.test.ts +++ b/x-pack/plugins/cases/common/types/api/configure/v1.test.ts @@ -36,6 +36,7 @@ import { CustomFieldConfigurationWithoutTypeRt, TextCustomFieldConfigurationRt, ToggleCustomFieldConfigurationRt, + NumberCustomFieldConfigurationRt, TemplateConfigurationRt, } from './v1'; @@ -79,6 +80,12 @@ describe('configure', () => { type: CustomFieldTypes.TOGGLE, required: false, }, + { + key: 'number_custom_field', + label: 'Number custom field', + type: CustomFieldTypes.NUMBER, + required: false, + }, ], }; const query = ConfigurationRequestRt.decode(request); @@ -512,6 +519,93 @@ describe('configure', () => { }); }); + describe('NumberCustomFieldConfigurationRt', () => { + const defaultRequest = { + key: 'my_number_custom_field', + label: 'Number Custom Field', + type: CustomFieldTypes.NUMBER, + required: true, + }; + + it('has expected attributes in request', () => { + const query = NumberCustomFieldConfigurationRt.decode(defaultRequest); + + expect(query).toStrictEqual({ + _tag: 'Right', + right: { ...defaultRequest }, + }); + }); + + it('has expected attributes in request with defaultValue', () => { + const query = NumberCustomFieldConfigurationRt.decode({ + ...defaultRequest, + defaultValue: 1, + }); + + expect(query).toStrictEqual({ + _tag: 'Right', + right: { ...defaultRequest, defaultValue: 1 }, + }); + }); + + it('removes foo:bar attributes from request', () => { + const query = NumberCustomFieldConfigurationRt.decode({ ...defaultRequest, foo: 'bar' }); + + expect(query).toStrictEqual({ + _tag: 'Right', + right: { ...defaultRequest }, + }); + }); + + it('defaultValue fails if the type is string', () => { + expect( + PathReporter.report( + NumberCustomFieldConfigurationRt.decode({ + ...defaultRequest, + defaultValue: 'string', + }) + )[0] + ).toContain('Invalid value "string" supplied'); + }); + + it('defaultValue fails if the type is boolean', () => { + expect( + PathReporter.report( + NumberCustomFieldConfigurationRt.decode({ + ...defaultRequest, + defaultValue: false, + }) + )[0] + ).toContain('Invalid value false supplied'); + }); + + it(`throws an error if the default value is more than ${Number.MAX_SAFE_INTEGER}`, () => { + expect( + PathReporter.report( + NumberCustomFieldConfigurationRt.decode({ + ...defaultRequest, + defaultValue: Number.MAX_SAFE_INTEGER + 1, + }) + )[0] + ).toContain( + 'The defaultValue field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.' + ); + }); + + it(`throws an error if the default value is less than ${Number.MIN_SAFE_INTEGER}`, () => { + expect( + PathReporter.report( + NumberCustomFieldConfigurationRt.decode({ + ...defaultRequest, + defaultValue: Number.MIN_SAFE_INTEGER - 1, + }) + )[0] + ).toContain( + 'The defaultValue field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.' + ); + }); + }); + describe('TemplateConfigurationRt', () => { const defaultRequest = { key: 'template_key_1', diff --git a/x-pack/plugins/cases/common/types/api/configure/v1.ts b/x-pack/plugins/cases/common/types/api/configure/v1.ts index bd2e1f5c11af0..52843da1ac1ad 100644 --- a/x-pack/plugins/cases/common/types/api/configure/v1.ts +++ b/x-pack/plugins/cases/common/types/api/configure/v1.ts @@ -18,12 +18,19 @@ import { MAX_TEMPLATE_TAG_LENGTH, } from '../../../constants'; import { limitedArraySchema, limitedStringSchema, regexStringRt } from '../../../schema'; -import { CustomFieldTextTypeRt, CustomFieldToggleTypeRt } from '../../domain'; +import { + CustomFieldTextTypeRt, + CustomFieldToggleTypeRt, + CustomFieldNumberTypeRt, +} from '../../domain'; import type { Configurations, Configuration } from '../../domain/configure/v1'; import { ConfigurationBasicWithoutOwnerRt, ClosureTypeRt } from '../../domain/configure/v1'; import { CaseConnectorRt } from '../../domain/connector/v1'; import { CaseBaseOptionalFieldsRequestRt } from '../case/v1'; -import { CaseCustomFieldTextWithValidationValueRt } from '../custom_field/v1'; +import { + CaseCustomFieldTextWithValidationValueRt, + CaseCustomFieldNumberWithValidationValueRt, +} from '../custom_field/v1'; export const CustomFieldConfigurationWithoutTypeRt = rt.strict({ /** @@ -64,8 +71,25 @@ export const ToggleCustomFieldConfigurationRt = rt.intersection([ ), ]); +export const NumberCustomFieldConfigurationRt = rt.intersection([ + rt.strict({ type: CustomFieldNumberTypeRt }), + CustomFieldConfigurationWithoutTypeRt, + rt.exact( + rt.partial({ + defaultValue: rt.union([ + CaseCustomFieldNumberWithValidationValueRt({ fieldName: 'defaultValue' }), + rt.null, + ]), + }) + ), +]); + export const CustomFieldsConfigurationRt = limitedArraySchema({ - codec: rt.union([TextCustomFieldConfigurationRt, ToggleCustomFieldConfigurationRt]), + codec: rt.union([ + TextCustomFieldConfigurationRt, + ToggleCustomFieldConfigurationRt, + NumberCustomFieldConfigurationRt, + ]), min: 0, max: MAX_CUSTOM_FIELDS_PER_CASE, fieldName: 'customFields', diff --git a/x-pack/plugins/cases/common/types/api/custom_field/v1.test.ts b/x-pack/plugins/cases/common/types/api/custom_field/v1.test.ts index 83d9a437c998d..d17c936ff4463 100644 --- a/x-pack/plugins/cases/common/types/api/custom_field/v1.test.ts +++ b/x-pack/plugins/cases/common/types/api/custom_field/v1.test.ts @@ -7,7 +7,11 @@ import { PathReporter } from 'io-ts/lib/PathReporter'; import { MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH } from '../../../constants'; -import { CaseCustomFieldTextWithValidationValueRt, CustomFieldPutRequestRt } from './v1'; +import { + CaseCustomFieldTextWithValidationValueRt, + CustomFieldPutRequestRt, + CaseCustomFieldNumberWithValidationValueRt, +} from './v1'; describe('Custom Fields', () => { describe('CaseCustomFieldTextWithValidationValueRt', () => { @@ -100,4 +104,34 @@ describe('Custom Fields', () => { ).toContain('The value field cannot be an empty string.'); }); }); + + describe('CaseCustomFieldNumberWithValidationValueRt', () => { + const numberCustomFieldValueType = CaseCustomFieldNumberWithValidationValueRt({ + fieldName: 'value', + }); + it('should decode number correctly', () => { + const query = numberCustomFieldValueType.decode(123); + + expect(query).toStrictEqual({ + _tag: 'Right', + right: 123, + }); + }); + + it('should not be more than Number.MAX_SAFE_INTEGER', () => { + expect( + PathReporter.report(numberCustomFieldValueType.decode(Number.MAX_SAFE_INTEGER + 1))[0] + ).toContain( + 'The value field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.' + ); + }); + + it('should not be less than Number.MIN_SAFE_INTEGER', () => { + expect( + PathReporter.report(numberCustomFieldValueType.decode(Number.MIN_SAFE_INTEGER - 1))[0] + ).toContain( + 'The value field should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.' + ); + }); + }); }); diff --git a/x-pack/plugins/cases/common/types/api/custom_field/v1.ts b/x-pack/plugins/cases/common/types/api/custom_field/v1.ts index fb59f187991b3..c3e618278adbe 100644 --- a/x-pack/plugins/cases/common/types/api/custom_field/v1.ts +++ b/x-pack/plugins/cases/common/types/api/custom_field/v1.ts @@ -7,7 +7,7 @@ import * as rt from 'io-ts'; import { MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH } from '../../../constants'; -import { limitedStringSchema } from '../../../schema'; +import { limitedStringSchema, limitedNumberAsIntegerSchema } from '../../../schema'; export const CaseCustomFieldTextWithValidationValueRt = (fieldName: string) => limitedStringSchema({ @@ -16,12 +16,22 @@ export const CaseCustomFieldTextWithValidationValueRt = (fieldName: string) => max: MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH, }); +export const CaseCustomFieldNumberWithValidationValueRt = ({ fieldName }: { fieldName: string }) => + limitedNumberAsIntegerSchema({ + fieldName, + }); + /** * Update custom_field */ export const CustomFieldPutRequestRt = rt.strict({ - value: rt.union([rt.boolean, rt.null, CaseCustomFieldTextWithValidationValueRt('value')]), + value: rt.union([ + rt.boolean, + rt.null, + CaseCustomFieldTextWithValidationValueRt('value'), + CaseCustomFieldNumberWithValidationValueRt({ fieldName: 'value' }), + ]), caseVersion: rt.string, }); diff --git a/x-pack/plugins/cases/common/types/domain/case/v1.test.ts b/x-pack/plugins/cases/common/types/domain/case/v1.test.ts index 267e08d205f15..b0a6f96bcacd0 100644 --- a/x-pack/plugins/cases/common/types/domain/case/v1.test.ts +++ b/x-pack/plugins/cases/common/types/domain/case/v1.test.ts @@ -85,6 +85,11 @@ const basicCase = { type: 'toggle', value: true, }, + { + key: 'third_custom_field_key', + type: 'number', + value: 0, + }, ], }; @@ -193,6 +198,11 @@ describe('CaseAttributesRt', () => { type: 'toggle', value: true, }, + { + key: 'third_custom_field_key', + type: 'number', + value: 0, + }, ], }; diff --git a/x-pack/plugins/cases/common/types/domain/configure/v1.test.ts b/x-pack/plugins/cases/common/types/domain/configure/v1.test.ts index 13637fb4d8c68..59682de1e7c7a 100644 --- a/x-pack/plugins/cases/common/types/domain/configure/v1.test.ts +++ b/x-pack/plugins/cases/common/types/domain/configure/v1.test.ts @@ -16,6 +16,7 @@ import { TemplateConfigurationRt, TextCustomFieldConfigurationRt, ToggleCustomFieldConfigurationRt, + NumberCustomFieldConfigurationRt, } from './v1'; describe('configure', () => { @@ -47,6 +48,13 @@ describe('configure', () => { required: false, }; + const numberCustomField = { + key: 'number_custom_field', + label: 'Number custom field', + type: CustomFieldTypes.NUMBER, + required: false, + }; + const templateWithAllCaseFields = { key: 'template_sample_1', name: 'Sample template 1', @@ -98,7 +106,7 @@ describe('configure', () => { const defaultRequest = { connector: resilient, closure_type: 'close-by-user', - customFields: [textCustomField, toggleCustomField], + customFields: [textCustomField, toggleCustomField, numberCustomField], templates: [], owner: 'cases', created_at: '2020-02-19T23:06:33.798Z', @@ -122,7 +130,7 @@ describe('configure', () => { _tag: 'Right', right: { ...defaultRequest, - customFields: [textCustomField, toggleCustomField], + customFields: [textCustomField, toggleCustomField, numberCustomField], }, }); }); @@ -134,7 +142,7 @@ describe('configure', () => { _tag: 'Right', right: { ...defaultRequest, - customFields: [textCustomField, toggleCustomField], + customFields: [textCustomField, toggleCustomField, numberCustomField], }, }); }); @@ -142,14 +150,14 @@ describe('configure', () => { it('removes foo:bar attributes from custom fields', () => { const query = ConfigurationAttributesRt.decode({ ...defaultRequest, - customFields: [{ ...textCustomField, foo: 'bar' }, toggleCustomField], + customFields: [{ ...textCustomField, foo: 'bar' }, toggleCustomField, numberCustomField], }); expect(query).toStrictEqual({ _tag: 'Right', right: { ...defaultRequest, - customFields: [textCustomField, toggleCustomField], + customFields: [textCustomField, toggleCustomField, numberCustomField], }, }); }); @@ -351,6 +359,62 @@ describe('configure', () => { }); }); + describe('NumberCustomFieldConfigurationRt', () => { + const defaultRequest = { + key: 'my_number_custom_field', + label: 'Number Custom Field', + type: CustomFieldTypes.NUMBER, + required: false, + }; + + it('has expected attributes in request with required: false', () => { + const query = NumberCustomFieldConfigurationRt.decode(defaultRequest); + + expect(query).toStrictEqual({ + _tag: 'Right', + right: { ...defaultRequest }, + }); + }); + + it('has expected attributes in request with defaultValue and required: true', () => { + const query = NumberCustomFieldConfigurationRt.decode({ + ...defaultRequest, + required: true, + defaultValue: 0, + }); + + expect(query).toStrictEqual({ + _tag: 'Right', + right: { + ...defaultRequest, + required: true, + defaultValue: 0, + }, + }); + }); + + it('defaultValue fails if the type is not number', () => { + expect( + PathReporter.report( + NumberCustomFieldConfigurationRt.decode({ + ...defaultRequest, + required: true, + defaultValue: 'foobar', + }) + )[0] + ).toContain('Invalid value "foobar" supplied'); + }); + + it('removes foo:bar attributes from request', () => { + const query = NumberCustomFieldConfigurationRt.decode({ ...defaultRequest, foo: 'bar' }); + + expect(query).toStrictEqual({ + _tag: 'Right', + right: { ...defaultRequest }, + }); + }); + }); + describe('TemplateConfigurationRt', () => { const defaultRequest = templateWithAllCaseFields; diff --git a/x-pack/plugins/cases/common/types/domain/configure/v1.ts b/x-pack/plugins/cases/common/types/domain/configure/v1.ts index 1e4e30c95e381..17760922d2cda 100644 --- a/x-pack/plugins/cases/common/types/domain/configure/v1.ts +++ b/x-pack/plugins/cases/common/types/domain/configure/v1.ts @@ -8,7 +8,11 @@ import * as rt from 'io-ts'; import { CaseConnectorRt, ConnectorMappingsRt } from '../connector/v1'; import { UserRt } from '../user/v1'; -import { CustomFieldTextTypeRt, CustomFieldToggleTypeRt } from '../custom_field/v1'; +import { + CustomFieldTextTypeRt, + CustomFieldToggleTypeRt, + CustomFieldNumberTypeRt, +} from '../custom_field/v1'; import { CaseBaseOptionalFieldsRt } from '../case/v1'; export const ClosureTypeRt = rt.union([ @@ -51,9 +55,20 @@ export const ToggleCustomFieldConfigurationRt = rt.intersection([ ), ]); +export const NumberCustomFieldConfigurationRt = rt.intersection([ + rt.strict({ type: CustomFieldNumberTypeRt }), + CustomFieldConfigurationWithoutTypeRt, + rt.exact( + rt.partial({ + defaultValue: rt.union([rt.number, rt.null]), + }) + ), +]); + export const CustomFieldConfigurationRt = rt.union([ TextCustomFieldConfigurationRt, ToggleCustomFieldConfigurationRt, + NumberCustomFieldConfigurationRt, ]); export const CustomFieldsConfigurationRt = rt.array(CustomFieldConfigurationRt); diff --git a/x-pack/plugins/cases/common/types/domain/custom_field/v1.test.ts b/x-pack/plugins/cases/common/types/domain/custom_field/v1.test.ts index ea57d3e3201c1..5513325d30fb0 100644 --- a/x-pack/plugins/cases/common/types/domain/custom_field/v1.test.ts +++ b/x-pack/plugins/cases/common/types/domain/custom_field/v1.test.ts @@ -42,6 +42,22 @@ describe('CaseCustomFieldRt', () => { value: null, }, ], + [ + 'type number value number', + { + key: 'number_custom_field_1', + type: 'number', + value: 1, + }, + ], + [ + 'type number value null', + { + key: 'number_custom_field_2', + type: 'number', + value: null, + }, + ], ])(`has expected attributes for customField with %s`, (_, customField) => { const query = CaseCustomFieldRt.decode(customField); @@ -70,4 +86,14 @@ describe('CaseCustomFieldRt', () => { expect(PathReporter.report(query)[0]).toContain('Invalid value "hello" supplied'); }); + + it('fails if number type but value is a string', () => { + const query = CaseCustomFieldRt.decode({ + key: 'list_custom_field_1', + type: 'number', + value: 'hi', + }); + + expect(PathReporter.report(query)[0]).toContain('Invalid value "hi" supplied'); + }); }); diff --git a/x-pack/plugins/cases/common/types/domain/custom_field/v1.ts b/x-pack/plugins/cases/common/types/domain/custom_field/v1.ts index 4878fea326b04..d0f9404f8f113 100644 --- a/x-pack/plugins/cases/common/types/domain/custom_field/v1.ts +++ b/x-pack/plugins/cases/common/types/domain/custom_field/v1.ts @@ -9,10 +9,12 @@ import * as rt from 'io-ts'; export enum CustomFieldTypes { TEXT = 'text', TOGGLE = 'toggle', + NUMBER = 'number', } export const CustomFieldTextTypeRt = rt.literal(CustomFieldTypes.TEXT); export const CustomFieldToggleTypeRt = rt.literal(CustomFieldTypes.TOGGLE); +export const CustomFieldNumberTypeRt = rt.literal(CustomFieldTypes.NUMBER); const CaseCustomFieldTextRt = rt.strict({ key: rt.string, @@ -26,10 +28,21 @@ export const CaseCustomFieldToggleRt = rt.strict({ value: rt.union([rt.boolean, rt.null]), }); -export const CaseCustomFieldRt = rt.union([CaseCustomFieldTextRt, CaseCustomFieldToggleRt]); +export const CaseCustomFieldNumberRt = rt.strict({ + key: rt.string, + type: CustomFieldNumberTypeRt, + value: rt.union([rt.number, rt.null]), +}); + +export const CaseCustomFieldRt = rt.union([ + CaseCustomFieldTextRt, + CaseCustomFieldToggleRt, + CaseCustomFieldNumberRt, +]); export const CaseCustomFieldsRt = rt.array(CaseCustomFieldRt); export type CaseCustomFields = rt.TypeOf; export type CaseCustomField = rt.TypeOf; export type CaseCustomFieldToggle = rt.TypeOf; export type CaseCustomFieldText = rt.TypeOf; +export type CaseCustomFieldNumber = rt.TypeOf; diff --git a/x-pack/plugins/cases/public/common/translations.ts b/x-pack/plugins/cases/public/common/translations.ts index 2e11c3a64caae..7fa5b54db00ec 100644 --- a/x-pack/plugins/cases/public/common/translations.ts +++ b/x-pack/plugins/cases/public/common/translations.ts @@ -300,6 +300,12 @@ export const MAX_LENGTH_ERROR = (field: string, length: number) => 'The length of the {field} is too long. The maximum length is {length} characters.', }); +export const SAFE_INTEGER_NUMBER_ERROR = (field: string) => + i18n.translate('xpack.cases.customFields.safeIntegerNumberError', { + values: { field }, + defaultMessage: `The value of the {field} should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.`, + }); + export const MAX_TAGS_ERROR = (length: number) => i18n.translate('xpack.cases.createCase.maxTagsError', { values: { length }, diff --git a/x-pack/plugins/cases/public/components/all_cases/columns_popover.test.tsx b/x-pack/plugins/cases/public/components/all_cases/columns_popover.test.tsx index 7746c5f0a4f1b..84f2c9f3726d6 100644 --- a/x-pack/plugins/cases/public/components/all_cases/columns_popover.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/columns_popover.test.tsx @@ -14,7 +14,8 @@ import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; import { ColumnsPopover } from './columns_popover'; -describe('ColumnsPopover', () => { +// FLAKY: https://github.com/elastic/kibana/issues/174682 +describe.skip('ColumnsPopover', () => { let appMockRenderer: AppMockRenderer; beforeEach(() => { diff --git a/x-pack/plugins/cases/public/components/case_form_fields/custom_fields.test.tsx b/x-pack/plugins/cases/public/components/case_form_fields/custom_fields.test.tsx index f11e5826ca91c..9a96b0a342771 100644 --- a/x-pack/plugins/cases/public/components/case_form_fields/custom_fields.test.tsx +++ b/x-pack/plugins/cases/public/components/case_form_fields/custom_fields.test.tsx @@ -78,7 +78,7 @@ describe.skip('CustomFields', () => { ); - expect(await screen.findAllByTestId('form-optional-field-label')).toHaveLength(2); + expect(await screen.findAllByTestId('form-optional-field-label')).toHaveLength(4); }); it('should not set default value when in edit mode', async () => { @@ -115,12 +115,14 @@ describe.skip('CustomFields', () => { const customFields = customFieldsWrapper.querySelectorAll('.euiFormRow'); - expect(customFields).toHaveLength(4); + expect(customFields).toHaveLength(6); expect(customFields[0]).toHaveTextContent('My test label 1'); expect(customFields[1]).toHaveTextContent('My test label 2'); expect(customFields[2]).toHaveTextContent('My test label 3'); expect(customFields[3]).toHaveTextContent('My test label 4'); + expect(customFields[4]).toHaveTextContent('My test label 5'); + expect(customFields[5]).toHaveTextContent('My test label 6'); }); it('should update the custom fields', async () => { @@ -132,6 +134,7 @@ describe.skip('CustomFields', () => { const textField = customFieldsConfigurationMock[2]; const toggleField = customFieldsConfigurationMock[3]; + const numberField = customFieldsConfigurationMock[5]; await userEvent.type( await screen.findByTestId(`${textField.key}-${textField.type}-create-custom-field`), @@ -140,6 +143,10 @@ describe.skip('CustomFields', () => { await userEvent.click( await screen.findByTestId(`${toggleField.key}-${toggleField.type}-create-custom-field`) ); + await userEvent.type( + await screen.findByTestId(`${numberField.key}-${numberField.type}-create-custom-field`), + '4' + ); await userEvent.click(await screen.findByText('Submit')); @@ -152,6 +159,8 @@ describe.skip('CustomFields', () => { [customFieldsConfigurationMock[1].key]: customFieldsConfigurationMock[1].defaultValue, [textField.key]: 'hello', [toggleField.key]: true, + [customFieldsConfigurationMock[4].key]: customFieldsConfigurationMock[4].defaultValue, + [numberField.key]: '4', }, }, true diff --git a/x-pack/plugins/cases/public/components/case_form_fields/index.test.tsx b/x-pack/plugins/cases/public/components/case_form_fields/index.test.tsx index ac162e41a47e4..438b0a24841e9 100644 --- a/x-pack/plugins/cases/public/components/case_form_fields/index.test.tsx +++ b/x-pack/plugins/cases/public/components/case_form_fields/index.test.tsx @@ -206,6 +206,7 @@ describe('CaseFormFields', () => { const textField = customFieldsConfigurationMock[0]; const toggleField = customFieldsConfigurationMock[1]; + const numberField = customFieldsConfigurationMock[4]; const textCustomField = await screen.findByTestId( `${textField.key}-${textField.type}-create-custom-field` @@ -219,6 +220,13 @@ describe('CaseFormFields', () => { await screen.findByTestId(`${toggleField.key}-${toggleField.type}-create-custom-field`) ); + const numberCustomField = await screen.findByTestId( + `${numberField.key}-${numberField.type}-create-custom-field` + ); + + await user.clear(numberCustomField); + await user.paste('4321'); + await user.click(await screen.findByText('Submit')); await waitFor(() => { @@ -230,6 +238,7 @@ describe('CaseFormFields', () => { test_key_1: 'My text test value 1', test_key_2: false, test_key_4: false, + test_key_5: '4321', }, }, true @@ -268,6 +277,7 @@ describe('CaseFormFields', () => { test_key_1: 'Test custom filed value', test_key_2: true, test_key_4: false, + test_key_5: 123, }, }, true diff --git a/x-pack/plugins/cases/public/components/case_view/components/custom_fields.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/custom_fields.test.tsx index 3b9d762137abb..67d8f8fd05764 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/custom_fields.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/custom_fields.test.tsx @@ -89,7 +89,7 @@ describe('Case View Page files tab', () => { exact: false, }); - expect(customFields.length).toBe(4); + expect(customFields.length).toBe(6); expect(await within(customFields[0]).findByRole('heading')).toHaveTextContent( 'My test label 1' @@ -103,6 +103,12 @@ describe('Case View Page files tab', () => { expect(await within(customFields[3]).findByRole('heading')).toHaveTextContent( 'My test label 4' ); + expect(await within(customFields[4]).findByRole('heading')).toHaveTextContent( + 'My test label 5' + ); + expect(await within(customFields[5]).findByRole('heading')).toHaveTextContent( + 'My test label 6' + ); }); it('pass the permissions to custom fields correctly', async () => { diff --git a/x-pack/plugins/cases/public/components/category/category_form_field.test.tsx b/x-pack/plugins/cases/public/components/category/category_form_field.test.tsx index 87477a5f84a75..8380276e3e106 100644 --- a/x-pack/plugins/cases/public/components/category/category_form_field.test.tsx +++ b/x-pack/plugins/cases/public/components/category/category_form_field.test.tsx @@ -16,7 +16,8 @@ import { categories } from '../../containers/mock'; import { MAX_CATEGORY_LENGTH } from '../../../common/constants'; import { FormTestComponent } from '../../common/test_utils'; -describe('Category', () => { +// FLAKY: https://github.com/elastic/kibana/issues/189739 +describe.skip('Category', () => { let appMockRender: AppMockRenderer; const onSubmit = jest.fn(); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx index 0769e7a29cc59..1dc3346a72da6 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx @@ -21,12 +21,20 @@ import { import { ConnectorsDropdown } from './connectors_dropdown'; import { connectors, actionTypes } from './__mock__'; import { ConnectorTypes } from '../../../common/types/domain'; +import userEvent from '@testing-library/user-event'; +import { useApplicationCapabilities } from '../../common/lib/kibana'; + +const useApplicationCapabilitiesMock = useApplicationCapabilities as jest.Mocked< + typeof useApplicationCapabilities +>; +jest.mock('../../common/lib/kibana'); describe('Connectors', () => { let wrapper: ReactWrapper; let appMockRender: AppMockRenderer; const onChangeConnector = jest.fn(); const handleShowEditFlyout = jest.fn(); + const onAddNewConnector = jest.fn(); const props: Props = { actionTypes, @@ -38,6 +46,7 @@ describe('Connectors', () => { onChangeConnector, selectedConnector: { id: 'none', type: ConnectorTypes.none }, updateConnectorDisabled: false, + onAddNewConnector, }; beforeAll(() => { @@ -104,12 +113,16 @@ describe('Connectors', () => { }); it('shows the add connector button', () => { - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); + appMockRender.render(); - expect( - wrapper.find('button[data-test-subj="dropdown-connector-add-connector"]').exists() - ).toBeTruthy(); + expect(screen.getByTestId('add-new-connector')).toBeInTheDocument(); + }); + + it('shows the add connector flyout when the button is clicked', async () => { + appMockRender.render(); + + await userEvent.click(await screen.findByTestId('add-new-connector')); + expect(onAddNewConnector).toHaveBeenCalled(); }); it('the text of the update button is shown correctly', () => { @@ -156,16 +169,14 @@ describe('Connectors', () => { }); it('shows the actions permission message if the user does not have read access to actions', async () => { - appMockRender.coreStart.application.capabilities = { - ...appMockRender.coreStart.application.capabilities, - actions: { save: false, show: false }, - }; + useApplicationCapabilitiesMock().actions = { crud: false, read: false }; + + appMockRender.render(); - const result = appMockRender.render(); expect( - result.getByTestId('configure-case-connector-permissions-error-msg') + await screen.findByTestId('configure-case-connector-permissions-error-msg') ).toBeInTheDocument(); - expect(result.queryByTestId('case-connectors-dropdown')).toBe(null); + expect(screen.queryByTestId('case-connectors-dropdown')).not.toBeInTheDocument(); }); it('shows the actions permission message if the user does not have access to case connector', async () => { @@ -177,4 +188,12 @@ describe('Connectors', () => { ).toBeInTheDocument(); expect(result.queryByTestId('case-connectors-dropdown')).toBe(null); }); + + it('it should hide the "Add Connector" button when the user lacks the capability to add a new connector', () => { + useApplicationCapabilitiesMock().actions = { crud: false, read: true }; + + appMockRender.render(); + + expect(screen.queryByTestId('add-new-connector')).not.toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx index b1ab16109c28f..3d742a202a0b7 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx @@ -13,10 +13,9 @@ import { EuiFlexItem, EuiLink, EuiText, + EuiButtonEmpty, } from '@elastic/eui'; -import { css } from '@emotion/react'; - import { ConnectorsDropdown } from './connectors_dropdown'; import * as i18n from './translations'; @@ -39,6 +38,7 @@ export interface Props { onChangeConnector: (id: string) => void; selectedConnector: { id: string; type: ConnectorTypes }; updateConnectorDisabled: boolean; + onAddNewConnector: () => void; } const ConnectorsComponent: React.FC = ({ actionTypes, @@ -50,8 +50,10 @@ const ConnectorsComponent: React.FC = ({ onChangeConnector, selectedConnector, updateConnectorDisabled, + onAddNewConnector, }) => { const { actions } = useApplicationCapabilities(); + const canSave = actions.crud; const connector = useMemo( () => connectors.find((c) => c.id === selectedConnector.id), [connectors, selectedConnector.id] @@ -95,13 +97,19 @@ const ConnectorsComponent: React.FC = ({ > + {i18n.ADD_CONNECTOR} + + ) : null + } > @@ -113,7 +121,6 @@ const ConnectorsComponent: React.FC = ({ isLoading={isLoading} onChange={onChangeConnector} data-test-subj="case-connectors-dropdown" - appendAddConnectorButton={true} /> ) : ( diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx index faabf3f42c70f..30c45453ebc17 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx @@ -15,13 +15,6 @@ import type { Props } from './connectors_dropdown'; import { ConnectorsDropdown } from './connectors_dropdown'; import { TestProviders } from '../../common/mock'; import { connectors } from './__mock__'; -import userEvent from '@testing-library/user-event'; -import { useApplicationCapabilities } from '../../common/lib/kibana'; - -const useApplicationCapabilitiesMock = useApplicationCapabilities as jest.Mocked< - typeof useApplicationCapabilities ->; -jest.mock('../../common/lib/kibana'); describe('ConnectorsDropdown', () => { let wrapper: ReactWrapper; @@ -388,23 +381,4 @@ describe('ConnectorsDropdown', () => { ); expect(tooltips[0]).toBeInTheDocument(); }); - - test('it should hide the "Add New Connector" button when the user lacks the capability to add a new connector', async () => { - const selectedConnector = 'none'; - useApplicationCapabilitiesMock().actions = { crud: false, read: true }; - render( - {}} - />, - { wrapper: ({ children }) => {children} } - ); - - await userEvent.click(screen.getByTestId('dropdown-connectors')); - expect(screen.queryByTestId('dropdown-connector-add-connector')).not.toBeInTheDocument(); - }); }); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx index 71df212399bc2..04fa9e3ef3647 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx @@ -6,7 +6,6 @@ */ import React, { Suspense, useMemo } from 'react'; -import type { EuiThemeComputed } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, @@ -20,7 +19,7 @@ import { css } from '@emotion/react'; import type { ActionConnector } from '../../containers/configure/types'; import * as i18n from './translations'; -import { useApplicationCapabilities, useKibana } from '../../common/lib/kibana'; +import { useKibana } from '../../common/lib/kibana'; import { getConnectorIcon, isDeprecatedConnector } from '../utils'; export interface Props { @@ -29,7 +28,6 @@ export interface Props { isLoading: boolean; onChange: (id: string) => void; selectedConnector: string; - appendAddConnectorButton?: boolean; } const suspendedComponentWithProps = (ComponentToSuspend: React.ComponentType) => { @@ -65,37 +63,14 @@ const noConnectorOption = { 'data-test-subj': 'dropdown-connector-no-connector', }; -const addNewConnector = (euiTheme: EuiThemeComputed<{}>) => ({ - value: 'add-connector', - inputDisplay: ( - - {i18n.ADD_NEW_CONNECTOR} - - ), - 'data-test-subj': 'dropdown-connector-add-connector', -}); - const ConnectorsDropdownComponent: React.FC = ({ connectors, disabled, isLoading, onChange, selectedConnector, - appendAddConnectorButton = false, }) => { const { triggersActionsUi } = useKibana().services; - const { actions } = useApplicationCapabilities(); - const canSave = actions.crud; const { euiTheme } = useEuiTheme(); const connectorsAsOptions = useMemo(() => { const connectorsFormatted = connectors.reduce( @@ -152,10 +127,6 @@ const ConnectorsDropdownComponent: React.FC = ({ [noConnectorOption] ); - if (appendAddConnectorButton && canSave) { - return [...connectorsFormatted, addNewConnector(euiTheme)]; - } - return connectorsFormatted; // eslint-disable-next-line react-hooks/exhaustive-deps }, [connectors]); diff --git a/x-pack/plugins/cases/public/components/configure_cases/flyout.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/flyout.test.tsx index b3c782f83fb50..8b42dd7df6f0d 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/flyout.test.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/flyout.test.tsx @@ -612,6 +612,16 @@ describe('CommonFlyout ', () => { type: 'toggle', value: false, }, + { + key: 'test_key_5', + type: 'number', + value: 123, + }, + { + key: 'test_key_6', + type: 'number', + value: null, + }, ], }, }); diff --git a/x-pack/plugins/cases/public/components/configure_cases/index.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/index.test.tsx index 6c65eae41c78b..7a29c959d2525 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/index.test.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/index.test.tsx @@ -565,8 +565,7 @@ describe('ConfigureCases', () => { wrappingComponent: TestProviders as ComponentType>, }); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.find('button[data-test-subj="dropdown-connector-add-connector"]').simulate('click'); + wrapper.find('button[data-test-subj="add-new-connector"]').simulate('click'); await waitFor(() => { wrapper.update(); @@ -716,6 +715,8 @@ describe('ConfigureCases', () => { { ...customFieldsConfigurationMock[1] }, { ...customFieldsConfigurationMock[2] }, { ...customFieldsConfigurationMock[3] }, + { ...customFieldsConfigurationMock[4] }, + { ...customFieldsConfigurationMock[5] }, ], templates: [], id: '', @@ -775,6 +776,8 @@ describe('ConfigureCases', () => { { ...customFieldsConfigurationMock[1] }, { ...customFieldsConfigurationMock[2] }, { ...customFieldsConfigurationMock[3] }, + { ...customFieldsConfigurationMock[4] }, + { ...customFieldsConfigurationMock[5] }, ], templates: [ { @@ -868,6 +871,16 @@ describe('ConfigureCases', () => { type: customFieldsConfigurationMock[3].type, value: false, }, + { + key: customFieldsConfigurationMock[4].key, + type: customFieldsConfigurationMock[4].type, + value: customFieldsConfigurationMock[4].defaultValue, + }, + { + key: customFieldsConfigurationMock[5].key, + type: customFieldsConfigurationMock[5].type, + value: null, + }, { key: expect.anything(), type: CustomFieldTypes.TEXT as const, @@ -931,6 +944,8 @@ describe('ConfigureCases', () => { { ...customFieldsConfigurationMock[1] }, { ...customFieldsConfigurationMock[2] }, { ...customFieldsConfigurationMock[3] }, + { ...customFieldsConfigurationMock[4] }, + { ...customFieldsConfigurationMock[5] }, ], templates: [], id: '', @@ -1108,6 +1123,16 @@ describe('ConfigureCases', () => { type: customFieldsConfigurationMock[3].type, value: false, // when no default value for toggle, we set it to false }, + { + key: customFieldsConfigurationMock[4].key, + type: customFieldsConfigurationMock[4].type, + value: customFieldsConfigurationMock[4].defaultValue, + }, + { + key: customFieldsConfigurationMock[5].key, + type: customFieldsConfigurationMock[5].type, + value: null, + }, ], }, }, diff --git a/x-pack/plugins/cases/public/components/configure_cases/index.tsx b/x-pack/plugins/cases/public/components/configure_cases/index.tsx index 61f99a46a0b08..641482ceca4fe 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/index.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/index.tsx @@ -215,6 +215,10 @@ export const ConfigureCases: React.FC = React.memo(() => { [] ); + const onAddNewConnector = useCallback(() => { + setFlyOutVisibility({ type: 'addConnector', visible: true }); + }, []); + const onChangeConnector = useCallback( (id: string) => { if (id === 'add-connector') { @@ -577,6 +581,7 @@ export const ConfigureCases: React.FC = React.memo(() => { onChangeConnector={onChangeConnector} selectedConnector={connector} updateConnectorDisabled={updateConnectorDisabled || !permissions.update} + onAddNewConnector={onAddNewConnector} />

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�_I|vJrqUFZ@j=gX7gLA!ei%)oEVc3) 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%0Ak+~xwxf7)t0hxgg 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 $z4W$cnrAs%ZE7WE8ncCHm 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Ða!umRotAkXT@= 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

diff --git a/x-pack/plugins/cases/public/components/configure_cases/translations.ts b/x-pack/plugins/cases/public/components/configure_cases/translations.ts index 7a2e0e84b0306..4fe462655dcc1 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/translations.ts +++ b/x-pack/plugins/cases/public/components/configure_cases/translations.ts @@ -35,6 +35,10 @@ export const ADD_NEW_CONNECTOR = i18n.translate('xpack.cases.configureCases.addN defaultMessage: 'Add new connector', }); +export const ADD_CONNECTOR = i18n.translate('xpack.cases.configureCases.addConnector', { + defaultMessage: 'Add connector', +}); + export const CASE_CLOSURE_OPTIONS_TITLE = i18n.translate( 'xpack.cases.configureCases.caseClosureOptionsTitle', { diff --git a/x-pack/plugins/cases/public/components/connector_selector/form.tsx b/x-pack/plugins/cases/public/components/connector_selector/form.tsx index fa991bc5b9871..2419aa60b148f 100644 --- a/x-pack/plugins/cases/public/components/connector_selector/form.tsx +++ b/x-pack/plugins/cases/public/components/connector_selector/form.tsx @@ -12,9 +12,17 @@ import { css } from '@emotion/react'; import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { getFieldValidityAndErrorMessage } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { i18n } from '@kbn/i18n'; import type { ActionConnector } from '../../../common/types/domain'; import { ConnectorsDropdown } from '../configure_cases/connectors_dropdown'; +const ADD_CONNECTOR_HELPER_TEXT = i18n.translate( + 'xpack.cases.connectorSelector.addConnectorHelperText', + { + defaultMessage: 'Go to Cases > Settings to add an external incident management system', + } +); + interface ConnectorSelectorProps { connectors: ActionConnector[]; dataTestSubj: string; @@ -60,7 +68,7 @@ export const ConnectorSelector = ({ describedByIds={idAria ? [idAria] : undefined} error={errorMessage} fullWidth - helpText={field.helpText} + helpText={ADD_CONNECTOR_HELPER_TEXT} isInvalid={isInvalid} label={field.label} labelAppend={field.labelAppend} diff --git a/x-pack/plugins/cases/public/components/create/form_context.test.tsx b/x-pack/plugins/cases/public/components/create/form_context.test.tsx index 0f28e6f9db1c2..252726ef559c9 100644 --- a/x-pack/plugins/cases/public/components/create/form_context.test.tsx +++ b/x-pack/plugins/cases/public/components/create/form_context.test.tsx @@ -517,6 +517,7 @@ describe('Create case', () => { const textField = customFieldsConfigurationMock[0]; const toggleField = customFieldsConfigurationMock[1]; + const numberField = customFieldsConfigurationMock[4]; expect(await screen.findByTestId('caseCustomFields')).toBeInTheDocument(); @@ -532,6 +533,14 @@ describe('Create case', () => { await screen.findByTestId(`${toggleField.key}-${toggleField.type}-create-custom-field`) ); + const numberCustomField = await screen.findByTestId( + `${numberField.key}-${numberField.type}-create-custom-field` + ); + + await user.clear(numberCustomField); + await user.click(numberCustomField); + await user.paste('678'); + await user.click(await screen.findByTestId('create-case-submit')); await waitFor(() => expect(postCase).toHaveBeenCalled()); @@ -544,6 +553,8 @@ describe('Create case', () => { { ...customFieldsMock[1], value: false }, // toggled the default customFieldsMock[2], { ...customFieldsMock[3], value: false }, + { ...customFieldsMock[4], value: 678 }, + customFieldsMock[5], { key: 'my_custom_field_key', type: CustomFieldTypes.TEXT, diff --git a/x-pack/plugins/cases/public/components/custom_fields/builder.tsx b/x-pack/plugins/cases/public/components/custom_fields/builder.tsx index d2ee25d08bfa6..4baf050fd0f52 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/builder.tsx +++ b/x-pack/plugins/cases/public/components/custom_fields/builder.tsx @@ -9,8 +9,10 @@ import type { CustomFieldBuilderMap } from './types'; import { CustomFieldTypes } from '../../../common/types/domain'; import { configureTextCustomFieldFactory } from './text/configure_text_field'; import { configureToggleCustomFieldFactory } from './toggle/configure_toggle_field'; +import { configureNumberCustomFieldFactory } from './number/configure_number_field'; export const builderMap = Object.freeze({ [CustomFieldTypes.TEXT]: configureTextCustomFieldFactory, [CustomFieldTypes.TOGGLE]: configureToggleCustomFieldFactory, + [CustomFieldTypes.NUMBER]: configureNumberCustomFieldFactory, } as const) as CustomFieldBuilderMap; diff --git a/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.test.tsx index eaaa0e28747ea..0f87c04bc9ad3 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.test.tsx +++ b/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.test.tsx @@ -59,13 +59,20 @@ describe('CustomFieldsList', () => { ) ).toBeInTheDocument(); expect((await screen.findAllByText('Text')).length).toBe(2); - expect((await screen.findAllByText('Required')).length).toBe(2); + expect((await screen.findAllByText('Required')).length).toBe(3); expect( await screen.findByTestId( `custom-field-${customFieldsConfigurationMock[1].key}-${customFieldsConfigurationMock[1].type}` ) ).toBeInTheDocument(); expect((await screen.findAllByText('Toggle')).length).toBe(2); + + expect( + await screen.findByTestId( + `custom-field-${customFieldsConfigurationMock[4].key}-${customFieldsConfigurationMock[4].type}` + ) + ).toBeInTheDocument(); + expect((await screen.findAllByText('Number')).length).toBe(2); }); it('shows single CustomFieldsList correctly', async () => { diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/config.ts b/x-pack/plugins/cases/public/components/custom_fields/number/config.ts new file mode 100644 index 0000000000000..b73bc033883a8 --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/config.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FieldConfig } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; +import { REQUIRED_FIELD, SAFE_INTEGER_NUMBER_ERROR } from '../translations'; + +const { emptyField } = fieldValidators; + +export const getNumberFieldConfig = ({ + required, + label, + defaultValue, +}: { + required: boolean; + label: string; + defaultValue?: number; +}): FieldConfig => { + const validators = []; + + if (required) { + validators.push({ + validator: emptyField(REQUIRED_FIELD(label)), + }); + } + + return { + ...(defaultValue && { defaultValue }), + validations: [ + ...validators, + { + validator: ({ value }) => { + if (value == null) { + return; + } + const numericValue = Number(value); + + if (!Number.isSafeInteger(numericValue)) { + return { message: SAFE_INTEGER_NUMBER_ERROR(label) }; + } + }, + }, + ], + }; +}; diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/configure.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/configure.test.tsx new file mode 100644 index 0000000000000..f96e47ce30918 --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/configure.test.tsx @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { FormTestComponent } from '../../../common/test_utils'; +import * as i18n from '../translations'; +import { Configure } from './configure'; + +describe('Configure ', () => { + const onSubmit = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders correctly', async () => { + render( + + + + ); + + expect(screen.getByText(i18n.FIELD_OPTION_REQUIRED)).toBeInTheDocument(); + }); + + it('updates field options without default value correctly when not required', async () => { + render( + + + + ); + + await userEvent.click(await screen.findByTestId('form-test-component-submit-button')); + + await waitFor(() => { + // data, isValid + expect(onSubmit).toBeCalledWith({}, true); + }); + }); + + it('updates field options with default value correctly when not required', async () => { + render( + + + + ); + + await userEvent.click(await screen.findByTestId('number-custom-field-default-value')); + await userEvent.paste('123'); + await userEvent.click(await screen.findByTestId('form-test-component-submit-button')); + + await waitFor(() => { + // data, isValid + expect(onSubmit).toBeCalledWith({ defaultValue: '123' }, true); + }); + }); + + it('updates field options with default value correctly when required', async () => { + render( + + + + ); + + await userEvent.click(await screen.findByTestId('number-custom-field-required')); + await userEvent.click(await screen.findByTestId('number-custom-field-default-value')); + await userEvent.paste('123'); + await userEvent.click(await screen.findByTestId('form-test-component-submit-button')); + + await waitFor(() => { + // data, isValid + expect(onSubmit).toBeCalledWith( + { + required: true, + defaultValue: '123', + }, + true + ); + }); + }); + + it('updates field options without default value correctly when required', async () => { + render( + + + + ); + + await userEvent.click(await screen.findByTestId('number-custom-field-required')); + await userEvent.click(await screen.findByTestId('form-test-component-submit-button')); + + await waitFor(() => { + // data, isValid + expect(onSubmit).toBeCalledWith( + { + required: true, + }, + true + ); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/configure.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/configure.tsx new file mode 100644 index 0000000000000..db1fcffd0be0b --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/configure.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { CheckBoxField, NumericField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import type { CaseCustomFieldNumber } from '../../../../common/types/domain'; +import type { CustomFieldType } from '../types'; +import { getNumberFieldConfig } from './config'; +import * as i18n from '../translations'; + +const ConfigureComponent: CustomFieldType['Configure'] = () => { + const config = getNumberFieldConfig({ + required: false, + label: i18n.DEFAULT_VALUE.toLocaleLowerCase(), + }); + + return ( + <> + + + + ); +}; + +ConfigureComponent.displayName = 'Configure'; + +export const Configure = React.memo(ConfigureComponent); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/configure_number_field.test.ts b/x-pack/plugins/cases/public/components/custom_fields/number/configure_number_field.test.ts new file mode 100644 index 0000000000000..aee9a4439792d --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/configure_number_field.test.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { configureNumberCustomFieldFactory } from './configure_number_field'; + +describe('configureTextCustomFieldFactory ', () => { + const builder = configureNumberCustomFieldFactory(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders correctly', async () => { + expect(builder).toEqual({ + id: 'number', + label: 'Number', + getEuiTableColumn: expect.any(Function), + build: expect.any(Function), + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/configure_number_field.ts b/x-pack/plugins/cases/public/components/custom_fields/number/configure_number_field.ts new file mode 100644 index 0000000000000..428559f5f83c0 --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/configure_number_field.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { CustomFieldFactory } from '../types'; +import type { CaseCustomFieldNumber } from '../../../../common/types/domain'; + +import { CustomFieldTypes } from '../../../../common/types/domain'; +import * as i18n from '../translations'; +import { getEuiTableColumn } from './get_eui_table_column'; +import { Edit } from './edit'; +import { View } from './view'; +import { Configure } from './configure'; +import { Create } from './create'; + +export const configureNumberCustomFieldFactory: CustomFieldFactory = () => ({ + id: CustomFieldTypes.NUMBER, + label: i18n.NUMBER_LABEL, + getEuiTableColumn, + build: () => ({ + Configure, + Edit, + View, + Create, + }), +}); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx new file mode 100644 index 0000000000000..2a8a515df01ee --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx @@ -0,0 +1,225 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { FormTestComponent } from '../../../common/test_utils'; +import { Create } from './create'; +import { customFieldsConfigurationMock } from '../../../containers/mock'; + +describe('Create ', () => { + const onSubmit = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + // required number custom field with a default value + const customFieldConfiguration = customFieldsConfigurationMock[4]; + + it('renders correctly with default value and required', async () => { + render( + + + + ); + + expect(await screen.findByText(customFieldConfiguration.label)).toBeInTheDocument(); + + expect( + await screen.findByTestId(`${customFieldConfiguration.key}-number-create-custom-field`) + ).toHaveValue(customFieldConfiguration.defaultValue as number); + }); + + it('renders correctly without default value and not required', async () => { + const optionalField = customFieldsConfigurationMock[5]; // optional number custom field + + render( + + + + ); + + expect(await screen.findByText(optionalField.label)).toBeInTheDocument(); + expect( + await screen.findByTestId(`${optionalField.key}-number-create-custom-field`) + ).toHaveValue(null); + }); + + it('does not render default value when setDefaultValue is false', async () => { + render( + + + + ); + + expect( + await screen.findByTestId(`${customFieldConfiguration.key}-number-create-custom-field`) + ).toHaveValue(null); + }); + + it('renders loading state correctly', async () => { + render( + + + + ); + + expect(await screen.findByRole('progressbar')).toBeInTheDocument(); + }); + + it('disables the text when loading', async () => { + render( + + + + ); + + expect( + await screen.findByTestId(`${customFieldConfiguration.key}-number-create-custom-field`) + ).toHaveAttribute('disabled'); + }); + + it('updates the value correctly', async () => { + render( + + + + ); + + const numberCustomField = await screen.findByTestId( + `${customFieldConfiguration.key}-number-create-custom-field` + ); + + await userEvent.clear(numberCustomField); + await userEvent.click(numberCustomField); + await userEvent.paste('1234'); + await userEvent.click(await screen.findByText('Submit')); + + await waitFor(() => { + // data, isValid + expect(onSubmit).toHaveBeenCalledWith( + { + customFields: { + [customFieldConfiguration.key]: '1234', + }, + }, + true + ); + }); + }); + + it('shows error when number is too big', async () => { + render( + + + + ); + + const numberCustomField = await screen.findByTestId( + `${customFieldConfiguration.key}-number-create-custom-field` + ); + + await userEvent.clear(numberCustomField); + await userEvent.click(numberCustomField); + await userEvent.paste(`${Number.MAX_SAFE_INTEGER + 1}`); + + await userEvent.click(await screen.findByText('Submit')); + + expect( + await screen.findByText( + 'The value of the My test label 5 should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.' + ) + ).toBeInTheDocument(); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({}, false); + }); + }); + + it('shows error when number is too small', async () => { + render( + + + + ); + + const numberCustomField = await screen.findByTestId( + `${customFieldConfiguration.key}-number-create-custom-field` + ); + + await userEvent.clear(numberCustomField); + await userEvent.click(numberCustomField); + await userEvent.paste(`${Number.MIN_SAFE_INTEGER - 1}`); + + await userEvent.click(await screen.findByText('Submit')); + + expect( + await screen.findByText( + 'The value of the My test label 5 should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.' + ) + ).toBeInTheDocument(); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({}, false); + }); + }); + + it('shows error when number is required but is empty', async () => { + render( + + + + ); + + await userEvent.clear( + await screen.findByTestId(`${customFieldConfiguration.key}-number-create-custom-field`) + ); + await userEvent.click(await screen.findByText('Submit')); + + expect( + await screen.findByText(`${customFieldConfiguration.label} is required.`) + ).toBeInTheDocument(); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({}, false); + }); + }); + + it('does not show error when number is not required but is empty', async () => { + render( + + + + ); + + await userEvent.click(await screen.findByText('Submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({}, true); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/create.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/create.tsx new file mode 100644 index 0000000000000..bc01145fd5d46 --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/create.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { NumericField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import type { CaseCustomFieldNumber } from '../../../../common/types/domain'; +import type { CustomFieldType } from '../types'; +import { getNumberFieldConfig } from './config'; +import { OptionalFieldLabel } from '../../optional_field_label'; + +const CreateComponent: CustomFieldType['Create'] = ({ + customFieldConfiguration, + isLoading, + setAsOptional, + setDefaultValue = true, +}) => { + const { key, label, required, defaultValue } = customFieldConfiguration; + const config = getNumberFieldConfig({ + required: setAsOptional ? false : required, + label, + ...(defaultValue && + setDefaultValue && + !isNaN(Number(defaultValue)) && { defaultValue: Number(defaultValue) }), + }); + + return ( + + ); +}; + +CreateComponent.displayName = 'Create'; + +export const Create = React.memo(CreateComponent); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/edit.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/edit.test.tsx new file mode 100644 index 0000000000000..fb19bdb553d41 --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/edit.test.tsx @@ -0,0 +1,475 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; +import { FormTestComponent } from '../../../common/test_utils'; +import { Edit } from './edit'; +import { customFieldsMock, customFieldsConfigurationMock } from '../../../containers/mock'; +import userEvent from '@testing-library/user-event'; +import type { CaseCustomFieldNumber } from '../../../../common/types/domain'; +import { POPULATED_WITH_DEFAULT } from '../translations'; + +describe('Edit ', () => { + const onSubmit = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + const customField = customFieldsMock[4] as CaseCustomFieldNumber; + const customFieldConfiguration = customFieldsConfigurationMock[4]; + + it('renders correctly', async () => { + render( + + + + ); + + expect(await screen.findByTestId('case-number-custom-field-test_key_5')).toBeInTheDocument(); + expect( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ).toBeInTheDocument(); + expect(await screen.findByText(customFieldConfiguration.label)).toBeInTheDocument(); + expect(await screen.findByText('1234')).toBeInTheDocument(); + }); + + it('does not shows the edit button if the user does not have permissions', async () => { + render( + + + + ); + + expect( + screen.queryByTestId('case-number-custom-field-edit-button-test_key_1') + ).not.toBeInTheDocument(); + }); + + it('does not shows the edit button when loading', async () => { + render( + + + + ); + + expect( + screen.queryByTestId('case-number-custom-field-edit-button-test_key_1') + ).not.toBeInTheDocument(); + }); + + it('shows the loading spinner when loading', async () => { + render( + + + + ); + + expect( + await screen.findByTestId('case-number-custom-field-loading-test_key_5') + ).toBeInTheDocument(); + }); + + it('shows the no value number if the custom field is undefined', async () => { + render( + + + + ); + + expect(await screen.findByText('No value is added')).toBeInTheDocument(); + }); + + it('uses the required value correctly if a required field is empty', async () => { + render( + + + + ); + + expect(await screen.findByText('No value is added')).toBeInTheDocument(); + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + + expect( + await screen.findByTestId( + `case-number-custom-field-form-field-${customFieldConfiguration.key}` + ) + ).toHaveValue(customFieldConfiguration.defaultValue as number); + expect( + await screen.findByText('This field is populated with the default value.') + ).toBeInTheDocument(); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-submit-button-test_key_5') + ); + + await waitFor(() => { + expect(onSubmit).toBeCalledWith({ + ...customField, + value: customFieldConfiguration.defaultValue, + }); + }); + }); + + it('does not show the value when the custom field is undefined', async () => { + render( + + + + ); + + expect(screen.queryByTestId('number-custom-field-view-test_key_5')).not.toBeInTheDocument(); + }); + + it('does not show the value when the value is null', async () => { + render( + + + + ); + + expect(screen.queryByTestId('number-custom-field-view-test_key_5')).not.toBeInTheDocument(); + }); + + it('does not show the form when the user does not have permissions', async () => { + render( + + + + ); + + expect( + screen.queryByTestId('case-number-custom-field-form-field-test_key_5') + ).not.toBeInTheDocument(); + expect( + screen.queryByTestId('case-number-custom-field-submit-button-test_key_5') + ).not.toBeInTheDocument(); + expect( + screen.queryByTestId('case-number-custom-field-cancel-button-test_key_5') + ).not.toBeInTheDocument(); + }); + + it('calls onSubmit when changing value', async () => { + render( + + + + ); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + await userEvent.click( + await screen.findByTestId('case-number-custom-field-form-field-test_key_5') + ); + await userEvent.paste('12345'); + + expect( + await screen.findByTestId('case-number-custom-field-submit-button-test_key_5') + ).not.toBeDisabled(); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-submit-button-test_key_5') + ); + + await waitFor(() => { + expect(onSubmit).toBeCalledWith({ + ...customField, + value: 123412345, + }); + }); + }); + + it('calls onSubmit with defaultValue if no initialValue exists', async () => { + render( + + + + ); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + + expect(await screen.findByText(POPULATED_WITH_DEFAULT)).toBeInTheDocument(); + expect(await screen.findByTestId('case-number-custom-field-form-field-test_key_5')).toHaveValue( + customFieldConfiguration.defaultValue as number + ); + expect( + await screen.findByTestId('case-number-custom-field-submit-button-test_key_5') + ).not.toBeDisabled(); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-submit-button-test_key_5') + ); + + await waitFor(() => { + expect(onSubmit).toBeCalledWith({ + ...customField, + value: customFieldConfiguration.defaultValue, + }); + }); + }); + + it('sets the value to null if the number field is empty', async () => { + render( + + + + ); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + await userEvent.clear( + await screen.findByTestId('case-number-custom-field-form-field-test_key_5') + ); + + expect( + await screen.findByTestId('case-number-custom-field-submit-button-test_key_5') + ).not.toBeDisabled(); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-submit-button-test_key_5') + ); + + await waitFor(() => { + expect(onSubmit).toBeCalledWith({ + ...customField, + value: null, + }); + }); + }); + + it('hides the form when clicking the cancel button', async () => { + render( + + + + ); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + + expect( + await screen.findByTestId('case-number-custom-field-form-field-test_key_5') + ).toBeInTheDocument(); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-cancel-button-test_key_5') + ); + + expect( + screen.queryByTestId('case-number-custom-field-form-field-test_key_5') + ).not.toBeInTheDocument(); + }); + + it('reset to initial value when canceling', async () => { + render( + + + + ); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + await userEvent.click( + await screen.findByTestId('case-number-custom-field-form-field-test_key_5') + ); + await userEvent.paste('321'); + + expect( + await screen.findByTestId('case-number-custom-field-submit-button-test_key_5') + ).not.toBeDisabled(); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-cancel-button-test_key_5') + ); + + expect( + screen.queryByTestId('case-number-custom-field-form-field-test_key_5') + ).not.toBeInTheDocument(); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + expect(await screen.findByTestId('case-number-custom-field-form-field-test_key_5')).toHaveValue( + 1234 + ); + }); + + it('shows validation error if the field is required', async () => { + render( + + + + ); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + await userEvent.clear( + await screen.findByTestId('case-number-custom-field-form-field-test_key_5') + ); + + expect(await screen.findByText('My test label 5 is required.')).toBeInTheDocument(); + }); + + it('does not shows a validation error if the field is not required', async () => { + render( + + + + ); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + await userEvent.clear( + await screen.findByTestId('case-number-custom-field-form-field-test_key_5') + ); + + expect( + await screen.findByTestId('case-number-custom-field-submit-button-test_key_5') + ).not.toBeDisabled(); + + expect(screen.queryByText('My test label 1 is required.')).not.toBeInTheDocument(); + }); + + it('shows validation error if the number is too big', async () => { + render( + + + + ); + + await userEvent.click( + await screen.findByTestId('case-number-custom-field-edit-button-test_key_5') + ); + await userEvent.clear( + await screen.findByTestId('case-number-custom-field-form-field-test_key_5') + ); + await userEvent.click( + await screen.findByTestId('case-number-custom-field-form-field-test_key_5') + ); + await userEvent.paste(`${2 ** 53 + 1}`); + + expect( + await screen.findByText( + 'The value of the My test label 5 should be an integer between -(2^53 - 1) and 2^53 - 1, inclusive.' + ) + ).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/edit.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/edit.tsx new file mode 100644 index 0000000000000..3ebb65a9dab8e --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/edit.tsx @@ -0,0 +1,246 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect, useState, useCallback } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiLoadingSpinner, + EuiText, +} from '@elastic/eui'; +import type { FormHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { + useForm, + UseField, + Form, + useFormData, +} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { NumericField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import type { CaseCustomFieldNumber } from '../../../../common/types/domain'; +import { CustomFieldTypes } from '../../../../common/types/domain'; +import type { CasesConfigurationUICustomField } from '../../../../common/ui'; +import type { CustomFieldType } from '../types'; +import { View } from './view'; +import { + CANCEL, + EDIT_CUSTOM_FIELDS_ARIA_LABEL, + NO_CUSTOM_FIELD_SET, + SAVE, + POPULATED_WITH_DEFAULT, +} from '../translations'; +import { getNumberFieldConfig } from './config'; + +const isEmpty = (value: number | null | undefined) => { + return value == null; +}; + +interface FormState { + value: number | null; + isValid?: boolean; + submit: FormHook<{ value: number | null }>['submit']; +} + +interface FormWrapper { + initialValue: number | null; + isLoading: boolean; + customFieldConfiguration: CasesConfigurationUICustomField; + onChange: (state: FormState) => void; +} + +const FormWrapperComponent: React.FC = ({ + initialValue, + customFieldConfiguration, + isLoading, + onChange, +}) => { + const { form } = useForm<{ value: number | null }>({ + defaultValue: { + value: + customFieldConfiguration?.defaultValue != null && isEmpty(initialValue) + ? Number(customFieldConfiguration.defaultValue) + : initialValue, + }, + }); + + const [{ value }] = useFormData({ form }); + const { submit, isValid } = form; + const formFieldConfig = getNumberFieldConfig({ + required: customFieldConfiguration.required, + label: customFieldConfiguration.label, + }); + const populatedWithDefault = + value === customFieldConfiguration?.defaultValue && isEmpty(initialValue); + + useEffect(() => { + onChange({ + value, + isValid, + submit, + }); + }, [isValid, onChange, submit, value]); + + return ( +
+ + + ); +}; + +FormWrapperComponent.displayName = 'FormWrapper'; + +const EditComponent: CustomFieldType['Edit'] = ({ + customField, + customFieldConfiguration, + onSubmit, + isLoading, + canUpdate, +}) => { + const initialValue = customField?.value ?? null; + const [isEdit, setIsEdit] = useState(false); + const [formState, setFormState] = useState({ + isValid: undefined, + submit: async () => ({ isValid: false, data: { value: null } }), + value: initialValue, + }); + + const onEdit = useCallback(() => { + setIsEdit(true); + }, []); + + const onCancel = useCallback(() => { + setIsEdit(false); + }, []); + + const onSubmitCustomField = useCallback(async () => { + const { isValid, data } = await formState.submit(); + + if (isValid) { + onSubmit({ + ...customField, + key: customField?.key ?? customFieldConfiguration.key, + type: CustomFieldTypes.NUMBER, + value: data.value ? Number(data.value) : null, + }); + } + setIsEdit(false); + }, [customField, customFieldConfiguration.key, formState, onSubmit]); + + const title = customFieldConfiguration.label; + + const isNumberFieldValid = + formState.isValid || + (formState.value === customFieldConfiguration.defaultValue && isEmpty(initialValue)); + + const isCustomFieldValueDefined = !isEmpty(customField?.value); + + return ( + <> + + + +

{title}

+
+
+ {isLoading && ( + + )} + {!isLoading && canUpdate && ( + + + + )} +
+ + + {!isCustomFieldValueDefined && !isEdit && ( +

{NO_CUSTOM_FIELD_SET}

+ )} + {!isEdit && isCustomFieldValueDefined && ( + + + + )} + {isEdit && canUpdate && ( + + + + + + + + + {SAVE} + + + + + {CANCEL} + + + + + + )} +
+ + ); +}; + +EditComponent.displayName = 'Edit'; + +export const Edit = React.memo(EditComponent); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/get_eui_table_column.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/get_eui_table_column.test.tsx new file mode 100644 index 0000000000000..73e94f9335705 --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/get_eui_table_column.test.tsx @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; + +import { screen } from '@testing-library/react'; + +import { CustomFieldTypes } from '../../../../common/types/domain'; +import type { AppMockRenderer } from '../../../common/mock'; +import { createAppMockRenderer } from '../../../common/mock'; +import { getEuiTableColumn } from './get_eui_table_column'; + +describe('getEuiTableColumn ', () => { + let appMockRender: AppMockRenderer; + + beforeEach(() => { + appMockRender = createAppMockRenderer(); + + jest.clearAllMocks(); + }); + + it('returns a name and a render function', async () => { + const label = 'MockLabel'; + + expect(getEuiTableColumn({ label })).toEqual({ + name: label, + render: expect.any(Function), + width: '150px', + 'data-test-subj': 'number-custom-field-column', + }); + }); + + it('render function renders a number column correctly', async () => { + const key = 'test_key_1'; + const value = 1234567; + const column = getEuiTableColumn({ label: 'MockLabel' }); + + appMockRender.render(
{column.render({ key, type: CustomFieldTypes.NUMBER, value })}
); + + expect(screen.getByTestId(`number-custom-field-column-view-${key}`)).toBeInTheDocument(); + expect(screen.getByTestId(`number-custom-field-column-view-${key}`)).toHaveTextContent( + String(value) + ); + }); +}); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/get_eui_table_column.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/get_eui_table_column.tsx new file mode 100644 index 0000000000000..a5b68364b9758 --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/get_eui_table_column.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import type { CaseCustomField } from '../../../../common/types/domain'; +import type { CustomFieldEuiTableColumn } from '../types'; + +export const getEuiTableColumn = ({ label }: { label: string }): CustomFieldEuiTableColumn => ({ + name: label, + width: '150px', + render: (customField: CaseCustomField) => { + return ( +

+ {customField.value} +

+ ); + }, + 'data-test-subj': 'number-custom-field-column', +}); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/view.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/view.test.tsx new file mode 100644 index 0000000000000..cdcc3cdacf534 --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/view.test.tsx @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { CustomFieldTypes } from '../../../../common/types/domain'; +import { View } from './view'; + +describe('View ', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + const customField = { + type: CustomFieldTypes.NUMBER as const, + key: 'test_key_1', + value: 123 as number, + }; + + it('renders correctly', async () => { + render(); + + expect(screen.getByText('123')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/view.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/view.tsx new file mode 100644 index 0000000000000..542ea92def998 --- /dev/null +++ b/x-pack/plugins/cases/public/components/custom_fields/number/view.tsx @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiText } from '@elastic/eui'; +import type { CaseCustomFieldNumber } from '../../../../common/types/domain'; +import type { CustomFieldType } from '../types'; + +const ViewComponent: CustomFieldType['View'] = ({ customField }) => { + const value = customField?.value ?? '-'; + + return ( + + {value} + + ); +}; + +ViewComponent.displayName = 'View'; + +export const View = React.memo(ViewComponent); diff --git a/x-pack/plugins/cases/public/components/custom_fields/text/configure_text_field.ts b/x-pack/plugins/cases/public/components/custom_fields/text/configure_text_field.ts index c0f50820d45f3..0f1595135f9b8 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/text/configure_text_field.ts +++ b/x-pack/plugins/cases/public/components/custom_fields/text/configure_text_field.ts @@ -25,5 +25,6 @@ export const configureTextCustomFieldFactory: CustomFieldFactory (value == null ? '' : String(value)), + convertNullToEmpty: (value: string | number | boolean | null) => + value == null ? '' : String(value), }); diff --git a/x-pack/plugins/cases/public/components/custom_fields/translations.ts b/x-pack/plugins/cases/public/components/custom_fields/translations.ts index 5f1a91765193f..22bafbb80f92f 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/translations.ts +++ b/x-pack/plugins/cases/public/components/custom_fields/translations.ts @@ -51,6 +51,10 @@ export const TOGGLE_LABEL = i18n.translate('xpack.cases.customFields.toggleLabel defaultMessage: 'Toggle', }); +export const NUMBER_LABEL = i18n.translate('xpack.cases.customFields.textLabel', { + defaultMessage: 'Number', +}); + export const FIELD_TYPE = i18n.translate('xpack.cases.customFields.fieldType', { defaultMessage: 'Field type', }); diff --git a/x-pack/plugins/cases/public/components/custom_fields/types.ts b/x-pack/plugins/cases/public/components/custom_fields/types.ts index 70caeabd8edd2..ca63caef38748 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/types.ts +++ b/x-pack/plugins/cases/public/components/custom_fields/types.ts @@ -55,7 +55,7 @@ export type CustomFieldFactory = () => { build: () => CustomFieldType; filterOptions?: CustomFieldFactoryFilterOption[]; getDefaultValue?: () => string | boolean | null; - convertNullToEmpty?: (value: string | boolean | null) => string; + convertNullToEmpty?: (value: string | number | boolean | null) => string; }; export type CustomFieldBuilderMap = { diff --git a/x-pack/plugins/cases/public/components/custom_fields/utils.test.ts b/x-pack/plugins/cases/public/components/custom_fields/utils.test.ts index 5a21319645836..61a77fc941451 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/utils.test.ts +++ b/x-pack/plugins/cases/public/components/custom_fields/utils.test.ts @@ -97,5 +97,40 @@ describe('utils ', () => { } `); }); + + it('serializes the data correctly if the default value is integer number', async () => { + const customField = { + key: 'my_test_key', + type: CustomFieldTypes.NUMBER, + required: true, + defaultValue: 1, + } as CustomFieldConfiguration; + + expect(customFieldSerializer(customField)).toMatchInlineSnapshot(` + Object { + "defaultValue": 1, + "key": "my_test_key", + "required": true, + "type": "number", + } + `); + }); + + it('serializes the data correctly if the default value is float number', async () => { + const customField = { + key: 'my_test_key', + type: CustomFieldTypes.NUMBER, + required: true, + defaultValue: 1.5, + } as CustomFieldConfiguration; + + expect(customFieldSerializer(customField)).toMatchInlineSnapshot(` + Object { + "key": "my_test_key", + "required": true, + "type": "number", + } + `); + }); }); }); diff --git a/x-pack/plugins/cases/public/components/custom_fields/utils.ts b/x-pack/plugins/cases/public/components/custom_fields/utils.ts index 3842b75b5a7ea..96438a9337265 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/utils.ts +++ b/x-pack/plugins/cases/public/components/custom_fields/utils.ts @@ -8,6 +8,7 @@ import { isEmptyString } from '@kbn/es-ui-shared-plugin/static/validators/string'; import { isString } from 'lodash'; import type { CustomFieldConfiguration } from '../../../common/types/domain'; +import { CustomFieldTypes } from '../../../common/types/domain'; export const customFieldSerializer = ( field: CustomFieldConfiguration @@ -18,5 +19,13 @@ export const customFieldSerializer = ( return otherProperties; } + if (field.type === CustomFieldTypes.NUMBER) { + if (defaultValue !== null && Number.isSafeInteger(Number(defaultValue))) { + return { ...field, defaultValue: Number(defaultValue) }; + } else { + return otherProperties; + } + } + return field; }; diff --git a/x-pack/plugins/cases/public/components/files/file_attachment_event.test.tsx b/x-pack/plugins/cases/public/components/files/file_attachment_event.test.tsx index 344eab2634cb0..543496622b0c6 100644 --- a/x-pack/plugins/cases/public/components/files/file_attachment_event.test.tsx +++ b/x-pack/plugins/cases/public/components/files/file_attachment_event.test.tsx @@ -16,7 +16,8 @@ import { createAppMockRenderer } from '../../common/mock'; import { basicFileMock } from '../../containers/mock'; import { FileAttachmentEvent } from './file_attachment_event'; -describe('FileAttachmentEvent', () => { +// FLAKY: https://github.com/elastic/kibana/issues/174661 +describe.skip('FileAttachmentEvent', () => { let appMockRender: AppMockRenderer; beforeEach(() => { diff --git a/x-pack/plugins/cases/public/components/markdown_editor/editable_markdown_renderer.test.tsx b/x-pack/plugins/cases/public/components/markdown_editor/editable_markdown_renderer.test.tsx index 6e56126708034..81758ea1076c7 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/editable_markdown_renderer.test.tsx +++ b/x-pack/plugins/cases/public/components/markdown_editor/editable_markdown_renderer.test.tsx @@ -61,7 +61,8 @@ const defaultProps = { editorRef, }; -describe('EditableMarkdown', () => { +// FLAKY: https://github.com/elastic/kibana/issues/171177 +describe.skip('EditableMarkdown', () => { let appMockRender: AppMockRenderer; beforeEach(() => { diff --git a/x-pack/plugins/cases/public/components/templates/form.test.tsx b/x-pack/plugins/cases/public/components/templates/form.test.tsx index bf5f66aaa3e21..349457c2be98f 100644 --- a/x-pack/plugins/cases/public/components/templates/form.test.tsx +++ b/x-pack/plugins/cases/public/components/templates/form.test.tsx @@ -589,11 +589,14 @@ describe('TemplateForm', () => { expect( await within(customFieldsElement).findAllByTestId('form-optional-field-label') ).toHaveLength( - customFieldsConfigurationMock.filter((field) => field.type === CustomFieldTypes.TEXT).length + customFieldsConfigurationMock.filter( + (field) => field.type === CustomFieldTypes.TEXT || field.type === CustomFieldTypes.NUMBER + ).length ); const textField = customFieldsConfigurationMock[0]; const toggleField = customFieldsConfigurationMock[3]; + const numberField = customFieldsConfigurationMock[4]; const textCustomField = await screen.findByTestId( `${textField.key}-${textField.type}-create-custom-field` @@ -608,6 +611,15 @@ describe('TemplateForm', () => { await screen.findByTestId(`${toggleField.key}-${toggleField.type}-create-custom-field`) ); + const numberCustomField = await screen.findByTestId( + `${numberField.key}-${numberField.type}-create-custom-field` + ); + + await user.clear(numberCustomField); + + await user.click(numberCustomField); + await user.paste('765'); + const submitSpy = jest.spyOn(formState!, 'submit'); await user.click(screen.getByText('testSubmit')); @@ -644,6 +656,16 @@ describe('TemplateForm', () => { type: 'toggle', value: true, }, + { + key: 'test_key_5', + type: 'number', + value: 1234, + }, + { + key: 'test_key_6', + type: 'number', + value: true, + }, ], settings: { syncAlerts: true, diff --git a/x-pack/plugins/cases/public/components/templates/form_fields.test.tsx b/x-pack/plugins/cases/public/components/templates/form_fields.test.tsx index 75cfa58e8d5f8..48c6f956ccc7c 100644 --- a/x-pack/plugins/cases/public/components/templates/form_fields.test.tsx +++ b/x-pack/plugins/cases/public/components/templates/form_fields.test.tsx @@ -311,6 +311,7 @@ describe('form fields', () => { const textField = customFieldsConfigurationMock[0]; const toggleField = customFieldsConfigurationMock[1]; + const numberField = customFieldsConfigurationMock[4]; const textCustomField = await screen.findByTestId( `${textField.key}-${textField.type}-create-custom-field` @@ -324,6 +325,14 @@ describe('form fields', () => { await screen.findByTestId(`${toggleField.key}-${toggleField.type}-create-custom-field`) ); + const numberCustomField = await screen.findByTestId( + `${numberField.key}-${numberField.type}-create-custom-field` + ); + + await userEvent.clear(numberCustomField); + await userEvent.click(numberCustomField); + await userEvent.paste('987'); + await userEvent.click(screen.getByText('Submit')); await waitFor(() => { @@ -336,6 +345,7 @@ describe('form fields', () => { test_key_1: 'My text test value 1', test_key_2: false, test_key_4: false, + test_key_5: '987', }, syncAlerts: true, templateTags: [], diff --git a/x-pack/plugins/cases/public/components/utils.test.ts b/x-pack/plugins/cases/public/components/utils.test.ts index 005f15b78b3d7..f10590cc9a358 100644 --- a/x-pack/plugins/cases/public/components/utils.test.ts +++ b/x-pack/plugins/cases/public/components/utils.test.ts @@ -523,19 +523,46 @@ describe('Utils', () => { }); it('returns the string when the value is a non-empty string', async () => { - expect(convertCustomFieldValue('my text value')).toMatchInlineSnapshot(`"my text value"`); + expect( + convertCustomFieldValue({ value: 'my text value', type: CustomFieldTypes.TEXT }) + ).toMatchInlineSnapshot(`"my text value"`); }); it('returns null when value is empty string', async () => { - expect(convertCustomFieldValue('')).toMatchInlineSnapshot('null'); + expect( + convertCustomFieldValue({ value: '', type: CustomFieldTypes.TEXT }) + ).toMatchInlineSnapshot('null'); }); it('returns value as it is when value is true', async () => { - expect(convertCustomFieldValue(true)).toMatchInlineSnapshot('true'); + expect( + convertCustomFieldValue({ value: true, type: CustomFieldTypes.TOGGLE }) + ).toMatchInlineSnapshot('true'); }); it('returns value as it is when value is false', async () => { - expect(convertCustomFieldValue(false)).toMatchInlineSnapshot('false'); + expect( + convertCustomFieldValue({ value: false, type: CustomFieldTypes.TOGGLE }) + ).toMatchInlineSnapshot('false'); + }); + it('returns value as integer number when value is integer string and type is number', () => { + expect(convertCustomFieldValue({ value: '123', type: CustomFieldTypes.NUMBER })).toEqual(123); + }); + + it('returns value as null when value is float string and type is number', () => { + expect(convertCustomFieldValue({ value: '0.5', type: CustomFieldTypes.NUMBER })).toEqual( + null + ); + }); + + it('returns value as null when value is null and type is number', () => { + expect(convertCustomFieldValue({ value: null, type: CustomFieldTypes.NUMBER })).toEqual(null); + }); + + it('returns value as null when value is characters string and type is number', () => { + expect(convertCustomFieldValue({ value: 'fdgdg', type: CustomFieldTypes.NUMBER })).toEqual( + null + ); }); }); @@ -575,6 +602,16 @@ describe('Utils', () => { "type": "toggle", "value": null, }, + Object { + "key": "test_key_5", + "type": "number", + "value": 1234, + }, + Object { + "key": "test_key_6", + "type": "number", + "value": null, + }, Object { "key": "my_test_key", "type": "text", @@ -598,6 +635,8 @@ describe('Utils', () => { { ...customFieldsMock[1] }, { ...customFieldsMock[2] }, { ...customFieldsMock[3] }, + { ...customFieldsMock[4] }, + { ...customFieldsMock[5] }, ], ` Array [ @@ -626,6 +665,16 @@ describe('Utils', () => { "type": "toggle", "value": null, }, + Object { + "key": "test_key_5", + "type": "number", + "value": 1234, + }, + Object { + "key": "test_key_6", + "type": "number", + "value": null, + }, ] ` ); @@ -669,6 +718,19 @@ describe('Utils', () => { "required": false, "type": "toggle", }, + Object { + "defaultValue": 123, + "key": "test_key_5", + "label": "My test label 5", + "required": true, + "type": "number", + }, + Object { + "key": "test_key_6", + "label": "My test label 6", + "required": false, + "type": "number", + }, Object { "key": "my_test_key", "label": "my_test_label", @@ -693,6 +755,8 @@ describe('Utils', () => { { ...customFieldsConfigurationMock[1] }, { ...customFieldsConfigurationMock[2] }, { ...customFieldsConfigurationMock[3] }, + { ...customFieldsConfigurationMock[4] }, + { ...customFieldsConfigurationMock[5] }, ], ` Array [ @@ -722,6 +786,19 @@ describe('Utils', () => { "required": false, "type": "toggle", }, + Object { + "defaultValue": 123, + "key": "test_key_5", + "label": "My test label 5", + "required": true, + "type": "number", + }, + Object { + "key": "test_key_6", + "label": "My test label 6", + "required": false, + "type": "number", + }, ] ` ); diff --git a/x-pack/plugins/cases/public/components/utils.ts b/x-pack/plugins/cases/public/components/utils.ts index 7e1aa54554f50..bcc6be9a7ae9e 100644 --- a/x-pack/plugins/cases/public/components/utils.ts +++ b/x-pack/plugins/cases/public/components/utils.ts @@ -13,7 +13,7 @@ import type { } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; import type { ConnectorTypeFields } from '../../common/types/domain'; -import { ConnectorTypes } from '../../common/types/domain'; +import { ConnectorTypes, CustomFieldTypes } from '../../common/types/domain'; import type { CasesPublicStartDependencies } from '../types'; import { connectorValidator as swimlaneConnectorValidator } from './connectors/swimlane/validator'; import type { CaseActionConnector } from './types'; @@ -234,11 +234,25 @@ export const parseCaseUsers = ({ return { userProfiles, reporterAsArray }; }; -export const convertCustomFieldValue = (value: string | boolean) => { +export const convertCustomFieldValue = ({ + value, + type, +}: { + value: string | number | boolean | null; + type: CustomFieldTypes; +}) => { if (typeof value === 'string' && isEmpty(value)) { return null; } + if (type === CustomFieldTypes.NUMBER) { + if (value !== null && Number.isSafeInteger(Number(value))) { + return Number(value); + } else { + return null; + } + } + return value; }; @@ -288,7 +302,7 @@ export const customFieldsFormDeserializer = ( }; export const customFieldsFormSerializer = ( - customFields: Record, + customFields: Record, selectedCustomFieldsConfiguration: CasesConfigurationUI['customFields'] ): CaseUI['customFields'] => { const transformedCustomFields: CaseUI['customFields'] = []; @@ -303,7 +317,7 @@ export const customFieldsFormSerializer = ( transformedCustomFields.push({ key: configCustomField.key, type: configCustomField.type, - value: convertCustomFieldValue(value), + value: convertCustomFieldValue({ value, type: configCustomField.type }), } as CaseUICustomField); } } diff --git a/x-pack/plugins/cases/public/containers/mock.ts b/x-pack/plugins/cases/public/containers/mock.ts index 8d2feca6b9be0..c3cee2d60d2b0 100644 --- a/x-pack/plugins/cases/public/containers/mock.ts +++ b/x-pack/plugins/cases/public/containers/mock.ts @@ -1158,6 +1158,8 @@ export const customFieldsMock: CaseUICustomField[] = [ { type: CustomFieldTypes.TOGGLE, key: 'test_key_2', value: true }, { type: CustomFieldTypes.TEXT, key: 'test_key_3', value: null }, { type: CustomFieldTypes.TOGGLE, key: 'test_key_4', value: null }, + { type: CustomFieldTypes.NUMBER, key: 'test_key_5', value: 1234 }, + { type: CustomFieldTypes.NUMBER, key: 'test_key_6', value: null }, ]; export const customFieldsConfigurationMock: CasesConfigurationUICustomField[] = [ @@ -1177,6 +1179,19 @@ export const customFieldsConfigurationMock: CasesConfigurationUICustomField[] = }, { type: CustomFieldTypes.TEXT, key: 'test_key_3', label: 'My test label 3', required: false }, { type: CustomFieldTypes.TOGGLE, key: 'test_key_4', label: 'My test label 4', required: false }, + { + type: CustomFieldTypes.NUMBER, + key: 'test_key_5', + label: 'My test label 5', + required: true, + defaultValue: 123, + }, + { + type: CustomFieldTypes.NUMBER, + key: 'test_key_6', + label: 'My test label 6', + required: false, + }, ]; export const templatesConfigurationMock: CasesConfigurationUITemplate[] = [ diff --git a/x-pack/plugins/cases/public/containers/use_replace_custom_field.tsx b/x-pack/plugins/cases/public/containers/use_replace_custom_field.tsx index 5d2969f6e6d44..f1d0b87ff07e8 100644 --- a/x-pack/plugins/cases/public/containers/use_replace_custom_field.tsx +++ b/x-pack/plugins/cases/public/containers/use_replace_custom_field.tsx @@ -16,7 +16,7 @@ import * as i18n from './translations'; interface ReplaceCustomField { caseId: string; customFieldId: string; - customFieldValue: string | boolean | null; + customFieldValue: string | number | boolean | null; caseVersion: string; } diff --git a/x-pack/plugins/cases/server/client/utils.test.ts b/x-pack/plugins/cases/server/client/utils.test.ts index eb7aaea6d6938..680887b82c653 100644 --- a/x-pack/plugins/cases/server/client/utils.test.ts +++ b/x-pack/plugins/cases/server/client/utils.test.ts @@ -906,7 +906,7 @@ describe('utils', () => { ...customFieldsConfiguration, { key: 'fourth_key', - type: 'number', + type: 'symbol', label: 'Number field', required: true, }, diff --git a/x-pack/plugins/cases/server/common/types/configure.ts b/x-pack/plugins/cases/server/common/types/configure.ts index faf2517fbe173..27e66ba76eb02 100644 --- a/x-pack/plugins/cases/server/common/types/configure.ts +++ b/x-pack/plugins/cases/server/common/types/configure.ts @@ -39,7 +39,7 @@ type PersistedCustomFieldsConfiguration = Array<{ type: string; label: string; required: boolean; - defaultValue?: string | boolean | null; + defaultValue?: string | number | boolean | null; }>; type PersistedTemplatesConfiguration = Array<{ diff --git a/x-pack/plugins/cases/server/connectors/cases/constants.ts b/x-pack/plugins/cases/server/connectors/cases/constants.ts index fafd1a3e0eaeb..f1d0e548e1f3a 100644 --- a/x-pack/plugins/cases/server/connectors/cases/constants.ts +++ b/x-pack/plugins/cases/server/connectors/cases/constants.ts @@ -12,8 +12,11 @@ export const MAX_OPEN_CASES = 10; export const DEFAULT_MAX_OPEN_CASES = 5; export const INITIAL_ORACLE_RECORD_COUNTER = 1; -export const VALUES_FOR_CUSTOM_FIELDS_MISSING_DEFAULTS: Record = - { - [CustomFieldTypes.TEXT]: 'N/A', - [CustomFieldTypes.TOGGLE]: false, - }; +export const VALUES_FOR_CUSTOM_FIELDS_MISSING_DEFAULTS: Record< + CustomFieldTypes, + string | boolean | number +> = { + [CustomFieldTypes.TEXT]: 'N/A', + [CustomFieldTypes.TOGGLE]: false, + [CustomFieldTypes.NUMBER]: 0, +}; diff --git a/x-pack/plugins/cases/server/custom_fields/factory.ts b/x-pack/plugins/cases/server/custom_fields/factory.ts index d9e1bc86671fe..3b42dcfd6eddb 100644 --- a/x-pack/plugins/cases/server/custom_fields/factory.ts +++ b/x-pack/plugins/cases/server/custom_fields/factory.ts @@ -9,10 +9,12 @@ import { CustomFieldTypes } from '../../common/types/domain'; import type { ICasesCustomField, CasesCustomFieldsMap } from './types'; import { getCasesTextCustomField } from './text'; import { getCasesToggleCustomField } from './toggle'; +import { getCasesNumberCustomField } from './number'; const mapping: Record = { [CustomFieldTypes.TEXT]: getCasesTextCustomField(), [CustomFieldTypes.TOGGLE]: getCasesToggleCustomField(), + [CustomFieldTypes.NUMBER]: getCasesNumberCustomField(), }; export const casesCustomFields: CasesCustomFieldsMap = { diff --git a/x-pack/plugins/cases/server/custom_fields/number.ts b/x-pack/plugins/cases/server/custom_fields/number.ts new file mode 100644 index 0000000000000..f036a01cbe1b8 --- /dev/null +++ b/x-pack/plugins/cases/server/custom_fields/number.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import Boom from '@hapi/boom'; + +export const getCasesNumberCustomField = () => ({ + isFilterable: false, + isSortable: false, + savedObjectMappingType: 'long', + validateFilteringValues: (values: Array) => { + values.forEach((value) => { + if (value !== null && !Number.isSafeInteger(value)) { + throw Boom.badRequest('Unsupported filtering value for custom field of type number.'); + } + }); + }, +}); diff --git a/x-pack/plugins/cases/server/plugin.ts b/x-pack/plugins/cases/server/plugin.ts index fa172b48520a7..b40089ff75050 100644 --- a/x-pack/plugins/cases/server/plugin.ts +++ b/x-pack/plugins/cases/server/plugin.ts @@ -122,9 +122,14 @@ export class CasePlugin const router = core.http.createRouter(); const telemetryUsageCounter = plugins.usageCollection?.createUsageCounter(APP_ID); + const isServerless = plugins.cloud?.isServerlessEnabled; + registerRoutes({ router, - routes: [...getExternalRoutes(), ...getInternalRoutes(this.userProfileService)], + routes: [ + ...getExternalRoutes({ isServerless }), + ...getInternalRoutes(this.userProfileService), + ], logger: this.logger, kibanaVersion: this.kibanaVersion, telemetryUsageCounter, diff --git a/x-pack/plugins/cases/server/routes/api/cases/get_case.test.ts b/x-pack/plugins/cases/server/routes/api/cases/get_case.test.ts new file mode 100644 index 0000000000000..45ee5e8f47163 --- /dev/null +++ b/x-pack/plugins/cases/server/routes/api/cases/get_case.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createCasesClientMock } from '../../../client/mocks'; +import { getCaseRoute } from './get_case'; +import { httpServerMock, loggingSystemMock } from '@kbn/core/server/mocks'; + +describe('getCaseRoute', () => { + const casesClientMock = createCasesClientMock(); + const logger = loggingSystemMock.createLogger(); + const response = httpServerMock.createResponseFactory(); + const kibanaVersion = '8.17'; + const context = { cases: { getCasesClient: jest.fn().mockResolvedValue(casesClientMock) } }; + + it('throws a bad request if the includeComments is set in serverless', async () => { + const router = getCaseRoute({ isServerless: true }); + const request = httpServerMock.createKibanaRequest({ + path: '/api/cases/{case_id}/?includeComments=true', + query: { includeComments: true }, + params: { case_id: 'foo' }, + }); + + await expect( + // @ts-expect-error: no need to create the context + router.handler({ response, request, logger, kibanaVersion, context }) + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Failed to retrieve case in route case id: foo + include comments: true: Error: includeComments is not supported" + `); + }); + + it('does not throw a bad request if the includeComments is set in non-serverless', async () => { + const router = getCaseRoute({ isServerless: false }); + const request = httpServerMock.createKibanaRequest({ + path: '/api/cases/{case_id}/?includeComments=true', + query: { includeComments: true }, + params: { case_id: 'foo' }, + }); + + await expect( + // @ts-expect-error: no need to create the context + router.handler({ response, request, logger, kibanaVersion, context }) + ).resolves.not.toThrow(); + }); + + it('does not throw a bad request if the includeComments is not set in serverless', async () => { + const router = getCaseRoute({ isServerless: true }); + const request = httpServerMock.createKibanaRequest({ + path: '/api/cases/{case_id}', + params: { case_id: 'foo' }, + }); + + await expect( + // @ts-expect-error: no need to create the context + router.handler({ response, request, logger, kibanaVersion, context }) + ).resolves.not.toThrow(); + }); +}); diff --git a/x-pack/plugins/cases/server/routes/api/cases/get_case.ts b/x-pack/plugins/cases/server/routes/api/cases/get_case.ts index 831a7be129f70..158360ff7b23f 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/get_case.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/get_case.ts @@ -5,6 +5,7 @@ * 2.0. */ +import Boom from '@hapi/boom'; import { schema } from '@kbn/config-schema'; import type { caseApiV1 } from '../../../../common/types/api'; @@ -26,53 +27,58 @@ const params = { }), }; -export const getCaseRoute = createCasesRoute({ - method: 'get', - path: CASE_DETAILS_URL, - params, - routerOptions: { - access: 'public', - summary: `Get a case`, - tags: ['oas-tag:cases'], - }, - handler: async ({ context, request, response, logger, kibanaVersion }) => { - try { - const isIncludeCommentsParamProvidedByTheUser = - request.url.searchParams.has('includeComments'); +export const getCaseRoute = ({ isServerless }: { isServerless?: boolean }) => + createCasesRoute({ + method: 'get', + path: CASE_DETAILS_URL, + params, + routerOptions: { + access: 'public', + summary: `Get a case`, + tags: ['oas-tag:cases'], + }, + handler: async ({ context, request, response, logger, kibanaVersion }) => { + try { + const isIncludeCommentsParamProvidedByTheUser = + request.url.searchParams.has('includeComments'); - if (isIncludeCommentsParamProvidedByTheUser) { - logDeprecatedEndpoint( - logger, - request.headers, - `The query parameter 'includeComments' of the get case API '${CASE_DETAILS_URL}' is deprecated` - ); - } + if (isServerless && isIncludeCommentsParamProvidedByTheUser) { + throw Boom.badRequest('includeComments is not supported'); + } - const caseContext = await context.cases; - const casesClient = await caseContext.getCasesClient(); - const id = request.params.case_id; + if (isIncludeCommentsParamProvidedByTheUser) { + logDeprecatedEndpoint( + logger, + request.headers, + `The query parameter 'includeComments' of the get case API '${CASE_DETAILS_URL}' is deprecated` + ); + } - const res: caseDomainV1.Case = await casesClient.cases.get({ - id, - includeComments: request.query.includeComments, - }); + const caseContext = await context.cases; + const casesClient = await caseContext.getCasesClient(); + const id = request.params.case_id; - return response.ok({ - ...(isIncludeCommentsParamProvidedByTheUser && { - headers: { - ...getWarningHeader(kibanaVersion, 'Deprecated query parameter includeComments'), - }, - }), - body: res, - }); - } catch (error) { - throw createCaseError({ - message: `Failed to retrieve case in route case id: ${request.params.case_id} \ninclude comments: ${request.query.includeComments}: ${error}`, - error, - }); - } - }, -}); + const res: caseDomainV1.Case = await casesClient.cases.get({ + id, + includeComments: request.query.includeComments, + }); + + return response.ok({ + ...(isIncludeCommentsParamProvidedByTheUser && { + headers: { + ...getWarningHeader(kibanaVersion, 'Deprecated query parameter includeComments'), + }, + }), + body: res, + }); + } catch (error) { + throw createCaseError({ + message: `Failed to retrieve case in route case id: ${request.params.case_id} \ninclude comments: ${request.query.includeComments}: ${error}`, + error, + }); + } + }, + }); export const resolveCaseRoute = createCasesRoute({ method: 'get', diff --git a/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.test.ts b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.test.ts new file mode 100644 index 0000000000000..9687e73d1f7c8 --- /dev/null +++ b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getAllCommentsRoute } from './get_all_comment'; + +describe('getAllCommentsRoute', () => { + it('marks the endpoint internal in serverless', async () => { + const router = getAllCommentsRoute({ isServerless: true }); + + expect(router.routerOptions?.access).toBe('internal'); + }); + + it('marks the endpoint public in non-serverless', async () => { + const router = getAllCommentsRoute({ isServerless: false }); + + expect(router.routerOptions?.access).toBe('public'); + }); +}); diff --git a/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts index 6e8ac79bffec9..0f84ed29dce29 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts @@ -15,41 +15,42 @@ import type { attachmentDomainV1 } from '../../../../common/types/domain'; /** * @deprecated since version 8.1.0 */ -export const getAllCommentsRoute = createCasesRoute({ - method: 'get', - path: CASE_COMMENTS_URL, - params: { - params: schema.object({ - case_id: schema.string(), - }), - }, - options: { - deprecated: true, - }, - routerOptions: { - access: 'public', - summary: `Gets all case comments`, - tags: ['oas-tag:cases'], - // description: 'You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases with the comments you\'re seeking.', - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - }, - handler: async ({ context, request, response }) => { - try { - const caseContext = await context.cases; - const client = await caseContext.getCasesClient(); - const res: attachmentDomainV1.Attachments = await client.attachments.getAll({ - caseID: request.params.case_id, - }); +export const getAllCommentsRoute = ({ isServerless }: { isServerless?: boolean }) => + createCasesRoute({ + method: 'get', + path: CASE_COMMENTS_URL, + params: { + params: schema.object({ + case_id: schema.string(), + }), + }, + options: { + deprecated: true, + }, + routerOptions: { + access: isServerless ? 'internal' : 'public', + summary: `Gets all case comments`, + tags: ['oas-tag:cases'], + // description: 'You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases with the comments you\'re seeking.', + // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} + deprecated: true, + }, + handler: async ({ context, request, response }) => { + try { + const caseContext = await context.cases; + const client = await caseContext.getCasesClient(); + const res: attachmentDomainV1.Attachments = await client.attachments.getAll({ + caseID: request.params.case_id, + }); - return response.ok({ - body: res, - }); - } catch (error) { - throw createCaseError({ - message: `Failed to get all comments in route case id: ${request.params.case_id}: ${error}`, - error, - }); - } - }, -}); + return response.ok({ + body: res, + }); + } catch (error) { + throw createCaseError({ + message: `Failed to get all comments in route case id: ${request.params.case_id}: ${error}`, + error, + }); + } + }, + }); diff --git a/x-pack/plugins/cases/server/routes/api/get_external_routes.ts b/x-pack/plugins/cases/server/routes/api/get_external_routes.ts index bd990deefbdfa..4412d0b695079 100644 --- a/x-pack/plugins/cases/server/routes/api/get_external_routes.ts +++ b/x-pack/plugins/cases/server/routes/api/get_external_routes.ts @@ -31,18 +31,18 @@ import { postCaseConfigureRoute } from './configure/post_configure'; import { getAllAlertsAttachedToCaseRoute } from './comments/get_alerts'; import { findUserActionsRoute } from './user_actions/find_user_actions'; -export const getExternalRoutes = () => +export const getExternalRoutes = ({ isServerless }: { isServerless?: boolean }) => [ deleteCaseRoute, findCaseRoute, - getCaseRoute, + getCaseRoute({ isServerless }), resolveCaseRoute, patchCaseRoute, postCaseRoute, pushCaseRoute, findUserActionsRoute, - getUserActionsRoute, - getStatusRoute, + getUserActionsRoute({ isServerless }), + getStatusRoute({ isServerless }), getCasesByAlertIdRoute, getReportersRoute, getTagsRoute, @@ -50,7 +50,7 @@ export const getExternalRoutes = () => deleteAllCommentsRoute, findCommentsRoute, getCommentRoute, - getAllCommentsRoute, + getAllCommentsRoute({ isServerless }), patchCommentRoute, postCommentRoute, getCaseConfigureRoute, diff --git a/x-pack/plugins/cases/server/routes/api/stats/get_status.test.ts b/x-pack/plugins/cases/server/routes/api/stats/get_status.test.ts new file mode 100644 index 0000000000000..9376a46b76808 --- /dev/null +++ b/x-pack/plugins/cases/server/routes/api/stats/get_status.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getStatusRoute } from './get_status'; + +describe('getStatusRoute', () => { + it('marks the endpoint internal in serverless', async () => { + const router = getStatusRoute({ isServerless: true }); + + expect(router.routerOptions?.access).toBe('internal'); + }); + + it('marks the endpoint public in non-serverless', async () => { + const router = getStatusRoute({ isServerless: false }); + + expect(router.routerOptions?.access).toBe('public'); + }); +}); diff --git a/x-pack/plugins/cases/server/routes/api/stats/get_status.ts b/x-pack/plugins/cases/server/routes/api/stats/get_status.ts index dce369e4a0f45..0889644f6a80a 100644 --- a/x-pack/plugins/cases/server/routes/api/stats/get_status.ts +++ b/x-pack/plugins/cases/server/routes/api/stats/get_status.ts @@ -15,37 +15,38 @@ import type { statsApiV1 } from '../../../../common/types/api'; /** * @deprecated since version 8.1.0 */ -export const getStatusRoute: CaseRoute = createCasesRoute({ - method: 'get', - path: CASE_STATUS_URL, - options: { deprecated: true }, - routerOptions: { - access: 'public', - summary: `Get case status summary`, - tags: ['oas-tag:cases'], - description: - 'Returns the number of cases that are open, closed, and in progress in the default space.', - // You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases you're seeking. - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - }, - handler: async ({ context, request, response }) => { - try { - const caseContext = await context.cases; - const client = await caseContext.getCasesClient(); +export const getStatusRoute = ({ isServerless }: { isServerless?: boolean }): CaseRoute => + createCasesRoute({ + method: 'get', + path: CASE_STATUS_URL, + options: { deprecated: true }, + routerOptions: { + access: isServerless ? 'internal' : 'public', + summary: `Get case status summary`, + tags: ['oas-tag:cases'], + description: + 'Returns the number of cases that are open, closed, and in progress in the default space.', + // You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases you're seeking. + // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} + deprecated: true, + }, + handler: async ({ context, request, response }) => { + try { + const caseContext = await context.cases; + const client = await caseContext.getCasesClient(); - const res: statsApiV1.CasesStatusResponse = await client.metrics.getStatusTotalsByType( - request.query as statsApiV1.CasesStatusRequest - ); + const res: statsApiV1.CasesStatusResponse = await client.metrics.getStatusTotalsByType( + request.query as statsApiV1.CasesStatusRequest + ); - return response.ok({ - body: res, - }); - } catch (error) { - throw createCaseError({ - message: `Failed to get status stats in route: ${error}`, - error, - }); - } - }, -}); + return response.ok({ + body: res, + }); + } catch (error) { + throw createCaseError({ + message: `Failed to get status stats in route: ${error}`, + error, + }); + } + }, + }); diff --git a/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.test.ts b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.test.ts new file mode 100644 index 0000000000000..d99b90c29bbb4 --- /dev/null +++ b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getUserActionsRoute } from './get_all_user_actions'; + +describe('getUserActionsRoute', () => { + it('marks the endpoint internal in serverless', async () => { + const router = getUserActionsRoute({ isServerless: true }); + + expect(router.routerOptions?.access).toBe('internal'); + }); + + it('marks the endpoint public in non-serverless', async () => { + const router = getUserActionsRoute({ isServerless: false }); + + expect(router.routerOptions?.access).toBe('public'); + }); +}); diff --git a/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts index 17fe0dcdb9012..19d7f1f8956ac 100644 --- a/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts +++ b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts @@ -15,41 +15,42 @@ import { createCasesRoute } from '../create_cases_route'; /** * @deprecated since version 8.1.0 */ -export const getUserActionsRoute = createCasesRoute({ - method: 'get', - path: CASE_USER_ACTIONS_URL, - params: { - params: schema.object({ - case_id: schema.string(), - }), - }, - options: { deprecated: true }, - routerOptions: { - access: 'public', - summary: 'Get case activity', - description: `Returns all user activity for a case.`, - // You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the case you're seeking. - tags: ['oas-tag:cases'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - }, - handler: async ({ context, request, response }) => { - try { - const caseContext = await context.cases; - const casesClient = await caseContext.getCasesClient(); - const caseId = request.params.case_id; +export const getUserActionsRoute = ({ isServerless }: { isServerless?: boolean }) => + createCasesRoute({ + method: 'get', + path: CASE_USER_ACTIONS_URL, + params: { + params: schema.object({ + case_id: schema.string(), + }), + }, + options: { deprecated: true }, + routerOptions: { + access: isServerless ? 'internal' : 'public', + summary: 'Get case activity', + description: `Returns all user activity for a case.`, + // You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the case you're seeking. + tags: ['oas-tag:cases'], + // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} + deprecated: true, + }, + handler: async ({ context, request, response }) => { + try { + const caseContext = await context.cases; + const casesClient = await caseContext.getCasesClient(); + const caseId = request.params.case_id; - const res: userActionApiV1.CaseUserActionsDeprecatedResponse = - await casesClient.userActions.getAll({ caseId }); + const res: userActionApiV1.CaseUserActionsDeprecatedResponse = + await casesClient.userActions.getAll({ caseId }); - return response.ok({ - body: res, - }); - } catch (error) { - throw createCaseError({ - message: `Failed to retrieve case user actions in route case id: ${request.params.case_id}: ${error}`, - error, - }); - } - }, -}); + return response.ok({ + body: res, + }); + } catch (error) { + throw createCaseError({ + message: `Failed to retrieve case user actions in route case id: ${request.params.case_id}: ${error}`, + error, + }); + } + }, + }); diff --git a/x-pack/plugins/cases/server/telemetry/queries/alerts.test.ts b/x-pack/plugins/cases/server/telemetry/queries/alerts.test.ts index 11636b50ebd4e..fd00aea939dc8 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/alerts.test.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/alerts.test.ts @@ -17,19 +17,20 @@ describe('alerts', () => { const telemetrySavedObjectsClient = new TelemetrySavedObjectsClient(savedObjectsClient); savedObjectsClient.find.mockResolvedValue({ - total: 5, + total: 3, saved_objects: [], per_page: 1, page: 1, aggregations: { counts: { buckets: [ - { doc_count: 1, key: 1 }, - { doc_count: 2, key: 2 }, - { doc_count: 3, key: 3 }, + { topAlertsPerBucket: { value: 12 } }, + { topAlertsPerBucket: { value: 5 } }, + { topAlertsPerBucket: { value: 3 } }, ], }, references: { cases: { max: { value: 1 } } }, + uniqueAlertCommentsCount: { value: 5 }, }, }); @@ -42,12 +43,13 @@ describe('alerts', () => { savedObjectsClient: telemetrySavedObjectsClient, logger, }); + expect(res).toEqual({ all: { total: 5, daily: 3, - weekly: 2, - monthly: 1, + weekly: 5, + monthly: 12, maxOnACase: 1, }, }); @@ -76,6 +78,13 @@ describe('alerts', () => { }, ], }, + aggregations: { + topAlertsPerBucket: { + cardinality: { + field: 'cases-comments.attributes.alertId', + }, + }, + }, }, references: { aggregations: { @@ -85,10 +94,22 @@ describe('alerts', () => { terms: { field: 'cases-comments.references.id', }, + aggregations: { + reverse: { + reverse_nested: {}, + aggregations: { + topAlerts: { + cardinality: { + field: 'cases-comments.attributes.alertId', + }, + }, + }, + }, + }, }, max: { max_bucket: { - buckets_path: 'ids._count', + buckets_path: 'ids>reverse.topAlerts', }, }, }, @@ -103,6 +124,11 @@ describe('alerts', () => { path: 'cases-comments.references', }, }, + uniqueAlertCommentsCount: { + cardinality: { + field: 'cases-comments.attributes.alertId', + }, + }, }, filter: { arguments: [ diff --git a/x-pack/plugins/cases/server/telemetry/queries/alerts.ts b/x-pack/plugins/cases/server/telemetry/queries/alerts.ts index 96aaec211acb8..88a9c25c88c3d 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/alerts.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/alerts.ts @@ -5,17 +5,14 @@ * 2.0. */ -import { CASE_COMMENT_SAVED_OBJECT } from '../../../common/constants'; import type { CasesTelemetry, CollectTelemetryDataParams } from '../types'; -import { getCountsAndMaxData, getOnlyAlertsCommentsFilter } from './utils'; +import { getCountsAndMaxAlertsData } from './utils'; export const getAlertsTelemetryData = async ({ savedObjectsClient, }: CollectTelemetryDataParams): Promise => { - const res = await getCountsAndMaxData({ + const res = await getCountsAndMaxAlertsData({ savedObjectsClient, - savedObjectType: CASE_COMMENT_SAVED_OBJECT, - filter: getOnlyAlertsCommentsFilter(), }); return res; diff --git a/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts b/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts index 6c66c5aab81c7..b4b18f231eb6a 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts @@ -16,10 +16,12 @@ import type { import { findValueInBuckets, getAggregationsBuckets, + getAlertsCountsFromBuckets, getAttachmentsFrameworkStats, getBucketFromAggregation, getConnectorsCardinalityAggregationQuery, getCountsAggregationQuery, + getCountsAndMaxAlertsData, getCountsAndMaxData, getCountsFromBuckets, getCustomFieldsTelemetry, @@ -28,6 +30,7 @@ import { getOnlyConnectorsFilter, getReferencesAggregationQuery, getSolutionValues, + getUniqueAlertCommentsCountQuery, } from './utils'; import { TelemetrySavedObjectsClient } from '../telemetry_saved_objects_client'; @@ -994,6 +997,63 @@ describe('utils', () => { }); }); + describe('getAlertsCountsFromBuckets', () => { + it('returns the correct counts', () => { + const buckets = [ + { topAlertsPerBucket: { value: 12 } }, + { topAlertsPerBucket: { value: 5 } }, + { topAlertsPerBucket: { value: 3 } }, + ]; + + expect(getAlertsCountsFromBuckets(buckets)).toEqual({ + daily: 3, + weekly: 5, + monthly: 12, + }); + }); + + it('returns zero counts when the bucket does not have the topAlertsPerBucket field', () => { + const buckets = [{}]; + // @ts-expect-error + expect(getAlertsCountsFromBuckets(buckets)).toEqual({ + daily: 0, + weekly: 0, + monthly: 0, + }); + }); + + it('returns zero counts when the bucket is undefined', () => { + // @ts-expect-error + expect(getAlertsCountsFromBuckets(undefined)).toEqual({ + daily: 0, + weekly: 0, + monthly: 0, + }); + }); + + it('returns zero counts when the topAlertsPerBucket field is missing in some buckets', () => { + const buckets = [{ doc_count: 1, key: 1, topAlertsPerBucket: { value: 5 } }, {}, {}]; + // @ts-expect-error + expect(getAlertsCountsFromBuckets(buckets)).toEqual({ + daily: 0, + weekly: 0, + monthly: 5, + }); + }); + }); + + describe('getUniqueAlertCommentsCountQuery', () => { + it('returns the correct query', () => { + expect(getUniqueAlertCommentsCountQuery()).toEqual({ + uniqueAlertCommentsCount: { + cardinality: { + field: 'cases-comments.attributes.alertId', + }, + }, + }); + }); + }); + describe('getCountsAndMaxData', () => { const savedObjectsClient = savedObjectsRepositoryMock.create(); savedObjectsClient.find.mockResolvedValue({ @@ -1125,6 +1185,174 @@ describe('utils', () => { }); }); + describe('getCountsAndMaxAlertsData', () => { + const savedObjectsClient = savedObjectsRepositoryMock.create(); + savedObjectsClient.find.mockResolvedValue({ + total: 3, + saved_objects: [], + per_page: 1, + page: 1, + aggregations: { + counts: { + buckets: [ + { doc_count: 1, key: 1, topAlertsPerBucket: { value: 5 } }, + { doc_count: 2, key: 2, topAlertsPerBucket: { value: 3 } }, + { doc_count: 3, key: 3, topAlertsPerBucket: { value: 1 } }, + ], + }, + references: { cases: { max: { value: 1 } } }, + uniqueAlertCommentsCount: { value: 5 }, + }, + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('returns the correct counts and max data', async () => { + const telemetrySavedObjectsClient = new TelemetrySavedObjectsClient(savedObjectsClient); + + const res = await getCountsAndMaxAlertsData({ + savedObjectsClient: telemetrySavedObjectsClient, + }); + expect(res).toEqual({ + all: { + total: 5, + daily: 1, + weekly: 3, + monthly: 5, + maxOnACase: 1, + }, + }); + }); + + it('returns zero data if the response aggregation is not as expected', async () => { + const telemetrySavedObjectsClient = new TelemetrySavedObjectsClient(savedObjectsClient); + savedObjectsClient.find.mockResolvedValue({ + total: 5, + saved_objects: [], + per_page: 1, + page: 1, + }); + + const res = await getCountsAndMaxAlertsData({ + savedObjectsClient: telemetrySavedObjectsClient, + }); + expect(res).toEqual({ + all: { + total: 0, + daily: 0, + weekly: 0, + monthly: 0, + maxOnACase: 0, + }, + }); + }); + + it('should call find with correct arguments', async () => { + const telemetrySavedObjectsClient = new TelemetrySavedObjectsClient(savedObjectsClient); + + await getCountsAndMaxAlertsData({ + savedObjectsClient: telemetrySavedObjectsClient, + }); + + expect(savedObjectsClient.find).toBeCalledWith({ + aggs: { + counts: { + date_range: { + field: 'cases-comments.attributes.created_at', + format: 'dd/MM/YYYY', + ranges: [ + { + from: 'now-1d', + to: 'now', + }, + { + from: 'now-1w', + to: 'now', + }, + { + from: 'now-1M', + to: 'now', + }, + ], + }, + aggregations: { + topAlertsPerBucket: { + cardinality: { + field: 'cases-comments.attributes.alertId', + }, + }, + }, + }, + references: { + aggregations: { + cases: { + aggregations: { + ids: { + terms: { + field: 'cases-comments.references.id', + }, + aggregations: { + reverse: { + reverse_nested: {}, + aggregations: { + topAlerts: { + cardinality: { + field: 'cases-comments.attributes.alertId', + }, + }, + }, + }, + }, + }, + max: { + max_bucket: { + buckets_path: 'ids>reverse.topAlerts', + }, + }, + }, + filter: { + term: { + 'cases-comments.references.type': 'cases', + }, + }, + }, + }, + nested: { + path: 'cases-comments.references', + }, + }, + uniqueAlertCommentsCount: { + cardinality: { + field: 'cases-comments.attributes.alertId', + }, + }, + }, + filter: { + arguments: [ + { + isQuoted: false, + type: 'literal', + value: 'cases-comments.attributes.type', + }, + { + isQuoted: false, + type: 'literal', + value: 'alert', + }, + ], + function: 'is', + type: 'function', + }, + page: 0, + perPage: 0, + type: 'cases-comments', + namespaces: ['*'], + }); + }); + }); + describe('getBucketFromAggregation', () => { it('returns the buckets', () => { expect( diff --git a/x-pack/plugins/cases/server/telemetry/queries/utils.ts b/x-pack/plugins/cases/server/telemetry/queries/utils.ts index 65b81e3362300..6992ed8f7ac06 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/utils.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/utils.ts @@ -27,6 +27,7 @@ import type { FileAttachmentAggsResult, AttachmentFrameworkAggsResult, CustomFieldsTelemetry, + AlertBuckets, } from '../types'; import { buildFilter } from '../../client/utils'; import type { Owner } from '../../../common/constants/types'; @@ -47,6 +48,27 @@ export const getCountsAggregationQuery = (savedObjectType: string) => ({ }, }); +export const getAlertsCountsAggregationQuery = () => ({ + counts: { + date_range: { + field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.created_at`, + format: 'dd/MM/YYYY', + ranges: [ + { from: 'now-1d', to: 'now' }, + { from: 'now-1w', to: 'now' }, + { from: 'now-1M', to: 'now' }, + ], + }, + aggregations: { + topAlertsPerBucket: { + cardinality: { + field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.alertId`, + }, + }, + }, + }, +}); + export const getMaxBucketOnCaseAggregationQuery = (savedObjectType: string) => ({ references: { nested: { @@ -76,6 +98,55 @@ export const getMaxBucketOnCaseAggregationQuery = (savedObjectType: string) => ( }, }); +export const getAlertsMaxBucketOnCaseAggregationQuery = () => ({ + references: { + nested: { + path: `${CASE_COMMENT_SAVED_OBJECT}.references`, + }, + aggregations: { + cases: { + filter: { + term: { + [`${CASE_COMMENT_SAVED_OBJECT}.references.type`]: CASE_SAVED_OBJECT, + }, + }, + aggregations: { + ids: { + terms: { + field: `${CASE_COMMENT_SAVED_OBJECT}.references.id`, + }, + aggregations: { + reverse: { + reverse_nested: {}, + aggregations: { + topAlerts: { + cardinality: { + field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.alertId`, + }, + }, + }, + }, + }, + }, + max: { + max_bucket: { + buckets_path: 'ids>reverse.topAlerts', + }, + }, + }, + }, + }, + }, +}); + +export const getUniqueAlertCommentsCountQuery = () => ({ + uniqueAlertCommentsCount: { + cardinality: { + field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.alertId`, + }, + }, +}); + export const getReferencesAggregationQuery = ({ savedObjectType, referenceType, @@ -121,6 +192,52 @@ export const getCountsFromBuckets = (buckets: Buckets['buckets']) => ({ monthly: buckets?.[0]?.doc_count ?? 0, }); +export const getAlertsCountsFromBuckets = (buckets: AlertBuckets['buckets']) => ({ + daily: buckets?.[2]?.topAlertsPerBucket?.value ?? 0, + weekly: buckets?.[1]?.topAlertsPerBucket?.value ?? 0, + monthly: buckets?.[0]?.topAlertsPerBucket?.value ?? 0, +}); + +export const getCountsAndMaxAlertsData = async ({ + savedObjectsClient, +}: { + savedObjectsClient: TelemetrySavedObjectsClient; +}) => { + const filter = getOnlyAlertsCommentsFilter(); + + const res = await savedObjectsClient.find< + unknown, + { + counts: AlertBuckets; + references: MaxBucketOnCaseAggregation['references']; + uniqueAlertCommentsCount: { value: number }; + } + >({ + page: 0, + perPage: 0, + filter, + type: CASE_COMMENT_SAVED_OBJECT, + namespaces: ['*'], + aggs: { + ...getAlertsCountsAggregationQuery(), + ...getAlertsMaxBucketOnCaseAggregationQuery(), + ...getUniqueAlertCommentsCountQuery(), + }, + }); + + const countsBuckets = res.aggregations?.counts?.buckets ?? []; + const totalAlerts = res.aggregations?.uniqueAlertCommentsCount.value ?? 0; + const maxOnACase = res.aggregations?.references?.cases?.max?.value ?? 0; + + return { + all: { + total: totalAlerts, + ...getAlertsCountsFromBuckets(countsBuckets), + maxOnACase, + }, + }; +}; + export const getCountsAndMaxData = async ({ savedObjectsClient, savedObjectType, @@ -132,7 +249,10 @@ export const getCountsAndMaxData = async ({ }) => { const res = await savedObjectsClient.find< unknown, - { counts: Buckets; references: MaxBucketOnCaseAggregation['references'] } + { + counts: Buckets; + references: MaxBucketOnCaseAggregation['references']; + } >({ page: 0, perPage: 0, diff --git a/x-pack/plugins/cases/server/telemetry/types.ts b/x-pack/plugins/cases/server/telemetry/types.ts index b4996da27f234..228aa0c7ae397 100644 --- a/x-pack/plugins/cases/server/telemetry/types.ts +++ b/x-pack/plugins/cases/server/telemetry/types.ts @@ -17,6 +17,10 @@ export interface Bucket { key: T; } +export interface AlertBuckets { + buckets: Array<{ topAlertsPerBucket: { value: number } }>; +} + export interface Buckets { buckets: Array>; } diff --git a/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts b/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts index 5b064eecce12d..483e6771394d2 100644 --- a/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts +++ b/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { OnBoardingDefaultSolution } from './types'; +import type { SolutionId } from '@kbn/core-chrome-browser'; /** * Cloud does not type the value of the "use case" that is set during onboarding for a deployment. Any string can @@ -14,12 +14,12 @@ import type { OnBoardingDefaultSolution } from './types'; * @param value The solution value set by Cloud. * @returns The default solution value for onboarding that matches Kibana naming. */ -export function parseOnboardingSolution(value?: string): OnBoardingDefaultSolution | undefined { +export function parseOnboardingSolution(value?: string): SolutionId | undefined { if (!value) return; const solutions: Array<{ cloudValue: 'search' | 'elasticsearch' | 'observability' | 'security'; - kibanaValue: OnBoardingDefaultSolution; + kibanaValue: SolutionId; }> = [ { cloudValue: 'search', diff --git a/x-pack/plugins/cloud/common/types.ts b/x-pack/plugins/cloud/common/types.ts index 0f72caf515058..b3a32270af6cc 100644 --- a/x-pack/plugins/cloud/common/types.ts +++ b/x-pack/plugins/cloud/common/types.ts @@ -5,8 +5,6 @@ * 2.0. */ -export type OnBoardingDefaultSolution = 'es' | 'oblt' | 'security'; - export interface ElasticsearchConfigType { elasticsearch_url?: string; } diff --git a/x-pack/plugins/cloud/public/types.ts b/x-pack/plugins/cloud/public/types.ts index 2a6140ba8e97e..91972b69ec4ef 100644 --- a/x-pack/plugins/cloud/public/types.ts +++ b/x-pack/plugins/cloud/public/types.ts @@ -5,8 +5,8 @@ * 2.0. */ +import type { SolutionId } from '@kbn/core-chrome-browser'; import type { FC, PropsWithChildren } from 'react'; -import type { OnBoardingDefaultSolution } from '../common'; export interface CloudStart { /** @@ -192,7 +192,7 @@ export interface CloudSetup { /** * The default solution selected during onboarding. */ - defaultSolution?: OnBoardingDefaultSolution; + defaultSolution?: SolutionId; }; /** * `true` when running on Serverless Elastic Cloud diff --git a/x-pack/plugins/cloud/server/plugin.ts b/x-pack/plugins/cloud/server/plugin.ts index 9f45b5398ac22..9821aa318e264 100644 --- a/x-pack/plugins/cloud/server/plugin.ts +++ b/x-pack/plugins/cloud/server/plugin.ts @@ -8,10 +8,10 @@ import type { Logger } from '@kbn/logging'; import type { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/server'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; +import type { SolutionId } from '@kbn/core-chrome-browser'; import { registerCloudDeploymentMetadataAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context'; import type { CloudConfigType } from './config'; import { registerCloudUsageCollector } from './collectors'; -import type { OnBoardingDefaultSolution } from '../common'; import { getIsCloudEnabled } from '../common/is_cloud_enabled'; import { parseDeploymentIdFromDeploymentUrl } from '../common/parse_deployment_id_from_deployment_url'; import { decodeCloudId, DecodedCloudId } from '../common/decode_cloud_id'; @@ -108,7 +108,7 @@ export interface CloudSetup { /** * The default solution selected during onboarding. */ - defaultSolution?: OnBoardingDefaultSolution; + defaultSolution?: SolutionId; }; /** * `true` when running on Serverless Elastic Cloud diff --git a/x-pack/plugins/cloud/tsconfig.json b/x-pack/plugins/cloud/tsconfig.json index fdf2ad6db58cd..dd25064897758 100644 --- a/x-pack/plugins/cloud/tsconfig.json +++ b/x-pack/plugins/cloud/tsconfig.json @@ -12,6 +12,7 @@ ], "kbn_references": [ "@kbn/core", + "@kbn/core-chrome-browser", "@kbn/usage-collection-plugin", "@kbn/config-schema", "@kbn/logging-mocks", diff --git a/x-pack/plugins/cloud_defend/server/routes/policies/policies.ts b/x-pack/plugins/cloud_defend/server/routes/policies/policies.ts index 71d7f17ca612e..ad40dcf3b693f 100644 --- a/x-pack/plugins/cloud_defend/server/routes/policies/policies.ts +++ b/x-pack/plugins/cloud_defend/server/routes/policies/policies.ts @@ -42,7 +42,7 @@ const createPolicies = ( const agentPolicyStatus = { id: agentPolicy.id, name: agentPolicy.name, - agents: agentStatusByAgentPolicyId[agentPolicy.id]?.total, + agents: agentStatusByAgentPolicyId[agentPolicy.id]?.active, }; return { package_policy: cloudDefendPackage, diff --git a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts index 90e11734d72c6..86eb6ba963402 100644 --- a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts +++ b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts @@ -214,7 +214,7 @@ export const getBenchmarkApplicableTo = (benchmarkId: BenchmarksCisId) => { }; export const getCloudProviderNameFromAbbreviation = (cloudProvider: string) => { - switch (cloudProvider) { + switch (cloudProvider.toLowerCase()) { case 'azure': return CLOUD_PROVIDER_NAMES.AZURE; case 'aws': diff --git a/x-pack/plugins/cloud_security_posture/public/common/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/constants.ts index 50d191cf07167..fab73eb153e69 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/constants.ts @@ -256,3 +256,33 @@ export const VULNERABILITY_GROUPING_OPTIONS = { CLOUD_ACCOUNT_NAME: VULNERABILITY_FIELDS.CLOUD_ACCOUNT_NAME, CVE: VULNERABILITY_FIELDS.VULNERABILITY_ID, }; + +/* +The fields below are default columns of the Cloud Security Data Table that need to have keyword mapping. +The runtime mappings are used to prevent filtering out the data when any of these columns are sorted in the Data Table. +TODO: Remove the fields below once they are mapped as Keyword in the Third Party integrations, or remove +the fields from the runtime mappings if they are removed from the Data Table. +*/ +export const CDR_VULNERABILITY_DATA_TABLE_RUNTIME_MAPPING_FIELDS: string[] = [ + VULNERABILITY_FIELDS.VENDOR, +]; +export const CDR_MISCONFIGURATION_DATA_TABLE_RUNTIME_MAPPING_FIELDS: string[] = [ + 'rule.benchmark.rule_number', + 'rule.section', + 'resource.sub_type', +]; + +/* +The fields below are used to group the data in the Cloud Security Data Table. +The keys are the fields that are used to group the data, and the values are the fields that need to have keyword mapping +to prevent filtering out the data when grouping by the key field. +TODO: Remove the fields below once they are mapped as Keyword in the Third Party integrations, or remove +the fields from the runtime mappings if they are removed from the Data Table. +*/ +export const CDR_VULNERABILITY_GROUPING_RUNTIME_MAPPING_FIELDS: Record = { + [VULNERABILITY_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME]: [VULNERABILITY_FIELDS.CLOUD_PROVIDER], +}; +export const CDR_MISCONFIGURATION_GROUPING_RUNTIME_MAPPING_FIELDS: Record = { + [FINDINGS_GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME]: ['orchestrator.cluster.name'], + [FINDINGS_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME]: ['cloud.account.name'], +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.test.tsx index d81737fea1ec2..9f5f2ec85d021 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.test.tsx @@ -45,6 +45,7 @@ describe('AccountsEvaluatedWidget', () => { expect(mockNavToFindings).toHaveBeenCalledWith( { 'cloud.provider': 'aws', + 'rule.benchmark.posture_type': 'cspm', }, ['cloud.account.name'] ); diff --git a/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx b/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx index 1d4f26274690d..5ae8a47a93e71 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; import { useNavigateFindings } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; +import { CSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import { CLOUD_PROVIDERS, getBenchmarkApplicableTo } from '../../common/utils/helpers'; import { CIS_AWS, CIS_GCP, CIS_AZURE, CIS_K8S, CIS_EKS } from '../../common/constants'; import { CISBenchmarkIcon } from './cis_benchmark_icon'; @@ -61,7 +62,10 @@ export const AccountsEvaluatedWidget = ({ const navToFindings = useNavigateFindings(); const navToFindingsByCloudProvider = (provider: string) => { - navToFindings({ 'cloud.provider': provider }, [FINDINGS_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME]); + navToFindings( + { 'cloud.provider': provider, 'rule.benchmark.posture_type': CSPM_POLICY_TEMPLATE }, + [FINDINGS_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME] + ); }; const navToFindingsByCisBenchmark = (cisBenchmark: string) => { diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_provider_icon.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_provider_icon.tsx index b6acdac0ee1b1..a022e38960894 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_provider_icon.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_provider_icon.tsx @@ -18,7 +18,7 @@ interface Props { } const getCloudProviderIcon = (cloudProvider: string) => { - switch (cloudProvider) { + switch (cloudProvider.toLowerCase()) { case 'azure': return 'logoAzure'; case 'aws': diff --git a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.test.tsx new file mode 100644 index 0000000000000..166fb1184e0b9 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.test.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { ComplianceScoreBar } from './compliance_score_bar'; +import { + COMPLIANCE_SCORE_BAR_UNKNOWN, + COMPLIANCE_SCORE_BAR_PASSED, + COMPLIANCE_SCORE_BAR_FAILED, +} from './test_subjects'; + +describe('', () => { + it('should display 0% compliance score with status unknown when both passed and failed are 0', () => { + render(); + expect(screen.getByText('0%')).toBeInTheDocument(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).not.toBeNull(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).toBeNull(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).toBeNull(); + }); + + it('should display 100% compliance score when passed is greater than 0 and failed is 0', () => { + render(); + expect(screen.getByText('100%')).toBeInTheDocument(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).not.toBeNull(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).toBeNull(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull(); + }); + + it('should display 0% compliance score when passed is 0 and failed is greater than 0', () => { + render(); + expect(screen.getByText('0%')).toBeInTheDocument(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).not.toBeNull(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).toBeNull(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull(); + }); + + it('should display 50% compliance score when passed is equal to failed', () => { + render(); + expect(screen.getByText('50%')).toBeInTheDocument(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).not.toBeNull(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).not.toBeNull(); + expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull(); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx index d4acbc97ab10c..3829542829909 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx @@ -11,7 +11,12 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { statusColors } from '@kbn/cloud-security-posture'; import { calculatePostureScore } from '../../common/utils/helpers'; -import { CSP_FINDINGS_COMPLIANCE_SCORE } from './test_subjects'; +import { + CSP_FINDINGS_COMPLIANCE_SCORE, + COMPLIANCE_SCORE_BAR_UNKNOWN, + COMPLIANCE_SCORE_BAR_FAILED, + COMPLIANCE_SCORE_BAR_PASSED, +} from './test_subjects'; /** * This component will take 100% of the width set by the parent @@ -59,12 +64,22 @@ export const ComplianceScoreBar = ({ gap: 1px; `} > + {!totalPassed && !totalFailed && ( + + )} {!!totalPassed && ( )} {!!totalFailed && ( @@ -73,6 +88,7 @@ export const ComplianceScoreBar = ({ flex: ${totalFailed}; background: ${statusColors.failed}; `} + data-test-subj={COMPLIANCE_SCORE_BAR_FAILED} /> )} diff --git a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts index d29971d3352e3..b609950720ecd 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts @@ -92,3 +92,7 @@ export const CIS_GCP_INPUT_FIELDS_TEST_SUBJECTS = { }; export const SUBSCRIPTION_NOT_ALLOWED_TEST_SUBJECT = 'cloud_posture_page_subscription_not_allowed'; + +export const COMPLIANCE_SCORE_BAR_UNKNOWN = 'complianceScoreBarUnknown'; +export const COMPLIANCE_SCORE_BAR_FAILED = 'complianceScoreBarFailed'; +export const COMPLIANCE_SCORE_BAR_PASSED = 'complianceScoreBarPassed'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx index 4a4d4b6c1b193..f4cc7a5ba0028 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx @@ -13,7 +13,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { useNavigateFindings } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; -import type { NavFilter } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; +import type { NavFilter } from '@kbn/cloud-security-posture/src/utils/query_utils'; import type { BenchmarkData, ComplianceDashboardDataV2, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx index 9cb41910f8f83..e5ea0a9139a7e 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx @@ -16,7 +16,7 @@ import { import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; -import type { NavFilter } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; +import type { NavFilter } from '@kbn/cloud-security-posture/src/utils/query_utils'; import { useNavigateFindings } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; import { useCspIntegrationLink } from '../../../common/navigation/use_csp_integration_link'; import { DASHBOARD_COUNTER_CARDS, DASHBOARD_SUMMARY_CONTAINER } from '../test_subjects'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.test.tsx new file mode 100644 index 0000000000000..60aa64aa88141 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.test.tsx @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { useEuiTheme } from '@elastic/eui'; +import { ComplianceBarComponent } from './latest_findings_group_renderer'; +import { RawBucket } from '@kbn/grouping/src'; +import { FindingsGroupingAggregation } from './use_grouped_findings'; +import { ComplianceScoreBar } from '../../../components/compliance_score_bar'; + +jest.mock('@elastic/eui', () => { + const actual = jest.requireActual('@elastic/eui'); + return { + ...actual, + useEuiTheme: jest.fn(), + }; +}); + +jest.mock('../../../components/compliance_score_bar', () => ({ + ComplianceScoreBar: jest.fn(() => null), +})); + +jest.mock('../../../components/cloud_security_grouping'); + +describe('', () => { + beforeEach(() => { + (useEuiTheme as jest.Mock).mockReturnValue({ euiTheme: { size: { s: 's' } } }); + (ComplianceScoreBar as jest.Mock).mockClear(); + }); + + it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when total = failed+passed', () => { + const bucket = { + doc_count: 10, + failedFindings: { + doc_count: 4, + }, + passedFindings: { + doc_count: 6, + }, + } as RawBucket; + + render(); + + expect(ComplianceScoreBar).toHaveBeenCalledWith( + expect.objectContaining({ + totalFailed: 4, + totalPassed: 6, + }), + {} + ); + }); + + it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when there are unknown findings', () => { + const bucket = { + doc_count: 10, + failedFindings: { + doc_count: 3, + }, + passedFindings: { + doc_count: 6, + }, + } as RawBucket; + + render(); + + expect(ComplianceScoreBar).toHaveBeenCalledWith( + expect.objectContaining({ + totalFailed: 3, + totalPassed: 6, + }), + {} + ); + }); + + it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when there are no findings', () => { + const bucket = { + doc_count: 10, + failedFindings: { + doc_count: 0, + }, + passedFindings: { + doc_count: 0, + }, + } as RawBucket; + + render(); + + expect(ComplianceScoreBar).toHaveBeenCalledWith( + expect.objectContaining({ + totalFailed: 0, + totalPassed: 0, + }), + {} + ); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx index b4ad5d15ec8e9..b41c5e4996db1 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx @@ -198,11 +198,15 @@ const FindingsCountComponent = ({ bucket }: { bucket: RawBucket }) => { +export const ComplianceBarComponent = ({ + bucket, +}: { + bucket: RawBucket; +}) => { const { euiTheme } = useEuiTheme(); const totalFailed = bucket.failedFindings?.doc_count || 0; - const totalPassed = bucket.doc_count - totalFailed; + const totalPassed = bucket.passedFindings?.doc_count || 0; return ( { - return sort.reduce((acc, [field]) => { - // TODO: Add proper type for all fields available in the field selector - const type: RuntimePrimitiveTypes = field === '@timestamp' ? 'date' : 'keyword'; + return sort + .filter(([field]) => CDR_MISCONFIGURATION_DATA_TABLE_RUNTIME_MAPPING_FIELDS.includes(field)) + .reduce((acc, [field]) => { + const type: RuntimePrimitiveTypes = 'keyword'; - return { - ...acc, - [field]: { - type, - }, - }; - }, {}); + return { + ...acc, + [field]: { + type, + }, + }; + }, {}); }; export const getFindingsQuery = ( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx index e009ee966fb96..45c5418ed5129 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx @@ -21,6 +21,7 @@ import { } from '@kbn/cloud-security-posture-common'; import { useGetCspBenchmarkRulesStatesApi } from '@kbn/cloud-security-posture/src/hooks/use_get_benchmark_rules_state_api'; import { + CDR_MISCONFIGURATION_GROUPING_RUNTIME_MAPPING_FIELDS, FINDINGS_GROUPING_OPTIONS, LOCAL_STORAGE_FINDINGS_GROUPING_KEY, } from '../../../common/constants'; @@ -90,7 +91,6 @@ const getAggregationsByGroupField = (field: string): NamedAggregation[] => { ...aggMetrics, getTermAggregation('resourceName', 'resource.id'), getTermAggregation('resourceSubType', 'resource.sub_type'), - getTermAggregation('resourceType', 'resource.type'), ]; case FINDINGS_GROUPING_OPTIONS.RULE_NAME: return [ @@ -122,62 +122,18 @@ const getAggregationsByGroupField = (field: string): NamedAggregation[] => { const getRuntimeMappingsByGroupField = ( field: string ): Record | undefined => { - switch (field) { - case FINDINGS_GROUPING_OPTIONS.RESOURCE_NAME: - return { - [FINDINGS_GROUPING_OPTIONS.RESOURCE_NAME]: { - type: 'keyword', - }, - 'resource.id': { - type: 'keyword', - }, - 'resource.sub_type': { - type: 'keyword', - }, - 'resource.type': { - type: 'keyword', - }, - }; - case FINDINGS_GROUPING_OPTIONS.RULE_NAME: - return { - [FINDINGS_GROUPING_OPTIONS.RULE_NAME]: { - type: 'keyword', - }, - 'rule.benchmark.version': { - type: 'keyword', - }, - }; - case FINDINGS_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME: - return { - [FINDINGS_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME]: { + if (CDR_MISCONFIGURATION_GROUPING_RUNTIME_MAPPING_FIELDS?.[field]) { + return CDR_MISCONFIGURATION_GROUPING_RUNTIME_MAPPING_FIELDS[field].reduce( + (acc, runtimeField) => ({ + ...acc, + [runtimeField]: { type: 'keyword', }, - 'rule.benchmark.name': { - type: 'keyword', - }, - 'rule.benchmark.id': { - type: 'keyword', - }, - }; - case FINDINGS_GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME: - return { - [FINDINGS_GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME]: { - type: 'keyword', - }, - 'rule.benchmark.name': { - type: 'keyword', - }, - 'rule.benchmark.id': { - type: 'keyword', - }, - }; - default: - return { - [field]: { - type: 'keyword', - }, - }; + }), + {} + ); } + return {}; }; /** @@ -255,12 +211,7 @@ export const useLatestFindingsGrouping = ({ size: pageSize, sort: [{ groupByField: { order: 'desc' } }, { complianceScore: { order: 'asc' } }], statsAggregations: getAggregationsByGroupField(currentSelectedGroup), - runtimeMappings: { - ...getRuntimeMappingsByGroupField(currentSelectedGroup), - 'result.evaluation': { - type: 'keyword', - }, - }, + runtimeMappings: getRuntimeMappingsByGroupField(currentSelectedGroup), rootAggregations: [ { failedFindings: { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx index 5f01a4693c8f5..a998707c4704f 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx @@ -24,7 +24,10 @@ import { import { FindingsBaseEsQuery, showErrorToast } from '@kbn/cloud-security-posture'; import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; import type { RuntimePrimitiveTypes } from '@kbn/data-views-plugin/common'; -import { VULNERABILITY_FIELDS } from '../../../common/constants'; +import { + CDR_VULNERABILITY_DATA_TABLE_RUNTIME_MAPPING_FIELDS, + VULNERABILITY_FIELDS, +} from '../../../common/constants'; import { useKibana } from '../../../common/hooks/use_kibana'; import { getCaseInsensitiveSortScript } from '../utils/custom_sort_script'; type LatestFindingsRequest = IKibanaSearchRequest; @@ -54,22 +57,18 @@ const getMultiFieldsSort = (sort: string[][]) => { }; const getRuntimeMappingsFromSort = (sort: string[][]) => { - return sort.reduce((acc, [field]) => { - // TODO: Add proper type for all fields available in the field selector - const type: RuntimePrimitiveTypes = - field === VULNERABILITY_FIELDS.SCORE_BASE - ? 'double' - : field === '@timestamp' - ? 'date' - : 'keyword'; + return sort + .filter(([field]) => CDR_VULNERABILITY_DATA_TABLE_RUNTIME_MAPPING_FIELDS.includes(field)) + .reduce((acc, [field]) => { + const type: RuntimePrimitiveTypes = 'keyword'; - return { - ...acc, - [field]: { - type, - }, - }; - }, {}); + return { + ...acc, + [field]: { + type, + }, + }; + }, {}); }; export const getVulnerabilitiesQuery = ( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx index d79b4620ec899..1d73b21f083a5 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx @@ -23,6 +23,7 @@ import { LOCAL_STORAGE_VULNERABILITIES_GROUPING_KEY, VULNERABILITY_GROUPING_OPTIONS, VULNERABILITY_FIELDS, + CDR_VULNERABILITY_GROUPING_RUNTIME_MAPPING_FIELDS, } from '../../../common/constants'; import { useDataViewContext } from '../../../common/contexts/data_view_context'; import { @@ -102,41 +103,18 @@ const getAggregationsByGroupField = (field: string): NamedAggregation[] => { const getRuntimeMappingsByGroupField = ( field: string ): Record | undefined => { - switch (field) { - case VULNERABILITY_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME: - return { - [VULNERABILITY_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME]: { - type: 'keyword', - }, - [VULNERABILITY_FIELDS.CLOUD_PROVIDER]: { - type: 'keyword', - }, - }; - case VULNERABILITY_GROUPING_OPTIONS.RESOURCE_NAME: - return { - [VULNERABILITY_GROUPING_OPTIONS.RESOURCE_NAME]: { - type: 'keyword', - }, - [VULNERABILITY_FIELDS.RESOURCE_ID]: { - type: 'keyword', - }, - }; - case VULNERABILITY_GROUPING_OPTIONS.CVE: - return { - [VULNERABILITY_GROUPING_OPTIONS.CVE]: { - type: 'keyword', - }, - [VULNERABILITY_FIELDS.DESCRIPTION]: { - type: 'keyword', - }, - }; - default: - return { - [field]: { + if (CDR_VULNERABILITY_GROUPING_RUNTIME_MAPPING_FIELDS?.[field]) { + return CDR_VULNERABILITY_GROUPING_RUNTIME_MAPPING_FIELDS[field].reduce( + (acc, runtimeField) => ({ + ...acc, + [runtimeField]: { type: 'keyword', }, - }; + }), + {} + ); } + return {}; }; /** diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_statistics.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_statistics.tsx index 114f28ccfc271..de1f7ec3ba37a 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_statistics.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_statistics.tsx @@ -7,7 +7,7 @@ import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiHealth } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { useNavigateVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; +import { useNavigateNativeVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; import { VULNERABILITIES_SEVERITY } from '@kbn/cloud-security-posture-common'; import { getSeverityStatusColor } from '@kbn/cloud-security-posture'; import { VulnCounterCard, type VulnCounterCardProps } from '../../components/vuln_counter_card'; @@ -15,7 +15,7 @@ import { useVulnerabilityDashboardApi } from '../../common/api/use_vulnerability import { CompactFormattedNumber } from '../../components/compact_formatted_number'; export const VulnerabilityStatistics = () => { - const navToVulnerabilities = useNavigateVulnerabilities(); + const navToVulnerabilities = useNavigateNativeVulnerabilities(); const getVulnerabilityDashboard = useVulnerabilityDashboardApi(); const stats: VulnCounterCardProps[] = useMemo( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx index 28012e3e8e438..c3a5f21867723 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx @@ -16,8 +16,8 @@ import { useEuiTheme, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { NavFilter } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; -import { useNavigateVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; +import type { NavFilter } from '@kbn/cloud-security-posture/src/utils/query_utils'; +import { useNavigateNativeVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; import type { VulnSeverity } from '@kbn/cloud-security-posture-common'; import { CVSScoreBadge, SeverityStatusBadge } from '@kbn/cloud-security-posture'; import { @@ -33,7 +33,7 @@ import { VULNERABILITY_GROUPING_OPTIONS, VULNERABILITY_FIELDS } from '../../comm export const VulnerabilityTablePanelSection = () => { const getVulnerabilityDashboard = useVulnerabilityDashboardApi(); const { euiTheme } = useEuiTheme(); - const navToVulnerabilities = useNavigateVulnerabilities(); + const navToVulnerabilities = useNavigateNativeVulnerabilities(); const onCellClick = useCallback( (filters: NavFilter) => { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_trend_graph.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_trend_graph.tsx index ff610b640cd3f..599928eea88b8 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_trend_graph.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_trend_graph.tsx @@ -19,7 +19,7 @@ import { EuiButton, EuiComboBox } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useNavigateVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; +import { useNavigateNativeVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; import type { VulnSeverity } from '@kbn/cloud-security-posture-common'; import { VULNERABILITIES_SEVERITY } from '@kbn/cloud-security-posture-common'; import { getSeverityStatusColor } from '@kbn/cloud-security-posture'; @@ -50,7 +50,7 @@ const theme: PartialTheme = { }; const ViewAllButton = () => { - const navToVulnerabilities = useNavigateVulnerabilities(); + const navToVulnerabilities = useNavigateNativeVulnerabilities(); return ( navToVulnerabilities()} size="s"> diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/v1.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/v1.ts index 611a58436e995..c52b57d057c38 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/v1.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/v1.ts @@ -48,7 +48,7 @@ export const getBenchmarksData = ( const agentPolicyStatus = { id: agentPolicy.id, name: agentPolicy.name, - agents: agentStatusByAgentPolicyId[agentPolicy.id]?.total, + agents: agentStatusByAgentPolicyId[agentPolicy.id]?.active, }; return { package_policy: cspPackage, diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.test.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.test.ts new file mode 100644 index 0000000000000..fa26fb68289a6 --- /dev/null +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.test.ts @@ -0,0 +1,454 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core/server'; +import moment from 'moment-timezone'; + +import type { + FetchAvailableCatIndicesResponseRequired, + IndexSearchAggregationResponse, +} from './fetch_available_indices'; +import { fetchAvailableIndices } from './fetch_available_indices'; + +function getEsClientMock() { + return { + search: jest.fn().mockResolvedValue({ + aggregations: { + index: { + buckets: [], + }, + }, + }), + cat: { + indices: jest.fn().mockResolvedValue([]), + }, + } as unknown as ElasticsearchClient & { + cat: { + indices: jest.Mock>; + }; + search: jest.Mock>; + }; +} + +// fixing timezone for both Date and moment +// so when tests are run in different timezones, the results are consistent +process.env.TZ = 'UTC'; +moment.tz.setDefault('UTC'); + +const DAY_IN_MILLIS = 24 * 60 * 60 * 1000; + +// We assume that the dates are in UTC, because es is using UTC +// It also diminishes difference date parsing by Date and moment constructors +// in different timezones, i.e. short ISO format '2021-10-01' is parsed as local +// date by moment and as UTC date by Date, whereas long ISO format '2021-10-01T00:00:00Z' +// is parsed as UTC date by both +const startDateString: string = '2021-10-01T00:00:00Z'; +const endDateString: string = '2021-10-07T00:00:00Z'; + +const startDateMillis: number = new Date(startDateString).getTime(); +const endDateMillis: number = new Date(endDateString).getTime(); + +describe('fetchAvailableIndices', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('aggregate search given index by startDate and endDate', async () => { + const esClientMock = getEsClientMock(); + + await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(esClientMock.search).toHaveBeenCalledWith({ + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'strict_date_optional_time', + gte: startDateString, + lte: endDateString, + }, + }, + }, + ], + must: [], + must_not: [], + should: [], + }, + }, + index: 'logs-*', + size: 0, + aggs: { + index: { + terms: { + field: '_index', + }, + }, + }, + }); + }); + + it('should call esClient.cat.indices for given index', async () => { + const esClientMock = getEsClientMock(); + + await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(esClientMock.cat.indices).toHaveBeenCalledWith({ + index: 'logs-*', + format: 'json', + h: 'index,creation.date', + }); + }); + + describe('when indices are created within the date range', () => { + it('returns indices within the date range', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockResolvedValue([ + { + index: 'logs-2021.10.01', + 'creation.date': `${startDateMillis}`, + }, + { + index: 'logs-2021.10.05', + 'creation.date': `${startDateMillis + 4 * DAY_IN_MILLIS}`, + }, + { + index: 'logs-2021.09.30', + 'creation.date': `${startDateMillis - DAY_IN_MILLIS}`, + }, + ]); + + const result = await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(result).toEqual(['logs-2021.10.01', 'logs-2021.10.05']); + + expect(esClientMock.cat.indices).toHaveBeenCalledWith({ + index: 'logs-*', + format: 'json', + h: 'index,creation.date', + }); + }); + }); + + describe('when indices are outside the date range', () => { + it('returns an empty list', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockResolvedValue([ + { + index: 'logs-2021.09.30', + 'creation.date': `${startDateMillis - DAY_IN_MILLIS}`, + }, + { + index: 'logs-2021.10.08', + 'creation.date': `${endDateMillis + DAY_IN_MILLIS}`, + }, + ]); + + const result = await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(result).toEqual([]); + }); + }); + + describe('when no indices match the index pattern', () => { + it('returns empty list', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockResolvedValue([]); + + const result = await fetchAvailableIndices(esClientMock, { + indexPattern: 'nonexistent-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(result).toEqual([]); + }); + }); + + describe('when indices have data in the date range', () => { + it('returns indices with data in the date range', async () => { + const esClientMock = getEsClientMock(); + + // esClient.cat.indices returns no indices + esClientMock.cat.indices.mockResolvedValue([]); + + // esClient.search returns indices with data in the date range + esClientMock.search.mockResolvedValue({ + aggregations: { + index: { + buckets: [ + { key: 'logs-2021.10.02', doc_count: 100 }, + { key: 'logs-2021.10.03', doc_count: 150 }, + ], + }, + }, + }); + + const result = await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(result).toEqual(['logs-2021.10.02', 'logs-2021.10.03']); + }); + + it('combines indices from both methods without duplicates', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockResolvedValue([ + { + index: 'logs-2021.10.01', + 'creation.date': `${startDateMillis}`, + }, + { + index: 'logs-2021.10.03', + 'creation.date': `${startDateMillis + 2 * DAY_IN_MILLIS}`, + }, + ]); + + esClientMock.search.mockResolvedValue({ + aggregations: { + index: { + buckets: [ + { key: 'logs-2021.10.03', doc_count: 150 }, + { key: 'logs-2021.10.04', doc_count: 200 }, + ], + }, + }, + }); + + const result = await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(result).toEqual(['logs-2021.10.01', 'logs-2021.10.03', 'logs-2021.10.04']); + }); + }); + + describe('edge cases for creation dates', () => { + it('includes indices with creation date exactly at startDate and endDate', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockResolvedValue([ + { + index: 'logs-2021.10.01', + 'creation.date': `${startDateMillis}`, + }, + { + index: 'logs-2021.10.07', + 'creation.date': `${endDateMillis}`, + }, + ]); + + const result = await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(result).toEqual(['logs-2021.10.01', 'logs-2021.10.07']); + }); + }); + + describe('when esClient.search rejects', () => { + it('throws an error', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.search.mockRejectedValue(new Error('Elasticsearch search error')); + + await expect( + fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }) + ).rejects.toThrow('Elasticsearch search error'); + }); + }); + + describe('when both esClient.cat.indices and esClient.search return empty', () => { + it('returns an empty list', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockResolvedValue([]); + esClientMock.search.mockResolvedValue({ + aggregations: { + index: { + buckets: [], + }, + }, + }); + + const result = await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(result).toEqual([]); + }); + }); + + describe('when indices are returned with both methods and have duplicates', () => { + it('does not duplicate indices in the result', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockResolvedValue([ + { + index: 'logs-2021.10.05', + 'creation.date': `${startDateMillis + 4 * DAY_IN_MILLIS}`, + }, + ]); + + esClientMock.search.mockResolvedValue({ + aggregations: { + index: { + buckets: [{ key: 'logs-2021.10.05', doc_count: 100 }], + }, + }, + }); + + const result = await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }); + + expect(result).toEqual(['logs-2021.10.05']); + }); + }); + + describe('given keyword dates', () => { + describe('given 7 days range', () => { + beforeEach(() => { + jest.useFakeTimers(); + jest.setSystemTime(new Date('2021-10-07T00:00:00Z').getTime()); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('finds indices created within the date range', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockResolvedValue([ + { + index: 'logs-2021.10.01', + 'creation.date': `${startDateMillis}`, + }, + { + index: 'logs-2021.10.05', + 'creation.date': `${startDateMillis + 4 * DAY_IN_MILLIS}`, + }, + ]); + + const results = await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: 'now-7d/d', + endDate: 'now/d', + }); + + expect(results).toEqual(['logs-2021.10.01', 'logs-2021.10.05']); + }); + + it('finds indices with end date rounded up to the end of the day', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockResolvedValue([ + { + index: 'logs-2021.10.06', + 'creation.date': `${new Date('2021-10-06T23:59:59Z').getTime()}`, + }, + ]); + + const results = await fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: 'now-7d/d', + endDate: 'now-1d/d', + }); + + expect(results).toEqual(['logs-2021.10.06']); + }); + }); + }); + + describe('rejections', () => { + beforeEach(() => { + jest.spyOn(console, 'warn').mockImplementation(() => {}); + }); + afterEach(() => { + jest.restoreAllMocks(); + }); + describe('when esClient.cat.indices rejects', () => { + it('throws an error', async () => { + const esClientMock = getEsClientMock(); + + esClientMock.cat.indices.mockRejectedValue(new Error('Elasticsearch error')); + + await expect( + fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: endDateString, + }) + ).rejects.toThrow('Elasticsearch error'); + }); + }); + + describe('when startDate is invalid', () => { + it('throws an error', async () => { + const esClientMock = getEsClientMock(); + + await expect( + fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: 'invalid-date', + endDate: endDateString, + }) + ).rejects.toThrow('Invalid date format: invalid-date'); + }); + }); + + describe('when endDate is invalid', () => { + it('throws an error', async () => { + const esClientMock = getEsClientMock(); + + await expect( + fetchAvailableIndices(esClientMock, { + indexPattern: 'logs-*', + startDate: startDateString, + endDate: 'invalid-date', + }) + ).rejects.toThrow('Invalid date format: invalid-date'); + }); + }); + }); +}); diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.ts index 584a261689113..32311f28d636a 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.ts @@ -4,18 +4,72 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import type { ElasticsearchClient } from '@kbn/core/server'; +import type { CatIndicesIndicesRecord } from '@elastic/elasticsearch/lib/api/types'; +import dateMath from '@kbn/datemath'; + import { getRequestBody } from '../helpers/get_available_indices'; +export type FetchAvailableCatIndicesResponseRequired = Array< + Required> +>; + type AggregateName = 'index'; -interface Result { +export interface IndexSearchAggregationResponse { index: { - buckets: Array<{ key: string }>; - doc_count: number; + buckets: Array<{ key: string; doc_count: number }>; }; } -export const fetchAvailableIndices = ( +const getParsedDateMs = (dateStr: string, roundUp = false) => { + const date = dateMath.parse(dateStr, roundUp ? { roundUp: true } : undefined); + if (!date?.isValid()) { + throw new Error(`Invalid date format: ${dateStr}`); + } + return date.valueOf(); +}; + +export const fetchAvailableIndices = async ( esClient: ElasticsearchClient, params: { indexPattern: string; startDate: string; endDate: string } -) => esClient.search(getRequestBody(params)); +): Promise => { + const { indexPattern, startDate, endDate } = params; + + const startDateMs = getParsedDateMs(startDate); + const endDateMs = getParsedDateMs(endDate, true); + + const indicesCats = (await esClient.cat.indices({ + index: indexPattern, + format: 'json', + h: 'index,creation.date', + })) as FetchAvailableCatIndicesResponseRequired; + + const indicesCatsInRange = indicesCats.filter((indexInfo) => { + const creationDateMs = parseInt(indexInfo['creation.date'], 10); + return creationDateMs >= startDateMs && creationDateMs <= endDateMs; + }); + + const timeSeriesIndicesWithDataInRangeSearchResult = await esClient.search< + AggregateName, + IndexSearchAggregationResponse + >(getRequestBody(params)); + + const timeSeriesIndicesWithDataInRange = + timeSeriesIndicesWithDataInRangeSearchResult.aggregations?.index.buckets.map( + (bucket) => bucket.key + ) || []; + + // Combine indices from both sources removing duplicates + const resultingIndices = new Set(); + + for (const indicesCat of indicesCatsInRange) { + resultingIndices.add(indicesCat.index); + } + + for (const timeSeriesIndex of timeSeriesIndicesWithDataInRange) { + resultingIndices.add(timeSeriesIndex); + } + + return Array.from(resultingIndices); +}; diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_stats.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_stats.ts index 536fd461c61c9..40fc59219342c 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_stats.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_stats.ts @@ -57,16 +57,16 @@ export const parseMeteringStats = (meteringStatsIndices: MeteringStatsIndex[]) = }, {}); export const pickAvailableMeteringStats = ( - indicesBuckets: Array<{ key: string }>, + indicesBuckets: string[], meteringStatsIndices: Record ) => - indicesBuckets.reduce((acc: Record, { key }: { key: string }) => { - if (meteringStatsIndices?.[key]) { - acc[key] = { - name: meteringStatsIndices?.[key].name, - num_docs: meteringStatsIndices?.[key].num_docs, + indicesBuckets.reduce((acc: Record, indexName: string) => { + if (meteringStatsIndices?.[indexName]) { + acc[indexName] = { + name: meteringStatsIndices?.[indexName].name, + num_docs: meteringStatsIndices?.[indexName].num_docs, size_in_bytes: null, // We don't have size_in_bytes intentionally when ILM is not available - data_stream: meteringStatsIndices?.[key].data_stream, + data_stream: meteringStatsIndices?.[indexName].data_stream, }; } return acc; diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_ilm_explain.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_ilm_explain.ts index 31202adffed2c..ee413ea09ef67 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_ilm_explain.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_ilm_explain.ts @@ -19,7 +19,11 @@ export const getILMExplainRoute = (router: IRouter, logger: Logger) => { .get({ path: GET_ILM_EXPLAIN, access: 'internal', - options: { tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_mappings.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_mappings.ts index f3c59ccf9f3e2..845e118bc6f05 100755 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_mappings.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_mappings.ts @@ -19,7 +19,11 @@ export const getIndexMappingsRoute = (router: IRouter, logger: Logger) => { .get({ path: GET_INDEX_MAPPINGS, access: 'internal', - options: { tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.test.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.test.ts index f3ff5ec256ad6..91996a4ab9f89 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.test.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.test.ts @@ -152,17 +152,7 @@ describe('getIndexStatsRoute route', () => { }, }; (fetchMeteringStats as jest.Mock).mockResolvedValue(mockMeteringStatsIndex); - (fetchAvailableIndices as jest.Mock).mockResolvedValue({ - aggregations: { - index: { - buckets: [ - { - key: 'my-index-000001', - }, - ], - }, - }, - }); + (fetchAvailableIndices as jest.Mock).mockResolvedValue(['my-index-000001']); const response = await server.inject(request, requestContextMock.convertContext(context)); expect(response.status).toEqual(200); @@ -198,7 +188,7 @@ describe('getIndexStatsRoute route', () => { ); }); - test('returns an empty object when "availableIndices" indices are not available', async () => { + test('returns an empty object when "availableIndices" indices are empty', async () => { const request = requestMock.create({ method: 'get', path: GET_INDEX_STATS, @@ -214,9 +204,7 @@ describe('getIndexStatsRoute route', () => { const mockIndices = {}; (fetchMeteringStats as jest.Mock).mockResolvedValue(mockMeteringStatsIndex); - (fetchAvailableIndices as jest.Mock).mockResolvedValue({ - aggregations: undefined, - }); + (fetchAvailableIndices as jest.Mock).mockResolvedValue([]); const response = await server.inject(request, requestContextMock.convertContext(context)); expect(response.status).toEqual(200); diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.ts index 665c178c62cdf..d1bb25d34fc2a 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.ts @@ -26,7 +26,11 @@ export const getIndexStatsRoute = (router: IRouter, logger: Logger) => { .get({ path: GET_INDEX_STATS, access: 'internal', - options: { tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, }) .addVersion( { @@ -86,7 +90,7 @@ export const getIndexStatsRoute = (router: IRouter, logger: Logger) => { endDate: decodedEndDate, }); - if (!availableIndices.aggregations?.index?.buckets) { + if (availableIndices.length === 0) { logger.warn( `No available indices found under pattern: ${decodedIndexName}, in the given date range: ${decodedStartDate} - ${decodedEndDate}` ); @@ -95,10 +99,7 @@ export const getIndexStatsRoute = (router: IRouter, logger: Logger) => { }); } - const indices = pickAvailableMeteringStats( - availableIndices.aggregations.index.buckets, - meteringStatsIndices - ); + const indices = pickAvailableMeteringStats(availableIndices, meteringStatsIndices); return response.ok({ body: indices, diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results.ts index bbab7dede3c21..71f2422146f9c 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results.ts @@ -87,7 +87,11 @@ export const getIndexResultsRoute = ( .get({ path: GET_INDEX_RESULTS, access: 'internal', - options: { tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.ts index 55ff8e01a01dc..3a294409af869 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.ts @@ -41,7 +41,11 @@ export const getIndexResultsLatestRoute = ( .get({ path: GET_INDEX_RESULTS_LATEST, access: 'internal', - options: { tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/post_index_results.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/post_index_results.ts index 5e87cadb4dadf..0c627d4cc0364 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/post_index_results.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/post_index_results.ts @@ -24,7 +24,11 @@ export const postIndexResultsRoute = ( .post({ path: POST_INDEX_RESULTS, access: 'internal', - options: { tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/ecs_data_quality_dashboard/tsconfig.json b/x-pack/plugins/ecs_data_quality_dashboard/tsconfig.json index ceb43169165b4..cf31d7461b509 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/tsconfig.json +++ b/x-pack/plugins/ecs_data_quality_dashboard/tsconfig.json @@ -26,6 +26,7 @@ "@kbn/core-elasticsearch-server-mocks", "@kbn/core-elasticsearch-server", "@kbn/core-security-common", + "@kbn/datemath", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/elastic_assistant/server/__mocks__/msearch_query.ts b/x-pack/plugins/elastic_assistant/server/__mocks__/msearch_query.ts index e411dfaa2f1ef..ae5adcfab61aa 100644 --- a/x-pack/plugins/elastic_assistant/server/__mocks__/msearch_query.ts +++ b/x-pack/plugins/elastic_assistant/server/__mocks__/msearch_query.ts @@ -34,12 +34,10 @@ export const mSearchQueryBody: MsearchQueryBody = { ], must: [ { - text_expansion: { - 'vector.tokens': { - model_id: '.elser_model_2', - model_text: - 'Generate an ESQL query that will count the number of connections made to external IP addresses, broken down by user. If the count is greater than 100 for a specific user, add a new field called "follow_up" that contains a value of "true", otherwise, it should contain "false". The user names should also be enriched with their respective group names.', - }, + semantic: { + field: 'semantic_text', + query: + 'Generate an ESQL query that will count the number of connections made to external IP addresses, broken down by user. If the count is greater than 100 for a specific user, add a new field called "follow_up" that contains a value of "true", otherwise, it should contain "false". The user names should also be enriched with their respective group names.', }, }, ], diff --git a/x-pack/plugins/elastic_assistant/server/__mocks__/vector_search_query.ts b/x-pack/plugins/elastic_assistant/server/__mocks__/vector_search_query.ts index 30fbd0ad2c58f..04263c5d242bb 100644 --- a/x-pack/plugins/elastic_assistant/server/__mocks__/vector_search_query.ts +++ b/x-pack/plugins/elastic_assistant/server/__mocks__/vector_search_query.ts @@ -26,12 +26,10 @@ export const mockVectorSearchQuery: QueryDslQueryContainer = { ], must: [ { - text_expansion: { - 'vector.tokens': { - model_id: '.elser_model_2', - model_text: - 'Generate an ES|QL query that will count the number of connections made to external IP addresses, broken down by user. If the count is greater than 100 for a specific user, add a new field called "follow_up" that contains a value of "true", otherwise, it should contain "false". The user names should also be enriched with their respective group names.', - }, + semantic: { + field: 'semantic_text', + query: + 'Generate an ES|QL query that will count the number of connections made to external IP addresses, broken down by user. If the count is greater than 100 for a specific user, add a new field called "follow_up" that contains a value of "true", otherwise, it should contain "false". The user names should also be enriched with their respective group names.', }, }, ], diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/anonymization_fields/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/anonymization_fields/helpers.ts index 9a4a3b6e1c0ce..0f577df4e56e1 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/anonymization_fields/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/anonymization_fields/helpers.ts @@ -99,7 +99,8 @@ export const getUpdateScript = ({ isPatch?: boolean; }) => { return { - source: ` + script: { + source: ` if (params.assignEmpty == true || params.containsKey('allowed')) { ctx._source.allowed = params.allowed; } @@ -108,11 +109,12 @@ export const getUpdateScript = ({ } ctx._source.updated_at = params.updated_at; `, - lang: 'painless', - params: { - ...anonymizationField, // when assigning undefined in painless, it will remove property and wil set it to null - // for patch we don't want to remove unspecified value in payload - assignEmpty: !(isPatch ?? true), + lang: 'painless', + params: { + ...anonymizationField, // when assigning undefined in painless, it will remove property and wil set it to null + // for patch we don't want to remove unspecified value in payload + assignEmpty: !(isPatch ?? true), + }, }, }; }; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/helpers.ts index 9e52b4a7414a6..bdd1107942cc1 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/helpers.ts @@ -15,7 +15,8 @@ export const getUpdateScript = ({ isPatch?: boolean; }) => { return { - source: ` + script: { + source: ` if (params.assignEmpty == true || params.containsKey('api_config')) { if (ctx._source.api_config != null) { if (params.assignEmpty == true || params.api_config.containsKey('connector_id')) { @@ -70,11 +71,12 @@ export const getUpdateScript = ({ } ctx._source.updated_at = params.updated_at; `, - lang: 'painless', - params: { - ...conversation, // when assigning undefined in painless, it will remove property and wil set it to null - // for patch we don't want to remove unspecified value in payload - assignEmpty: !(isPatch ?? true), + lang: 'painless', + params: { + ...conversation, // when assigning undefined in painless, it will remove property and wil set it to null + // for patch we don't want to remove unspecified value in payload + assignEmpty: !(isPatch ?? true), + }, }, }; }; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/update_conversation.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/update_conversation.ts index 807fea2decd99..7e9ee336f6fe1 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/update_conversation.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/update_conversation.ts @@ -76,7 +76,7 @@ export const updateConversation = async ({ }, }, refresh: true, - script: getUpdateScript({ conversation: params, isPatch }), + script: getUpdateScript({ conversation: params, isPatch }).script, }); if (response.failures && response.failures.length > 0) { diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts index 23f73501b1056..09bb5b291ef9a 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts @@ -139,55 +139,11 @@ export const getUpdateScript = ({ entry: UpdateKnowledgeBaseEntrySchema; isPatch?: boolean; }) => { + // Cannot use script for updating documents with semantic_text fields return { - source: ` - if (params.assignEmpty == true || params.containsKey('name')) { - ctx._source.name = params.name; - } - if (params.assignEmpty == true || params.containsKey('type')) { - ctx._source.type = params.type; - } - if (params.assignEmpty == true || params.containsKey('users')) { - ctx._source.users = params.users; - } - if (params.assignEmpty == true || params.containsKey('query_description')) { - ctx._source.query_description = params.query_description; - } - if (params.assignEmpty == true || params.containsKey('input_schema')) { - ctx._source.input_schema = params.input_schema; - } - if (params.assignEmpty == true || params.containsKey('output_fields')) { - ctx._source.output_fields = params.output_fields; - } - if (params.assignEmpty == true || params.containsKey('kb_resource')) { - ctx._source.kb_resource = params.kb_resource; - } - if (params.assignEmpty == true || params.containsKey('required')) { - ctx._source.required = params.required; - } - if (params.assignEmpty == true || params.containsKey('source')) { - ctx._source.source = params.source; - } - if (params.assignEmpty == true || params.containsKey('text')) { - ctx._source.text = params.text; - } - if (params.assignEmpty == true || params.containsKey('description')) { - ctx._source.description = params.description; - } - if (params.assignEmpty == true || params.containsKey('field')) { - ctx._source.field = params.field; - } - if (params.assignEmpty == true || params.containsKey('index')) { - ctx._source.index = params.index; - } - ctx._source.updated_at = params.updated_at; - ctx._source.updated_by = params.updated_by; - `, - lang: 'painless', - params: { - ...entry, // when assigning undefined in painless, it will remove property and wil set it to null - // for patch we don't want to remove unspecified value in payload - assignEmpty: !(isPatch ?? true), + doc: { + ...entry, + semantic_text: entry.text, }, }; }; @@ -247,7 +203,7 @@ export const transformToCreateSchema = ({ required: entry.required ?? false, source: entry.source, text: entry.text, - vector: undefined, + semantic_text: entry.text, }; }; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/field_maps_configuration.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/field_maps_configuration.ts index 0712664bbfeed..348efb5a18f7d 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/field_maps_configuration.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/field_maps_configuration.ts @@ -6,6 +6,8 @@ */ import { FieldMap } from '@kbn/data-stream-adapter'; +export const ASSISTANT_ELSER_INFERENCE_ID = 'elastic-security-ai-assistant-elser2'; + export const knowledgeBaseFieldMap: FieldMap = { '@timestamp': { type: 'date', @@ -169,6 +171,12 @@ export const knowledgeBaseFieldMapV2: FieldMap = { required: false, }, // Embeddings field + semantic_text: { + type: 'semantic_text', + array: false, + required: false, + inference_id: ASSISTANT_ELSER_INFERENCE_ID, + }, vector: { type: 'object', array: false, diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts index de76a38135f0b..a19b3f0945086 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts @@ -46,7 +46,7 @@ export const getKBVectorSearchQuery = ({ filter?: QueryDslQueryContainer | undefined; kbResource?: string | undefined; modelId: string; - query: string; + query?: string; required?: boolean | undefined; user: AuthenticatedUser; v2KnowledgeBaseEnabled: boolean; @@ -114,20 +114,37 @@ export const getKBVectorSearchQuery = ({ ], }; - return { - bool: { - must: [ - { - text_expansion: { - 'vector.tokens': { - model_id: modelId, - model_text: query, - }, + let semanticTextFilter: + | Array<{ semantic: { field: string; query: string } }> + | Array<{ + text_expansion: { 'vector.tokens': { model_id: string; model_text: string } }; + }> = []; + + if (v2KnowledgeBaseEnabled && query) { + semanticTextFilter = [ + { + semantic: { + field: 'semantic_text', + query, + }, + }, + ]; + } else if (!v2KnowledgeBaseEnabled) { + semanticTextFilter = [ + { + text_expansion: { + 'vector.tokens': { + model_id: modelId, + model_text: query as string, }, }, - ...requiredFilter, - ...resourceFilter, - ], + }, + ]; + } + + return { + bool: { + must: [...semanticTextFilter, ...requiredFilter, ...resourceFilter], ...userFilter, filter, minimum_should_match: 1, @@ -220,6 +237,17 @@ export const getStructuredToolForIndexEntry = ({ return { ...prev, [field]: hit._source[field] }; }, {}); } + + // We want to send relevant inner hits (chunks) to the LLM as a context + const innerHitPath = `${indexEntry.name}.${indexEntry.field}`; + if (hit.inner_hits?.[innerHitPath]) { + return { + text: hit.inner_hits[innerHitPath].hits.hits + .map((innerHit) => innerHit._source.text) + .join('\n --- \n'), + }; + } + return { text: get(hit._source, `${indexEntry.field}.inference.chunks[0].text`), }; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts index 64e7b00089c08..f985095661f3e 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts @@ -8,6 +8,7 @@ import { MlTrainedModelDeploymentNodesStats, MlTrainedModelStats, + SearchTotalHits, } from '@elastic/elasticsearch/lib/api/types'; import type { MlPluginSetup } from '@kbn/ml-plugin/server'; import type { KibanaRequest } from '@kbn/core-http-server'; @@ -25,6 +26,8 @@ import pRetry from 'p-retry'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { StructuredTool } from '@langchain/core/tools'; import { ElasticsearchClient } from '@kbn/core/server'; +import { IndexPatternsFetcher } from '@kbn/data-views-plugin/server'; +import { map } from 'lodash'; import { AIAssistantDataClient, AIAssistantDataClientParams } from '..'; import { AssistantToolParams, GetElser } from '../../types'; import { @@ -38,6 +41,7 @@ import { transformESSearchToKnowledgeBaseEntry } from './transforms'; import { ESQL_DOCS_LOADED_QUERY, SECURITY_LABS_RESOURCE, + USER_RESOURCE, } from '../../routes/knowledge_base/constants'; import { getKBVectorSearchQuery, @@ -45,7 +49,11 @@ import { isModelAlreadyExistsError, } from './helpers'; import { getKBUserFilter } from '../../routes/knowledge_base/entries/utils'; -import { loadSecurityLabs } from '../../lib/langchain/content_loaders/security_labs_loader'; +import { + loadSecurityLabs, + getSecurityLabsDocsCount, +} from '../../lib/langchain/content_loaders/security_labs_loader'; +import { ASSISTANT_ELSER_INFERENCE_ID } from './field_maps_configuration'; /** * Params for when creating KbDataClient in Request Context Factory. Useful if needing to modify @@ -169,30 +177,83 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { this.options.logger.debug(`Checking if ELSER model '${elserId}' is deployed...`); try { - const esClient = await this.options.elasticsearchClientPromise; - const getResponse = await esClient.ml.getTrainedModelsStats({ - model_id: elserId, - }); + if (this.isV2KnowledgeBaseEnabled) { + return await this.isInferenceEndpointExists(); + } else { + const esClient = await this.options.elasticsearchClientPromise; + const getResponse = await esClient.ml.getTrainedModelsStats({ + model_id: elserId, + }); - // For standardized way of checking deployment status see: https://github.com/elastic/elasticsearch/issues/106986 - const isReadyESS = (stats: MlTrainedModelStats) => - stats.deployment_stats?.state === 'started' && - stats.deployment_stats?.allocation_status.state === 'fully_allocated'; + // For standardized way of checking deployment status see: https://github.com/elastic/elasticsearch/issues/106986 + const isReadyESS = (stats: MlTrainedModelStats) => + stats.deployment_stats?.state === 'started' && + stats.deployment_stats?.allocation_status.state === 'fully_allocated'; - const isReadyServerless = (stats: MlTrainedModelStats) => - (stats.deployment_stats?.nodes as unknown as MlTrainedModelDeploymentNodesStats[]).some( - (node) => node.routing_state.routing_state === 'started' - ); + const isReadyServerless = (stats: MlTrainedModelStats) => + (stats.deployment_stats?.nodes as unknown as MlTrainedModelDeploymentNodesStats[])?.some( + (node) => node.routing_state.routing_state === 'started' + ); - return getResponse.trained_model_stats.some( - (stats) => isReadyESS(stats) || isReadyServerless(stats) - ); + return getResponse.trained_model_stats?.some( + (stats) => isReadyESS(stats) || isReadyServerless(stats) + ); + } } catch (e) { + this.options.logger.debug(`Error checking if ELSER model '${elserId}' is deployed: ${e}`); // Returns 404 if it doesn't exist return false; } }; + public isInferenceEndpointExists = async (): Promise => { + try { + const esClient = await this.options.elasticsearchClientPromise; + + return !!(await esClient.inference.get({ + inference_id: ASSISTANT_ELSER_INFERENCE_ID, + task_type: 'sparse_embedding', + })); + } catch (error) { + this.options.logger.debug( + `Error checking if Inference endpoint ${ASSISTANT_ELSER_INFERENCE_ID} exists: ${error}` + ); + return false; + } + }; + + public createInferenceEndpoint = async () => { + const elserId = await this.options.getElserId(); + this.options.logger.debug(`Deploying ELSER model '${elserId}'...`); + try { + const esClient = await this.options.elasticsearchClientPromise; + if (this.isV2KnowledgeBaseEnabled) { + await esClient.inference.put({ + task_type: 'sparse_embedding', + inference_id: ASSISTANT_ELSER_INFERENCE_ID, + inference_config: { + service: 'elasticsearch', + service_settings: { + adaptive_allocations: { + enabled: true, + min_number_of_allocations: 0, + max_number_of_allocations: 8, + }, + num_threads: 1, + model_id: elserId, + }, + task_settings: {}, + }, + }); + } + } catch (error) { + this.options.logger.error( + `Error creating inference endpoint for ELSER model '${elserId}':\n${error}` + ); + throw new Error(`Error creating inference endpoint for ELSER model '${elserId}':\n${error}`); + } + }; + /** * Downloads and deploys recommended ELSER (if not already), then loads ES|QL docs * @@ -238,8 +299,22 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { `Removed ${legacyESQL?.total} ESQL knowledge base docs from knowledge base data stream: ${this.indexTemplateAndPattern.alias}.` ); } + // Delete any existing Security Labs content + const securityLabsDocs = await esClient.deleteByQuery({ + index: this.indexTemplateAndPattern.alias, + query: { + bool: { + must: [{ terms: { kb_resource: [SECURITY_LABS_RESOURCE] } }], + }, + }, + }); + if (securityLabsDocs?.total) { + this.options.logger.info( + `Removed ${securityLabsDocs?.total} Security Labs knowledge base docs from knowledge base data stream: ${this.indexTemplateAndPattern.alias}.` + ); + } } catch (e) { - this.options.logger.info('No legacy ESQL knowledge base docs to delete'); + this.options.logger.info('No legacy ESQL or Security Labs knowledge base docs to delete'); } } @@ -259,19 +334,34 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { this.options.logger.debug(`ELSER model '${elserId}' is already installed`); } - const isDeployed = await this.isModelDeployed(); - if (!isDeployed) { - await this.deployModel(); - await pRetry( - async () => - (await this.isModelDeployed()) - ? Promise.resolve() - : Promise.reject(new Error('Model not deployed')), - { minTimeout: 2000, retries: 10 } - ); - this.options.logger.debug(`ELSER model '${elserId}' successfully deployed!`); + if (!this.isV2KnowledgeBaseEnabled) { + const isDeployed = await this.isModelDeployed(); + if (!isDeployed) { + await this.deployModel(); + await pRetry( + async () => + (await this.isModelDeployed()) + ? Promise.resolve() + : Promise.reject(new Error('Model not deployed')), + { minTimeout: 2000, retries: 10 } + ); + this.options.logger.debug(`ELSER model '${elserId}' successfully deployed!`); + } else { + this.options.logger.debug(`ELSER model '${elserId}' is already deployed`); + } } else { - this.options.logger.debug(`ELSER model '${elserId}' is already deployed`); + const inferenceExists = await this.isInferenceEndpointExists(); + if (!inferenceExists) { + await this.createInferenceEndpoint(); + + this.options.logger.debug( + `Inference endpoint for ELSER model '${elserId}' successfully deployed!` + ); + } else { + this.options.logger.debug( + `Inference endpoint for ELSER model '${elserId}' is already deployed` + ); + } } this.options.logger.debug(`Checking if Knowledge Base docs have been loaded...`); @@ -289,8 +379,9 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { this.options.setIsKBSetupInProgress(false); this.options.logger.error(`Error setting up Knowledge Base: ${e.message}`); throw new Error(`Error setting up Knowledge Base: ${e.message}`); + } finally { + this.options.setIsKBSetupInProgress(false); } - this.options.setIsKBSetupInProgress(false); }; /** @@ -385,15 +476,87 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { }; /** - * Returns if Security Labs KB docs have been loaded + * Returns if user's KB docs exists + */ + + public isUserDataExists = async (): Promise => { + const user = this.options.currentUser; + if (user == null) { + throw new Error( + 'Authenticated user not found! Ensure kbDataClient was initialized from a request.' + ); + } + + const esClient = await this.options.elasticsearchClientPromise; + const modelId = await this.options.getElserId(); + + try { + const vectorSearchQuery = getKBVectorSearchQuery({ + kbResource: USER_RESOURCE, + required: false, + user, + modelId, + v2KnowledgeBaseEnabled: this.options.v2KnowledgeBaseEnabled, + }); + + const result = await esClient.search({ + index: this.indexTemplateAndPattern.alias, + size: 0, + query: vectorSearchQuery, + track_total_hits: true, + }); + + return !!(result.hits?.total as SearchTotalHits).value; + } catch (e) { + this.options.logger.debug(`Error checking if user's KB docs exist: ${e.message}`); + return false; + } + }; + + /** + * Returns if allSecurity Labs KB docs have been loaded */ public isSecurityLabsDocsLoaded = async (): Promise => { - const securityLabsDocs = await this.getKnowledgeBaseDocumentEntries({ - query: '', - kbResource: SECURITY_LABS_RESOURCE, - required: false, - }); - return securityLabsDocs.length > 0; + const user = this.options.currentUser; + if (user == null) { + throw new Error( + 'Authenticated user not found! Ensure kbDataClient was initialized from a request.' + ); + } + + const expectedDocsCount = await getSecurityLabsDocsCount({ logger: this.options.logger }); + + const esClient = await this.options.elasticsearchClientPromise; + const modelId = await this.options.getElserId(); + + try { + const vectorSearchQuery = getKBVectorSearchQuery({ + kbResource: SECURITY_LABS_RESOURCE, + required: false, + user, + modelId, + v2KnowledgeBaseEnabled: this.options.v2KnowledgeBaseEnabled, + }); + + const result = await esClient.search({ + index: this.indexTemplateAndPattern.alias, + size: 0, + query: vectorSearchQuery, + track_total_hits: true, + }); + + const existingDocs = (result.hits?.total as SearchTotalHits).value; + + if (existingDocs !== expectedDocsCount) { + this.options.logger.debug( + `Security Labs docs are not loaded, existing docs: ${existingDocs}, expected docs: ${expectedDocsCount}` + ); + } + return existingDocs === expectedDocsCount; + } catch (e) { + this.options.logger.info(`Error checking if Security Labs docs are loaded: ${e.message}`); + return false; + } }; /** @@ -423,10 +586,10 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { const vectorSearchQuery = getKBVectorSearchQuery({ filter, kbResource, - modelId, query, required, user, + modelId, v2KnowledgeBaseEnabled: this.options.v2KnowledgeBaseEnabled, }); @@ -576,7 +739,9 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { } try { - const elserId = await this.options.getElserId(); + const elserId = this.isV2KnowledgeBaseEnabled + ? ASSISTANT_ELSER_INFERENCE_ID + : await this.options.getElserId(); const userFilter = getKBUserFilter(user); const results = await this.findDocuments({ // Note: This is a magic number to set some upward bound as to not blow the context with too @@ -595,14 +760,21 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { if (results) { const entries = transformESSearchToKnowledgeBaseEntry(results.data) as IndexEntry[]; - return entries.map((indexEntry) => { - return getStructuredToolForIndexEntry({ - indexEntry, - esClient, - logger: this.options.logger, - elserId, - }); - }); + const indexPatternFetcher = new IndexPatternsFetcher(esClient); + const existingIndices = await indexPatternFetcher.getExistingIndices(map(entries, 'index')); + return ( + entries + // Filter out any IndexEntries that don't have an existing index + .filter((entry) => existingIndices.includes(entry.index)) + .map((indexEntry) => { + return getStructuredToolForIndexEntry({ + indexEntry, + esClient, + logger: this.options.logger, + elserId, + }); + }) + ); } } catch (e) { this.options.logger.error(`kbDataClient.getAssistantTools() - Failed to fetch IndexEntries`); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/ingest_pipeline.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/ingest_pipeline.ts index e11840b94e660..8f459848af420 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/ingest_pipeline.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/ingest_pipeline.ts @@ -5,22 +5,31 @@ * 2.0. */ -// TODO: Ensure old pipeline is updated/replaced -export const knowledgeBaseIngestPipeline = ({ id, modelId }: { id: string; modelId: string }) => ({ +export const knowledgeBaseIngestPipeline = ({ + id, + modelId, + v2KnowledgeBaseEnabled, +}: { + id: string; + modelId: string; + v2KnowledgeBaseEnabled: boolean; +}) => ({ id, description: 'Embedding pipeline for Elastic AI Assistant ELSER Knowledge Base', - processors: [ - { - inference: { - if: 'ctx?.text != null', - model_id: modelId, - input_output: [ - { - input_field: 'text', - output_field: 'vector.tokens', + processors: !v2KnowledgeBaseEnabled + ? [ + { + inference: { + if: 'ctx?.text != null', + model_id: modelId, + input_output: [ + { + input_field: 'text', + output_field: 'vector.tokens', + }, + ], }, - ], - }, - }, - ], + }, + ] + : [], }); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts index 3de1a15d79b2a..443d03941ccdd 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts @@ -27,6 +27,7 @@ export interface EsDocumentEntry { required: boolean; source: string; text: string; + semantic_text?: string; vector?: { tokens: Record; model_id: string; @@ -99,6 +100,7 @@ export interface UpdateKnowledgeBaseEntrySchema { required?: boolean; source?: string; text?: string; + semantic_text?: string; vector?: { tokens: Record; model_id: string; @@ -135,6 +137,7 @@ export interface CreateKnowledgeBaseEntrySchema { required?: boolean; source?: string; text?: string; + semantic_text?: string; vector?: { tokens: Record; model_id: string; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/prompts/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/prompts/helpers.ts index a4534972c8478..eb71270127b2a 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/prompts/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/prompts/helpers.ts @@ -143,7 +143,8 @@ export const getUpdateScript = ({ isPatch?: boolean; }) => { return { - source: ` + script: { + source: ` if (params.assignEmpty == true || params.containsKey('content')) { ctx._source.content = params.content; } @@ -158,11 +159,12 @@ export const getUpdateScript = ({ } ctx._source.updated_at = params.updated_at; `, - lang: 'painless', - params: { - ...prompt, // when assigning undefined in painless, it will remove property and wil set it to null - // for patch we don't want to remove unspecified value in payload - assignEmpty: !(isPatch ?? true), + lang: 'painless', + params: { + ...prompt, // when assigning undefined in painless, it will remove property and wil set it to null + // for patch we don't want to remove unspecified value in payload + assignEmpty: !(isPatch ?? true), + }, }, }; }; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/create_resource_installation_helper.test.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/create_resource_installation_helper.test.ts index 8e34581332ff6..85f6de83592ae 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/create_resource_installation_helper.test.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/create_resource_installation_helper.test.ts @@ -141,7 +141,7 @@ describe('createResourceInstallationHelper', () => { async () => (await getContextInitialized(helper)) === false ); - expect(logger.error).toHaveBeenCalledWith(`Error initializing resources test1 - fail`); + expect(logger.warn).toHaveBeenCalledWith(`Error initializing resources test1 - fail`); expect(await helper.getInitializedResources('test1')).toEqual({ result: false, error: `fail`, @@ -204,7 +204,7 @@ describe('createResourceInstallationHelper', () => { async () => (await getContextInitialized(helper)) === false ); - expect(logger.error).toHaveBeenCalledWith(`Error initializing resources default - first error`); + expect(logger.warn).toHaveBeenCalledWith(`Error initializing resources default - first error`); expect(await helper.getInitializedResources(DEFAULT_NAMESPACE_STRING)).toEqual({ result: false, error: `first error`, @@ -221,9 +221,7 @@ describe('createResourceInstallationHelper', () => { return logger.error.mock.calls.length === 1; }); - expect(logger.error).toHaveBeenCalledWith( - `Error initializing resources default - second error` - ); + expect(logger.warn).toHaveBeenCalledWith(`Error initializing resources default - second error`); // the second retry is throttled so this is never called expect(logger.info).not.toHaveBeenCalledWith('test1_default successfully retried'); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/create_resource_installation_helper.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/create_resource_installation_helper.ts index 39e0e69a8fc49..e8d1f1eb1d85d 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/create_resource_installation_helper.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/create_resource_installation_helper.ts @@ -65,7 +65,7 @@ export function createResourceInstallationHelper( return errorResult(commonInitError); } } catch (err) { - logger.error(`Error initializing resources ${namespace} - ${err.message}`); + logger.warn(`Error initializing resources ${namespace} - ${err.message}`); return errorResult(err.message); } }; @@ -113,7 +113,7 @@ export function createResourceInstallationHelper( const key = namespace; return ( initializedResources.has(key) - ? initializedResources.get(key) + ? await initializedResources.get(key) : errorResult(`Unrecognized spaceId ${key}`) ) as InitializationPromise; }, diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts index 07da930320712..93338174364fc 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts @@ -54,6 +54,7 @@ interface CreatePipelineParams { esClient: ElasticsearchClient; id: string; modelId: string; + v2KnowledgeBaseEnabled: boolean; } /** @@ -70,12 +71,14 @@ export const createPipeline = async ({ esClient, id, modelId, + v2KnowledgeBaseEnabled, }: CreatePipelineParams): Promise => { try { const response = await esClient.ingest.putPipeline( knowledgeBaseIngestPipeline({ id, modelId, + v2KnowledgeBaseEnabled, }) ); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.test.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.test.ts index 8bd1173e93d89..23a1a55564415 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.test.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.test.ts @@ -18,11 +18,17 @@ import { AIAssistantService, AIAssistantServiceOpts } from '.'; import { retryUntil } from './create_resource_installation_helper.test'; import { mlPluginMock } from '@kbn/ml-plugin/public/mocks'; import type { MlPluginSetup } from '@kbn/ml-plugin/server'; +import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; jest.mock('../ai_assistant_data_clients/conversations', () => ({ AIAssistantConversationsDataClient: jest.fn(), })); +const licensing = Promise.resolve( + licensingMock.createRequestHandlerContext({ + license: { type: 'enterprise' }, + }) +); let logger: ReturnType<(typeof loggingSystemMock)['createLogger']>; const clusterClient = elasticsearchServiceMock.createClusterClient().asInternalUser; @@ -191,6 +197,7 @@ describe('AI Assistant Service', () => { logger, spaceId: 'default', currentUser: mockUser1, + licensing, }); expect(AIAssistantConversationsDataClient).toHaveBeenCalledWith({ @@ -221,6 +228,7 @@ describe('AI Assistant Service', () => { logger, spaceId: 'default', currentUser: mockUser1, + licensing, }); expect(clusterClient.indices.putIndexTemplate).toHaveBeenCalled(); @@ -274,11 +282,13 @@ describe('AI Assistant Service', () => { logger, spaceId: 'default', currentUser: mockUser1, + licensing, }), assistantService.createAIAssistantConversationsDataClient({ logger, spaceId: 'default', currentUser: mockUser1, + licensing, }), ]); @@ -340,6 +350,7 @@ describe('AI Assistant Service', () => { logger, spaceId: 'default', currentUser: mockUser1, + licensing, }); expect(AIAssistantConversationsDataClient).toHaveBeenCalledWith({ @@ -400,6 +411,7 @@ describe('AI Assistant Service', () => { logger, spaceId: 'default', currentUser: mockUser1, + licensing, }); }; @@ -472,6 +484,7 @@ describe('AI Assistant Service', () => { logger, spaceId: 'default', currentUser: mockUser1, + licensing, }); }; @@ -513,6 +526,7 @@ describe('AI Assistant Service', () => { logger, spaceId: 'test', currentUser: mockUser1, + licensing, }); expect(clusterClient.indices.putIndexTemplate).not.toHaveBeenCalled(); @@ -560,6 +574,7 @@ describe('AI Assistant Service', () => { logger, spaceId: 'test', currentUser: mockUser1, + licensing, }); expect(clusterClient.indices.putIndexTemplate).not.toHaveBeenCalled(); @@ -607,6 +622,7 @@ describe('AI Assistant Service', () => { logger, spaceId: 'test', currentUser: mockUser1, + licensing, }); expect(AIAssistantConversationsDataClient).not.toHaveBeenCalled(); @@ -752,6 +768,7 @@ describe('AI Assistant Service', () => { logger, spaceId: 'default', currentUser: mockUser1, + licensing, }); await retryUntil( diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts index bfdf8b96f44b0..15274f2323259 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts @@ -11,6 +11,7 @@ import type { AuthenticatedUser, Logger, ElasticsearchClient } from '@kbn/core/s import type { TaskManagerSetupContract } from '@kbn/task-manager-plugin/server'; import type { MlPluginSetup } from '@kbn/ml-plugin/server'; import { Subject } from 'rxjs'; +import { LicensingApiRequestHandlerContext } from '@kbn/licensing-plugin/server'; import { attackDiscoveryFieldMap } from '../lib/attack_discovery/persistence/field_maps_configuration/field_maps_configuration'; import { getDefaultAnonymizationFields } from '../../common/anonymization'; import { AssistantResourceNames, GetElser } from '../types'; @@ -36,6 +37,7 @@ import { } from '../ai_assistant_data_clients/knowledge_base'; import { AttackDiscoveryDataClient } from '../lib/attack_discovery/persistence'; import { createGetElserId, createPipeline, pipelineExists } from './helpers'; +import { hasAIAssistantLicense } from '../routes/helpers'; const TOTAL_FIELDS_LIMIT = 2500; @@ -56,6 +58,7 @@ export interface CreateAIAssistantClientParams { logger: Logger; spaceId: string; currentUser: AuthenticatedUser | null; + licensing: Promise; } export type CreateDataStream = (params: { @@ -97,7 +100,7 @@ export class AIAssistantService { this.knowledgeBaseDataStream = this.createDataStream({ resource: 'knowledgeBase', kibanaVersion: options.kibanaVersion, - fieldMap: knowledgeBaseFieldMap, // TODO: use V2 if FF is enabled + fieldMap: knowledgeBaseFieldMap, }); this.promptsDataStream = this.createDataStream({ resource: 'prompts', @@ -151,7 +154,9 @@ export class AIAssistantService { name: this.resourceNames.indexTemplate[resource], componentTemplateRefs: [this.resourceNames.componentTemplate[resource]], // Apply `default_pipeline` if pipeline exists for resource - ...(resource in this.resourceNames.pipelines + ...(resource in this.resourceNames.pipelines && + // Remove this param and initialization when the `assistantKnowledgeBaseByDefault` feature flag is removed + !(resource === 'knowledgeBase' && this.v2KnowledgeBaseEnabled) ? { template: { settings: { @@ -202,7 +207,12 @@ export class AIAssistantService { id: this.resourceNames.pipelines.knowledgeBase, }); // TODO: When FF is removed, ensure pipeline is re-created for those upgrading - if (!pipelineCreated || this.v2KnowledgeBaseEnabled) { + if ( + // Install for v1 + (!this.v2KnowledgeBaseEnabled && !pipelineCreated) || + // Upgrade from v1 to v2 + (pipelineCreated && this.v2KnowledgeBaseEnabled) + ) { this.options.logger.debug( `Installing ingest pipeline - ${this.resourceNames.pipelines.knowledgeBase}` ); @@ -210,6 +220,7 @@ export class AIAssistantService { esClient, id: this.resourceNames.pipelines.knowledgeBase, modelId: await this.getElserId(), + v2KnowledgeBaseEnabled: this.v2KnowledgeBaseEnabled, }); this.options.logger.debug(`Installed ingest pipeline: ${response}`); @@ -237,7 +248,7 @@ export class AIAssistantService { pluginStop$: this.options.pluginStop$, }); } catch (error) { - this.options.logger.error(`Error initializing AI assistant resources: ${error.message}`); + this.options.logger.warn(`Error initializing AI assistant resources: ${error.message}`); this.initialized = false; this.isInitializing = false; return errorResult(error.message); @@ -282,6 +293,8 @@ export class AIAssistantService { }; private async checkResourcesInstallation(opts: CreateAIAssistantClientParams) { + const licensing = await opts.licensing; + if (!hasAIAssistantLicense(licensing.license)) return null; // Check if resources installation has succeeded const { result: initialized, error } = await this.getSpaceResourcesInitializationPromise( opts.spaceId @@ -502,7 +515,7 @@ export class AIAssistantService { await this.createDefaultAnonymizationFields(spaceId); } } catch (error) { - this.options.logger.error( + this.options.logger.warn( `Error initializing AI assistant namespace level resources: ${error.message}` ); throw error; diff --git a/x-pack/plugins/elastic_assistant/server/lib/data_stream/documents_data_writer.ts b/x-pack/plugins/elastic_assistant/server/lib/data_stream/documents_data_writer.ts index 32b579fdeb71a..08892038a58b7 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/data_stream/documents_data_writer.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/data_stream/documents_data_writer.ts @@ -34,7 +34,10 @@ interface BulkParams { documentsToCreate?: TCreateParams[]; documentsToUpdate?: TUpdateParams[]; documentsToDelete?: string[]; - getUpdateScript?: (document: TUpdateParams, updatedAt: string) => Script; + getUpdateScript?: ( + document: TUpdateParams, + updatedAt: string + ) => { script?: Script; doc?: TUpdateParams }; authenticatedUser?: AuthenticatedUser; } @@ -73,7 +76,7 @@ export class DocumentsDataWriter implements DocumentsDataWriter { body: await this.buildBulkOperations(params), }, { - // Increasing timout to 2min as KB docs were failing to load after 30s + // Increasing timeout to 2min as KB docs were failing to load after 30s requestTimeout: 120000, } ); @@ -151,7 +154,10 @@ export class DocumentsDataWriter implements DocumentsDataWriter { private getUpdateDocumentsQuery = async ( documentsToUpdate: TUpdateParams[], - getUpdateScript: (document: TUpdateParams, updatedAt: string) => Script, + getUpdateScript: ( + document: TUpdateParams, + updatedAt: string + ) => { script?: Script; doc?: TUpdateParams }, authenticatedUser?: AuthenticatedUser ) => { const updatedAt = new Date().toISOString(); @@ -196,10 +202,7 @@ export class DocumentsDataWriter implements DocumentsDataWriter { _source: true, }, }, - { - script: getUpdateScript(document, updatedAt), - upsert: { counter: 1 }, - }, + getUpdateScript(document, updatedAt), ]); }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/security_labs_loader.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/security_labs_loader.ts index 10566b3e5a1d5..f37e20df2bd98 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/security_labs_loader.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/security_labs_loader.ts @@ -5,13 +5,14 @@ * 2.0. */ +import globby from 'globby'; import { Logger } from '@kbn/core/server'; import { DirectoryLoader } from 'langchain/document_loaders/fs/directory'; import { TextLoader } from 'langchain/document_loaders/fs/text'; import { resolve } from 'path'; import { Document } from 'langchain/document'; import { Metadata } from '@kbn/elastic-assistant-common'; - +import pMap from 'p-map'; import { addRequiredKbResourceMetadata } from './add_required_kb_resource_metadata'; import { SECURITY_LABS_RESOURCE } from '../../../routes/knowledge_base/constants'; import { AIAssistantKnowledgeBaseDataClient } from '../../../ai_assistant_data_clients/knowledge_base'; @@ -42,10 +43,22 @@ export const loadSecurityLabs = async ( logger.info(`Loading ${docs.length} Security Labs docs into the Knowledge Base`); - const response = await kbDataClient.addKnowledgeBaseDocuments({ - documents: docs, - global: true, - }); + /** + * Ingest Security Labs docs into the Knowledge Base one by one to avoid blocking + * Inference Endpoint for too long + */ + + const response = ( + await pMap( + docs, + (singleDoc) => + kbDataClient.addKnowledgeBaseDocuments({ + documents: [singleDoc], + global: true, + }), + { concurrency: 1 } + ) + ).flat(); logger.info(`Loaded ${response?.length ?? 0} Security Labs docs into the Knowledge Base`); @@ -55,3 +68,13 @@ export const loadSecurityLabs = async ( return false; } }; + +export const getSecurityLabsDocsCount = async ({ logger }: { logger: Logger }): Promise => { + try { + return (await globby(`${resolve(__dirname, '../../../knowledge_base/security_labs')}/**/*.md`)) + ?.length; + } catch (e) { + logger.error(`Failed to get Security Labs source docs count\n${e}`); + return 0; + } +}; diff --git a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/bulk_actions_route.ts index 5464756739c08..9aedffae5cfb5 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/bulk_actions_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/bulk_actions_route.ts @@ -38,7 +38,7 @@ import { EsAnonymizationFieldsSchema, UpdateAnonymizationFieldSchema, } from '../../ai_assistant_data_clients/anonymization_fields/types'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; +import { performChecks } from '../helpers'; export interface BulkOperationError { message: string; @@ -162,22 +162,18 @@ export const bulkActionAnonymizationFieldsRoute = ( request.events.completed$.subscribe(() => abortController.abort()); try { const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); - } + // Perform license and authenticated user checks + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); - const authenticatedUser = ctx.elasticAssistant.getCurrentUser(); - if (authenticatedUser == null) { - return assistantResponse.error({ - body: `Authenticated user not found`, - statusCode: 401, - }); + if (!checkResponse.isSuccess) { + return checkResponse.response; } + const authenticatedUser = checkResponse.currentUser; + const dataClient = await ctx.elasticAssistant.getAIAssistantAnonymizationFieldsDataClient(); @@ -199,7 +195,7 @@ export const bulkActionAnonymizationFieldsRoute = ( } const writer = await dataClient?.getWriter(); - const changedAt = new Date().toISOString(); + const createdAt = new Date().toISOString(); const { errors, docs_created: docsCreated, @@ -207,12 +203,12 @@ export const bulkActionAnonymizationFieldsRoute = ( docs_deleted: docsDeleted, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion } = await writer!.bulk({ - documentsToCreate: body.create?.map((f) => - transformToCreateScheme(authenticatedUser, changedAt, f) + documentsToCreate: body.create?.map((doc) => + transformToCreateScheme(authenticatedUser, createdAt, doc) ), documentsToDelete: body.delete?.ids, - documentsToUpdate: body.update?.map((f) => - transformToUpdateScheme(authenticatedUser, changedAt, f) + documentsToUpdate: body.update?.map((doc) => + transformToUpdateScheme(authenticatedUser, createdAt, doc) ), getUpdateScript: (document: UpdateAnonymizationFieldSchema) => getUpdateScript({ anonymizationField: document, isPatch: true }), diff --git a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.test.ts b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.test.ts index 4659503261a6e..7c2b1d330a3db 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.test.ts @@ -12,6 +12,7 @@ import { requestContextMock } from '../../__mocks__/request_context'; import { getFindAnonymizationFieldsResultWithSingleHit } from '../../__mocks__/response'; import { findAnonymizationFieldsRoute } from './find_route'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import type { AuthenticatedUser } from '@kbn/core-security-common'; describe('Find user anonymization fields route', () => { let server: ReturnType; @@ -21,19 +22,26 @@ describe('Find user anonymization fields route', () => { beforeEach(async () => { server = serverMock.create(); ({ clients, context } = requestContextMock.createTools()); + const mockUser1 = { + username: 'my_username', + authentication_realm: { + type: 'my_realm_type', + name: 'my_realm_name', + }, + } as AuthenticatedUser; clients.elasticAssistant.getAIAssistantAnonymizationFieldsDataClient.findDocuments.mockResolvedValue( Promise.resolve(getFindAnonymizationFieldsResultWithSingleHit()) ); - clients.elasticAssistant.getCurrentUser.mockResolvedValue({ + context.elasticAssistant.getCurrentUser.mockReturnValue({ username: 'my_username', authentication_realm: { type: 'my_realm_type', name: 'my_realm_name', }, - }); + } as AuthenticatedUser); logger = loggingSystemMock.createLogger(); - + context.elasticAssistant.getCurrentUser.mockReturnValue(mockUser1); findAnonymizationFieldsRoute(server.router, logger); }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.ts index 904a80d6a3ea4..061dd9ff3eac6 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.ts @@ -22,7 +22,7 @@ import { ElasticAssistantPluginRouter } from '../../types'; import { buildResponse } from '../utils'; import { EsAnonymizationFieldsSchema } from '../../ai_assistant_data_clients/anonymization_fields/types'; import { transformESSearchToAnonymizationFields } from '../../ai_assistant_data_clients/anonymization_fields/helpers'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; +import { performChecks } from '../helpers'; export const findAnonymizationFieldsRoute = ( router: ElasticAssistantPluginRouter, @@ -55,14 +55,16 @@ export const findAnonymizationFieldsRoute = ( try { const { query } = request; const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); + // Perform license and authenticated user checks + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); + if (!checkResponse.isSuccess) { + return checkResponse.response; } + const dataClient = await ctx.elasticAssistant.getAIAssistantAnonymizationFieldsDataClient(); diff --git a/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.test.ts b/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.test.ts index 0b05bb2875cb6..f03a3394cdaac 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.test.ts @@ -32,7 +32,17 @@ const actionsClient = actionsClientMock.create(); jest.mock('../../lib/build_response', () => ({ buildResponse: jest.fn().mockImplementation((x) => x), })); -jest.mock('../helpers'); + +jest.mock('../helpers', () => { + const original = jest.requireActual('../helpers'); + + return { + ...original, + appendAssistantMessageToConversation: jest.fn(), + createConversationWithUserInput: jest.fn(), + langChainExecute: jest.fn(), + }; +}); const mockAppendAssistantMessageToConversation = appendAssistantMessageToConversation as jest.Mock; const mockLangChainExecute = langChainExecute as jest.Mock; @@ -280,6 +290,7 @@ describe('chatCompleteRoute', () => { actionTypeId: '.gen-ai', model: 'gpt-4', assistantStreamingEnabled: false, + isEnabledKnowledgeBase: false, }); }), }; diff --git a/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts b/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts index 47f6f1a486957..c6eb81dd86ebd 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts @@ -25,6 +25,9 @@ import { buildResponse } from '../../lib/build_response'; import { appendAssistantMessageToConversation, createConversationWithUserInput, + DEFAULT_PLUGIN_NAME, + getIsKnowledgeBaseInstalled, + getPluginNameFromRequest, langChainExecute, performChecks, } from '../helpers'; @@ -63,22 +66,20 @@ export const chatCompleteRoute = ( const assistantResponse = buildResponse(response); let telemetry; let actionTypeId; + const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); + const logger: Logger = ctx.elasticAssistant.logger; try { - const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const logger: Logger = ctx.elasticAssistant.logger; telemetry = ctx.elasticAssistant.telemetry; const inference = ctx.elasticAssistant.inference; // Perform license and authenticated user checks const checkResponse = performChecks({ - authenticatedUser: true, context: ctx, - license: true, request, response, }); - if (checkResponse) { - return checkResponse; + if (!checkResponse.isSuccess) { + return checkResponse.response; } const conversationsDataClient = @@ -221,6 +222,19 @@ export const chatCompleteRoute = ( }); } catch (err) { const error = transformError(err as Error); + const pluginName = getPluginNameFromRequest({ + request, + defaultPluginName: DEFAULT_PLUGIN_NAME, + logger, + }); + const v2KnowledgeBaseEnabled = + ctx.elasticAssistant.getRegisteredFeatures(pluginName).assistantKnowledgeBaseByDefault; + const kbDataClient = + (await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient({ + v2KnowledgeBaseEnabled, + })) ?? undefined; + const isKnowledgeBaseInstalled = await getIsKnowledgeBaseInstalled(kbDataClient); + telemetry?.reportEvent(INVOKE_ASSISTANT_ERROR_EVENT.eventType, { actionTypeId: actionTypeId ?? '', model: request.body.model, @@ -228,6 +242,7 @@ export const chatCompleteRoute = ( // TODO rm actionTypeId check when llmClass for bedrock streaming is implemented // tracked here: https://github.com/elastic/security-team/issues/7363 assistantStreamingEnabled: request.body.isStream ?? false, + isEnabledKnowledgeBase: isKnowledgeBaseInstalled, }); return assistantResponse.error({ body: error.message, diff --git a/x-pack/plugins/elastic_assistant/server/routes/evaluate/get_evaluate.ts b/x-pack/plugins/elastic_assistant/server/routes/evaluate/get_evaluate.ts index 41b455a73598b..dd7462696621b 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/evaluate/get_evaluate.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/evaluate/get_evaluate.ts @@ -48,15 +48,14 @@ export const getEvaluateRoute = (router: IRouter(result); }; @@ -561,55 +560,66 @@ export const updateConversationWithUserInput = async ({ }; interface PerformChecksParams { - authenticatedUser?: boolean; capability?: AssistantFeatureKey; context: AwaitedProperties< Pick >; - license?: boolean; request: KibanaRequest; response: KibanaResponseFactory; } /** - * Helper to perform checks for authenticated user, capability, and license. Perform all or one - * of the checks by providing relevant optional params. Check order is license, authenticated user, - * then capability. + * Helper to perform checks for authenticated user, license, and optionally capability. + * Check order is license, authenticated user, then capability. + * + * Returns either a successful check with an AuthenticatedUser or + * an unsuccessful check with an error IKibanaResponse. * - * @param authenticatedUser - Whether to check for an authenticated user * @param capability - Specific capability to check if enabled, e.g. `assistantModelEvaluation` * @param context - Route context - * @param license - Whether to check for a valid license * @param request - Route KibanaRequest * @param response - Route KibanaResponseFactory + * @returns PerformChecks */ + +type PerformChecks = + | { + isSuccess: true; + currentUser: AuthenticatedUser; + } + | { + isSuccess: false; + response: IKibanaResponse; + }; export const performChecks = ({ - authenticatedUser, capability, context, - license, request, response, -}: PerformChecksParams): IKibanaResponse | undefined => { +}: PerformChecksParams): PerformChecks => { const assistantResponse = buildResponse(response); - if (license) { - if (!hasAIAssistantLicense(context.licensing.license)) { - return response.forbidden({ + if (!hasAIAssistantLicense(context.licensing.license)) { + return { + isSuccess: false, + response: response.forbidden({ body: { message: UPGRADE_LICENSE_MESSAGE, }, - }); - } + }), + }; } - if (authenticatedUser) { - if (context.elasticAssistant.getCurrentUser() == null) { - return assistantResponse.error({ + const currentUser = context.elasticAssistant.getCurrentUser(); + + if (currentUser == null) { + return { + isSuccess: false, + response: assistantResponse.error({ body: `Authenticated user not found`, statusCode: 401, - }); - } + }), + }; } if (capability) { @@ -619,11 +629,17 @@ export const performChecks = ({ }); const registeredFeatures = context.elasticAssistant.getRegisteredFeatures(pluginName); if (!registeredFeatures[capability]) { - return response.notFound(); + return { + isSuccess: false, + response: response.notFound(), + }; } } - return undefined; + return { + isSuccess: true, + currentUser, + }; }; /** @@ -653,23 +669,20 @@ export const isV2KnowledgeBaseEnabled = ({ * Telemetry function to determine whether knowledge base has been installed * @param kbDataClient */ -export const getIsKnowledgeBaseEnabled = async ( +export const getIsKnowledgeBaseInstalled = async ( kbDataClient?: AIAssistantKnowledgeBaseDataClient | null -): Promise<{ - esqlExists: boolean; - isModelDeployed: boolean; -}> => { - let esqlExists = false; +): Promise => { + let securityLabsDocsExist = false; let isModelDeployed = false; if (kbDataClient != null) { try { isModelDeployed = await kbDataClient.isModelDeployed(); if (isModelDeployed) { - esqlExists = + securityLabsDocsExist = ( await kbDataClient.getKnowledgeBaseDocumentEntries({ - query: ESQL_DOCS_LOADED_QUERY, - required: true, + kbResource: SECURITY_LABS_RESOURCE, + query: SECURITY_LABS_LOADED_QUERY, }) ).length > 0; } @@ -678,8 +691,5 @@ export const getIsKnowledgeBaseEnabled = async ( } } - return { - esqlExists, - isModelDeployed, - }; + return isModelDeployed && securityLabsDocsExist; }; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/constants.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/constants.ts index 89970611df0e9..052b2cac57609 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/constants.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/constants.ts @@ -12,3 +12,6 @@ export const KNOWLEDGE_BASE_INGEST_PIPELINE = '.kibana-elastic-ai-assistant-kb-i export const ESQL_DOCS_LOADED_QUERY = 'You can chain processing commands, separated by a pipe character: `|`.'; export const SECURITY_LABS_RESOURCE = 'security_labs'; +export const USER_RESOURCE = 'user'; +// Query for determining if Security Labs docs have been loaded. Intended for use with Telemetry +export const SECURITY_LABS_LOADED_QUERY = 'What is Elastic Security Labs'; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts index cfb2303010756..fbe73525578b0 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts @@ -6,7 +6,7 @@ */ import moment from 'moment'; -import type { AuthenticatedUser, IKibanaResponse, KibanaResponseFactory } from '@kbn/core/server'; +import type { IKibanaResponse, KibanaResponseFactory } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { @@ -143,15 +143,13 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug // Perform license, authenticated user and FF checks const checkResponse = performChecks({ - authenticatedUser: true, capability: 'assistantKnowledgeBaseByDefault', context: ctx, - license: true, request, response, }); - if (checkResponse) { - return checkResponse; + if (!checkResponse.isSuccess) { + return checkResponse.response; } logger.debug( @@ -181,8 +179,7 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug v2KnowledgeBaseEnabled: true, }); const spaceId = ctx.elasticAssistant.getSpaceId(); - // Authenticated user null check completed in `performChecks()` above - const authenticatedUser = ctx.elasticAssistant.getCurrentUser() as AuthenticatedUser; + const authenticatedUser = checkResponse.currentUser; const userFilter = getKBUserFilter(authenticatedUser); const manageGlobalKnowledgeBaseAIAssistant = kbDataClient?.options.manageGlobalKnowledgeBaseAIAssistant; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts index 96753bdd690bd..0bfe9de269f7c 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts @@ -47,15 +47,13 @@ export const createKnowledgeBaseEntryRoute = (router: ElasticAssistantPluginRout // Perform license, authenticated user and FF checks const checkResponse = performChecks({ - authenticatedUser: true, capability: 'assistantKnowledgeBaseByDefault', context: ctx, - license: true, request, response, }); - if (checkResponse) { - return checkResponse; + if (!checkResponse.isSuccess) { + return checkResponse.response; } // Check mappings and upgrade if necessary -- this route only supports v2 KB, so always `true` diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts index 356d5d9150a67..13334d0d829b1 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts @@ -58,21 +58,19 @@ export const findKnowledgeBaseEntriesRoute = (router: ElasticAssistantPluginRout // Perform license, authenticated user and FF checks const checkResponse = performChecks({ - authenticatedUser: true, capability: 'assistantKnowledgeBaseByDefault', context: ctx, - license: true, request, response, }); - if (checkResponse) { - return checkResponse; + if (!checkResponse.isSuccess) { + return checkResponse.response; } const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient({ v2KnowledgeBaseEnabled: true, }); - const currentUser = ctx.elasticAssistant.getCurrentUser(); + const currentUser = checkResponse.currentUser; const userFilter = getKBUserFilter(currentUser); const systemFilter = ` AND (kb_resource:"user" OR type:"index")`; const additionalFilter = query.filter ? ` AND ${query.filter}` : ''; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts index 6244599a2af27..b30e5ac3653ad 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts @@ -38,6 +38,7 @@ describe('Get Knowledge Base Status Route', () => { isModelDeployed: jest.fn().mockResolvedValue(true), isSetupInProgress: false, isSecurityLabsDocsLoaded: jest.fn().mockResolvedValue(true), + isUserDataExists: jest.fn().mockResolvedValue(true), }); getKnowledgeBaseStatusRoute(server.router); @@ -58,6 +59,7 @@ describe('Get Knowledge Base Status Route', () => { is_setup_available: true, pipeline_exists: true, security_labs_exists: true, + user_data_exists: true, }); }); }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts index 833e674b68ffd..f278cd469ac0e 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts @@ -74,11 +74,18 @@ export const getKnowledgeBaseStatusRoute = (router: ElasticAssistantPluginRouter }; if (indexExists && isModelDeployed) { - const securityLabsExists = await kbDataClient.isSecurityLabsDocsLoaded(); + const securityLabsExists = v2KnowledgeBaseEnabled + ? await kbDataClient.isSecurityLabsDocsLoaded() + : true; + const userDataExists = v2KnowledgeBaseEnabled + ? await kbDataClient.isUserDataExists() + : true; + return response.ok({ body: { ...body, - security_labs_exists: v2KnowledgeBaseEnabled ? securityLabsExists : true, + security_labs_exists: securityLabsExists, + user_data_exists: userDataExists, }, }); } diff --git a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts index d19127be0d7e8..a7abac27dac6f 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts @@ -46,7 +46,18 @@ jest.mock('../lib/executor', () => ({ const mockStream = jest.fn().mockImplementation(() => new PassThrough()); const mockLangChainExecute = langChainExecute as jest.Mock; const mockAppendAssistantMessageToConversation = appendAssistantMessageToConversation as jest.Mock; -jest.mock('./helpers'); +jest.mock('./helpers', () => { + const original = jest.requireActual('./helpers'); + + return { + ...original, + getIsKnowledgeBaseInstalled: jest.fn(), + appendAssistantMessageToConversation: jest.fn(), + langChainExecute: jest.fn(), + getPluginNameFromRequest: jest.fn(), + getSystemPromptFromUserConversation: jest.fn(), + }; +}); const existingConversation = getConversationResponseMock(); const reportEvent = jest.fn(); const appendConversationMessages = jest.fn(); diff --git a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts index 4b65b5bb3f1e5..bb217f7f5aa3a 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts @@ -24,10 +24,11 @@ import { ElasticAssistantRequestHandlerContext, GetElser } from '../types'; import { appendAssistantMessageToConversation, DEFAULT_PLUGIN_NAME, - getIsKnowledgeBaseEnabled, + getIsKnowledgeBaseInstalled, getPluginNameFromRequest, getSystemPromptFromUserConversation, langChainExecute, + performChecks, } from './helpers'; import { isOpenSourceModel } from './utils'; @@ -66,12 +67,16 @@ export const postActionsConnectorExecuteRoute = ( let onLlmResponse; try { - const authenticatedUser = assistantContext.getCurrentUser(); - if (authenticatedUser == null) { - return response.unauthorized({ - body: `Authenticated user not found`, - }); + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); + + if (!checkResponse.isSuccess) { + return checkResponse.response; } + let latestReplacements: Replacements = request.body.replacements; const onNewReplacements = (newReplacements: Replacements) => { latestReplacements = { ...latestReplacements, ...newReplacements }; @@ -165,14 +170,13 @@ export const postActionsConnectorExecuteRoute = ( (await assistantContext.getAIAssistantKnowledgeBaseDataClient({ v2KnowledgeBaseEnabled, })) ?? undefined; - const isEnabledKnowledgeBase = await getIsKnowledgeBaseEnabled(kbDataClient); - + const isKnowledgeBaseInstalled = await getIsKnowledgeBaseInstalled(kbDataClient); telemetry.reportEvent(INVOKE_ASSISTANT_ERROR_EVENT.eventType, { actionTypeId: request.body.actionTypeId, model: request.body.model, errorMessage: error.message, assistantStreamingEnabled: request.body.subAction !== 'invokeAI', - isEnabledKnowledgeBase, + isEnabledKnowledgeBase: isKnowledgeBaseInstalled, }); return resp.error({ diff --git a/x-pack/plugins/elastic_assistant/server/routes/prompts/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/prompts/bulk_actions_route.ts index 44a949cd22eeb..d3ee47854e7a0 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/prompts/bulk_actions_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/prompts/bulk_actions_route.ts @@ -35,7 +35,7 @@ import { transformESSearchToPrompts, } from '../../ai_assistant_data_clients/prompts/helpers'; import { EsPromptsSchema, UpdatePromptSchema } from '../../ai_assistant_data_clients/prompts/types'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; +import { performChecks } from '../helpers'; export interface BulkOperationError { message: string; @@ -156,22 +156,17 @@ export const bulkPromptsRoute = (router: ElasticAssistantPluginRouter, logger: L request.events.completed$.subscribe(() => abortController.abort()); try { const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); + // Perform license and authenticated user checks + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); + if (!checkResponse.isSuccess) { + return checkResponse.response; } + const authenticatedUser = checkResponse.currentUser; - const authenticatedUser = ctx.elasticAssistant.getCurrentUser(); - if (authenticatedUser == null) { - return assistantResponse.error({ - body: `Authenticated user not found`, - statusCode: 401, - }); - } const dataClient = await ctx.elasticAssistant.getAIAssistantPromptsDataClient(); if (body.create && body.create.length > 0) { @@ -211,7 +206,7 @@ export const bulkPromptsRoute = (router: ElasticAssistantPluginRouter, logger: L ), getUpdateScript: (document: UpdatePromptSchema) => getUpdateScript({ prompt: document, isPatch: true }), - authenticatedUser, + authenticatedUser: authenticatedUser ?? undefined, }); const created = docsCreated.length > 0 diff --git a/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.test.ts b/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.test.ts index 68ce67d842a0f..151c1622d0219 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.test.ts @@ -12,6 +12,7 @@ import { requestContextMock } from '../../__mocks__/request_context'; import { getFindPromptsResultWithSingleHit } from '../../__mocks__/response'; import { findPromptsRoute } from './find_route'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import type { AuthenticatedUser } from '@kbn/core-security-common'; describe('Find user prompts route', () => { let server: ReturnType; @@ -21,19 +22,26 @@ describe('Find user prompts route', () => { beforeEach(async () => { server = serverMock.create(); ({ clients, context } = requestContextMock.createTools()); + const mockUser1 = { + username: 'my_username', + authentication_realm: { + type: 'my_realm_type', + name: 'my_realm_name', + }, + } as AuthenticatedUser; clients.elasticAssistant.getAIAssistantPromptsDataClient.findDocuments.mockResolvedValue( Promise.resolve(getFindPromptsResultWithSingleHit()) ); - clients.elasticAssistant.getCurrentUser.mockResolvedValue({ + context.elasticAssistant.getCurrentUser.mockReturnValue({ username: 'my_username', authentication_realm: { type: 'my_realm_type', name: 'my_realm_name', }, - }); + } as AuthenticatedUser); logger = loggingSystemMock.createLogger(); - + context.elasticAssistant.getCurrentUser.mockReturnValue(mockUser1); findPromptsRoute(server.router, logger); }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.ts index 848680be662a3..a2980b173d76a 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.ts @@ -18,7 +18,7 @@ import { ElasticAssistantPluginRouter } from '../../types'; import { buildResponse } from '../utils'; import { EsPromptsSchema } from '../../ai_assistant_data_clients/prompts/types'; import { transformESSearchToPrompts } from '../../ai_assistant_data_clients/prompts/helpers'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; +import { performChecks } from '../helpers'; export const findPromptsRoute = (router: ElasticAssistantPluginRouter, logger: Logger) => { router.versioned @@ -44,13 +44,14 @@ export const findPromptsRoute = (router: ElasticAssistantPluginRouter, logger: L try { const { query } = request; const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); + // Perform license and authenticated user checks + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); + if (!checkResponse.isSuccess) { + return checkResponse.response; } const dataClient = await ctx.elasticAssistant.getAIAssistantPromptsDataClient(); diff --git a/x-pack/plugins/elastic_assistant/server/routes/request_context_factory.ts b/x-pack/plugins/elastic_assistant/server/routes/request_context_factory.ts index eeb1a5564d1cf..7d97029e7252a 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/request_context_factory.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/request_context_factory.ts @@ -101,6 +101,7 @@ export class RequestContextFactory implements IRequestContextFactory { return this.assistantService.createAIAssistantKnowledgeBaseDataClient({ spaceId: getSpaceId(), logger: this.logger, + licensing: context.licensing, currentUser, modelIdOverride, v2KnowledgeBaseEnabled, @@ -114,6 +115,7 @@ export class RequestContextFactory implements IRequestContextFactory { const currentUser = getCurrentUser(); return this.assistantService.createAttackDiscoveryDataClient({ spaceId: getSpaceId(), + licensing: context.licensing, logger: this.logger, currentUser, }); @@ -123,6 +125,7 @@ export class RequestContextFactory implements IRequestContextFactory { const currentUser = getCurrentUser(); return this.assistantService.createAIAssistantPromptsDataClient({ spaceId: getSpaceId(), + licensing: context.licensing, logger: this.logger, currentUser, }); @@ -132,6 +135,7 @@ export class RequestContextFactory implements IRequestContextFactory { const currentUser = getCurrentUser(); return this.assistantService.createAIAssistantAnonymizationFieldsDataClient({ spaceId: getSpaceId(), + licensing: context.licensing, logger: this.logger, currentUser, }); @@ -141,6 +145,7 @@ export class RequestContextFactory implements IRequestContextFactory { const currentUser = getCurrentUser(); return this.assistantService.createAIAssistantConversationsDataClient({ spaceId: getSpaceId(), + licensing: context.licensing, logger: this.logger, currentUser, }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/append_conversation_messages_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/append_conversation_messages_route.ts index 796c0d617fe5d..06bfa023136d9 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/append_conversation_messages_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/append_conversation_messages_route.ts @@ -17,7 +17,7 @@ import { import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; import { buildResponse } from '../utils'; import { ElasticAssistantPluginRouter } from '../../types'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; +import { performChecks } from '../helpers'; export const appendConversationMessageRoute = (router: ElasticAssistantPluginRouter) => { router.versioned @@ -43,22 +43,16 @@ export const appendConversationMessageRoute = (router: ElasticAssistantPluginRou const { id } = request.params; try { const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); + if (!checkResponse.isSuccess) { + return checkResponse.response; } const dataClient = await ctx.elasticAssistant.getAIAssistantConversationsDataClient(); - const authenticatedUser = ctx.elasticAssistant.getCurrentUser(); - if (authenticatedUser == null) { - return assistantResponse.error({ - body: `Authenticated user not found`, - statusCode: 401, - }); - } + const authenticatedUser = checkResponse.currentUser; const existingConversation = await dataClient?.getConversation({ id, authenticatedUser }); if (existingConversation == null) { diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/bulk_actions_route.ts index 6e30acb1a47c7..9c353997f1d46 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/bulk_actions_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/bulk_actions_route.ts @@ -35,7 +35,7 @@ import { transformToUpdateScheme, } from '../../ai_assistant_data_clients/conversations/update_conversation'; import { EsConversationSchema } from '../../ai_assistant_data_clients/conversations/types'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; +import { performChecks } from '../helpers'; export interface BulkOperationError { message: string; @@ -156,23 +156,17 @@ export const bulkActionConversationsRoute = ( request.events.completed$.subscribe(() => abortController.abort()); try { const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); + if (!checkResponse.isSuccess) { + return checkResponse.response; } + const authenticatedUser = checkResponse.currentUser; const dataClient = await ctx.elasticAssistant.getAIAssistantConversationsDataClient(); const spaceId = ctx.elasticAssistant.getSpaceId(); - const authenticatedUser = ctx.elasticAssistant.getCurrentUser(); - if (authenticatedUser == null) { - return assistantResponse.error({ - body: `Authenticated user not found`, - statusCode: 401, - }); - } if (body.create && body.create.length > 0) { const userFilter = authenticatedUser?.username diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/create_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/create_route.ts index b92ad5462963e..9955494b5f294 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/create_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/create_route.ts @@ -44,14 +44,12 @@ export const createConversationRoute = (router: ElasticAssistantPluginRouter): v const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); // Perform license and authenticated user checks const checkResponse = performChecks({ - authenticatedUser: true, context: ctx, - license: true, request, response, }); - if (checkResponse) { - return checkResponse; + if (!checkResponse.isSuccess) { + return checkResponse.response; } const dataClient = await ctx.elasticAssistant.getAIAssistantConversationsDataClient(); diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/delete_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/delete_route.ts index 5d761c09f682c..9c974fdb78de8 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/delete_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/delete_route.ts @@ -14,7 +14,7 @@ import { import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; import { ElasticAssistantPluginRouter } from '../../types'; import { buildResponse } from '../utils'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; +import { performChecks } from '../helpers'; export const deleteConversationRoute = (router: ElasticAssistantPluginRouter) => { router.versioned @@ -40,23 +40,18 @@ export const deleteConversationRoute = (router: ElasticAssistantPluginRouter) => const { id } = request.params; const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); + if (!checkResponse.isSuccess) { + return checkResponse.response; } const dataClient = await ctx.elasticAssistant.getAIAssistantConversationsDataClient(); - const authenticatedUser = ctx.elasticAssistant.getCurrentUser(); - if (authenticatedUser == null) { - return assistantResponse.error({ - body: `Authenticated user not found`, - statusCode: 401, - }); - } + const authenticatedUser = checkResponse.currentUser; + const existingConversation = await dataClient?.getConversation({ id, authenticatedUser }); if (existingConversation == null) { return assistantResponse.error({ diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.test.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.test.ts index 63141fe5475a6..2b20ab03371f6 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { type AuthenticatedUser } from '@kbn/core/server'; import { getCurrentUserFindRequest, requestMock } from '../../__mocks__/request'; import { ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_FIND } from '@kbn/elastic-assistant-common'; import { serverMock } from '../../__mocks__/server'; @@ -15,7 +15,6 @@ import { findUserConversationsRoute } from './find_route'; describe('Find user conversations route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); - beforeEach(async () => { server = serverMock.create(); ({ clients, context } = requestContextMock.createTools()); @@ -23,13 +22,13 @@ describe('Find user conversations route', () => { clients.elasticAssistant.getAIAssistantConversationsDataClient.findDocuments.mockResolvedValue( Promise.resolve(getFindConversationsResultWithSingleHit()) ); - clients.elasticAssistant.getCurrentUser.mockResolvedValue({ + context.elasticAssistant.getCurrentUser.mockReturnValue({ username: 'my_username', authentication_realm: { type: 'my_realm_type', name: 'my_realm_name', }, - }); + } as AuthenticatedUser); findUserConversationsRoute(server.router); }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.ts index e7ce80039beb0..07ba23710b12c 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.ts @@ -21,7 +21,7 @@ import { ElasticAssistantPluginRouter } from '../../types'; import { buildResponse } from '../utils'; import { EsConversationSchema } from '../../ai_assistant_data_clients/conversations/types'; import { transformESSearchToConversations } from '../../ai_assistant_data_clients/conversations/transforms'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; +import { performChecks } from '../helpers'; export const findUserConversationsRoute = (router: ElasticAssistantPluginRouter) => { router.versioned @@ -46,16 +46,17 @@ export const findUserConversationsRoute = (router: ElasticAssistantPluginRouter) try { const { query } = request; const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); + // Perform license and authenticated user checks + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); + if (!checkResponse.isSuccess) { + return checkResponse.response; } const dataClient = await ctx.elasticAssistant.getAIAssistantConversationsDataClient(); - const currentUser = ctx.elasticAssistant.getCurrentUser(); + const currentUser = checkResponse.currentUser; const additionalFilter = query.filter ? ` AND ${query.filter}` : ''; const userFilter = currentUser?.username diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/read_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/read_route.ts index dd540897b0ece..ab69dc20999a2 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/read_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/read_route.ts @@ -16,7 +16,7 @@ import { ReadConversationRequestParams } from '@kbn/elastic-assistant-common/imp import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; import { buildResponse } from '../utils'; import { ElasticAssistantPluginRouter } from '../../types'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; +import { performChecks } from '../helpers'; export const readConversationRoute = (router: ElasticAssistantPluginRouter) => { router.versioned @@ -43,21 +43,15 @@ export const readConversationRoute = (router: ElasticAssistantPluginRouter) => { try { const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); - } - const authenticatedUser = ctx.elasticAssistant.getCurrentUser(); - if (authenticatedUser == null) { - return assistantResponse.error({ - body: `Authenticated user not found`, - statusCode: 401, - }); + const checkResponse = performChecks({ + context: ctx, + request, + response, + }); + if (!checkResponse.isSuccess) { + return checkResponse.response; } + const authenticatedUser = checkResponse.currentUser; const dataClient = await ctx.elasticAssistant.getAIAssistantConversationsDataClient(); const conversation = await dataClient?.getConversation({ id, authenticatedUser }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/update_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/update_route.ts index 4ad819ef0caa0..41956b9bc80f7 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/update_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/update_route.ts @@ -45,18 +45,16 @@ export const updateConversationRoute = (router: ElasticAssistantPluginRouter) => const { id } = request.params; try { const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const authenticatedUser = ctx.elasticAssistant.getCurrentUser(); // Perform license and authenticated user checks const checkResponse = performChecks({ - authenticatedUser: true, context: ctx, - license: true, request, response, }); - if (checkResponse) { - return checkResponse; + if (!checkResponse.isSuccess) { + return checkResponse.response; } + const authenticatedUser = checkResponse.currentUser; const dataClient = await ctx.elasticAssistant.getAIAssistantConversationsDataClient(); diff --git a/x-pack/plugins/elastic_assistant/tsconfig.json b/x-pack/plugins/elastic_assistant/tsconfig.json index 747a58ed930d3..d3436f28a1d3e 100644 --- a/x-pack/plugins/elastic_assistant/tsconfig.json +++ b/x-pack/plugins/elastic_assistant/tsconfig.json @@ -48,7 +48,8 @@ "@kbn/apm-utils", "@kbn/std", "@kbn/zod", - "@kbn/inference-plugin" + "@kbn/inference-plugin", + "@kbn/data-views-plugin" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/enterprise_search/common/constants.ts b/x-pack/plugins/enterprise_search/common/constants.ts index 4da0244b2ec5e..797f94fa29e51 100644 --- a/x-pack/plugins/enterprise_search/common/constants.ts +++ b/x-pack/plugins/enterprise_search/common/constants.ts @@ -15,6 +15,10 @@ import { ENTERPRISE_SEARCH_ANALYTICS_APP_ID, ENTERPRISE_SEARCH_APPSEARCH_APP_ID, ENTERPRISE_SEARCH_WORKPLACESEARCH_APP_ID, + SEARCH_ELASTICSEARCH, + SEARCH_VECTOR_SEARCH, + SEARCH_SEMANTIC_SEARCH, + SEARCH_AI_SEARCH, } from '@kbn/deeplinks-search'; import { i18n } from '@kbn/i18n'; @@ -58,7 +62,7 @@ export const ENTERPRISE_SEARCH_CONTENT_PLUGIN = { }; export const AI_SEARCH_PLUGIN = { - ID: 'enterpriseSearchAISearch', + ID: SEARCH_AI_SEARCH, NAME: i18n.translate('xpack.enterpriseSearch.aiSearch.productName', { defaultMessage: 'AI Search', }), @@ -91,7 +95,7 @@ export const ANALYTICS_PLUGIN = { }; export const ELASTICSEARCH_PLUGIN = { - ID: 'enterpriseSearchElasticsearch', + ID: SEARCH_ELASTICSEARCH, NAME: i18n.translate('xpack.enterpriseSearch.elasticsearch.productName', { defaultMessage: 'Elasticsearch', }), @@ -167,7 +171,7 @@ export const VECTOR_SEARCH_PLUGIN = { defaultMessage: 'Elasticsearch can be used as a vector database, which enables vector search and semantic search use cases.', }), - ID: 'enterpriseSearchVectorSearch', + ID: SEARCH_VECTOR_SEARCH, LOGO: 'logoEnterpriseSearch', NAME: i18n.translate('xpack.enterpriseSearch.vectorSearch.productName', { defaultMessage: 'Vector Search', @@ -184,7 +188,7 @@ export const SEMANTIC_SEARCH_PLUGIN = { defaultMessage: 'Easily add semantic search to Elasticsearch with inference endpoints and the semantic_text field type, to boost search relevance.', }), - ID: 'enterpriseSearchSemanticSearch', + ID: SEARCH_SEMANTIC_SEARCH, LOGO: 'logoEnterpriseSearch', NAME: i18n.translate('xpack.enterpriseSearch.SemanticSearch.productName', { defaultMessage: 'Semantic Search', @@ -218,50 +222,6 @@ export const CREATE_CONNECTOR_PLUGIN = { --index-language en --from-file config.yml `, - CONSOLE_SNIPPET: dedent`# Create an index -PUT /my-index-000001 -{ - "settings": { - "index": { - "number_of_shards": 3, - "number_of_replicas": 2 - } - } -} - -# Create an API key -POST /_security/api_key -{ - "name": "my-api-key", - "expiration": "1d", - "role_descriptors": - { - "role-a": { - "cluster": ["all"], - "indices": [ - { - "names": ["index-a*"], - "privileges": ["read"] - } - ] - }, - "role-b": { - "cluster": ["all"], - "indices": [ - { - "names": ["index-b*"], - "privileges": ["all"] - }] - } - }, "metadata": - { "application": "my-application", - "environment": { - "level": 1, - "trusted": true, - "tags": ["dev", "staging"] - } - } - }`, }; export const LICENSED_SUPPORT_URL = 'https://support.elastic.co'; @@ -341,3 +301,14 @@ export const CRAWLER = { // TODO remove this once the connector service types are no longer in "example" state export const EXAMPLE_CONNECTOR_SERVICE_TYPES = ['opentext_documentum']; + +export const GETTING_STARTED_TITLE = i18n.translate('xpack.enterpriseSearch.gettingStarted.title', { + defaultMessage: 'Getting started', +}); + +export const SEARCH_APPS_BREADCRUMB = i18n.translate( + 'xpack.enterpriseSearch.searchApplications.breadcrumb', + { + defaultMessage: 'Search Applications', + } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts index cca5523ded681..9b37c661d923a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts @@ -41,6 +41,7 @@ export const mockKibanaValues = { data: dataPluginMock.createStartContract(), esConfig: { elasticsearch_host: 'https://your_deployment_url' }, getChromeStyle$: jest.fn().mockReturnValue(of('classic')), + getNavLinks: jest.fn().mockReturnValue([]), guidedOnboarding: {}, history: mockHistory, indexMappingComponent: null, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.tsx index c78bf3e918737..bf8cf009759d0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.tsx @@ -11,7 +11,7 @@ import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { API_DOCS_URL } from '../../../routes'; +import { docLinks } from '../../../../shared/doc_links'; export const EmptyState: React.FC = () => ( (

} actions={ - + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.empty.buttonLabel', { defaultMessage: 'View the API reference', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawl_rules_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawl_rules_table.tsx index bef8ed4462fdc..2f66dc455442e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawl_rules_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawl_rules_table.tsx @@ -23,11 +23,11 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { docLinks } from '../../../../shared/doc_links'; import { clearFlashMessages, flashSuccessToast } from '../../../../shared/flash_messages'; import { GenericEndpointInlineEditableTable } from '../../../../shared/tables/generic_endpoint_inline_editable_table'; import { InlineEditableTableColumn } from '../../../../shared/tables/inline_editable_table/types'; import { ItemWithAnID } from '../../../../shared/tables/types'; -import { CRAWL_RULES_DOCS_URL } from '../../../routes'; import { CrawlerSingleDomainLogic } from '../crawler_single_domain_logic'; import { CrawlerPolicies, @@ -53,7 +53,7 @@ const DEFAULT_DESCRIPTION = ( defaultMessage="Create a crawl rule to include or exclude pages whose URL matches the rule. Rules run in sequential order, and each URL is evaluated according to the first match. {link}" values={{ link: ( - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.crawler.crawlRulesTable.descriptionLinkText', { defaultMessage: 'Learn more about crawl rules' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/deduplication_panel/deduplication_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/deduplication_panel/deduplication_panel.tsx index 26794d0421353..ef4d7448a5785 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/deduplication_panel/deduplication_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/deduplication_panel/deduplication_panel.tsx @@ -27,7 +27,7 @@ import { EuiSelectableLIOption } from '@elastic/eui/src/components/selectable/se import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { DUPLICATE_DOCS_URL } from '../../../../routes'; +import { docLinks } from '../../../../../shared/doc_links'; import { DataPanel } from '../../../data_panel'; import { CrawlerSingleDomainLogic } from '../../crawler_single_domain_logic'; @@ -84,7 +84,7 @@ export const DeduplicationPanel: React.FC = () => { documents on this domain. {documentationLink}." values={{ documentationLink: ( - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.crawler.deduplicationPanel.learnMoreMessage', { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/entry_points_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/entry_points_table.tsx index 4fc7a0569ba0e..d4bfdf77704b8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/entry_points_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/entry_points_table.tsx @@ -14,10 +14,10 @@ import { EuiFieldText, EuiLink, EuiSpacer, EuiText, EuiTitle } from '@elastic/eu import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { docLinks } from '../../../../shared/doc_links'; import { GenericEndpointInlineEditableTable } from '../../../../shared/tables/generic_endpoint_inline_editable_table'; import { InlineEditableTableColumn } from '../../../../shared/tables/inline_editable_table/types'; import { ItemWithAnID } from '../../../../shared/tables/types'; -import { ENTRY_POINTS_DOCS_URL } from '../../../routes'; import { CrawlerDomain, EntryPoint } from '../types'; import { EntryPointsTableLogic } from './entry_points_table_logic'; @@ -80,7 +80,7 @@ export const EntryPointsTable: React.FC = ({ defaultMessage: 'Include the most important URLs for your website here. Entry point URLs will be the first pages to be indexed and processed for links to other pages.', })}{' '} - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.crawler.entryPointsTable.learnMoreLinkText', { defaultMessage: 'Learn more about entry points.' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/manage_crawls_popover/automatic_crawl_scheduler.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/manage_crawls_popover/automatic_crawl_scheduler.tsx index 4533ca04c75bc..cb0377a471b93 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/manage_crawls_popover/automatic_crawl_scheduler.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/manage_crawls_popover/automatic_crawl_scheduler.tsx @@ -36,8 +36,8 @@ import { MONTHS_UNIT_LABEL, WEEKS_UNIT_LABEL, } from '../../../../../shared/constants/units'; +import { docLinks } from '../../../../../shared/doc_links'; -import { WEB_CRAWLER_DOCS_URL } from '../../../../routes'; import { CrawlUnits } from '../../types'; import { AutomaticCrawlSchedulerLogic } from './automatic_crawl_scheduler_logic'; @@ -81,7 +81,7 @@ export const AutomaticCrawlScheduler: React.FC = () => { defaultMessage="Don't worry about it, we'll start a crawl for you. {readMoreMessage}." values={{ readMoreMessage: ( - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.crawler.automaticCrawlSchedule.readMoreLink', { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_overview.tsx index 13a13c25a5ad8..d18f40c4c9f23 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_overview.tsx @@ -13,7 +13,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiSpacer, EuiText, EuiTitle } from import { i18n } from '@kbn/i18n'; -import { WEB_CRAWLER_DOCS_URL, WEB_CRAWLER_LOG_DOCS_URL } from '../../routes'; +import { docLinks } from '../../../shared/doc_links'; import { getEngineBreadcrumbs } from '../engine'; import { AppSearchPageTemplate } from '../layout'; @@ -82,7 +82,7 @@ export const CrawlerOverview: React.FC = () => { defaultMessage: "Easily index your website's content. To get started, enter your domain name, provide optional entry points and crawl rules, and we will handle the rest.", })}{' '} - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.crawler.empty.crawlerDocumentationLinkDescription', { @@ -125,7 +125,7 @@ export const CrawlerOverview: React.FC = () => { defaultMessage: "Recent crawl requests are logged here. Using the request ID of each crawl, you can track progress and examine crawl events in Kibana's Discover or Logs user interfaces.", })}{' '} - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.crawler.configurationDocumentationLinkDescription', { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts index 9676e7f859ac5..7468597294026 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts @@ -7,8 +7,6 @@ import { i18n } from '@kbn/i18n'; -import { AUTHENTICATION_DOCS_URL } from '../../routes'; - export const CREDENTIALS_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.credentials.title', { defaultMessage: 'Credentials' } @@ -108,5 +106,3 @@ export const TOKEN_TYPE_INFO = [ ]; export const FLYOUT_ARIA_LABEL_ID = 'credentialsFlyoutTitle'; - -export const DOCS_HREF = AUTHENTICATION_DOCS_URL; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.tsx index 2cf381d8f604f..5213f786dfead 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.tsx @@ -12,8 +12,10 @@ import { useValues, useActions } from 'kea'; import { EuiFormRow, EuiSelect, EuiText, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { docLinks } from '../../../../../shared/doc_links'; + import { AppLogic } from '../../../../app_logic'; -import { TOKEN_TYPE_DESCRIPTION, TOKEN_TYPE_INFO, DOCS_HREF } from '../../constants'; +import { TOKEN_TYPE_DESCRIPTION, TOKEN_TYPE_INFO } from '../../constants'; import { CredentialsLogic } from '../../credentials_logic'; export const FormKeyType: React.FC = () => { @@ -36,7 +38,7 @@ export const FormKeyType: React.FC = () => {

{tokenDescription}{' '} - + {i18n.translate('xpack.enterpriseSearch.appSearch.credentials.documentationLink1', { defaultMessage: 'Visit the documentation', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx index e351cdf36c657..4f45da9e26046 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx @@ -19,9 +19,9 @@ import { import { i18n } from '@kbn/i18n'; import { EDIT_BUTTON_LABEL, DELETE_BUTTON_LABEL } from '../../../../shared/constants'; +import { docLinks } from '../../../../shared/doc_links'; import { HiddenText } from '../../../../shared/hidden_text'; import { convertMetaToPagination, handlePageChange } from '../../../../shared/table_pagination'; -import { API_KEYS_DOCS_URL } from '../../../routes'; import { TOKEN_TYPE_DISPLAY_NAMES } from '../constants'; import { CredentialsLogic } from '../credentials_logic'; import { ApiToken } from '../types'; @@ -141,7 +141,7 @@ export const CredentialsList: React.FC = () => { defaultMessage: 'Allow applications to access Elastic App Search on your behalf.', })} actions={ - + {i18n.translate('xpack.enterpriseSearch.appSearch.credentials.empty.buttonLabel', { defaultMessage: 'Learn about API keys', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/empty_state.tsx index 10d81f1623959..363da83d56aac 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/empty_state.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { CURATIONS_DOCS_URL } from '../../../routes'; +import { docLinks } from '../../../../shared/doc_links'; export const EmptyState: React.FC = () => ( (

} actions={ - + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.curations.empty.buttonLabel', { defaultMessage: 'Read the curations guide', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.tsx index 7bbe276aedf69..98da6dc88ef57 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.tsx @@ -30,8 +30,8 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { DocumentCreationLogic } from '..'; import { CANCEL_BUTTON_LABEL } from '../../../../shared/constants'; +import { docLinks } from '../../../../shared/doc_links'; import { getEnterpriseSearchUrl } from '../../../../shared/enterprise_search_url'; -import { API_CLIENTS_DOCS_URL, INDEXING_DOCS_URL } from '../../../routes'; import { EngineLogic } from '../../engine'; import { EngineDetails } from '../../engine/types'; @@ -74,12 +74,12 @@ export const FlyoutBody: React.FC = () => { defaultMessage="The {documentsApiLink} can be used to add new documents to your engine, update documents, retrieve documents by id, and delete documents. There are a variety of {clientLibrariesLink} to help you get started." values={{ documentsApiLink: ( - + documents API ), clientLibrariesLink: ( - + client libraries ), diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.tsx index 07de7b3ec0c34..80e087e007671 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.tsx @@ -26,9 +26,10 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { docLinks } from '../../../shared/doc_links'; import { parseQueryParams } from '../../../shared/query_params'; import { EuiCardTo } from '../../../shared/react_router_helpers'; -import { INDEXING_DOCS_URL, ENGINE_CRAWLER_PATH } from '../../routes'; +import { ENGINE_CRAWLER_PATH } from '../../routes'; import { generateEnginePath } from '../engine'; import illustration from './illustration.svg'; @@ -106,7 +107,7 @@ export const DocumentCreationButtons: React.FC = ({ )} {' '} - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.documentCreation.buttons.emptyStateFooterLink', { defaultMessage: 'Read documentation' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/components/empty_state.tsx index 85e834b320751..a311899d380e9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/components/empty_state.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { INDEXING_DOCS_URL } from '../../../routes'; +import { docLinks } from '../../../../shared/doc_links'; export const EmptyState = () => ( (

} actions={ - + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.documents.empty.buttonLabel', { defaultMessage: 'Read the documents guide', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx index e31a17406ffd3..e4bcf810d58f8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx @@ -12,8 +12,8 @@ import { useValues } from 'kea'; import { EuiButton, EuiEmptyPrompt, EuiImage, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { docLinks } from '../../../shared/doc_links'; import { EuiButtonTo } from '../../../shared/react_router_helpers'; -import { DOCS_URL } from '../../routes'; import { DocumentCreationButtons, DocumentCreationFlyout } from '../document_creation'; import illustration from '../document_creation/illustration.svg'; @@ -85,7 +85,7 @@ export const EmptyEngineOverview: React.FC = () => { { defaultMessage: 'Engine setup' } ), rightSideItems: [ - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.overview.empty.headingAction', { defaultMessage: 'View documentation' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_meta_engines_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_meta_engines_state.tsx index 3cf461e3f7d45..0824997ba8896 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_meta_engines_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_meta_engines_state.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiEmptyPrompt, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { META_ENGINES_DOCS_URL } from '../../../routes'; +import { docLinks } from '../../../../shared/doc_links'; export const EmptyMetaEnginesState: React.FC = () => ( (

} actions={ - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engines.metaEngines.emptyPromptButtonLabel', { defaultMessage: 'Learn more about meta engines' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/constants.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/constants.tsx index e30868beeb209..8b32ffe77e701 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/constants.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/constants.tsx @@ -11,7 +11,7 @@ import { EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { META_ENGINES_DOCS_URL } from '../../routes'; +import { docLinks } from '../../../shared/doc_links'; export const DEFAULT_LANGUAGE = 'Universal'; @@ -57,7 +57,7 @@ export const META_ENGINE_CREATION_FORM_DOCUMENTATION_DESCRIPTION = ( defaultMessage="{documentationLink} for information about how to get started." values={{ documentationLink: ( - + {META_ENGINE_CREATION_FORM_DOCUMENTATION_LINK} ), diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/components/empty_state.tsx index f17f7a582efdf..b792dec2cba0e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/components/empty_state.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { RELEVANCE_DOCS_URL } from '../../../routes'; +import { docLinks } from '../../../../shared/doc_links'; export const EmptyState: React.FC = () => ( ( } )} actions={ - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.relevanceTuning.empty.buttonLabel', { defaultMessage: 'Read the relevance tuning guide' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/components/precision_slider/precision_slider.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/components/precision_slider/precision_slider.tsx index e4b2027aa3d6d..d78949d0fbe74 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/components/precision_slider/precision_slider.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/components/precision_slider/precision_slider.tsx @@ -21,7 +21,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { PRECISION_DOCS_URL } from '../../../../routes'; +import { docLinks } from '../../../../../shared/doc_links'; import { RelevanceTuningLogic } from '../../relevance_tuning_logic'; import { STEP_DESCRIPTIONS } from './constants'; @@ -57,7 +57,11 @@ export const PrecisionSlider: React.FC = () => { defaultMessage: 'Fine tune the precision vs. recall settings on your engine.', } )}{' '} - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.relevanceTuning.precisionSlider.learnMore.link', { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_callouts.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_callouts.tsx index bf2c21a1003f5..ef0bea39439c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_callouts.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_callouts.tsx @@ -13,8 +13,9 @@ import { EuiCallOut, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { docLinks } from '../../../shared/doc_links'; import { EuiLinkTo } from '../../../shared/react_router_helpers'; -import { META_ENGINES_DOCS_URL, ENGINE_SCHEMA_PATH } from '../../routes'; +import { ENGINE_SCHEMA_PATH } from '../../routes'; import { EngineLogic, generateEnginePath } from '../engine'; import { RelevanceTuningLogic } from '.'; @@ -98,7 +99,7 @@ export const RelevanceTuningCallouts: React.FC = () => { values={{ schemaFieldsWithConflictsCount, link: ( - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.relevanceTuning.whatsThisLinkLabel', { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/components/empty_state.tsx index 7f91447b910b6..6434a877ead5e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/components/empty_state.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { RESULT_SETTINGS_DOCS_URL } from '../../../routes'; +import { docLinks } from '../../../../shared/doc_links'; export const EmptyState: React.FC = () => ( ( } )} actions={ - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.resultSettings.empty.buttonLabel', { defaultMessage: 'Read the result settings guide' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.tsx index aff138b9c3884..2ffe6cb357e54 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.tsx @@ -12,6 +12,7 @@ import { useActions, useValues } from 'kea'; import { EuiSpacer } from '@elastic/eui'; import { APP_SEARCH_PLUGIN } from '../../../../../common/constants'; +import { docLinks } from '../../../shared/doc_links'; import { RoleMappingsTable, RoleMappingsHeading, @@ -22,7 +23,6 @@ import { } from '../../../shared/role_mapping'; import { ROLE_MAPPINGS_TITLE } from '../../../shared/role_mapping/constants'; -import { SECURITY_DOCS_URL } from '../../routes'; import { AppSearchPageTemplate } from '../layout'; import { ROLE_MAPPINGS_ENGINE_ACCESS_HEADING } from './constants'; @@ -57,7 +57,7 @@ export const RoleMappings: React.FC = () => { const rolesEmptyState = ( ); @@ -66,7 +66,7 @@ export const RoleMappings: React.FC = () => {
initializeRoleMapping()} /> { @@ -40,7 +40,12 @@ export const EmptyState: React.FC = () => {

} actions={ - + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.schema.empty.buttonLabel', { defaultMessage: 'Read the indexing schema guide', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/components/empty_state.tsx index 9a663e1372211..e5b0f2facedbd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/components/empty_state.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { SEARCH_UI_DOCS_URL } from '../../../routes'; +import { docLinks } from '../../../../shared/doc_links'; export const EmptyState: React.FC = () => ( (

} actions={ - + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.searchUI.empty.buttonLabel', { defaultMessage: 'Read the Search UI guide', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui.tsx index d7398357a5e58..cfef71d34fb9f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui.tsx @@ -12,7 +12,7 @@ import { useActions, useValues } from 'kea'; import { EuiText, EuiFlexItem, EuiFlexGroup, EuiSpacer, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { SEARCH_UI_DOCS_URL } from '../../routes'; +import { docLinks } from '../../../shared/doc_links'; import { EngineLogic, getEngineBreadcrumbs } from '../engine'; import { AppSearchPageTemplate } from '../layout'; @@ -63,7 +63,7 @@ export const SearchUI: React.FC = () => { defaultMessage="Use the fields below to generate a sample search experience built with Search UI. Use the sample to preview search results, or build upon it to create your own custom search experience. {link}." values={{ link: ( - + { defaultMessage: 'Log retention is determined by the ILM policies for your deployment.', })}
- + {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.learnMore', { defaultMessage: 'Learn more about log retention for Enterprise Search.', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/synonyms/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/synonyms/components/empty_state.tsx index ef5e1dafa443f..ff7e8ce16c6d2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/synonyms/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/synonyms/components/empty_state.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiEmptyPrompt, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { SYNONYMS_DOCS_URL } from '../../../routes'; +import { docLinks } from '../../../../shared/doc_links'; import { SynonymModal, SynonymIcon } from '.'; @@ -35,7 +35,7 @@ export const EmptyState: React.FC = () => {

} actions={ - + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.synonyms.empty.buttonLabel', { defaultMessage: 'Read the synonyms guide', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts index 1a41004c882e3..128af5adacfad 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts @@ -5,30 +5,6 @@ * 2.0. */ -import { docLinks } from '../shared/doc_links'; - -export const API_DOCS_URL = docLinks.appSearchApis; -export const API_CLIENTS_DOCS_URL = docLinks.appSearchApiClients; -export const API_KEYS_DOCS_URL = docLinks.appSearchApiKeys; -export const AUTHENTICATION_DOCS_URL = docLinks.appSearchAuthentication; -export const CRAWL_RULES_DOCS_URL = docLinks.appSearchCrawlRules; -export const CURATIONS_DOCS_URL = docLinks.appSearchCurations; -export const DOCS_URL = docLinks.appSearchGuide; -export const DUPLICATE_DOCS_URL = docLinks.appSearchDuplicateDocuments; -export const ENTRY_POINTS_DOCS_URL = docLinks.appSearchEntryPoints; -export const INDEXING_DOCS_URL = docLinks.appSearchIndexingDocs; -export const INDEXING_SCHEMA_DOCS_URL = docLinks.appSearchIndexingDocsSchema; -export const LOG_SETTINGS_DOCS_URL = docLinks.appSearchLogSettings; -export const META_ENGINES_DOCS_URL = docLinks.appSearchMetaEngines; -export const PRECISION_DOCS_URL = docLinks.appSearchPrecision; -export const RELEVANCE_DOCS_URL = docLinks.appSearchRelevance; -export const RESULT_SETTINGS_DOCS_URL = docLinks.appSearchResultSettings; -export const SEARCH_UI_DOCS_URL = docLinks.appSearchSearchUI; -export const SECURITY_DOCS_URL = docLinks.appSearchSecurity; -export const SYNONYMS_DOCS_URL = docLinks.appSearchSynonyms; -export const WEB_CRAWLER_DOCS_URL = docLinks.appSearchWebCrawler; -export const WEB_CRAWLER_LOG_DOCS_URL = docLinks.appSearchWebCrawlerEventLogs; - export const ROOT_PATH = '/'; export const SETUP_GUIDE_PATH = '/setup_guide'; export const LIBRARY_PATH = '/library'; diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/page_template.tsx new file mode 100644 index 0000000000000..40698b273730b --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/page_template.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useLayoutEffect } from 'react'; + +import { useValues } from 'kea'; + +import useObservable from 'react-use/lib/useObservable'; + +import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; +import { KibanaLogic } from '../../../shared/kibana'; +import { SetSearchPlaygroundChrome } from '../../../shared/kibana_chrome/set_chrome'; +import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout'; +import { useEnterpriseSearchNav } from '../../../shared/layout'; +import { SendEnterpriseSearchTelemetry } from '../../../shared/telemetry'; + +import { PlaygroundHeaderDocsAction } from './header_docs_action'; + +export type SearchPlaygroundPageTemplateProps = Omit< + PageTemplateProps, + 'useEndpointHeaderActions' +> & { + hasSchemaConflicts?: boolean; + restrictWidth?: boolean; + searchApplicationName?: string; +}; + +export const SearchPlaygroundPageTemplate: React.FC = ({ + children, + pageChrome, + pageViewTelemetry, + searchApplicationName, + hasSchemaConflicts, + restrictWidth = true, + ...pageTemplateProps +}) => { + const navItems = useEnterpriseSearchNav(); + + const { renderHeaderActions, getChromeStyle$ } = useValues(KibanaLogic); + const chromeStyle = useObservable(getChromeStyle$(), 'classic'); + + useLayoutEffect(() => { + renderHeaderActions(PlaygroundHeaderDocsAction); + + return () => { + renderHeaderActions(); + }; + }, []); + + return ( + } + useEndpointHeaderActions={false} + > + {pageViewTelemetry && ( + + )} + {children} + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/playground.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/playground.tsx index b117518d3a6e0..e8e72e5dfb37a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/playground.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/playground.tsx @@ -12,7 +12,8 @@ import { useValues } from 'kea'; import { i18n } from '@kbn/i18n'; import { KibanaLogic } from '../../../shared/kibana'; -import { EnterpriseSearchApplicationsPageTemplate } from '../layout/page_template'; + +import { SearchPlaygroundPageTemplate } from './page_template'; export const Playground: React.FC = () => { const { searchPlayground } = useValues(KibanaLogic); @@ -22,7 +23,7 @@ export const Playground: React.FC = () => { } return ( - { panelled={false} customPageSections bottomBorder="extended" - docLink="playground" > - + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/elasticsearch_guide/elasticsearch_guide.tsx b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/elasticsearch_guide/elasticsearch_guide.tsx index 80a8de9acdc21..be470577cd519 100644 --- a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/elasticsearch_guide/elasticsearch_guide.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/elasticsearch_guide/elasticsearch_guide.tsx @@ -40,7 +40,7 @@ export const ElasticsearchGuide = () => { }, []); return ( - + {isFlyoutOpen && setIsFlyoutOpen(false)} />}

diff --git a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.tsx index 7f2eded8a6565..c5c777cb74773 100644 --- a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.tsx @@ -19,13 +19,14 @@ export const EnterpriseSearchElasticsearchPageTemplate: React.FC { + const navItems = useEnterpriseSearchNav(); return ( } > diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration.tsx index 13273266a2068..825f47920d256 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration.tsx @@ -6,16 +6,27 @@ */ import React, { useState } from 'react'; +import { css } from '@emotion/react'; +import dedent from 'dedent'; + +import { useValues } from 'kea'; + import { EuiButtonIcon, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover, useGeneratedHtmlId, + useEuiTheme, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { NATIVE_CONNECTOR_DEFINITIONS, NativeConnector } from '@kbn/search-connectors'; +import { TryInConsoleButton } from '@kbn/try-in-console'; +import { KibanaDeps } from '../../../../../../../common/types'; +import { NewConnectorLogic } from '../../../new_index/method_connector/new_connector_logic'; import { SelfManagePreference } from '../create_connector'; import { ManualConfigurationFlyout } from './manual_configuration_flyout'; @@ -25,10 +36,18 @@ export interface ManualConfigurationProps { selfManagePreference: SelfManagePreference; } +interface ConnectorConfiguration { + [key: string]: { + value: string; + }; +} + export const ManualConfiguration: React.FC = ({ isDisabled, selfManagePreference, }) => { + const { euiTheme } = useEuiTheme(); + const { services } = useKibana(); const [isPopoverOpen, setPopover] = useState(false); const splitButtonPopoverId = useGeneratedHtmlId({ prefix: 'splitButtonPopover', @@ -40,9 +59,104 @@ export const ManualConfiguration: React.FC = ({ const closePopover = () => { setPopover(false); }; - + const { selectedConnector, rawName } = useValues(NewConnectorLogic); const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); const [flyoutContent, setFlyoutContent] = useState<'manual_config' | 'client'>(); + const getCodeSnippet = (): string => { + const connectorInfo: NativeConnector | undefined = selectedConnector?.serviceType + ? NATIVE_CONNECTOR_DEFINITIONS[selectedConnector.serviceType] + : undefined; + if (!connectorInfo) { + return ''; + } + + const dynamicConfigValues = Object.entries( + connectorInfo.configuration as ConnectorConfiguration + ) + .map(([key, config]) => { + const defaultValue = config ? JSON.stringify(config.value) : null; + return ` "${key}": ${defaultValue}`; + }) + .join(',\n'); + const CONSOLE_SNIPPET = dedent` # Example of how to create a ${connectorInfo?.name} connector using the API +# This also creates related resources like an index and an API key. +# This is an alternative to using the UI creation flow. + +# 1. Create an index +PUT connector-${rawName} +{ + "settings": { + "index": { + "number_of_shards": 3, + "number_of_replicas": 2 + } + } +} +# 2. Create a connector +PUT _connector/${rawName} +{ + "name": "My ${connectorInfo?.name} connector", + "index_name": "connector-${rawName}", + "service_type": "${selectedConnector?.serviceType}" +} +# 3. Create an API key +POST /_security/api_key +{ + "name": "${rawName}-api-key", + "role_descriptors": { + "${selectedConnector?.serviceType}-api-key-role": { + "cluster": [ + "monitor", + "manage_connector" + ], + "indices": [ + { + "names": [ + "connector-${rawName}", + ".search-acl-filter-connector-${rawName}", + ".elastic-connectors*" + ], + "privileges": [ + "all" + ], + "allow_restricted_indices": false + } + ] + } + } +} + +# 🔧 Configure your connector +# NOTE: Configuration keys differ per service type. +PUT _connector/${rawName}/_configuration +{ + "values": { +${dynamicConfigValues} + } +} + +# 🔌 Verify your connector is connected +GET _connector/${rawName} + +# 🔄 Sync data +POST _connector/_sync_job +{ + "id": "${rawName}", + "job_type": "full" +} + +# ⏳ Check sync status +GET _connector/_sync_job?connector_id=${rawName}&size=1 + +# Once the job completes, the status should return completed +# 🎉 Verify that data is present in the index with the following API call +GET connector-${rawName}/_count + +# 🔎 Elasticsearch stores data in documents, which are JSON objects. List the individual documents with the following API call +GET connector-${rawName}/_search +`; + return CONSOLE_SNIPPET; + }; const items = [ = ({ { defaultMessage: 'Manual configuration' } )} , + { + closePopover(); + }} + css={css` + .euiLink { + color: ${euiTheme.colors.text}; + font-weight: ${euiTheme.font.weight.regular}; + } + `} + > + + , = ({ title, setCurrentStep }) => { const { connector } = useValues(ConnectorViewLogic); const { updateConnectorConfiguration } = useActions(ConnectorViewLogic); + const { setFormDirty } = useActions(NewConnectorLogic); const { status } = useValues(ConnectorConfigurationApiLogic); const isSyncing = false; @@ -109,7 +111,10 @@ export const ConfigurationStep: React.FC = ({ title, set setCurrentStep('finish')} + onClick={() => { + setFormDirty(false); + setCurrentStep('finish'); + }} fill > {Constants.NEXT_BUTTON_LABEL} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx index e8cef81662096..6e83bf98c2371 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx @@ -28,6 +28,11 @@ import { import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps'; import { i18n } from '@kbn/i18n'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { useUnsavedChangesPrompt } from '@kbn/unsaved-changes-prompt'; + +import { HttpLogic } from '../../../../shared/http'; +import { KibanaLogic } from '../../../../shared/kibana'; import { AddConnectorApiLogic } from '../../../api/connector/add_connector_api_logic'; import { EnterpriseSearchContentPageTemplate } from '../../layout'; @@ -47,20 +52,23 @@ import { StartStep } from './start_step'; export type ConnectorCreationSteps = 'start' | 'deployment' | 'configure' | 'finish'; export type SelfManagePreference = 'native' | 'selfManaged'; export const CreateConnector: React.FC = () => { + const { overlays } = useKibana().services; + + const { http } = useValues(HttpLogic); + const { application, history } = useValues(KibanaLogic); + const { error } = useValues(AddConnectorApiLogic); const { euiTheme } = useEuiTheme(); const [selfManagePreference, setSelfManagePreference] = useState('native'); - const { selectedConnector, currentStep } = useValues(NewConnectorLogic); + const { selectedConnector, currentStep, isFormDirty } = useValues(NewConnectorLogic); const { setCurrentStep } = useActions(NewConnectorLogic); const stepStates = generateStepState(currentStep); useEffect(() => { // TODO: separate this to ability and preference - if (!selectedConnector?.isNative || !selfManagePreference) { + if (selectedConnector && !selectedConnector.isNative && selfManagePreference === 'native') { setSelfManagePreference('selfManaged'); - } else { - setSelfManagePreference('native'); } }, [selectedConnector]); @@ -137,6 +145,33 @@ export const CreateConnector: React.FC = () => { ), }; + useUnsavedChangesPrompt({ + cancelButtonText: i18n.translate( + 'xpack.enterpriseSearch.createConnector.unsavedPrompt.cancel', + { + defaultMessage: 'Continue setup', + } + ), + confirmButtonText: i18n.translate( + 'xpack.enterpriseSearch.createConnector.unsavedPrompt.confirm', + { + defaultMessage: 'Leave the page', + } + ), + hasUnsavedChanges: isFormDirty, + history, + http, + messageText: i18n.translate('xpack.enterpriseSearch.createConnector.unsavedPrompt.body', { + defaultMessage: + 'Your connector is created but missing some details. You can complete the setup later in the connector configuration page, but this guided flow offers more help.', + }), + navigateToUrl: application.navigateToUrl, + openConfirm: overlays?.openConfirm ?? (() => Promise.resolve(false)), + titleText: i18n.translate('xpack.enterpriseSearch.createConnector.unsavedPrompt.title', { + defaultMessage: 'Your connector is not fully configured', + }), + }); + return ( { - {selfManagePreference + {selfManagePreference === 'selfManaged' ? i18n.translate( 'xpack.enterpriseSearch.createConnector.badgeType.selfManaged', { - defaultMessage: 'Self managed', + defaultMessage: 'Self-managed', } ) : i18n.translate( diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx index 28d04750b80ba..7e23474b207f1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx @@ -27,6 +27,7 @@ import { import { i18n } from '@kbn/i18n'; import * as Constants from '../../../../shared/constants'; +import { isValidIndexName } from '../../../utils/validate_index_name'; import { GeneratedConfigFields } from '../../connector_detail/components/generated_config_fields'; import { ConnectorViewLogic } from '../../connector_detail/connector_view_logic'; @@ -63,13 +64,26 @@ export const StartStep: React.FC = ({ isGenerateLoading, isCreateLoading, } = useValues(NewConnectorLogic); - const { setRawName, createConnector, generateConnectorName } = useActions(NewConnectorLogic); + const { setRawName, createConnector, generateConnectorName, setFormDirty } = + useActions(NewConnectorLogic); const { connector } = useValues(ConnectorViewLogic); const handleNameChange = (e: ChangeEvent) => { setRawName(e.target.value); }; + const formError = isValidIndexName(rawName) + ? error + : i18n.translate( + 'xpack.enterpriseSearch.createConnector.startStep.euiFormRow.nameInputHelpText.lineOne', + { + defaultMessage: '{connectorName} is an invalid index name', + values: { + connectorName: rawName, + }, + } + ); + return ( @@ -99,6 +113,22 @@ export const StartStep: React.FC = ({ 'xpack.enterpriseSearch.createConnector.startStep.euiFormRow.connectorNameLabel', { defaultMessage: 'Connector name' } )} + helpText={ + <> + + {formError} + + + {i18n.translate( + 'xpack.enterpriseSearch.startStep.namesShouldBeLowercaseTextLabel', + { + defaultMessage: + 'The connector name should be lowercase and cannot contain spaces or special characters.', + } + )} + + + } > = ({ 'xpack.enterpriseSearch.createConnector.startStep.euiFormRow.descriptionLabel', { defaultMessage: 'Description' } )} + labelAppend={ + + {i18n.translate( + 'xpack.enterpriseSearch.createConnector.startStep.euiFormRow.descriptionLabelAppend', + { defaultMessage: 'Optional' } + )} + + } > = ({ hasShadow={false} hasBorder paddingSize="l" - color={selectedConnector?.name ? 'plain' : 'subdued'} + color={ + selectedConnector?.name && isValidIndexName(rawName) && !error ? 'plain' : 'subdued' + } > - +

{i18n.translate( 'xpack.enterpriseSearch.createConnector.startStep.h4.deploymentLabel', @@ -217,7 +263,10 @@ export const StartStep: React.FC = ({

- +

{i18n.translate( 'xpack.enterpriseSearch.createConnector.startStep.p.youWillStartTheLabel', @@ -236,11 +285,12 @@ export const StartStep: React.FC = ({ createConnector({ isSelfManaged: true, }); + setFormDirty(true); setCurrentStep('deployment'); } }} fill - disabled={!canConfigureConnector} + disabled={!canConfigureConnector || !isValidIndexName(rawName) || Boolean(error)} isLoading={isCreateLoading || isGenerateLoading} > {Constants.NEXT_BUTTON_LABEL} @@ -250,12 +300,20 @@ export const StartStep: React.FC = ({ ) : ( - +

{i18n.translate( 'xpack.enterpriseSearch.createConnector.startStep.h4.configureIndexAndAPILabel', @@ -266,7 +324,14 @@ export const StartStep: React.FC = ({

- +

{i18n.translate( 'xpack.enterpriseSearch.createConnector.startStep.p.thisProcessWillCreateLabel', @@ -294,7 +359,9 @@ export const StartStep: React.FC = ({ setCurrentStep('configure')} + onClick={() => { + setCurrentStep('configure'); + }} > {Constants.NEXT_BUTTON_LABEL} @@ -305,11 +372,14 @@ export const StartStep: React.FC = ({ { + setFormDirty(true); createConnector({ isSelfManaged: false, }); @@ -325,7 +395,13 @@ export const StartStep: React.FC = ({ diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts index 796a2a64ab56c..0d21db6e03baf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts @@ -56,6 +56,7 @@ export interface NewConnectorValues { | undefined; generatedNameData: GenerateConnectorNamesApiResponse | undefined; isCreateLoading: boolean; + isFormDirty: boolean; isGenerateLoading: boolean; rawName: string; selectedConnector: ConnectorDefinition | null; @@ -85,6 +86,7 @@ type NewConnectorActions = { createConnectorApi: AddConnectorApiLogicActions['makeRequest']; fetchConnector: ConnectorViewActions['fetchConnector']; setCurrentStep(step: ConnectorCreationSteps): { step: ConnectorCreationSteps }; + setFormDirty: (isDirty: boolean) => { isDirty: boolean }; setRawName(rawName: string): { rawName: string }; setSelectedConnector(connector: ConnectorDefinition | null): { connector: ConnectorDefinition | null; @@ -103,6 +105,7 @@ export const NewConnectorLogic = kea ({ step }), + setFormDirty: (isDirty) => ({ isDirty }), setRawName: (rawName) => ({ rawName }), setSelectedConnector: (connector) => ({ connector }), }, @@ -214,6 +217,13 @@ export const NewConnectorLogic = kea step, }, ], + isFormDirty: [ + false, // Initial state (form is not dirty) + { + // @ts-expect-error upgrade typescript v5.1.6 + setFormDirty: (_, { isDirty }) => isDirty, + }, + ], rawName: [ '', { diff --git a/x-pack/plugins/enterprise_search/public/applications/index.tsx b/x-pack/plugins/enterprise_search/public/applications/index.tsx index eafa8827869d8..717379d433dd1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/index.tsx @@ -114,6 +114,7 @@ export const renderApp = ( data: plugins.data, esConfig, getChromeStyle$: chrome.getChromeStyle$, + getNavLinks: chrome.navLinks.getAll, guidedOnboarding, history, indexMappingComponent, diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts index f74345a1c75c1..6cd6e5410ef11 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts @@ -55,6 +55,7 @@ export interface KibanaLogicProps { data?: DataPublicPluginStart; esConfig: ESConfig; getChromeStyle$: ChromeStart['getChromeStyle$']; + getNavLinks: ChromeStart['navLinks']['getAll']; guidedOnboarding?: GuidedOnboardingPluginStart; history: ScopedHistory; indexMappingComponent?: React.FC; @@ -87,6 +88,7 @@ export interface KibanaValues { data: DataPublicPluginStart | null; esConfig: ESConfig; getChromeStyle$: ChromeStart['getChromeStyle$']; + getNavLinks: ChromeStart['navLinks']['getAll']; guidedOnboarding: GuidedOnboardingPluginStart | null; history: ScopedHistory; indexMappingComponent: React.FC | null; @@ -126,6 +128,7 @@ export const KibanaLogic = kea>({ data: [props.data || null, {}], esConfig: [props.esConfig || { elasticsearch_host: ELASTICSEARCH_URL_PLACEHOLDER }, {}], getChromeStyle$: [props.getChromeStyle$, {}], + getNavLinks: [props.getNavLinks, {}], guidedOnboarding: [props.guidedOnboarding || null, {}], history: [props.history, {}], indexMappingComponent: [props.indexMappingComponent || null, {}], diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts index ea6bda26be450..189ca53e362e1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts @@ -22,6 +22,8 @@ import { VECTOR_SEARCH_PLUGIN, WORKPLACE_SEARCH_PLUGIN, SEMANTIC_SEARCH_PLUGIN, + APPLICATIONS_PLUGIN, + GETTING_STARTED_TITLE, } from '../../../../common/constants'; import { stripLeadingSlash } from '../../../../common/strip_slashes'; @@ -126,7 +128,11 @@ export const useEnterpriseSearchBreadcrumbs = (breadcrumbs: Breadcrumbs = []) => ]); export const useAnalyticsBreadcrumbs = (breadcrumbs: Breadcrumbs = []) => - useSearchBreadcrumbs([{ text: ANALYTICS_PLUGIN.NAME, path: '/' }, ...breadcrumbs]); + useSearchBreadcrumbs([ + { text: APPLICATIONS_PLUGIN.NAV_TITLE }, + { text: ANALYTICS_PLUGIN.NAME, path: '/' }, + ...breadcrumbs, + ]); export const useElasticsearchBreadcrumbs = (breadcrumbs: Breadcrumbs = []) => useSearchBreadcrumbs([ @@ -161,13 +167,25 @@ export const useSearchExperiencesBreadcrumbs = (breadcrumbs: Breadcrumbs = []) = useSearchBreadcrumbs([{ text: SEARCH_EXPERIENCES_PLUGIN.NAV_TITLE, path: '/' }, ...breadcrumbs]); export const useEnterpriseSearchApplicationsBreadcrumbs = (breadcrumbs: Breadcrumbs = []) => - useSearchBreadcrumbs(breadcrumbs); + useSearchBreadcrumbs([{ text: APPLICATIONS_PLUGIN.NAV_TITLE }, ...breadcrumbs]); export const useAiSearchBreadcrumbs = (breadcrumbs: Breadcrumbs = []) => - useSearchBreadcrumbs([{ text: AI_SEARCH_PLUGIN.NAME, path: '/' }, ...breadcrumbs]); + useSearchBreadcrumbs([ + { text: GETTING_STARTED_TITLE }, + { text: AI_SEARCH_PLUGIN.NAME, path: '/' }, + ...breadcrumbs, + ]); export const useVectorSearchBreadcrumbs = (breadcrumbs: Breadcrumbs = []) => - useSearchBreadcrumbs([{ text: VECTOR_SEARCH_PLUGIN.NAV_TITLE, path: '/' }, ...breadcrumbs]); + useSearchBreadcrumbs([ + { text: GETTING_STARTED_TITLE }, + { text: VECTOR_SEARCH_PLUGIN.NAV_TITLE, path: '/' }, + ...breadcrumbs, + ]); export const useSemanticSearchBreadcrumbs = (breadcrumbs: Breadcrumbs = []) => - useSearchBreadcrumbs([{ text: SEMANTIC_SEARCH_PLUGIN.NAME, path: '/' }, ...breadcrumbs]); + useSearchBreadcrumbs([ + { text: GETTING_STARTED_TITLE }, + { text: SEMANTIC_SEARCH_PLUGIN.NAME, path: '/' }, + ...breadcrumbs, + ]); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_title.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_title.ts index eaeb30f1540d0..df7d16cddc4d4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_title.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_title.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { i18n } from '@kbn/i18n'; + import { AI_SEARCH_PLUGIN, ANALYTICS_PLUGIN, @@ -40,7 +42,12 @@ export const searchTitle = (page: Title = []) => generateTitle([...page, SEARCH_ export const analyticsTitle = (page: Title = []) => generateTitle([...page, ANALYTICS_PLUGIN.NAME]); export const elasticsearchTitle = (page: Title = []) => - generateTitle([...page, 'Getting started with Elasticsearch']); + generateTitle([ + ...page, + i18n.translate('xpack.enterpriseSearch.titles.elasticsearch', { + defaultMessage: 'Getting started with Elasticsearch', + }), + ]); export const appSearchTitle = (page: Title = []) => generateTitle([...page, APP_SEARCH_PLUGIN.NAME]); @@ -61,3 +68,11 @@ export const semanticSearchTitle = (page: Title = []) => export const enterpriseSearchContentTitle = (page: Title = []) => generateTitle([...page, ENTERPRISE_SEARCH_CONTENT_PLUGIN.NAME]); + +export const searchApplicationsTitle = (page: Title = []) => + generateTitle([ + ...page, + i18n.translate('xpack.enterpriseSearch.titles.searchApplications', { + defaultMessage: 'Search Applications', + }), + ]); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx index 8f7c71d1309c0..0c05cb0c02ca0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx @@ -9,8 +9,7 @@ import React, { useEffect } from 'react'; import { useValues } from 'kea'; -import { APPLICATIONS_PLUGIN } from '../../../../common/constants'; - +import { SEARCH_APPS_BREADCRUMB } from '../../../../common/constants'; import { KibanaLogic } from '../kibana'; import { @@ -35,6 +34,8 @@ import { appSearchTitle, elasticsearchTitle, enterpriseSearchContentTitle, + generateTitle, + searchApplicationsTitle, searchExperiencesTitle, searchTitle, semanticSearchTitle, @@ -210,14 +211,30 @@ export const SetSearchExperiencesChrome: React.FC = ({ trail = [ return null; }; +export const SetSearchPlaygroundChrome: React.FC = ({ trail = [] }) => { + const { setBreadcrumbs, setDocTitle } = useValues(KibanaLogic); + + const title = reverseArray(trail); + const docTitle = generateTitle(title); + + const breadcrumbs = useEnterpriseSearchApplicationsBreadcrumbs(useGenerateBreadcrumbs(trail)); + + useEffect(() => { + setBreadcrumbs(breadcrumbs); + setDocTitle(docTitle); + }, [trail]); + + return null; +}; + export const SetEnterpriseSearchApplicationsChrome: React.FC = ({ trail = [] }) => { const { setBreadcrumbs, setDocTitle } = useValues(KibanaLogic); const title = reverseArray(trail); - const docTitle = appSearchTitle(title); + const docTitle = searchApplicationsTitle(title); const breadcrumbs = useEnterpriseSearchApplicationsBreadcrumbs( - useGenerateBreadcrumbs([APPLICATIONS_PLUGIN.NAV_TITLE, ...trail]) + useGenerateBreadcrumbs([SEARCH_APPS_BREADCRUMB, ...trail]) ); useEffect(() => { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/base_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/base_nav.tsx new file mode 100644 index 0000000000000..b971ab6deff53 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/base_nav.tsx @@ -0,0 +1,201 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiText } from '@elastic/eui'; +import { + ENTERPRISE_SEARCH_APP_ID, + ENTERPRISE_SEARCH_ANALYTICS_APP_ID, + SEARCH_ELASTICSEARCH, + SEARCH_VECTOR_SEARCH, + SEARCH_SEMANTIC_SEARCH, + SEARCH_AI_SEARCH, +} from '@kbn/deeplinks-search'; +import { i18n } from '@kbn/i18n'; + +import { GETTING_STARTED_TITLE } from '../../../../common/constants'; + +import { ClassicNavItem, BuildClassicNavParameters } from '../types'; + +export const buildBaseClassicNavItems = ({ + productAccess, +}: BuildClassicNavParameters): ClassicNavItem[] => { + const navItems: ClassicNavItem[] = []; + + // Home + navItems.push({ + 'data-test-subj': 'searchSideNav-Home', + deepLink: { + link: ENTERPRISE_SEARCH_APP_ID, + shouldShowActiveForSubroutes: true, + }, + id: 'home', + name: ( + + {i18n.translate('xpack.enterpriseSearch.nav.homeTitle', { + defaultMessage: 'Home', + })} + + ), + }); + + // Content + navItems.push({ + 'data-test-subj': 'searchSideNav-Content', + id: 'content', + items: [ + { + 'data-test-subj': 'searchSideNav-Indices', + deepLink: { + link: 'enterpriseSearchContent:searchIndices', + shouldShowActiveForSubroutes: true, + }, + id: 'search_indices', + }, + { + 'data-test-subj': 'searchSideNav-Connectors', + deepLink: { + link: 'enterpriseSearchContent:connectors', + shouldShowActiveForSubroutes: true, + }, + id: 'connectors', + }, + { + 'data-test-subj': 'searchSideNav-Crawlers', + deepLink: { + link: 'enterpriseSearchContent:webCrawlers', + shouldShowActiveForSubroutes: true, + }, + id: 'crawlers', + }, + ], + name: i18n.translate('xpack.enterpriseSearch.nav.contentTitle', { + defaultMessage: 'Content', + }), + }); + + // Build + navItems.push({ + 'data-test-subj': 'searchSideNav-Build', + id: 'build', + items: [ + { + 'data-test-subj': 'searchSideNav-Playground', + deepLink: { + link: 'enterpriseSearchApplications:playground', + shouldShowActiveForSubroutes: true, + }, + id: 'playground', + }, + { + 'data-test-subj': 'searchSideNav-SearchApplications', + deepLink: { + link: 'enterpriseSearchApplications:searchApplications', + }, + id: 'searchApplications', + }, + { + 'data-test-subj': 'searchSideNav-BehavioralAnalytics', + deepLink: { + link: ENTERPRISE_SEARCH_ANALYTICS_APP_ID, + }, + id: 'analyticsCollections', + }, + ], + name: i18n.translate('xpack.enterpriseSearch.nav.applicationsTitle', { + defaultMessage: 'Build', + }), + }); + + navItems.push({ + 'data-test-subj': 'searchSideNav-Relevance', + id: 'relevance', + items: [ + { + 'data-test-subj': 'searchSideNav-InferenceEndpoints', + deepLink: { + link: 'searchInferenceEndpoints:inferenceEndpoints', + shouldShowActiveForSubroutes: true, + }, + id: 'inference_endpoints', + }, + ], + name: i18n.translate('xpack.enterpriseSearch.nav.relevanceTitle', { + defaultMessage: 'Relevance', + }), + }); + + // Getting Started + navItems.push({ + 'data-test-subj': 'searchSideNav-GettingStarted', + id: 'es_getting_started', + items: [ + { + 'data-test-subj': 'searchSideNav-Elasticsearch', + deepLink: { + link: SEARCH_ELASTICSEARCH, + }, + id: 'elasticsearch', + }, + { + 'data-test-subj': 'searchSideNav-VectorSearch', + deepLink: { + link: SEARCH_VECTOR_SEARCH, + }, + id: 'vectorSearch', + }, + { + 'data-test-subj': 'searchSideNav-SemanticSearch', + deepLink: { + link: SEARCH_SEMANTIC_SEARCH, + }, + id: 'semanticSearch', + }, + { + 'data-test-subj': 'searchSideNav-AISearch', + deepLink: { + link: SEARCH_AI_SEARCH, + }, + id: 'aiSearch', + }, + ], + name: GETTING_STARTED_TITLE, + }); + + if (productAccess.hasAppSearchAccess || productAccess.hasWorkplaceSearchAccess) { + const entSearchItems: ClassicNavItem[] = []; + if (productAccess.hasAppSearchAccess) { + entSearchItems.push({ + 'data-test-subj': 'searchSideNav-AppSearch', + deepLink: { + link: 'appSearch:engines', + }, + id: 'app_search', + }); + } + if (productAccess.hasWorkplaceSearchAccess) { + entSearchItems.push({ + 'data-test-subj': 'searchSideNav-WorkplaceSearch', + deepLink: { + link: 'workplaceSearch', + }, + id: 'workplace_search', + }); + } + navItems.push({ + 'data-test-subj': 'searchSideNav-EnterpriseSearch', + id: 'enterpriseSearch', + items: entSearchItems, + name: i18n.translate('xpack.enterpriseSearch.nav.title', { + defaultMessage: 'Enterprise Search', + }), + }); + } + + return navItems; +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/classic_nav_helpers.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/layout/classic_nav_helpers.test.ts new file mode 100644 index 0000000000000..514072ba297aa --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/classic_nav_helpers.test.ts @@ -0,0 +1,189 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockKibanaValues } from '../../__mocks__/kea_logic'; + +import type { ChromeNavLink } from '@kbn/core-chrome-browser'; + +import '../../__mocks__/react_router'; + +jest.mock('../react_router_helpers/link_events', () => ({ + letBrowserHandleEvent: jest.fn(), +})); + +import { ClassicNavItem } from '../types'; + +import { generateSideNavItems } from './classic_nav_helpers'; + +describe('generateSideNavItems', () => { + const deepLinksMap = { + enterpriseSearch: { + id: 'enterpriseSearch', + url: '/app/enterprise_search/overview', + title: 'Overview', + }, + 'enterpriseSearchContent:searchIndices': { + id: 'enterpriseSearchContent:searchIndices', + title: 'Indices', + url: '/app/enterprise_search/content/search_indices', + }, + 'enterpriseSearchContent:connectors': { + id: 'enterpriseSearchContent:connectors', + title: 'Connectors', + url: '/app/enterprise_search/content/connectors', + }, + 'enterpriseSearchContent:webCrawlers': { + id: 'enterpriseSearchContent:webCrawlers', + title: 'Web crawlers', + url: '/app/enterprise_search/content/crawlers', + }, + } as unknown as Record; + beforeEach(() => { + jest.clearAllMocks(); + mockKibanaValues.history.location.pathname = '/'; + }); + + it('renders top-level items', () => { + const classicNavItems: ClassicNavItem[] = [ + { + id: 'unit-test', + deepLink: { + link: 'enterpriseSearch', + }, + }, + ]; + + expect(generateSideNavItems(classicNavItems, deepLinksMap)).toEqual([ + { + href: '/app/enterprise_search/overview', + id: 'unit-test', + isSelected: false, + name: 'Overview', + onClick: expect.any(Function), + }, + ]); + }); + + it('renders items with children', () => { + const classicNavItems: ClassicNavItem[] = [ + { + id: 'parent', + name: 'Parent', + items: [ + { + id: 'unit-test', + deepLink: { + link: 'enterpriseSearch', + }, + }, + ], + }, + ]; + + expect(generateSideNavItems(classicNavItems, deepLinksMap)).toEqual([ + { + id: 'parent', + items: [ + { + href: '/app/enterprise_search/overview', + id: 'unit-test', + isSelected: false, + name: 'Overview', + onClick: expect.any(Function), + }, + ], + name: 'Parent', + }, + ]); + }); + + it('renders classic nav name over deep link title if provided', () => { + const classicNavItems: ClassicNavItem[] = [ + { + deepLink: { + link: 'enterpriseSearch', + }, + id: 'unit-test', + name: 'Home', + }, + ]; + + expect(generateSideNavItems(classicNavItems, deepLinksMap)).toEqual([ + { + href: '/app/enterprise_search/overview', + id: 'unit-test', + isSelected: false, + name: 'Home', + onClick: expect.any(Function), + }, + ]); + }); + + it('removes item if deep link is not defined', () => { + const classicNavItems: ClassicNavItem[] = [ + { + deepLink: { + link: 'enterpriseSearch', + }, + id: 'unit-test', + name: 'Home', + }, + { + deepLink: { + link: 'enterpriseSearchApplications:playground', + }, + id: 'unit-test-missing', + }, + ]; + + expect(generateSideNavItems(classicNavItems, deepLinksMap)).toEqual([ + { + href: '/app/enterprise_search/overview', + id: 'unit-test', + isSelected: false, + name: 'Home', + onClick: expect.any(Function), + }, + ]); + }); + + it('adds pre-rendered child items provided', () => { + const classicNavItems: ClassicNavItem[] = [ + { + id: 'unit-test', + name: 'Indices', + }, + ]; + const subItems = { + 'unit-test': [ + { + href: '/app/unit-test', + id: 'child', + isSelected: true, + name: 'Index', + onClick: jest.fn(), + }, + ], + }; + + expect(generateSideNavItems(classicNavItems, deepLinksMap, subItems)).toEqual([ + { + id: 'unit-test', + items: [ + { + href: '/app/unit-test', + id: 'child', + isSelected: true, + name: 'Index', + onClick: expect.any(Function), + }, + ], + name: 'Indices', + }, + ]); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/classic_nav_helpers.ts b/x-pack/plugins/enterprise_search/public/applications/shared/layout/classic_nav_helpers.ts new file mode 100644 index 0000000000000..89f3c2ab5b59a --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/classic_nav_helpers.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ChromeNavLink, EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; + +import { + ClassicNavItem, + GenerateNavLinkFromDeepLinkParameters, + GenerateNavLinkParameters, +} from '../types'; + +import { generateNavLink } from './nav_link_helpers'; + +export const generateSideNavItems = ( + navItems: ClassicNavItem[], + deepLinks: Record, + subItemsMap: Record> | undefined> = {} +): Array> => { + const sideNavItems: Array> = []; + + for (const navItem of navItems) { + let sideNavChildItems: Array> | undefined; + + const { deepLink, items, ...rest } = navItem; + const subItems = subItemsMap?.[navItem.id]; + + if (items || subItems) { + sideNavChildItems = []; + if (items) { + sideNavChildItems.push(...generateSideNavItems(items, deepLinks, subItemsMap)); + } + if (subItems) { + sideNavChildItems.push(...subItems); + } + } + + let sideNavItem: EuiSideNavItemTypeEnhanced | undefined; + if (deepLink) { + const navLinkParams = getNavLinkParameters(deepLink, deepLinks); + if (navLinkParams !== undefined) { + const name = navItem.name ?? getDeepLinkTitle(deepLink.link, deepLinks); + sideNavItem = { + ...rest, + name, + ...generateNavLink({ + ...navLinkParams, + items: sideNavChildItems, + }), + }; + } + } else { + sideNavItem = { + ...rest, + items: sideNavChildItems, + name: navItem.name, + }; + } + + if (isValidSideNavItem(sideNavItem)) { + sideNavItems.push(sideNavItem); + } + } + + return sideNavItems; +}; + +const getNavLinkParameters = ( + navLink: GenerateNavLinkFromDeepLinkParameters, + deepLinks: Record +): GenerateNavLinkParameters | undefined => { + const { link, ...navLinkProps } = navLink; + const deepLink = deepLinks[link]; + if (!deepLink || !deepLink.url) return undefined; + return { + ...navLinkProps, + shouldNotCreateHref: true, + shouldNotPrepend: true, + to: deepLink.url, + }; +}; +const getDeepLinkTitle = ( + link: string, + deepLinks: Record +): string | undefined => { + const deepLink = deepLinks[link]; + if (!deepLink || !deepLink.url) return undefined; + return deepLink.title; +}; + +function isValidSideNavItem( + item: EuiSideNavItemTypeEnhanced | undefined +): item is EuiSideNavItemTypeEnhanced { + if (item === undefined) return false; + if (item.href || item.onClick) return true; + if (item?.items?.length ?? 0 > 0) return true; + + return false; +} diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx index b2c31ff4868bc..3305e92dd8d9e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx @@ -15,6 +15,8 @@ jest.mock('../../enterprise_search_content/components/search_index/indices/indic import { setMockValues, mockKibanaValues } from '../../__mocks__/kea_logic'; +import { renderHook } from '@testing-library/react-hooks'; + import { EuiSideNavItemType } from '@elastic/eui'; import { DEFAULT_PRODUCT_FEATURES } from '../../../../common/constants'; @@ -32,26 +34,31 @@ const DEFAULT_PRODUCT_ACCESS: ProductAccess = { }; const baseNavItems = [ expect.objectContaining({ + 'data-test-subj': 'searchSideNav-Home', href: '/app/enterprise_search/overview', id: 'home', items: undefined, }), { + 'data-test-subj': 'searchSideNav-Content', id: 'content', items: [ { + 'data-test-subj': 'searchSideNav-Indices', href: '/app/enterprise_search/content/search_indices', id: 'search_indices', items: [], name: 'Indices', }, { + 'data-test-subj': 'searchSideNav-Connectors', href: '/app/enterprise_search/content/connectors', id: 'connectors', items: undefined, name: 'Connectors', }, { + 'data-test-subj': 'searchSideNav-Crawlers', href: '/app/enterprise_search/content/crawlers', id: 'crawlers', items: undefined, @@ -61,21 +68,25 @@ const baseNavItems = [ name: 'Content', }, { + 'data-test-subj': 'searchSideNav-Build', id: 'build', items: [ { + 'data-test-subj': 'searchSideNav-Playground', href: '/app/enterprise_search/applications/playground', id: 'playground', items: undefined, name: 'Playground', }, { + 'data-test-subj': 'searchSideNav-SearchApplications', href: '/app/enterprise_search/applications/search_applications', id: 'searchApplications', items: undefined, name: 'Search Applications', }, { + 'data-test-subj': 'searchSideNav-BehavioralAnalytics', href: '/app/enterprise_search/analytics', id: 'analyticsCollections', items: undefined, @@ -85,9 +96,11 @@ const baseNavItems = [ name: 'Build', }, { + 'data-test-subj': 'searchSideNav-Relevance', id: 'relevance', items: [ { + 'data-test-subj': 'searchSideNav-InferenceEndpoints', href: '/app/enterprise_search/relevance/inference_endpoints', id: 'inference_endpoints', items: undefined, @@ -97,27 +110,32 @@ const baseNavItems = [ name: 'Relevance', }, { + 'data-test-subj': 'searchSideNav-GettingStarted', id: 'es_getting_started', items: [ { + 'data-test-subj': 'searchSideNav-Elasticsearch', href: '/app/enterprise_search/elasticsearch', id: 'elasticsearch', items: undefined, name: 'Elasticsearch', }, { + 'data-test-subj': 'searchSideNav-VectorSearch', href: '/app/enterprise_search/vector_search', id: 'vectorSearch', items: undefined, name: 'Vector Search', }, { + 'data-test-subj': 'searchSideNav-SemanticSearch', href: '/app/enterprise_search/semantic_search', id: 'semanticSearch', items: undefined, name: 'Semantic Search', }, { + 'data-test-subj': 'searchSideNav-AISearch', href: '/app/enterprise_search/ai_search', id: 'aiSearch', items: undefined, @@ -127,15 +145,18 @@ const baseNavItems = [ name: 'Getting started', }, { + 'data-test-subj': 'searchSideNav-EnterpriseSearch', id: 'enterpriseSearch', items: [ { + 'data-test-subj': 'searchSideNav-AppSearch', href: '/app/enterprise_search/app_search', id: 'app_search', items: undefined, name: 'App Search', }, { + 'data-test-subj': 'searchSideNav-WorkplaceSearch', href: '/app/enterprise_search/workplace_search', id: 'workplace_search', items: undefined, @@ -146,21 +167,102 @@ const baseNavItems = [ }, ]; +const mockNavLinks = [ + { + id: 'enterpriseSearch', + url: '/app/enterprise_search/overview', + }, + { + id: 'enterpriseSearchContent:searchIndices', + title: 'Indices', + url: '/app/enterprise_search/content/search_indices', + }, + { + id: 'enterpriseSearchContent:connectors', + title: 'Connectors', + url: '/app/enterprise_search/content/connectors', + }, + { + id: 'enterpriseSearchContent:webCrawlers', + title: 'Web crawlers', + url: '/app/enterprise_search/content/crawlers', + }, + { + id: 'enterpriseSearchApplications:playground', + title: 'Playground', + url: '/app/enterprise_search/applications/playground', + }, + { + id: 'enterpriseSearchApplications:searchApplications', + title: 'Search Applications', + url: '/app/enterprise_search/applications/search_applications', + }, + { + id: 'enterpriseSearchAnalytics', + title: 'Behavioral Analytics', + url: '/app/enterprise_search/analytics', + }, + { + id: 'searchInferenceEndpoints:inferenceEndpoints', + title: 'Inference Endpoints', + url: '/app/enterprise_search/relevance/inference_endpoints', + }, + { + id: 'appSearch:engines', + title: 'App Search', + url: '/app/enterprise_search/app_search', + }, + { + id: 'workplaceSearch', + title: 'Workplace Search', + url: '/app/enterprise_search/workplace_search', + }, + { + id: 'enterpriseSearchElasticsearch', + title: 'Elasticsearch', + url: '/app/enterprise_search/elasticsearch', + }, + { + id: 'enterpriseSearchVectorSearch', + title: 'Vector Search', + url: '/app/enterprise_search/vector_search', + }, + { + id: 'enterpriseSearchSemanticSearch', + title: 'Semantic Search', + url: '/app/enterprise_search/semantic_search', + }, + { + id: 'enterpriseSearchAISearch', + title: 'AI Search', + url: '/app/enterprise_search/ai_search', + }, +]; + +const defaultMockValues = { + hasEnterpriseLicense: true, + isSidebarEnabled: true, + productAccess: DEFAULT_PRODUCT_ACCESS, + productFeatures: DEFAULT_PRODUCT_FEATURES, +}; + describe('useEnterpriseSearchContentNav', () => { beforeEach(() => { jest.clearAllMocks(); mockKibanaValues.uiSettings.get.mockReturnValue(false); + mockKibanaValues.getNavLinks.mockReturnValue(mockNavLinks); }); it('returns an array of top-level Enterprise Search nav items', () => { const fullProductAccess: ProductAccess = DEFAULT_PRODUCT_ACCESS; setMockValues({ - isSidebarEnabled: true, + ...defaultMockValues, productAccess: fullProductAccess, - productFeatures: DEFAULT_PRODUCT_FEATURES, }); - expect(useEnterpriseSearchNav()).toEqual(baseNavItems); + const { result } = renderHook(() => useEnterpriseSearchNav()); + + expect(result.current).toEqual(baseNavItems); }); it('excludes legacy products when the user has no access to them', () => { @@ -171,13 +273,13 @@ describe('useEnterpriseSearchContentNav', () => { }; setMockValues({ - isSidebarEnabled: true, + ...defaultMockValues, productAccess: noProductAccess, - productFeatures: DEFAULT_PRODUCT_FEATURES, }); mockKibanaValues.uiSettings.get.mockReturnValue(false); - const esNav = useEnterpriseSearchNav(); + const { result } = renderHook(() => useEnterpriseSearchNav()); + const esNav = result.current; const legacyESNav = esNav?.find((item) => item.id === 'enterpriseSearch'); expect(legacyESNav).toBeUndefined(); }); @@ -190,18 +292,20 @@ describe('useEnterpriseSearchContentNav', () => { }; setMockValues({ - isSidebarEnabled: true, + ...defaultMockValues, productAccess: workplaceSearchProductAccess, - productFeatures: DEFAULT_PRODUCT_FEATURES, }); - const esNav = useEnterpriseSearchNav(); + const { result } = renderHook(() => useEnterpriseSearchNav()); + const esNav = result.current; const legacyESNav = esNav?.find((item) => item.id === 'enterpriseSearch'); expect(legacyESNav).not.toBeUndefined(); expect(legacyESNav).toEqual({ + 'data-test-subj': 'searchSideNav-EnterpriseSearch', id: 'enterpriseSearch', items: [ { + 'data-test-subj': 'searchSideNav-WorkplaceSearch', href: '/app/enterprise_search/workplace_search', id: 'workplace_search', name: 'Workplace Search', @@ -218,18 +322,20 @@ describe('useEnterpriseSearchContentNav', () => { }; setMockValues({ - isSidebarEnabled: true, + ...defaultMockValues, productAccess: appSearchProductAccess, - productFeatures: DEFAULT_PRODUCT_FEATURES, }); - const esNav = useEnterpriseSearchNav(); + const { result } = renderHook(() => useEnterpriseSearchNav()); + const esNav = result.current; const legacyESNav = esNav?.find((item) => item.id === 'enterpriseSearch'); expect(legacyESNav).not.toBeUndefined(); expect(legacyESNav).toEqual({ + 'data-test-subj': 'searchSideNav-EnterpriseSearch', id: 'enterpriseSearch', items: [ { + 'data-test-subj': 'searchSideNav-AppSearch', href: '/app/enterprise_search/app_search', id: 'app_search', name: 'App Search', @@ -243,21 +349,21 @@ describe('useEnterpriseSearchContentNav', () => { describe('useEnterpriseSearchApplicationNav', () => { beforeEach(() => { jest.clearAllMocks(); + mockKibanaValues.getNavLinks.mockReturnValue(mockNavLinks); mockKibanaValues.uiSettings.get.mockReturnValue(true); - setMockValues({ - isSidebarEnabled: true, - productAccess: DEFAULT_PRODUCT_ACCESS, - productFeatures: DEFAULT_PRODUCT_FEATURES, - }); + setMockValues(defaultMockValues); }); it('returns an array of top-level Enterprise Search nav items', () => { - expect(useEnterpriseSearchApplicationNav()).toEqual(baseNavItems); + const { result } = renderHook(() => useEnterpriseSearchApplicationNav()); + expect(result.current).toEqual(baseNavItems); }); it('returns selected engine sub nav items', () => { const engineName = 'my-test-engine'; - const navItems = useEnterpriseSearchApplicationNav(engineName); + const { + result: { current: navItems }, + } = renderHook(() => useEnterpriseSearchApplicationNav(engineName)); expect(navItems![0].id).toEqual('home'); expect(navItems?.slice(1).map((ni) => ni.name)).toEqual([ 'Content', @@ -317,7 +423,9 @@ describe('useEnterpriseSearchApplicationNav', () => { it('returns selected engine without tabs when isEmpty', () => { const engineName = 'my-test-engine'; - const navItems = useEnterpriseSearchApplicationNav(engineName, true); + const { + result: { current: navItems }, + } = renderHook(() => useEnterpriseSearchApplicationNav(engineName, true)); expect(navItems![0].id).toEqual('home'); expect(navItems?.slice(1).map((ni) => ni.name)).toEqual([ 'Content', @@ -348,7 +456,9 @@ describe('useEnterpriseSearchApplicationNav', () => { it('returns selected engine with conflict warning when hasSchemaConflicts', () => { const engineName = 'my-test-engine'; - const navItems = useEnterpriseSearchApplicationNav(engineName, false, true); + const { + result: { current: navItems }, + } = renderHook(() => useEnterpriseSearchApplicationNav(engineName, false, true)); // @ts-ignore const engineItem = navItems @@ -383,27 +493,20 @@ describe('useEnterpriseSearchApplicationNav', () => { describe('useEnterpriseSearchAnalyticsNav', () => { beforeEach(() => { jest.clearAllMocks(); - setMockValues({ - isSidebarEnabled: true, - }); + setMockValues(defaultMockValues); + mockKibanaValues.getNavLinks.mockReturnValue(mockNavLinks); }); it('returns basic nav all params are empty', () => { - const navItems = useEnterpriseSearchAnalyticsNav(); - expect(navItems).toEqual( - baseNavItems.map((item) => - item.id === 'content' - ? { - ...item, - items: item.items, - } - : item - ) - ); + const { result } = renderHook(() => useEnterpriseSearchAnalyticsNav()); + + expect(result.current).toEqual(baseNavItems); }); it('returns basic nav if only name provided', () => { - const navItems = useEnterpriseSearchAnalyticsNav('my-test-collection'); + const { + result: { current: navItems }, + } = renderHook(() => useEnterpriseSearchAnalyticsNav('my-test-collection')); expect(navItems).toEqual( baseNavItems.map((item) => item.id === 'content' @@ -417,16 +520,21 @@ describe('useEnterpriseSearchAnalyticsNav', () => { }); it('returns nav with sub items when name and paths provided', () => { - const navItems = useEnterpriseSearchAnalyticsNav('my-test-collection', { - explorer: '/explorer-path', - integration: '/integration-path', - overview: '/overview-path', - }); + const { + result: { current: navItems }, + } = renderHook(() => + useEnterpriseSearchAnalyticsNav('my-test-collection', { + explorer: '/explorer-path', + integration: '/integration-path', + overview: '/overview-path', + }) + ); const applicationsNav = navItems?.find((item) => item.id === 'build'); expect(applicationsNav).not.toBeUndefined(); const analyticsNav = applicationsNav?.items?.[2]; expect(analyticsNav).not.toBeUndefined(); expect(analyticsNav).toEqual({ + 'data-test-subj': 'searchSideNav-BehavioralAnalytics', href: '/app/enterprise_search/analytics', id: 'analyticsCollections', items: [ diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx index 3b3960a7a92ba..8f83b6c73402e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx @@ -5,44 +5,22 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { useValues } from 'kea'; -import { EuiFlexGroup, EuiIcon, EuiText } from '@elastic/eui'; -import type { EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; +import { EuiFlexGroup, EuiIcon } from '@elastic/eui'; +import type { ChromeNavLink, EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; import { i18n } from '@kbn/i18n'; -import { - ANALYTICS_PLUGIN, - APPLICATIONS_PLUGIN, - APP_SEARCH_PLUGIN, - ELASTICSEARCH_PLUGIN, - ENTERPRISE_SEARCH_CONTENT_PLUGIN, - ENTERPRISE_SEARCH_OVERVIEW_PLUGIN, - AI_SEARCH_PLUGIN, - VECTOR_SEARCH_PLUGIN, - WORKPLACE_SEARCH_PLUGIN, - SEARCH_RELEVANCE_PLUGIN, - SEMANTIC_SEARCH_PLUGIN, -} from '../../../../common/constants'; -import { - SEARCH_APPLICATIONS_PATH, - SearchApplicationViewTabs, - PLAYGROUND_PATH, -} from '../../applications/routes'; +import { ANALYTICS_PLUGIN, APPLICATIONS_PLUGIN } from '../../../../common/constants'; +import { SEARCH_APPLICATIONS_PATH, SearchApplicationViewTabs } from '../../applications/routes'; import { useIndicesNav } from '../../enterprise_search_content/components/search_index/indices/indices_nav'; -import { - CONNECTORS_PATH, - CRAWLERS_PATH, - SEARCH_INDICES_PATH, -} from '../../enterprise_search_content/routes'; -import { INFERENCE_ENDPOINTS_PATH } from '../../enterprise_search_relevance/routes'; import { KibanaLogic } from '../kibana'; -import { LicensingLogic } from '../licensing'; - +import { buildBaseClassicNavItems } from './base_nav'; +import { generateSideNavItems } from './classic_nav_helpers'; import { generateNavLink } from './nav_link_helpers'; /** @@ -52,219 +30,21 @@ import { generateNavLink } from './nav_link_helpers'; * @returns The Enterprise Search navigation items */ export const useEnterpriseSearchNav = (alwaysReturn = false) => { - const { isSidebarEnabled, productAccess } = useValues(KibanaLogic); - - const { hasEnterpriseLicense } = useValues(LicensingLogic); + const { isSidebarEnabled, productAccess, getNavLinks } = useValues(KibanaLogic); const indicesNavItems = useIndicesNav(); - if (!isSidebarEnabled && !alwaysReturn) return undefined; + const navItems: Array> = useMemo(() => { + const baseNavItems = buildBaseClassicNavItems({ productAccess }); + const deepLinks = getNavLinks().reduce((links, link) => { + links[link.id] = link; + return links; + }, {} as Record); - const navItems: Array> = [ - { - id: 'home', - name: ( - - {i18n.translate('xpack.enterpriseSearch.nav.homeTitle', { - defaultMessage: 'Home', - })} - - ), - ...generateNavLink({ - shouldNotCreateHref: true, - shouldShowActiveForSubroutes: true, - to: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, - }), - }, - { - id: 'content', - items: [ - { - id: 'search_indices', - name: i18n.translate('xpack.enterpriseSearch.nav.searchIndicesTitle', { - defaultMessage: 'Indices', - }), - ...generateNavLink({ - items: indicesNavItems, - shouldNotCreateHref: true, - shouldShowActiveForSubroutes: true, - to: ENTERPRISE_SEARCH_CONTENT_PLUGIN.URL + SEARCH_INDICES_PATH, - }), - }, - { - id: 'connectors', - name: i18n.translate('xpack.enterpriseSearch.nav.connectorsTitle', { - defaultMessage: 'Connectors', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - shouldShowActiveForSubroutes: true, - to: ENTERPRISE_SEARCH_CONTENT_PLUGIN.URL + CONNECTORS_PATH, - }), - }, - { - id: 'crawlers', - name: i18n.translate('xpack.enterpriseSearch.nav.crawlersTitle', { - defaultMessage: 'Web crawlers', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - shouldShowActiveForSubroutes: true, - to: ENTERPRISE_SEARCH_CONTENT_PLUGIN.URL + CRAWLERS_PATH, - }), - }, - ], - name: i18n.translate('xpack.enterpriseSearch.nav.contentTitle', { - defaultMessage: 'Content', - }), - }, - { - id: 'build', - items: [ - { - id: 'playground', - name: i18n.translate('xpack.enterpriseSearch.nav.PlaygroundTitle', { - defaultMessage: 'Playground', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - shouldShowActiveForSubroutes: true, - to: APPLICATIONS_PLUGIN.URL + PLAYGROUND_PATH, - }), - }, - { - id: 'searchApplications', - name: i18n.translate('xpack.enterpriseSearch.nav.searchApplicationsTitle', { - defaultMessage: 'Search Applications', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - to: APPLICATIONS_PLUGIN.URL + SEARCH_APPLICATIONS_PATH, - }), - }, - { - id: 'analyticsCollections', - name: i18n.translate('xpack.enterpriseSearch.nav.analyticsTitle', { - defaultMessage: 'Behavioral Analytics', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - to: ANALYTICS_PLUGIN.URL, - }), - }, - ], - name: i18n.translate('xpack.enterpriseSearch.nav.applicationsTitle', { - defaultMessage: 'Build', - }), - }, - ...(hasEnterpriseLicense - ? [ - { - id: 'relevance', - items: [ - { - id: 'inference_endpoints', - name: i18n.translate('xpack.enterpriseSearch.nav.inferenceEndpointsTitle', { - defaultMessage: 'Inference Endpoints', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - shouldShowActiveForSubroutes: true, - to: SEARCH_RELEVANCE_PLUGIN.URL + INFERENCE_ENDPOINTS_PATH, - }), - }, - ], - name: i18n.translate('xpack.enterpriseSearch.nav.relevanceTitle', { - defaultMessage: 'Relevance', - }), - }, - ] - : []), - { - id: 'es_getting_started', - items: [ - { - id: 'elasticsearch', - name: i18n.translate('xpack.enterpriseSearch.nav.elasticsearchTitle', { - defaultMessage: 'Elasticsearch', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - to: ELASTICSEARCH_PLUGIN.URL, - }), - }, - { - id: 'vectorSearch', - name: VECTOR_SEARCH_PLUGIN.NAME, - ...generateNavLink({ - shouldNotCreateHref: true, - to: VECTOR_SEARCH_PLUGIN.URL, - }), - }, - { - id: 'semanticSearch', - name: SEMANTIC_SEARCH_PLUGIN.NAME, - ...generateNavLink({ - shouldNotCreateHref: true, - to: SEMANTIC_SEARCH_PLUGIN.URL, - }), - }, - { - id: 'aiSearch', - name: i18n.translate('xpack.enterpriseSearch.nav.aiSearchTitle', { - defaultMessage: 'AI Search', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - to: AI_SEARCH_PLUGIN.URL, - }), - }, - ], - name: i18n.translate('xpack.enterpriseSearch.nav.enterpriseSearchOverviewTitle', { - defaultMessage: 'Getting started', - }), - }, - ...(productAccess.hasAppSearchAccess || productAccess.hasWorkplaceSearchAccess - ? [ - { - id: 'enterpriseSearch', - items: [ - ...(productAccess.hasAppSearchAccess - ? [ - { - id: 'app_search', - name: i18n.translate('xpack.enterpriseSearch.nav.appSearchTitle', { - defaultMessage: 'App Search', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - to: APP_SEARCH_PLUGIN.URL, - }), - }, - ] - : []), - ...(productAccess.hasWorkplaceSearchAccess - ? [ - { - id: 'workplace_search', - name: i18n.translate('xpack.enterpriseSearch.nav.workplaceSearchTitle', { - defaultMessage: 'Workplace Search', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - to: WORKPLACE_SEARCH_PLUGIN.URL, - }), - }, - ] - : []), - ], - name: i18n.translate('xpack.enterpriseSearch.nav.title', { - defaultMessage: 'Enterprise Search', - }), - }, - ] - : []), - ]; + return generateSideNavItems(baseNavItems, deepLinks, { search_indices: indicesNavItems }); + }, [productAccess, indicesNavItems]); + + if (!isSidebarEnabled && !alwaysReturn) return undefined; return navItems; }; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav_link_helpers.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav_link_helpers.test.ts index fff28345bb1bb..50c85a268e366 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav_link_helpers.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav_link_helpers.test.ts @@ -36,6 +36,7 @@ describe('generateNavLink', () => { navItem.onClick({ preventDefault: jest.fn() } as any); expect(mockKibanaValues.navigateToUrl).toHaveBeenCalledWith('/test', { shouldNotCreateHref: false, + shouldNotPrepend: false, }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav_link_helpers.ts b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav_link_helpers.ts index f086433c9fc0e..36000307adcc3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav_link_helpers.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav_link_helpers.ts @@ -5,27 +5,32 @@ * 2.0. */ -import { EuiSideNavItemType } from '@elastic/eui'; +import { EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; import { stripTrailingSlash } from '../../../../common/strip_slashes'; import { KibanaLogic } from '../kibana'; -import { generateReactRouterProps, ReactRouterProps } from '../react_router_helpers'; -import { GeneratedReactRouterProps } from '../react_router_helpers/generate_react_router_props'; +import { + type GeneratedReactRouterProps, + generateReactRouterProps, +} from '../react_router_helpers/generate_react_router_props'; +import { ReactRouterProps } from '../types'; interface Params { - items?: Array>; // Primarily passed if using `items` to determine isSelected - if not, you can just set `items` outside of this helper + items?: Array>; // Primarily passed if using `items` to determine isSelected - if not, you can just set `items` outside of this helper shouldShowActiveForSubroutes?: boolean; to: string; } type NavLinkProps = GeneratedReactRouterProps & - Pick, 'isSelected' | 'items'>; + Pick, 'isSelected' | 'items'>; + +export type GenerateNavLinkParameters = Params & ReactRouterProps; export const generateNavLink = ({ items, ...rest -}: Params & ReactRouterProps): NavLinkProps => { +}: GenerateNavLinkParameters): NavLinkProps => { const linkProps = { ...generateReactRouterProps({ ...rest }), isSelected: getNavLinkActive({ items, ...rest }), @@ -38,14 +43,15 @@ export const getNavLinkActive = ({ shouldShowActiveForSubroutes = false, items = [], shouldNotCreateHref = false, -}: Params & ReactRouterProps): boolean => { + shouldNotPrepend = false, +}: GenerateNavLinkParameters): boolean => { const { pathname } = KibanaLogic.values.history.location; const currentPath = stripTrailingSlash(pathname); const { href: currentPathHref } = generateReactRouterProps({ shouldNotCreateHref: false, to: currentPath, }); - const { href: toHref } = generateReactRouterProps({ shouldNotCreateHref, to }); + const { href: toHref } = generateReactRouterProps({ shouldNotCreateHref, shouldNotPrepend, to }); if (currentPathHref === toHref) return true; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.ts b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.ts index a399d632140b6..cf02c3ed74f71 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.ts @@ -30,12 +30,19 @@ interface CreateHrefDeps { } export interface CreateHrefOptions { shouldNotCreateHref?: boolean; + shouldNotPrepend?: boolean; } export const createHref = ( path: string, { history, http }: CreateHrefDeps, - { shouldNotCreateHref }: CreateHrefOptions = {} + { shouldNotCreateHref, shouldNotPrepend }: CreateHrefOptions = {} ): string => { - return shouldNotCreateHref ? http.basePath.prepend(path) : history.createHref({ pathname: path }); + if (shouldNotCreateHref) { + if (shouldNotPrepend) { + return path; + } + return http.basePath.prepend(path); + } + return history.createHref({ pathname: path }); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.tsx index 8271f49f9f39a..708cc597e582d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.tsx @@ -26,7 +26,9 @@ import { } from '@elastic/eui'; import { EuiPanelProps } from '@elastic/eui/src/components/panel/panel'; -import { generateReactRouterProps, ReactRouterProps } from '.'; +import { ReactRouterProps } from '../types'; + +import { generateReactRouterProps } from '.'; /** * Correctly typed component helpers with React-Router-friendly `href` and `onClick` props diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/generate_react_router_props.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/generate_react_router_props.test.ts index 309f94fcf55b4..de2a80ee5eaf4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/generate_react_router_props.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/generate_react_router_props.test.ts @@ -44,6 +44,7 @@ describe('generateReactRouterProps', () => { expect(mockEvent.preventDefault).toHaveBeenCalled(); expect(mockKibanaValues.navigateToUrl).toHaveBeenCalledWith('/test', { shouldNotCreateHref: false, + shouldNotPrepend: false, }); }); @@ -63,6 +64,7 @@ describe('generateReactRouterProps', () => { expect(mockEvent.preventDefault).toHaveBeenCalled(); expect(mockKibanaValues.navigateToUrl).toHaveBeenCalledWith('/app/enterprise_search/test', { shouldNotCreateHref: true, + shouldNotPrepend: false, }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/generate_react_router_props.ts b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/generate_react_router_props.ts index 2ef7f556eb2d1..89219362e5be4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/generate_react_router_props.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/generate_react_router_props.ts @@ -11,6 +11,7 @@ import { EuiSideNavItemType } from '@elastic/eui'; import { HttpLogic } from '../http'; import { KibanaLogic } from '../kibana'; +import { ReactRouterProps } from '../types'; import { letBrowserHandleEvent, createHref } from '.'; @@ -23,14 +24,6 @@ import { letBrowserHandleEvent, createHref } from '.'; * but separated out from EuiLink portion as we use this for multiple EUI components */ -export interface ReactRouterProps { - to: string; - onClick?(): void; - // Used to navigate outside of the React Router plugin basename but still within Kibana, - // e.g. if we need to go from Enterprise Search to App Search - shouldNotCreateHref?: boolean; -} - export type GeneratedReactRouterProps = Required< Pick, 'href' | 'onClick'> >; @@ -39,12 +32,13 @@ export const generateReactRouterProps = ({ to, onClick, shouldNotCreateHref = false, + shouldNotPrepend = false, }: ReactRouterProps): GeneratedReactRouterProps => { const { navigateToUrl, history } = KibanaLogic.values; const { http } = HttpLogic.values; // Generate the correct link href (with basename etc. accounted for) - const href = createHref(to, { history, http }, { shouldNotCreateHref }); + const href = createHref(to, { history, http }, { shouldNotCreateHref, shouldNotPrepend }); const reactRouterLinkClick = (event: React.MouseEvent) => { if (onClick) onClick(); // Run any passed click events (e.g. telemetry) @@ -54,7 +48,7 @@ export const generateReactRouterProps = ({ event.preventDefault(); // Perform SPA navigation. - navigateToUrl(to, { shouldNotCreateHref }); + navigateToUrl(to, { shouldNotCreateHref, shouldNotPrepend }); }; return { href, onClick: reactRouterLinkClick }; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/index.ts index ded9310fe361a..237e0d342ed1f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/index.ts @@ -8,7 +8,6 @@ export { letBrowserHandleEvent } from './link_events'; export type { CreateHrefOptions } from './create_href'; export { createHref } from './create_href'; -export type { ReactRouterProps } from './generate_react_router_props'; export { generateReactRouterProps } from './generate_react_router_props'; export { EuiLinkTo, diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts b/x-pack/plugins/enterprise_search/public/applications/shared/types.ts index 51a83cb15cca5..095f1dddfcc4a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/types.ts @@ -5,7 +5,12 @@ * 2.0. */ +import type { ReactNode } from 'react'; + +import type { AppDeepLinkId, EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; + import { APP_SEARCH_PLUGIN, WORKPLACE_SEARCH_PLUGIN } from '../../../common/constants'; +import type { ProductAccess } from '../../../common/types'; import { ADD, UPDATE } from './constants/operations'; @@ -57,3 +62,37 @@ export interface SingleUserRoleMapping { roleMapping: T; hasEnterpriseSearchRole?: boolean; } + +export interface ReactRouterProps { + to: string; + onClick?(): void; + // Used to navigate outside of the React Router plugin basename but still within Kibana, + // e.g. if we need to go from Enterprise Search to App Search + shouldNotCreateHref?: boolean; + // Used if to is already a fully qualified URL that doesn't need basePath prepended + shouldNotPrepend?: boolean; +} + +export type GenerateNavLinkParameters = { + items?: Array>; // Primarily passed if using `items` to determine isSelected - if not, you can just set `items` outside of this helper + shouldShowActiveForSubroutes?: boolean; + to: string; +} & ReactRouterProps; + +export interface GenerateNavLinkFromDeepLinkParameters { + link: AppDeepLinkId; + shouldShowActiveForSubroutes?: boolean; +} + +export interface BuildClassicNavParameters { + productAccess: ProductAccess; +} + +export interface ClassicNavItem { + 'data-test-subj'?: string; + deepLink?: GenerateNavLinkFromDeepLinkParameters; + iconToString?: string; + id: string; + items?: ClassicNavItem[]; + name?: ReactNode; +} diff --git a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx index d1729a50909ed..da30e6e93fadb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx @@ -58,6 +58,7 @@ export const mockKibanaProps: KibanaLogicProps = { elasticsearch_host: 'https://your_deployment_url', }, getChromeStyle$: jest.fn().mockReturnValue(of('classic')), + getNavLinks: jest.fn().mockReturnValue([]), guidedOnboarding: {}, history: mockHistory, indexMappingComponent: () => { diff --git a/x-pack/plugins/enterprise_search/tsconfig.json b/x-pack/plugins/enterprise_search/tsconfig.json index fa0751078c0f7..7b7556729a76c 100644 --- a/x-pack/plugins/enterprise_search/tsconfig.json +++ b/x-pack/plugins/enterprise_search/tsconfig.json @@ -82,6 +82,7 @@ "@kbn/navigation-plugin", "@kbn/security-plugin-types-common", "@kbn/core-security-server", - "@kbn/core-security-server-mocks" + "@kbn/core-security-server-mocks", + "@kbn/unsaved-changes-prompt" ] } diff --git a/x-pack/plugins/entity_manager/public/lib/entity_client.test.ts b/x-pack/plugins/entity_manager/public/lib/entity_client.test.ts new file mode 100644 index 0000000000000..dbaf1205cdf98 --- /dev/null +++ b/x-pack/plugins/entity_manager/public/lib/entity_client.test.ts @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EntityClient, EnitityInstance } from './entity_client'; +import { coreMock } from '@kbn/core/public/mocks'; + +const commonEntityFields: EnitityInstance = { + entity: { + last_seen_timestamp: '2023-10-09T00:00:00Z', + id: '1', + display_name: 'entity_name', + definition_id: 'entity_definition_id', + } as EnitityInstance['entity'], +}; + +describe('EntityClient', () => { + let entityClient: EntityClient; + + beforeEach(() => { + entityClient = new EntityClient(coreMock.createStart()); + }); + + describe('asKqlFilter', () => { + it('should return the kql filter', () => { + const entityLatest: EnitityInstance = { + entity: { + ...commonEntityFields.entity, + identity_fields: ['service.name', 'service.environment'], + type: 'service', + }, + service: { + name: 'my-service', + }, + }; + + const result = entityClient.asKqlFilter(entityLatest); + expect(result).toEqual('service.name: my-service'); + }); + + it('should return the kql filter when indentity_fields is composed by multiple fields', () => { + const entityLatest: EnitityInstance = { + entity: { + ...commonEntityFields.entity, + identity_fields: ['service.name', 'service.environment'], + type: 'service', + }, + service: { + name: 'my-service', + environment: 'staging', + }, + }; + + const result = entityClient.asKqlFilter(entityLatest); + expect(result).toEqual('(service.name: my-service AND service.environment: staging)'); + }); + + it('should ignore fields that are not present in the entity', () => { + const entityLatest: EnitityInstance = { + entity: { + ...commonEntityFields.entity, + identity_fields: ['host.name', 'foo.bar'], + }, + host: { + name: 'my-host', + }, + }; + + const result = entityClient.asKqlFilter(entityLatest); + expect(result).toEqual('host.name: my-host'); + }); + }); + + describe('getIdentityFieldsValue', () => { + it('should return identity fields values', () => { + const entityLatest: EnitityInstance = { + entity: { + ...commonEntityFields.entity, + identity_fields: ['service.name', 'service.environment'], + type: 'service', + }, + service: { + name: 'my-service', + }, + }; + + expect(entityClient.getIdentityFieldsValue(entityLatest)).toEqual({ + 'service.name': 'my-service', + }); + }); + + it('should return identity fields values when indentity_fields is composed by multiple fields', () => { + const entityLatest: EnitityInstance = { + entity: { + ...commonEntityFields.entity, + identity_fields: ['service.name', 'service.environment'], + type: 'service', + }, + service: { + name: 'my-service', + environment: 'staging', + }, + }; + + expect(entityClient.getIdentityFieldsValue(entityLatest)).toEqual({ + 'service.name': 'my-service', + 'service.environment': 'staging', + }); + }); + + it('should return identity fields when field is in the root', () => { + const entityLatest: EnitityInstance = { + entity: { + ...commonEntityFields.entity, + identity_fields: ['name'], + type: 'service', + }, + name: 'foo', + }; + + expect(entityClient.getIdentityFieldsValue(entityLatest)).toEqual({ + name: 'foo', + }); + }); + + it('should throw an error when identity fields are missing', () => { + const entityLatest: EnitityInstance = { + ...commonEntityFields, + }; + + expect(() => entityClient.getIdentityFieldsValue(entityLatest)).toThrow( + 'Identity fields are missing' + ); + }); + }); +}); diff --git a/x-pack/plugins/entity_manager/public/lib/entity_client.ts b/x-pack/plugins/entity_manager/public/lib/entity_client.ts index dc22a0b991b0d..08794873ba930 100644 --- a/x-pack/plugins/entity_manager/public/lib/entity_client.ts +++ b/x-pack/plugins/entity_manager/public/lib/entity_client.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { z } from '@kbn/zod'; import { CoreSetup, CoreStart } from '@kbn/core/public'; import { ClientRequestParamsOf, @@ -12,6 +13,9 @@ import { createRepositoryClient, isHttpFetchError, } from '@kbn/server-route-repository-client'; +import { type KueryNode, nodeTypes, toKqlExpression } from '@kbn/es-query'; +import { entityLatestSchema } from '@kbn/entities-schema'; +import { castArray } from 'lodash'; import { DisableManagedEntityResponse, EnableManagedEntityResponse, @@ -35,6 +39,8 @@ type CreateEntityDefinitionQuery = QueryParamOf< ClientRequestParamsOf >; +export type EnitityInstance = z.infer; + export class EntityClient { public readonly repositoryClient: EntityManagerRepositoryClient['fetch']; @@ -83,4 +89,38 @@ export class EntityClient { throw err; } } + + asKqlFilter(entityLatest: EnitityInstance) { + const identityFieldsValue = this.getIdentityFieldsValue(entityLatest); + + const nodes: KueryNode[] = Object.entries(identityFieldsValue).map(([identityField, value]) => { + return nodeTypes.function.buildNode('is', identityField, value); + }); + + if (nodes.length === 0) return ''; + + const kqlExpression = nodes.length > 1 ? nodeTypes.function.buildNode('and', nodes) : nodes[0]; + + return toKqlExpression(kqlExpression); + } + + getIdentityFieldsValue(entityLatest: EnitityInstance) { + const { identity_fields: identityFields } = entityLatest.entity; + + if (!identityFields) { + throw new Error('Identity fields are missing'); + } + + return castArray(identityFields).reduce((acc, field) => { + const value = field.split('.').reduce((obj: any, part: string) => { + return obj && typeof obj === 'object' ? (obj as Record)[part] : undefined; + }, entityLatest); + + if (value) { + acc[field] = value; + } + + return acc; + }, {} as Record); + } } diff --git a/x-pack/plugins/entity_manager/server/lib/entity_client.ts b/x-pack/plugins/entity_manager/server/lib/entity_client.ts index 67e9f52e32bf5..4e1dd263f9ca3 100644 --- a/x-pack/plugins/entity_manager/server/lib/entity_client.ts +++ b/x-pack/plugins/entity_manager/server/lib/entity_client.ts @@ -117,9 +117,7 @@ export class EntityClient { }); if (!definition) { - const message = `Unable to find entity definition [${id}]`; - this.options.logger.error(message); - throw new EntityDefinitionNotFound(message); + throw new EntityDefinitionNotFound(`Unable to find entity definition [${id}]`); } this.options.logger.info( diff --git a/x-pack/plugins/file_upload/public/components/__snapshots__/import_complete_view.test.tsx.snap b/x-pack/plugins/file_upload/public/components/__snapshots__/import_complete_view.test.tsx.snap index 8dd4858dfea5d..4108062e4fec4 100644 --- a/x-pack/plugins/file_upload/public/components/__snapshots__/import_complete_view.test.tsx.snap +++ b/x-pack/plugins/file_upload/public/components/__snapshots__/import_complete_view.test.tsx.snap @@ -348,7 +348,7 @@ exports[`Should render success 1`] = ` /> { ) { diff --git a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts index bb69346bbdce4..b990e5367bb42 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts @@ -21,15 +21,13 @@ import type { ListResult, ListWithKuery } from './common'; export interface GetAgentsRequest { query: ListWithKuery & { - showInactive: boolean; + showInactive?: boolean; showUpgradeable?: boolean; withMetrics?: boolean; }; } export interface GetAgentsResponse extends ListResult { - // deprecated in 8.x - list?: Agent[]; statusSummary?: Record; } @@ -128,16 +126,6 @@ export type PostBulkAgentUpgradeResponse = BulkAgentAction; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface PostAgentUpgradeResponse {} -// deprecated -export interface PutAgentReassignRequest { - params: { - agentId: string; - }; - body: { policy_id: string }; -} -// deprecated -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface PutAgentReassignResponse {} export interface PostAgentReassignRequest { params: { agentId: string; @@ -217,8 +205,6 @@ export interface GetAgentStatusRequest { export interface GetAgentStatusResponse { results: { events: number; - // deprecated - total: number; online: number; error: number; offline: number; diff --git a/x-pack/plugins/fleet/kibana.jsonc b/x-pack/plugins/fleet/kibana.jsonc index dec968457f294..823328da8ada6 100644 --- a/x-pack/plugins/fleet/kibana.jsonc +++ b/x-pack/plugins/fleet/kibana.jsonc @@ -29,7 +29,8 @@ "uiActions", "dashboard", "fieldsMetadata", - "logsDataAccess" + "logsDataAccess", + "spaces" ], "optionalPlugins": [ "features", @@ -40,7 +41,6 @@ "telemetry", "discover", "ingestPipelines", - "spaces", "guidedOnboarding", "integrationAssistant" ], diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/hooks/use_quick_start_form.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/hooks/use_quick_start_form.ts index e56ae45b1661a..559fcad522351 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/hooks/use_quick_start_form.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/hooks/use_quick_start_form.ts @@ -5,30 +5,35 @@ * 2.0. */ -import { useState, useCallback, useEffect } from 'react'; +import { useState, useCallback, useEffect, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; +import { getDefaultFleetServerpolicyId } from '../../../../../../common/services/agent_policies_helpers'; import type { useComboInput, useInput, useSwitchInput } from '../../../hooks'; -import { sendCreateAgentPolicy, sendGetOneAgentPolicy, useStartServices } from '../../../hooks'; - +import { + sendCreateAgentPolicy, + sendGetOneAgentPolicy, + useFleetStatus, + useStartServices, +} from '../../../hooks'; import type { NewAgentPolicy } from '../../../types'; - import type { FleetServerHost } from '../../../types'; - import { useServiceToken } from '../../../hooks/use_service_token'; import { useSelectFleetServerPolicy } from './use_select_fleet_server_policy'; import { useFleetServerHost } from './use_fleet_server_host'; -const QUICK_START_FLEET_SERVER_POLICY_FIELDS: NewAgentPolicy = { - id: 'fleet-server-policy', - name: 'Fleet Server Policy', - description: 'Fleet Server policy generated by Kibana', - namespace: 'default', - has_fleet_server: true, - monitoring_enabled: ['logs', 'metrics'], - is_default_fleet_server: true, -}; +function getQuickStartFleetServerPolicyFields(spaceId?: string): NewAgentPolicy { + return { + id: getDefaultFleetServerpolicyId(spaceId), + name: 'Fleet Server Policy', + description: 'Fleet Server policy generated by Kibana', + namespace: 'default', + has_fleet_server: true, + monitoring_enabled: ['logs', 'metrics'], + is_default_fleet_server: true, + }; +} export type QuickStartCreateFormStatus = 'initial' | 'loading' | 'error' | 'success'; @@ -69,6 +74,7 @@ export const useQuickStartCreateForm = (): QuickStartCreateForm => { setFleetServerHost, inputs, } = useFleetServerHost(); + const { spaceId } = useFleetStatus(); // When a validation error is surfaced from the Fleet Server host form, we want to treat it // the same way we do errors from the service token or policy creation steps @@ -81,6 +87,11 @@ export const useQuickStartCreateForm = (): QuickStartCreateForm => { const { fleetServerPolicyId, setFleetServerPolicyId } = useSelectFleetServerPolicy(); const { serviceToken, generateServiceToken } = useServiceToken(); + const quickStartFleetServerPolicyFields = useMemo( + () => getQuickStartFleetServerPolicyFields(spaceId), + [spaceId] + ); + const submit = useCallback(async () => { try { if (!fleetServerHost || fleetServerHost) { @@ -98,16 +109,14 @@ export const useQuickStartCreateForm = (): QuickStartCreateForm => { await generateServiceToken(); - const existingPolicy = await sendGetOneAgentPolicy( - QUICK_START_FLEET_SERVER_POLICY_FIELDS.id! - ); + const existingPolicy = await sendGetOneAgentPolicy(quickStartFleetServerPolicyFields.id!); // Don't attempt to create the policy if it's already been created in a previous quick start flow if (existingPolicy.data?.item) { setFleetServerPolicyId(existingPolicy.data?.item.id); } else { const createPolicyResponse = await sendCreateAgentPolicy( - QUICK_START_FLEET_SERVER_POLICY_FIELDS, + quickStartFleetServerPolicyFields, { withSysMonitoring: true, } @@ -134,6 +143,7 @@ export const useQuickStartCreateForm = (): QuickStartCreateForm => { generateServiceToken, setFleetServerPolicyId, notifications.toasts, + quickStartFleetServerPolicyFields, ]); return { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx index f4f519b0a9c95..88dd00546e51f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx @@ -137,13 +137,22 @@ export const AgentPolicyActionMenu = memo<{ const copyPolicyItem = ( { setIsContextMenuOpen(false); copyAgentPolicyPrompt(agentPolicy, onCopySuccess); }} key="copyPolicy" + toolTipContent={ + hasManagedPackagePolicy ? ( + + ) : undefined + } > = } > { }); }); -describe('useSetupTechnology', () => { +// FLAKY: https://github.com/elastic/kibana/issues/189038 +// FLAKY: https://github.com/elastic/kibana/issues/192126 +describe.skip('useSetupTechnology', () => { const setNewAgentPolicy = jest.fn(); const updateAgentPoliciesMock = jest.fn(); const setSelectedPolicyTabMock = jest.fn(); @@ -592,7 +594,7 @@ describe('useSetupTechnology', () => { }); it('should revert the agent policy name to the original value when switching from agentless back to agent-based', async () => { - const { result, waitForNextUpdate } = renderHook(() => + const { result, rerender } = renderHook(() => useSetupTechnology({ setNewAgentPolicy, newAgentPolicy: newAgentPolicyMock, @@ -601,8 +603,7 @@ describe('useSetupTechnology', () => { packagePolicy: packagePolicyMock, }) ); - - await waitForNextUpdate(); + await rerender(); expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); @@ -611,21 +612,17 @@ describe('useSetupTechnology', () => { }); expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS); - - waitFor(() => { - expect(setNewAgentPolicy).toHaveBeenCalledWith({ - name: 'Agentless policy for endpoint-1', - supports_agentless: true, - inactivity_timeout: 3600, - }); + expect(setNewAgentPolicy).toHaveBeenCalledWith({ + id: 'agentless-policy-id', }); act(() => { result.current.handleSetupTechnologyChange(SetupTechnology.AGENT_BASED); }); - - expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); - expect(setNewAgentPolicy).toHaveBeenCalledWith(newAgentPolicyMock); + await waitFor(() => { + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + expect(setNewAgentPolicy).toHaveBeenCalledWith(newAgentPolicyMock); + }); }); it('should have global_data_tags with the integration team when updating the agentless policy', async () => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index 24f8fa8a04fe5..93631f63d0e04 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -238,8 +238,8 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ let count = 0; for (const policyId of agentPolicyIds) { const { data } = await sendGetAgentStatus({ policyId }); - if (data?.results.total) { - count += data.results.total; + if (data?.results.active) { + count += data.results.active; } } setAgentCount(count); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx index 91cd710db4343..9de7a3f22adff 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx @@ -150,8 +150,8 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( if (isFleetEnabled) { setIsLoading(true); const { data } = await sendGetAgentStatus({ policyId: agentPolicy.id }); - if (data?.results.total) { - setAgentCount(data.results.total); + if (data?.results.active) { + setAgentCount(data.results.active); } else { await submitUpdateAgentPolicy(); } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index 6157f09968680..9522d02756887 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -166,8 +166,8 @@ export const EditPackagePolicyForm = memo<{ let count = 0; for (const id of packagePolicy.policy_ids) { const { data } = await sendGetAgentStatus({ policyId: id }); - if (data?.results.total) { - count += data.results.total; + if (data?.results.active) { + count += data.results.active; } } setAgentCount(count); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agents_selection_status.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agents_selection_status.tsx index 682aaa91af6b6..618a7a6b8e112 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agents_selection_status.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agents_selection_status.tsx @@ -7,7 +7,7 @@ import React from 'react'; import styled from 'styled-components'; -import { EuiFlexGroup, EuiFlexItem, EuiText, EuiButtonEmpty } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiText, EuiButtonEmpty, EuiIconTip } from '@elastic/eui'; import { FormattedMessage, FormattedNumber } from '@kbn/i18n-react'; import { SO_SEARCH_LIMIT } from '../../../../constants'; @@ -33,6 +33,7 @@ const Button = styled(EuiButtonEmpty)` export const AgentsSelectionStatus: React.FunctionComponent<{ totalAgents: number; + totalManagedAgents: number; selectableAgents: number; managedAgentsOnCurrentPage: number; selectionMode: SelectionMode; @@ -41,6 +42,7 @@ export const AgentsSelectionStatus: React.FunctionComponent<{ setSelectedAgents: (agents: Agent[]) => void; }> = ({ totalAgents, + totalManagedAgents, selectableAgents, managedAgentsOnCurrentPage, selectionMode, @@ -71,11 +73,28 @@ export const AgentsSelectionStatus: React.FunctionComponent<{ }} /> ) : ( - + <> + {' '} + + } + /> + )} @@ -96,7 +115,24 @@ export const AgentsSelectionStatus: React.FunctionComponent<{ selectionMode, count: selectedAgents.length, }} - /> + />{' '} + {selectionMode === 'query' && ( + + } + /> + )} {showSelectEverything ? ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx index e0235fab01446..c5fd1c2caec81 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx @@ -77,7 +77,7 @@ export const AgentBulkActions: React.FunctionComponent = ({ const [isRequestDiagnosticsModalOpen, setIsRequestDiagnosticsModalOpen] = useState(false); - // update the query removing the "managed" agents + // update the query removing the "managed" agents in any state (unenrolled, offline, etc) const selectionQuery = useMemo(() => { if (totalManagedAgentIds.length) { const excludedKuery = `${AGENTS_PREFIX}.agent.id : (${totalManagedAgentIds diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_header.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_header.tsx index bcac45801be05..48757ecebdd80 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_header.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_header.tsx @@ -21,6 +21,7 @@ export const AgentTableHeader: React.FunctionComponent<{ agentStatus?: { [k in SimplifiedAgentStatus]: number }; totalAgents: number; selectableAgents: number; + totalManagedAgents: number; managedAgentsOnCurrentPage: number; selectionMode: SelectionMode; setSelectionMode: (mode: SelectionMode) => void; @@ -31,6 +32,7 @@ export const AgentTableHeader: React.FunctionComponent<{ }> = ({ agentStatus, totalAgents, + totalManagedAgents, selectableAgents, managedAgentsOnCurrentPage, selectionMode, @@ -47,6 +49,7 @@ export const AgentTableHeader: React.FunctionComponent<{ `policy_id:"${policy.id}"`) - .join(' or '); + // Find all the agents that have managed policies + // to the correct ids we need to build the kuery applying the same filters as the global ones + const managedPoliciesKuery = getKuery({ + search, + selectedAgentPolicies: managedAgentPolicies.map((policy) => policy.id), + selectedTags, + selectedStatus, + }); const response = await sendGetAgents({ - kuery: `NOT (status:unenrolled) and ${policiesKuery}`, + kuery: `${managedPoliciesKuery}`, perPage: SO_SEARCH_LIMIT, - showInactive: true, + showInactive, }); if (response.error) { throw new Error(response.error.message); @@ -350,7 +354,6 @@ export function useFetchAgentsData() { fetchDataAsync(); }, [ - fullAgentPolicyFecher, pagination.currentPage, pagination.pageSize, kuery, @@ -359,8 +362,12 @@ export function useFetchAgentsData() { showInactive, showUpgradeable, displayAgentMetrics, + fullAgentPolicyFecher, allTags, latestAgentActionErrors, + search, + selectedTags, + selectedStatus, notifications.toasts, ] ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/index.tsx index 51f3fe68a9d95..a4171a8d5197a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/index.tsx @@ -434,6 +434,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { {/* Agent total, bulk actions and status bar */} { const basePath = '/mock'; diff --git a/x-pack/plugins/fleet/server/config.ts b/x-pack/plugins/fleet/server/config.ts index 746498221de55..ab5e06ef03716 100644 --- a/x-pack/plugins/fleet/server/config.ts +++ b/x-pack/plugins/fleet/server/config.ts @@ -201,64 +201,68 @@ export const config: PluginConfigDescriptor = { defaultValue: () => [], }), - internal: schema.maybe( - schema.object({ - disableILMPolicies: schema.boolean({ - defaultValue: false, - }), - fleetServerStandalone: schema.boolean({ - defaultValue: false, - }), - onlyAllowAgentUpgradeToKnownVersions: schema.boolean({ - defaultValue: false, - }), - activeAgentsSoftLimit: schema.maybe( - schema.number({ - min: 0, - }) - ), - retrySetupOnBoot: schema.boolean({ defaultValue: false }), - registry: schema.object( - { - kibanaVersionCheckEnabled: schema.boolean({ defaultValue: true }), - excludePackages: schema.arrayOf(schema.string(), { defaultValue: [] }), - spec: schema.object( - { - min: schema.maybe(schema.string()), - max: schema.string({ defaultValue: REGISTRY_SPEC_MAX_VERSION }), - }, - { - defaultValue: { - max: REGISTRY_SPEC_MAX_VERSION, - }, - } - ), - capabilities: schema.arrayOf( - schema.oneOf([ - // See package-spec for the list of available capiblities https://github.com/elastic/package-spec/blob/dcc37b652690f8a2bca9cf8a12fc28fd015730a0/spec/integration/manifest.spec.yml#L113 - schema.literal('apm'), - schema.literal('enterprise_search'), - schema.literal('observability'), - schema.literal('security'), - schema.literal('serverless_search'), - schema.literal('uptime'), - ]), - { defaultValue: [] } - ), - }, - { - defaultValue: { - kibanaVersionCheckEnabled: true, - capabilities: [], - excludePackages: [], - spec: { + internal: schema.object({ + disableILMPolicies: schema.boolean({ + defaultValue: false, + }), + fleetServerStandalone: schema.boolean({ + defaultValue: false, + }), + onlyAllowAgentUpgradeToKnownVersions: schema.boolean({ + defaultValue: false, + }), + activeAgentsSoftLimit: schema.maybe( + schema.number({ + min: 0, + }) + ), + retrySetupOnBoot: schema.boolean({ defaultValue: false }), + registry: schema.object( + { + // Must be set back to `true` before v9 release + // Requires all registry packages to add v9 as a compatible semver range + // https://github.com/elastic/kibana/issues/192624 + kibanaVersionCheckEnabled: schema.boolean({ defaultValue: false }), + excludePackages: schema.arrayOf(schema.string(), { defaultValue: [] }), + spec: schema.object( + { + min: schema.maybe(schema.string()), + max: schema.string({ defaultValue: REGISTRY_SPEC_MAX_VERSION }), + }, + { + defaultValue: { max: REGISTRY_SPEC_MAX_VERSION, }, + } + ), + capabilities: schema.arrayOf( + schema.oneOf([ + // See package-spec for the list of available capiblities https://github.com/elastic/package-spec/blob/dcc37b652690f8a2bca9cf8a12fc28fd015730a0/spec/integration/manifest.spec.yml#L113 + schema.literal('apm'), + schema.literal('enterprise_search'), + schema.literal('observability'), + schema.literal('security'), + schema.literal('serverless_search'), + schema.literal('uptime'), + ]), + { defaultValue: [] } + ), + }, + { + defaultValue: { + // Must be set back to `true` before v9 release + // Requires all registry packages to add v9 as a compatible semver range + // https://github.com/elastic/kibana/issues/192624 + kibanaVersionCheckEnabled: false, + capabilities: [], + excludePackages: [], + spec: { + max: REGISTRY_SPEC_MAX_VERSION, }, - } - ), - }) - ), + }, + } + ), + }), enabled: schema.boolean({ defaultValue: true }), /** * The max size of the artifacts encoded_size sum in a batch when more than one (there is at least one artifact in a batch). diff --git a/x-pack/plugins/fleet/server/mocks/index.ts b/x-pack/plugins/fleet/server/mocks/index.ts index 43b113899072e..f032c1f7bb8c7 100644 --- a/x-pack/plugins/fleet/server/mocks/index.ts +++ b/x-pack/plugins/fleet/server/mocks/index.ts @@ -113,6 +113,7 @@ export const createAppContextStartContractMock = ( experimentalFeatures: { agentTamperProtectionEnabled: true, diagnosticFileUploadEnabled: true, + enableReusableIntegrationPolicies: true, } as ExperimentalFeatures, isProductionMode: true, configInitialValue: { @@ -186,7 +187,7 @@ export const createPackagePolicyServiceMock = (): jest.Mocked => { return { - get: jest.fn(), - list: jest.fn(), - getFullAgentPolicy: jest.fn(), - getByIds: jest.fn(), - turnOffAgentTamperProtections: jest.fn(), - fetchAllAgentPolicies: jest.fn(), - fetchAllAgentPolicyIds: jest.fn(), + get: jest.fn().mockReturnValue(Promise.resolve()), + list: jest.fn().mockReturnValue(Promise.resolve()), + getFullAgentPolicy: jest.fn().mockReturnValue(Promise.resolve()), + getByIds: jest.fn().mockReturnValue(Promise.resolve()), + turnOffAgentTamperProtections: jest.fn().mockReturnValue(Promise.resolve()), + fetchAllAgentPolicies: jest.fn().mockReturnValue(Promise.resolve()), + fetchAllAgentPolicyIds: jest.fn().mockReturnValue(Promise.resolve()), }; }; diff --git a/x-pack/plugins/fleet/server/routes/agent/handlers.ts b/x-pack/plugins/fleet/server/routes/agent/handlers.ts index 4f4b5592f2d04..76d0fefe90fde 100644 --- a/x-pack/plugins/fleet/server/routes/agent/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/handlers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { uniq } from 'lodash'; +import { omit, uniq } from 'lodash'; import { type RequestHandler, SavedObjectsErrorHelpers } from '@kbn/core/server'; import type { TypeOf } from '@kbn/config-schema'; @@ -13,7 +13,6 @@ import type { GetAgentsResponse, GetOneAgentResponse, GetAgentStatusResponse, - PutAgentReassignResponse, GetAgentTagsResponse, GetAvailableVersionsResponse, GetActionStatusResponse, @@ -30,7 +29,6 @@ import type { DeleteAgentRequestSchema, GetAgentStatusRequestSchema, GetAgentDataRequestSchema, - PutAgentReassignRequestSchemaDeprecated, PostAgentReassignRequestSchema, PostBulkAgentReassignRequestSchema, PostBulkUpdateAgentTagsRequestSchema, @@ -207,7 +205,6 @@ export const getAgentsHandler: FleetRequestHandler< } const body: GetAgentsResponse = { - list: agents, // deprecated items: agents, total, page, @@ -243,29 +240,6 @@ export const getAgentTagsHandler: RequestHandler< } }; -export const putAgentsReassignHandlerDeprecated: RequestHandler< - TypeOf, - undefined, - TypeOf -> = async (context, request, response) => { - const coreContext = await context.core; - const soClient = coreContext.savedObjects.client; - const esClient = coreContext.elasticsearch.client.asInternalUser; - try { - await AgentService.reassignAgent( - soClient, - esClient, - request.params.agentId, - request.body.policy_id - ); - - const body: PutAgentReassignResponse = {}; - return response.ok({ body }); - } catch (error) { - return defaultFleetErrorHandler({ error, response }); - } -}; - export const postAgentReassignHandler: RequestHandler< TypeOf, undefined, @@ -341,7 +315,7 @@ export const getAgentStatusForAgentPolicyHandler: FleetRequestHandler< parsePolicyIds(request.query.policyIds) ); - const body: GetAgentStatusResponse = { results }; + const body: GetAgentStatusResponse = { results: omit(results, 'total') }; return response.ok({ body }); } catch (error) { diff --git a/x-pack/plugins/fleet/server/routes/agent/index.test.ts b/x-pack/plugins/fleet/server/routes/agent/index.test.ts index 7f210028ff742..34f66da425da3 100644 --- a/x-pack/plugins/fleet/server/routes/agent/index.test.ts +++ b/x-pack/plugins/fleet/server/routes/agent/index.test.ts @@ -222,7 +222,6 @@ describe('schema validation', () => { it('list agents should return valid response', async () => { const expectedResponse: GetAgentsResponse = { items: [agent], - list: [agent], total: 1, page: 1, perPage: 1, @@ -366,7 +365,6 @@ describe('schema validation', () => { const expectedResponse: GetAgentStatusResponse = { results: { events: 1, - total: 1, online: 1, error: 1, offline: 1, diff --git a/x-pack/plugins/fleet/server/routes/agent/index.ts b/x-pack/plugins/fleet/server/routes/agent/index.ts index fc45869dc1219..1c40f36a7e481 100644 --- a/x-pack/plugins/fleet/server/routes/agent/index.ts +++ b/x-pack/plugins/fleet/server/routes/agent/index.ts @@ -23,7 +23,6 @@ import { GetAgentStatusRequestSchema, GetAgentDataRequestSchema, PostNewAgentActionRequestSchema, - PutAgentReassignRequestSchemaDeprecated, PostAgentReassignRequestSchema, PostBulkAgentReassignRequestSchema, PostAgentUpgradeRequestSchema, @@ -68,7 +67,6 @@ import { updateAgentHandler, deleteAgentHandler, getAgentStatusForAgentPolicyHandler, - putAgentsReassignHandlerDeprecated, postBulkAgentReassignHandler, getAgentDataHandler, bulkUpdateAgentTagsHandler, @@ -391,23 +389,6 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT postAgentUnenrollHandler ); - router.versioned - .put({ - path: AGENT_API_ROUTES.REASSIGN_PATTERN, - fleetAuthz: { - fleet: { allAgents: true }, - }, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - }) - .addVersion( - { - version: API_VERSIONS.public.v1, - validate: { request: PutAgentReassignRequestSchemaDeprecated }, - }, - putAgentsReassignHandlerDeprecated - ); - router.versioned .post({ path: AGENT_API_ROUTES.REASSIGN_PATTERN, @@ -613,22 +594,6 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT }, getAgentStatusForAgentPolicyHandler ); - router.versioned - .get({ - path: AGENT_API_ROUTES.STATUS_PATTERN_DEPRECATED, - fleetAuthz: { - fleet: { readAgents: true }, - }, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - }) - .addVersion( - { - version: API_VERSIONS.public.v1, - validate: { request: GetAgentStatusRequestSchema }, - }, - getAgentStatusForAgentPolicyHandler - ); // Agent data router.versioned .get({ diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts index 49b5590a2e761..713c054d8105e 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts @@ -343,6 +343,7 @@ export const createAgentPolicyHandler: FleetRequestHandler< currentSpaceId: spaceId, newSpaceIds: spaceIds, authorizedSpaces, + options: { force }, }); } @@ -385,6 +386,7 @@ export const updateAgentPolicyHandler: FleetRequestHandler< currentSpaceId: spaceId, newSpaceIds: spaceIds, authorizedSpaces, + options: { force }, }); spaceId = spaceIds[0]; diff --git a/x-pack/plugins/fleet/server/routes/app/index.ts b/x-pack/plugins/fleet/server/routes/app/index.ts index c0b7dbcfa1743..e66f9f02a687b 100644 --- a/x-pack/plugins/fleet/server/routes/app/index.ts +++ b/x-pack/plugins/fleet/server/routes/app/index.ts @@ -285,22 +285,4 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType }, generateServiceTokenHandler ); - - router.versioned - .post({ - path: APP_API_ROUTES.GENERATE_SERVICE_TOKEN_PATTERN_DEPRECATED, - fleetAuthz: { - fleet: { allAgents: true }, - }, - description: `Create a service token`, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, - }) - .addVersion( - { - version: API_VERSIONS.public.v1, - validate: {}, - }, - generateServiceTokenHandler - ); }; diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index 00bc01aa1f2cb..fb3274b6eef77 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -1285,6 +1285,68 @@ describe('Agent policy', () => { }) ).resolves.not.toThrow(); }); + + it('should run external "agentPolicyPostUpdate" callbacks when update is successful', async () => { + const soClient = getAgentPolicyCreateMock(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + + const postUpdateCallback = jest.fn(async (policy) => policy); + mockedAppContextService.getExternalCallbacks.mockImplementation((type) => { + if (type === 'agentPolicyPostUpdate') { + return new Set([postUpdateCallback]); + } + }); + + soClient.get.mockResolvedValue({ + attributes: {}, + id: 'test-id', + type: 'mocked', + references: [], + }); + + await expect( + agentPolicyService.update(soClient, esClient, 'test-id', { + name: 'test', + namespace: 'default', + }) + ).resolves.not.toThrow(); + + expect(mockedAppContextService.getExternalCallbacks).toHaveBeenCalledWith( + 'agentPolicyPostUpdate' + ); + + expect(postUpdateCallback).toHaveBeenCalled(); + }); + }); + + describe('copy', () => { + let soClient: ReturnType; + let esClient: ReturnType['asInternalUser']; + + beforeEach(() => { + soClient = getSavedObjectMock({ revision: 1, package_policies: ['package-1'] }); + esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + }); + + it('should throw error for agent policy which has managed package policy', async () => { + mockedPackagePolicyService.findAllForAgentPolicy.mockReturnValue([ + { + id: 'package-1', + is_managed: true, + }, + ] as any); + try { + await agentPolicyService.copy(soClient, esClient, 'mocked', { + name: 'copy mocked', + }); + } catch (e) { + expect(e.message).toEqual( + new PackagePolicyRestrictionRelatedError( + `Cannot copy an agent policy mocked that contains managed package policies` + ).message + ); + } + }); }); describe('deployPolicy', () => { diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 0209ee6edb630..f93bf583945a0 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -62,6 +62,7 @@ import type { PostAgentPolicyUpdateCallback, PreconfiguredAgentPolicy, OutputsForAgentPolicy, + PostAgentPolicyPostUpdateCallback, } from '../types'; import { AGENT_POLICY_INDEX, @@ -309,8 +310,8 @@ class AgentPolicyService { public async runExternalCallbacks( externalCallbackType: ExternalCallback[0], - agentPolicy: NewAgentPolicy | Partial - ): Promise> { + agentPolicy: NewAgentPolicy | Partial | AgentPolicy + ): Promise | AgentPolicy> { const logger = appContextService.getLogger(); logger.debug(`Running external callbacks for ${externalCallbackType}`); try { @@ -333,6 +334,12 @@ class AgentPolicyService { ); updatedNewAgentPolicy = result; } + if (externalCallbackType === 'agentPolicyPostUpdate') { + result = await (callback as PostAgentPolicyPostUpdateCallback)( + newAgentPolicy as AgentPolicy + ); + updatedNewAgentPolicy = result; + } } newAgentPolicy = updatedNewAgentPolicy; } @@ -741,6 +748,11 @@ class AgentPolicyService { bumpRevision: true, removeProtection: false, skipValidation: options?.skipValidation ?? false, + }).then((updatedAgentPolicy) => { + return this.runExternalCallbacks( + 'agentPolicyPostUpdate', + updatedAgentPolicy + ) as unknown as AgentPolicy; }); } @@ -759,6 +771,17 @@ class AgentPolicyService { if (!baseAgentPolicy) { throw new AgentPolicyNotFoundError('Agent policy not found'); } + if (baseAgentPolicy.package_policies?.length) { + const hasManagedPackagePolicies = baseAgentPolicy.package_policies.some( + (packagePolicy) => packagePolicy.is_managed + ); + if (hasManagedPackagePolicies) { + throw new PackagePolicyRestrictionRelatedError( + `Cannot copy an agent policy ${id} that contains managed package policies` + ); + } + } + const newAgentPolicy = await this.create( soClient, esClient, diff --git a/x-pack/plugins/fleet/server/services/agent_policy_create.ts b/x-pack/plugins/fleet/server/services/agent_policy_create.ts index f370867fc493b..3902548581595 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_create.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_create.ts @@ -11,6 +11,7 @@ import type { SavedObjectsClientContract, } from '@kbn/core/server'; +import { getDefaultFleetServerpolicyId } from '../../common/services/agent_policies_helpers'; import type { HTTPAuthorizationHeader } from '../../common/http_authorization_header'; import { @@ -27,23 +28,25 @@ import { bulkInstallPackages } from './epm/packages'; import { ensureDefaultEnrollmentAPIKeyForAgentPolicy } from './api_keys'; import { agentlessAgentService } from './agents/agentless_agent'; -const FLEET_SERVER_POLICY_ID = 'fleet-server-policy'; - async function getFleetServerAgentPolicyId( soClient: SavedObjectsClientContract ): Promise { let agentPolicyId; - // creating first fleet server policy with id 'fleet-server-policy' + // creating first fleet server policy with id '(space-)?fleet-server-policy' let agentPolicy; try { - agentPolicy = await agentPolicyService.get(soClient, FLEET_SERVER_POLICY_ID, false); + agentPolicy = await agentPolicyService.get( + soClient, + getDefaultFleetServerpolicyId(soClient.getCurrentNamespace()), + false + ); } catch (err) { if (!err.isBoom || err.output.statusCode !== 404) { throw err; } } if (!agentPolicy) { - agentPolicyId = FLEET_SERVER_POLICY_ID; + agentPolicyId = getDefaultFleetServerpolicyId(soClient.getCurrentNamespace()); } return agentPolicyId; } @@ -118,7 +121,7 @@ export async function createAgentPolicyWithPackages({ packagesToInstall.push(FLEET_SERVER_PACKAGE); agentPolicyId = agentPolicyId || (await getFleetServerAgentPolicyId(soClient)); - if (agentPolicyId === FLEET_SERVER_POLICY_ID) { + if (agentPolicyId === getDefaultFleetServerpolicyId(spaceId)) { // setting first fleet server policy to default, so that fleet server can enroll without setting policy_id newPolicy.is_default_fleet_server = true; } diff --git a/x-pack/plugins/fleet/server/services/package_policy.test.ts b/x-pack/plugins/fleet/server/services/package_policy.test.ts index 8c322d997a612..7ea6ae290708b 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -76,9 +76,12 @@ import { sendTelemetryEvents } from './upgrade_sender'; import { auditLoggingService } from './audit_logging'; import { agentPolicyService } from './agent_policy'; import { isSpaceAwarenessEnabled } from './spaces/helpers'; +import { licenseService } from './license'; jest.mock('./spaces/helpers'); +jest.mock('./license'); + const mockedSendTelemetryEvents = sendTelemetryEvents as jest.MockedFunction< typeof sendTelemetryEvents >; @@ -207,7 +210,7 @@ const mockedAuditLoggingService = auditLoggingService as jest.Mocked { +const mockAgentPolicyGet = (spaceIds: string[] = ['default']) => { mockAgentPolicyService.get.mockImplementation( (_soClient: SavedObjectsClientContract, id: string, _force = false, _errorMessage?: string) => { return Promise.resolve({ @@ -220,9 +223,29 @@ const mockAgentPolicyGet = () => { updated_by: 'test', revision: 1, is_protected: false, + space_ids: spaceIds, }); } ); + mockAgentPolicyService.getByIDs.mockImplementation( + // @ts-ignore + (_soClient: SavedObjectsClientContract, ids: string[]) => { + return Promise.resolve( + ids.map((id) => ({ + id, + name: 'Test Agent Policy', + namespace: 'test', + status: 'active', + is_managed: false, + updated_at: new Date().toISOString(), + updated_by: 'test', + revision: 1, + is_protected: false, + space_ids: spaceIds, + })) + ); + } + ); }; describe('Package policy service', () => { @@ -240,6 +263,9 @@ describe('Package policy service', () => { }); describe('create', () => { + beforeEach(() => { + jest.mocked(licenseService.hasAtLeast).mockReturnValue(true); + }); it('should call audit logger', async () => { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; const soClient = savedObjectsClientMock.create(); @@ -279,6 +305,46 @@ describe('Package policy service', () => { savedObjectType: LEGACY_PACKAGE_POLICY_SAVED_OBJECT_TYPE, }); }); + + it('should not allow to add a reusable integration policies to an agent policies belonging to multiple spaces', async () => { + jest.mocked(isSpaceAwarenessEnabled).mockResolvedValue(true); + + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + const soClient = savedObjectsClientMock.create(); + + soClient.create.mockResolvedValueOnce({ + id: 'test-package-policy', + attributes: {}, + references: [], + type: PACKAGE_POLICY_SAVED_OBJECT_TYPE, + }); + + mockAgentPolicyGet(['test', 'default']); + + await expect( + packagePolicyService.create( + soClient, + esClient, + { + name: 'Test Package Policy', + namespace: 'test', + enabled: true, + policy_id: 'test', + policy_ids: ['test1', 'test2'], + inputs: [], + package: { + name: 'test', + title: 'Test', + version: '0.0.1', + }, + }, + // Skipping unique name verification just means we have to less mocking/setup + { id: 'test-package-policy', skipUniqueNameVerification: true } + ) + ).rejects.toThrowError( + /Reusable integration policies cannot be used with agent policies belonging to multiple spaces./ + ); + }); }); describe('inspect', () => { @@ -1718,6 +1784,41 @@ describe('Package policy service', () => { }); }); + it('should run "packagePolicyPostUpdate" external callbacks', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + const mockPackagePolicy = createPackagePolicyMock(); + const attributes = { + ...mockPackagePolicy, + inputs: [], + }; + + jest.spyOn(appContextService, 'getExternalCallbacks'); + + soClient.get.mockResolvedValue({ + id: 'test-package-policy', + type: LEGACY_PACKAGE_POLICY_SAVED_OBJECT_TYPE, + references: [], + attributes, + }); + + soClient.update.mockResolvedValue({ + id: 'test-package-policy', + type: LEGACY_PACKAGE_POLICY_SAVED_OBJECT_TYPE, + references: [], + attributes, + }); + + await packagePolicyService.update(soClient, esClient, 'test-package-policy', { + ...mockPackagePolicy, + inputs: [], + }); + + expect(appContextService.getExternalCallbacks).toHaveBeenCalledWith( + 'packagePolicyPostUpdate' + ); + }); + describe('remove protections', () => { beforeEach(() => { mockAgentPolicyService.bumpRevision.mockReset(); diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 2d360dba63767..bc5bce9eea2a3 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -7,6 +7,7 @@ /* eslint-disable max-classes-per-file */ import { omit, partition, isEqual, cloneDeep, without } from 'lodash'; +import { indexBy } from 'lodash/fp'; import { i18n } from '@kbn/i18n'; import semverLt from 'semver/functions/lt'; import { getFlattenedObject } from '@kbn/std'; @@ -94,6 +95,7 @@ import type { DryRunPackagePolicy, PostPackagePolicyCreateCallback, PostPackagePolicyPostCreateCallback, + PutPackagePolicyPostUpdateCallback, } from '../types'; import type { ExternalCallback } from '..'; @@ -127,6 +129,8 @@ import type { PackagePolicyClient, PackagePolicyClientFetchAllItemsOptions, PackagePolicyService, + RunExternalCallbacksPackagePolicyArgument, + RunExternalCallbacksPackagePolicyResponse, } from './package_policy_service'; import { installAssetsForInputPackagePolicy } from './epm/packages/install'; import { auditLoggingService } from './audit_logging'; @@ -141,6 +145,7 @@ import { validateAgentPolicyOutputForIntegration } from './agent_policies/output import type { PackagePolicyClientFetchAllItemIdsOptions } from './package_policy_service'; import { validatePolicyNamespaceForSpace } from './spaces/policy_namespaces'; import { isSpaceAwarenessEnabled, isSpaceAwarenessMigrationPending } from './spaces/helpers'; +import { updatePackagePolicySpaces } from './spaces/package_policy'; export type InputsOverride = Partial & { vars?: Array; @@ -224,6 +229,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { context?: RequestHandlerContext, request?: KibanaRequest ): Promise { + const useSpaceAwareness = await isSpaceAwarenessEnabled(); const packagePolicyId = options?.id || uuidv4(); let authorizationHeader = options.authorizationHeader; @@ -271,6 +277,10 @@ class PackagePolicyClientImpl implements PackagePolicyClient { for (const policyId of enrichedPackagePolicy.policy_ids) { const agentPolicy = await agentPolicyService.get(soClient, policyId, true); + if (!agentPolicy) { + throw new AgentPolicyNotFoundError('Agent policy not found'); + } + agentPolicies.push(agentPolicy); // If package policy did not set an output_id, see if the agent policy's output is compatible @@ -282,7 +292,10 @@ class PackagePolicyClientImpl implements PackagePolicyClient { ); } - await validateIsNotHostedPolicy(soClient, policyId, options?.force); + validateIsNotHostedPolicy(agentPolicy, options?.force); + if (useSpaceAwareness) { + validateReusableIntegrationsAndSpaceAwareness(enrichedPackagePolicy, agentPolicies); + } } // trailing whitespace causes issues creating API keys @@ -410,6 +423,21 @@ class PackagePolicyClientImpl implements PackagePolicyClient { { ...options, id: packagePolicyId } ); + for (const agentPolicy of agentPolicies) { + if ( + useSpaceAwareness && + agentPolicy && + agentPolicy.space_ids && + agentPolicy.space_ids.length > 1 + ) { + await updatePackagePolicySpaces({ + packagePolicyId: newSo.id, + currentSpaceId: soClient.getCurrentNamespace() ?? DEFAULT_SPACE_ID, + newSpaceIds: agentPolicy.space_ids, + }); + } + } + if (options?.bumpRevision ?? true) { for (const policyId of enrichedPackagePolicy.policy_ids) { await agentPolicyService.bumpRevision(soClient, esClient, policyId, { @@ -457,6 +485,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { created: PackagePolicy[]; failed: Array<{ packagePolicy: NewPackagePolicy; error?: Error | SavedObjectError }>; }> { + const useSpaceAwareness = await isSpaceAwarenessEnabled(); const savedObjectType = await getPackagePolicySavedObjectType(); for (const packagePolicy of packagePolicies) { const basePkgInfo = packagePolicy.package @@ -483,8 +512,20 @@ class PackagePolicyClientImpl implements PackagePolicyClient { const agentPolicyIds = new Set(packagePolicies.flatMap((pkgPolicy) => pkgPolicy.policy_ids)); - for (const agentPolicyId of agentPolicyIds) { - await validateIsNotHostedPolicy(soClient, agentPolicyId, options?.force); + const agentPolicies = await agentPolicyService.getByIDs(soClient, [...agentPolicyIds]); + const agentPoliciesIndexById = indexBy('id', agentPolicies); + for (const agentPolicy of agentPolicies) { + validateIsNotHostedPolicy(agentPolicy, options?.force); + } + if (useSpaceAwareness) { + for (const packagePolicy of packagePolicies) { + validateReusableIntegrationsAndSpaceAwareness( + packagePolicy, + packagePolicy.policy_ids + .map((policyId) => agentPoliciesIndexById[policyId]) + .filter((policy) => policy !== undefined) + ); + } } const packageInfos = await getPackageInfoForPackagePolicies(packagePolicies, soClient); @@ -601,6 +642,23 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } }); + if (useSpaceAwareness) { + for (const newSo of newSos) { + // Do not support multpile spaces for reusable integrations + if (newSo.attributes.policy_ids.length > 1) { + continue; + } + const agentPolicy = agentPoliciesIndexById[newSo.attributes.policy_ids[0]]; + if (agentPolicy && agentPolicy.space_ids && agentPolicy.space_ids.length > 1) { + await updatePackagePolicySpaces({ + packagePolicyId: newSo.id, + currentSpaceId: soClient.getCurrentNamespace() ?? DEFAULT_SPACE_ID, + newSpaceIds: agentPolicy.space_ids, + }); + } + } + } + // Assign it to the given agent policy if (options?.bumpRevision ?? true) { @@ -998,6 +1056,17 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } } + if ((packagePolicyUpdate.policy_ids?.length ?? 0) > 1) { + for (const policyId of packagePolicyUpdate.policy_ids) { + const agentPolicy = await agentPolicyService.get(soClient, policyId, true); + if ((agentPolicy?.space_ids?.length ?? 0) > 1) { + throw new FleetError( + 'Reusable integration policies cannot be used with agent policies belonging to multiple spaces.' + ); + } + } + } + // Handle component template/mappings updates for experimental features, e.g. synthetic source await handleExperimentalDatastreamFeatureOptIn({ soClient, @@ -1091,9 +1160,16 @@ class PackagePolicyClientImpl implements PackagePolicyClient { await Promise.all([...bumpPromises, assetRemovePromise, deleteSecretsPromise]); sendUpdatePackagePolicyTelemetryEvent(soClient, [packagePolicyUpdate], [oldPackagePolicy]); + logger.debug(`Package policy ${id} update completed`); - return newPolicy; + // Run external post-update callbacks and return + return packagePolicyService.runExternalCallbacks( + 'packagePolicyPostUpdate', + newPolicy, + soClient, + esClient + ); } public async bulkUpdate( @@ -1381,9 +1457,13 @@ class PackagePolicyClientImpl implements PackagePolicyClient { for (const agentPolicyId of uniqueAgentPolicyIds) { try { - const agentPolicy = await validateIsNotHostedPolicy( - soClient, - agentPolicyId, + const agentPolicy = await agentPolicyService.get(soClient, agentPolicyId); + if (!agentPolicy) { + throw new AgentPolicyNotFoundError('Agent policy not found'); + } + + validateIsNotHostedPolicy( + agentPolicy, options?.force, 'Cannot remove integrations of hosted agent policy' ); @@ -1930,48 +2010,21 @@ class PackagePolicyClientImpl implements PackagePolicyClient { public async runExternalCallbacks( externalCallbackType: A, - packagePolicy: A extends 'packagePolicyDelete' - ? DeletePackagePoliciesResponse - : A extends 'packagePolicyPostDelete' - ? PostDeletePackagePoliciesResponse - : A extends 'packagePolicyPostCreate' - ? PackagePolicy - : A extends 'packagePolicyCreate' - ? NewPackagePolicy - : never, - soClient: SavedObjectsClientContract, - esClient: ElasticsearchClient, - context?: RequestHandlerContext, - request?: KibanaRequest - ): Promise< - A extends 'packagePolicyDelete' - ? void - : A extends 'packagePolicyPostDelete' - ? void - : A extends 'packagePolicyPostCreate' - ? PackagePolicy - : A extends 'packagePolicyCreate' - ? NewPackagePolicy - : never - >; - public async runExternalCallbacks( - externalCallbackType: ExternalCallback[0], - packagePolicy: - | PackagePolicy - | NewPackagePolicy - | PostDeletePackagePoliciesResponse - | DeletePackagePoliciesResponse, + packagePolicy: RunExternalCallbacksPackagePolicyArgument, soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, context?: RequestHandlerContext, request?: KibanaRequest - ): Promise { + ): Promise> { const logger = appContextService.getLogger(); const numberOfCallbacks = appContextService.getExternalCallbacks(externalCallbackType)?.size; + let runResult: any; + logger.debug(`Running ${numberOfCallbacks} external callbacks for ${externalCallbackType}`); + try { if (externalCallbackType === 'packagePolicyPostDelete') { - return await this.runPostDeleteExternalCallbacks( + runResult = await this.runPostDeleteExternalCallbacks( packagePolicy as PostDeletePackagePoliciesResponse, soClient, esClient, @@ -1979,7 +2032,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { request ); } else if (externalCallbackType === 'packagePolicyDelete') { - return await this.runDeleteExternalCallbacks( + runResult = await this.runDeleteExternalCallbacks( packagePolicy as DeletePackagePoliciesResponse, soClient, esClient @@ -1988,21 +2041,33 @@ class PackagePolicyClientImpl implements PackagePolicyClient { if (!Array.isArray(packagePolicy)) { let newData = packagePolicy; const externalCallbacks = appContextService.getExternalCallbacks(externalCallbackType); + if (externalCallbacks && externalCallbacks.size > 0) { - let updatedNewData = newData; + let updatedNewData: any = newData; + for (const callback of externalCallbacks) { - let result; + let thisCallbackResponse; + if (externalCallbackType === 'packagePolicyPostCreate') { - result = await (callback as PostPackagePolicyPostCreateCallback)( + thisCallbackResponse = await (callback as PostPackagePolicyPostCreateCallback)( updatedNewData as PackagePolicy, soClient, esClient, context, request ); - updatedNewData = PackagePolicySchema.validate(result) as NewPackagePolicy; + updatedNewData = PackagePolicySchema.validate(thisCallbackResponse); + } else if (externalCallbackType === 'packagePolicyPostUpdate') { + thisCallbackResponse = await (callback as PutPackagePolicyPostUpdateCallback)( + updatedNewData as PackagePolicy, + soClient, + esClient, + context, + request + ); + updatedNewData = PackagePolicySchema.validate(thisCallbackResponse); } else { - result = await (callback as PostPackagePolicyCreateCallback)( + thisCallbackResponse = await (callback as PostPackagePolicyCreateCallback)( updatedNewData as NewPackagePolicy, soClient, esClient, @@ -2012,10 +2077,10 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } if (externalCallbackType === 'packagePolicyCreate') { - updatedNewData = NewPackagePolicySchema.validate(result) as NewPackagePolicy; + updatedNewData = NewPackagePolicySchema.validate(thisCallbackResponse); } else if (externalCallbackType === 'packagePolicyUpdate') { const omitted = { - ...omit(result, [ + ...omit(thisCallbackResponse, [ 'id', 'spaceIds', 'version', @@ -2026,16 +2091,19 @@ class PackagePolicyClientImpl implements PackagePolicyClient { 'created_by', 'elasticsearch', ]), - inputs: result.inputs.map((input) => omit(input, ['compiled_input'])), + inputs: thisCallbackResponse.inputs.map((input) => + omit(input, ['compiled_input']) + ), }; - updatedNewData = UpdatePackagePolicySchema.validate(omitted) as PackagePolicy; + updatedNewData = UpdatePackagePolicySchema.validate(omitted); } } newData = updatedNewData; } - return newData; + + runResult = newData; } } } catch (error) { @@ -2043,6 +2111,8 @@ class PackagePolicyClientImpl implements PackagePolicyClient { logger.error(error); throw error; } + + return runResult as unknown as RunExternalCallbacksPackagePolicyResponse; } public async runPostDeleteExternalCallbacks( @@ -3025,27 +3095,30 @@ export function _validateRestrictedFieldsNotModifiedOrThrow(opts: { } } -async function validateIsNotHostedPolicy( - soClient: SavedObjectsClientContract, - id: string, - force = false, - errorMessage?: string -): Promise { - const agentPolicy = await agentPolicyService.get(soClient, id, false); - - if (!agentPolicy) { - throw new AgentPolicyNotFoundError('Agent policy not found'); +function validateReusableIntegrationsAndSpaceAwareness( + packagePolicy: Pick, + agentPolicies: AgentPolicy[] +) { + if ((packagePolicy.policy_ids.length ?? 0) <= 1) { + return; } + for (const agentPolicy of agentPolicies) { + if ((agentPolicy?.space_ids?.length ?? 0) > 1) { + throw new FleetError( + 'Reusable integration policies cannot be used with agent policies belonging to multiple spaces.' + ); + } + } +} +function validateIsNotHostedPolicy(agentPolicy: AgentPolicy, force = false, errorMessage?: string) { const isManagedPolicyWithoutServerlessSupport = agentPolicy.is_managed && !force; if (isManagedPolicyWithoutServerlessSupport) { throw new HostedAgentPolicyRestrictionRelatedError( - errorMessage ?? `Cannot update integrations of hosted agent policy ${id}` + errorMessage ?? `Cannot update integrations of hosted agent policy ${agentPolicy.id}` ); } - - return agentPolicy; } export function sendUpdatePackagePolicyTelemetryEvent( diff --git a/x-pack/plugins/fleet/server/services/package_policy_service.ts b/x-pack/plugins/fleet/server/services/package_policy_service.ts index f5cb879cef7cb..967efb1055cfb 100644 --- a/x-pack/plugins/fleet/server/services/package_policy_service.ts +++ b/x-pack/plugins/fleet/server/services/package_policy_service.ts @@ -40,6 +40,36 @@ export interface PackagePolicyService { get asInternalUser(): PackagePolicyClient; } +export type RunExternalCallbacksPackagePolicyArgument = + A extends 'packagePolicyDelete' + ? DeletePackagePoliciesResponse + : A extends 'packagePolicyPostDelete' + ? PostDeletePackagePoliciesResponse + : A extends 'packagePolicyCreate' + ? NewPackagePolicy + : A extends 'packagePolicyPostCreate' + ? PackagePolicy + : A extends 'packagePolicyUpdate' + ? UpdatePackagePolicy + : A extends 'packagePolicyPostUpdate' + ? PackagePolicy + : never; + +export type RunExternalCallbacksPackagePolicyResponse = + A extends 'packagePolicyDelete' + ? void + : A extends 'packagePolicyPostDelete' + ? void + : A extends 'packagePolicyCreate' + ? NewPackagePolicy + : A extends 'packagePolicyPostCreate' + ? PackagePolicy + : A extends 'packagePolicyUpdate' + ? UpdatePackagePolicy + : A extends 'packagePolicyPostUpdate' + ? PackagePolicy + : undefined; + export interface PackagePolicyClient { create( soClient: SavedObjectsClientContract, @@ -169,30 +199,12 @@ export interface PackagePolicyClient { runExternalCallbacks( externalCallbackType: A, - packagePolicy: A extends 'packagePolicyDelete' - ? DeletePackagePoliciesResponse - : A extends 'packagePolicyPostDelete' - ? PostDeletePackagePoliciesResponse - : A extends 'packagePolicyPostCreate' - ? PackagePolicy - : A extends 'packagePolicyUpdate' - ? UpdatePackagePolicy - : NewPackagePolicy, + packagePolicy: RunExternalCallbacksPackagePolicyArgument, soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, context?: RequestHandlerContext, request?: KibanaRequest - ): Promise< - A extends 'packagePolicyDelete' - ? void - : A extends 'packagePolicyPostDelete' - ? void - : A extends 'packagePolicyPostCreate' - ? PackagePolicy - : A extends 'packagePolicyUpdate' - ? UpdatePackagePolicy - : NewPackagePolicy - >; + ): Promise>; runDeleteExternalCallbacks( deletedPackagePolicies: DeletePackagePoliciesResponse, diff --git a/x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts new file mode 100644 index 0000000000000..ab69d4708c436 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createAppContextStartContractMock } from '../../mocks'; +import { agentPolicyService } from '../agent_policy'; +import { appContextService } from '../app_context'; +import { packagePolicyService } from '../package_policy'; + +import { updateAgentPolicySpaces } from './agent_policy'; +import { isSpaceAwarenessEnabled } from './helpers'; + +jest.mock('./helpers'); +jest.mock('../agent_policy'); +jest.mock('../package_policy'); + +describe('updateAgentPolicySpaces', () => { + beforeEach(() => { + jest.mocked(isSpaceAwarenessEnabled).mockResolvedValue(true); + jest.mocked(agentPolicyService.get).mockResolvedValue({ + id: 'policy1', + space_ids: ['default'], + } as any); + jest.mocked(packagePolicyService.findAllForAgentPolicy).mockResolvedValue([ + { + id: 'package-policy-1', + policy_ids: ['policy1'], + }, + { + id: 'package-policy-2', + policy_ids: ['policy1'], + }, + ] as any); + appContextService.start(createAppContextStartContractMock()); + + jest + .mocked(appContextService.getInternalUserSOClientWithoutSpaceExtension()) + .updateObjectsSpaces.mockResolvedValue({ objects: [] }); + }); + + it('does nothings if agent policy already in correct space', async () => { + await updateAgentPolicySpaces({ + agentPolicyId: 'policy1', + currentSpaceId: 'default', + newSpaceIds: ['default'], + authorizedSpaces: ['default'], + }); + expect( + appContextService.getInternalUserSOClientWithoutSpaceExtension().updateObjectsSpaces + ).not.toBeCalled(); + }); + + it('does nothing if feature flag is not enabled', async () => { + jest.mocked(isSpaceAwarenessEnabled).mockResolvedValue(false); + await updateAgentPolicySpaces({ + agentPolicyId: 'policy1', + currentSpaceId: 'default', + newSpaceIds: ['test'], + authorizedSpaces: ['test', 'default'], + }); + + expect( + appContextService.getInternalUserSOClientWithoutSpaceExtension().updateObjectsSpaces + ).not.toBeCalled(); + }); + + it('allow to change spaces', async () => { + await updateAgentPolicySpaces({ + agentPolicyId: 'policy1', + currentSpaceId: 'default', + newSpaceIds: ['test'], + authorizedSpaces: ['test', 'default'], + }); + + expect( + appContextService.getInternalUserSOClientWithoutSpaceExtension().updateObjectsSpaces + ).toBeCalledWith( + [ + { id: 'policy1', type: 'fleet-agent-policies' }, + { id: 'package-policy-1', type: 'fleet-package-policies' }, + { id: 'package-policy-2', type: 'fleet-package-policies' }, + ], + ['test'], + ['default'], + { namespace: 'default', refresh: 'wait_for' } + ); + }); + + it('throw when trying to change space to a policy with reusable package policies', async () => { + jest.mocked(packagePolicyService.findAllForAgentPolicy).mockResolvedValue([ + { + id: 'package-policy-1', + policy_ids: ['policy1'], + }, + { + id: 'package-policy-2', + policy_ids: ['policy1', 'policy2'], + }, + ] as any); + await expect( + updateAgentPolicySpaces({ + agentPolicyId: 'policy1', + currentSpaceId: 'default', + newSpaceIds: ['test'], + authorizedSpaces: ['test', 'default'], + }) + ).rejects.toThrowError( + /Agent policies using reusable integration policies cannot be moved to a different space./ + ); + }); + + it('throw when trying to change a managed policies space', async () => { + jest.mocked(agentPolicyService.get).mockResolvedValue({ + id: 'policy1', + space_ids: ['default'], + is_managed: true, + } as any); + jest.mocked(packagePolicyService.findAllForAgentPolicy).mockResolvedValue([] as any); + await expect( + updateAgentPolicySpaces({ + agentPolicyId: 'policy1', + currentSpaceId: 'default', + newSpaceIds: ['test'], + authorizedSpaces: ['test', 'default'], + }) + ).rejects.toThrowError(/Cannot update hosted agent policy policy1 space/); + }); + + it('throw when trying to add a space with missing permissions', async () => { + await expect( + updateAgentPolicySpaces({ + agentPolicyId: 'policy1', + currentSpaceId: 'default', + newSpaceIds: ['default', 'test'], + authorizedSpaces: ['default'], + }) + ).rejects.toThrowError(/Not enough permissions to create policies in space test/); + }); + + it('throw when trying to remove a space with missing permissions', async () => { + await expect( + updateAgentPolicySpaces({ + agentPolicyId: 'policy1', + currentSpaceId: 'default', + newSpaceIds: ['test'], + authorizedSpaces: ['test'], + }) + ).rejects.toThrowError(/Not enough permissions to remove policies from space default/); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts b/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts index f488a89297265..2f8d5ff1b14c7 100644 --- a/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts @@ -19,7 +19,7 @@ import { appContextService } from '../app_context'; import { agentPolicyService } from '../agent_policy'; import { ENROLLMENT_API_KEYS_INDEX } from '../../constants'; import { packagePolicyService } from '../package_policy'; -import { FleetError } from '../../errors'; +import { FleetError, HostedAgentPolicyRestrictionRelatedError } from '../../errors'; import { isSpaceAwarenessEnabled } from './helpers'; @@ -28,11 +28,13 @@ export async function updateAgentPolicySpaces({ currentSpaceId, newSpaceIds, authorizedSpaces, + options, }: { agentPolicyId: string; currentSpaceId: string; newSpaceIds: string[]; authorizedSpaces: string[]; + options?: { force?: boolean }; }) { const useSpaceAwareness = await isSpaceAwarenessEnabled(); if (!useSpaceAwareness || !newSpaceIds || newSpaceIds.length === 0) { @@ -50,10 +52,25 @@ export async function updateAgentPolicySpaces({ agentPolicyId ); + if (!existingPolicy) { + return; + } + + if (existingPolicy.is_managed && !options?.force) { + throw new HostedAgentPolicyRestrictionRelatedError( + `Cannot update hosted agent policy ${existingPolicy.id} space ` + ); + } + if (deepEqual(existingPolicy?.space_ids?.sort() ?? [DEFAULT_SPACE_ID], newSpaceIds.sort())) { return; } + if (existingPackagePolicies.some((packagePolicy) => packagePolicy.policy_ids.length > 1)) { + throw new FleetError( + 'Agent policies using reusable integration policies cannot be moved to a different space.' + ); + } const spacesToAdd = newSpaceIds.filter( (spaceId) => !existingPolicy?.space_ids?.includes(spaceId) ?? true ); @@ -63,13 +80,13 @@ export async function updateAgentPolicySpaces({ // Privileges check for (const spaceId of spacesToAdd) { if (!authorizedSpaces.includes(spaceId)) { - throw new FleetError(`No enough permissions to create policies in space ${spaceId}`); + throw new FleetError(`Not enough permissions to create policies in space ${spaceId}`); } } for (const spaceId of spacesToRemove) { if (!authorizedSpaces.includes(spaceId)) { - throw new FleetError(`No enough permissions to remove policies from space ${spaceId}`); + throw new FleetError(`Not enough permissions to remove policies from space ${spaceId}`); } } @@ -98,12 +115,30 @@ export async function updateAgentPolicySpaces({ // Update fleet server index agents, enrollment api keys await esClient.updateByQuery({ index: ENROLLMENT_API_KEYS_INDEX, + query: { + bool: { + must: { + terms: { + policy_id: [agentPolicyId], + }, + }, + }, + }, script: `ctx._source.namespaces = [${newSpaceIds.map((spaceId) => `"${spaceId}"`).join(',')}]`, ignore_unavailable: true, refresh: true, }); await esClient.updateByQuery({ index: AGENTS_INDEX, + query: { + bool: { + must: { + terms: { + policy_id: [agentPolicyId], + }, + }, + }, + }, script: `ctx._source.namespaces = [${newSpaceIds.map((spaceId) => `"${spaceId}"`).join(',')}]`, ignore_unavailable: true, refresh: true, diff --git a/x-pack/plugins/fleet/server/services/spaces/package_policy.ts b/x-pack/plugins/fleet/server/services/spaces/package_policy.ts new file mode 100644 index 0000000000000..3abf796061a07 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/spaces/package_policy.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../common/constants'; + +import { appContextService } from '../app_context'; + +export async function updatePackagePolicySpaces({ + packagePolicyId, + currentSpaceId, + newSpaceIds, +}: { + packagePolicyId: string; + currentSpaceId: string; + newSpaceIds: string[]; +}) { + const soClientWithoutSpaceExtension = + appContextService.getInternalUserSOClientWithoutSpaceExtension(); + + const results = await soClientWithoutSpaceExtension.updateObjectsSpaces( + [ + { + id: packagePolicyId, + type: PACKAGE_POLICY_SAVED_OBJECT_TYPE, + }, + ], + newSpaceIds, + [], + { refresh: 'wait_for', namespace: currentSpaceId } + ); + + for (const soRes of results.objects) { + if (soRes.error) { + throw soRes.error; + } + } +} diff --git a/x-pack/plugins/fleet/server/types/extensions.ts b/x-pack/plugins/fleet/server/types/extensions.ts index 594e16f619556..2293747b253e3 100644 --- a/x-pack/plugins/fleet/server/types/extensions.ts +++ b/x-pack/plugins/fleet/server/types/extensions.ts @@ -60,6 +60,14 @@ export type PutPackagePolicyUpdateCallback = ( request?: KibanaRequest ) => Promise; +export type PutPackagePolicyPostUpdateCallback = ( + packagePolicy: PackagePolicy, + soClient: SavedObjectsClientContract, + esClient: ElasticsearchClient, + context?: RequestHandlerContext, + request?: KibanaRequest +) => Promise; + export type PostAgentPolicyCreateCallback = ( agentPolicy: NewAgentPolicy ) => Promise; @@ -68,6 +76,8 @@ export type PostAgentPolicyUpdateCallback = ( agentPolicy: Partial ) => Promise>; +export type PostAgentPolicyPostUpdateCallback = (agentPolicy: AgentPolicy) => Promise; + export type ExternalCallbackCreate = ['packagePolicyCreate', PostPackagePolicyCreateCallback]; export type ExternalCallbackPostCreate = [ 'packagePolicyPostCreate', @@ -79,7 +89,12 @@ export type ExternalCallbackPostDelete = [ 'packagePolicyPostDelete', PostPackagePolicyPostDeleteCallback ]; + export type ExternalCallbackUpdate = ['packagePolicyUpdate', PutPackagePolicyUpdateCallback]; +export type ExternalCallbackPostUpdate = [ + 'packagePolicyPostUpdate', + PutPackagePolicyPostUpdateCallback +]; export type ExternalCallbackAgentPolicyCreate = [ 'agentPolicyCreate', @@ -89,6 +104,10 @@ export type ExternalCallbackAgentPolicyUpdate = [ 'agentPolicyUpdate', PostAgentPolicyUpdateCallback ]; +export type ExternalCallbackAgentPolicyPostUpdate = [ + 'agentPolicyPostUpdate', + PostAgentPolicyPostUpdateCallback +]; /** * Callbacks supported by the Fleet plugin @@ -99,7 +118,9 @@ export type ExternalCallback = | ExternalCallbackDelete | ExternalCallbackPostDelete | ExternalCallbackUpdate + | ExternalCallbackPostUpdate | ExternalCallbackAgentPolicyCreate - | ExternalCallbackAgentPolicyUpdate; + | ExternalCallbackAgentPolicyUpdate + | ExternalCallbackAgentPolicyPostUpdate; export type ExternalCallbacksStorage = Map>; diff --git a/x-pack/plugins/fleet/server/types/rest_spec/agent.ts b/x-pack/plugins/fleet/server/types/rest_spec/agent.ts index c1dface818f28..f9db02b92a659 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/agent.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/agent.ts @@ -217,11 +217,6 @@ export const AgentResponseSchema = schema.object({ }); export const GetAgentsResponseSchema = ListResponseSchema(AgentResponseSchema).extends({ - list: schema.maybe( - schema.arrayOf(AgentResponseSchema, { - meta: { deprecated: true }, - }) - ), statusSummary: schema.maybe(schema.recordOf(AgentStatusSchema, schema.number())), }); @@ -377,15 +372,6 @@ export const PostBulkAgentUpgradeRequestSchema = { }), }; -export const PutAgentReassignRequestSchemaDeprecated = { - params: schema.object({ - agentId: schema.string(), - }), - body: schema.object({ - policy_id: schema.string(), - }), -}; - export const PostAgentReassignRequestSchema = { params: schema.object({ agentId: schema.string(), @@ -518,9 +504,6 @@ export const GetAgentStatusRequestSchema = { return validationObj?.error; } }, - meta: { - deprecated: true, - }, }) ), }), @@ -529,11 +512,6 @@ export const GetAgentStatusRequestSchema = { export const GetAgentStatusResponseSchema = schema.object({ results: schema.object({ events: schema.number(), - total: schema.number({ - meta: { - deprecated: true, - }, - }), online: schema.number(), error: schema.number(), offline: schema.number(), diff --git a/x-pack/plugins/global_search_bar/public/components/search_bar.tsx b/x-pack/plugins/global_search_bar/public/components/search_bar.tsx index de9bb85f7a8a3..6c7eef92c6623 100644 --- a/x-pack/plugins/global_search_bar/public/components/search_bar.tsx +++ b/x-pack/plugins/global_search_bar/public/components/search_bar.tsx @@ -39,10 +39,6 @@ import { PopoverPlaceholder } from './popover_placeholder'; import './search_bar.scss'; import { SearchBarProps } from './types'; -const NoMatchesMessage = (props: { basePathUrl: string }) => { - return ; -}; - const SearchCharLimitExceededMessage = (props: { basePathUrl: string }) => { const charLimitMessage = ( <> @@ -90,17 +86,17 @@ export const SearchBar: FC = (opts) => { // General hooks const [initialLoad, setInitialLoad] = useState(false); const [searchValue, setSearchValue] = useState(''); - const [searchTerm, setSearchTerm] = useState(''); const [searchRef, setSearchRef] = useState(null); const [buttonRef, setButtonRef] = useState(null); const searchSubscription = useRef(null); - const [options, _setOptions] = useState([]); + const [options, setOptions] = useState([]); const [searchableTypes, setSearchableTypes] = useState([]); const [showAppend, setShowAppend] = useState(true); const UNKNOWN_TAG_ID = '__unknown__'; const [isLoading, setIsLoading] = useState(false); const [searchCharLimitExceeded, setSearchCharLimitExceeded] = useState(false); + // Initialize searchableTypes data useEffect(() => { if (initialLoad) { const fetch = async () => { @@ -111,6 +107,11 @@ export const SearchBar: FC = (opts) => { } }, [globalSearch, initialLoad]); + // Whenever searchValue changes, isLoading = true + useEffect(() => { + setIsLoading(true); + }, [searchValue]); + const loadSuggestions = useCallback( (term: string) => { return getSuggestions({ @@ -122,17 +123,13 @@ export const SearchBar: FC = (opts) => { [taggingApi, searchableTypes] ); - const setOptions = useCallback( + const setDecoratedOptions = useCallback( ( _options: GlobalSearchResult[], suggestions: SearchSuggestion[], searchTagIds: string[] = [] ) => { - if (!isMounted()) { - return; - } - - _setOptions([ + setOptions([ ...suggestions.map(suggestionToOption), ..._options.map((option) => resultToOption( @@ -143,7 +140,7 @@ export const SearchBar: FC = (opts) => { ), ]); }, - [isMounted, _setOptions, taggingApi] + [setOptions, taggingApi] ); useDebounce( @@ -163,9 +160,7 @@ export const SearchBar: FC = (opts) => { setSearchCharLimitExceeded(false); } - setIsLoading(true); const suggestions = loadSuggestions(searchValue.toLowerCase()); - setIsLoading(false); let aggregatedResults: GlobalSearchResult[] = []; @@ -187,26 +182,23 @@ export const SearchBar: FC = (opts) => { types: rawParams.filters.types, tags: tagIds, }; - // TODO technically a subtle bug here - // this term won't be set until the next time the debounce is fired - // so the SearchOption won't highlight anything if only one call is fired - // in practice, this is hard to spot, unlikely to happen, and is a negligible issue - setSearchTerm(rawParams.term ?? ''); - setIsLoading(true); + searchSubscription.current = globalSearch.find(searchParams, {}).subscribe({ next: ({ results }) => { + if (!isMounted()) { + return; + } + if (searchValue.length > 0) { aggregatedResults = [...results, ...aggregatedResults].sort(sort.byScore); - setOptions(aggregatedResults, suggestions, searchParams.tags); + setDecoratedOptions(aggregatedResults, suggestions, searchParams.tags); return; } // if searchbar is empty, filter to only applications and sort alphabetically results = results.filter(({ type }: GlobalSearchResult) => type === 'application'); - aggregatedResults = [...results, ...aggregatedResults].sort(sort.byTitle); - - setOptions(aggregatedResults, suggestions, searchParams.tags); + setDecoratedOptions(aggregatedResults, suggestions, searchParams.tags); }, error: (err) => { setIsLoading(false); @@ -325,11 +317,12 @@ export const SearchBar: FC = (opts) => { buttonRef={visibilityButtonRef} color="text" data-test-subj="nav-search-reveal" - iconType="search" onClick={() => { setIsVisible(true); }} - /> + > + + ); } @@ -370,7 +363,7 @@ export const SearchBar: FC = (opts) => { className="kbnSearchBar" popoverButtonBreakpoints={['xs', 's']} singleSelection={true} - renderOption={(option) => euiSelectableTemplateSitewideRenderOptions(option, searchTerm)} + renderOption={(option) => euiSelectableTemplateSitewideRenderOptions(option, searchValue)} listProps={{ className: 'eui-yScroll', css: css` @@ -400,7 +393,7 @@ export const SearchBar: FC = (opts) => { }} errorMessage={searchCharLimitExceeded ? : null} emptyMessage={} - noMatchesMessage={} + noMatchesMessage={} popoverProps={{ 'data-test-subj': 'nav-search-popover', panelClassName: 'navSearch__panel', diff --git a/x-pack/plugins/global_search_bar/public/telemetry/telemetry.test.tsx b/x-pack/plugins/global_search_bar/public/telemetry/telemetry.test.tsx index 2137679fcf5c3..e4302c1e64aec 100644 --- a/x-pack/plugins/global_search_bar/public/telemetry/telemetry.test.tsx +++ b/x-pack/plugins/global_search_bar/public/telemetry/telemetry.test.tsx @@ -194,9 +194,7 @@ describe('SearchBar', () => { }); it(`tracks the user's search term`, async () => { - searchService.find.mockReturnValueOnce( - of(createBatch('Discover', { id: 'My Dashboard', type: 'test' })) - ); + searchService.find.mockReturnValue(of(createBatch('Discover'))); render( diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts index bd119a77378af..608d2ce5390da 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts @@ -298,6 +298,7 @@ export const createDataStreamPayload = (dataStream: Partial): DataSt enabled: true, data_retention: '7d', }, + indexMode: 'standard', ...dataStream, }); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts index a4ea7b9296e28..1d7ee65790cfd 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts @@ -205,8 +205,8 @@ describe('Data Streams tab', () => { const { tableCellsValues } = table.getMetaData('dataStreamTable'); expect(tableCellsValues).toEqual([ - ['', 'dataStream1', 'green', '1', '7 days', 'Delete'], - ['', 'dataStream2', 'green', '1', '5 days ', 'Delete'], + ['', 'dataStream1', 'green', '1', 'Standard', '7 days', 'Delete'], + ['', 'dataStream2', 'green', '1', 'Standard', '5 days ', 'Delete'], ]); }); @@ -254,6 +254,7 @@ describe('Data Streams tab', () => { 'December 31st, 1969 7:00:00 PM', '5b', '1', + 'Standard', '7 days', 'Delete', ], @@ -264,6 +265,7 @@ describe('Data Streams tab', () => { 'December 31st, 1969 7:00:00 PM', '1kb', '1', + 'Standard', '5 days ', 'Delete', ], @@ -289,6 +291,7 @@ describe('Data Streams tab', () => { 'December 31st, 1969 7:00:00 PM', '5b', '1', + 'Standard', '7 days', 'Delete', ], @@ -299,6 +302,7 @@ describe('Data Streams tab', () => { 'December 31st, 1969 7:00:00 PM', '1kb', '1', + 'Standard', '5 days ', 'Delete', ], @@ -346,8 +350,8 @@ describe('Data Streams tab', () => { const { tableCellsValues } = table.getMetaData('dataStreamTable'); expect(tableCellsValues).toEqual([ - ['', 'dataStream1', 'green', '156kb', '10000', '1', '7 days', 'Delete'], - ['', 'dataStream2', 'green', '156kb', '10000', '1', '5 days ', 'Delete'], + ['', 'dataStream1', 'green', '156kb', '10000', '1', 'Standard', '7 days', 'Delete'], + ['', 'dataStream2', 'green', '156kb', '10000', '1', 'Standard', '5 days ', 'Delete'], ]); }); @@ -378,6 +382,7 @@ describe('Data Streams tab', () => { 'December 31st, 1969 7:00:00 PM', '5b', '1', + 'Standard', '7 days', 'Delete', ], @@ -388,6 +393,7 @@ describe('Data Streams tab', () => { 'December 31st, 1969 7:00:00 PM', '1kb', '1', + 'Standard', '5 days ', 'Delete', ], @@ -509,8 +515,8 @@ describe('Data Streams tab', () => { const { tableCellsValues } = table.getMetaData('dataStreamTable'); expect(tableCellsValues).toEqual([ - ['', 'dataStream1', 'green', '1', 'Disabled', 'Delete'], - ['', 'dataStream2', 'green', '1', '', 'Delete'], + ['', 'dataStream1', 'green', '1', 'Standard', 'Disabled', 'Delete'], + ['', 'dataStream2', 'green', '1', 'Standard', '', 'Delete'], ]); await actions.clickNameAt(0); @@ -892,8 +898,16 @@ describe('Data Streams tab', () => { const { tableCellsValues } = table.getMetaData('dataStreamTable'); expect(tableCellsValues).toEqual([ - ['', `managed-data-stream${nonBreakingSpace}Managed`, 'green', '1', '7 days', 'Delete'], - ['', 'non-managed-data-stream', 'green', '1', '7 days', 'Delete'], + [ + '', + `managed-data-stream${nonBreakingSpace}Managed`, + 'green', + '1', + 'Standard', + '7 days', + 'Delete', + ], + ['', 'non-managed-data-stream', 'green', '1', 'Standard', '7 days', 'Delete'], ]); }); @@ -902,15 +916,23 @@ describe('Data Streams tab', () => { let { tableCellsValues } = table.getMetaData('dataStreamTable'); expect(tableCellsValues).toEqual([ - ['', `managed-data-stream${nonBreakingSpace}Managed`, 'green', '1', '7 days', 'Delete'], - ['', 'non-managed-data-stream', 'green', '1', '7 days', 'Delete'], + [ + '', + `managed-data-stream${nonBreakingSpace}Managed`, + 'green', + '1', + 'Standard', + '7 days', + 'Delete', + ], + ['', 'non-managed-data-stream', 'green', '1', 'Standard', '7 days', 'Delete'], ]); actions.toggleViewFilterAt(0); ({ tableCellsValues } = table.getMetaData('dataStreamTable')); expect(tableCellsValues).toEqual([ - ['', 'non-managed-data-stream', 'green', '1', '7 days', 'Delete'], + ['', 'non-managed-data-stream', 'green', '1', 'Standard', '7 days', 'Delete'], ]); }); }); @@ -942,7 +964,15 @@ describe('Data Streams tab', () => { const { tableCellsValues } = table.getMetaData('dataStreamTable'); expect(tableCellsValues).toEqual([ - ['', `hidden-data-stream${nonBreakingSpace}Hidden`, 'green', '1', '7 days', 'Delete'], + [ + '', + `hidden-data-stream${nonBreakingSpace}Hidden`, + 'green', + '1', + 'Standard', + '7 days', + 'Delete', + ], ]); }); }); @@ -989,10 +1019,10 @@ describe('Data Streams tab', () => { const { tableCellsValues } = table.getMetaData('dataStreamTable'); expect(tableCellsValues).toEqual([ - ['', 'dataStreamNoDelete', 'green', '1', '7 days', ''], - ['', 'dataStreamNoEditRetention', 'green', '1', '7 days', 'Delete'], - ['', 'dataStreamNoPermissions', 'green', '1', '7 days', ''], - ['', 'dataStreamWithDelete', 'green', '1', '7 days', 'Delete'], + ['', 'dataStreamNoDelete', 'green', '1', 'Standard', '7 days', ''], + ['', 'dataStreamNoEditRetention', 'green', '1', 'Standard', '7 days', 'Delete'], + ['', 'dataStreamNoPermissions', 'green', '1', 'Standard', '7 days', ''], + ['', 'dataStreamWithDelete', 'green', '1', 'Standard', '7 days', 'Delete'], ]); }); diff --git a/x-pack/plugins/index_management/common/lib/template_serialization.ts b/x-pack/plugins/index_management/common/lib/template_serialization.ts index f8b4ed47a22f7..0ed52e3f04ba0 100644 --- a/x-pack/plugins/index_management/common/lib/template_serialization.ts +++ b/x-pack/plugins/index_management/common/lib/template_serialization.ts @@ -73,6 +73,8 @@ export function deserializeTemplate( type = 'managed'; } + const ilmPolicyName = settings?.index?.lifecycle?.name; + const deserializedTemplate: TemplateDeserialized = { name, version, @@ -80,7 +82,7 @@ export function deserializeTemplate( ...(template.lifecycle ? { lifecycle: deserializeESLifecycle(template.lifecycle) } : {}), indexPatterns: indexPatterns.sort(), template, - ilmPolicy: settings?.index?.lifecycle, + ilmPolicy: ilmPolicyName ? { name: ilmPolicyName } : undefined, composedOf: composedOf ?? [], ignoreMissingComponentTemplates: ignoreMissingComponentTemplates ?? [], dataStream, diff --git a/x-pack/plugins/index_management/common/types/data_streams.ts b/x-pack/plugins/index_management/common/types/data_streams.ts index 78c671969f579..993d32f32bee1 100644 --- a/x-pack/plugins/index_management/common/types/data_streams.ts +++ b/x-pack/plugins/index_management/common/types/data_streams.ts @@ -33,6 +33,8 @@ export type DataStreamIndexFromEs = IndicesDataStreamIndex; export type Health = 'green' | 'yellow' | 'red'; +export type IndexMode = 'standard' | 'logsdb' | 'time_series'; + export interface EnhancedDataStreamFromEs extends IndicesDataStream { global_max_retention?: string; store_size?: IndicesDataStreamsStatsDataStreamsStatsItem['store_size']; @@ -45,6 +47,7 @@ export interface EnhancedDataStreamFromEs extends IndicesDataStream { delete_index: boolean; manage_data_stream_lifecycle: boolean; }; + index_mode?: string | null; } export interface DataStream { @@ -71,6 +74,7 @@ export interface DataStream { retention_determined_by?: string; globalMaxRetention?: string; }; + indexMode: IndexMode; } export interface DataStreamIndex { diff --git a/x-pack/plugins/index_management/common/types/indices.ts b/x-pack/plugins/index_management/common/types/indices.ts index 612aaf3bd6c9b..804a1bce1e299 100644 --- a/x-pack/plugins/index_management/common/types/indices.ts +++ b/x-pack/plugins/index_management/common/types/indices.ts @@ -5,29 +5,9 @@ * 2.0. */ -export type { Index } from '@kbn/index-management-shared-types'; +import { IndicesIndexSettingsKeys } from '@elastic/elasticsearch/lib/api/types'; -export interface IndexModule { - number_of_shards: number | string; - codec: string; - routing_partition_size: number; - refresh_interval: string; - load_fixed_bitset_filters_eagerly: boolean; - shard: { - check_on_startup: boolean | 'checksum'; - }; - number_of_replicas: number; - auto_expand_replicas: false | string; - lifecycle: LifecycleModule; - routing: { - allocation: { - enable: 'all' | 'primaries' | 'new_primaries' | 'none'; - }; - rebalance: { - enable: 'all' | 'primaries' | 'replicas' | 'none'; - }; - }; -} +export type { Index } from '@kbn/index-management-shared-types'; interface AnalysisModule { analyzer: { @@ -41,15 +21,8 @@ interface AnalysisModule { }; } -interface LifecycleModule { - name: string; - rollover_alias?: string; - parse_origination_date?: boolean; - origination_date?: number; -} - export interface IndexSettings { - index?: Partial; + index?: IndicesIndexSettingsKeys; analysis?: AnalysisModule; [key: string]: any; } diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts index 728ba79eedd81..71231c89b673c 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts @@ -623,7 +623,7 @@ export const getFieldsMatchingFilterFromState = ( } => { return Object.fromEntries( Object.entries(state.fields.byId).filter(([_, fieldId]) => - filteredDataTypes.includes(TYPE_DEFINITION[state.fields.byId[fieldId.id].source.type].label) + filteredDataTypes.includes(getTypeLabelFromField(state.fields.byId[fieldId.id].source)) ) ); }; @@ -646,9 +646,7 @@ export const getFieldsFromState = ( const getField = (fieldId: string) => { if (filteredDataTypes) { if ( - filteredDataTypes.includes( - TYPE_DEFINITION[normalizedFields.byId[fieldId].source.type].label - ) + filteredDataTypes.includes(getTypeLabelFromField(normalizedFields.byId[fieldId].source)) ) { return normalizedFields.byId[fieldId]; } diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/use_state_listener.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/use_state_listener.tsx index 5c5e1c6a289fa..26610773ddbf4 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/use_state_listener.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/use_state_listener.tsx @@ -26,9 +26,9 @@ import { deNormalizeRuntimeFields, getAllFieldTypesFromState, getFieldsFromState, + getTypeLabelFromField, } from './lib'; import { useMappingsState, useDispatch } from './mappings_state_context'; -import { TYPE_DEFINITION } from './constants'; interface Args { onChange?: OnUpdateHandler; @@ -56,7 +56,7 @@ export const useMappingsStateListener = ({ onChange, value, status }: Args) => { const allFieldsTypes = getAllFieldTypesFromState(deNormalize(normalize(mappedFields))); return allFieldsTypes.map((dataType) => ({ checked: undefined, - label: TYPE_DEFINITION[dataType].label, + label: getTypeLabelFromField({ type: dataType }), 'data-test-subj': `indexDetailsMappingsSelectFilter-${dataType}`, })); }, [mappedFields]); diff --git a/x-pack/plugins/index_management/public/application/components/template_form/steps/step_review.tsx b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_review.tsx index 24544db04498b..9cb5c481b6b50 100644 --- a/x-pack/plugins/index_management/public/application/components/template_form/steps/step_review.tsx +++ b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_review.tsx @@ -22,6 +22,7 @@ import { EuiCodeBlock, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { getIndexModeLabel } from '../../../lib/index_mode_labels'; import { allowAutoCreateRadioIds } from '../../../../../common/constants'; import { serializers } from '../../../../shared_imports'; @@ -268,6 +269,19 @@ export const StepReview: React.FunctionComponent = React.memo( {getDescriptionText(serializedSettings)} + {/* Index mode */} + + + + + {getIndexModeLabel( + serializedSettings?.['index.mode'] ?? serializedSettings?.index?.mode + )} + + {/* Mappings */} { describe('getLifecycleValue', () => { @@ -45,4 +45,36 @@ describe('Data stream helpers', () => { ).toBe('5 days'); }); }); + + describe('deserializeGlobalMaxRetention', () => { + it('if globalMaxRetention is undefined', () => { + expect(deserializeGlobalMaxRetention(undefined)).toEqual({}); + }); + + it('split globalMaxRetention size and units', () => { + expect(deserializeGlobalMaxRetention('1000h')).toEqual({ + size: '1000', + unit: 'h', + unitText: 'hours', + }); + }); + + it('support all of the units that are accepted by es', () => { + expect(deserializeGlobalMaxRetention('1000ms')).toEqual({ + size: '1000', + unit: 'ms', + unitText: 'milliseconds', + }); + expect(deserializeGlobalMaxRetention('1000micros')).toEqual({ + size: '1000', + unit: 'micros', + unitText: 'microseconds', + }); + expect(deserializeGlobalMaxRetention('1000nanos')).toEqual({ + size: '1000', + unit: 'nanos', + unitText: 'nanoseconds', + }); + }); + }); }); diff --git a/x-pack/plugins/index_management/public/application/lib/data_streams.tsx b/x-pack/plugins/index_management/public/application/lib/data_streams.tsx index 71c8bb0f61177..6747e84df751d 100644 --- a/x-pack/plugins/index_management/public/application/lib/data_streams.tsx +++ b/x-pack/plugins/index_management/public/application/lib/data_streams.tsx @@ -121,3 +121,19 @@ export const isDSLWithILMIndices = (dataStream?: DataStream | null) => { return; }; + +export const deserializeGlobalMaxRetention = (globalMaxRetention?: string) => { + if (!globalMaxRetention) { + return {}; + } + + const { size, unit } = splitSizeAndUnits(globalMaxRetention); + const availableTimeUnits = [...timeUnits, ...extraTimeUnits]; + const match = availableTimeUnits.find((timeUnit) => timeUnit.value === unit); + + return { + size, + unit, + unitText: match?.text ?? unit, + }; +}; diff --git a/x-pack/plugins/index_management/public/application/lib/index_mode_labels.ts b/x-pack/plugins/index_management/public/application/lib/index_mode_labels.ts new file mode 100644 index 0000000000000..409659b8133c3 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/lib/index_mode_labels.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const getIndexModeLabel = (mode?: string | null) => { + switch (mode) { + case 'standard': + case null: + case undefined: + return i18n.translate('xpack.idxMgmt.indexModeLabels.standardModeLabel', { + defaultMessage: 'Standard', + }); + case 'logsdb': + return i18n.translate('xpack.idxMgmt.indexModeLabels.logsdbModeLabel', { + defaultMessage: 'LogsDB', + }); + case 'time_series': + return i18n.translate('xpack.idxMgmt.indexModeLabels.tsdbModeLabel', { + defaultMessage: 'Time series', + }); + default: + return mode; + } +}; diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_detail_panel/data_stream_detail_panel.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_detail_panel/data_stream_detail_panel.tsx index 974ba6f082042..5b3bf0920c3b7 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_detail_panel/data_stream_detail_panel.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_detail_panel/data_stream_detail_panel.tsx @@ -34,6 +34,7 @@ import { EuiSpacer, } from '@elastic/eui'; +import { getIndexModeLabel } from '../../../../lib/index_mode_labels'; import { DiscoverLink } from '../../../../lib/discover_link'; import { getLifecycleValue } from '../../../../lib/data_streams'; import { SectionLoading, reactRouterNavigate } from '../../../../../shared_imports'; @@ -166,6 +167,7 @@ export const DataStreamDetailPanel: React.FunctionComponent = ({ meteringStorageSize, meteringDocsCount, lifecycle, + indexMode, } = dataStream; const getManagementDetails = () => { @@ -345,6 +347,17 @@ export const DataStreamDetailPanel: React.FunctionComponent = ({ ), dataTestSubj: 'indexTemplateDetail', }, + { + name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.indexModeTitle', { + defaultMessage: 'Index mode', + }), + toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.indexModeToolTip', { + defaultMessage: + "The index mode applied to the data stream's backing indices, as defined in its associated index template.", + }), + content: getIndexModeLabel(indexMode), + dataTestSubj: 'indexModeDetail', + }, { name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.dataRetentionTitle', { defaultMessage: 'Effective data retention', diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_table/data_stream_table.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_table/data_stream_table.tsx index 927907757fe7b..e91fd644f795c 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_table/data_stream_table.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_table/data_stream_table.tsx @@ -36,6 +36,7 @@ import { humanizeTimeStamp } from '../humanize_time_stamp'; import { DataStreamsBadges } from '../data_stream_badges'; import { ConditionalWrap } from '../data_stream_detail_panel'; import { isDataStreamFullyManagedByILM } from '../../../../lib/data_streams'; +import { getIndexModeLabel } from '../../../../lib/index_mode_labels'; import { FilterListButton, Filters } from '../../components'; import { type DataStreamFilterName } from '../data_stream_list'; @@ -184,6 +185,16 @@ export const DataStreamTable: React.FunctionComponent = ({ ), }); + columns.push({ + field: 'indexMode', + name: i18n.translate('xpack.idxMgmt.dataStreamList.table.indexModeColumnTitle', { + defaultMessage: 'Index mode', + }), + truncateText: true, + sortable: true, + render: (indexMode: DataStream['indexMode']) => getIndexModeLabel(indexMode), + }); + columns.push({ field: 'lifecycle', name: ( diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/edit_data_retention_modal.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/edit_data_retention_modal.tsx index f5eee4671481a..2c60e04be31a6 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/edit_data_retention_modal.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/edit_data_retention_modal.tsx @@ -43,7 +43,7 @@ import { getIndexListUri } from '../../../../services/routing'; import { documentationService } from '../../../../services/documentation'; import { splitSizeAndUnits, DataStream } from '../../../../../../common'; import { timeUnits } from '../../../../constants/time_units'; -import { isDSLWithILMIndices } from '../../../../lib/data_streams'; +import { deserializeGlobalMaxRetention, isDSLWithILMIndices } from '../../../../lib/data_streams'; import { useAppContext } from '../../../../app_context'; import { UnitField } from '../../../../components/shared'; import { updateDataRetention } from '../../../../services/api'; @@ -214,6 +214,7 @@ export const EditDataRetentionModal: React.FunctionComponent = ({ const { history } = useAppContext(); const dslWithIlmIndices = isDSLWithILMIndices(dataStream); const { size, unit } = splitSizeAndUnits(lifecycle?.data_retention as string); + const globalMaxRetention = deserializeGlobalMaxRetention(lifecycle?.globalMaxRetention); const { services: { notificationService }, config: { enableTogglingDataRetention, enableProjectLevelRetentionChecks }, @@ -331,8 +332,11 @@ export const EditDataRetentionModal: React.FunctionComponent = ({ <> diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/validations.test.ts b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/validations.test.ts index 0768d0990cdc0..87cc1d36526fb 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/validations.test.ts +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/validations.test.ts @@ -47,6 +47,26 @@ describe('isBiggerThanGlobalMaxRetention', () => { }); }); + it('should correctly compare retention in all of the units that are accepted by es', () => { + // 1000 milliseconds = 1 seconds + expect(isBiggerThanGlobalMaxRetention(1, 's', '1000ms')).toBeUndefined(); + expect(isBiggerThanGlobalMaxRetention(2, 's', '1000ms')).toEqual({ + message: 'Maximum data retention period on this project is 1000 milliseconds.', + }); + + // 1000000 microseconds = 1 seconds + expect(isBiggerThanGlobalMaxRetention(1, 's', '1000000micros')).toBeUndefined(); + expect(isBiggerThanGlobalMaxRetention(2, 'm', '1000000micros')).toEqual({ + message: 'Maximum data retention period on this project is 1000000 microseconds.', + }); + + // 1000000000 microseconds = 1 seconds + expect(isBiggerThanGlobalMaxRetention(2, 's', '1000000000nanos')); + expect(isBiggerThanGlobalMaxRetention(2, 'h', '1000000000nanos')).toEqual({ + message: 'Maximum data retention period on this project is 1000000000 nanoseconds.', + }); + }); + it('should throw an error for unknown time units', () => { expect(() => isBiggerThanGlobalMaxRetention(10, 'x', '30d')).toThrow('Unknown unit: x'); }); diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/validations.ts b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/validations.ts index 831ac2f4c26b9..8486f01fb5b44 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/validations.ts +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/edit_data_retention_modal/validations.ts @@ -7,34 +7,44 @@ import { i18n } from '@kbn/i18n'; import { splitSizeAndUnits } from '../../../../../../common'; +import { deserializeGlobalMaxRetention } from '../../../../lib/data_streams'; -const convertToMinutes = (value: string) => { +const convertToSeconds = (value: string) => { const { size, unit } = splitSizeAndUnits(value); const sizeNum = parseInt(size, 10); switch (unit) { case 'd': - // days to minutes - return sizeNum * 24 * 60; + // days to seconds + return sizeNum * 24 * 60 * 60; case 'h': - // hours to minutes - return sizeNum * 60; + // hours to seconds + return sizeNum * 60 * 60; case 'm': - // minutes to minutes - return sizeNum; + // minutes to seconds + return sizeNum * 60; case 's': - // seconds to minutes (round up if any remainder) - return Math.ceil(sizeNum / 60); + // seconds to seconds + return sizeNum; + case 'ms': + // milliseconds to seconds + return sizeNum / 1000; + case 'micros': + // microseconds to seconds + return sizeNum / 1000 / 1000; + case 'nanos': + // nanoseconds to seconds + return sizeNum / 1000 / 1000 / 1000; default: throw new Error(`Unknown unit: ${unit}`); } }; const isRetentionBiggerThan = (valueA: string, valueB: string) => { - const minutesA = convertToMinutes(valueA); - const minutesB = convertToMinutes(valueB); + const secondsA = convertToSeconds(valueA); + const secondsB = convertToSeconds(valueB); - return minutesA > minutesB; + return secondsA > secondsB; }; export const isBiggerThanGlobalMaxRetention = ( @@ -46,14 +56,19 @@ export const isBiggerThanGlobalMaxRetention = ( return undefined; } + const { size, unitText } = deserializeGlobalMaxRetention(globalMaxRetention); return isRetentionBiggerThan(`${retentionValue}${retentionTimeUnit}`, globalMaxRetention) ? { message: i18n.translate( 'xpack.idxMgmt.dataStreamsDetailsPanel.editDataRetentionModal.dataRetentionFieldMaxError', { - defaultMessage: 'Maximum data retention period on this project is {maxRetention} days.', + defaultMessage: + 'Maximum data retention period on this project is {maxRetention} {unitText}.', // Remove the unit from the globalMaxRetention value - values: { maxRetention: globalMaxRetention.slice(0, -1) }, + values: { + maxRetention: size, + unitText, + }, } ), } diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table_pagination.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table_pagination.tsx index b9dd98e21a426..a0988aec797f6 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table_pagination.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table_pagination.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiTablePagination } from '@elastic/eui'; import { useEuiTablePersist } from '@kbn/shared-ux-table-persist'; -import { IndexModule } from '../../../../../../common'; +import { Index } from '../../../../../../common'; interface IndexTablePaginationProps { pager: any; @@ -27,7 +27,7 @@ export const IndexTablePagination = ({ readURLParams, setURLParam, }: IndexTablePaginationProps) => { - const { pageSize, onTableChange } = useEuiTablePersist({ + const { pageSize, onTableChange } = useEuiTablePersist({ tableId: 'indices', initialPageSize: pager.itemsPerPage, pageSizeOptions: PAGE_SIZE_OPTIONS, diff --git a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx index 513377714ffe0..ff06a08014f61 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx @@ -28,6 +28,7 @@ import { TemplateDeserialized } from '../../../../../../../common'; import { ILM_PAGES_POLICY_EDIT } from '../../../../../constants'; import { useIlmLocator } from '../../../../../services/use_ilm_locator'; import { allowAutoCreateRadioIds } from '../../../../../../../common/constants'; +import { getIndexModeLabel } from '../../../../../lib/index_mode_labels'; interface Props { templateDetails: TemplateDeserialized; @@ -57,6 +58,7 @@ export const TabSummary: React.FunctionComponent = ({ templateDetails }) _meta, _kbnMeta: { isLegacy, hasDatastream }, allowAutoCreate, + template, } = templateDetails; const numIndexPatterns = indexPatterns.length; @@ -221,6 +223,17 @@ export const TabSummary: React.FunctionComponent = ({ templateDetails }) )} + {/* Index mode */} + + + + + {getIndexModeLabel(template?.settings?.index?.mode)} + + {/* Allow auto create */} {isLegacy !== true && allowAutoCreate !== allowAutoCreateRadioIds.NO_OVERWRITE_RADIO_OPTION && ( diff --git a/x-pack/plugins/index_management/server/lib/data_stream_serialization.ts b/x-pack/plugins/index_management/server/lib/data_stream_serialization.ts index 2e493ca02aa79..31c0baa6c6b8c 100644 --- a/x-pack/plugins/index_management/server/lib/data_stream_serialization.ts +++ b/x-pack/plugins/index_management/server/lib/data_stream_serialization.ts @@ -6,6 +6,7 @@ */ import { ByteSizeValue } from '@kbn/config-schema'; +import { IndexMode } from '../../common/types/data_streams'; import type { DataStream, EnhancedDataStreamFromEs, Health } from '../../common'; export function deserializeDataStream(dataStreamFromEs: EnhancedDataStreamFromEs): DataStream { @@ -28,6 +29,7 @@ export function deserializeDataStream(dataStreamFromEs: EnhancedDataStreamFromEs lifecycle, global_max_retention: globalMaxRetention, next_generation_managed_by: nextGenerationManagedBy, + index_mode: indexMode, } = dataStreamFromEs; const meteringStorageSize = meteringStorageSizeBytes !== undefined @@ -73,6 +75,7 @@ export function deserializeDataStream(dataStreamFromEs: EnhancedDataStreamFromEs globalMaxRetention, }, nextGenerationManagedBy, + indexMode: (indexMode ?? 'standard') as IndexMode, }; } diff --git a/x-pack/plugins/index_management/server/routes/api/data_streams/register_get_route.ts b/x-pack/plugins/index_management/server/routes/api/data_streams/register_get_route.ts index 8b62c2b3a25cb..cd47b8cc9e0bb 100644 --- a/x-pack/plugins/index_management/server/routes/api/data_streams/register_get_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/data_streams/register_get_route.ts @@ -11,6 +11,7 @@ import { IScopedClusterClient } from '@kbn/core/server'; import { IndicesDataStream, IndicesDataStreamsStatsDataStreamsStatsItem, + IndicesGetIndexTemplateIndexTemplateItem, SecurityHasPrivilegesResponse, } from '@elastic/elasticsearch/lib/api/types'; import type { MeteringStats } from '../../../lib/types'; @@ -31,12 +32,14 @@ const enhanceDataStreams = ({ meteringStats, dataStreamsPrivileges, globalMaxRetention, + indexTemplates, }: { dataStreams: IndicesDataStream[]; dataStreamsStats?: IndicesDataStreamsStatsDataStreamsStatsItem[]; meteringStats?: MeteringStats[]; dataStreamsPrivileges?: SecurityHasPrivilegesResponse; globalMaxRetention?: string; + indexTemplates?: IndicesGetIndexTemplateIndexTemplateItem[]; }): EnhancedDataStreamFromEs[] => { return dataStreams.map((dataStream) => { const enhancedDataStream: EnhancedDataStreamFromEs = { @@ -71,6 +74,16 @@ const enhanceDataStreams = ({ } } + if (indexTemplates) { + const indexTemplate = indexTemplates.find( + (template) => template.name === dataStream.template + ); + if (indexTemplate) { + enhancedDataStream.index_mode = + indexTemplate.index_template?.template?.settings?.index?.mode; + } + } + return enhancedDataStream; }); }; @@ -152,11 +165,15 @@ export function registerGetAllRoute({ router, lib: { handleEsError }, config }: ); } + const { index_templates: indexTemplates } = + await client.asCurrentUser.indices.getIndexTemplate(); + const enhancedDataStreams = enhanceDataStreams({ dataStreams, dataStreamsStats, meteringStats, dataStreamsPrivileges, + indexTemplates, }); return response.ok({ body: deserializeDataStreamList(enhancedDataStreams) }); @@ -199,17 +216,30 @@ export function registerGetOneRoute({ router, lib: { handleEsError }, config }: if (dataStreams[0]) { let dataStreamsPrivileges; + let indexTemplates; if (config.isSecurityEnabled()) { dataStreamsPrivileges = await getDataStreamsPrivileges(client, [dataStreams[0].name]); } + if (dataStreams[0].template) { + const { index_templates: templates } = + await client.asCurrentUser.indices.getIndexTemplate({ + name: dataStreams[0].template, + }); + + if (templates) { + indexTemplates = templates; + } + } + const enhancedDataStreams = enhanceDataStreams({ dataStreams, dataStreamsStats, meteringStats, dataStreamsPrivileges, globalMaxRetention, + indexTemplates, }); const body = deserializeDataStream(enhancedDataStreams[0]); return response.ok({ body }); diff --git a/x-pack/plugins/inference/common/chat_complete/index.ts b/x-pack/plugins/inference/common/chat_complete/index.ts deleted file mode 100644 index aef9de12ba7a9..0000000000000 --- a/x-pack/plugins/inference/common/chat_complete/index.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { Observable } from 'rxjs'; -import type { InferenceTaskEventBase } from '../inference_task'; -import type { ToolCall, ToolCallsOf, ToolOptions } from './tools'; - -export enum MessageRole { - User = 'user', - Assistant = 'assistant', - Tool = 'tool', -} - -interface MessageBase { - role: TRole; -} - -export type UserMessage = MessageBase & { content: string }; - -export type AssistantMessage = MessageBase & { - content: string | null; - toolCalls?: Array | undefined>>; -}; - -export type ToolMessage | unknown> = - MessageBase & { - toolCallId: string; - response: TToolResponse; - }; - -export type Message = UserMessage | AssistantMessage | ToolMessage; - -export type ChatCompletionMessageEvent = - InferenceTaskEventBase & { - content: string; - } & { toolCalls: ToolCallsOf['toolCalls'] }; - -export type ChatCompletionResponse = Observable< - ChatCompletionEvent ->; - -export enum ChatCompletionEventType { - ChatCompletionChunk = 'chatCompletionChunk', - ChatCompletionTokenCount = 'chatCompletionTokenCount', - ChatCompletionMessage = 'chatCompletionMessage', -} - -export interface ChatCompletionChunkToolCall { - index: number; - toolCallId: string; - function: { - name: string; - arguments: string; - }; -} - -export type ChatCompletionChunkEvent = - InferenceTaskEventBase & { - content: string; - tool_calls: ChatCompletionChunkToolCall[]; - }; - -export type ChatCompletionTokenCountEvent = - InferenceTaskEventBase & { - tokens: { - prompt: number; - completion: number; - total: number; - }; - }; - -export type ChatCompletionEvent = - | ChatCompletionChunkEvent - | ChatCompletionTokenCountEvent - | ChatCompletionMessageEvent; - -export type FunctionCallingMode = 'native' | 'simulated'; - -/** - * Request a completion from the LLM based on a prompt or conversation. - * - * @param {string} options.connectorId The ID of the connector to use - * @param {string} [options.system] A system message that defines the behavior of the LLM. - * @param {Message[]} options.message A list of messages that make up the conversation to be completed. - * @param {ToolChoice} [options.toolChoice] Force the LLM to call a (specific) tool, or no tool - * @param {Record} [options.tools] A map of tools that can be called by the LLM - */ -export type ChatCompleteAPI = ( - options: { - connectorId: string; - system?: string; - messages: Message[]; - functionCalling?: FunctionCallingMode; - } & TToolOptions -) => ChatCompletionResponse; diff --git a/x-pack/plugins/inference/common/chat_complete/is_chat_completion_chunk_event.ts b/x-pack/plugins/inference/common/chat_complete/is_chat_completion_chunk_event.ts deleted file mode 100644 index 1630d765ab81e..0000000000000 --- a/x-pack/plugins/inference/common/chat_complete/is_chat_completion_chunk_event.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ChatCompletionChunkEvent, ChatCompletionEvent, ChatCompletionEventType } from '.'; - -export function isChatCompletionChunkEvent( - event: ChatCompletionEvent -): event is ChatCompletionChunkEvent { - return event.type === ChatCompletionEventType.ChatCompletionChunk; -} diff --git a/x-pack/plugins/inference/common/chat_complete/is_chat_completion_event.ts b/x-pack/plugins/inference/common/chat_complete/is_chat_completion_event.ts deleted file mode 100644 index d4d9305cac94b..0000000000000 --- a/x-pack/plugins/inference/common/chat_complete/is_chat_completion_event.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ChatCompletionEvent, ChatCompletionEventType } from '.'; -import { InferenceTaskEvent } from '../inference_task'; - -export function isChatCompletionEvent(event: InferenceTaskEvent): event is ChatCompletionEvent { - return ( - event.type === ChatCompletionEventType.ChatCompletionChunk || - event.type === ChatCompletionEventType.ChatCompletionMessage || - event.type === ChatCompletionEventType.ChatCompletionTokenCount - ); -} diff --git a/x-pack/plugins/inference/common/chat_complete/is_chat_completion_message_event.ts b/x-pack/plugins/inference/common/chat_complete/is_chat_completion_message_event.ts deleted file mode 100644 index 172e55df9e4b4..0000000000000 --- a/x-pack/plugins/inference/common/chat_complete/is_chat_completion_message_event.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ChatCompletionEvent, ChatCompletionEventType, ChatCompletionMessageEvent } from '.'; -import type { ToolOptions } from './tools'; - -export function isChatCompletionMessageEvent>( - event: ChatCompletionEvent -): event is ChatCompletionMessageEvent { - return event.type === ChatCompletionEventType.ChatCompletionMessage; -} diff --git a/x-pack/plugins/inference/common/chat_complete/without_chunk_events.ts b/x-pack/plugins/inference/common/chat_complete/without_chunk_events.ts deleted file mode 100644 index 58e72e2c90903..0000000000000 --- a/x-pack/plugins/inference/common/chat_complete/without_chunk_events.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { filter, OperatorFunction } from 'rxjs'; -import { ChatCompletionChunkEvent, ChatCompletionEvent, ChatCompletionEventType } from '.'; - -export function withoutChunkEvents(): OperatorFunction< - T, - Exclude -> { - return filter( - (event): event is Exclude => - event.type !== ChatCompletionEventType.ChatCompletionChunk - ); -} diff --git a/x-pack/plugins/inference/common/chat_complete/without_token_count_events.ts b/x-pack/plugins/inference/common/chat_complete/without_token_count_events.ts deleted file mode 100644 index 1b7dbdb9c1372..0000000000000 --- a/x-pack/plugins/inference/common/chat_complete/without_token_count_events.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { filter, OperatorFunction } from 'rxjs'; -import { ChatCompletionEvent, ChatCompletionEventType, ChatCompletionTokenCountEvent } from '.'; - -export function withoutTokenCountEvents(): OperatorFunction< - T, - Exclude -> { - return filter( - (event): event is Exclude => - event.type !== ChatCompletionEventType.ChatCompletionTokenCount - ); -} diff --git a/x-pack/plugins/inference/common/connectors.ts b/x-pack/plugins/inference/common/connectors.ts index f7ad616741d79..ee628f520feff 100644 --- a/x-pack/plugins/inference/common/connectors.ts +++ b/x-pack/plugins/inference/common/connectors.ts @@ -22,7 +22,3 @@ export interface InferenceConnector { export function isSupportedConnectorType(id: string): id is InferenceConnectorType { return allSupportedConnectorTypes.includes(id as InferenceConnectorType); } - -export interface GetConnectorsResponseBody { - connectors: InferenceConnector[]; -} diff --git a/x-pack/plugins/inference/common/output/create_output_api.ts b/x-pack/plugins/inference/common/create_output_api.ts similarity index 85% rename from x-pack/plugins/inference/common/output/create_output_api.ts rename to x-pack/plugins/inference/common/create_output_api.ts index 848135beefb0f..450114c892cba 100644 --- a/x-pack/plugins/inference/common/output/create_output_api.ts +++ b/x-pack/plugins/inference/common/create_output_api.ts @@ -6,10 +6,16 @@ */ import { map } from 'rxjs'; -import { ChatCompleteAPI, ChatCompletionEventType, MessageRole } from '../chat_complete'; -import { withoutTokenCountEvents } from '../chat_complete/without_token_count_events'; -import { OutputAPI, OutputEvent, OutputEventType } from '.'; -import { ensureMultiTurn } from '../ensure_multi_turn'; +import { + OutputAPI, + OutputEvent, + OutputEventType, + ChatCompleteAPI, + ChatCompletionEventType, + MessageRole, + withoutTokenCountEvents, +} from '@kbn/inference-common'; +import { ensureMultiTurn } from './utils/ensure_multi_turn'; export function createOutputApi(chatCompleteApi: ChatCompleteAPI): OutputAPI { return (id, { connectorId, input, schema, system, previousMessages, functionCalling }) => { diff --git a/x-pack/plugins/inference/common/chat_complete/request.ts b/x-pack/plugins/inference/common/http_apis.ts similarity index 66% rename from x-pack/plugins/inference/common/chat_complete/request.ts rename to x-pack/plugins/inference/common/http_apis.ts index 1038e481a6260..c07fcd29b2211 100644 --- a/x-pack/plugins/inference/common/chat_complete/request.ts +++ b/x-pack/plugins/inference/common/http_apis.ts @@ -5,8 +5,8 @@ * 2.0. */ -import type { Message, FunctionCallingMode } from '.'; -import type { ToolOptions } from './tools'; +import type { FunctionCallingMode, Message, ToolOptions } from '@kbn/inference-common'; +import { InferenceConnector } from './connectors'; export type ChatCompleteRequestBody = { connectorId: string; @@ -15,3 +15,7 @@ export type ChatCompleteRequestBody = { messages: Message[]; functionCalling?: FunctionCallingMode; } & ToolOptions; + +export interface GetConnectorsResponseBody { + connectors: InferenceConnector[]; +} diff --git a/x-pack/plugins/inference/common/index.ts b/x-pack/plugins/inference/common/index.ts index 58c84a47c1804..19b24d53a389a 100644 --- a/x-pack/plugins/inference/common/index.ts +++ b/x-pack/plugins/inference/common/index.ts @@ -10,22 +10,8 @@ export { splitIntoCommands, } from './tasks/nl_to_esql/correct_common_esql_mistakes'; -export { isChatCompletionChunkEvent } from './chat_complete/is_chat_completion_chunk_event'; -export { isChatCompletionMessageEvent } from './chat_complete/is_chat_completion_message_event'; -export { isChatCompletionEvent } from './chat_complete/is_chat_completion_event'; +export { generateFakeToolCallId } from './utils/generate_fake_tool_call_id'; -export { isOutputUpdateEvent } from './output/is_output_update_event'; -export { isOutputCompleteEvent } from './output/is_output_complete_event'; -export { isOutputEvent } from './output/is_output_event'; +export { createOutputApi } from './create_output_api'; -export type { ToolSchema } from './chat_complete/tool_schema'; - -export { - type Message, - MessageRole, - type ToolMessage, - type AssistantMessage, - type UserMessage, -} from './chat_complete'; - -export { generateFakeToolCallId } from './chat_complete/generate_fake_tool_call_id'; +export type { ChatCompleteRequestBody, GetConnectorsResponseBody } from './http_apis'; diff --git a/x-pack/plugins/inference/common/output/index.ts b/x-pack/plugins/inference/common/output/index.ts deleted file mode 100644 index 0f7655f8f1cd4..0000000000000 --- a/x-pack/plugins/inference/common/output/index.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Observable } from 'rxjs'; -import { ServerSentEventBase } from '@kbn/sse-utils'; -import { FromToolSchema, ToolSchema } from '../chat_complete/tool_schema'; -import type { Message, FunctionCallingMode } from '../chat_complete'; - -export enum OutputEventType { - OutputUpdate = 'output', - OutputComplete = 'complete', -} - -type Output = Record | undefined | unknown; - -export type OutputUpdateEvent = ServerSentEventBase< - OutputEventType.OutputUpdate, - { - id: TId; - content: string; - } ->; - -export type OutputCompleteEvent< - TId extends string = string, - TOutput extends Output = Output -> = ServerSentEventBase< - OutputEventType.OutputComplete, - { - id: TId; - output: TOutput; - content: string; - } ->; - -export type OutputEvent = - | OutputUpdateEvent - | OutputCompleteEvent; - -/** - * Generate a response with the LLM for a prompt, optionally based on a schema. - * - * @param {string} id The id of the operation - * @param {string} options.connectorId The ID of the connector that is to be used. - * @param {string} options.input The prompt for the LLM. - * @param {string} options.messages Previous messages in a conversation. - * @param {ToolSchema} [options.schema] The schema the response from the LLM should adhere to. - */ -export type OutputAPI = < - TId extends string = string, - TOutputSchema extends ToolSchema | undefined = ToolSchema | undefined ->( - id: TId, - options: { - connectorId: string; - system?: string; - input: string; - schema?: TOutputSchema; - previousMessages?: Message[]; - functionCalling?: FunctionCallingMode; - } -) => Observable< - OutputEvent : undefined> ->; - -export function createOutputCompleteEvent( - id: TId, - output: TOutput, - content?: string -): OutputCompleteEvent { - return { - type: OutputEventType.OutputComplete, - id, - output, - content: content ?? '', - }; -} diff --git a/x-pack/plugins/inference/common/output/is_output_complete_event.ts b/x-pack/plugins/inference/common/output/is_output_complete_event.ts deleted file mode 100644 index bac3443b8258c..0000000000000 --- a/x-pack/plugins/inference/common/output/is_output_complete_event.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { OutputEvent, OutputEventType, OutputUpdateEvent } from '.'; - -export function isOutputCompleteEvent( - event: TOutputEvent -): event is Exclude { - return event.type === OutputEventType.OutputComplete; -} diff --git a/x-pack/plugins/inference/common/output/is_output_event.ts b/x-pack/plugins/inference/common/output/is_output_event.ts deleted file mode 100644 index dad2b0967a6ac..0000000000000 --- a/x-pack/plugins/inference/common/output/is_output_event.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { OutputEvent, OutputEventType } from '.'; -import type { InferenceTaskEvent } from '../inference_task'; - -export function isOutputEvent(event: InferenceTaskEvent): event is OutputEvent { - return ( - event.type === OutputEventType.OutputComplete || event.type === OutputEventType.OutputUpdate - ); -} diff --git a/x-pack/plugins/inference/common/output/without_output_update_events.ts b/x-pack/plugins/inference/common/output/without_output_update_events.ts deleted file mode 100644 index 38f26c8c8ece1..0000000000000 --- a/x-pack/plugins/inference/common/output/without_output_update_events.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { filter, OperatorFunction } from 'rxjs'; -import { OutputEvent, OutputEventType, OutputUpdateEvent } from '.'; - -export function withoutOutputUpdateEvents(): OperatorFunction< - T, - Exclude -> { - return filter( - (event): event is Exclude => event.type !== OutputEventType.OutputUpdate - ); -} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts index 15b050c3a3897..30e2c11adb6de 100644 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { validateQuery, getActions } from '@kbn/esql-validation-autocomplete'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; diff --git a/x-pack/plugins/inference/common/ensure_multi_turn.ts b/x-pack/plugins/inference/common/utils/ensure_multi_turn.ts similarity index 92% rename from x-pack/plugins/inference/common/ensure_multi_turn.ts rename to x-pack/plugins/inference/common/utils/ensure_multi_turn.ts index 8d222564f3e72..476ecec108e94 100644 --- a/x-pack/plugins/inference/common/ensure_multi_turn.ts +++ b/x-pack/plugins/inference/common/utils/ensure_multi_turn.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Message, MessageRole } from './chat_complete'; +import { Message, MessageRole } from '@kbn/inference-common'; function isUserMessage(message: Message): boolean { return message.role !== MessageRole.Assistant; diff --git a/x-pack/plugins/inference/common/chat_complete/generate_fake_tool_call_id.ts b/x-pack/plugins/inference/common/utils/generate_fake_tool_call_id.ts similarity index 100% rename from x-pack/plugins/inference/common/chat_complete/generate_fake_tool_call_id.ts rename to x-pack/plugins/inference/common/utils/generate_fake_tool_call_id.ts diff --git a/x-pack/plugins/inference/common/util/truncate_list.ts b/x-pack/plugins/inference/common/utils/truncate_list.ts similarity index 100% rename from x-pack/plugins/inference/common/util/truncate_list.ts rename to x-pack/plugins/inference/common/utils/truncate_list.ts diff --git a/x-pack/plugins/inference/public/chat_complete/index.ts b/x-pack/plugins/inference/public/chat_complete.ts similarity index 79% rename from x-pack/plugins/inference/public/chat_complete/index.ts rename to x-pack/plugins/inference/public/chat_complete.ts index e229f6c8f8eae..5319f7c31c381 100644 --- a/x-pack/plugins/inference/public/chat_complete/index.ts +++ b/x-pack/plugins/inference/public/chat_complete.ts @@ -7,9 +7,9 @@ import { from } from 'rxjs'; import type { HttpStart } from '@kbn/core/public'; -import type { ChatCompleteAPI } from '../../common/chat_complete'; -import type { ChatCompleteRequestBody } from '../../common/chat_complete/request'; -import { httpResponseIntoObservable } from '../util/http_response_into_observable'; +import type { ChatCompleteAPI } from '@kbn/inference-common'; +import type { ChatCompleteRequestBody } from '../common/http_apis'; +import { httpResponseIntoObservable } from './util/http_response_into_observable'; export function createChatCompleteApi({ http }: { http: HttpStart }): ChatCompleteAPI { return ({ connectorId, messages, system, toolChoice, tools, functionCalling }) => { diff --git a/x-pack/plugins/inference/public/index.ts b/x-pack/plugins/inference/public/index.ts index 82d36a7abe82d..4928242879b3b 100644 --- a/x-pack/plugins/inference/public/index.ts +++ b/x-pack/plugins/inference/public/index.ts @@ -4,9 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { PluginInitializer, PluginInitializerContext } from '@kbn/core/public'; -import { InferencePlugin } from './plugin'; +import type { PluginInitializer, PluginInitializerContext } from '@kbn/core/public'; import type { InferencePublicSetup, InferencePublicStart, @@ -14,6 +13,7 @@ import type { InferenceStartDependencies, ConfigSchema, } from './types'; +import { InferencePlugin } from './plugin'; export { httpResponseIntoObservable } from './util/http_response_into_observable'; diff --git a/x-pack/plugins/inference/public/plugin.tsx b/x-pack/plugins/inference/public/plugin.tsx index 13ef4a0373845..f1023bc9c2546 100644 --- a/x-pack/plugins/inference/public/plugin.tsx +++ b/x-pack/plugins/inference/public/plugin.tsx @@ -7,8 +7,8 @@ import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; import type { Logger } from '@kbn/logging'; -import { createOutputApi } from '../common/output/create_output_api'; -import type { GetConnectorsResponseBody } from '../common/connectors'; +import { createOutputApi } from '../common/create_output_api'; +import type { GetConnectorsResponseBody } from '../common/http_apis'; import { createChatCompleteApi } from './chat_complete'; import type { ConfigSchema, @@ -41,10 +41,11 @@ export class InferencePlugin start(coreStart: CoreStart, pluginsStart: InferenceStartDependencies): InferencePublicStart { const chatComplete = createChatCompleteApi({ http: coreStart.http }); + const output = createOutputApi(chatComplete); return { chatComplete, - output: createOutputApi(chatComplete), + output, getConnectors: async () => { const res = await coreStart.http.get( '/internal/inference/connectors' diff --git a/x-pack/plugins/inference/public/types.ts b/x-pack/plugins/inference/public/types.ts index df80256679ab4..735abfb5459a0 100644 --- a/x-pack/plugins/inference/public/types.ts +++ b/x-pack/plugins/inference/public/types.ts @@ -4,9 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { ChatCompleteAPI } from '../common/chat_complete'; + +import type { ChatCompleteAPI, OutputAPI } from '@kbn/inference-common'; import type { InferenceConnector } from '../common/connectors'; -import type { OutputAPI } from '../common/output'; /* eslint-disable @typescript-eslint/no-empty-interface*/ diff --git a/x-pack/plugins/inference/public/util/create_observable_from_http_response.ts b/x-pack/plugins/inference/public/util/create_observable_from_http_response.ts index 09e9b9b2d5f5e..862986ce1c73a 100644 --- a/x-pack/plugins/inference/public/util/create_observable_from_http_response.ts +++ b/x-pack/plugins/inference/public/util/create_observable_from_http_response.ts @@ -4,9 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { createParser } from 'eventsource-parser'; import { Observable, throwError } from 'rxjs'; -import { createInferenceInternalError } from '../../common/errors'; +import { createInferenceInternalError } from '@kbn/inference-common'; export interface StreamedHttpResponse { response?: { body: ReadableStream | null | undefined }; diff --git a/x-pack/plugins/inference/public/util/http_response_into_observable.test.ts b/x-pack/plugins/inference/public/util/http_response_into_observable.test.ts index 2b99b6f1db6f5..a0964da025af8 100644 --- a/x-pack/plugins/inference/public/util/http_response_into_observable.test.ts +++ b/x-pack/plugins/inference/public/util/http_response_into_observable.test.ts @@ -7,10 +7,12 @@ import { lastValueFrom, of, toArray } from 'rxjs'; import { httpResponseIntoObservable } from './http_response_into_observable'; +import { + ChatCompletionEventType, + InferenceTaskEventType, + InferenceTaskErrorCode, +} from '@kbn/inference-common'; import type { StreamedHttpResponse } from './create_observable_from_http_response'; -import { ChatCompletionEventType } from '../../common/chat_complete'; -import { InferenceTaskEventType } from '../../common/inference_task'; -import { InferenceTaskErrorCode } from '../../common/errors'; function toSse(...events: Array>) { return events.map((event) => new TextEncoder().encode(`data: ${JSON.stringify(event)}\n\n`)); diff --git a/x-pack/plugins/inference/public/util/http_response_into_observable.ts b/x-pack/plugins/inference/public/util/http_response_into_observable.ts index c63a7bcb3cd15..0aab09cdebe0c 100644 --- a/x-pack/plugins/inference/public/util/http_response_into_observable.ts +++ b/x-pack/plugins/inference/public/util/http_response_into_observable.ts @@ -10,8 +10,9 @@ import { createInferenceInternalError, InferenceTaskError, InferenceTaskErrorEvent, -} from '../../common/errors'; -import { InferenceTaskEvent, InferenceTaskEventType } from '../../common/inference_task'; + InferenceTaskEvent, + InferenceTaskEventType, +} from '@kbn/inference-common'; import { createObservableFromHttpResponse, StreamedHttpResponse, diff --git a/x-pack/plugins/inference/scripts/evaluation/evaluation_client.ts b/x-pack/plugins/inference/scripts/evaluation/evaluation_client.ts index acf2fece1d0ff..d35c214542255 100644 --- a/x-pack/plugins/inference/scripts/evaluation/evaluation_client.ts +++ b/x-pack/plugins/inference/scripts/evaluation/evaluation_client.ts @@ -7,8 +7,7 @@ import { remove } from 'lodash'; import { lastValueFrom } from 'rxjs'; -import type { OutputAPI } from '../../common/output'; -import { withoutOutputUpdateEvents } from '../../common/output/without_output_update_events'; +import { type OutputAPI, withoutOutputUpdateEvents } from '@kbn/inference-common'; import type { EvaluationResult } from './types'; export interface InferenceEvaluationClient { diff --git a/x-pack/plugins/inference/scripts/evaluation/scenarios/esql/index.spec.ts b/x-pack/plugins/inference/scripts/evaluation/scenarios/esql/index.spec.ts index 3aeca67030366..d9071b3f0ae3f 100644 --- a/x-pack/plugins/inference/scripts/evaluation/scenarios/esql/index.spec.ts +++ b/x-pack/plugins/inference/scripts/evaluation/scenarios/esql/index.spec.ts @@ -8,11 +8,12 @@ /// import expect from '@kbn/expect'; +import type { Logger } from '@kbn/logging'; import { firstValueFrom, lastValueFrom, filter } from 'rxjs'; +import { isOutputCompleteEvent } from '@kbn/inference-common'; import { naturalLanguageToEsql } from '../../../../server/tasks/nl_to_esql'; import { chatClient, evaluationClient, logger } from '../../services'; import { EsqlDocumentBase } from '../../../../server/tasks/nl_to_esql/doc_base'; -import { isOutputCompleteEvent } from '../../../../common'; interface TestCase { title: string; @@ -40,7 +41,7 @@ const callNaturalLanguageToEsql = async (question: string) => { debug: (source) => { logger.debug(typeof source === 'function' ? source() : source); }, - }, + } as Logger, }) ); }; diff --git a/x-pack/plugins/inference/scripts/load_esql_docs/utils/output_executor.ts b/x-pack/plugins/inference/scripts/load_esql_docs/utils/output_executor.ts index 6697446f93cec..62cfd8f877e3f 100644 --- a/x-pack/plugins/inference/scripts/load_esql_docs/utils/output_executor.ts +++ b/x-pack/plugins/inference/scripts/load_esql_docs/utils/output_executor.ts @@ -6,7 +6,7 @@ */ import { lastValueFrom } from 'rxjs'; -import type { OutputAPI } from '../../../common/output'; +import type { OutputAPI } from '@kbn/inference-common'; export interface Prompt { system?: string; diff --git a/x-pack/plugins/inference/scripts/util/cli_options.ts b/x-pack/plugins/inference/scripts/util/cli_options.ts index 13bac131922ff..8bbb6dabe406e 100644 --- a/x-pack/plugins/inference/scripts/util/cli_options.ts +++ b/x-pack/plugins/inference/scripts/util/cli_options.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { format, parse } from 'url'; import { readKibanaConfig } from './read_kibana_config'; diff --git a/x-pack/plugins/inference/scripts/util/kibana_client.ts b/x-pack/plugins/inference/scripts/util/kibana_client.ts index ca26ef76b2c72..b599ab81a4af4 100644 --- a/x-pack/plugins/inference/scripts/util/kibana_client.ts +++ b/x-pack/plugins/inference/scripts/util/kibana_client.ts @@ -13,18 +13,19 @@ import { from, map, switchMap, throwError } from 'rxjs'; import { UrlObject, format, parse } from 'url'; import { inspect } from 'util'; import { isReadable } from 'stream'; -import type { ChatCompleteAPI, ChatCompletionEvent } from '../../common/chat_complete'; -import { ChatCompleteRequestBody } from '../../common/chat_complete/request'; -import type { InferenceConnector } from '../../common/connectors'; import { + ChatCompleteAPI, + OutputAPI, + ChatCompletionEvent, InferenceTaskError, InferenceTaskErrorEvent, + InferenceTaskEventType, createInferenceInternalError, -} from '../../common/errors'; -import { InferenceTaskEventType } from '../../common/inference_task'; -import type { OutputAPI } from '../../common/output'; -import { createOutputApi } from '../../common/output/create_output_api'; -import { withoutOutputUpdateEvents } from '../../common/output/without_output_update_events'; + withoutOutputUpdateEvents, +} from '@kbn/inference-common'; +import type { ChatCompleteRequestBody } from '../../common/http_apis'; +import type { InferenceConnector } from '../../common/connectors'; +import { createOutputApi } from '../../common/create_output_api'; import { eventSourceStreamIntoObservable } from '../../server/util/event_source_stream_into_observable'; // eslint-disable-next-line spaced-comment diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/bedrock_claude_adapter.test.ts b/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/bedrock_claude_adapter.test.ts index d34b8693cb85f..ca6f60dd45a55 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/bedrock_claude_adapter.test.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/bedrock_claude_adapter.test.ts @@ -8,8 +8,7 @@ import { PassThrough } from 'stream'; import { loggerMock } from '@kbn/logging-mocks'; import type { InferenceExecutor } from '../../utils/inference_executor'; -import { MessageRole } from '../../../../common/chat_complete'; -import { ToolChoiceType } from '../../../../common/chat_complete/tools'; +import { MessageRole, ToolChoiceType } from '@kbn/inference-common'; import { bedrockClaudeAdapter } from './bedrock_claude_adapter'; import { addNoToolUsageDirective } from './prompts'; diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/bedrock_claude_adapter.ts b/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/bedrock_claude_adapter.ts index a0b48e6fc8631..e73d9c9344c98 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/bedrock_claude_adapter.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/bedrock_claude_adapter.ts @@ -7,10 +7,15 @@ import { filter, from, map, switchMap, tap } from 'rxjs'; import { Readable } from 'stream'; +import { + Message, + MessageRole, + createInferenceInternalError, + ToolChoiceType, + ToolSchemaType, + type ToolOptions, +} from '@kbn/inference-common'; import { parseSerdeChunkMessage } from './serde_utils'; -import { Message, MessageRole } from '../../../../common/chat_complete'; -import { createInferenceInternalError } from '../../../../common/errors'; -import { ToolChoiceType, type ToolOptions } from '../../../../common/chat_complete/tools'; import { InferenceConnectorAdapter } from '../../types'; import type { BedRockMessage, BedrockToolChoice } from './types'; import { @@ -19,7 +24,6 @@ import { } from './serde_eventstream_into_observable'; import { processCompletionChunks } from './process_completion_chunks'; import { addNoToolUsageDirective } from './prompts'; -import { ToolSchemaType } from '../../../../common/chat_complete/tool_schema'; export const bedrockClaudeAdapter: InferenceConnectorAdapter = { chatComplete: ({ executor, system, messages, toolChoice, tools }) => { diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/process_completion_chunks.ts b/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/process_completion_chunks.ts index 5513cc9028ac9..8a5c9805ddf63 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/process_completion_chunks.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/process_completion_chunks.ts @@ -11,7 +11,7 @@ import { ChatCompletionTokenCountEvent, ChatCompletionChunkToolCall, ChatCompletionEventType, -} from '../../../../common/chat_complete'; +} from '@kbn/inference-common'; import type { CompletionChunk, MessageStopChunk } from './types'; export function processCompletionChunks() { diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/serde_eventstream_into_observable.ts b/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/serde_eventstream_into_observable.ts index 24a245ab2efcc..5ab264750e5a9 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/serde_eventstream_into_observable.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/bedrock/serde_eventstream_into_observable.ts @@ -11,7 +11,7 @@ import { identity } from 'lodash'; import { Observable } from 'rxjs'; import { Readable } from 'stream'; import { Message } from '@smithy/types'; -import { createInferenceInternalError } from '../../../../common/errors'; +import { createInferenceInternalError } from '@kbn/inference-common'; interface ModelStreamErrorException { name: 'ModelStreamErrorException'; diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/gemini/gemini_adapter.test.ts b/x-pack/plugins/inference/server/chat_complete/adapters/gemini/gemini_adapter.test.ts index a9f4305a3c532..c3410b2af3623 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/gemini/gemini_adapter.test.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/gemini/gemini_adapter.test.ts @@ -11,8 +11,7 @@ import { noop, tap, lastValueFrom, toArray, Subject } from 'rxjs'; import { loggerMock } from '@kbn/logging-mocks'; import type { InferenceExecutor } from '../../utils/inference_executor'; import { observableIntoEventSourceStream } from '../../../util/observable_into_event_source_stream'; -import { MessageRole } from '../../../../common/chat_complete'; -import { ToolChoiceType } from '../../../../common/chat_complete/tools'; +import { MessageRole, ToolChoiceType } from '@kbn/inference-common'; import { geminiAdapter } from './gemini_adapter'; describe('geminiAdapter', () => { diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/gemini/gemini_adapter.ts b/x-pack/plugins/inference/server/chat_complete/adapters/gemini/gemini_adapter.ts index 2e86adcc82a85..80d0439449066 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/gemini/gemini_adapter.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/gemini/gemini_adapter.ts @@ -8,10 +8,15 @@ import * as Gemini from '@google/generative-ai'; import { from, map, switchMap } from 'rxjs'; import { Readable } from 'stream'; +import { + Message, + MessageRole, + ToolChoiceType, + ToolOptions, + ToolSchema, + ToolSchemaType, +} from '@kbn/inference-common'; import type { InferenceConnectorAdapter } from '../../types'; -import { Message, MessageRole } from '../../../../common/chat_complete'; -import { ToolChoiceType, ToolOptions } from '../../../../common/chat_complete/tools'; -import type { ToolSchema, ToolSchemaType } from '../../../../common/chat_complete/tool_schema'; import { eventSourceStreamIntoObservable } from '../../../util/event_source_stream_into_observable'; import { processVertexStream } from './process_vertex_stream'; import type { GenerateContentResponseChunk, GeminiMessage, GeminiToolConfig } from './types'; diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/gemini/process_vertex_stream.test.ts b/x-pack/plugins/inference/server/chat_complete/adapters/gemini/process_vertex_stream.test.ts index 78e0da0a384b8..8613799846e3b 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/gemini/process_vertex_stream.test.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/gemini/process_vertex_stream.test.ts @@ -6,7 +6,7 @@ */ import { TestScheduler } from 'rxjs/testing'; -import { ChatCompletionEventType } from '../../../../common/chat_complete'; +import { ChatCompletionEventType } from '@kbn/inference-common'; import { processVertexStream } from './process_vertex_stream'; import type { GenerateContentResponseChunk } from './types'; diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/gemini/process_vertex_stream.ts b/x-pack/plugins/inference/server/chat_complete/adapters/gemini/process_vertex_stream.ts index e2a6c74a0447f..3081317882c65 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/gemini/process_vertex_stream.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/gemini/process_vertex_stream.ts @@ -10,7 +10,7 @@ import { ChatCompletionChunkEvent, ChatCompletionTokenCountEvent, ChatCompletionEventType, -} from '../../../../common/chat_complete'; +} from '@kbn/inference-common'; import { generateFakeToolCallId } from '../../../../common'; import type { GenerateContentResponseChunk } from './types'; diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/openai/openai_adapter.test.ts b/x-pack/plugins/inference/server/chat_complete/adapters/openai/openai_adapter.test.ts index 813e88760de8c..ff1bbc71a876d 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/openai/openai_adapter.test.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/openai/openai_adapter.test.ts @@ -12,7 +12,7 @@ import { pick } from 'lodash'; import { lastValueFrom, Subject, toArray } from 'rxjs'; import type { Logger } from '@kbn/logging'; import { loggerMock } from '@kbn/logging-mocks'; -import { ChatCompletionEventType, MessageRole } from '../../../../common/chat_complete'; +import { ChatCompletionEventType, MessageRole } from '@kbn/inference-common'; import { observableIntoEventSourceStream } from '../../../util/observable_into_event_source_stream'; import { InferenceExecutor } from '../../utils/inference_executor'; import { openAIAdapter } from '.'; diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/openai/openai_adapter.ts b/x-pack/plugins/inference/server/chat_complete/adapters/openai/openai_adapter.ts index f1821be4d4d57..121ba96ab115a 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/openai/openai_adapter.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/openai/openai_adapter.ts @@ -20,10 +20,10 @@ import { ChatCompletionEventType, Message, MessageRole, -} from '../../../../common/chat_complete'; -import type { ToolOptions } from '../../../../common/chat_complete/tools'; -import { createTokenLimitReachedError } from '../../../../common/chat_complete/errors'; -import { createInferenceInternalError } from '../../../../common/errors'; + ToolOptions, + createInferenceInternalError, +} from '@kbn/inference-common'; +import { createTokenLimitReachedError } from '../../errors'; import { eventSourceStreamIntoObservable } from '../../../util/event_source_stream_into_observable'; import type { InferenceConnectorAdapter } from '../../types'; import { diff --git a/x-pack/plugins/inference/server/chat_complete/api.ts b/x-pack/plugins/inference/server/chat_complete/api.ts index ca9e61ff3627f..62a1ea8b26146 100644 --- a/x-pack/plugins/inference/server/chat_complete/api.ts +++ b/x-pack/plugins/inference/server/chat_complete/api.ts @@ -9,8 +9,11 @@ import { last } from 'lodash'; import { defer, switchMap, throwError } from 'rxjs'; import type { Logger } from '@kbn/logging'; import type { KibanaRequest } from '@kbn/core-http-server'; -import type { ChatCompleteAPI, ChatCompletionResponse } from '../../common/chat_complete'; -import { createInferenceRequestError } from '../../common/errors'; +import { + type ChatCompleteAPI, + type ChatCompletionResponse, + createInferenceRequestError, +} from '@kbn/inference-common'; import type { InferenceStartDependencies } from '../types'; import { getConnectorById } from '../util/get_connector_by_id'; import { getInferenceAdapter } from './adapters'; diff --git a/x-pack/plugins/inference/server/chat_complete/errors.ts b/x-pack/plugins/inference/server/chat_complete/errors.ts new file mode 100644 index 0000000000000..a830f57fec559 --- /dev/null +++ b/x-pack/plugins/inference/server/chat_complete/errors.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { InferenceTaskError, type UnvalidatedToolCall } from '@kbn/inference-common'; +import { i18n } from '@kbn/i18n'; +import { + ChatCompletionErrorCode, + ChatCompletionTokenLimitReachedError, + ChatCompletionToolNotFoundError, + ChatCompletionToolValidationError, +} from '@kbn/inference-common/src/chat_complete/errors'; + +export function createTokenLimitReachedError( + tokenLimit?: number, + tokenCount?: number +): ChatCompletionTokenLimitReachedError { + return new InferenceTaskError( + ChatCompletionErrorCode.TokenLimitReachedError, + i18n.translate('xpack.inference.chatCompletionError.tokenLimitReachedError', { + defaultMessage: `Token limit reached. Token limit is {tokenLimit}, but the current conversation has {tokenCount} tokens.`, + values: { tokenLimit, tokenCount }, + }), + { tokenLimit, tokenCount } + ); +} + +export function createToolNotFoundError(name: string): ChatCompletionToolNotFoundError { + return new InferenceTaskError( + ChatCompletionErrorCode.ToolNotFoundError, + `Tool ${name} called but was not available`, + { + name, + } + ); +} + +export function createToolValidationError( + message: string, + meta: { + name?: string; + arguments?: string; + errorsText?: string; + toolCalls?: UnvalidatedToolCall[]; + } +): ChatCompletionToolValidationError { + return new InferenceTaskError(ChatCompletionErrorCode.ToolValidationError, message, meta); +} diff --git a/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/get_system_instructions.ts b/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/get_system_instructions.ts index abfc48dfa2ef2..c4adfae7e3f19 100644 --- a/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/get_system_instructions.ts +++ b/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/get_system_instructions.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { ToolDefinition } from '@kbn/inference-common'; import { TOOL_USE_END, TOOL_USE_START } from './constants'; -import { ToolDefinition } from '../../../common/chat_complete/tools'; export function getSystemMessageInstructions({ tools, diff --git a/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/parse_inline_function_calls.ts b/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/parse_inline_function_calls.ts index 3436d7a7edac5..73d03ee2f00af 100644 --- a/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/parse_inline_function_calls.ts +++ b/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/parse_inline_function_calls.ts @@ -8,11 +8,11 @@ import { Observable } from 'rxjs'; import { Logger } from '@kbn/logging'; import { + createInferenceInternalError, ChatCompletionChunkEvent, ChatCompletionTokenCountEvent, ChatCompletionEventType, -} from '../../../common/chat_complete'; -import { createInferenceInternalError } from '../../../common/errors'; +} from '@kbn/inference-common'; import { TOOL_USE_END, TOOL_USE_START } from './constants'; function matchOnSignalStart(buffer: string) { diff --git a/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/wrap_with_simulated_function_calling.ts b/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/wrap_with_simulated_function_calling.ts index d8cfc373b66cc..4eb6cfd8d50e1 100644 --- a/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/wrap_with_simulated_function_calling.ts +++ b/x-pack/plugins/inference/server/chat_complete/simulated_function_calling/wrap_with_simulated_function_calling.ts @@ -5,9 +5,16 @@ * 2.0. */ -import { AssistantMessage, Message, ToolMessage, UserMessage } from '../../../common'; -import { MessageRole } from '../../../common/chat_complete'; -import { ToolChoice, ToolChoiceType, ToolDefinition } from '../../../common/chat_complete/tools'; +import { + MessageRole, + AssistantMessage, + Message, + ToolMessage, + UserMessage, + ToolChoice, + ToolChoiceType, + ToolDefinition, +} from '@kbn/inference-common'; import { TOOL_USE_END, TOOL_USE_START } from './constants'; import { getSystemMessageInstructions } from './get_system_instructions'; diff --git a/x-pack/plugins/inference/server/chat_complete/types.ts b/x-pack/plugins/inference/server/chat_complete/types.ts index 394fe370240ef..64cc542ff6119 100644 --- a/x-pack/plugins/inference/server/chat_complete/types.ts +++ b/x-pack/plugins/inference/server/chat_complete/types.ts @@ -12,8 +12,8 @@ import type { ChatCompletionTokenCountEvent, FunctionCallingMode, Message, -} from '../../common/chat_complete'; -import type { ToolOptions } from '../../common/chat_complete/tools'; + ToolOptions, +} from '@kbn/inference-common'; import type { InferenceExecutor } from './utils'; /** diff --git a/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.test.ts b/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.test.ts index 0c5552a0113b8..c6e5b032120a3 100644 --- a/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.test.ts +++ b/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.test.ts @@ -4,13 +4,14 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { lastValueFrom, of } from 'rxjs'; import { + ToolChoiceType, ChatCompletionChunkEvent, ChatCompletionEventType, ChatCompletionTokenCountEvent, -} from '../../../common/chat_complete'; -import { ToolChoiceType } from '../../../common/chat_complete/tools'; +} from '@kbn/inference-common'; import { chunksIntoMessage } from './chunks_into_message'; import type { Logger } from '@kbn/logging'; diff --git a/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.ts b/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.ts index 902289182a37a..fe9b745f442fc 100644 --- a/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.ts +++ b/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.ts @@ -7,14 +7,15 @@ import { last, map, merge, OperatorFunction, scan, share } from 'rxjs'; import type { Logger } from '@kbn/logging'; -import type { UnvalidatedToolCall, ToolOptions } from '../../../common/chat_complete/tools'; import { + UnvalidatedToolCall, + ToolOptions, ChatCompletionChunkEvent, ChatCompletionEventType, ChatCompletionMessageEvent, ChatCompletionTokenCountEvent, -} from '../../../common/chat_complete'; -import { withoutTokenCountEvents } from '../../../common/chat_complete/without_token_count_events'; + withoutTokenCountEvents, +} from '@kbn/inference-common'; import { validateToolCalls } from '../../util/validate_tool_calls'; export function chunksIntoMessage({ diff --git a/x-pack/plugins/inference/server/index.ts b/x-pack/plugins/inference/server/index.ts index d02dfec733941..60ce870020feb 100644 --- a/x-pack/plugins/inference/server/index.ts +++ b/x-pack/plugins/inference/server/index.ts @@ -4,25 +4,22 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import type { PluginInitializer, PluginInitializerContext } from '@kbn/core/server'; import type { InferenceConfig } from './config'; -import { InferencePlugin } from './plugin'; import type { InferenceServerSetup, InferenceServerStart, InferenceSetupDependencies, InferenceStartDependencies, } from './types'; - -export { withoutTokenCountEvents } from '../common/chat_complete/without_token_count_events'; -export { withoutChunkEvents } from '../common/chat_complete/without_chunk_events'; -export { withoutOutputUpdateEvents } from '../common/output/without_output_update_events'; +import { InferencePlugin } from './plugin'; export type { InferenceClient } from './types'; -export { naturalLanguageToEsql } from './tasks/nl_to_esql'; - export type { InferenceServerSetup, InferenceServerStart }; +export { naturalLanguageToEsql } from './tasks/nl_to_esql'; + export const plugin: PluginInitializer< InferenceServerSetup, InferenceServerStart, diff --git a/x-pack/plugins/inference/server/inference_client/index.ts b/x-pack/plugins/inference/server/inference_client/index.ts index 25208bebc54bb..03da0e3da200f 100644 --- a/x-pack/plugins/inference/server/inference_client/index.ts +++ b/x-pack/plugins/inference/server/inference_client/index.ts @@ -9,7 +9,7 @@ import type { Logger } from '@kbn/logging'; import type { KibanaRequest } from '@kbn/core-http-server'; import type { InferenceClient, InferenceStartDependencies } from '../types'; import { createChatCompleteApi } from '../chat_complete'; -import { createOutputApi } from '../../common/output/create_output_api'; +import { createOutputApi } from '../../common/create_output_api'; import { getConnectorById } from '../util/get_connector_by_id'; export function createInferenceClient({ diff --git a/x-pack/plugins/inference/server/routes/chat_complete.ts b/x-pack/plugins/inference/server/routes/chat_complete.ts index fdf33fbf0af82..d4d0d012a78cd 100644 --- a/x-pack/plugins/inference/server/routes/chat_complete.ts +++ b/x-pack/plugins/inference/server/routes/chat_complete.ts @@ -7,9 +7,8 @@ import { schema, Type } from '@kbn/config-schema'; import type { CoreSetup, IRouter, Logger, RequestHandlerContext } from '@kbn/core/server'; -import { MessageRole } from '../../common/chat_complete'; -import type { ChatCompleteRequestBody } from '../../common/chat_complete/request'; -import { ToolCall, ToolChoiceType } from '../../common/chat_complete/tools'; +import { MessageRole, ToolCall, ToolChoiceType } from '@kbn/inference-common'; +import type { ChatCompleteRequestBody } from '../../common/http_apis'; import { createInferenceClient } from '../inference_client'; import { InferenceServerStart, InferenceStartDependencies } from '../types'; import { observableIntoEventSourceStream } from '../util/observable_into_event_source_stream'; diff --git a/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/generate_esql.ts b/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/generate_esql.ts index d31952e2f5252..26a8fb63ce013 100644 --- a/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/generate_esql.ts +++ b/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/generate_esql.ts @@ -7,21 +7,23 @@ import { Observable, map, merge, of, switchMap } from 'rxjs'; import type { Logger } from '@kbn/logging'; -import { ToolCall, ToolOptions } from '../../../../common/chat_complete/tools'; import { - correctCommonEsqlMistakes, - generateFakeToolCallId, + ToolCall, + ToolOptions, + withoutTokenCountEvents, isChatCompletionMessageEvent, Message, MessageRole, -} from '../../../../common'; -import { InferenceClient, withoutTokenCountEvents } from '../../..'; -import { OutputCompleteEvent, OutputEventType } from '../../../../common/output'; + OutputCompleteEvent, + OutputEventType, + FunctionCallingMode, +} from '@kbn/inference-common'; +import { correctCommonEsqlMistakes, generateFakeToolCallId } from '../../../../common'; +import { InferenceClient } from '../../..'; import { INLINE_ESQL_QUERY_REGEX } from '../../../../common/tasks/nl_to_esql/constants'; import { EsqlDocumentBase } from '../doc_base'; import { requestDocumentationSchema } from './shared'; import type { NlToEsqlTaskEvent } from '../types'; -import type { FunctionCallingMode } from '../../../../common/chat_complete'; export const generateEsqlTask = ({ chatCompleteApi, diff --git a/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/request_documentation.ts b/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/request_documentation.ts index d4eb3060f59bb..aea428208be1d 100644 --- a/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/request_documentation.ts +++ b/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/request_documentation.ts @@ -6,11 +6,15 @@ */ import { isEmpty } from 'lodash'; -import { InferenceClient, withoutOutputUpdateEvents } from '../../..'; -import { Message } from '../../../../common'; -import { ToolChoiceType, ToolOptions } from '../../../../common/chat_complete/tools'; +import { + ToolChoiceType, + ToolOptions, + Message, + withoutOutputUpdateEvents, + FunctionCallingMode, +} from '@kbn/inference-common'; +import { InferenceClient } from '../../..'; import { requestDocumentationSchema } from './shared'; -import type { FunctionCallingMode } from '../../../../common/chat_complete'; export const requestDocumentation = ({ outputApi, diff --git a/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/shared.ts b/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/shared.ts index f0fc796173b23..60114188ea37f 100644 --- a/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/shared.ts +++ b/x-pack/plugins/inference/server/tasks/nl_to_esql/actions/shared.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ToolSchema } from '../../../../common'; +import { ToolSchema } from '@kbn/inference-common'; export const requestDocumentationSchema = { type: 'object', diff --git a/x-pack/plugins/inference/server/tasks/nl_to_esql/task.ts b/x-pack/plugins/inference/server/tasks/nl_to_esql/task.ts index e0c5a838ea148..56c48b73f4994 100644 --- a/x-pack/plugins/inference/server/tasks/nl_to_esql/task.ts +++ b/x-pack/plugins/inference/server/tasks/nl_to_esql/task.ts @@ -7,8 +7,7 @@ import { once } from 'lodash'; import { Observable, from, switchMap } from 'rxjs'; -import { Message, MessageRole } from '../../../common/chat_complete'; -import type { ToolOptions } from '../../../common/chat_complete/tools'; +import { Message, MessageRole, ToolOptions } from '@kbn/inference-common'; import { EsqlDocumentBase } from './doc_base'; import { requestDocumentation, generateEsqlTask } from './actions'; import { NlToEsqlTaskParams, NlToEsqlTaskEvent } from './types'; diff --git a/x-pack/plugins/inference/server/tasks/nl_to_esql/types.ts b/x-pack/plugins/inference/server/tasks/nl_to_esql/types.ts index a0bcd635081ea..ce45d9a15e4b3 100644 --- a/x-pack/plugins/inference/server/tasks/nl_to_esql/types.ts +++ b/x-pack/plugins/inference/server/tasks/nl_to_esql/types.ts @@ -11,9 +11,9 @@ import type { ChatCompletionMessageEvent, FunctionCallingMode, Message, -} from '../../../common/chat_complete'; -import type { ToolOptions } from '../../../common/chat_complete/tools'; -import type { OutputCompleteEvent } from '../../../common/output'; + ToolOptions, + OutputCompleteEvent, +} from '@kbn/inference-common'; import type { InferenceClient } from '../../types'; export type NlToEsqlTaskEvent = diff --git a/x-pack/plugins/inference/server/types.ts b/x-pack/plugins/inference/server/types.ts index 20679ffd4cedf..f538448372e36 100644 --- a/x-pack/plugins/inference/server/types.ts +++ b/x-pack/plugins/inference/server/types.ts @@ -10,9 +10,8 @@ import type { PluginSetupContract as ActionsPluginSetup, } from '@kbn/actions-plugin/server'; import type { KibanaRequest } from '@kbn/core-http-server'; -import { ChatCompleteAPI } from '../common/chat_complete'; +import { ChatCompleteAPI, OutputAPI } from '@kbn/inference-common'; import { InferenceConnector } from '../common/connectors'; -import { OutputAPI } from '../common/output'; /* eslint-disable @typescript-eslint/no-empty-interface*/ diff --git a/x-pack/plugins/inference/server/util/get_connector_by_id.ts b/x-pack/plugins/inference/server/util/get_connector_by_id.ts index 3fd77630ad3d1..1dbf9a6f0d75e 100644 --- a/x-pack/plugins/inference/server/util/get_connector_by_id.ts +++ b/x-pack/plugins/inference/server/util/get_connector_by_id.ts @@ -6,8 +6,8 @@ */ import type { ActionsClient, ActionResult as ActionConnector } from '@kbn/actions-plugin/server'; +import { createInferenceRequestError } from '@kbn/inference-common'; import { isSupportedConnectorType, type InferenceConnector } from '../../common/connectors'; -import { createInferenceRequestError } from '../../common/errors'; /** * Retrieves a connector given the provided `connectorId` and asserts it's an inference connector diff --git a/x-pack/plugins/inference/server/util/observable_into_event_source_stream.test.ts b/x-pack/plugins/inference/server/util/observable_into_event_source_stream.test.ts index ed5466ba1e027..8ece214c27599 100644 --- a/x-pack/plugins/inference/server/util/observable_into_event_source_stream.test.ts +++ b/x-pack/plugins/inference/server/util/observable_into_event_source_stream.test.ts @@ -8,7 +8,7 @@ import { createParser } from 'eventsource-parser'; import { partition } from 'lodash'; import { merge, of, throwError } from 'rxjs'; -import type { InferenceTaskEvent } from '../../common/inference_task'; +import type { InferenceTaskEvent } from '@kbn/inference-common'; import { observableIntoEventSourceStream } from './observable_into_event_source_stream'; import type { Logger } from '@kbn/logging'; diff --git a/x-pack/plugins/inference/server/util/observable_into_event_source_stream.ts b/x-pack/plugins/inference/server/util/observable_into_event_source_stream.ts index bcd1ef60ce1da..62eae6609441f 100644 --- a/x-pack/plugins/inference/server/util/observable_into_event_source_stream.ts +++ b/x-pack/plugins/inference/server/util/observable_into_event_source_stream.ts @@ -9,11 +9,11 @@ import { catchError, map, Observable, of } from 'rxjs'; import { PassThrough } from 'stream'; import type { Logger } from '@kbn/logging'; import { + InferenceTaskEventType, InferenceTaskErrorCode, InferenceTaskErrorEvent, isInferenceError, -} from '../../common/errors'; -import { InferenceTaskEventType } from '../../common/inference_task'; +} from '@kbn/inference-common'; export function observableIntoEventSourceStream( source$: Observable, diff --git a/x-pack/plugins/inference/server/util/validate_tool_calls.test.ts b/x-pack/plugins/inference/server/util/validate_tool_calls.test.ts index 96bf202fa236b..57b030771c6c0 100644 --- a/x-pack/plugins/inference/server/util/validate_tool_calls.test.ts +++ b/x-pack/plugins/inference/server/util/validate_tool_calls.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { isToolValidationError } from '../../common/chat_complete/errors'; -import { ToolChoiceType } from '../../common/chat_complete/tools'; +import { ToolChoiceType, isToolValidationError } from '@kbn/inference-common'; import { validateToolCalls } from './validate_tool_calls'; describe('validateToolCalls', () => { diff --git a/x-pack/plugins/inference/server/util/validate_tool_calls.ts b/x-pack/plugins/inference/server/util/validate_tool_calls.ts index 5d1e659bc36f5..ffc2482774b23 100644 --- a/x-pack/plugins/inference/server/util/validate_tool_calls.ts +++ b/x-pack/plugins/inference/server/util/validate_tool_calls.ts @@ -5,16 +5,13 @@ * 2.0. */ import Ajv from 'ajv'; -import { - createToolNotFoundError, - createToolValidationError, -} from '../../common/chat_complete/errors'; import { ToolCallsOf, ToolChoiceType, ToolOptions, UnvalidatedToolCall, -} from '../../common/chat_complete/tools'; +} from '@kbn/inference-common'; +import { createToolNotFoundError, createToolValidationError } from '../chat_complete/errors'; export function validateToolCalls({ toolCalls, diff --git a/x-pack/plugins/inference/tsconfig.json b/x-pack/plugins/inference/tsconfig.json index cc81eec1da96c..92327007829a9 100644 --- a/x-pack/plugins/inference/tsconfig.json +++ b/x-pack/plugins/inference/tsconfig.json @@ -19,7 +19,6 @@ ], "kbn_references": [ "@kbn/i18n", - "@kbn/sse-utils", "@kbn/esql-ast", "@kbn/esql-validation-autocomplete", "@kbn/core", @@ -33,6 +32,7 @@ "@kbn/core-http-server", "@kbn/actions-plugin", "@kbn/config-schema", + "@kbn/inference-common", "@kbn/es-types", "@kbn/field-types", "@kbn/expressions-plugin", diff --git a/x-pack/plugins/ml/public/application/components/job_selector/use_job_selection.ts b/x-pack/plugins/ml/public/application/components/job_selector/use_job_selection.ts index 7fcc1e71e1808..51d1882084d3e 100644 --- a/x-pack/plugins/ml/public/application/components/job_selector/use_job_selection.ts +++ b/x-pack/plugins/ml/public/application/components/job_selector/use_job_selection.ts @@ -25,6 +25,24 @@ function getInvalidJobIds(jobs: MlJobWithTimeRange[], ids: string[]) { }); } +// This is useful when redirecting from dashboards where groupIds are treated as jobIds +const getJobIdsFromGroups = (jobIds: string[], jobs: MlJobWithTimeRange[]) => { + const result = new Set(); + + jobIds.forEach((id) => { + const jobsInGroup = jobs.filter((job) => job.groups?.includes(id)); + + if (jobsInGroup.length > 0) { + jobsInGroup.forEach((job) => result.add(job.job_id)); + } else { + // If it's not a group ID, keep it (regardless of whether it's valid or not) + result.add(id); + } + }); + + return Array.from(result); +}; + export interface JobSelection { jobIds: string[]; selectedGroups: string[]; @@ -37,9 +55,9 @@ export const useJobSelection = (jobs: MlJobWithTimeRange[]) => { const getJobSelection = useJobSelectionFlyout(); const tmpIds = useMemo(() => { - const ids = globalState?.ml?.jobIds || []; + const ids = getJobIdsFromGroups(globalState?.ml?.jobIds || [], jobs); return (typeof ids === 'string' ? [ids] : ids).map((id: string) => String(id)); - }, [globalState?.ml?.jobIds]); + }, [globalState?.ml?.jobIds, jobs]); const invalidIds = useMemo(() => { return getInvalidJobIds(jobs, tmpIds); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/_index.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/_index.scss index a043a691c9ef6..9b97275417d50 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/_index.scss +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/_index.scss @@ -1,5 +1,3 @@ -@import 'pages/analytics_exploration/components/regression_exploration/index'; @import 'pages/job_map/components/index'; @import 'pages/analytics_management/components/analytics_list/index'; -@import 'pages/analytics_management/components/create_analytics_button/index'; -@import 'pages/analytics_creation/components/index'; +@import 'pages/analytics_creation/components/index'; \ No newline at end of file diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss deleted file mode 100644 index c429daaf3c8dc..0000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss +++ /dev/null @@ -1,47 +0,0 @@ -/* Fixed width so we can align it with the padding of the AUC ROC chart. */ -$labelColumnWidth: 80px; - -/* - Workaround for EuiDataGrid within a Flex Layout, - this tricks browsers treating the width as a px value instead of % -*/ -.mlDataFrameAnalyticsClassification { - width: 100%; -} - -.mlDataFrameAnalyticsClassification__evaluateSectionContent { - padding: 0 5%; -} - -/* - The following two classes are a workaround to avoid having EuiDataGrid in a flex layout - and just uses a legacy approach for a two column layout so we don't break IE11. -*/ -.mlDataFrameAnalyticsClassification__evaluateSectionContent:after { - content: ''; - display: table; - clear: both; -} - -.mlDataFrameAnalyticsClassification__actualLabel { - float: left; - width: $labelColumnWidth; - padding-top: $euiSize * 4; -} - -/* - Gives EuiDataGrid a min-width of 480px, otherwise the columns options will disappear if you hide all columns. -*/ -.mlDataFrameAnalyticsClassification__dataGridMinWidth { - float: left; - min-width: 480px; - width: calc(100% - #{$labelColumnWidth}); - - .euiDataGridRowCell--boolean { - text-transform: none; - } -} - -.mlDataFrameAnalyticsClassification__evaluationMetrics { - width: 60%; -} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx index 8a198666a9732..fac1c8e76a759 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx @@ -19,18 +19,16 @@ interface Props { } export const ClassificationExploration: FC = ({ jobId }) => ( -

+ ); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx index 0298a70ba4afa..0d30b0371a027 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx @@ -5,8 +5,6 @@ * 2.0. */ -import './_classification_exploration.scss'; - import type { FC } from 'react'; import React, { useEffect, useState } from 'react'; @@ -291,190 +289,218 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, se } contentPadding={true} content={ - <> - {!isLoadingConfusionMatrix ? ( - <> - {errorConfusionMatrix !== null && } - {errorConfusionMatrix === null && ( + + + {/* Confusion matrix title and table */} + + {!isLoadingConfusionMatrix ? ( <> - - - {getHelpText(dataSubsetTitle)} - - - - - - {/* BEGIN TABLE ELEMENTS */} - -
-
- - - -
-
- {columns.length > 0 && columnsData.length > 0 && ( - <> -
+ {errorConfusionMatrix !== null && } + {errorConfusionMatrix === null && ( + <> + {/* confusion matrix title */} + + + + + {getHelpText(dataSubsetTitle)} + + + + + + + + {/* confusion matrix table */} + + + -
- - - - )} -
-
- {/* END TABLE ELEMENTS */} - - )} - - ) : null} - {/* Accuracy and Recall */} - - - {evaluationQualityMetricsHelpText} - - - - - - - - - - - - - - - - - - {/* AUC ROC Chart */} - - - - - - - - - - - - {Array.isArray(errorRocCurve) && ( - - {errorRocCurve.map((e) => ( - <> - {e} -
+
+ + + {columns.length > 0 && columnsData.length > 0 ? ( + <> + + + + + + + + + + ) : null} + + +
+ - ))} + )} - } - /> - )} - {!isLoadingRocCurve && errorRocCurve === null && rocCurveData.length > 0 && ( -
- + + + {/* evaluation quality metrics */} + + + {/* evaluation title */} + + {evaluationQualityMetricsHelpText} + + + + {/* evaluation stats */} + + + + + + + + + + + + + + + + + {/* AUC ROC Chart */} + + + + + + + + + + + + + + + {Array.isArray(errorRocCurve) && ( + + {errorRocCurve.map((e) => ( + <> + {e} +
+ + ))} + + } + /> + )} + {!isLoadingRocCurve && errorRocCurve === null && rocCurveData.length > 0 && ( +
+ +
)} - /> -
- )} - {isLoadingRocCurve && } - + {isLoadingRocCurve && } + + + + } /> diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_stat.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_stat.tsx index c4ebd2da2ead9..279744e479b80 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_stat.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_stat.tsx @@ -7,7 +7,7 @@ import type { FC } from 'react'; import React from 'react'; -import { EuiStat, EuiIconTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiStat, EuiIconTip, EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; import { EMPTY_STAT } from '../../../../common/analytics'; interface Props { @@ -24,22 +24,25 @@ export const EvaluateStat: FC = ({ description, dataTestSubj, tooltipContent, -}) => ( - - - - - - - - -); +}) => { + const { + euiTheme: { size }, + } = useEuiTheme(); + + return ( + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/data_view_prompt.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/data_view_prompt.tsx index 9f3cfaffc53fb..6de4a59521313 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/data_view_prompt.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/data_view_prompt.tsx @@ -8,7 +8,7 @@ import type { FC } from 'react'; import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiLink, EuiText } from '@elastic/eui'; +import { EuiLink, EuiText, useEuiTheme } from '@elastic/eui'; import { useMlKibana } from '../../../../../contexts/kibana'; interface Props { @@ -24,6 +24,10 @@ export const DataViewPrompt: FC = ({ destIndex, color }) => { }, } = useMlKibana(); + const { + euiTheme: { size }, + } = useEuiTheme(); + const canCreateDataView = useMemo( () => capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true, @@ -31,36 +35,34 @@ export const DataViewPrompt: FC = ({ destIndex, color }) => { ); return ( - <> - + + + {canCreateDataView === true ? ( + + + ), }} /> - {canCreateDataView === true ? ( - - - - ), - }} - /> - ) : null} - - + ) : null} + ); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss deleted file mode 100644 index 59fd59d69c4a5..0000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss +++ /dev/null @@ -1,13 +0,0 @@ -.mlExpandableSection { - padding: $euiSizeS $euiSize; -} - -.mlExpandableSection-contentPadding { - padding: $euiSizeS; -} - -// Make sure the charts tooltip in popover -// have higher zIndex than Eui popover cells -[id^='echTooltipPortal'] { - z-index: $euiZLevel9 !important; -} \ No newline at end of file diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx index 68de97b30b575..9ba13f16926fe 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx @@ -5,8 +5,6 @@ * 2.0. */ -import './expandable_section.scss'; - import type { FC, ReactNode } from 'react'; import React, { useCallback, useMemo } from 'react'; @@ -18,6 +16,7 @@ import { EuiSkeletonText, EuiPanel, EuiText, + useEuiTheme, } from '@elastic/eui'; import { getDefaultExplorationPageUrlState, @@ -59,6 +58,10 @@ export const ExpandableSection: FC = ({ docsLink, urlStateKey, }) => { + const { + euiTheme: { size }, + } = useEuiTheme(); + const overrides = useMemo( () => (isExpandedDefault !== undefined ? { [urlStateKey]: isExpandedDefault } : undefined), [urlStateKey, isExpandedDefault] @@ -77,68 +80,65 @@ export const ExpandableSection: FC = ({ return ( -
- - - - - - -

{title}

-
-
-
- {headerItems === HEADER_ITEMS_LOADING && } - {isHeaderItems(headerItems) - ? headerItems.map(({ label, value, id }) => ( - - {label !== undefined && value !== undefined ? ( - - - -

{label}

-
-
- - {value} - -
- ) : null} - {label === undefined ? ( - - - - {value} - - - - ) : null} -
- )) - : null} -
-
- {docsLink !== undefined && {docsLink}} -
-
+ + + + + + +

{title}

+
+
+
+ {headerItems === HEADER_ITEMS_LOADING && } + {isHeaderItems(headerItems) + ? headerItems.map(({ label, value, id }) => ( + + {label !== undefined && value !== undefined ? ( + + + +

{label}

+
+
+ + {value} + +
+ ) : null} + {label === undefined ? ( + + + + {value} + + + + ) : null} +
+ )) + : null} +
+
+ {docsLink !== undefined && {docsLink}} +
{isExpanded && (
{content} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx index cc296a42afbae..d8c20f7f3d6fc 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx @@ -23,6 +23,7 @@ import { EuiSpacer, EuiText, EuiToolTip, + useEuiTheme, } from '@elastic/eui'; import type { DataView } from '@kbn/data-views-plugin/public'; @@ -142,6 +143,9 @@ export const ExpandableSectionResults: FC = ({ notifications: { toasts }, }, } = useMlKibana(); + const { + euiTheme: { size }, + } = useEuiTheme(); const dataViewId = dataView?.id; @@ -371,14 +375,12 @@ export const ExpandableSectionResults: FC = ({ const resultsSectionContent = ( <> {jobConfig !== undefined && needsDestDataView && ( -
- -
+ )} {jobConfig !== undefined && (isRegressionAnalysis(jobConfig.analysis) || isClassificationAnalysis(jobConfig.analysis)) && ( - + {tableItems.length === SEARCH_SIZE ? showingFirstDocs : showingDocs} )} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_splom.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_splom.tsx index 22b31abb17661..8ada4cab23410 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_splom.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_splom.tsx @@ -5,14 +5,12 @@ * 2.0. */ -import './expandable_section.scss'; - import type { FC } from 'react'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; +import { EuiHorizontalRule, EuiSpacer, useEuiTheme } from '@elastic/eui'; import type { ScatterplotMatrixProps } from '../../../../../components/scatterplot_matrix'; import { ScatterplotMatrix } from '../../../../../components/scatterplot_matrix'; @@ -20,11 +18,15 @@ import { ScatterplotMatrix } from '../../../../../components/scatterplot_matrix' import { ExpandableSection } from './expandable_section'; export const ExpandableSectionSplom: FC = (props) => { + const { + euiTheme: { size }, + } = useEuiTheme(); + const splomSectionHeaderItems = undefined; const splomSectionContent = ( <> -
+
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/_index.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/_index.scss deleted file mode 100644 index bb948785d3efa..0000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'regression_exploration'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/_regression_exploration.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/_regression_exploration.scss deleted file mode 100644 index edcc9870ff93b..0000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/_regression_exploration.scss +++ /dev/null @@ -1,3 +0,0 @@ -.mlDataFrameAnalyticsRegression__evaluateStat { - padding-top: $euiSizeL; -} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_stat.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_stat.tsx index 89582c51b68f0..f56e1b1dc53f7 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_stat.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_stat.tsx @@ -9,7 +9,7 @@ import type { FC } from 'react'; import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiStat, EuiIconTip, EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; +import { EuiStat, EuiIconTip, EuiFlexGroup, EuiFlexItem, EuiLink, useEuiTheme } from '@elastic/eui'; import { REGRESSION_STATS } from '../../../../common/analytics'; interface Props { @@ -83,24 +83,25 @@ const tooltipContent = { ), }; -export const EvaluateStat: FC = ({ isLoading, statType, title, dataTestSubj }) => ( - - - - - - {statType !== REGRESSION_STATS.HUBER && ( - = ({ isLoading, statType, title, dataTestSubj }) => { + const { + euiTheme: { size }, + } = useEuiTheme(); + + return ( + + + - )} - - -); + + + {statType !== REGRESSION_STATS.HUBER && } + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.scss deleted file mode 100644 index 5343760b1fe9f..0000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.scss +++ /dev/null @@ -1,8 +0,0 @@ -.mlExpandedRowDetails { - padding: $euiSizeS $euiSize $euiSize; -} - -/* Hide the basic table's header */ -.mlExpandedRowDetailsSection thead { - display: none; -} \ No newline at end of file diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.tsx index 32394ec3d1dd4..2c9a79fbc1c0d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.tsx @@ -5,10 +5,9 @@ * 2.0. */ -import './expanded_row_details_pane.scss'; - import type { FC, ReactElement } from 'react'; import React from 'react'; +import { i18n } from '@kbn/i18n'; import { EuiBasicTable, @@ -21,6 +20,7 @@ import { EuiText, EuiTitle, EuiSpacer, + useEuiTheme, } from '@elastic/eui'; export interface SectionItem { @@ -106,11 +106,21 @@ export const Section: FC = ({ section }) => { const columns = [ { field: 'title', - name: '', + name: i18n.translate( + 'xpack.ml.dataframe.analytics.expandedRowDetails.analysisStatsHeaderField', + { + defaultMessage: 'Field', + } + ), }, { field: 'description', - name: '', + name: i18n.translate( + 'xpack.ml.dataframe.analytics.expandedRowDetails.analysisStatsHeaderValue', + { + defaultMessage: 'Value', + } + ), render: (v: SectionItem['description']) => <>{v}, }, ]; @@ -126,7 +136,6 @@ export const Section: FC = ({ section }) => { columns={columns} tableCaption={section.title} tableLayout="auto" - className="mlExpandedRowDetailsSection" data-test-subj={`${section.dataTestSubj}-table`} />
@@ -150,12 +159,16 @@ export const ExpandedRowDetailsPane: FC = ({ progress, dataTestSubj, }) => { + const { + euiTheme: { size }, + } = useEuiTheme(); + return ( <> diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_button/_index.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_button/_index.scss deleted file mode 100644 index 14ff9de7ded4d..0000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_button/_index.scss +++ /dev/null @@ -1,4 +0,0 @@ -.dataFrameAnalyticsCreateSearchDialog { - width: $euiSizeL * 30; - min-height: $euiSizeL * 25; -} diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/_time_range_selector.scss b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/_time_range_selector.scss deleted file mode 100644 index faa69e90ecab5..0000000000000 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/_time_range_selector.scss +++ /dev/null @@ -1,61 +0,0 @@ -// stylelint-disable selector-no-qualifying-type -// SASSTODO: Looks like this could use a rewrite. Needs selectors -.time-range-selector { - .time-range-section-title { - font-weight: bold; - margin-bottom: $euiSizeS; - } - .time-range-section { - flex: 50%; - padding: 0 $euiSizeS; - border-right: $euiBorderThin; - } - - .tab-stack { - margin-bottom: 0; - padding-left: 0; - list-style: none; - - & > li { - float: none; - position: relative; - display: block; - margin-bottom: $euiSizeXS; - - & > a { - position: relative; - display: block; - padding: $euiSizeS $euiSize; - border-radius: $euiSizeXS; - } - & > a:hover { - background-color: $euiColorLightestShade; - } - .body { - display: none; - } - } - & > li.active { - & > a { - color: $euiColorEmptyShade; - background-color: $euiColorPrimary; - - } - .body { - display: block; - } - } - & > li.has-body.active { - & > a { - border-radius: $euiBorderRadius $euiBorderRadius 0 0; - } - .react-datepicker { - border-radius: 0 0 $euiBorderRadius $euiBorderRadius; - border-top: none; - } - } - } - .time-range-section:last-child { - border-right: none; - } -} diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector.js index af3a4d22c1e7e..a6889c745f763 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector.js @@ -5,7 +5,6 @@ * 2.0. */ -import './_time_range_selector.scss'; import PropTypes from 'prop-types'; import React, { Component, useState, useEffect } from 'react'; @@ -16,6 +15,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { TIME_FORMAT } from '@kbn/ml-date-utils'; import { ManagedJobsWarningCallout } from '../../confirm_modals/managed_jobs_warning_callout'; +import { TimeRangeSelectorWrapper } from './time_range_selector_wrapper'; export class TimeRangeSelector extends Component { constructor(props) { @@ -166,7 +166,7 @@ export class TimeRangeSelector extends Component { render() { const { startItems, endItems } = this.getTabItems(); return ( -
+ {this.props.hasManagedJob === true && this.state.endTab !== 0 ? ( <> -
+ ); } } diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector_wrapper.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector_wrapper.tsx new file mode 100644 index 0000000000000..fed58a975eabb --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector_wrapper.tsx @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC, PropsWithChildren } from 'react'; +import React from 'react'; +import { useEuiTheme } from '@elastic/eui'; + +export const TimeRangeSelectorWrapper: FC = ({ children }) => { + const { euiTheme } = useEuiTheme(); + const style = { + '.time-range-section-title': { + fontWeight: 'bold', + marginBottom: euiTheme.size.s, + }, + '.time-range-section': { + flex: '50%', + padding: `0 ${euiTheme.size.s}`, + borderRight: euiTheme.border.thin, + }, + + '.tab-stack': { + marginBottom: 0, + paddingLeft: 0, + listStyle: 'none', + + '& > li': { + float: 'none', + position: 'relative', + display: 'block', + marginBottom: euiTheme.size.xs, + + '& > a': { + position: 'relative', + display: 'block', + padding: `${euiTheme.size.s} ${euiTheme.size.base}`, + borderRadius: euiTheme.border.radius.medium, + }, + '& > a:hover': { + backgroundColor: euiTheme.colors.lightestShade, + }, + '.body': { + display: 'none', + }, + }, + '& > li.active': { + '& > a': { + color: euiTheme.colors.emptyShade, + backgroundColor: euiTheme.colors.primary, + }, + '.body': { + display: 'block', + '.euiFieldText': { + borderRadius: `0 0 ${euiTheme.border.radius.medium} ${euiTheme.border.radius.medium}`, + }, + }, + }, + '& > li.has-body.active': { + '& > a': { + borderRadius: `${euiTheme.border.radius.medium} ${euiTheme.border.radius.medium} 0 0`, + }, + '.react-datepicker': { + borderRadius: `0 0 ${euiTheme.border.radius.medium} ${euiTheme.border.radius.medium}`, + borderTop: 'none', + }, + }, + }, + '.time-range-section:last-child': { + borderRight: 'none', + }, + }; + + // @ts-expect-error style object strings cause a type error + return
{children}
; +}; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx index 7966a73c85faa..d09791941a379 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx @@ -8,10 +8,16 @@ import type { FC, PropsWithChildren } from 'react'; import React, { memo, Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiHorizontalRule, + EuiSpacer, + useEuiTheme, +} from '@elastic/eui'; import type { SplitField } from '@kbn/ml-anomaly-utils'; import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job'; -import './style.scss'; interface Props { fieldValues: string[]; @@ -28,8 +34,14 @@ interface Panel { export const SplitCards: FC> = memo( ({ fieldValues, splitField, children, numberOfDetectors, jobType, animate = false }) => { + const { euiTheme } = useEuiTheme(); const panels: Panel[] = []; + const splitCardStyle = { + border: euiTheme.border.thin, + paddingTop: euiTheme.size.xs, + }; + function storePanels(panel: HTMLDivElement | null, marginBottom: number) { if (panel !== null) { if (animate === false) { @@ -70,14 +82,10 @@ export const SplitCards: FC> = memo( ...(animate ? { transition: 'margin 0.5s' } : {}), }; return ( -
storePanels(ref, marginBottom)} style={style}> - +
storePanels(ref, marginBottom)} css={style}> +
{fieldName} @@ -97,7 +105,7 @@ export const SplitCards: FC> = memo( {(jobType === JOB_TYPE.MULTI_METRIC || jobType === JOB_TYPE.GEO) && (
> = memo( )} {getBackPanels()} - +
{fieldValues[0]} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/style.scss b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/style.scss deleted file mode 100644 index b6b4be7ab5c9d..0000000000000 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/style.scss +++ /dev/null @@ -1,4 +0,0 @@ -.mlPickFields__splitCard { - padding-top: $euiSizeXS; - border: $euiBorderThin; -} diff --git a/x-pack/plugins/ml/public/application/model_management/models_list.tsx b/x-pack/plugins/ml/public/application/model_management/models_list.tsx index f218030c65ad3..a717995d4ee14 100644 --- a/x-pack/plugins/ml/public/application/model_management/models_list.tsx +++ b/x-pack/plugins/ml/public/application/model_management/models_list.tsx @@ -316,6 +316,16 @@ export const ModelsList: FC = ({ }; }); }); + + setItemIdToExpandedRowMap((prev) => { + // Refresh expanded rows + return Object.fromEntries( + Object.keys(prev).map((modelId) => { + const item = resultItems.find((i) => i.model_id === modelId); + return item ? [modelId, ] : []; + }) + ); + }); } catch (error) { displayErrorToast( error, @@ -947,6 +957,14 @@ export const ModelsList: FC = ({ } }); + setItemIdToExpandedRowMap((prev) => { + const newMap = { ...prev }; + modelsToDelete.forEach((model) => { + delete newMap[model.model_id]; + }); + return newMap; + }); + setModelsToDelete([]); if (refreshList) { diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts index f69e60453bfd4..f21e67fe450f4 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts @@ -11,7 +11,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { RuntimeMappings } from '@kbn/ml-runtime-field-utils'; -import { isNumber } from 'lodash'; +import { chunk, isNumber } from 'lodash'; import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app'; import type { MlServerDefaults, @@ -397,13 +397,13 @@ export function mlApiProvider(httpService: HttpService) { end, overallScore, }: { - jobId: string; + jobId: string[]; topN: string; bucketSpan: string; start: number; end: number; overallScore?: number; - }) { + }): Promise { const body = JSON.stringify({ topN, bucketSpan, @@ -411,11 +411,31 @@ export function mlApiProvider(httpService: HttpService) { end, ...(overallScore ? { overall_score: overallScore } : {}), }); - return httpService.http({ - path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/results/overall_buckets`, - method: 'POST', - body, - version: '1', + + // Max permitted job_id is 64 characters, so we can fit around 30 jobs per request + const maxJobsPerRequest = 30; + + return Promise.all( + chunk(jobId, maxJobsPerRequest).map((jobIdsChunk) => { + return httpService.http({ + path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobIdsChunk.join( + ',' + )}/results/overall_buckets`, + method: 'POST', + body, + version: '1', + }); + }) + ).then((responses) => { + // Merge responses + return responses.reduce( + (acc, response) => { + acc.count += response.count; + acc.overall_buckets.push(...response.overall_buckets); + return acc; + }, + { count: 0, overall_buckets: [] } + ); }); }, diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js index d78ed1ed6e7fc..f39bab106c643 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js @@ -1370,8 +1370,6 @@ class TimeseriesChartIntl extends Component { .attr('y', -2) .attr('height', contextChartLineTopMargin); - // Draw the brush handles using SVG foreignObject elements. - // Note these are not supported on IE11 and below, so will not appear in IE. const leftHandle = contextGroup .append('foreignObject') .attr('width', 10) diff --git a/x-pack/plugins/observability_solution/apm/common/es_fields/entities.ts b/x-pack/plugins/observability_solution/apm/common/es_fields/entities.ts deleted file mode 100644 index 28e4a3ec79165..0000000000000 --- a/x-pack/plugins/observability_solution/apm/common/es_fields/entities.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const ENTITY_METRICS_LATENCY = 'entity.metrics.latency'; -export const ENTITY_METRICS_LOG_ERROR_RATE = 'entity.metrics.logErrorRate'; -export const ENTITY_METRICS_LOG_RATE = 'entity.metrics.logRate'; -export const ENTITY_METRICS_THROUGHPUT = 'entity.metrics.throughput'; -export const ENTITY_METRICS_FAILED_TRANSACTION_RATE = 'entity.metrics.failedTransactionRate'; diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml deleted file mode 100644 index d37137302fd21..0000000000000 --- a/x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml +++ /dev/null @@ -1,186 +0,0 @@ -openapi: 3.0.0 -info: - title: APM UI - version: 1.0.0 -tags: - - name: APM agent keys - description: > - Configure APM agent keys to authorize requests from APM agents to the APM Server. - - name: APM annotations - description: > - Annotate visualizations in the APM app with significant events. - Annotations enable you to easily see how events are impacting the performance of your applications. -paths: - /api/apm/agent_keys: - post: - summary: Create an APM agent key - description: Create a new agent key for APM. - operationId: createAgentKey - tags: - - APM agent keys - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - name: - type: string - privileges: - type: array - items: - type: string - enum: - - event:write - - config_agent:read - responses: - "200": - description: Agent key created successfully - content: - application/json: - schema: - type: object - properties: - api_key: - type: string - expiration: - type: integer - format: int64 - id: - type: string - name: - type: string - encoded: - type: string - /api/apm/services/{serviceName}/annotation/search: - get: - summary: Search for annotations - description: Search for annotations related to a specific service. - operationId: getAnnotation - tags: - - APM annotations - parameters: - - name: serviceName - in: path - required: true - description: The name of the service - schema: - type: string - - name: environment - in: query - required: false - description: The environment to filter annotations by - schema: - type: string - - name: start - in: query - required: false - description: The start date for the search - schema: - type: string - - name: end - in: query - required: false - description: The end date for the search - schema: - type: string - responses: - "200": - description: Successful response - content: - application/json: - schema: - type: object - properties: - annotations: - type: array - items: - type: object - properties: - type: - type: string - enum: - - version - id: - type: string - "@timestamp": - type: number - text: - type: string - /api/apm/services/{serviceName}/annotation: - post: - summary: Create a service annotation - description: Create a new annotation for a specific service. - operationId: createAnnotation - tags: - - APM annotations - parameters: - - name: serviceName - in: path - required: true - description: The name of the service - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - '@timestamp': - type: string - service: - type: object - properties: - version: - type: string - environment: - type: string - message: - type: string - tags: - type: array - items: - type: string - - responses: - '200': - description: Annotation created successfully - content: - application/json: - schema: - type: object - properties: - _id: - type: string - _index: - type: string - _source: - type: object - properties: - annotation: - type: string - tags: - type: array - items: - type: string - message: - type: string - service: - type: object - properties: - name: - type: string - environment: - type: string - version: - type: string - event: - type: object - properties: - created: - type: string - '@timestamp': - type: string diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/README.md b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/README.md index da35d6b891239..74b9c6a034821 100644 --- a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/README.md +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/README.md @@ -2,16 +2,26 @@ This directory contains [OpenAPI specifications](https://swagger.io/specification/) for the [APM app API](https://www.elastic.co/guide/en/kibana/current/apm-api.html) in Kibana. -Included: +# OpenAPI (Experimental) -* [Agent Configuration API](https://www.elastic.co/guide/en/kibana/current/agent-config-api.html) -* [Annotation API](https://www.elastic.co/guide/en/kibana/current/apm-annotation-api.html) +The current self-contained spec file is available as `bundled.json` or `bundled.yaml` and can be used for online tools like those found at . +This spec is experimental and may be incomplete or change later. -Not included: +A guide about the openApi specification can be found at [https://swagger.io/docs/specification/about/](https://swagger.io/docs/specification/about/). -* [APM agent Key API](https://www.elastic.co/guide/en/kibana/current/agent-key-api.html) -* [RUM source map API](https://www.elastic.co/guide/en/kibana/current/rum-sourcemap-api.html) +## The `openapi` folder -The specifications for the included APIs are in the apm.yaml file in this directory. +* `entrypoint.yaml` is the overview file which pulls together all the paths and components. +* [Paths](paths/README.md): Defines each endpoint. A path can have one operation per http method. +* [Components](components/README.md): Defines reusable components. -These specifications are manually written. The missing ones will be included in the future. +## Tools + +Generate the `bundled` files by running the following commands: + +```bash +npx @redocly/cli bundle entrypoint.yaml --output bundled.yaml --ext yaml +npx @redocly/cli bundle entrypoint.yaml --output bundled.json --ext json +``` + +Then join these files with the rest of the Kibana APIs per `oas_docs/README.md` diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.json b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.json new file mode 100644 index 0000000000000..9fdcc3cdb6294 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.json @@ -0,0 +1,1827 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "APM UI", + "version": "1.0.0" + }, + "tags": [ + { + "name": "APM agent keys", + "description": "Configure APM agent keys to authorize requests from APM agents to the APM Server.\n" + }, + { + "name": "APM agent configuration", + "description": "Adjust APM agent configuration without need to redeploy your application.\n" + }, + { + "name": "APM sourcemaps", + "description": "Configure APM source maps." + }, + { + "name": "APM annotations", + "description": "Annotate visualizations in the APM app with significant events. Annotations enable you to easily see how events are impacting the performance of your applications.\n" + }, + { + "name": "APM server schema", + "description": "Create APM fleet server schema." + } + ], + "paths": { + "/api/apm/agent_keys": { + "post": { + "summary": "Create an APM agent key", + "description": "Create a new agent key for APM.", + "operationId": "createAgentKey", + "tags": [ + "APM agent keys" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/agent_keys_object" + } + } + } + }, + "responses": { + "200": { + "description": "Agent key created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/agent_keys_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Forbidden response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "500": { + "description": "Internal Server Error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500_response" + } + } + } + } + } + } + }, + "/api/apm/services/{serviceName}/annotation/search": { + "get": { + "summary": "Search for annotations", + "description": "Search for annotations related to a specific service.", + "operationId": "getAnnotation", + "tags": [ + "APM annotations" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "name": "serviceName", + "in": "path", + "required": true, + "description": "The name of the service", + "schema": { + "type": "string" + } + }, + { + "name": "environment", + "in": "query", + "required": false, + "description": "The environment to filter annotations by", + "schema": { + "type": "string" + } + }, + { + "name": "start", + "in": "query", + "required": false, + "description": "The start date for the search", + "schema": { + "type": "string" + } + }, + { + "name": "end", + "in": "query", + "required": false, + "description": "The end date for the search", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/annotation_search_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "500": { + "description": "Internal Server Error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500_response" + } + } + } + } + } + } + }, + "/api/apm/services/{serviceName}/annotation": { + "post": { + "summary": "Create a service annotation", + "description": "Create a new annotation for a specific service.", + "operationId": "createAnnotation", + "tags": [ + "APM annotations" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "name": "serviceName", + "in": "path", + "required": true, + "description": "The name of the service", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/create_annotation_object" + } + } + } + }, + "responses": { + "200": { + "description": "Annotation created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/create_annotation_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Forbidden response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/api/apm/settings/agent-configuration": { + "get": { + "summary": "Get a list of agent configurations", + "operationId": "getAgentConfigurations", + "tags": [ + "APM agent configuration" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/agent_configurations_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + }, + "delete": { + "summary": "Delete agent configuration", + "operationId": "deleteAgentConfiguration", + "tags": [ + "APM agent configuration" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/service_object" + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/delete_agent_configurations_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Forbidden response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + }, + "put": { + "summary": "Create or update agent configuration", + "operationId": "createUpdateAgentConfiguration", + "tags": [ + "APM agent configuration" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "name": "overwrite", + "in": "query", + "description": "If the config exists ?overwrite=true is required", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/agent_configuration_intake_object" + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Forbidden response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/api/apm/settings/agent-configuration/view": { + "get": { + "summary": "Get single agent configuration", + "operationId": "getSingleAgentConfiguration", + "tags": [ + "APM agent configuration" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "name": "name", + "in": "query", + "description": "Service name", + "schema": { + "type": "string" + }, + "example": "node" + }, + { + "name": "environment", + "in": "query", + "description": "Service environment", + "schema": { + "type": "string" + }, + "example": "prod" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/single_agent_configuration_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/api/apm/settings/agent-configuration/search": { + "post": { + "summary": "Lookup single agent configuration", + "description": "This endpoint allows to search for single agent configuration and update 'applied_by_agent' field.\n", + "operationId": "searchSingleConfiguration", + "tags": [ + "APM agent configuration" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/search_agent_configuration_object" + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/search_agent_configuration_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/api/apm/settings/agent-configuration/environments": { + "get": { + "summary": "Get environments for service", + "operationId": "getEnvironmentsForService", + "tags": [ + "APM agent configuration" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "name": "serviceName", + "in": "query", + "description": "The name of the service", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/service_environments_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/api/apm/settings/agent-configuration/agent_name": { + "get": { + "summary": "Get agent name for service", + "description": "Retrieve `agentName` for a service.", + "operationId": "getAgentNameForService", + "tags": [ + "APM agent configuration" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "name": "serviceName", + "in": "query", + "description": "The name of the service", + "required": true, + "schema": { + "type": "string" + }, + "example": "node" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/service_agent_name_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/api/apm/sourcemaps": { + "get": { + "summary": "Get source maps", + "description": "Returns an array of Fleet artifacts, including source map uploads.", + "operationId": "getSourceMaps", + "tags": [ + "APM sourcemaps" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "name": "page", + "in": "query", + "description": "Page number", + "schema": { + "type": "number" + } + }, + { + "name": "perPage", + "in": "query", + "description": "Number of records per page", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/source_maps_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "500": { + "description": "Internal Server Error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500_response" + } + } + } + }, + "501": { + "description": "Not Implemented response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/501_response" + } + } + } + } + } + }, + "post": { + "summary": "Upload source map", + "description": "Upload a source map for a specific service and version.", + "operationId": "uploadSourceMap", + "tags": [ + "APM sourcemaps" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/upload_source_map_object" + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/upload_source_maps_response" + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Forbidden response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "500": { + "description": "Internal Server Error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500_response" + } + } + } + }, + "501": { + "description": "Not Implemented response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/501_response" + } + } + } + } + } + } + }, + "/api/apm/sourcemaps/{id}": { + "delete": { + "summary": "Delete source map", + "description": "Delete a previously uploaded source map.", + "operationId": "deleteSourceMap", + "tags": [ + "APM sourcemaps" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "name": "id", + "in": "path", + "description": "Source map identifier", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Forbidden response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "500": { + "description": "Internal Server Error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500_response" + } + } + } + }, + "501": { + "description": "Not Implemented response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/501_response" + } + } + } + } + } + } + }, + "/api/apm/fleet/apm_server_schema": { + "post": { + "summary": "Save APM server schema", + "operationId": "saveApmServerSchema", + "tags": [ + "APM server schema" + ], + "parameters": [ + { + "$ref": "#/components/parameters/elastic_api_version" + }, + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schema": { + "type": "object", + "description": "Schema object", + "additionalProperties": true, + "example": { + "foo": "bar" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false + } + } + } + }, + "400": { + "description": "Bad Request response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Forbidden response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + } + }, + "components": { + "parameters": { + "elastic_api_version": { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "required": true, + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + "kbn_xsrf": { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + } + }, + "schemas": { + "agent_keys_object": { + "type": "object", + "required": [ + "name", + "privileges" + ], + "properties": { + "name": { + "type": "string", + "description": "Agent name" + }, + "privileges": { + "type": "array", + "description": "Privileges configuration", + "items": { + "type": "string", + "enum": [ + "event:write", + "config_agent:read" + ] + } + } + } + }, + "agent_keys_response": { + "type": "object", + "properties": { + "agentKey": { + "type": "object", + "description": "Agent key", + "required": [ + "id", + "name", + "api_key", + "encoded" + ], + "properties": { + "expiration": { + "type": "integer", + "format": "int64" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "api_key": { + "type": "string" + }, + "encoded": { + "type": "string" + } + } + } + } + }, + "400_response": { + "type": "object", + "properties": { + "statusCode": { + "type": "number", + "example": 400, + "description": "Error status code" + }, + "error": { + "type": "string", + "example": "Not Found", + "description": "Error type" + }, + "message": { + "type": "string", + "example": "Not Found", + "description": "Error message" + } + } + }, + "401_response": { + "type": "object", + "properties": { + "statusCode": { + "type": "number", + "example": 401, + "description": "Error status code" + }, + "error": { + "type": "string", + "example": "Unauthorized", + "description": "Error type" + }, + "message": { + "type": "string", + "description": "Error message" + } + } + }, + "403_response": { + "type": "object", + "properties": { + "statusCode": { + "type": "number", + "example": 403, + "description": "Error status code" + }, + "error": { + "type": "string", + "example": "Forbidden", + "description": "Error type" + }, + "message": { + "type": "string", + "description": "Error message" + } + } + }, + "500_response": { + "type": "object", + "properties": { + "statusCode": { + "type": "number", + "example": 500, + "description": "Error status code" + }, + "error": { + "type": "string", + "example": "Internal Server Error", + "description": "Error type" + }, + "message": { + "type": "string", + "description": "Error message" + } + } + }, + "annotation_search_response": { + "type": "object", + "properties": { + "annotations": { + "type": "array", + "description": "Annotations", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "version" + ] + }, + "id": { + "type": "string" + }, + "@timestamp": { + "type": "number" + }, + "text": { + "type": "string" + } + } + } + } + } + }, + "create_annotation_object": { + "type": "object", + "required": [ + "@timestamp", + "service" + ], + "properties": { + "@timestamp": { + "type": "string", + "description": "Timestamp" + }, + "service": { + "type": "object", + "description": "Service", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "string" + }, + "environment": { + "type": "string" + } + } + }, + "message": { + "type": "string", + "description": "Message" + }, + "tags": { + "type": "array", + "description": "Tags", + "items": { + "type": "string" + } + } + } + }, + "create_annotation_response": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "description": "Identifier" + }, + "_index": { + "type": "string", + "description": "Index" + }, + "_source": { + "type": "object", + "description": "Response", + "properties": { + "annotation": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "title": { + "type": "string" + } + } + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "message": { + "type": "string" + }, + "service": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "event": { + "type": "object", + "properties": { + "created": { + "type": "string" + } + } + }, + "@timestamp": { + "type": "string" + } + } + } + } + }, + "404_response": { + "type": "object", + "properties": { + "statusCode": { + "type": "number", + "example": 404, + "description": "Error status code" + }, + "error": { + "type": "string", + "example": "Not Found", + "description": "Error type" + }, + "message": { + "type": "string", + "example": "Not Found", + "description": "Error message" + } + } + }, + "service_object": { + "type": "object", + "description": "Service", + "properties": { + "name": { + "type": "string", + "example": "node", + "description": "Name" + }, + "environment": { + "type": "string", + "example": "prod", + "description": "Environment" + } + } + }, + "settings_object": { + "type": "object", + "description": "Agent configuration settings", + "additionalProperties": { + "type": "string" + } + }, + "agent_configuration_object": { + "type": "object", + "required": [ + "service", + "settings", + "@timestamp", + "etag" + ], + "description": "Agent configuration", + "properties": { + "agent_name": { + "type": "string", + "description": "Agent name" + }, + "service": { + "$ref": "#/components/schemas/service_object" + }, + "settings": { + "$ref": "#/components/schemas/settings_object" + }, + "@timestamp": { + "type": "number", + "example": 1730194190636, + "description": "Timestamp" + }, + "applied_by_agent": { + "type": "boolean", + "example": true, + "description": "Applied by agent" + }, + "etag": { + "type": "string", + "example": "0bc3b5ebf18fba8163fe4c96f491e3767a358f85", + "description": "Etag" + } + } + }, + "agent_configurations_response": { + "type": "object", + "properties": { + "configurations": { + "type": "array", + "description": "Agent configuration", + "items": { + "$ref": "#/components/schemas/agent_configuration_object" + } + } + } + }, + "agent_configuration_intake_object": { + "type": "object", + "required": [ + "service", + "settings" + ], + "properties": { + "agent_name": { + "type": "string", + "description": "Agent name" + }, + "service": { + "$ref": "#/components/schemas/service_object" + }, + "settings": { + "$ref": "#/components/schemas/settings_object" + } + } + }, + "delete_agent_configurations_response": { + "type": "object", + "properties": { + "result": { + "type": "string", + "description": "Result" + } + } + }, + "single_agent_configuration_response": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/agent_configuration_object" + } + ] + }, + "search_agent_configuration_object": { + "type": "object", + "required": [ + "service" + ], + "properties": { + "service": { + "$ref": "#/components/schemas/service_object" + }, + "etag": { + "type": "string", + "description": "If etags match then `applied_by_agent` field will be set to `true`", + "example": "0bc3b5ebf18fba8163fe4c96f491e3767a358f85" + }, + "mark_as_applied_by_agent": { + "type": "boolean", + "description": "`markAsAppliedByAgent=true` means \"force setting it to true regardless of etag\".\nThis is needed for Jaeger agent that doesn't have etags\n" + } + } + }, + "search_agent_configuration_response": { + "type": "object", + "properties": { + "_index": { + "type": "string", + "description": "Index" + }, + "_id": { + "type": "string", + "description": "Identifier" + }, + "_score": { + "type": "number", + "description": "Score" + }, + "_source": { + "$ref": "#/components/schemas/agent_configuration_object" + } + } + }, + "service_environment_object": { + "type": "object", + "properties": { + "name": { + "type": "string", + "example": "ALL_OPTION_VALUE", + "description": "Service environment name" + }, + "alreadyConfigured": { + "type": "boolean", + "description": "Already configured" + } + } + }, + "service_environments_response": { + "type": "object", + "properties": { + "environments": { + "type": "array", + "description": "Service environment list", + "items": { + "$ref": "#/components/schemas/service_environment_object" + } + } + } + }, + "service_agent_name_response": { + "type": "object", + "properties": { + "agentName": { + "type": "string", + "description": "Agent name", + "example": "nodejs" + } + } + }, + "base_source_map_object": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Type" + }, + "identifier": { + "type": "string", + "description": "Identifier" + }, + "relative_url": { + "type": "string", + "description": "Relative URL" + }, + "created": { + "type": "string", + "description": "Created date" + }, + "id": { + "type": "string", + "description": "Identifier" + }, + "compressionAlgorithm": { + "type": "string", + "description": "Compression Algorithm" + }, + "decodedSha256": { + "type": "string", + "description": "Decoded SHA-256" + }, + "decodedSize": { + "type": "number", + "description": "Decoded size" + }, + "encodedSha256": { + "type": "string", + "description": "Encoded SHA-256" + }, + "encodedSize": { + "type": "number", + "description": "Encoded size" + }, + "encryptionAlgorithm": { + "type": "string", + "description": "Encryption Algorithm" + }, + "packageName": { + "type": "string", + "description": "Package name" + } + } + }, + "source_maps_response": { + "type": "object", + "properties": { + "artifacts": { + "type": "array", + "description": "Artifacts", + "items": { + "allOf": [ + { + "type": "object", + "properties": { + "body": { + "type": "object", + "properties": { + "serviceName": { + "type": "string" + }, + "serviceVersion": { + "type": "string" + }, + "bundleFilepath": { + "type": "string" + }, + "sourceMap": { + "type": "object", + "properties": { + "version": { + "type": "number" + }, + "file": { + "type": "string" + }, + "sources": { + "type": "array", + "items": { + "type": "string" + } + }, + "sourcesContent": { + "type": "array", + "items": { + "type": "string" + } + }, + "mappings": { + "type": "string" + }, + "sourceRoot": { + "type": "string" + } + } + } + } + } + } + }, + { + "$ref": "#/components/schemas/base_source_map_object" + } + ] + } + } + } + }, + "501_response": { + "type": "object", + "properties": { + "statusCode": { + "type": "number", + "example": 501, + "description": "Error status code" + }, + "error": { + "type": "string", + "example": "Not Implemented", + "description": "Error type" + }, + "message": { + "type": "string", + "example": "Not Implemented", + "description": "Error message" + } + } + }, + "upload_source_map_object": { + "type": "object", + "required": [ + "service_name", + "service_version", + "bundle_filepath", + "sourcemap" + ], + "properties": { + "service_name": { + "type": "string", + "description": "The name of the service that the service map should apply to." + }, + "service_version": { + "type": "string", + "description": "The version of the service that the service map should apply to." + }, + "bundle_filepath": { + "type": "string", + "description": "The absolute path of the final bundle as used in the web application." + }, + "sourcemap": { + "type": "string", + "format": "binary", + "description": "The source map. String or file upload. It must follow the\n[source map revision 3 proposal](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k).\n" + } + } + }, + "upload_source_maps_response": { + "allOf": [ + { + "type": "object", + "properties": { + "body": { + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/base_source_map_object" + } + ] + } + } + } +} \ No newline at end of file diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.yaml new file mode 100644 index 0000000000000..caa71f6645e77 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/bundled.yaml @@ -0,0 +1,1162 @@ +openapi: 3.0.2 +info: + title: APM UI + version: 1.0.0 +tags: + - name: APM agent keys + description: | + Configure APM agent keys to authorize requests from APM agents to the APM Server. + - name: APM agent configuration + description: | + Adjust APM agent configuration without need to redeploy your application. + - name: APM sourcemaps + description: Configure APM source maps. + - name: APM annotations + description: | + Annotate visualizations in the APM app with significant events. Annotations enable you to easily see how events are impacting the performance of your applications. + - name: APM server schema + description: Create APM fleet server schema. +paths: + /api/apm/agent_keys: + post: + summary: Create an APM agent key + description: Create a new agent key for APM. + operationId: createAgentKey + tags: + - APM agent keys + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - $ref: '#/components/parameters/kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/agent_keys_object' + responses: + '200': + description: Agent key created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/agent_keys_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '#/components/schemas/500_response' + /api/apm/services/{serviceName}/annotation/search: + get: + summary: Search for annotations + description: Search for annotations related to a specific service. + operationId: getAnnotation + tags: + - APM annotations + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + - name: environment + in: query + required: false + description: The environment to filter annotations by + schema: + type: string + - name: start + in: query + required: false + description: The start date for the search + schema: + type: string + - name: end + in: query + required: false + description: The end date for the search + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/annotation_search_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '#/components/schemas/500_response' + /api/apm/services/{serviceName}/annotation: + post: + summary: Create a service annotation + description: Create a new annotation for a specific service. + operationId: createAnnotation + tags: + - APM annotations + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - $ref: '#/components/parameters/kbn_xsrf' + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/create_annotation_object' + responses: + '200': + description: Annotation created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/create_annotation_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + /api/apm/settings/agent-configuration: + get: + summary: Get a list of agent configurations + operationId: getAgentConfigurations + tags: + - APM agent configuration + parameters: + - $ref: '#/components/parameters/elastic_api_version' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/agent_configurations_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + delete: + summary: Delete agent configuration + operationId: deleteAgentConfiguration + tags: + - APM agent configuration + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - $ref: '#/components/parameters/kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/service_object' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/delete_agent_configurations_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + put: + summary: Create or update agent configuration + operationId: createUpdateAgentConfiguration + tags: + - APM agent configuration + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - $ref: '#/components/parameters/kbn_xsrf' + - name: overwrite + in: query + description: If the config exists ?overwrite=true is required + schema: + type: boolean + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/agent_configuration_intake_object' + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + additionalProperties: false + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + /api/apm/settings/agent-configuration/view: + get: + summary: Get single agent configuration + operationId: getSingleAgentConfiguration + tags: + - APM agent configuration + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - name: name + in: query + description: Service name + schema: + type: string + example: node + - name: environment + in: query + description: Service environment + schema: + type: string + example: prod + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/single_agent_configuration_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + /api/apm/settings/agent-configuration/search: + post: + summary: Lookup single agent configuration + description: | + This endpoint allows to search for single agent configuration and update 'applied_by_agent' field. + operationId: searchSingleConfiguration + tags: + - APM agent configuration + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - $ref: '#/components/parameters/kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/search_agent_configuration_object' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/search_agent_configuration_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + /api/apm/settings/agent-configuration/environments: + get: + summary: Get environments for service + operationId: getEnvironmentsForService + tags: + - APM agent configuration + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - name: serviceName + in: query + description: The name of the service + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/service_environments_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + /api/apm/settings/agent-configuration/agent_name: + get: + summary: Get agent name for service + description: Retrieve `agentName` for a service. + operationId: getAgentNameForService + tags: + - APM agent configuration + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - name: serviceName + in: query + description: The name of the service + required: true + schema: + type: string + example: node + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/service_agent_name_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + /api/apm/sourcemaps: + get: + summary: Get source maps + description: Returns an array of Fleet artifacts, including source map uploads. + operationId: getSourceMaps + tags: + - APM sourcemaps + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - name: page + in: query + description: Page number + schema: + type: number + - name: perPage + in: query + description: Number of records per page + schema: + type: number + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/source_maps_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '#/components/schemas/500_response' + '501': + description: Not Implemented response + content: + application/json: + schema: + $ref: '#/components/schemas/501_response' + post: + summary: Upload source map + description: Upload a source map for a specific service and version. + operationId: uploadSourceMap + tags: + - APM sourcemaps + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - $ref: '#/components/parameters/kbn_xsrf' + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/upload_source_map_object' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/upload_source_maps_response' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '#/components/schemas/500_response' + '501': + description: Not Implemented response + content: + application/json: + schema: + $ref: '#/components/schemas/501_response' + /api/apm/sourcemaps/{id}: + delete: + summary: Delete source map + description: Delete a previously uploaded source map. + operationId: deleteSourceMap + tags: + - APM sourcemaps + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - $ref: '#/components/parameters/kbn_xsrf' + - name: id + in: path + description: Source map identifier + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + additionalProperties: false + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '#/components/schemas/500_response' + '501': + description: Not Implemented response + content: + application/json: + schema: + $ref: '#/components/schemas/501_response' + /api/apm/fleet/apm_server_schema: + post: + summary: Save APM server schema + operationId: saveApmServerSchema + tags: + - APM server schema + parameters: + - $ref: '#/components/parameters/elastic_api_version' + - $ref: '#/components/parameters/kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + schema: + type: object + description: Schema object + additionalProperties: true + example: + foo: bar + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + additionalProperties: false + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' +components: + parameters: + elastic_api_version: + description: The version of the API to use + in: header + name: elastic-api-version + required: true + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + kbn_xsrf: + description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + schemas: + agent_keys_object: + type: object + required: + - name + - privileges + properties: + name: + type: string + description: Agent name + privileges: + type: array + description: Privileges configuration + items: + type: string + enum: + - event:write + - config_agent:read + agent_keys_response: + type: object + properties: + agentKey: + type: object + description: Agent key + required: + - id + - name + - api_key + - encoded + properties: + expiration: + type: integer + format: int64 + id: + type: string + name: + type: string + api_key: + type: string + encoded: + type: string + 400_response: + type: object + properties: + statusCode: + type: number + example: 400 + description: Error status code + error: + type: string + example: Not Found + description: Error type + message: + type: string + example: Not Found + description: Error message + 401_response: + type: object + properties: + statusCode: + type: number + example: 401 + description: Error status code + error: + type: string + example: Unauthorized + description: Error type + message: + type: string + description: Error message + 403_response: + type: object + properties: + statusCode: + type: number + example: 403 + description: Error status code + error: + type: string + example: Forbidden + description: Error type + message: + type: string + description: Error message + 500_response: + type: object + properties: + statusCode: + type: number + example: 500 + description: Error status code + error: + type: string + example: Internal Server Error + description: Error type + message: + type: string + description: Error message + annotation_search_response: + type: object + properties: + annotations: + type: array + description: Annotations + items: + type: object + properties: + type: + type: string + enum: + - version + id: + type: string + '@timestamp': + type: number + text: + type: string + create_annotation_object: + type: object + required: + - '@timestamp' + - service + properties: + '@timestamp': + type: string + description: Timestamp + service: + type: object + description: Service + required: + - version + properties: + version: + type: string + environment: + type: string + message: + type: string + description: Message + tags: + type: array + description: Tags + items: + type: string + create_annotation_response: + type: object + properties: + _id: + type: string + description: Identifier + _index: + type: string + description: Index + _source: + type: object + description: Response + properties: + annotation: + type: object + properties: + type: + type: string + title: + type: string + tags: + type: array + items: + type: string + message: + type: string + service: + type: object + properties: + name: + type: string + environment: + type: string + version: + type: string + event: + type: object + properties: + created: + type: string + '@timestamp': + type: string + 404_response: + type: object + properties: + statusCode: + type: number + example: 404 + description: Error status code + error: + type: string + example: Not Found + description: Error type + message: + type: string + example: Not Found + description: Error message + service_object: + type: object + description: Service + properties: + name: + type: string + example: node + description: Name + environment: + type: string + example: prod + description: Environment + settings_object: + type: object + description: Agent configuration settings + additionalProperties: + type: string + agent_configuration_object: + type: object + required: + - service + - settings + - '@timestamp' + - etag + description: Agent configuration + properties: + agent_name: + type: string + description: Agent name + service: + $ref: '#/components/schemas/service_object' + settings: + $ref: '#/components/schemas/settings_object' + '@timestamp': + type: number + example: 1730194190636 + description: Timestamp + applied_by_agent: + type: boolean + example: true + description: Applied by agent + etag: + type: string + example: 0bc3b5ebf18fba8163fe4c96f491e3767a358f85 + description: Etag + agent_configurations_response: + type: object + properties: + configurations: + type: array + description: Agent configuration + items: + $ref: '#/components/schemas/agent_configuration_object' + agent_configuration_intake_object: + type: object + required: + - service + - settings + properties: + agent_name: + type: string + description: Agent name + service: + $ref: '#/components/schemas/service_object' + settings: + $ref: '#/components/schemas/settings_object' + delete_agent_configurations_response: + type: object + properties: + result: + type: string + description: Result + single_agent_configuration_response: + allOf: + - type: object + required: + - id + properties: + id: + type: string + - $ref: '#/components/schemas/agent_configuration_object' + search_agent_configuration_object: + type: object + required: + - service + properties: + service: + $ref: '#/components/schemas/service_object' + etag: + type: string + description: If etags match then `applied_by_agent` field will be set to `true` + example: 0bc3b5ebf18fba8163fe4c96f491e3767a358f85 + mark_as_applied_by_agent: + type: boolean + description: | + `markAsAppliedByAgent=true` means "force setting it to true regardless of etag". + This is needed for Jaeger agent that doesn't have etags + search_agent_configuration_response: + type: object + properties: + _index: + type: string + description: Index + _id: + type: string + description: Identifier + _score: + type: number + description: Score + _source: + $ref: '#/components/schemas/agent_configuration_object' + service_environment_object: + type: object + properties: + name: + type: string + example: ALL_OPTION_VALUE + description: Service environment name + alreadyConfigured: + type: boolean + description: Already configured + service_environments_response: + type: object + properties: + environments: + type: array + description: Service environment list + items: + $ref: '#/components/schemas/service_environment_object' + service_agent_name_response: + type: object + properties: + agentName: + type: string + description: Agent name + example: nodejs + base_source_map_object: + type: object + properties: + type: + type: string + description: Type + identifier: + type: string + description: Identifier + relative_url: + type: string + description: Relative URL + created: + type: string + description: Created date + id: + type: string + description: Identifier + compressionAlgorithm: + type: string + description: Compression Algorithm + decodedSha256: + type: string + description: Decoded SHA-256 + decodedSize: + type: number + description: Decoded size + encodedSha256: + type: string + description: Encoded SHA-256 + encodedSize: + type: number + description: Encoded size + encryptionAlgorithm: + type: string + description: Encryption Algorithm + packageName: + type: string + description: Package name + source_maps_response: + type: object + properties: + artifacts: + type: array + description: Artifacts + items: + allOf: + - type: object + properties: + body: + type: object + properties: + serviceName: + type: string + serviceVersion: + type: string + bundleFilepath: + type: string + sourceMap: + type: object + properties: + version: + type: number + file: + type: string + sources: + type: array + items: + type: string + sourcesContent: + type: array + items: + type: string + mappings: + type: string + sourceRoot: + type: string + - $ref: '#/components/schemas/base_source_map_object' + 501_response: + type: object + properties: + statusCode: + type: number + example: 501 + description: Error status code + error: + type: string + example: Not Implemented + description: Error type + message: + type: string + example: Not Implemented + description: Error message + upload_source_map_object: + type: object + required: + - service_name + - service_version + - bundle_filepath + - sourcemap + properties: + service_name: + type: string + description: The name of the service that the service map should apply to. + service_version: + type: string + description: The version of the service that the service map should apply to. + bundle_filepath: + type: string + description: The absolute path of the final bundle as used in the web application. + sourcemap: + type: string + format: binary + description: | + The source map. String or file upload. It must follow the + [source map revision 3 proposal](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k). + upload_source_maps_response: + allOf: + - type: object + properties: + body: + type: string + - $ref: '#/components/schemas/base_source_map_object' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/README.md b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/README.md new file mode 100644 index 0000000000000..6beadcd86e1e9 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/README.md @@ -0,0 +1,7 @@ +Reusable components +=========== + + - `examples` - reusable [Example objects](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.2.md#example-object) + - `headers` - reusable [Header objects](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#header-object) + - `parameters` - reusable [Parameter objects](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#parameter-object) + - `schemas` - reusable [Schema objects](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.2.md#schema-object) diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/headers/elastic_api_version.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/headers/elastic_api_version.yaml new file mode 100644 index 0000000000000..b11a093b7b581 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/headers/elastic_api_version.yaml @@ -0,0 +1,9 @@ +description: The version of the API to use +in: header +name: elastic-api-version +required: true +schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/headers/kbn_xsrf.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/headers/kbn_xsrf.yaml new file mode 100644 index 0000000000000..25fcd49c04e65 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/headers/kbn_xsrf.yaml @@ -0,0 +1,7 @@ +description: A required header to protect against CSRF attacks +in: header +name: kbn-xsrf +required: true +schema: + example: 'true' + type: string diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/400_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/400_response.yaml new file mode 100644 index 0000000000000..3f09203cd49d3 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/400_response.yaml @@ -0,0 +1,14 @@ +type: object +properties: + statusCode: + type: number + example: 400 + description: Error status code + error: + type: string + example: Not Found + description: Error type + message: + type: string + example: Not Found + description: Error message diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/401_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/401_response.yaml new file mode 100644 index 0000000000000..cf5afb3482e6c --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/401_response.yaml @@ -0,0 +1,13 @@ +type: object +properties: + statusCode: + type: number + example: 401 + description: Error status code + error: + type: string + example: Unauthorized + description: Error type + message: + type: string + description: Error message diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/403_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/403_response.yaml new file mode 100644 index 0000000000000..f04184dcb1bb2 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/403_response.yaml @@ -0,0 +1,13 @@ +type: object +properties: + statusCode: + type: number + example: 403 + description: Error status code + error: + type: string + example: Forbidden + description: Error type + message: + type: string + description: Error message diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/404_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/404_response.yaml new file mode 100644 index 0000000000000..9e539dcbda096 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/404_response.yaml @@ -0,0 +1,14 @@ +type: object +properties: + statusCode: + type: number + example: 404 + description: Error status code + error: + type: string + example: Not Found + description: Error type + message: + type: string + example: Not Found + description: Error message diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/500_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/500_response.yaml new file mode 100644 index 0000000000000..e952739138146 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/500_response.yaml @@ -0,0 +1,13 @@ +type: object +properties: + statusCode: + type: number + example: 500 + description: Error status code + error: + type: string + example: Internal Server Error + description: Error type + message: + type: string + description: Error message diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/501_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/501_response.yaml new file mode 100644 index 0000000000000..f5a1545f7183e --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/501_response.yaml @@ -0,0 +1,14 @@ +type: object +properties: + statusCode: + type: number + example: 501 + description: Error status code + error: + type: string + example: Not Implemented + description: Error type + message: + type: string + example: Not Implemented + description: Error message diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configuration_intake_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configuration_intake_object.yaml new file mode 100644 index 0000000000000..0be4a414cd35a --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configuration_intake_object.yaml @@ -0,0 +1,12 @@ +type: object +required: + - service + - settings +properties: + agent_name: + type: string + description: Agent name + service: + $ref: 'service_object.yaml' + settings: + $ref: 'settings_object.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configuration_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configuration_object.yaml new file mode 100644 index 0000000000000..8dfa922c25874 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configuration_object.yaml @@ -0,0 +1,27 @@ +type: object +required: + - service + - settings + - '@timestamp' + - etag +description: Agent configuration +properties: + agent_name: + type: string + description: Agent name + service: + $ref: 'service_object.yaml' + settings: + $ref: 'settings_object.yaml' + '@timestamp': + type: number + example: 1730194190636 + description: Timestamp + applied_by_agent: + type: boolean + example: true + description: Applied by agent + etag: + type: string + example: 0bc3b5ebf18fba8163fe4c96f491e3767a358f85 + description: Etag diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configurations_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configurations_response.yaml new file mode 100644 index 0000000000000..a6bdb51466fb4 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_configurations_response.yaml @@ -0,0 +1,7 @@ +type: object +properties: + configurations: + type: array + description: Agent configuration + items: + $ref: 'agent_configuration_object.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_keys_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_keys_object.yaml new file mode 100644 index 0000000000000..c5e248471db90 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_keys_object.yaml @@ -0,0 +1,16 @@ +type: object +required: + - name + - privileges +properties: + name: + type: string + description: Agent name + privileges: + type: array + description: Privileges configuration + items: + type: string + enum: + - event:write + - config_agent:read diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_keys_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_keys_response.yaml new file mode 100644 index 0000000000000..3507dae535faf --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/agent_keys_response.yaml @@ -0,0 +1,22 @@ +type: object +properties: + agentKey: + type: object + description: Agent key + required: + - id + - name + - api_key + - encoded + properties: + expiration: + type: integer + format: int64 + id: + type: string + name: + type: string + api_key: + type: string + encoded: + type: string diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/annotation_search_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/annotation_search_response.yaml new file mode 100644 index 0000000000000..7827f17ffb979 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/annotation_search_response.yaml @@ -0,0 +1,18 @@ +type: object +properties: + annotations: + type: array + description: Annotations + items: + type: object + properties: + type: + type: string + enum: + - version + id: + type: string + "@timestamp": + type: number + text: + type: string diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/base_source_map_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/base_source_map_object.yaml new file mode 100644 index 0000000000000..f642c933f2b71 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/base_source_map_object.yaml @@ -0,0 +1,38 @@ +type: object +properties: + type: + type: string + description: Type + identifier: + type: string + description: Identifier + relative_url: + type: string + description: Relative URL + created: + type: string + description: Created date + id: + type: string + description: Identifier + compressionAlgorithm: + type: string + description: Compression Algorithm + decodedSha256: + type: string + description: Decoded SHA-256 + decodedSize: + type: number + description: Decoded size + encodedSha256: + type: string + description: Encoded SHA-256 + encodedSize: + type: number + description: Encoded size + encryptionAlgorithm: + type: string + description: Encryption Algorithm + packageName: + type: string + description: Package name diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/create_annotation_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/create_annotation_object.yaml new file mode 100644 index 0000000000000..6a8f8ba9b96d0 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/create_annotation_object.yaml @@ -0,0 +1,26 @@ +type: object +required: + - '@timestamp' + - service +properties: + '@timestamp': + type: string + description: Timestamp + service: + type: object + description: Service + required: + - version + properties: + version: + type: string + environment: + type: string + message: + type: string + description: Message + tags: + type: array + description: Tags + items: + type: string diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/create_annotation_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/create_annotation_response.yaml new file mode 100644 index 0000000000000..4738406a1e765 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/create_annotation_response.yaml @@ -0,0 +1,41 @@ +type: object +properties: + _id: + type: string + description: Identifier + _index: + type: string + description: Index + _source: + type: object + description: Response + properties: + annotation: + type: object + properties: + type: + type: string + title: + type: string + tags: + type: array + items: + type: string + message: + type: string + service: + type: object + properties: + name: + type: string + environment: + type: string + version: + type: string + event: + type: object + properties: + created: + type: string + '@timestamp': + type: string diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/delete_agent_configurations_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/delete_agent_configurations_response.yaml new file mode 100644 index 0000000000000..3dc7c58998b1f --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/delete_agent_configurations_response.yaml @@ -0,0 +1,5 @@ +type: object +properties: + result: + type: string + description: Result diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/search_agent_configuration_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/search_agent_configuration_object.yaml new file mode 100644 index 0000000000000..abbbf91b77b89 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/search_agent_configuration_object.yaml @@ -0,0 +1,15 @@ +type: object +required: + - service +properties: + service: + $ref: 'service_object.yaml' + etag: + type: string + description: If etags match then `applied_by_agent` field will be set to `true` + example: 0bc3b5ebf18fba8163fe4c96f491e3767a358f85 + mark_as_applied_by_agent: + type: boolean + description: | + `markAsAppliedByAgent=true` means "force setting it to true regardless of etag". + This is needed for Jaeger agent that doesn't have etags diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/search_agent_configuration_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/search_agent_configuration_response.yaml new file mode 100644 index 0000000000000..d0a5ff1d91a78 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/search_agent_configuration_response.yaml @@ -0,0 +1,13 @@ +type: object +properties: + _index: + type: string + description: Index + _id: + type: string + description: Identifier + _score: + type: number + description: Score + _source: + $ref: 'agent_configuration_object.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_agent_name_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_agent_name_response.yaml new file mode 100644 index 0000000000000..b67c34b65df8e --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_agent_name_response.yaml @@ -0,0 +1,6 @@ +type: object +properties: + agentName: + type: string + description: Agent name + example: nodejs diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_environment_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_environment_object.yaml new file mode 100644 index 0000000000000..0f7f11371e59c --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_environment_object.yaml @@ -0,0 +1,9 @@ +type: object +properties: + name: + type: string + example: ALL_OPTION_VALUE + description: Service environment name + alreadyConfigured: + type: boolean + description: Already configured diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_environments_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_environments_response.yaml new file mode 100644 index 0000000000000..1b8cdc1cab48e --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_environments_response.yaml @@ -0,0 +1,7 @@ +type: object +properties: + environments: + type: array + description: Service environment list + items: + $ref: 'service_environment_object.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_object.yaml new file mode 100644 index 0000000000000..c73dd8bc0eb19 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/service_object.yaml @@ -0,0 +1,11 @@ +type: object +description: Service +properties: + name: + type: string + example: node + description: Name + environment: + type: string + example: prod + description: Environment diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/settings_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/settings_object.yaml new file mode 100644 index 0000000000000..cf09f1b6254bd --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/settings_object.yaml @@ -0,0 +1,4 @@ +type: object +description: Agent configuration settings +additionalProperties: + type: string diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/single_agent_configuration_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/single_agent_configuration_response.yaml new file mode 100644 index 0000000000000..4ef312304cc60 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/single_agent_configuration_response.yaml @@ -0,0 +1,8 @@ +allOf: + - type: object + required: + - id + properties: + id: + type: string + - $ref: 'agent_configuration_object.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/source_maps_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/source_maps_response.yaml new file mode 100644 index 0000000000000..f5590110fecd2 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/source_maps_response.yaml @@ -0,0 +1,38 @@ +type: object +properties: + artifacts: + type: array + description: Artifacts + items: + allOf: + - type: object + properties: + body: + type: object + properties: + serviceName: + type: string + serviceVersion: + type: string + bundleFilepath: + type: string + sourceMap: + type: object + properties: + version: + type: number + file: + type: string + sources: + type: array + items: + type: string + sourcesContent: + type: array + items: + type: string + mappings: + type: string + sourceRoot: + type: string + - $ref: 'base_source_map_object.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/upload_source_map_object.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/upload_source_map_object.yaml new file mode 100644 index 0000000000000..00483e3606df0 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/upload_source_map_object.yaml @@ -0,0 +1,22 @@ +type: object +required: + - service_name + - service_version + - bundle_filepath + - sourcemap +properties: + service_name: + type: string + description: The name of the service that the service map should apply to. + service_version: + type: string + description: The version of the service that the service map should apply to. + bundle_filepath: + type: string + description: The absolute path of the final bundle as used in the web application. + sourcemap: + type: string + format: binary + description: | + The source map. String or file upload. It must follow the + [source map revision 3 proposal](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k). diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/upload_source_maps_response.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/upload_source_maps_response.yaml new file mode 100644 index 0000000000000..6b677374de4ab --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/components/schemas/upload_source_maps_response.yaml @@ -0,0 +1,6 @@ +allOf: + - type: object + properties: + body: + type: string + - $ref: 'base_source_map_object.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/entrypoint.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/entrypoint.yaml new file mode 100644 index 0000000000000..abb21fb980a9a --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/entrypoint.yaml @@ -0,0 +1,42 @@ +openapi: 3.0.2 +info: + title: APM UI + version: 1.0.0 +tags: + - name: APM agent keys + description: > + Configure APM agent keys to authorize requests from APM agents to the APM Server. + - name: APM agent configuration + description: > + Adjust APM agent configuration without need to redeploy your application. + - name: APM sourcemaps + description: Configure APM source maps. + - name: APM annotations + description: > + Annotate visualizations in the APM app with significant events. + Annotations enable you to easily see how events are impacting the performance of your applications. + - name: APM server schema + description: Create APM fleet server schema. +paths: + /api/apm/agent_keys: + $ref: 'paths/api@apm@agent_keys.yaml' + /api/apm/services/{serviceName}/annotation/search: + $ref: 'paths/api@apm@services@{service_name}@annotation@search.yaml' + /api/apm/services/{serviceName}/annotation: + $ref: 'paths/api@apm@services@{service_name}@annotation.yaml' + /api/apm/settings/agent-configuration: + $ref: 'paths/api@apm@settings@agent_configuration.yaml' + /api/apm/settings/agent-configuration/view: + $ref: 'paths/api@apm@settings@agent_configuration@view.yaml' + /api/apm/settings/agent-configuration/search: + $ref: 'paths/api@apm@settings@agent_configuration@search.yaml' + /api/apm/settings/agent-configuration/environments: + $ref: 'paths/api@apm@settings@agent_configuration@environments.yaml' + /api/apm/settings/agent-configuration/agent_name: + $ref: 'paths/api@apm@settings@agent_configuration@agent_name.yaml' + /api/apm/sourcemaps: + $ref: 'paths/api@apm@sourcemaps.yaml' + /api/apm/sourcemaps/{id}: + $ref: 'paths/api@apm@sourcemaps@{id}.yaml' + /api/apm/fleet/apm_server_schema: + $ref: 'paths/api@apm@fleet@apm_server_schema.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/README.md b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/README.md new file mode 100644 index 0000000000000..b7818c8474fc8 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/README.md @@ -0,0 +1,10 @@ +Paths +===== + +Each path definition for which there is a specification exists within this folder. + +These files currently use the following conventions: + +* path separator token (e.g. `@`) is included in the file name +* path parameter (e.g. `{example}`) is included in the file name +* there is one file per path; each file can contain multiple operations diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@agent_keys.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@agent_keys.yaml new file mode 100644 index 0000000000000..46b1588517761 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@agent_keys.yaml @@ -0,0 +1,46 @@ +post: + summary: Create an APM agent key + description: Create a new agent key for APM. + operationId: createAgentKey + tags: + - APM agent keys + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - $ref: '../components/headers/kbn_xsrf.yaml' + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/agent_keys_object.yaml' + responses: + "200": + description: Agent key created successfully + content: + application/json: + schema: + $ref: '../components/schemas/agent_keys_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '../components/schemas/500_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@fleet@apm_server_schema.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@fleet@apm_server_schema.yaml new file mode 100644 index 0000000000000..2c4629b44a211 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@fleet@apm_server_schema.yaml @@ -0,0 +1,53 @@ +post: + summary: Save APM server schema + operationId: saveApmServerSchema + tags: + - APM server schema + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - $ref: '../components/headers/kbn_xsrf.yaml' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + schema: + type: object + description: Schema object + additionalProperties: true + example: + foo: "bar" + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + additionalProperties: false + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@services@{service_name}@annotation.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@services@{service_name}@annotation.yaml new file mode 100644 index 0000000000000..3894bd6da2015 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@services@{service_name}@annotation.yaml @@ -0,0 +1,52 @@ +post: + summary: Create a service annotation + description: Create a new annotation for a specific service. + operationId: createAnnotation + tags: + - APM annotations + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - $ref: '../components/headers/kbn_xsrf.yaml' + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/create_annotation_object.yaml' + responses: + '200': + description: Annotation created successfully + content: + application/json: + schema: + $ref: '../components/schemas/create_annotation_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@services@{service_name}@annotation@search.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@services@{service_name}@annotation@search.yaml new file mode 100644 index 0000000000000..0f1391be89806 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@services@{service_name}@annotation@search.yaml @@ -0,0 +1,57 @@ +get: + summary: Search for annotations + description: Search for annotations related to a specific service. + operationId: getAnnotation + tags: + - APM annotations + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + - name: environment + in: query + required: false + description: The environment to filter annotations by + schema: + type: string + - name: start + in: query + required: false + description: The start date for the search + schema: + type: string + - name: end + in: query + required: false + description: The end date for the search + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + schema: + $ref: '../components/schemas/annotation_search_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '../components/schemas/500_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration.yaml new file mode 100644 index 0000000000000..f508e855a3883 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration.yaml @@ -0,0 +1,128 @@ +get: + summary: Get a list of agent configurations + operationId: getAgentConfigurations + tags: + - APM agent configuration + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '../components/schemas/agent_configurations_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' +delete: + summary: Delete agent configuration + operationId: deleteAgentConfiguration + tags: + - APM agent configuration + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - $ref: '../components/headers/kbn_xsrf.yaml' + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/service_object.yaml' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '../components/schemas/delete_agent_configurations_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' +put: + summary: Create or update agent configuration + operationId: createUpdateAgentConfiguration + tags: + - APM agent configuration + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - $ref: '../components/headers/kbn_xsrf.yaml' + - name: overwrite + in: query + description: If the config exists ?overwrite=true is required + schema: + type: boolean + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/agent_configuration_intake_object.yaml' + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + additionalProperties: false + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@agent_name.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@agent_name.yaml new file mode 100644 index 0000000000000..4ad10fbb00833 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@agent_name.yaml @@ -0,0 +1,40 @@ +get: + summary: Get agent name for service + description: Retrieve `agentName` for a service. + operationId: getAgentNameForService + tags: + - APM agent configuration + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - name: serviceName + in: query + description: The name of the service + required: true + schema: + type: string + example: node + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '../components/schemas/service_agent_name_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@environments.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@environments.yaml new file mode 100644 index 0000000000000..c0791b92ac148 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@environments.yaml @@ -0,0 +1,37 @@ +get: + summary: Get environments for service + operationId: getEnvironmentsForService + tags: + - APM agent configuration + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - name: serviceName + in: query + description: The name of the service + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '../components/schemas/service_environments_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@search.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@search.yaml new file mode 100644 index 0000000000000..8ae4ce975fc08 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@search.yaml @@ -0,0 +1,41 @@ +post: + summary: Lookup single agent configuration + description: | + This endpoint allows to search for single agent configuration and update 'applied_by_agent' field. + operationId: searchSingleConfiguration + tags: + - APM agent configuration + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - $ref: '../components/headers/kbn_xsrf.yaml' + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/search_agent_configuration_object.yaml' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '../components/schemas/search_agent_configuration_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@view.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@view.yaml new file mode 100644 index 0000000000000..23e5cc2186d12 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@settings@agent_configuration@view.yaml @@ -0,0 +1,44 @@ +get: + summary: Get single agent configuration + operationId: getSingleAgentConfiguration + tags: + - APM agent configuration + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - name: name + in: query + description: Service name + schema: + type: string + example: node + - name: environment + in: query + description: Service environment + schema: + type: string + example: prod + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '../components/schemas/single_agent_configuration_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@sourcemaps.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@sourcemaps.yaml new file mode 100644 index 0000000000000..142cd0d2673c1 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@sourcemaps.yaml @@ -0,0 +1,101 @@ +get: + summary: Get source maps + description: Returns an array of Fleet artifacts, including source map uploads. + operationId: getSourceMaps + tags: + - APM sourcemaps + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - name: page + in: query + description: Page number + schema: + type: number + - name: perPage + in: query + description: Number of records per page + schema: + type: number + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '../components/schemas/source_maps_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '../components/schemas/500_response.yaml' + '501': + description: Not Implemented response + content: + application/json: + schema: + $ref: '../components/schemas/501_response.yaml' +post: + summary: Upload source map + description: Upload a source map for a specific service and version. + operationId: uploadSourceMap + tags: + - APM sourcemaps + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - $ref: '../components/headers/kbn_xsrf.yaml' + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '../components/schemas/upload_source_map_object.yaml' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '../components/schemas/upload_source_maps_response.yaml' + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '../components/schemas/500_response.yaml' + '501': + description: Not Implemented response + content: + application/json: + schema: + $ref: '../components/schemas/501_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@sourcemaps@{id}.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@sourcemaps@{id}.yaml new file mode 100644 index 0000000000000..3f165360bf60c --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/paths/api@apm@sourcemaps@{id}.yaml @@ -0,0 +1,53 @@ +delete: + summary: Delete source map + description: Delete a previously uploaded source map. + operationId: deleteSourceMap + tags: + - APM sourcemaps + parameters: + - $ref: '../components/headers/elastic_api_version.yaml' + - $ref: '../components/headers/kbn_xsrf.yaml' + - name: id + in: path + description: Source map identifier + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + additionalProperties: false + '400': + description: Bad Request response + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '403': + description: Forbidden response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' + '500': + description: Internal Server Error response + content: + application/json: + schema: + $ref: '../components/schemas/500_response.yaml' + '501': + description: Not Implemented response + content: + application/json: + schema: + $ref: '../components/schemas/501_response.yaml' diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/empty_dashboards.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/empty_dashboards.tsx index 9ce282d267f11..9b7ace008206b 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/empty_dashboards.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/empty_dashboards.tsx @@ -59,7 +59,7 @@ export function EmptyDashboards({ actions }: Props) {

{i18n.translate('xpack.apm.serviceDashboards.emptyBody.getStarted', { - defaultMessage: 'To get started, add your dashaboard', + defaultMessage: 'To get started, add your dashboard', })}

diff --git a/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/context.tsx b/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/context.tsx index e661ef2450310..7ec17b3a6cf3b 100644 --- a/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/context.tsx +++ b/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/context.tsx @@ -76,7 +76,7 @@ export function BreadcrumbsContextProvider({ children }: { children: React.React }; }); - useBreadcrumbs(formattedBreadcrumbs, { serverless }); + useBreadcrumbs(formattedBreadcrumbs, { serverless, absoluteProjectStyleBreadcrumbs: false }); return {children}; } diff --git a/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/use_breadcrumb.ts b/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/use_breadcrumb.ts index a6b80fd088bff..846aa1ec70877 100644 --- a/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/use_breadcrumb.ts +++ b/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/use_breadcrumb.ts @@ -8,8 +8,10 @@ import { useCurrentRoute } from '@kbn/typed-react-router-config'; import { useContext, useEffect, useRef } from 'react'; import { castArray } from 'lodash'; +import useObservable from 'react-use/lib/useObservable'; import { Breadcrumb, BreadcrumbsContext } from './context'; import { useKibanaEnvironmentContext } from '../kibana_environment_context/use_kibana_environment_context'; +import { useKibana } from '../kibana_context/use_kibana'; export function useBreadcrumb( callback: () => Breadcrumb | Breadcrumb[], @@ -17,6 +19,9 @@ export function useBreadcrumb( options?: { omitRootOnServerless?: boolean; omitOnServerless?: boolean } ) { const { isServerlessEnv } = useKibanaEnvironmentContext(); + const { + services: { chrome }, + } = useKibana(); const { omitRootOnServerless = false, omitOnServerless = false } = options || {}; const api = useContext(BreadcrumbsContext); @@ -29,8 +34,11 @@ export function useBreadcrumb( const matchedRoute = useRef(match?.route); + const chromeStyle = useObservable(chrome.getChromeStyle$()); + useEffect(() => { - if (isServerlessEnv && omitOnServerless) { + const isProjectStyle = isServerlessEnv || chromeStyle === 'project'; + if (isProjectStyle && omitOnServerless) { return; } @@ -42,10 +50,9 @@ export function useBreadcrumb( if (matchedRoute.current) { const breadcrumbs = castArray(callback()); - api.set( matchedRoute.current, - isServerlessEnv && omitRootOnServerless && breadcrumbs.length >= 1 + isProjectStyle && omitRootOnServerless && breadcrumbs.length >= 1 ? breadcrumbs.slice(1) : breadcrumbs ); @@ -57,5 +64,5 @@ export function useBreadcrumb( } }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [match, ...fnDeps]); + }, [match, chromeStyle, ...fnDeps]); } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts index d1e55d488ba5c..5e065e55db44e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts @@ -47,12 +47,16 @@ export const useRedirectLink = ({ share.url.locators.get(SINGLE_DATASET_LOCATOR_ID); const isLogsExplorerAppAccessible = useObservable( - application.applications$.pipe( - map( - (apps) => - (apps.get(OBSERVABILITY_LOGS_EXPLORER_APP_ID)?.status ?? AppStatus.inaccessible) === - AppStatus.accessible - ) + useMemo( + () => + application.applications$.pipe( + map( + (apps) => + (apps.get(OBSERVABILITY_LOGS_EXPLORER_APP_ID)?.status ?? AppStatus.inaccessible) === + AppStatus.accessible + ) + ), + [application.applications$] ), false ); diff --git a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.tsx b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.tsx index a0079568803b6..a7760014dec8c 100644 --- a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.tsx +++ b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.tsx @@ -288,5 +288,8 @@ const Wrapper = styled.div<{ right: 50%; transform: translate(50%, -50%); } + .embPanel { + outline: none; + } } `; diff --git a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/index.tsx b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/index.tsx index c4061f05ce91b..750429602aecf 100644 --- a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/index.tsx +++ b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/index.tsx @@ -60,7 +60,7 @@ export function ExploratoryViewPage({ }), }, ], - { app } + { app, classicOnly: true } ); const kbnUrlStateStorage = useSessionStorage diff --git a/x-pack/plugins/observability_solution/infra/public/apps/logs_app.tsx b/x-pack/plugins/observability_solution/infra/public/apps/logs_app.tsx index 329e059288e3e..9d5583b0ecf4c 100644 --- a/x-pack/plugins/observability_solution/infra/public/apps/logs_app.tsx +++ b/x-pack/plugins/observability_solution/infra/public/apps/logs_app.tsx @@ -6,13 +6,19 @@ */ import { History } from 'history'; -import { CoreStart } from '@kbn/core/public'; -import React from 'react'; +import { AppStatus, CoreStart } from '@kbn/core/public'; +import React, { useMemo } from 'react'; import ReactDOM from 'react-dom'; import { Router, Routes, Route } from '@kbn/shared-ux-router'; import { AppMountParameters } from '@kbn/core/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { AllDatasetsLocatorParams, ALL_DATASETS_LOCATOR_ID } from '@kbn/deeplinks-observability'; +import { + AllDatasetsLocatorParams, + ALL_DATASETS_LOCATOR_ID, + OBSERVABILITY_LOGS_EXPLORER_APP_ID, +} from '@kbn/deeplinks-observability'; +import useObservable from 'react-use/lib/useObservable'; +import { map } from 'rxjs'; import { LinkToLogsPage } from '../pages/link_to/link_to_logs'; import { LogsPage } from '../pages/logs'; import { InfraClientStartDeps, InfraClientStartExports } from '../types'; @@ -57,7 +63,22 @@ const LogsApp: React.FC<{ storage: Storage; theme$: AppMountParameters['theme$']; }> = ({ core, history, pluginStart, plugins, setHeaderActionMenu, storage, theme$ }) => { - const { logs, discover, fleet } = core.application.capabilities; + const { logs } = core.application.capabilities; + + const isLogsExplorerAppAccessible = useObservable( + useMemo( + () => + core.application.applications$.pipe( + map( + (apps) => + (apps.get(OBSERVABILITY_LOGS_EXPLORER_APP_ID)?.status ?? AppStatus.inaccessible) === + AppStatus.accessible + ) + ), + [core.application.applications$] + ), + false + ); return ( @@ -74,7 +95,7 @@ const LogsApp: React.FC<{ toastsService={core.notifications.toasts} > - {Boolean(discover?.show && fleet?.read) && ( + {isLogsExplorerAppAccessible && ( { const { request$ } = useRequestObservable(); const { isActiveTab } = useTabSwitcherContext(); const { dataStreams, status: dataStreamsStatus } = useEntitySummary({ - entityType: EntityType.HOST, + entityType: ENTITY_TYPES.HOST, entityId: asset.name, }); const addMetricsCalloutId: AddMetricsCalloutKey = 'hostProcesses'; diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/template/page.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/template/page.tsx index c6e8790eeff6a..5c187bb6186d6 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/template/page.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/template/page.tsx @@ -50,18 +50,15 @@ export const Page = ({ tabs = [], links = [] }: ContentTemplateProps) => { const parentBreadcrumbResolver = useParentBreadcrumbResolver(); const breadcrumbOptions = parentBreadcrumbResolver.getBreadcrumbOptions(asset.type); - useMetricsBreadcrumbs( - [ - { - ...breadcrumbOptions.link, - text: breadcrumbOptions.text, - }, - { - text: asset.name, - }, - ], - { deeperContextServerless: true } - ); + useMetricsBreadcrumbs([ + { + ...breadcrumbOptions.link, + text: breadcrumbOptions.text, + }, + { + text: asset.name, + }, + ]); useEffect(() => { if (trackOnlyOnce.current) { diff --git a/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx b/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx index 63107f4a4d031..21e61c08d281b 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx @@ -9,13 +9,17 @@ import { EuiCallOut } from '@elastic/eui'; import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButton } from '@elastic/eui'; -import { AllDatasetsLocatorParams, ALL_DATASETS_LOCATOR_ID } from '@kbn/deeplinks-observability'; +import { + AllDatasetsLocatorParams, + ALL_DATASETS_LOCATOR_ID, + DatasetLocatorParams, +} from '@kbn/deeplinks-observability'; import { getRouterLinkProps } from '@kbn/router-utils'; import useLocalStorage from 'react-use/lib/useLocalStorage'; import { euiThemeVars } from '@kbn/ui-theme'; import { css } from '@emotion/css'; -import { SharePublicStart } from '@kbn/share-plugin/public/plugin'; +import { LocatorPublic } from '@kbn/share-plugin/common'; import { useKibanaContextForPlugin } from '../hooks/use_kibana'; const pageConfigurations = { @@ -44,14 +48,22 @@ interface LogsDeprecationCalloutProps { export const LogsDeprecationCallout = ({ page }: LogsDeprecationCalloutProps) => { const { - services: { share }, + services: { + share, + application: { + capabilities: { discover, fleet }, + }, + }, } = useKibanaContextForPlugin(); const { dismissalStorageKey, message } = pageConfigurations[page]; const [isDismissed, setDismissed] = useLocalStorage(dismissalStorageKey, false); - if (isDismissed) { + const allDatasetLocator = + share.url.locators.get(ALL_DATASETS_LOCATOR_ID); + + if (isDismissed || !(allDatasetLocator && discover?.show && fleet?.read)) { return null; } @@ -71,7 +83,7 @@ export const LogsDeprecationCallout = ({ page }: LogsDeprecationCalloutProps) => fill data-test-subj="infraLogsDeprecationCalloutTryLogsExplorerButton" color="warning" - {...getLogsExplorerLinkProps(share)} + {...getLogsExplorerLinkProps(allDatasetLocator)} > {i18n.translate('xpack.infra.logsDeprecationCallout.tryLogsExplorerButtonLabel', { defaultMessage: 'Try Logs Explorer', @@ -81,9 +93,7 @@ export const LogsDeprecationCallout = ({ page }: LogsDeprecationCalloutProps) => ); }; -const getLogsExplorerLinkProps = (share: SharePublicStart) => { - const locator = share.url.locators.get(ALL_DATASETS_LOCATOR_ID)!; - +const getLogsExplorerLinkProps = (locator: LocatorPublic) => { return getRouterLinkProps({ href: locator.getRedirectUrl({}), onClick: () => locator.navigate({}), diff --git a/x-pack/plugins/observability_solution/infra/public/components/ml/anomaly_detection/job_setup_screen.tsx b/x-pack/plugins/observability_solution/infra/public/components/ml/anomaly_detection/job_setup_screen.tsx index 9543e84585c02..e2ee8a127a881 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/ml/anomaly_detection/job_setup_screen.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/ml/anomaly_detection/job_setup_screen.tsx @@ -38,7 +38,7 @@ import { FixedDatePicker } from '../../fixed_datepicker'; import { DEFAULT_K8S_PARTITION_FIELD } from '../../../containers/ml/modules/metrics_k8s/module_descriptor'; import { convertKueryToElasticSearchQuery } from '../../../utils/kuery'; import { INFRA_ML_FLYOUT_FEEDBACK_LINK } from './flyout_home'; -import { KibanaEnvironmentContext } from '../../../hooks/use_kibana'; +import { KibanaEnvironmentContext, useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer/components/kuery_bar'; interface Props { @@ -60,6 +60,7 @@ export const JobSetupScreen = (props: Props) => { const trackMetric = useUiTracker({ app: 'infra_metrics' }); const { kibanaVersion, isCloudEnv, isServerlessEnv } = useContext(KibanaEnvironmentContext); const { euiTheme } = useEuiTheme(); + const { telemetry } = useKibanaContextForPlugin().services; const indices = host.sourceConfiguration.indices; @@ -95,23 +96,47 @@ export const JobSetupScreen = (props: Props) => { } }, [props.jobType, kubernetes.jobSummaries, host.jobSummaries]); - const updateStart = useCallback((date: Moment) => { - setStartDate(date); - }, []); + const updateStart = useCallback( + (date: Moment) => { + setStartDate(date); + telemetry.reportAnomalyDetectionDateFieldChange({ + job_type: props.jobType, + start_date: date.toISOString(), + }); + }, + [telemetry, props.jobType] + ); const createJobs = useCallback(() => { + const date = moment(startDate).toDate(); if (hasSummaries) { + telemetry.reportAnomalyDetectionSetup({ + job_type: props.jobType, + configured_fields: { + start_date: date.toISOString(), + partition_field: partitionField ? partitionField[0] : undefined, + filter_field: filter ? filter : undefined, + }, + }); cleanUpAndSetUpModule( indices, - moment(startDate).toDate().getTime(), + date.getTime(), undefined, filterQuery, partitionField ? partitionField[0] : undefined ); } else { + telemetry.reportAnomalyDetectionSetup({ + job_type: props.jobType, + configured_fields: { + start_date: date.toISOString(), + partition_field: partitionField ? partitionField[0] : undefined, + filter_field: filter, + }, + }); setUpModule( indices, - moment(startDate).toDate().getTime(), + date.getTime(), undefined, filterQuery, partitionField ? partitionField[0] : undefined @@ -125,22 +150,36 @@ export const JobSetupScreen = (props: Props) => { indices, partitionField, startDate, + telemetry, + filter, + props.jobType, ]); const onFilterChange = useCallback( (f: string) => { setFilter(f || ''); setFilterQuery(convertKueryToElasticSearchQuery(f, metricsView?.dataViewReference) || ''); + telemetry.reportAnomalyDetectionFilterFieldChange({ + job_type: props.jobType, + filter_field: f ? f : undefined, + }); }, - [metricsView?.dataViewReference] + [metricsView?.dataViewReference, telemetry, props.jobType] ); /* eslint-disable-next-line react-hooks/exhaustive-deps */ const debouncedOnFilterChange = useCallback(debounce(onFilterChange, 500), [onFilterChange]); - const onPartitionFieldChange = useCallback((value: Array<{ label: string }>) => { - setPartitionField(value.map((v) => v.label)); - }, []); + const onPartitionFieldChange = useCallback( + (value: Array<{ label: string }>) => { + setPartitionField(value.map((v) => v.label)); + telemetry.reportAnomalyDetectionPartitionFieldChange({ + job_type: props.jobType, + partition_field: value.length > 0 ? value[0].label : undefined, + }); + }, + [telemetry, props.jobType] + ); useEffect(() => { if (props.jobType === 'kubernetes') { diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_breadcrumbs.ts b/x-pack/plugins/observability_solution/infra/public/hooks/use_breadcrumbs.ts deleted file mode 100644 index 0cf9efef908bb..0000000000000 --- a/x-pack/plugins/observability_solution/infra/public/hooks/use_breadcrumbs.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ChromeBreadcrumb } from '@kbn/core/public'; -import { useEffect } from 'react'; -import { useLinkProps } from '@kbn/observability-shared-plugin/public'; -import { observabilityTitle } from '../translations'; -import { useKibanaContextForPlugin } from './use_kibana'; - -type AppId = 'logs' | 'metrics'; - -export const useBreadcrumbs = (app: AppId, appTitle: string, extraCrumbs: ChromeBreadcrumb[]) => { - const { - services: { chrome }, - } = useKibanaContextForPlugin(); - - const observabilityLinkProps = useLinkProps({ app: 'observability-overview' }); - const appLinkProps = useLinkProps({ app }); - - useEffect(() => { - const breadcrumbs = [ - { - ...observabilityLinkProps, - text: observabilityTitle, - }, - { - ...appLinkProps, - text: appTitle, - }, - ...extraCrumbs, - ]; - - const docTitle = [...breadcrumbs].reverse().map((breadcrumb) => breadcrumb.text as string); - - chrome.docTitle.change(docTitle); - chrome.setBreadcrumbs(breadcrumbs); - }, [appLinkProps, appTitle, chrome, extraCrumbs, observabilityLinkProps]); -}; diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_logs_breadcrumbs.tsx b/x-pack/plugins/observability_solution/infra/public/hooks/use_logs_breadcrumbs.tsx index d2fc556caa57b..2eba7845b8d24 100644 --- a/x-pack/plugins/observability_solution/infra/public/hooks/use_logs_breadcrumbs.tsx +++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_logs_breadcrumbs.tsx @@ -6,10 +6,18 @@ */ import { ChromeBreadcrumb } from '@kbn/core/public'; -import { useBreadcrumbs } from './use_breadcrumbs'; +import { useBreadcrumbs, useLinkProps } from '@kbn/observability-shared-plugin/public'; import { LOGS_APP } from '../../common/constants'; import { logsTitle } from '../translations'; export const useLogsBreadcrumbs = (extraCrumbs: ChromeBreadcrumb[]) => { - useBreadcrumbs(LOGS_APP, logsTitle, extraCrumbs); + const appLinkProps = useLinkProps({ app: LOGS_APP }); + const breadcrumbs = [ + { + ...appLinkProps, + text: logsTitle, + }, + ...extraCrumbs, + ]; + useBreadcrumbs(breadcrumbs, { classicOnly: true }); }; diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_metrics_breadcrumbs.tsx b/x-pack/plugins/observability_solution/infra/public/hooks/use_metrics_breadcrumbs.tsx index defc8b3210f48..d5a6011a68e8e 100644 --- a/x-pack/plugins/observability_solution/infra/public/hooks/use_metrics_breadcrumbs.tsx +++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_metrics_breadcrumbs.tsx @@ -5,42 +5,25 @@ * 2.0. */ -import { useEffect, useMemo } from 'react'; import { ChromeBreadcrumb } from '@kbn/core/public'; import { useBreadcrumbs, useLinkProps } from '@kbn/observability-shared-plugin/public'; import { METRICS_APP } from '../../common/constants'; import { metricsTitle } from '../translations'; import { useKibanaContextForPlugin } from './use_kibana'; -export const useMetricsBreadcrumbs = ( - extraCrumbs: ChromeBreadcrumb[], - options?: { deeperContextServerless: boolean } -) => { +export const useMetricsBreadcrumbs = (extraCrumbs: ChromeBreadcrumb[]) => { const { services: { serverless }, } = useKibanaContextForPlugin(); const appLinkProps = useLinkProps({ app: METRICS_APP }); - const breadcrumbs = useMemo( - () => [ - { - ...appLinkProps, - text: metricsTitle, - }, - ...extraCrumbs, - ], - [appLinkProps, extraCrumbs] - ); + const breadcrumbs = [ + { + ...appLinkProps, + text: metricsTitle, + }, + ...extraCrumbs, + ]; - useBreadcrumbs(breadcrumbs); - - useEffect(() => { - // For deeper context breadcrumbs in serveless, the `serverless` plugin provides its own breadcrumb service. - // https://docs.elastic.dev/kibana-dev-docs/serverless-project-navigation#breadcrumbs - if (serverless && options?.deeperContextServerless) { - // The initial path is already set in the breadcrumbs - const [, ...serverlessBreadcrumbs] = breadcrumbs; - serverless.setBreadcrumbs(serverlessBreadcrumbs); - } - }, [breadcrumbs, options?.deeperContextServerless, serverless]); + useBreadcrumbs(breadcrumbs, { serverless }); }; diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/index.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/index.tsx index 1d0e394b281d4..7a0289d461af7 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/index.tsx @@ -17,9 +17,8 @@ import { EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; -import { useKibana, useUiSetting } from '@kbn/kibana-react-plugin/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; import { HeaderMenuPortal, useLinkProps } from '@kbn/observability-shared-plugin/public'; -import { enableInfrastructureHostsView } from '@kbn/observability-plugin/common'; import { SharePublicStart } from '@kbn/share-plugin/public/plugin'; import { ObservabilityOnboardingLocatorParams, @@ -60,7 +59,6 @@ export const InfrastructurePage = () => { const config = usePluginConfig(); const { application } = useKibana<{ share: SharePublicStart }>().services; const { setHeaderActionMenu, theme$ } = useContext(HeaderActionMenuContext); - const isHostsViewEnabled = useUiSetting(enableInfrastructureHostsView); const uiCapabilities = application?.capabilities; @@ -128,7 +126,7 @@ export const InfrastructurePage = () => { )} - {isHostsViewEnabled ? : null} + diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx index fb787e8df7c5b..02e4e634d30d1 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx @@ -11,8 +11,6 @@ import { first } from 'lodash'; import { EuiPopover, EuiToolTip } from '@elastic/eui'; import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; import { useBoolean } from '@kbn/react-hooks'; -import { useUiSetting } from '@kbn/kibana-react-plugin/public'; -import { enableInfrastructureContainerAssetView } from '@kbn/observability-plugin/common'; import { InfraWaffleMapBounds, InfraWaffleMapNode, @@ -55,9 +53,7 @@ export const Node = ({ const color = colorFromValue(options.legend, rawValue, bounds); const value = formatter(rawValue); - const isContainerAssetViewEnabled = useUiSetting(enableInfrastructureContainerAssetView); - const showContainerAssetDetailPage = nodeType === 'container' && isContainerAssetViewEnabled; - const isFlyoutMode = nodeType === 'host' || showContainerAssetDetailPage; + const isFlyoutMode = nodeType === 'host' || nodeType === 'container'; const toggleAssetPopover = () => { if (isFlyoutMode) { diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/index.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/index.tsx index b41de1b7b9e3a..064973ebd92f6 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/index.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/index.tsx @@ -8,9 +8,7 @@ import { EuiErrorBoundary } from '@elastic/eui'; import React from 'react'; import { useRouteMatch } from 'react-router-dom'; -import { useUiSetting } from '@kbn/kibana-react-plugin/public'; import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; -import { enableInfrastructureContainerAssetView } from '@kbn/observability-plugin/common'; import { AssetDetailPage } from './asset_detail_page'; import { MetricDetailPage } from './metric_detail_page'; import { MetricsTimeProvider } from './hooks/use_metrics_time'; @@ -20,12 +18,9 @@ export const NodeDetail = () => { params: { type: nodeType }, } = useRouteMatch<{ type: InventoryItemType; node: string }>(); - const isContainerAssetViewEnabled = useUiSetting(enableInfrastructureContainerAssetView); - - const showContainerAssetDetailPage = nodeType === 'container' && isContainerAssetViewEnabled; return ( - {nodeType === 'host' || showContainerAssetDetailPage ? ( + {nodeType === 'host' || nodeType === 'container' ? ( ) : ( diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/metric_detail_page.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/metric_detail_page.tsx index 65ab15a5713be..0e6183268ddda 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/metric_detail_page.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/metric_detail_page.tsx @@ -54,18 +54,15 @@ export const MetricDetailPage = () => { }); const breadcrumbOptions = parentBreadcrumbResolver.getBreadcrumbOptions(nodeType); - useMetricsBreadcrumbs( - [ - { - ...breadcrumbOptions.link, - text: breadcrumbOptions.text, - }, - { - text: name, - }, - ], - { deeperContextServerless: true } - ); + useMetricsBreadcrumbs([ + { + ...breadcrumbOptions.link, + text: breadcrumbOptions.text, + }, + { + text: name, + }, + ]); const [sideNav, setSideNav] = useState([]); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/features_configuration_panel.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/features_configuration_panel.tsx index d8df6ef8b39fa..df8b78b5ef64b 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/features_configuration_panel.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/features_configuration_panel.tsx @@ -11,10 +11,8 @@ import { EuiForm } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { - enableInfrastructureHostsView, enableInfrastructureProfilingIntegration, enableInfrastructureAssetCustomDashboards, - enableInfrastructureContainerAssetView, } from '@kbn/observability-plugin/common'; import { useEditableSettings } from '@kbn/observability-shared-plugin/public'; import { withSuspense } from '@kbn/shared-ux-utility'; @@ -71,12 +69,6 @@ export function FeaturesConfigurationPanel({ validateChange: async () => settingsValidationResponse, }} > - )} - ); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx index de078dcb354df..8deaa805ba9b4 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx @@ -14,8 +14,6 @@ import { useEditableSettings, } from '@kbn/observability-shared-plugin/public'; import { - enableInfrastructureContainerAssetView, - enableInfrastructureHostsView, enableInfrastructureProfilingIntegration, enableInfrastructureAssetCustomDashboards, } from '@kbn/observability-plugin/common'; @@ -87,10 +85,8 @@ export const SourceConfigurationSettings = ({ getUnsavedChanges, } = useSourceConfigurationFormState(source?.configuration); const infraUiSettings = useEditableSettings([ - enableInfrastructureHostsView, enableInfrastructureProfilingIntegration, enableInfrastructureAssetCustomDashboards, - enableInfrastructureContainerAssetView, ]); const resetAllUnsavedChanges = useCallback(() => { diff --git a/x-pack/plugins/observability_solution/infra/public/plugin.ts b/x-pack/plugins/observability_solution/infra/public/plugin.ts index daaa3510e1660..0e88b514c51ec 100644 --- a/x-pack/plugins/observability_solution/infra/public/plugin.ts +++ b/x-pack/plugins/observability_solution/infra/public/plugin.ts @@ -13,16 +13,23 @@ import { DEFAULT_APP_CATEGORIES, PluginInitializerContext, AppDeepLinkLocations, + AppStatus, } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; -import { enableInfrastructureHostsView } from '@kbn/observability-plugin/public'; import { METRICS_EXPLORER_LOCATOR_ID, MetricsExplorerLocatorParams, ObservabilityTriggerId, } from '@kbn/observability-shared-plugin/common'; -import { BehaviorSubject, combineLatest, from } from 'rxjs'; -import { map } from 'rxjs'; +import { + BehaviorSubject, + combineLatest, + distinctUntilChanged, + from, + of, + switchMap, + map, +} from 'rxjs'; import type { EmbeddableApiContext } from '@kbn/presentation-publishing'; import { apiCanAddNewPanel } from '@kbn/presentation-containers'; import { IncompatibleActionError, ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public'; @@ -35,6 +42,7 @@ import { } from '@kbn/observability-shared-plugin/common'; import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; import { NavigationEntry } from '@kbn/observability-shared-plugin/public'; +import { OBSERVABILITY_LOGS_EXPLORER_APP_ID } from '@kbn/deeplinks-observability/constants'; import type { InfraPublicConfig } from '../common/plugin_config_types'; import { createInventoryMetricRuleType } from './alerting/inventory'; import { createLogThresholdRuleType } from './alerting/log_threshold'; @@ -131,76 +139,64 @@ export class Plugin implements InfraClientPluginClass { messageFields: this.config.sources?.default?.fields?.message, }); - const startDep$AndHostViewFlag$ = combineLatest([ - from(core.getStartServices()), - core.settings.client.get$(enableInfrastructureHostsView), - ]); + const startDep$AndAccessibleFlag$ = from(core.getStartServices()).pipe( + switchMap(([{ application }]) => + combineLatest([of(application), getLogsExplorerAccessible$(application)]) + ) + ); const logRoutes = getLogsAppRoutes({ isLogsStreamEnabled }); /** !! Need to be kept in sync with the deepLinks in x-pack/plugins/observability_solution/infra/public/plugin.ts */ pluginsSetup.observabilityShared.navigation.registerSections( - startDep$AndHostViewFlag$.pipe( - map( - ([ - [ - { - application: { capabilities }, - }, - ], - isInfrastructureHostsViewEnabled, - ]) => { - const { infrastructure, logs } = capabilities; - return [ - ...(logs.show - ? [ - { - label: logsTitle, - sortKey: 200, - entries: getLogsNavigationEntries({ - capabilities, - config: this.config, - routes: logRoutes, - }), - }, - ] - : []), - ...(infrastructure.show - ? [ - { - label: metricsTitle, - sortKey: 300, - entries: [ - { - label: inventoryTitle, - app: 'metrics', - path: '/inventory', - }, - ...(this.config.featureFlags.metricsExplorerEnabled - ? [ - { - label: metricsExplorerTitle, - app: 'metrics', - path: '/explorer', - }, - ] - : []), - ...(isInfrastructureHostsViewEnabled - ? [ - { - label: hostsTitle, - app: 'metrics', - path: '/hosts', - }, - ] - : []), - ], - }, - ] - : []), - ]; - } - ) + startDep$AndAccessibleFlag$.pipe( + map(([application, isLogsExplorerAccessible]) => { + const { infrastructure, logs } = application.capabilities; + return [ + ...(logs.show + ? [ + { + label: logsTitle, + sortKey: 200, + entries: getLogsNavigationEntries({ + isLogsExplorerAccessible, + config: this.config, + routes: logRoutes, + }), + }, + ] + : []), + ...(infrastructure.show + ? [ + { + label: metricsTitle, + sortKey: 300, + entries: [ + { + label: inventoryTitle, + app: 'metrics', + path: '/inventory', + }, + ...(this.config.featureFlags.metricsExplorerEnabled + ? [ + { + label: metricsExplorerTitle, + app: 'metrics', + path: '/explorer', + }, + ] + : []), + { + label: hostsTitle, + app: 'metrics', + path: '/hosts', + }, + ], + }, + ] + : []), + ]; + }) ) ); @@ -243,10 +239,8 @@ export class Plugin implements InfraClientPluginClass { // !! Need to be kept in sync with the routes in x-pack/plugins/observability_solution/infra/public/pages/metrics/index.tsx const getInfraDeepLinks = ({ - hostsEnabled, metricsExplorerEnabled, }: { - hostsEnabled: boolean; metricsExplorerEnabled: boolean; }): AppDeepLink[] => { const visibleIn: AppDeepLinkLocations[] = ['globalSearch']; @@ -258,18 +252,14 @@ export class Plugin implements InfraClientPluginClass { path: '/inventory', visibleIn, }, - ...(hostsEnabled - ? [ - { - id: 'hosts', - title: i18n.translate('xpack.infra.homePage.metricsHostsTabTitle', { - defaultMessage: 'Hosts', - }), - path: '/hosts', - visibleIn, - }, - ] - : []), + { + id: 'hosts', + title: i18n.translate('xpack.infra.homePage.metricsHostsTabTitle', { + defaultMessage: 'Hosts', + }), + path: '/hosts', + visibleIn, + }, ...(metricsExplorerEnabled ? [ { @@ -308,7 +298,6 @@ export class Plugin implements InfraClientPluginClass { category: DEFAULT_APP_CATEGORIES.observability, updater$: this.appUpdater$, deepLinks: getInfraDeepLinks({ - hostsEnabled: core.settings.client.get(enableInfrastructureHostsView), metricsExplorerEnabled: this.config.featureFlags.metricsExplorerEnabled, }), mount: async (params: AppMountParameters) => { @@ -332,20 +321,13 @@ export class Plugin implements InfraClientPluginClass { ); }, }); - - startDep$AndHostViewFlag$.subscribe( - ([_startServices, isInfrastructureHostsViewEnabled]: [ - [CoreStart, InfraClientStartDeps, InfraClientStartExports], - boolean - ]) => { - this.appUpdater$.next(() => ({ - deepLinks: getInfraDeepLinks({ - hostsEnabled: isInfrastructureHostsViewEnabled, - metricsExplorerEnabled: this.config.featureFlags.metricsExplorerEnabled, - }), - })); - } - ); + startDep$AndAccessibleFlag$.subscribe(([_applicationStart, _isLogsExplorerAccessible]) => { + this.appUpdater$.next(() => ({ + deepLinks: getInfraDeepLinks({ + metricsExplorerEnabled: this.config.featureFlags.metricsExplorerEnabled, + }), + })); + }); // Setup telemetry events this.telemetry.setup({ analytics: core.analytics }); @@ -408,11 +390,11 @@ export class Plugin implements InfraClientPluginClass { } const getLogsNavigationEntries = ({ - capabilities, + isLogsExplorerAccessible, config, routes, }: { - capabilities: CoreStart['application']['capabilities']; + isLogsExplorerAccessible: boolean; config: InfraPublicConfig; routes: LogsAppRoutes; }) => { @@ -420,7 +402,7 @@ const getLogsNavigationEntries = ({ if (!config.featureFlags.logsUIEnabled) return entries; - if (capabilities.discover?.show && capabilities.fleet?.read) { + if (isLogsExplorerAccessible) { entries.push({ label: 'Explorer', app: 'observability-logs-explorer', @@ -440,6 +422,18 @@ const getLogsNavigationEntries = ({ return entries; }; +const getLogsExplorerAccessible$ = (application: CoreStart['application']) => { + const { applications$ } = application; + return applications$.pipe( + map( + (apps) => + (apps.get(OBSERVABILITY_LOGS_EXPLORER_APP_ID)?.status ?? AppStatus.inaccessible) === + AppStatus.accessible + ), + distinctUntilChanged() + ); +}; + const createNavEntryFromRoute = ({ path, title }: LogsRoute): NavigationEntry => ({ app: 'logs', label: title, diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.mock.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.mock.ts index d5ea4958b95f2..2f68c4f5501c6 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.mock.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.mock.ts @@ -21,4 +21,8 @@ export const createTelemetryClientMock = (): jest.Mocked => ({ reportAddMetricsCalloutTryItClicked: jest.fn(), reportAddMetricsCalloutLearnMoreClicked: jest.fn(), reportAddMetricsCalloutDismissed: jest.fn(), + reportAnomalyDetectionSetup: jest.fn(), + reportAnomalyDetectionDateFieldChange: jest.fn(), + reportAnomalyDetectionFilterFieldChange: jest.fn(), + reportAnomalyDetectionPartitionFieldChange: jest.fn(), }); diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts index d5dcf9d3f0c8d..0adf6a04dea7f 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts @@ -9,6 +9,10 @@ import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { AddMetricsCalloutEventParams, + AnomalyDetectionDateFieldChangeParams, + AnomalyDetectionFilterFieldChangeParams, + AnomalyDetectionPartitionFieldChangeParams, + AnomalyDetectionSetupParams, AssetDashboardLoadedParams, AssetDetailsFlyoutViewedParams, AssetDetailsPageViewedParams, @@ -114,4 +118,35 @@ export class TelemetryClient implements ITelemetryClient { public reportAddMetricsCalloutDismissed = (params: AddMetricsCalloutEventParams) => { this.analytics.reportEvent(InfraTelemetryEventTypes.ADD_METRICS_CALLOUT_DISMISSED, params); }; + + public reportAnomalyDetectionSetup = (params: AnomalyDetectionSetupParams) => { + this.analytics.reportEvent(InfraTelemetryEventTypes.ANOMALY_DETECTION_SETUP, params); + }; + + public reportAnomalyDetectionDateFieldChange = ( + params: AnomalyDetectionDateFieldChangeParams + ) => { + this.analytics.reportEvent( + InfraTelemetryEventTypes.ANOMALY_DETECTION_DATE_FIELD_CHANGE, + params + ); + }; + + public reportAnomalyDetectionPartitionFieldChange = ( + params: AnomalyDetectionPartitionFieldChangeParams + ) => { + this.analytics.reportEvent( + InfraTelemetryEventTypes.ANOMALY_DETECTION_PARTITION_FIELD_CHANGE, + params + ); + }; + + public reportAnomalyDetectionFilterFieldChange = ( + params: AnomalyDetectionFilterFieldChangeParams + ) => { + this.analytics.reportEvent( + InfraTelemetryEventTypes.ANOMALY_DETECTION_FILTER_FIELD_CHANGE, + params + ); + }; } diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_events.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_events.ts index ec2f918354cbf..7f025c1051755 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_events.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_events.ts @@ -264,6 +264,98 @@ const addMetricsCalloutDismissed: InfraTelemetryEvent = { }, }; +const anomalyDetectionSetup: InfraTelemetryEvent = { + eventType: InfraTelemetryEventTypes.ANOMALY_DETECTION_SETUP, + schema: { + job_type: { + type: 'text', + _meta: { + description: 'Type of job for the anomaly detection', + }, + }, + configured_fields: { + properties: { + start_date: { + type: 'text', + _meta: { + description: 'Start date for the anomaly detection job', + }, + }, + partition_field: { + type: 'text', + _meta: { + description: 'Partition field for the anomaly detection job', + optional: true, + }, + }, + filter_field: { + type: 'text', + _meta: { + description: 'Filter field for the anomaly detection job', + optional: true, + }, + }, + }, + }, + }, +}; + +const anomalyDetectionDateFieldChange: InfraTelemetryEvent = { + eventType: InfraTelemetryEventTypes.ANOMALY_DETECTION_DATE_FIELD_CHANGE, + schema: { + job_type: { + type: 'text', + _meta: { + description: 'Type of job for the anomaly detection', + }, + }, + start_date: { + type: 'text', + _meta: { + description: 'Start date for the anomaly detection job', + }, + }, + }, +}; + +const anomalyDetectionPartitionFieldChange: InfraTelemetryEvent = { + eventType: InfraTelemetryEventTypes.ANOMALY_DETECTION_PARTITION_FIELD_CHANGE, + schema: { + job_type: { + type: 'text', + _meta: { + description: 'Type of job for the anomaly detection', + }, + }, + partition_field: { + type: 'text', + _meta: { + description: 'Partition field for the anomaly detection job', + optional: true, + }, + }, + }, +}; + +const anomalyDetectionFilterFieldChange: InfraTelemetryEvent = { + eventType: InfraTelemetryEventTypes.ANOMALY_DETECTION_FILTER_FIELD_CHANGE, + schema: { + job_type: { + type: 'text', + _meta: { + description: 'Type of job for the anomaly detection', + }, + }, + filter_field: { + type: 'text', + _meta: { + description: 'Filter field for the anomaly detection job', + optional: true, + }, + }, + }, +}; + export const infraTelemetryEvents = [ assetDetailsFlyoutViewed, assetDetailsPageViewed, @@ -277,4 +369,8 @@ export const infraTelemetryEvents = [ addMetricsCalloutTryItClicked, addMetricsCalloutLearnMoreClicked, addMetricsCalloutDismissed, + anomalyDetectionSetup, + anomalyDetectionDateFieldChange, + anomalyDetectionPartitionFieldChange, + anomalyDetectionFilterFieldChange, ]; diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts index 78f4d0e64d792..afce0e37126a5 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts @@ -52,6 +52,19 @@ describe('TelemetryService', () => { expect(telemetry).toHaveProperty('reportHostFlyoutFilterRemoved'); expect(telemetry).toHaveProperty('reportHostFlyoutFilterAdded'); expect(telemetry).toHaveProperty('reportHostsViewQuerySubmitted'); + expect(telemetry).toHaveProperty('reportHostsViewTotalHostCountRetrieved'); + expect(telemetry).toHaveProperty('reportAssetDetailsFlyoutViewed'); + expect(telemetry).toHaveProperty('reportAssetDetailsPageViewed'); + expect(telemetry).toHaveProperty('reportPerformanceMetricEvent'); + expect(telemetry).toHaveProperty('reportAssetDashboardLoaded'); + expect(telemetry).toHaveProperty('reportAddMetricsCalloutAddMetricsClicked'); + expect(telemetry).toHaveProperty('reportAddMetricsCalloutTryItClicked'); + expect(telemetry).toHaveProperty('reportAddMetricsCalloutLearnMoreClicked'); + expect(telemetry).toHaveProperty('reportAddMetricsCalloutDismissed'); + expect(telemetry).toHaveProperty('reportAnomalyDetectionSetup'); + expect(telemetry).toHaveProperty('reportAnomalyDetectionDateFieldChange'); + expect(telemetry).toHaveProperty('reportAnomalyDetectionPartitionFieldChange'); + expect(telemetry).toHaveProperty('reportAnomalyDetectionFilterFieldChange'); }); }); @@ -343,4 +356,99 @@ describe('TelemetryService', () => { ); }); }); + + describe('#reportAnomalyDetectionSetup', () => { + it('should report anomaly detection setup with properties', async () => { + const setupParams = getSetupParams(); + service.setup(setupParams); + const telemetry = service.start(); + const jobType = 'host'; + const configuredFields = { + start_date: new Date().toISOString(), + partition_field: 'partitionField', + filter_field: 'filterField', + }; + + telemetry.reportAnomalyDetectionSetup({ + job_type: jobType, + configured_fields: configuredFields, + }); + + expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); + expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith( + 'Infra Anomaly Detection Job Setup', + { + job_type: jobType, + configured_fields: configuredFields, + } + ); + }); + }); + + describe('#reportAnomalyDetectionDateFieldChange', () => { + it('should report anomaly detection date field change with properties', async () => { + const setupParams = getSetupParams(); + service.setup(setupParams); + const telemetry = service.start(); + const startDate = new Date().toISOString(); + + telemetry.reportAnomalyDetectionDateFieldChange({ + job_type: 'host', + start_date: startDate, + }); + + expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); + expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith( + 'Infra Anomaly Detection Job Date Field Change', + { + job_type: 'host', + start_date: startDate, + } + ); + }); + }); + + describe('#reportAnomalyDetectionPartitionFieldChange', () => { + it('should report anomaly detection partition field change with properties', async () => { + const setupParams = getSetupParams(); + service.setup(setupParams); + const telemetry = service.start(); + + telemetry.reportAnomalyDetectionPartitionFieldChange({ + job_type: 'host', + partition_field: 'partitionField', + }); + + expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); + expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith( + 'Infra Anomaly Detection Job Partition Field Change', + { + job_type: 'host', + partition_field: 'partitionField', + } + ); + }); + }); + + describe('#reportAnomalyDetectionFilterFieldChange', () => { + it('should report anomaly detection filter field change with properties', async () => { + const setupParams = getSetupParams(); + service.setup(setupParams); + const telemetry = service.start(); + + telemetry.reportAnomalyDetectionFilterFieldChange({ + job_type: 'host', + filter_field: 'filterField', + }); + + expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); + expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith( + 'Infra Anomaly Detection Job Filter Field Change', + { + job_type: 'host', + filter_field: 'filterField', + } + ); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts index 14816421fe695..982fddfd9492c 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts @@ -26,6 +26,10 @@ export enum InfraTelemetryEventTypes { ADD_METRICS_CALLOUT_TRY_IT_CLICKED = 'Add Metrics Callout Try It Clicked', ADD_METRICS_CALLOUT_LEARN_MORE_CLICKED = 'Add Metrics Callout Learn More Clicked', ADD_METRICS_CALLOUT_DISMISSED = 'Add Metrics Callout Dismissed', + ANOMALY_DETECTION_SETUP = 'Infra Anomaly Detection Job Setup', + ANOMALY_DETECTION_DATE_FIELD_CHANGE = 'Infra Anomaly Detection Job Date Field Change', + ANOMALY_DETECTION_PARTITION_FIELD_CHANGE = 'Infra Anomaly Detection Job Partition Field Change', + ANOMALY_DETECTION_FILTER_FIELD_CHANGE = 'Infra Anomaly Detection Job Filter Field Change', } export interface HostsViewQuerySubmittedParams { @@ -69,6 +73,26 @@ export interface AddMetricsCalloutEventParams { view: string; } +export interface AnomalyDetectionSetupParams { + job_type: string; + configured_fields: { start_date: string; partition_field?: string; filter_field?: string }; +} + +export interface AnomalyDetectionDateFieldChangeParams { + job_type: string; + start_date: string; +} + +export interface AnomalyDetectionPartitionFieldChangeParams { + job_type: string; + partition_field?: string; +} + +export interface AnomalyDetectionFilterFieldChangeParams { + job_type: string; + filter_field?: string; +} + export type InfraTelemetryEventParams = | HostsViewQuerySubmittedParams | HostEntryClickedParams @@ -76,7 +100,11 @@ export type InfraTelemetryEventParams = | HostsViewQueryHostsCountRetrievedParams | AssetDetailsFlyoutViewedParams | AssetDashboardLoadedParams - | AddMetricsCalloutEventParams; + | AddMetricsCalloutEventParams + | AnomalyDetectionSetupParams + | AnomalyDetectionDateFieldChangeParams + | AnomalyDetectionPartitionFieldChangeParams + | AnomalyDetectionFilterFieldChangeParams; export interface PerformanceMetricInnerEvents { key1?: string; @@ -102,6 +130,12 @@ export interface ITelemetryClient { reportAddMetricsCalloutTryItClicked(params: AddMetricsCalloutEventParams): void; reportAddMetricsCalloutLearnMoreClicked(params: AddMetricsCalloutEventParams): void; reportAddMetricsCalloutDismissed(params: AddMetricsCalloutEventParams): void; + reportAnomalyDetectionSetup(params: AnomalyDetectionSetupParams): void; + reportAnomalyDetectionDateFieldChange(params: AnomalyDetectionDateFieldChangeParams): void; + reportAnomalyDetectionPartitionFieldChange( + params: AnomalyDetectionPartitionFieldChangeParams + ): void; + reportAnomalyDetectionFilterFieldChange(params: AnomalyDetectionFilterFieldChangeParams): void; } export type InfraTelemetryEvent = @@ -152,4 +186,20 @@ export type InfraTelemetryEvent = | { eventType: InfraTelemetryEventTypes.ADD_METRICS_CALLOUT_DISMISSED; schema: RootSchema; + } + | { + eventType: InfraTelemetryEventTypes.ANOMALY_DETECTION_SETUP; + schema: RootSchema; + } + | { + eventType: InfraTelemetryEventTypes.ANOMALY_DETECTION_DATE_FIELD_CHANGE; + schema: RootSchema; + } + | { + eventType: InfraTelemetryEventTypes.ANOMALY_DETECTION_PARTITION_FIELD_CHANGE; + schema: RootSchema; + } + | { + eventType: InfraTelemetryEventTypes.ANOMALY_DETECTION_FILTER_FIELD_CHANGE; + schema: RootSchema; }; diff --git a/x-pack/plugins/observability_solution/infra/public/translations.ts b/x-pack/plugins/observability_solution/infra/public/translations.ts index ecb72b3df4b01..3377ae1dd1fa1 100644 --- a/x-pack/plugins/observability_solution/infra/public/translations.ts +++ b/x-pack/plugins/observability_solution/infra/public/translations.ts @@ -39,7 +39,7 @@ export const metricsTitle = i18n.translate('xpack.infra.header.infrastructureTit }); export const inventoryTitle = i18n.translate('xpack.infra.metrics.infrastructureInventoryTitle', { - defaultMessage: 'Infrastructure Inventory', + defaultMessage: 'Infrastructure inventory', }); export const metricsExplorerTitle = i18n.translate('xpack.infra.metrics.metricsExplorerTitle', { diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.test.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.test.ts index c54b29d52714f..a29308774440c 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.test.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.test.ts @@ -6,14 +6,7 @@ */ import rison from '@kbn/rison'; -import { - AlertInstanceContext as AlertContext, - AlertInstanceState as AlertState, -} from '@kbn/alerting-plugin/server'; import { RuleExecutorServicesMock, alertsMock } from '@kbn/alerting-plugin/server/mocks'; -import { LifecycleAlertServices } from '@kbn/rule-registry-plugin/server'; -import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks'; -import { createLifecycleRuleExecutorMock } from '@kbn/rule-registry-plugin/server/utils/create_lifecycle_rule_executor_mock'; import { COMPARATORS } from '@kbn/alerting-comparators'; import { Aggregators, InventoryMetricConditions } from '../../../../common/alerting/metrics'; import type { LogMeta, Logger } from '@kbn/logging'; @@ -150,9 +143,7 @@ const mockLibs = { infraPluginMock.createStartContract(), ], configuration: createMockStaticConfiguration({}), - metricsRules: { - createLifecycleRuleExecutor: createLifecycleRuleExecutorMock, - }, + metricsRules: {}, basePath: { publicBaseUrl: 'http://localhost:5601', prepend: (path: string) => path, @@ -165,14 +156,10 @@ const mockLibs = { logger, } as unknown as InfraBackendLibs; const alerts = new Map(); -let services: RuleExecutorServicesMock & LifecycleAlertServices; +let services: RuleExecutorServicesMock; const setup = () => { - const alertsServices = alertsMock.createRuleExecutorServices(); - services = { - ...alertsServices, - ...ruleRegistryMocks.createLifecycleAlertServices(alertsServices), - }; + services = alertsMock.createRuleExecutorServices(); services.alertsClient.report.mockImplementation((params: any) => { alerts.set(params.id, { actionGroup: params.actionGroup, context: [], payload: [] }); diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts index cb169f83f171d..1a8707678e8f7 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { METRICS_APP_ID } from '@kbn/deeplinks-observability/constants'; import { entityCentricExperience } from '@kbn/observability-plugin/common'; import { createObservabilityEsClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import { ENTITY_TYPES } from '@kbn/observability-shared-plugin/common'; import { getInfraMetricsClient } from '../../lib/helpers/get_infra_metrics_client'; import { InfraBackendLibs } from '../../lib/infra_types'; import { getDataStreamTypes } from './get_data_stream_types'; @@ -22,7 +23,10 @@ export const initEntitiesConfigurationRoutes = (libs: InfraBackendLibs) => { path: '/api/infra/entities/{entityType}/{entityId}/summary', validate: { params: schema.object({ - entityType: schema.oneOf([schema.literal('host'), schema.literal('container')]), + entityType: schema.oneOf([ + schema.literal(ENTITY_TYPES.HOST), + schema.literal(ENTITY_TYPES.CONTAINER), + ]), entityId: schema.string(), }), }, diff --git a/x-pack/plugins/observability_solution/infra/server/services/rules/rules_service.ts b/x-pack/plugins/observability_solution/infra/server/services/rules/rules_service.ts index 85d3d8548fbe6..99e7c57d857b5 100644 --- a/x-pack/plugins/observability_solution/infra/server/services/rules/rules_service.ts +++ b/x-pack/plugins/observability_solution/infra/server/services/rules/rules_service.ts @@ -6,7 +6,6 @@ */ import { CoreSetup, Logger } from '@kbn/core/server'; -import { createLifecycleExecutor } from '@kbn/rule-registry-plugin/server'; import { InfraFeatureId } from '../../../common/constants'; import { createRuleDataClient } from './rule_data_client'; import { @@ -36,12 +35,7 @@ export class RulesService { ruleDataService: setupDeps.ruleRegistry.ruleDataService, }); - const createLifecycleRuleExecutor = createLifecycleExecutor(this.logger, ruleDataClient); - - return { - createLifecycleRuleExecutor, - ruleDataClient, - }; + return { ruleDataClient }; } public start(_startDeps: RulesServiceStartDeps): RulesServiceStart { diff --git a/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts b/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts index fa14089de2ba5..68ae0bd95b410 100644 --- a/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts +++ b/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts @@ -6,13 +6,7 @@ */ import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; -import { - createLifecycleExecutor, - IRuleDataClient, - RuleRegistryPluginSetupContract, -} from '@kbn/rule-registry-plugin/server'; - -type LifecycleRuleExecutorCreator = ReturnType; +import { IRuleDataClient, RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server'; export interface RulesServiceSetupDeps { alerting: AlertingPluginSetup; ruleRegistry: RuleRegistryPluginSetupContract; @@ -22,7 +16,6 @@ export interface RulesServiceSetupDeps { export interface RulesServiceStartDeps {} export interface RulesServiceSetup { - createLifecycleRuleExecutor: LifecycleRuleExecutorCreator; ruleDataClient: IRuleDataClient; } diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts index d8a056074e339..f686490b90bfc 100644 --- a/x-pack/plugins/observability_solution/inventory/common/entities.ts +++ b/x-pack/plugins/observability_solution/inventory/common/entities.ts @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { ENTITY_LATEST, entitiesAliasPattern } from '@kbn/entities-schema'; +import { z } from '@kbn/zod'; +import { ENTITY_LATEST, entitiesAliasPattern, entityLatestSchema } from '@kbn/entities-schema'; import { ENTITY_DEFINITION_ID, ENTITY_DISPLAY_NAME, @@ -13,6 +14,7 @@ import { ENTITY_LAST_SEEN, ENTITY_TYPE, } from '@kbn/observability-shared-plugin/common'; +import { decode, encode } from '@kbn/rison'; import { isRight } from 'fp-ts/lib/Either'; import * as t from 'io-ts'; @@ -25,6 +27,49 @@ export const entityColumnIdsRt = t.union([ export type EntityColumnIds = t.TypeOf; +export const entityViewRt = t.union([t.literal('unified'), t.literal('grouped')]); + +const paginationRt = t.record(t.string, t.number); +export const entityPaginationRt = new t.Type | undefined, string, unknown>( + 'entityPaginationRt', + paginationRt.is, + (input, context) => { + switch (typeof input) { + case 'string': { + try { + const decoded = decode(input); + const validation = paginationRt.decode(decoded); + if (isRight(validation)) { + return t.success(validation.right); + } + + return t.failure(input, context); + } catch (e) { + return t.failure(input, context); + } + } + + case 'undefined': + return t.success(input); + + default: { + const validation = paginationRt.decode(input); + + if (isRight(validation)) { + return t.success(validation.right); + } + + return t.failure(input, context); + } + } + }, + (o) => encode(o) +); + +export type EntityView = t.TypeOf; + +export type EntityPagination = t.TypeOf; + export const defaultEntitySortField: EntityColumnIds = 'alertsCount'; export const MAX_NUMBER_OF_ENTITIES = 500; @@ -67,3 +112,13 @@ export interface Entity { alertsCount?: number; [key: string]: any; } + +export type EntityGroup = { + count: number; +} & { + [key: string]: any; +}; + +export type InventoryEntityLatest = z.infer & { + alertsCount?: number; +}; diff --git a/x-pack/plugins/observability_solution/inventory/common/utils/parse_identity_field_values_to_kql.test.ts b/x-pack/plugins/observability_solution/inventory/common/utils/parse_identity_field_values_to_kql.test.ts deleted file mode 100644 index 8703e995b4446..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/common/utils/parse_identity_field_values_to_kql.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - ENTITY_DEFINITION_ID, - ENTITY_DISPLAY_NAME, - ENTITY_ID, - ENTITY_IDENTITY_FIELDS, - ENTITY_LAST_SEEN, -} from '@kbn/observability-shared-plugin/common'; -import type { Entity } from '../entities'; -import { parseIdentityFieldValuesToKql } from './parse_identity_field_values_to_kql'; - -const commonEntityFields = { - [ENTITY_LAST_SEEN]: '2023-10-09T00:00:00Z', - [ENTITY_ID]: '1', - [ENTITY_DISPLAY_NAME]: 'entity_name', - [ENTITY_DEFINITION_ID]: 'entity_definition_id', - alertCount: 3, -}; - -describe('parseIdentityFieldValuesToKql', () => { - it('should return the value when identityFields is a single string', () => { - const entity: Entity = { - 'agent.name': 'node', - [ENTITY_IDENTITY_FIELDS]: 'service.name', - 'service.name': 'my-service', - 'entity.type': 'service', - ...commonEntityFields, - }; - - const result = parseIdentityFieldValuesToKql({ entity }); - expect(result).toEqual('service.name: "my-service"'); - }); - - it('should return values when identityFields is an array of strings', () => { - const entity: Entity = { - 'agent.name': 'node', - [ENTITY_IDENTITY_FIELDS]: ['service.name', 'service.environment'], - 'service.name': 'my-service', - 'entity.type': 'service', - 'service.environment': 'staging', - ...commonEntityFields, - }; - - const result = parseIdentityFieldValuesToKql({ entity }); - expect(result).toEqual('service.name: "my-service" AND service.environment: "staging"'); - }); - - it('should return an empty string if identityFields is empty string', () => { - const entity: Entity = { - 'agent.name': 'node', - [ENTITY_IDENTITY_FIELDS]: '', - 'service.name': 'my-service', - 'entity.type': 'service', - ...commonEntityFields, - }; - - const result = parseIdentityFieldValuesToKql({ entity }); - expect(result).toEqual(''); - }); - it('should return an empty array if identityFields is empty array', () => { - const entity: Entity = { - 'agent.name': 'node', - [ENTITY_IDENTITY_FIELDS]: [], - 'service.name': 'my-service', - 'entity.type': 'service', - ...commonEntityFields, - }; - - const result = parseIdentityFieldValuesToKql({ entity }); - expect(result).toEqual(''); - }); - - it('should ignore fields that are not present in the entity', () => { - const entity: Entity = { - [ENTITY_IDENTITY_FIELDS]: ['host.name', 'foo.bar'], - 'host.name': 'my-host', - 'entity.type': 'host', - 'cloud.provider': null, - ...commonEntityFields, - }; - - const result = parseIdentityFieldValuesToKql({ entity }); - expect(result).toEqual('host.name: "my-host"'); - }); -}); diff --git a/x-pack/plugins/observability_solution/inventory/common/utils/parse_identity_field_values_to_kql.ts b/x-pack/plugins/observability_solution/inventory/common/utils/parse_identity_field_values_to_kql.ts deleted file mode 100644 index 2e3f3dadd4109..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/common/utils/parse_identity_field_values_to_kql.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ENTITY_IDENTITY_FIELDS } from '@kbn/observability-shared-plugin/common'; -import { Entity } from '../entities'; - -type Operator = 'AND'; -export function parseIdentityFieldValuesToKql({ - entity, - operator = 'AND', -}: { - entity: Entity; - operator?: Operator; -}) { - const mapping: string[] = []; - - const identityFields = entity[ENTITY_IDENTITY_FIELDS]; - - if (identityFields) { - const fields = [identityFields].flat(); - - fields.forEach((field) => { - if (field in entity) { - mapping.push(`${[field]}: "${entity[field as keyof Entity]}"`); - } - }); - } - - return mapping.join(` ${operator} `); -} diff --git a/x-pack/plugins/observability_solution/inventory/common/utils/unflatten_entity.ts b/x-pack/plugins/observability_solution/inventory/common/utils/unflatten_entity.ts new file mode 100644 index 0000000000000..758d185a5753b --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/common/utils/unflatten_entity.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { unflattenObject } from '@kbn/observability-utils/object/unflatten_object'; +import type { Entity, InventoryEntityLatest } from '../entities'; + +export function unflattenEntity(entity: Entity) { + return unflattenObject(entity) as InventoryEntityLatest; +} diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts index c18f8866475ab..3ca60464d571b 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts @@ -59,12 +59,38 @@ describe('Home page', () => { logsSynthtrace.clean(); }); - it('Shows inventory page with entities', () => { + it('Shows inventory page with groups & entities', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); + cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); + cy.contains('host'); + cy.getByTestSubj('inventoryGroupTitle_entity.type_host').click(); + cy.wait('@getEntities'); + cy.contains('service'); + cy.getByTestSubj('inventoryGroupTitle_entity.type_service').click(); + cy.wait('@getEntities'); + cy.contains('container'); + cy.getByTestSubj('inventoryGroupTitle_entity.type_container').click(); + cy.wait('@getEntities'); + cy.contains('server1'); + cy.contains('synth-node-trace-logs'); + cy.contains('foo'); + }); + + it('Shows inventory page with unified view of entities', () => { + cy.intercept('GET', '/internal/entities/managed/enablement', { + fixture: 'eem_enabled.json', + }).as('getEEMStatus'); + cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); + cy.visitKibana('/app/inventory'); + cy.wait('@getEEMStatus'); + cy.contains('Group entities by: Type'); + cy.getByTestSubj('groupSelectorDropdown').click(); + cy.getByTestSubj('panelUnified').click(); + cy.wait('@getEntities'); cy.contains('server1'); cy.contains('host'); cy.contains('synth-node-trace-logs'); @@ -79,6 +105,7 @@ describe('Home page', () => { }).as('getEEMStatus'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); + cy.contains('service').click(); cy.contains('synth-node-trace-logs').click(); cy.url().should('include', '/app/apm/services/synth-node-trace-logs/overview'); }); @@ -89,6 +116,7 @@ describe('Home page', () => { }).as('getEEMStatus'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); + cy.contains('host').click(); cy.contains('server1').click(); cy.url().should('include', '/app/metrics/detail/host/server1'); }); @@ -99,6 +127,7 @@ describe('Home page', () => { }).as('getEEMStatus'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); + cy.contains('container').click(); cy.contains('foo').click(); cy.url().should('include', '/app/metrics/detail/container/foo'); }); @@ -107,51 +136,69 @@ describe('Home page', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); - cy.intercept('GET', '/internal/inventory/entities*').as('getEntitites'); + cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); + cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); cy.getByTestSubj('entityTypesFilterComboBox') .click() .getByTestSubj('entityTypesFilterserviceOption') .click(); - cy.wait('@getEntitites'); + cy.wait('@getGroups'); + cy.contains('service'); + cy.getByTestSubj('inventoryGroupTitle_entity.type_service').click(); + cy.wait('@getEntities'); cy.get('server1').should('not.exist'); cy.contains('synth-node-trace-logs'); - cy.get('foo').should('not.exist'); + cy.contains('foo').should('not.exist'); + cy.getByTestSubj('inventoryGroup_entity.type_host').should('not.exist'); + cy.getByTestSubj('inventoryGroup_entity.type_container').should('not.exist'); }); it('Filters entities by host type', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); - cy.intercept('GET', '/internal/inventory/entities*').as('getEntitites'); + cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); + cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); cy.getByTestSubj('entityTypesFilterComboBox') .click() .getByTestSubj('entityTypesFilterhostOption') .click(); - cy.wait('@getEntitites'); + cy.wait('@getGroups'); + cy.contains('host'); + cy.getByTestSubj('inventoryGroupTitle_entity.type_host').click(); + cy.wait('@getEntities'); cy.contains('server1'); - cy.get('synth-node-trace-logs').should('not.exist'); - cy.get('foo').should('not.exist'); + cy.contains('synth-node-trace-logs').should('not.exist'); + cy.contains('foo').should('not.exist'); + cy.getByTestSubj('inventoryGroup_entity.type_service').should('not.exist'); + cy.getByTestSubj('inventoryGroup_entity.type_container').should('not.exist'); }); it('Filters entities by container type', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); - cy.intercept('GET', '/internal/inventory/entities*').as('getEntitites'); + cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); + cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); cy.getByTestSubj('entityTypesFilterComboBox') .click() .getByTestSubj('entityTypesFiltercontainerOption') .click(); - cy.wait('@getEntitites'); - cy.get('server1').should('not.exist'); - cy.get('synth-node-trace-logs').should('not.exist'); + cy.wait('@getGroups'); + cy.contains('container'); + cy.getByTestSubj('inventoryGroupTitle_entity.type_container').click(); + cy.wait('@getEntities'); + cy.contains('server1').should('not.exist'); + cy.contains('synth-node-trace-logs').should('not.exist'); cy.contains('foo'); + cy.getByTestSubj('inventoryGroup_entity.type_host').should('not.exist'); + cy.getByTestSubj('inventoryGroup_entity.type_service').should('not.exist'); }); }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx index 60124e7813bc4..b5244cb29f7fc 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx @@ -5,22 +5,35 @@ * 2.0. */ import React from 'react'; -import { type KibanaReactContextValue } from '@kbn/kibana-react-plugin/public'; import { render, screen } from '@testing-library/react'; import { AlertsBadge } from './alerts_badge'; -import * as useKibana from '../../hooks/use_kibana'; +import { useKibana } from '../../hooks/use_kibana'; import type { Entity } from '../../../common/entities'; +jest.mock('../../hooks/use_kibana'); +const useKibanaMock = useKibana as jest.Mock; + describe('AlertsBadge', () => { - jest.spyOn(useKibana, 'useKibana').mockReturnValue({ - services: { - http: { - basePath: { - prepend: (path: string) => path, + const mockAsKqlFilter = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + + useKibanaMock.mockReturnValue({ + services: { + http: { + basePath: { + prepend: (path: string) => path, + }, + }, + entityManager: { + entityClient: { + asKqlFilter: mockAsKqlFilter, + }, }, }, - }, - } as unknown as KibanaReactContextValue); + }); + }); afterAll(() => { jest.clearAllMocks(); @@ -38,9 +51,11 @@ describe('AlertsBadge', () => { 'cloud.provider': null, alertsCount: 1, }; + mockAsKqlFilter.mockReturnValue('host.name: foo'); + render(); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.getAttribute('href')).toEqual( - '/app/observability/alerts?_a=(kuery:\'host.name: "foo"\',status:active)' + "/app/observability/alerts?_a=(kuery:'host.name: foo',status:active)" ); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('1'); }); @@ -57,9 +72,11 @@ describe('AlertsBadge', () => { 'cloud.provider': null, alertsCount: 5, }; + mockAsKqlFilter.mockReturnValue('service.name: bar'); + render(); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.getAttribute('href')).toEqual( - '/app/observability/alerts?_a=(kuery:\'service.name: "bar"\',status:active)' + "/app/observability/alerts?_a=(kuery:'service.name: bar',status:active)" ); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('5'); }); @@ -77,9 +94,12 @@ describe('AlertsBadge', () => { 'cloud.provider': null, alertsCount: 2, }; + + mockAsKqlFilter.mockReturnValue('service.name: bar AND service.environment: prod'); + render(); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.getAttribute('href')).toEqual( - '/app/observability/alerts?_a=(kuery:\'service.name: "bar" AND service.environment: "prod"\',status:active)' + "/app/observability/alerts?_a=(kuery:'service.name: bar AND service.environment: prod',status:active)" ); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('2'); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx index ba1b992ff62c1..a5845a7b42dcf 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx @@ -8,20 +8,21 @@ import React from 'react'; import rison from '@kbn/rison'; import { EuiBadge, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { Entity } from '../../../common/entities'; +import type { Entity } from '../../../common/entities'; +import { unflattenEntity } from '../../../common/utils/unflatten_entity'; import { useKibana } from '../../hooks/use_kibana'; -import { parseIdentityFieldValuesToKql } from '../../../common/utils/parse_identity_field_values_to_kql'; export function AlertsBadge({ entity }: { entity: Entity }) { const { services: { http: { basePath }, + entityManager, }, } = useKibana(); const activeAlertsHref = basePath.prepend( `/app/observability/alerts?_a=${rison.encode({ - kuery: parseIdentityFieldValuesToKql({ entity }), + kuery: entityManager.entityClient.asKqlFilter(unflattenEntity(entity)), status: 'active', })}` ); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx index 2e4f0c319edfc..d5d08ed415a40 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx @@ -5,148 +5,65 @@ * 2.0. */ -import { type KibanaReactContextValue } from '@kbn/kibana-react-plugin/public'; -import * as useKibana from '../../../hooks/use_kibana'; -import { EntityName } from '.'; -import type { Entity } from '../../../../common/entities'; -import { render, screen } from '@testing-library/react'; import React from 'react'; -import { ASSET_DETAILS_LOCATOR_ID } from '@kbn/observability-shared-plugin/common/locators/infra/asset_details_locator'; +import { render, screen } from '@testing-library/react'; +import { EntityName } from '.'; +import { useDetailViewRedirect } from '../../../hooks/use_detail_view_redirect'; +import { Entity } from '../../../../common/entities'; +import { + ENTITY_DEFINITION_ID, + ENTITY_DISPLAY_NAME, + ENTITY_ID, + ENTITY_IDENTITY_FIELDS, + ENTITY_LAST_SEEN, + ENTITY_TYPE, +} from '@kbn/observability-shared-plugin/common'; + +jest.mock('../../../hooks/use_detail_view_redirect'); + +const useDetailViewRedirectMock = useDetailViewRedirect as jest.Mock; describe('EntityName', () => { - jest.spyOn(useKibana, 'useKibana').mockReturnValue({ - services: { - share: { - url: { - locators: { - get: (locatorId: string) => { - return { - getRedirectUrl: (params: { [key: string]: any }) => { - if (locatorId === ASSET_DETAILS_LOCATOR_ID) { - return `assets_url/${params.assetType}/${params.assetId}`; - } - return `services_url/${params.serviceName}?environment=${params.environment}`; - }, - }; - }, - }, - }, - }, - }, - } as unknown as KibanaReactContextValue); + const mockEntity: Entity = { + [ENTITY_LAST_SEEN]: '2023-10-09T00:00:00Z', + [ENTITY_ID]: '1', + [ENTITY_DISPLAY_NAME]: 'entity_name', + [ENTITY_DEFINITION_ID]: 'entity_definition_id', + [ENTITY_IDENTITY_FIELDS]: ['service.name', 'service.environment'], + [ENTITY_TYPE]: 'service', + }; - afterAll(() => { + beforeEach(() => { jest.clearAllMocks(); }); - it('returns host link', () => { - const entity: Entity = { - 'entity.last_seen_timestamp': 'foo', - 'entity.id': '1', - 'entity.type': 'host', - 'entity.display_name': 'foo', - 'entity.identity_fields': 'host.name', - 'host.name': 'foo', - 'entity.definition_id': 'host', - 'cloud.provider': null, - }; - render(); - expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( - 'assets_url/host/foo' - ); - expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); - }); + it('should render the entity name correctly', () => { + useDetailViewRedirectMock.mockReturnValue({ + getEntityRedirectUrl: jest.fn().mockReturnValue(null), + }); - it('returns container link', () => { - const entity: Entity = { - 'entity.last_seen_timestamp': 'foo', - 'entity.id': '1', - 'entity.type': 'container', - 'entity.display_name': 'foo', - 'entity.identity_fields': 'container.id', - 'container.id': 'foo', - 'entity.definition_id': 'container', - 'cloud.provider': null, - }; - render(); - expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( - 'assets_url/container/foo' - ); - expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); - }); + render(); - it('returns service link without environment', () => { - const entity: Entity = { - 'entity.last_seen_timestamp': 'foo', - 'entity.id': '1', - 'entity.type': 'service', - 'entity.display_name': 'foo', - 'entity.identity_fields': 'service.name', - 'service.name': 'foo', - 'entity.definition_id': 'service', - 'agent.name': 'bar', - }; - render(); - expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( - 'services_url/foo?environment=undefined' - ); - expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); + expect(screen.getByText('entity_name')).toBeInTheDocument(); }); - it('returns service link with environment', () => { - const entity: Entity = { - 'entity.last_seen_timestamp': 'foo', - 'entity.id': '1', - 'entity.type': 'service', - 'entity.display_name': 'foo', - 'entity.identity_fields': 'service.name', - 'service.name': 'foo', - 'entity.definition_id': 'service', - 'agent.name': 'bar', - 'service.environment': 'baz', - }; - render(); - expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( - 'services_url/foo?environment=baz' - ); - expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); - }); + it('should a link when getEntityRedirectUrl returns a URL', () => { + useDetailViewRedirectMock.mockReturnValue({ + getEntityRedirectUrl: jest.fn().mockReturnValue('http://foo.bar'), + }); - it('returns service link with first environment when it is an array', () => { - const entity: Entity = { - 'entity.last_seen_timestamp': 'foo', - 'entity.id': '1', - 'entity.type': 'service', - 'entity.display_name': 'foo', - 'entity.identity_fields': 'service.name', - 'service.name': 'foo', - 'entity.definition_id': 'service', - 'agent.name': 'bar', - 'service.environment': ['baz', 'bar', 'foo'], - }; - render(); - expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( - 'services_url/foo?environment=baz' - ); - expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); + render(); + + expect(screen.getByRole('link')).toHaveAttribute('href', 'http://foo.bar'); }); - it('returns service link identity fields is an array', () => { - const entity: Entity = { - 'entity.last_seen_timestamp': 'foo', - 'entity.id': '1', - 'entity.type': 'service', - 'entity.display_name': 'foo', - 'entity.identity_fields': ['service.name', 'service.environment'], - 'service.name': 'foo', - 'entity.definition_id': 'service', - 'agent.name': 'bar', - 'service.environment': 'baz', - }; - render(); - expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( - 'services_url/foo?environment=baz' - ); - expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); + it('should not render a link when getEntityRedirectUrl returns null', () => { + useDetailViewRedirectMock.mockReturnValue({ + getEntityRedirectUrl: jest.fn().mockReturnValue(null), + }); + + render(); + + expect(screen.queryByRole('link')).not.toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx index 982a616da8fda..e8db7013f8cb3 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx @@ -6,19 +6,12 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; -import { - ASSET_DETAILS_LOCATOR_ID, - AssetDetailsLocatorParams, - ENTITY_DISPLAY_NAME, - ENTITY_IDENTITY_FIELDS, - ENTITY_TYPE, - SERVICE_ENVIRONMENT, - ServiceOverviewParams, -} from '@kbn/observability-shared-plugin/common'; import React, { useCallback } from 'react'; -import { Entity } from '../../../../common/entities'; +import { ENTITY_DISPLAY_NAME } from '@kbn/observability-shared-plugin/common'; import { useKibana } from '../../../hooks/use_kibana'; +import type { Entity } from '../../../../common/entities'; import { EntityIcon } from '../../entity_icon'; +import { useDetailViewRedirect } from '../../../hooks/use_detail_view_redirect'; interface EntityNameProps { entity: Entity; @@ -26,14 +19,12 @@ interface EntityNameProps { export function EntityName({ entity }: EntityNameProps) { const { - services: { telemetry, share }, + services: { telemetry }, } = useKibana(); - const assetDetailsLocator = - share?.url.locators.get(ASSET_DETAILS_LOCATOR_ID); + const { getEntityRedirectUrl } = useDetailViewRedirect(); - const serviceOverviewLocator = - share?.url.locators.get('serviceOverviewLocator'); + const href = getEntityRedirectUrl(entity); const handleLinkClick = useCallback(() => { telemetry.reportEntityViewClicked({ @@ -42,47 +33,25 @@ export function EntityName({ entity }: EntityNameProps) { }); }, [entity, telemetry]); - const getEntityRedirectUrl = useCallback(() => { - const type = entity[ENTITY_TYPE]; - // For service, host and container type there is only one identity field - const identityField = Array.isArray(entity[ENTITY_IDENTITY_FIELDS]) - ? entity[ENTITY_IDENTITY_FIELDS][0] - : entity[ENTITY_IDENTITY_FIELDS]; - const identityValue = entity[identityField]; - - switch (type) { - case 'host': - case 'container': - return assetDetailsLocator?.getRedirectUrl({ - assetId: identityValue, - assetType: type, - }); - - case 'service': - return serviceOverviewLocator?.getRedirectUrl({ - serviceName: identityValue, - environment: [entity[SERVICE_ENVIRONMENT] || undefined].flat()[0], - }); - } - }, [entity, assetDetailsLocator, serviceOverviewLocator]); + const entityName = ( + + + + + + + {entity[ENTITY_DISPLAY_NAME]} + + + + ); - return ( + return href ? ( // eslint-disable-next-line @elastic/eui/href-or-on-click - - - - - - - - {entity[ENTITY_DISPLAY_NAME]} - - - + + {entityName} + ) : ( + entityName ); } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx index a62f0026ddfa0..48b21779d2e38 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx @@ -6,7 +6,12 @@ */ import React from 'react'; -import { AGENT_NAME, CLOUD_PROVIDER, ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; +import { + AGENT_NAME, + CLOUD_PROVIDER, + ENTITY_TYPE, + ENTITY_TYPES, +} from '@kbn/observability-shared-plugin/common'; import { type CloudProvider, CloudProviderIcon, AgentIcon } from '@kbn/custom-icons'; import { EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; import type { AgentName } from '@kbn/elastic-agent-utils'; @@ -27,7 +32,7 @@ export function EntityIcon({ entity }: EntityIconProps) { const entityType = entity[ENTITY_TYPE]; const defaultIconSize = euiThemeVars.euiSizeL; - if (entityType === 'host' || entityType === 'container') { + if (entityType === ENTITY_TYPES.HOST || entityType === ENTITY_TYPES.CONTAINER) { const cloudProvider = getSingleValue( entity[CLOUD_PROVIDER] as NotNullableCloudProvider | NotNullableCloudProvider[] ); @@ -49,7 +54,7 @@ export function EntityIcon({ entity }: EntityIconProps) { ); } - if (entityType === 'service') { + if (entityType === ENTITY_TYPES.SERVICE) { const agentName = getSingleValue(entity[AGENT_NAME] as AgentName | AgentName[]); return ; } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx new file mode 100644 index 0000000000000..23cbb5b43c43b --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { GroupSelector } from './group_selector'; + +import { InventoryComponentWrapperMock } from './mock/inventory_component_wrapper_mock'; + +describe('GroupSelector', () => { + beforeEach(() => { + render( + + + + ); + }); + it('Should default to Type', async () => { + expect(await screen.findByText('Group entities by: Type')).toBeInTheDocument(); + }); + + it.skip('Should change to None', async () => { + const user = userEvent.setup(); + + const selector = screen.getByText('Group entities by: Type'); + + expect(selector).toBeInTheDocument(); + + await user.click(selector); + + const noneOption = screen.getByTestId('panelUnified'); + + expect(noneOption).toBeInTheDocument(); + + await user.click(noneOption); + + expect(await screen.findByText('Group entities by: None')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx new file mode 100644 index 0000000000000..95264f3c81303 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiPopover, EuiContextMenu, EuiButtonEmpty } from '@elastic/eui'; +import React, { useCallback, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import type { EntityView } from '../../../common/entities'; +import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventoryRouter } from '../../hooks/use_inventory_router'; + +const GROUP_LABELS: Record = { + unified: i18n.translate('xpack.inventory.groupedInventoryPage.noneLabel', { + defaultMessage: 'None', + }), + grouped: i18n.translate('xpack.inventory.groupedInventoryPage.typeLabel', { + defaultMessage: 'Type', + }), +}; + +export interface GroupedSelectorProps { + groupSelected: string; + onGroupChange: (groupSelection: string) => void; +} + +export function GroupSelector() { + const { query } = useInventoryParams('/'); + const inventoryRoute = useInventoryRouter(); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const groupBy = query.view ?? 'grouped'; + + const onGroupChange = (selected: EntityView) => { + const { pagination: _, ...rest } = query; + + inventoryRoute.push('/', { + path: {}, + query: { + ...rest, + view: groupBy === selected ? 'unified' : selected, + }, + }); + }; + + const isGroupSelected = (groupKey: EntityView) => { + return groupBy === groupKey; + }; + + const panels = [ + { + id: 'firstPanel', + title: i18n.translate('xpack.inventory.groupedInventoryPage.groupSelectorLabel', { + defaultMessage: 'Select grouping', + }), + items: [ + { + 'data-test-subj': 'panelUnified', + name: GROUP_LABELS.unified, + icon: isGroupSelected('unified') ? 'check' : 'empty', + onClick: () => onGroupChange('unified'), + }, + { + 'data-test-subj': 'panelType', + name: GROUP_LABELS.grouped, + icon: isGroupSelected('grouped') ? 'check' : 'empty', + onClick: () => onGroupChange('grouped'), + }, + ], + }, + ]; + + const onButtonClick = useCallback(() => setIsPopoverOpen((currentVal) => !currentVal), []); + + const closePopover = useCallback(() => setIsPopoverOpen(false), []); + + const button = ( + + + + ); + + return ( + + + + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx new file mode 100644 index 0000000000000..d005a001999d5 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx @@ -0,0 +1,130 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiDataGridSorting } from '@elastic/eui'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; +import { decodeOrThrow } from '@kbn/io-ts-utils'; +import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider'; +import { useKibana } from '../../hooks/use_kibana'; +import { EntitiesGrid } from '../entities_grid'; +import { + entityPaginationRt, + type EntityColumnIds, + type EntityPagination, +} from '../../../common/entities'; +import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventoryRouter } from '../../hooks/use_inventory_router'; + +interface Props { + field: string; +} + +const paginationDecoder = decodeOrThrow(entityPaginationRt); + +export function GroupedEntitiesGrid({ field }: Props) { + const { query } = useInventoryParams('/'); + const { sortField, sortDirection, kuery, pagination: paginationQuery } = query; + const inventoryRoute = useInventoryRouter(); + let pagination: EntityPagination | undefined = {}; + try { + pagination = paginationDecoder(paginationQuery); + } catch (error) { + inventoryRoute.push('/', { + path: {}, + query: { + sortField, + sortDirection, + kuery, + pagination: undefined, + }, + }); + window.location.reload(); + } + const pageIndex = pagination?.[field] ?? 0; + + const { refreshSubject$ } = useInventorySearchBarContext(); + const { + services: { inventoryAPIClient }, + } = useKibana(); + + const { + value = { entities: [] }, + loading, + refresh, + } = useInventoryAbortableAsync( + ({ signal }) => { + return inventoryAPIClient.fetch('GET /internal/inventory/entities', { + params: { + query: { + sortDirection, + sortField, + entityTypes: field?.length ? JSON.stringify([field]) : undefined, + kuery, + }, + }, + signal, + }); + }, + [field, inventoryAPIClient, kuery, sortDirection, sortField] + ); + + useEffectOnce(() => { + const refreshSubscription = refreshSubject$.subscribe(refresh); + + return () => refreshSubscription.unsubscribe(); + }); + + function handlePageChange(nextPage: number) { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + pagination: entityPaginationRt.encode({ + ...pagination, + [field]: nextPage, + }), + }, + }); + } + + function handleSortChange(sorting: EuiDataGridSorting['columns'][0]) { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + sortField: sorting.id as EntityColumnIds, + sortDirection: sorting.direction, + }, + }); + } + + function handleTypeFilter(type: string) { + const { pagination: _, ...rest } = query; + inventoryRoute.push('/', { + path: {}, + query: { + ...rest, + // Override the current entity types + entityTypes: [type], + }, + }); + } + + return ( + + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx new file mode 100644 index 0000000000000..b376200495e43 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiSpacer } from '@elastic/eui'; +import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; +import React from 'react'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; +import { InventoryGroupAccordion } from './inventory_group_accordion'; +import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import { useKibana } from '../../hooks/use_kibana'; +import { InventorySummary } from './inventory_summary'; +import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider'; + +export function GroupedInventory() { + const { + services: { inventoryAPIClient }, + } = useKibana(); + const { query } = useInventoryParams('/'); + const { kuery, entityTypes } = query; + const { refreshSubject$ } = useInventorySearchBarContext(); + + const { + value = { groupBy: ENTITY_TYPE, groups: [], entitiesCount: 0 }, + refresh, + loading, + } = useInventoryAbortableAsync( + ({ signal }) => { + return inventoryAPIClient.fetch('GET /internal/inventory/entities/group_by/{field}', { + params: { + path: { + field: ENTITY_TYPE, + }, + query: { + kuery, + entityTypes: entityTypes?.length ? JSON.stringify(entityTypes) : undefined, + }, + }, + signal, + }); + }, + [entityTypes, inventoryAPIClient, kuery] + ); + + useEffectOnce(() => { + const refreshSubscription = refreshSubject$.subscribe(refresh); + + return () => refreshSubscription.unsubscribe(); + }); + + return ( + <> + + + {value.groups.map((group) => ( + + ))} + + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx new file mode 100644 index 0000000000000..2cddbb8e46d79 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen, within } from '@testing-library/react'; + +import { InventoryGroupAccordion } from './inventory_group_accordion'; + +describe('Grouped Inventory Accordion', () => { + it('renders with correct values', () => { + const props = { + groupBy: 'entity.type', + groups: [ + { + count: 5999, + 'entity.type': 'host', + }, + { + count: 2001, + 'entity.type': 'service', + }, + ], + }; + render(); + expect(screen.getByText(props.groups[0]['entity.type'])).toBeInTheDocument(); + const container = screen.getByTestId('inventoryPanelBadgeEntitiesCount_entity.type_host'); + expect(within(container).getByText('Entities:')).toBeInTheDocument(); + expect(within(container).getByText(props.groups[0].count)).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx new file mode 100644 index 0000000000000..4c5d34e5a028f --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useCallback, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { css } from '@emotion/react'; +import { EuiAccordion, EuiPanel, EuiSpacer, EuiTitle, useEuiTheme } from '@elastic/eui'; +import { GroupedEntitiesGrid } from './grouped_entities_grid'; +import type { EntityGroup } from '../../../common/entities'; +import { InventoryPanelBadge } from './inventory_panel_badge'; + +const ENTITIES_COUNT_BADGE = i18n.translate( + 'xpack.inventory.inventoryGroupPanel.entitiesBadgeLabel', + { defaultMessage: 'Entities' } +); + +export interface InventoryGroupAccordionProps { + group: EntityGroup; + groupBy: string; + isLoading?: boolean; +} + +export function InventoryGroupAccordion({ + group, + groupBy, + isLoading, +}: InventoryGroupAccordionProps) { + const { euiTheme } = useEuiTheme(); + const field = group[groupBy]; + const [open, setOpen] = useState(false); + + const onToggle = useCallback(() => { + setOpen((opened) => !opened); + }, []); + + return ( + <> + + +

{field}

+ + } + buttonElement="div" + extraAction={ + + } + buttonProps={{ paddingSize: 'm' }} + paddingSize="none" + onToggle={onToggle} + isLoading={isLoading} + /> +
+ {open && ( + + + + )} + + + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx new file mode 100644 index 0000000000000..43db1c39154bc --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import React from 'react'; + +export function InventoryPanelBadge({ + name, + value, + 'data-test-subj': dataTestSubj, +}: { + name: string; + 'data-test-subj'?: string; + value: string | number; +}) { + return ( + + + + {name}: + + + + {value} + + + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx new file mode 100644 index 0000000000000..63583e60b0edd --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { EuiThemeProvider } from '@elastic/eui'; +import { I18nProvider } from '@kbn/i18n-react'; +import { InventorySummary } from './inventory_summary'; + +// Do not test the GroupSelector, as it needs a lot more complicated setup +jest.mock('./group_selector', () => ({ + GroupSelector: () => <>Selector, +})); + +function MockEnvWrapper({ children }: { children?: React.ReactNode }) { + return ( + + {children} + + ); +} + +describe('InventorySummary', () => { + it('renders the total entities without any group totals', () => { + render(, { wrapper: MockEnvWrapper }); + expect(screen.getByText('10 Entities')).toBeInTheDocument(); + expect(screen.queryByTestId('inventorySummaryGroupsTotal')).not.toBeInTheDocument(); + }); + it('renders the total entities with group totals', () => { + render(, { wrapper: MockEnvWrapper }); + expect(screen.getByText('15 Entities')).toBeInTheDocument(); + expect(screen.queryByText('3 Groups')).toBeInTheDocument(); + }); + it("won't render either totals when not provided anything", () => { + render(, { wrapper: MockEnvWrapper }); + expect(screen.queryByTestId('inventorySummaryEntitiesTotal')).not.toBeInTheDocument(); + expect(screen.queryByTestId('inventorySummaryGroupsTotal')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx new file mode 100644 index 0000000000000..55697790c4ee9 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { GroupSelector } from './group_selector'; + +export function InventorySummary({ + totalEntities, + totalGroups, +}: { + totalEntities?: number; + totalGroups?: number; +}) { + const { euiTheme } = useEuiTheme(); + + const isGrouped = totalGroups !== undefined; + + return ( + + + + {totalEntities !== undefined && ( + + + + + + )} + {isGrouped ? ( + + + + + + ) : null} + + + + + + + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/mock/inventory_component_wrapper_mock.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/mock/inventory_component_wrapper_mock.tsx new file mode 100644 index 0000000000000..08c8e93aadda8 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/mock/inventory_component_wrapper_mock.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { CoreStart } from '@kbn/core/public'; +import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; +import { createMemoryHistory } from 'history'; +import { RouterProvider } from '@kbn/typed-react-router-config'; +import { I18nProvider } from '@kbn/i18n-react'; +import { EuiThemeProvider } from '@elastic/eui'; +import { getMockInventoryContext } from '../../../../.storybook/get_mock_inventory_context'; +import { inventoryRouter } from '../../../routes/config'; +import { InventoryContextProvider } from '../../../context/inventory_context_provider'; + +export function InventoryComponentWrapperMock({ children }: React.PropsWithChildren<{}>) { + const context = getMockInventoryContext(); + const KibanaReactContext = createKibanaReactContext(context as unknown as Partial); + const history = createMemoryHistory({ + initialEntries: ['/'], + }); + return ( + + + + + + {children} + + + + + + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/unified_inventory.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/unified_inventory.tsx new file mode 100644 index 0000000000000..05f7437a32c4b --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/unified_inventory.tsx @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiDataGridSorting } from '@elastic/eui'; +import React from 'react'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; +import { decodeOrThrow } from '@kbn/io-ts-utils'; +import { + type EntityColumnIds, + entityPaginationRt, + type EntityPagination, +} from '../../../common/entities'; +import { EntitiesGrid } from '../entities_grid'; +import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventoryRouter } from '../../hooks/use_inventory_router'; +import { useKibana } from '../../hooks/use_kibana'; +import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider'; +import { InventorySummary } from './inventory_summary'; + +const paginationDecoder = decodeOrThrow(entityPaginationRt); + +export function UnifiedInventory() { + const { + services: { inventoryAPIClient }, + } = useKibana(); + const { refreshSubject$ } = useInventorySearchBarContext(); + const { query } = useInventoryParams('/'); + const { sortDirection, sortField, kuery, entityTypes, pagination: paginationQuery } = query; + let pagination: EntityPagination | undefined = {}; + const inventoryRoute = useInventoryRouter(); + try { + pagination = paginationDecoder(paginationQuery); + } catch (error) { + inventoryRoute.push('/', { + path: {}, + query: { + sortField, + sortDirection, + kuery, + pagination: undefined, + }, + }); + window.location.reload(); + } + + const pageIndex = pagination?.unified ?? 0; + + const { + value = { entities: [] }, + loading, + refresh, + } = useInventoryAbortableAsync( + ({ signal }) => { + return inventoryAPIClient.fetch('GET /internal/inventory/entities', { + params: { + query: { + sortDirection, + sortField, + entityTypes: entityTypes?.length ? JSON.stringify(entityTypes) : undefined, + kuery, + }, + }, + signal, + }); + }, + [entityTypes, inventoryAPIClient, kuery, sortDirection, sortField] + ); + + useEffectOnce(() => { + const refreshSubscription = refreshSubject$.subscribe(refresh); + + return () => refreshSubscription.unsubscribe(); + }); + + function handlePageChange(nextPage: number) { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + pagination: entityPaginationRt.encode({ + ...pagination, + unified: nextPage, + }), + }, + }); + } + + function handleSortChange(sorting: EuiDataGridSorting['columns'][0]) { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + sortField: sorting.id as EntityColumnIds, + sortDirection: sorting.direction, + }, + }); + } + + function handleTypeFilter(type: string) { + const { pagination: _, ...rest } = query; + + inventoryRoute.push('/', { + path: {}, + query: { + ...rest, + // Override the current entity types + entityTypes: [type], + }, + }); + } + + return ( + <> + + + + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx index 4e945dd9a1cad..2fd450aab30dd 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx @@ -19,7 +19,7 @@ import { DiscoverButton } from './discover_button'; import { getKqlFieldsWithFallback } from '../../utils/get_kql_field_names_with_fallback'; export function SearchBar() { - const { searchBarContentSubject$ } = useInventorySearchBarContext(); + const { searchBarContentSubject$, refreshSubject$ } = useInventorySearchBarContext(); const { services: { unifiedSearch, @@ -84,7 +84,7 @@ export function SearchBar() { const handleEntityTypesChange = useCallback( (nextEntityTypes: string[]) => { - searchBarContentSubject$.next({ kuery, entityTypes: nextEntityTypes, refresh: false }); + searchBarContentSubject$.next({ kuery, entityTypes: nextEntityTypes }); registerEntityTypeFilteredEvent({ filterEntityTypes: nextEntityTypes, filterKuery: kuery }); }, [kuery, registerEntityTypeFilteredEvent, searchBarContentSubject$] @@ -95,7 +95,6 @@ export function SearchBar() { searchBarContentSubject$.next({ kuery: query?.query as string, entityTypes, - refresh: !isUpdate, }); registerSearchSubmittedEvent({ @@ -103,8 +102,12 @@ export function SearchBar() { searchEntityTypes: entityTypes, searchIsUpdate: isUpdate, }); + + if (!isUpdate) { + refreshSubject$.next(); + } }, - [entityTypes, registerSearchSubmittedEvent, searchBarContentSubject$] + [entityTypes, registerSearchSubmittedEvent, searchBarContentSubject$, refreshSubject$] ); return ( diff --git a/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx b/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx index fbb51c4f0d7e7..eb5a2a057e529 100644 --- a/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx @@ -11,17 +11,20 @@ interface InventorySearchBarContextType { searchBarContentSubject$: Subject<{ kuery?: string; entityTypes?: string[]; - refresh: boolean; }>; + refreshSubject$: Subject; } const InventorySearchBarContext = createContext({ searchBarContentSubject$: new Subject(), + refreshSubject$: new Subject(), }); export function InventorySearchBarContextProvider({ children }: { children: ReactChild }) { return ( - + {children} ); diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts new file mode 100644 index 0000000000000..cf4993f871880 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts @@ -0,0 +1,170 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import { useDetailViewRedirect } from './use_detail_view_redirect'; +import { useKibana } from './use_kibana'; +import { + AGENT_NAME, + CLOUD_PROVIDER, + CONTAINER_ID, + ENTITY_DEFINITION_ID, + ENTITY_DISPLAY_NAME, + ENTITY_ID, + ENTITY_IDENTITY_FIELDS, + ENTITY_LAST_SEEN, + ENTITY_TYPE, + HOST_NAME, + ENTITY_TYPES, + SERVICE_ENVIRONMENT, + SERVICE_NAME, +} from '@kbn/observability-shared-plugin/common'; +import { unflattenEntity } from '../../common/utils/unflatten_entity'; +import type { Entity } from '../../common/entities'; + +jest.mock('./use_kibana'); +jest.mock('../../common/utils/unflatten_entity'); + +const useKibanaMock = useKibana as jest.Mock; +const unflattenEntityMock = unflattenEntity as jest.Mock; + +const commonEntityFields: Partial = { + [ENTITY_LAST_SEEN]: '2023-10-09T00:00:00Z', + [ENTITY_ID]: '1', + [ENTITY_DISPLAY_NAME]: 'entity_name', + [ENTITY_DEFINITION_ID]: 'entity_definition_id', +}; + +describe('useDetailViewRedirect', () => { + const mockGetIdentityFieldsValue = jest.fn(); + const mockAsKqlFilter = jest.fn(); + const mockGetRedirectUrl = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + + useKibanaMock.mockReturnValue({ + services: { + share: { + url: { + locators: { + get: jest.fn().mockReturnValue({ + getRedirectUrl: mockGetRedirectUrl, + }), + }, + }, + }, + entityManager: { + entityClient: { + getIdentityFieldsValue: mockGetIdentityFieldsValue, + asKqlFilter: mockAsKqlFilter, + }, + }, + }, + }); + + unflattenEntityMock.mockImplementation((entity) => entity); + }); + + it('getEntityRedirectUrl should return the correct URL for host entity', () => { + const entity: Entity = { + ...(commonEntityFields as Entity), + [ENTITY_IDENTITY_FIELDS]: [HOST_NAME], + [ENTITY_TYPE]: 'host', + [HOST_NAME]: 'host-1', + [CLOUD_PROVIDER]: null, + }; + + mockGetIdentityFieldsValue.mockReturnValue({ [HOST_NAME]: 'host-1' }); + mockGetRedirectUrl.mockReturnValue('asset-details-url'); + + const { result } = renderHook(() => useDetailViewRedirect()); + const url = result.current.getEntityRedirectUrl(entity); + + expect(url).toBe('asset-details-url'); + expect(mockGetRedirectUrl).toHaveBeenCalledWith({ assetId: 'host-1', assetType: 'host' }); + }); + + it('getEntityRedirectUrl should return the correct URL for container entity', () => { + const entity: Entity = { + ...(commonEntityFields as Entity), + [ENTITY_IDENTITY_FIELDS]: [CONTAINER_ID], + [ENTITY_TYPE]: 'container', + [CONTAINER_ID]: 'container-1', + [CLOUD_PROVIDER]: null, + }; + + mockGetIdentityFieldsValue.mockReturnValue({ [CONTAINER_ID]: 'container-1' }); + mockGetRedirectUrl.mockReturnValue('asset-details-url'); + + const { result } = renderHook(() => useDetailViewRedirect()); + const url = result.current.getEntityRedirectUrl(entity); + + expect(url).toBe('asset-details-url'); + expect(mockGetRedirectUrl).toHaveBeenCalledWith({ + assetId: 'container-1', + assetType: 'container', + }); + }); + + it('getEntityRedirectUrl should return the correct URL for service entity', () => { + const entity: Entity = { + ...(commonEntityFields as Entity), + [ENTITY_IDENTITY_FIELDS]: [SERVICE_NAME], + [ENTITY_TYPE]: 'service', + [SERVICE_NAME]: 'service-1', + [SERVICE_ENVIRONMENT]: 'prod', + [AGENT_NAME]: 'node', + }; + mockGetIdentityFieldsValue.mockReturnValue({ [SERVICE_NAME]: 'service-1' }); + mockGetRedirectUrl.mockReturnValue('service-overview-url'); + + const { result } = renderHook(() => useDetailViewRedirect()); + const url = result.current.getEntityRedirectUrl(entity); + + expect(url).toBe('service-overview-url'); + expect(mockGetRedirectUrl).toHaveBeenCalledWith({ + serviceName: 'service-1', + environment: 'prod', + }); + }); + + [ + [ENTITY_TYPES.KUBERNETES.CLUSTER.ecs, 'kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c'], + [ENTITY_TYPES.KUBERNETES.CLUSTER.semconv, 'kubernetes_otel-cluster-overview'], + [ENTITY_TYPES.KUBERNETES.CRONJOB.ecs, 'kubernetes-0a672d50-bcb1-11ec-b64f-7dd6e8e82013'], + [ENTITY_TYPES.KUBERNETES.DAEMONSET.ecs, 'kubernetes-85879010-bcb1-11ec-b64f-7dd6e8e82013'], + [ENTITY_TYPES.KUBERNETES.DEPLOYMENT.ecs, 'kubernetes-5be46210-bcb1-11ec-b64f-7dd6e8e82013'], + [ENTITY_TYPES.KUBERNETES.JOB.ecs, 'kubernetes-9bf990a0-bcb1-11ec-b64f-7dd6e8e82013'], + [ENTITY_TYPES.KUBERNETES.NODE.ecs, 'kubernetes-b945b7b0-bcb1-11ec-b64f-7dd6e8e82013'], + [ENTITY_TYPES.KUBERNETES.POD.ecs, 'kubernetes-3d4d9290-bcb1-11ec-b64f-7dd6e8e82013'], + [ENTITY_TYPES.KUBERNETES.STATEFULSET.ecs, 'kubernetes-21694370-bcb2-11ec-b64f-7dd6e8e82013'], + ].forEach(([entityType, dashboardId]) => { + it(`getEntityRedirectUrl should return the correct URL for ${entityType} entity`, () => { + const entity: Entity = { + ...(commonEntityFields as Entity), + [ENTITY_IDENTITY_FIELDS]: ['some.field'], + [ENTITY_TYPE]: entityType, + }; + + mockAsKqlFilter.mockReturnValue('kql-query'); + mockGetRedirectUrl.mockReturnValue('dashboard-url'); + + const { result } = renderHook(() => useDetailViewRedirect()); + const url = result.current.getEntityRedirectUrl(entity); + + expect(url).toBe('dashboard-url'); + expect(mockGetRedirectUrl).toHaveBeenCalledWith({ + dashboardId, + query: { + language: 'kuery', + query: 'kql-query', + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts new file mode 100644 index 0000000000000..ccfe07c5f0104 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + ASSET_DETAILS_LOCATOR_ID, + AssetDetailsLocatorParams, + ENTITY_IDENTITY_FIELDS, + ENTITY_TYPE, + SERVICE_OVERVIEW_LOCATOR_ID, + ServiceOverviewParams, +} from '@kbn/observability-shared-plugin/common'; +import { useCallback } from 'react'; +import { DashboardLocatorParams } from '@kbn/dashboard-plugin/public'; +import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; +import { castArray } from 'lodash'; +import { Exception } from 'handlebars'; +import type { Entity } from '../../common/entities'; +import { unflattenEntity } from '../../common/utils/unflatten_entity'; +import { useKibana } from './use_kibana'; + +const KUBERNETES_DASHBOARDS_IDS: Record = { + [ENTITY_TYPES.KUBERNETES.CLUSTER.ecs]: 'kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c', + [ENTITY_TYPES.KUBERNETES.CLUSTER.semconv]: 'kubernetes_otel-cluster-overview', + [ENTITY_TYPES.KUBERNETES.CRONJOB.ecs]: 'kubernetes-0a672d50-bcb1-11ec-b64f-7dd6e8e82013', + [ENTITY_TYPES.KUBERNETES.DAEMONSET.ecs]: 'kubernetes-85879010-bcb1-11ec-b64f-7dd6e8e82013', + [ENTITY_TYPES.KUBERNETES.DEPLOYMENT.ecs]: 'kubernetes-5be46210-bcb1-11ec-b64f-7dd6e8e82013', + [ENTITY_TYPES.KUBERNETES.JOB.ecs]: 'kubernetes-9bf990a0-bcb1-11ec-b64f-7dd6e8e82013', + [ENTITY_TYPES.KUBERNETES.NODE.ecs]: 'kubernetes-b945b7b0-bcb1-11ec-b64f-7dd6e8e82013', + [ENTITY_TYPES.KUBERNETES.POD.ecs]: 'kubernetes-3d4d9290-bcb1-11ec-b64f-7dd6e8e82013', + [ENTITY_TYPES.KUBERNETES.STATEFULSET.ecs]: 'kubernetes-21694370-bcb2-11ec-b64f-7dd6e8e82013', +}; + +export const useDetailViewRedirect = () => { + const { + services: { share, entityManager }, + } = useKibana(); + + const locators = share.url.locators; + const assetDetailsLocator = locators.get(ASSET_DETAILS_LOCATOR_ID); + const dashboardLocator = locators.get(DASHBOARD_APP_LOCATOR); + const serviceOverviewLocator = locators.get(SERVICE_OVERVIEW_LOCATOR_ID); + + const getSingleIdentityFieldValue = useCallback( + (entity: Entity) => { + const identityFields = castArray(entity[ENTITY_IDENTITY_FIELDS]); + if (identityFields.length > 1) { + throw new Exception( + `Multiple identity fields are not supported for ${entity[ENTITY_TYPE]}` + ); + } + + const identityField = identityFields[0]; + return entityManager.entityClient.getIdentityFieldsValue(unflattenEntity(entity))[ + identityField + ]; + }, + [entityManager.entityClient] + ); + + const getDetailViewRedirectUrl = useCallback( + (entity: Entity) => { + const identityValue = getIdentityValue(entity); + + switch (entity.entity.type) { + case ENTITY_TYPES.HOST: + case ENTITY_TYPES.CONTAINER: + return assetDetailsLocator?.getRedirectUrl({ + assetId: identityValue, + assetType: entity.entity.type, + }); + + case ENTITY_TYPES.SERVICE: + return serviceOverviewLocator?.getRedirectUrl({ + serviceName: identityValue, + // service.environemnt is not part of entity.identityFields + // we need to manually get its value + environment: entity.service?.environment, + }); + + default: + return undefined; + } + }, + [assetDetailsLocator, serviceOverviewLocator] + ); + + const getDashboardRedirectUrl = useCallback( + (entity: Entity) => { + const type = entity[ENTITY_TYPE]; + const dashboardId = KUBERNETES_DASHBOARDS_IDS[type]; + + return dashboardId + ? dashboardLocator?.getRedirectUrl({ + dashboardId, + query: { + language: 'kuery', + query: entityManager.entityClient.asKqlFilter(unflattenEntity(entity)), + }, + }) + : undefined; + }, + [dashboardLocator, entityManager.entityClient] + ); + + const getEntityRedirectUrl = useCallback( + (entity: Entity) => getDetailViewRedirectUrl(entity) ?? getDashboardRedirectUrl(entity), + [getDashboardRedirectUrl, getDetailViewRedirectUrl] + ); + + return { getEntityRedirectUrl }; +}; diff --git a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx index 00dfb9e24d2dd..03f8b6475175a 100644 --- a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx @@ -4,105 +4,36 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiDataGridSorting } from '@elastic/eui'; -import React from 'react'; -import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { EntityColumnIds } from '../../../common/entities'; -import { EntitiesGrid } from '../../components/entities_grid'; -import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider'; -import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import React, { useEffect } from 'react'; import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider'; import { useInventoryRouter } from '../../hooks/use_inventory_router'; -import { useKibana } from '../../hooks/use_kibana'; +import { UnifiedInventory } from '../../components/grouped_inventory/unified_inventory'; +import { GroupedInventory } from '../../components/grouped_inventory'; export function InventoryPage() { const { searchBarContentSubject$ } = useInventorySearchBarContext(); - const { - services: { inventoryAPIClient }, - } = useKibana(); - const { query } = useInventoryParams('/'); - const { sortDirection, sortField, pageIndex, kuery, entityTypes } = query; - const inventoryRoute = useInventoryRouter(); + const { query } = useInventoryParams('/'); - const { - value = { entities: [] }, - loading, - refresh, - } = useInventoryAbortableAsync( - ({ signal }) => { - return inventoryAPIClient.fetch('GET /internal/inventory/entities', { - params: { - query: { - sortDirection, - sortField, - entityTypes: entityTypes?.length ? JSON.stringify(entityTypes) : undefined, - kuery, - }, - }, - signal, - }); - }, - [entityTypes, inventoryAPIClient, kuery, sortDirection, sortField] - ); - - useEffectOnce(() => { + useEffect(() => { const searchBarContentSubscription = searchBarContentSubject$.subscribe( - ({ refresh: isRefresh, ...queryParams }) => { - if (isRefresh) { - refresh(); - } else { - inventoryRoute.push('/', { - path: {}, - query: { ...query, ...queryParams }, - }); - } + ({ ...queryParams }) => { + const { pagination: _, ...rest } = query; + + inventoryRoute.push('/', { + path: {}, + query: { ...rest, ...queryParams }, + }); } ); return () => { searchBarContentSubscription.unsubscribe(); }; - }); - - function handlePageChange(nextPage: number) { - inventoryRoute.push('/', { - path: {}, - query: { ...query, pageIndex: nextPage }, - }); - } - - function handleSortChange(sorting: EuiDataGridSorting['columns'][0]) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - sortField: sorting.id as EntityColumnIds, - sortDirection: sorting.direction, - }, - }); - } - - function handleTypeFilter(entityType: string) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - // Override the current entity types - entityTypes: [entityType], - }, - }); - } + // If query has updated, the inventoryRoute state is also updated + // as well, so we only need to track changes on query. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [query, searchBarContentSubject$]); - return ( - - ); + return query.view === 'unified' ? : ; } diff --git a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx index dc7ba13451e02..36a15c5ae542c 100644 --- a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx @@ -4,13 +4,17 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { toNumberRt } from '@kbn/io-ts-utils'; import { Outlet, createRouter } from '@kbn/typed-react-router-config'; import * as t from 'io-ts'; import React from 'react'; import { InventoryPageTemplate } from '../components/inventory_page_template'; import { InventoryPage } from '../pages/inventory_page'; -import { defaultEntitySortField, entityTypesRt, entityColumnIdsRt } from '../../common/entities'; +import { + defaultEntitySortField, + entityTypesRt, + entityColumnIdsRt, + entityViewRt, +} from '../../common/entities'; /** * The array of route definitions to be used when the application @@ -28,11 +32,12 @@ const inventoryRoutes = { t.type({ sortField: entityColumnIdsRt, sortDirection: t.union([t.literal('asc'), t.literal('desc')]), - pageIndex: toNumberRt, }), t.partial({ entityTypes: entityTypesRt, kuery: t.string, + view: entityViewRt, + pagination: t.string, }), ]), }), @@ -40,7 +45,7 @@ const inventoryRoutes = { query: { sortField: defaultEntitySortField, sortDirection: 'desc', - pageIndex: '0', + view: 'grouped', }, }, children: { diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts new file mode 100644 index 0000000000000..b61f245f1aaf2 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import { kqlQuery } from '@kbn/observability-utils/es/queries/kql_query'; +import { esqlResultToPlainObjects } from '@kbn/observability-utils/es/utils/esql_result_to_plain_objects'; +import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; +import { ScalarValue } from '@elastic/elasticsearch/lib/api/types'; +import { + ENTITIES_LATEST_ALIAS, + type EntityGroup, + MAX_NUMBER_OF_ENTITIES, +} from '../../../common/entities'; +import { getBuiltinEntityDefinitionIdESQLWhereClause } from './query_helper'; + +export async function getEntityGroupsBy({ + inventoryEsClient, + field, + kuery, + entityTypes, +}: { + inventoryEsClient: ObservabilityElasticsearchClient; + field: string; + kuery?: string; + entityTypes?: string[]; +}) { + const from = `FROM ${ENTITIES_LATEST_ALIAS}`; + const where = [getBuiltinEntityDefinitionIdESQLWhereClause()]; + const params: ScalarValue[] = []; + + if (entityTypes) { + where.push(`WHERE ${ENTITY_TYPE} IN (${entityTypes.map(() => '?').join()})`); + params.push(...entityTypes); + } + + // STATS doesn't support parameterisation. + const group = `STATS count = COUNT(*) by ${field}`; + const sort = `SORT ${field} asc`; + // LIMIT doesn't support parameterisation. + const limit = `LIMIT ${MAX_NUMBER_OF_ENTITIES}`; + const query = [from, ...where, group, sort, limit].join(' | '); + + const groups = await inventoryEsClient.esql('get_entities_groups', { + query, + filter: { + bool: { + filter: kqlQuery(kuery), + }, + }, + params, + }); + + return esqlResultToPlainObjects(groups); +} diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identify_fields.test.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identify_fields.test.ts index ffd5ba9c6f855..62d77c08fd27a 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identify_fields.test.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identify_fields.test.ts @@ -30,7 +30,7 @@ describe('getIdentityFields', () => { it('should return a Map with unique entity types and their respective identity fields', () => { const serviceEntity: Entity = { 'agent.name': 'node', - 'entity.identity_fields': ['service.name', 'service.environment'], + [ENTITY_IDENTITY_FIELDS]: ['service.name', 'service.environment'], 'service.name': 'my-service', 'entity.type': 'service', ...commonEntityFields, diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts index 4fb3b930beace..c95a488ad49dd 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -40,7 +40,7 @@ export async function getLatestEntities({ if (entityTypes) { where.push(`WHERE ${ENTITY_TYPE} IN (${entityTypes.map(() => '?').join()})`); - params.push(...entityTypes.map((entityType) => entityType)); + params.push(...entityTypes); } const sort = `SORT ${entitiesSortField} ${sortDirection}`; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts index 67b3803dd98de..88d6cb68ee214 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts @@ -7,6 +7,7 @@ import { INVENTORY_APP_ID } from '@kbn/deeplinks-observability/constants'; import { jsonRt } from '@kbn/io-ts-utils'; import { createObservabilityEsClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import * as t from 'io-ts'; import { orderBy } from 'lodash'; import { joinByKey } from '@kbn/observability-utils/array/join_by_key'; @@ -17,6 +18,7 @@ import { getLatestEntities } from './get_latest_entities'; import { createAlertsClient } from '../../lib/create_alerts_client.ts/create_alerts_client'; import { getLatestEntitiesAlerts } from './get_latest_entities_alerts'; import { getIdentityFieldsPerEntityType } from './get_identity_fields_per_entity_type'; +import { getEntityGroupsBy } from './get_entity_groups'; export const getEntityTypesRoute = createInventoryServerRoute({ endpoint: 'GET /internal/inventory/entities/types', @@ -106,7 +108,46 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ }, }); +export const groupEntitiesByRoute = createInventoryServerRoute({ + endpoint: 'GET /internal/inventory/entities/group_by/{field}', + params: t.intersection([ + t.type({ path: t.type({ field: t.literal(ENTITY_TYPE) }) }), + t.partial({ + query: t.partial({ + kuery: t.string, + entityTypes: jsonRt.pipe(t.array(t.string)), + }), + }), + ]), + options: { + tags: ['access:inventory'], + }, + handler: async ({ params, context, logger }) => { + const coreContext = await context.core; + const inventoryEsClient = createObservabilityEsClient({ + client: coreContext.elasticsearch.client.asCurrentUser, + logger, + plugin: `@kbn/${INVENTORY_APP_ID}-plugin`, + }); + + const { field } = params.path; + const { kuery, entityTypes } = params.query ?? {}; + + const groups = await getEntityGroupsBy({ + inventoryEsClient, + field, + kuery, + entityTypes, + }); + + const entitiesCount = groups.reduce((acc, group) => acc + group.count, 0); + + return { groupBy: field, groups, entitiesCount }; + }, +}); + export const entitiesRoutes = { ...listLatestEntitiesRoute, ...getEntityTypesRoute, + ...groupEntitiesByRoute, }; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts b/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts index 27ba8c0fe46c3..c1e4a82c343b0 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts @@ -26,7 +26,6 @@ export async function getHasData({ }); const totalCount = esqlResultToPlainObjects(esqlResults)?.[0]._count ?? 0; - return { hasData: totalCount > 0 }; } catch (e) { logger.error(e); diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json index 67de9919c6324..bd77df478cad1 100644 --- a/x-pack/plugins/observability_solution/inventory/tsconfig.json +++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json @@ -52,6 +52,9 @@ "@kbn/rule-data-utils", "@kbn/spaces-plugin", "@kbn/cloud-plugin", - "@kbn/storybook" + "@kbn/storybook", + "@kbn/zod", + "@kbn/dashboard-plugin", + "@kbn/deeplinks-analytics" ] } diff --git a/x-pack/plugins/observability_solution/investigate_app/server/lib/get_sample_documents.ts b/x-pack/plugins/observability_solution/investigate_app/server/lib/get_sample_documents.ts index 75e21526a6506..9621a5ff1a4ed 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/lib/get_sample_documents.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/lib/get_sample_documents.ts @@ -7,7 +7,7 @@ import pLimit from 'p-limit'; import { estypes } from '@elastic/elasticsearch'; import { castArray, sortBy, uniq, partition, shuffle } from 'lodash'; -import { truncateList } from '@kbn/inference-plugin/common/util/truncate_list'; +import { truncateList } from '@kbn/inference-plugin/common/utils/truncate_list'; import { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { rangeQuery, excludeFrozenQuery } from './queries'; diff --git a/x-pack/plugins/observability_solution/observability/common/index.ts b/x-pack/plugins/observability_solution/observability/common/index.ts index 3dc44c5ac02aa..4baaf7957fa81 100644 --- a/x-pack/plugins/observability_solution/observability/common/index.ts +++ b/x-pack/plugins/observability_solution/observability/common/index.ts @@ -30,8 +30,6 @@ export { apmServiceGroupMaxNumberOfServices, apmTraceExplorerTab, apmLabsButton, - enableInfrastructureHostsView, - enableInfrastructureContainerAssetView, enableInfrastructureProfilingIntegration, enableInfrastructureAssetCustomDashboards, enableAwsLambdaMetrics, diff --git a/x-pack/plugins/observability_solution/observability/common/ui_settings_keys.ts b/x-pack/plugins/observability_solution/observability/common/ui_settings_keys.ts index efceaca9a0427..7025c120cae5d 100644 --- a/x-pack/plugins/observability_solution/observability/common/ui_settings_keys.ts +++ b/x-pack/plugins/observability_solution/observability/common/ui_settings_keys.ts @@ -16,13 +16,10 @@ export const apmServiceGroupMaxNumberOfServices = 'observability:apmServiceGroupMaxNumberOfServices'; export const apmTraceExplorerTab = 'observability:apmTraceExplorerTab'; export const apmLabsButton = 'observability:apmLabsButton'; -export const enableInfrastructureHostsView = 'observability:enableInfrastructureHostsView'; export const enableInfrastructureProfilingIntegration = 'observability:enableInfrastructureProfilingIntegration'; export const enableInfrastructureAssetCustomDashboards = 'observability:enableInfrastructureAssetCustomDashboards'; -export const enableInfrastructureContainerAssetView = - 'observability:enableInfrastructureContainerAssetView'; export const enableAwsLambdaMetrics = 'observability:enableAwsLambdaMetrics'; export const enableAgentExplorerView = 'observability:apmAgentExplorerView'; export const apmEnableTableSearchBar = 'observability:apmEnableTableSearchBar'; diff --git a/x-pack/plugins/observability_solution/observability/public/index.ts b/x-pack/plugins/observability_solution/observability/public/index.ts index 58c3aa4cadd66..6230f5411b543 100644 --- a/x-pack/plugins/observability_solution/observability/public/index.ts +++ b/x-pack/plugins/observability_solution/observability/public/index.ts @@ -40,8 +40,6 @@ export { enableInspectEsQueries, enableComparisonByDefault, apmServiceGroupMaxNumberOfServices, - enableInfrastructureHostsView, - enableInfrastructureContainerAssetView, enableAgentExplorerView, apmEnableTableSearchBar, } from '../common/ui_settings_keys'; diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/alert_details.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/alert_details.tsx index 8f5acee54f57e..9403090b1e213 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/alert_details.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/alert_details.tsx @@ -93,6 +93,7 @@ export function AlertDetails() { triggersActionsUi: { ruleTypeRegistry }, observabilityAIAssistant, uiSettings, + serverless, } = useKibana().services; const { search } = useLocation(); @@ -158,20 +159,23 @@ export function AlertDetails() { } }, [alertDetail, ruleTypeRegistry]); - useBreadcrumbs([ - { - href: http.basePath.prepend(paths.observability.alerts), - text: i18n.translate('xpack.observability.breadcrumbs.alertsLinkText', { - defaultMessage: 'Alerts', - }), - deepLinkId: 'observability-overview:alerts', - }, - { - text: alertDetail - ? getPageTitle(alertDetail.formatted.fields[ALERT_RULE_CATEGORY]) - : defaultBreadcrumb, - }, - ]); + useBreadcrumbs( + [ + { + href: http.basePath.prepend(paths.observability.alerts), + text: i18n.translate('xpack.observability.breadcrumbs.alertsLinkText', { + defaultMessage: 'Alerts', + }), + deepLinkId: 'observability-overview:alerts', + }, + { + text: alertDetail + ? getPageTitle(alertDetail.formatted.fields[ALERT_RULE_CATEGORY]) + : defaultBreadcrumb, + }, + ], + { serverless } + ); const onUntrackAlert = () => { setAlertStatus(ALERT_STATUS_UNTRACKED); diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alerts/alerts.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alerts/alerts.tsx index ef883f40f4902..6607052225555 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alerts/alerts.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alerts/alerts.tsx @@ -159,13 +159,18 @@ function InternalAlertsPage() { [alertSearchBarStateProps.rangeFrom, alertSearchBarStateProps.rangeTo, bucketSize, esQuery] ); - useBreadcrumbs([ + useBreadcrumbs( + [ + { + text: i18n.translate('xpack.observability.breadcrumbs.alertsLinkText', { + defaultMessage: 'Alerts', + }), + }, + ], { - text: i18n.translate('xpack.observability.breadcrumbs.alertsLinkText', { - defaultMessage: 'Alerts', - }), - }, - ]); + classicOnly: true, + } + ); async function loadRuleStats() { setRuleStatsLoading(true); diff --git a/x-pack/plugins/observability_solution/observability/public/pages/overview/overview.tsx b/x-pack/plugins/observability_solution/observability/public/pages/overview/overview.tsx index 37942cdbca7d6..c7b71431050cf 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/overview/overview.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/overview/overview.tsx @@ -56,13 +56,18 @@ export function OverviewPage() { const { ObservabilityPageTemplate, observabilityRuleTypeRegistry } = usePluginContext(); - useBreadcrumbs([ + useBreadcrumbs( + [ + { + text: i18n.translate('xpack.observability.breadcrumbs.overviewLinkText', { + defaultMessage: 'Overview', + }), + }, + ], { - text: i18n.translate('xpack.observability.breadcrumbs.overviewLinkText', { - defaultMessage: 'Overview', - }), - }, - ]); + classicOnly: true, + } + ); const { data: newsFeed } = useFetcher( () => getNewsFeed({ http, kibanaVersion }), diff --git a/x-pack/plugins/observability_solution/observability/public/pages/rule_details/rule_details.tsx b/x-pack/plugins/observability_solution/observability/public/pages/rule_details/rule_details.tsx index e8270434c12b2..3b2e5d3118c4a 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/rule_details/rule_details.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/rule_details/rule_details.tsx @@ -61,6 +61,7 @@ export function RuleDetailsPage() { getRuleDefinition: RuleDefinition, getRuleStatusPanel: RuleStatusPanel, }, + serverless, } = useKibana().services; const { ObservabilityPageTemplate } = usePluginContext(); @@ -72,24 +73,27 @@ export function RuleDetailsPage() { filterByRuleTypeIds: filteredRuleTypes, }); - useBreadcrumbs([ - { - text: i18n.translate('xpack.observability.breadcrumbs.alertsLinkText', { - defaultMessage: 'Alerts', - }), - href: basePath.prepend(paths.observability.alerts), - deepLinkId: 'observability-overview:alerts', - }, - { - href: basePath.prepend(paths.observability.rules), - text: i18n.translate('xpack.observability.breadcrumbs.rulesLinkText', { - defaultMessage: 'Rules', - }), - }, - { - text: rule && rule.name, - }, - ]); + useBreadcrumbs( + [ + { + text: i18n.translate('xpack.observability.breadcrumbs.alertsLinkText', { + defaultMessage: 'Alerts', + }), + href: basePath.prepend(paths.observability.alerts), + deepLinkId: 'observability-overview:alerts', + }, + { + href: basePath.prepend(paths.observability.rules), + text: i18n.translate('xpack.observability.breadcrumbs.rulesLinkText', { + defaultMessage: 'Rules', + }), + }, + { + text: rule && rule.name, + }, + ], + { serverless } + ); const [activeTabId, setActiveTabId] = useState(() => { const searchParams = new URLSearchParams(search); diff --git a/x-pack/plugins/observability_solution/observability/public/pages/rules/rules.tsx b/x-pack/plugins/observability_solution/observability/public/pages/rules/rules.tsx index fb257f9f95cde..b94b9a7e4218f 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/rules/rules.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/rules/rules.tsx @@ -42,6 +42,7 @@ export function RulesPage({ activeTab = RULES_TAB_NAME }: RulesPageProps) { getAddRuleFlyout: AddRuleFlyout, getRulesSettingsLink: RulesSettingsLink, }, + serverless, } = useKibana().services; const { ObservabilityPageTemplate } = usePluginContext(); const history = useHistory(); @@ -50,20 +51,23 @@ export function RulesPage({ activeTab = RULES_TAB_NAME }: RulesPageProps) { const [addRuleFlyoutVisibility, setAddRuleFlyoutVisibility] = useState(false); const [stateRefresh, setRefresh] = useState(new Date()); - useBreadcrumbs([ - { - text: i18n.translate('xpack.observability.breadcrumbs.alertsLinkText', { - defaultMessage: 'Alerts', - }), - href: http.basePath.prepend('/app/observability/alerts'), - deepLinkId: 'observability-overview:alerts', - }, - { - text: i18n.translate('xpack.observability.breadcrumbs.rulesLinkText', { - defaultMessage: 'Rules', - }), - }, - ]); + useBreadcrumbs( + [ + { + text: i18n.translate('xpack.observability.breadcrumbs.alertsLinkText', { + defaultMessage: 'Alerts', + }), + href: http.basePath.prepend('/app/observability/alerts'), + deepLinkId: 'observability-overview:alerts', + }, + { + text: i18n.translate('xpack.observability.breadcrumbs.rulesLinkText', { + defaultMessage: 'Rules', + }), + }, + ], + { serverless } + ); const filteredRuleTypes = useGetFilteredRuleTypes(); const { diff --git a/x-pack/plugins/observability_solution/observability/server/ui_settings.ts b/x-pack/plugins/observability_solution/observability/server/ui_settings.ts index dae7e2ad9ab5b..1a387f24fbaed 100644 --- a/x-pack/plugins/observability_solution/observability/server/ui_settings.ts +++ b/x-pack/plugins/observability_solution/observability/server/ui_settings.ts @@ -28,7 +28,6 @@ import { apmEnableServiceMetrics, apmEnableContinuousRollups, enableCriticalPath, - enableInfrastructureHostsView, syntheticsThrottlingEnabled, enableLegacyUptimeApp, apmEnableProfilingIntegration, @@ -45,7 +44,6 @@ import { enableInfrastructureAssetCustomDashboards, apmEnableServiceInventoryTableSearchBar, profilingFetchTopNFunctionsFromStacktraces, - enableInfrastructureContainerAssetView, searchExcludedDataTiers, } from '../common/ui_settings_keys'; @@ -232,31 +230,6 @@ export const uiSettings: Record = { requiresPageReload: true, type: 'boolean', }, - [enableInfrastructureHostsView]: { - category: [observabilityFeatureId], - name: i18n.translate('xpack.observability.enableInfrastructureHostsView', { - defaultMessage: 'Infrastructure Hosts view', - }), - value: true, - description: i18n.translate('xpack.observability.enableInfrastructureHostsViewDescription', { - defaultMessage: 'Enable the Hosts view in the Infrastructure app.', - }), - schema: schema.boolean(), - }, - [enableInfrastructureContainerAssetView]: { - category: [observabilityFeatureId], - name: i18n.translate('xpack.observability.enableInfrastructureContainerAssetView', { - defaultMessage: 'Container view', - }), - value: true, - description: i18n.translate( - 'xpack.observability.enableInfrastructureContainerAssetViewDescription', - { - defaultMessage: 'Enable the Container asset view in the Infrastructure app.', - } - ), - schema: schema.boolean(), - }, [enableInfrastructureProfilingIntegration]: { category: [observabilityFeatureId], name: i18n.translate('xpack.observability.enableInfrastructureProfilingIntegration', { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts index 7595c42e4dc93..51ae37b39d90f 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts @@ -5,7 +5,7 @@ * 2.0. */ import { IconType } from '@elastic/eui'; -import type { ToolSchema } from '@kbn/inference-plugin/common'; +import type { ToolSchema } from '@kbn/inference-common'; import type { AssistantScope } from '@kbn/ai-assistant-common'; import type { ObservabilityAIAssistantChatService } from '../public'; import type { FunctionResponse } from './functions/types'; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts index 86b8f14bde9e4..049c5a1e65fb0 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts @@ -6,6 +6,7 @@ */ import type { AnalyticsServiceSetup, AnalyticsServiceStart } from '@kbn/core-analytics-browser'; +import { AssistantScope } from '@kbn/ai-assistant-common'; import type { Message } from '../../common'; import { chatFeedbackEventSchema, ChatFeedback } from './schemas/chat_feedback'; import { insightFeedbackEventSchema, InsightFeedback } from './schemas/insight_feedback'; @@ -17,7 +18,10 @@ const schemas = [chatFeedbackEventSchema, insightFeedbackEventSchema, userSentPr export type TelemetryEventTypeWithPayload = | { type: ObservabilityAIAssistantTelemetryEventType.ChatFeedback; payload: ChatFeedback } | { type: ObservabilityAIAssistantTelemetryEventType.InsightFeedback; payload: InsightFeedback } - | { type: ObservabilityAIAssistantTelemetryEventType.UserSentPromptInChat; payload: Message }; + | { + type: ObservabilityAIAssistantTelemetryEventType.UserSentPromptInChat; + payload: Message & { scopes: AssistantScope[] }; + }; export const registerTelemetryEventTypes = (analytics: AnalyticsServiceSetup) => { schemas.forEach((schema) => { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/common.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/common.ts index b01a8e05a4ea5..4a2739ef82c35 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/common.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/common.ts @@ -6,9 +6,10 @@ */ import type { RootSchema } from '@kbn/core/public'; +import { AssistantScope } from '@kbn/ai-assistant-common'; import type { Message } from '../../../common'; -export const messageSchema: RootSchema = { +export const messageSchema: RootSchema = { '@timestamp': { type: 'text', _meta: { @@ -74,4 +75,13 @@ export const messageSchema: RootSchema = { }, }, }, + scopes: { + type: 'array', + items: { + type: 'text', + _meta: { + description: 'The scopes that were used when generating the message.', + }, + }, + }, }; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx index 562749f24cc9d..e5168470be8f1 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx @@ -128,6 +128,7 @@ function ChatContent({ service.conversations.openNewConversation({ messages, title: defaultTitle, + hideConversationList: true, }); }} /> diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/service/create_service.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/service/create_service.ts index 07f967a4028d9..5b64073592430 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/service/create_service.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/service/create_service.ts @@ -36,7 +36,11 @@ export function createService({ const screenContexts$ = new BehaviorSubject([ { starterPrompts: defaultStarterPrompts }, ]); - const predefinedConversation$ = new Subject<{ messages: Message[]; title?: string }>(); + const predefinedConversation$ = new Subject<{ + messages: Message[]; + title?: string; + hideConversationList?: boolean; + }>(); const scope$ = new BehaviorSubject(scopes); @@ -104,8 +108,16 @@ export function createService({ ); }, conversations: { - openNewConversation: ({ messages, title }: { messages: Message[]; title?: string }) => { - predefinedConversation$.next({ messages, title }); + openNewConversation: ({ + messages, + title, + hideConversationList = false, + }: { + messages: Message[]; + title?: string; + hideConversationList?: boolean; + }) => { + predefinedConversation$.next({ messages, title, hideConversationList }); }, predefinedConversation$: predefinedConversation$.asObservable(), }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/types.ts index becc21f59c5f4..72517df5bffbc 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/types.ts @@ -91,8 +91,16 @@ export interface ObservabilityAIAssistantChatService { } export interface ObservabilityAIAssistantConversationService { - openNewConversation: ({}: { messages: Message[]; title?: string }) => void; - predefinedConversation$: Observable<{ messages: Message[]; title?: string }>; + openNewConversation: ({}: { + messages: Message[]; + title?: string; + hideConversationList?: boolean; + }) => void; + predefinedConversation$: Observable<{ + messages: Message[]; + title?: string; + hideConversationList?: boolean; + }>; } export interface ObservabilityAIAssistantService { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/functions/route.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/functions/route.ts index 8a61248d4e70e..c402a0506736f 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/functions/route.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/functions/route.ts @@ -68,7 +68,7 @@ const getFunctionsRoute = createObservabilityAIAssistantServerRoute({ systemMessage: getSystemMessageFromInstructions({ applicationInstructions: functionClient.getInstructions(), userInstructions, - adHocInstructions: [], + adHocInstructions: functionClient.getAdhocInstructions(), availableFunctionNames, }), }; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.test.ts index 3d83c470de0c5..0d911b497cbbb 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.test.ts @@ -7,6 +7,7 @@ import dedent from 'dedent'; import { ChatFunctionClient, GET_DATA_ON_SCREEN_FUNCTION_NAME } from '.'; import { FunctionVisibility } from '../../../common/functions/types'; +import { AdHocInstruction } from '../../../common/types'; describe('chatFunctionClient', () => { describe('when executing a function with invalid arguments', () => { @@ -86,6 +87,7 @@ describe('chatFunctionClient', () => { ]); const functions = client.getFunctions(); + const adHocInstructions = client.getAdhocInstructions(); expect(functions[0]).toEqual({ definition: { @@ -97,7 +99,7 @@ describe('chatFunctionClient', () => { respond: expect.any(Function), }); - expect(functions[0].definition.description).toContain( + expect(adHocInstructions[0].text).toContain( dedent(`my_dummy_data: My dummy data my_other_dummy_data: My other dummy data `) @@ -128,4 +130,52 @@ describe('chatFunctionClient', () => { }); }); }); + + describe('when adhoc instructions are provided', () => { + let client: ChatFunctionClient; + + beforeEach(() => { + client = new ChatFunctionClient([]); + }); + + describe('register an adhoc Instruction', () => { + it('should register a new adhoc instruction', () => { + const adhocInstruction: AdHocInstruction = { + text: 'Test adhoc instruction', + instruction_type: 'application_instruction', + }; + + client.registerAdhocInstruction(adhocInstruction); + + expect(client.getAdhocInstructions()).toContainEqual(adhocInstruction); + }); + }); + + describe('retrieve adHoc instructions', () => { + it('should return all registered adhoc instructions', () => { + const firstAdhocInstruction: AdHocInstruction = { + text: 'First adhoc instruction', + instruction_type: 'application_instruction', + }; + + const secondAdhocInstruction: AdHocInstruction = { + text: 'Second adhoc instruction', + instruction_type: 'application_instruction', + }; + + client.registerAdhocInstruction(firstAdhocInstruction); + client.registerAdhocInstruction(secondAdhocInstruction); + + const adhocInstructions = client.getAdhocInstructions(); + + expect(adhocInstructions).toEqual([firstAdhocInstruction, secondAdhocInstruction]); + }); + + it('should return an empty array if no adhoc instructions are registered', () => { + const adhocInstructions = client.getAdhocInstructions(); + + expect(adhocInstructions).toEqual([]); + }); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.ts index 97def121e8593..ad4b7f0a4fc92 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.ts @@ -10,13 +10,18 @@ import Ajv, { type ErrorObject, type ValidateFunction } from 'ajv'; import dedent from 'dedent'; import { compact, keyBy } from 'lodash'; import { FunctionVisibility, type FunctionResponse } from '../../../common/functions/types'; -import type { Message, ObservabilityAIAssistantScreenContextRequest } from '../../../common/types'; +import type { + AdHocInstruction, + Message, + ObservabilityAIAssistantScreenContextRequest, +} from '../../../common/types'; import { filterFunctionDefinitions } from '../../../common/utils/filter_function_definitions'; import type { FunctionCallChatFunction, FunctionHandler, FunctionHandlerRegistry, InstructionOrCallback, + RegisterAdHocInstruction, RegisterFunction, RegisterInstruction, } from '../types'; @@ -35,6 +40,8 @@ export const GET_DATA_ON_SCREEN_FUNCTION_NAME = 'get_data_on_screen'; export class ChatFunctionClient { private readonly instructions: InstructionOrCallback[] = []; + private readonly adhocInstructions: AdHocInstruction[] = []; + private readonly functionRegistry: FunctionHandlerRegistry = new Map(); private readonly validators: Map = new Map(); @@ -49,9 +56,7 @@ export class ChatFunctionClient { this.registerFunction( { name: GET_DATA_ON_SCREEN_FUNCTION_NAME, - description: dedent(`Get data that is on the screen: - ${allData.map((data) => `${data.name}: ${data.description}`).join('\n')} - `), + description: `Retrieve the structured data of content currently visible on the user's screen. Use this tool to understand what the user is viewing at this moment to provide more accurate and context-aware responses to their questions.`, visibility: FunctionVisibility.AssistantOnly, parameters: { type: 'object', @@ -75,6 +80,13 @@ export class ChatFunctionClient { }; } ); + + this.registerAdhocInstruction({ + text: `The ${GET_DATA_ON_SCREEN_FUNCTION_NAME} function will retrieve specific content from the user's screen by specifying a data key. Use this tool to provide context-aware responses. Available data: ${dedent( + allData.map((data) => `${data.name}: ${data.description}`).join('\n') + )}`, + instruction_type: 'application_instruction', + }); } this.actions.forEach((action) => { @@ -95,6 +107,10 @@ export class ChatFunctionClient { this.instructions.push(instruction); }; + registerAdhocInstruction: RegisterAdHocInstruction = (instruction: AdHocInstruction) => { + this.adhocInstructions.push(instruction); + }; + validate(name: string, parameters: unknown) { const validator = this.validators.get(name)!; if (!validator) { @@ -111,6 +127,10 @@ export class ChatFunctionClient { return this.instructions; } + getAdhocInstructions(): AdHocInstruction[] { + return this.adhocInstructions; + } + hasAction(name: string) { return !!this.actions.find((action) => action.name === name)!; } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts index 0476bda1af8a2..8da2a0d843b11 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts @@ -124,6 +124,7 @@ describe('Observability AI Assistant client', () => { getActions: jest.fn(), validate: jest.fn(), getInstructions: jest.fn(), + getAdhocInstructions: jest.fn(), } as any; let llmSimulator: LlmSimulator; @@ -173,6 +174,7 @@ describe('Observability AI Assistant client', () => { knowledgeBaseServiceMock.getUserInstructions.mockResolvedValue([]); functionClientMock.getInstructions.mockReturnValue(['system']); + functionClientMock.getAdhocInstructions.mockReturnValue([]); return new ObservabilityAIAssistantClient({ actionsClient: actionsClientMock, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts index a050edc8008fb..162220ec7a7f1 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts @@ -47,12 +47,12 @@ import { } from '../../../common/conversation_complete'; import { CompatibleJSONSchema } from '../../../common/functions/types'; import { + AdHocInstruction, type Conversation, type ConversationCreateRequest, type ConversationUpdateRequest, type KnowledgeBaseEntry, type Message, - type AdHocInstruction, } from '../../../common/types'; import { withoutTokenCountEvents } from '../../../common/utils/without_token_count_events'; import { CONTEXT_FUNCTION_NAME } from '../../functions/context'; @@ -210,6 +210,9 @@ export class ObservabilityAIAssistantClient { const userInstructions$ = from(this.getKnowledgeBaseUserInstructions()).pipe(shareReplay()); + const registeredAdhocInstructions = functionClient.getAdhocInstructions(); + const allAdHocInstructions = adHocInstructions.concat(registeredAdhocInstructions); + // from the initial messages, override any system message with // the one that is based on the instructions (registered, request, kb) const messagesWithUpdatedSystemMessage$ = userInstructions$.pipe( @@ -219,7 +222,7 @@ export class ObservabilityAIAssistantClient { getSystemMessageFromInstructions({ applicationInstructions: functionClient.getInstructions(), userInstructions, - adHocInstructions, + adHocInstructions: allAdHocInstructions, availableFunctionNames: functionClient .getFunctions() .map((fn) => fn.definition.name), diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/continue_conversation.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/continue_conversation.ts index 66204c96f31cb..4c55d32362878 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/continue_conversation.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/continue_conversation.ts @@ -178,7 +178,7 @@ export function continueConversation({ chat, signal, functionCallsLeft, - adHocInstructions, + adHocInstructions = [], userInstructions, logger, disableFunctions, @@ -213,11 +213,14 @@ export function continueConversation({ disableFunctions, }); + const registeredAdhocInstructions = functionClient.getAdhocInstructions(); + const allAdHocInstructions = adHocInstructions.concat(registeredAdhocInstructions); + const messagesWithUpdatedSystemMessage = replaceSystemMessage( getSystemMessageFromInstructions({ applicationInstructions: functionClient.getInstructions(), userInstructions, - adHocInstructions, + adHocInstructions: allAdHocInstructions, availableFunctionNames: definitions.map((def) => def.name), }), initialMessages diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/types.ts index b00da8d6518fa..2df3f36163972 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/types.ts @@ -18,6 +18,7 @@ import type { Message, ObservabilityAIAssistantScreenContextRequest, InstructionOrPlainText, + AdHocInstruction, } from '../../common/types'; import type { ObservabilityAIAssistantRouteHandlerResources } from '../routes/types'; import { ChatFunctionClient } from './chat_function_client'; @@ -76,6 +77,8 @@ export type RegisterInstructionCallback = ({ export type RegisterInstruction = (...instruction: InstructionOrCallback[]) => void; +export type RegisterAdHocInstruction = (...instruction: AdHocInstruction[]) => void; + export type RegisterFunction = < TParameters extends CompatibleJSONSchema = any, TResponse extends FunctionResponse = any, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/util/get_system_message_from_instructions.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/util/get_system_message_from_instructions.ts index b2797577883ba..570449673084b 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/util/get_system_message_from_instructions.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/util/get_system_message_from_instructions.ts @@ -45,7 +45,7 @@ export function getSystemMessageFromInstructions({ const adHocInstructionsWithId = adHocInstructions.map((adHocInstruction) => ({ ...adHocInstruction, - doc_id: adHocInstruction.doc_id ?? v4(), + doc_id: adHocInstruction?.doc_id ?? v4(), })); // split ad hoc instructions into user instructions and application instructions diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json b/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json index 7c2f2212ee946..750bf69477653 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json @@ -14,7 +14,6 @@ ], "kbn_references": [ "@kbn/i18n", - "@kbn/inference-plugin", "@kbn/logging", "@kbn/kibana-utils-plugin", "@kbn/core-analytics-browser", @@ -44,9 +43,9 @@ "@kbn/serverless", "@kbn/core-elasticsearch-server", "@kbn/core-ui-settings-server", - "@kbn/inference-plugin", "@kbn/management-settings-ids", "@kbn/ai-assistant-common", + "@kbn/inference-common", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/common/convert_messages_for_inference.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/common/convert_messages_for_inference.ts index 1dc8638626d0b..7ab9516440988 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/common/convert_messages_for_inference.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/common/convert_messages_for_inference.ts @@ -10,8 +10,8 @@ import { AssistantMessage, Message as InferenceMessage, MessageRole as InferenceMessageRole, - generateFakeToolCallId, -} from '@kbn/inference-plugin/common'; +} from '@kbn/inference-common'; +import { generateFakeToolCallId } from '@kbn/inference-plugin/common'; export function convertMessagesForInference(messages: Message[]): InferenceMessage[] { const inferenceMessages: InferenceMessage[] = []; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx index 883317c02274f..b6095ac595cea 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx @@ -103,9 +103,12 @@ export function NavControl() { }; }, [service.conversations.predefinedConversation$]); - const { messages, title } = useObservable(service.conversations.predefinedConversation$) ?? { + const { messages, title, hideConversationList } = useObservable( + service.conversations.predefinedConversation$ + ) ?? { messages: [], title: undefined, + hideConversationList: false, }; const theme = useTheme(); @@ -171,6 +174,7 @@ export function NavControl() { ) ); }} + hideConversationList={hideConversationList} /> ) : undefined} diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts index 3643c54365248..210dee20339af 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts @@ -5,11 +5,8 @@ * 2.0. */ -import { - correctCommonEsqlMistakes, - isChatCompletionChunkEvent, - isOutputEvent, -} from '@kbn/inference-plugin/common'; +import { isChatCompletionChunkEvent, isOutputEvent } from '@kbn/inference-common'; +import { correctCommonEsqlMistakes } from '@kbn/inference-plugin/common'; import { naturalLanguageToEsql } from '@kbn/inference-plugin/server'; import { FunctionVisibility, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.test.ts index 479ffeaa40f4f..de02e4cf841ce 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.test.ts @@ -91,6 +91,7 @@ describe('observabilityAIAssistant rule_connector', () => { getFunctionClient: async () => ({ getFunctions: () => [], getInstructions: () => [], + getAdhocInstructions: () => [], }), }, context: { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.ts index 19f1408275e1f..59b883fef9c18 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.ts @@ -230,7 +230,7 @@ If available, include the link of the conversation at the end of your answer.` availableFunctionNames: functionClient.getFunctions().map((fn) => fn.definition.name), applicationInstructions: functionClient.getInstructions(), userInstructions: [], - adHocInstructions: [], + adHocInstructions: functionClient.getAdhocInstructions(), }), }, }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json b/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json index af04a677f5e94..6608799caaf61 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json @@ -69,6 +69,7 @@ "@kbn/cloud-plugin", "@kbn/logs-data-access-plugin", "@kbn/ai-assistant-common", + "@kbn/inference-common", ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/public/routes/main/main_route.tsx b/x-pack/plugins/observability_solution/observability_logs_explorer/public/routes/main/main_route.tsx index d1a2dc1e74439..49b25c29dad53 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/public/routes/main/main_route.tsx +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/public/routes/main/main_route.tsx @@ -21,26 +21,17 @@ import { } from '../../state_machines/observability_logs_explorer/src'; import { LazyOriginInterpreter } from '../../state_machines/origin_interpreter/src/lazy_component'; import { ObservabilityLogsExplorerHistory } from '../../types'; -import { noBreadcrumbs, useBreadcrumbs } from '../../utils/breadcrumbs'; +import { useBreadcrumbs } from '../../utils/breadcrumbs'; import { useKbnUrlStateStorageFromRouterContext } from '../../utils/kbn_url_state_context'; import { useKibanaContextForPlugin } from '../../utils/use_kibana'; export const ObservabilityLogsExplorerMainRoute = () => { const { services } = useKibanaContextForPlugin(); - const { - logsExplorer, - serverless, - chrome, - notifications, - appParams, - analytics, - i18n, - theme, - logsDataAccess, - } = services; + const { logsExplorer, notifications, appParams, analytics, i18n, theme, logsDataAccess } = + services; const { history } = appParams; - useBreadcrumbs(noBreadcrumbs, chrome, serverless); + useBreadcrumbs(); const urlStateStorageContainer = useKbnUrlStateStorageFromRouterContext(); diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/public/utils/breadcrumbs.tsx b/x-pack/plugins/observability_solution/observability_logs_explorer/public/utils/breadcrumbs.tsx index 5e84404239866..4c63476e9507d 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/public/utils/breadcrumbs.tsx +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/public/utils/breadcrumbs.tsx @@ -5,71 +5,27 @@ * 2.0. */ -import { EuiBreadcrumb } from '@elastic/eui'; -import type { ChromeStart } from '@kbn/core-chrome-browser'; -import { - LOGS_APP_ID, - OBSERVABILITY_LOGS_EXPLORER_APP_ID, - OBSERVABILITY_OVERVIEW_APP_ID, -} from '@kbn/deeplinks-observability'; +import { LOGS_APP_ID, OBSERVABILITY_LOGS_EXPLORER_APP_ID } from '@kbn/deeplinks-observability'; import { useLinkProps } from '@kbn/observability-shared-plugin/public'; -import type { ServerlessPluginStart } from '@kbn/serverless/public'; -import { useEffect } from 'react'; -import { - logsExplorerAppTitle, - logsAppTitle, - observabilityAppTitle, -} from '../../common/translations'; +import { useMemo } from 'react'; +import { useBreadcrumbs as observabilityUseBreadcrumbs } from '@kbn/observability-shared-plugin/public'; +import { logsExplorerAppTitle, logsAppTitle } from '../../common/translations'; -export const useBreadcrumbs = ( - breadcrumbs: EuiBreadcrumb[], - chromeService: ChromeStart, - serverlessService?: ServerlessPluginStart -) => { - const observabilityLinkProps = useLinkProps({ app: OBSERVABILITY_OVERVIEW_APP_ID }); +export const useBreadcrumbs = () => { const logsLinkProps = useLinkProps({ app: LOGS_APP_ID }); const logsExplorerLinkProps = useLinkProps({ app: OBSERVABILITY_LOGS_EXPLORER_APP_ID }); + const classicCrumbs = useMemo(() => { + return [ + { + text: logsAppTitle, + ...logsLinkProps, + }, + { + text: logsExplorerAppTitle, + ...logsExplorerLinkProps, + }, + ]; + }, [logsExplorerLinkProps, logsLinkProps]); - useEffect(() => { - setBreadcrumbs( - serverlessService - ? breadcrumbs - : [ - { - text: observabilityAppTitle, - ...observabilityLinkProps, - }, - { - text: logsAppTitle, - ...logsLinkProps, - }, - { - text: logsExplorerAppTitle, - ...logsExplorerLinkProps, - }, - ...breadcrumbs, - ], - chromeService, - serverlessService - ); - }, [breadcrumbs, chromeService, serverlessService]); // eslint-disable-line react-hooks/exhaustive-deps + observabilityUseBreadcrumbs(classicCrumbs, { classicOnly: true }); }; - -export function setBreadcrumbs( - breadcrumbs: EuiBreadcrumb[], - chromeService: ChromeStart, - serverlessService?: ServerlessPluginStart -) { - chromeService.docTitle.change(getDocTitle(breadcrumbs)); - if (serverlessService) { - serverlessService.setBreadcrumbs(breadcrumbs); - } else if (chromeService) { - chromeService.setBreadcrumbs(breadcrumbs); - } -} - -export function getDocTitle(breadcrumbs: EuiBreadcrumb[]) { - return breadcrumbs.map(({ text }) => text as string).reverse(); -} - -export const noBreadcrumbs: EuiBreadcrumb[] = []; diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/tsconfig.json b/x-pack/plugins/observability_solution/observability_logs_explorer/tsconfig.json index be2b3c9efdff6..5a2f18aa4249a 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/tsconfig.json @@ -13,7 +13,6 @@ "kbn_references": [ "@kbn/config-schema", "@kbn/core", - "@kbn/core-chrome-browser", "@kbn/core-mount-utils-browser-internal", "@kbn/core-notifications-browser", "@kbn/data-plugin", diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/onboarding_flow_form.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/onboarding_flow_form.tsx index 9a46cf885b285..eb5ee3bc92369 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/onboarding_flow_form.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/onboarding_flow_form.tsx @@ -316,33 +316,34 @@ export const OnboardingFlowForm: FunctionComponent = () => { flowCategory={searchParams.get('category')} />
-
- - - - - - - - card.type === 'virtual' && !card.isCollectionCard - ) - .concat(virtualSearchResults)} - excludePackageIdList={searchExcludePackageIdList} - joinCardLists - /> -
+
+ +
+ + + + + + + + card.type === 'virtual' && !card.isCollectionCard + ) + .concat(virtualSearchResults)} + excludePackageIdList={searchExcludePackageIdList} + joinCardLists + />
); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.tsx index eb359f6158030..d6a72e25a2a9d 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.tsx @@ -51,7 +51,7 @@ export function useCustomCardsForCategory( title: i18n.translate( 'xpack.observability_onboarding.useCustomCardsForCategory.autoDetectTitle', { - defaultMessage: 'Auto-detect Integrations with Elastic Agent', + defaultMessage: 'Elastic Agent: Logs & Metrics', } ), description: i18n.translate( @@ -79,7 +79,6 @@ export function useCustomCardsForCategory( version: '', integration: '', isQuickstart: true, - release: 'preview', }, { id: 'otel-logs', @@ -88,7 +87,7 @@ export function useCustomCardsForCategory( title: i18n.translate( 'xpack.observability_onboarding.useCustomCardsForCategory.logsOtelTitle', { - defaultMessage: 'Host monitoring with EDOT Collector', + defaultMessage: 'OpenTelemetry: Logs & Metrics', } ), description: i18n.translate( @@ -130,14 +129,13 @@ export function useCustomCardsForCategory( title: i18n.translate( 'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesTitle', { - defaultMessage: 'Kubernetes monitoring with Elastic Agent', + defaultMessage: 'Elastic Agent: Logs & Metrics', } ), description: i18n.translate( 'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesDescription', { - defaultMessage: - 'Monitor your Kubernetes cluster with Elastic Agent, collect container logs', + defaultMessage: 'Collect logs and metrics from Kubernetes using Elastic Agent', } ), extraLabelsBadges: [ @@ -156,7 +154,6 @@ export function useCustomCardsForCategory( version: '', integration: '', isQuickstart: true, - release: 'preview', }, { id: 'otel-kubernetes', @@ -165,14 +162,14 @@ export function useCustomCardsForCategory( title: i18n.translate( 'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesOtelTitle', { - defaultMessage: 'Kubernetes monitoring with EDOT Collector', + defaultMessage: 'OpenTelemetry: Full Observability', } ), description: i18n.translate( 'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesOtelDescription', { defaultMessage: - 'Unified Kubernetes observability with Elastic Distro for OTel Collector', + 'Collect logs, traces and metrics with the Elastic Distro for OTel Collector', } ), extraLabelsBadges: [ diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/auto_detect.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/auto_detect.tsx index 7dc3d0acb0a2e..585e1061291a5 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/auto_detect.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/auto_detect.tsx @@ -29,7 +29,6 @@ export const AutoDetectPage = () => ( 'This installation scans your host and auto-detects log and metric files.', } )} - isTechnicalPreview={true} /> } > diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/kubernetes.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/kubernetes.tsx index f92b1d9a83ac6..8e1af954736c1 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/kubernetes.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/kubernetes.tsx @@ -29,7 +29,6 @@ export const KubernetesPage = () => ( 'This installation is tailored for configuring and collecting metrics and logs by deploying a new Elastic Agent within your host.', } )} - isTechnicalPreview={true} /> } > diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx index 5d62f1060b50e..d12f0cae583f4 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx @@ -23,6 +23,7 @@ import { } from '@kbn/deeplinks-observability/locators'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; +import { ASSET_DETAILS_LOCATOR_ID } from '@kbn/observability-shared-plugin/common'; import { getAutoDetectCommand } from './get_auto_detect_command'; import { DASHBOARDS, useOnboardingFlow } from './use_onboarding_flow'; import { ProgressIndicator } from '../shared/progress_indicator'; @@ -66,6 +67,7 @@ export const AutoDetectPanel: FunctionComponent = () => { (integration) => integration.installSource === 'custom' ); const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR); + const assetDetailsLocator = share.url.locators.get(ASSET_DETAILS_LOCATOR_ID); return ( @@ -147,88 +149,133 @@ export const AutoDetectPanel: FunctionComponent = () => { installedIntegrations.length > 0 ? ( <> - {registryIntegrations.map((integration) => ( - - ) : ( - - ) - } - title={i18n.translate( - 'xpack.observability_onboarding.autoDetectPanel.h3.getStartedWithNginxLabel', - { - defaultMessage: 'Get started with {title}', - values: { title: integration.title }, - } - )} - isDisabled={status !== 'dataReceived'} - initialIsOpen - > - asset.type === 'dashboard') - .map((asset) => { - const dashboard = DASHBOARDS[asset.id as keyof typeof DASHBOARDS]; - const href = - dashboardLocator?.getRedirectUrl({ - dashboardId: asset.id, - }) ?? ''; + {registryIntegrations + .slice() + /** + * System integration should always be on top + */ + .sort((a, b) => (a.pkgName === 'system' ? -1 : 0)) + .map((integration) => { + let actionLinks; - return { - id: asset.id, - title: - dashboard.type === 'metrics' - ? i18n.translate( - 'xpack.observability_onboarding.autoDetectPanel.exploreMetricsDataTitle', - { - defaultMessage: - 'Overview your metrics data with this pre-made dashboard', - } - ) - : i18n.translate( - 'xpack.observability_onboarding.autoDetectPanel.exploreLogsDataTitle', + switch (integration.pkgName) { + case 'system': + actionLinks = + assetDetailsLocator !== undefined + ? [ + { + id: 'inventory-host-details', + title: i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.systemOverviewTitle', { defaultMessage: - 'Overview your logs data with this pre-made dashboard', + 'Overview your system health within the Hosts Inventory', } ), - label: - dashboard.type === 'metrics' - ? i18n.translate( - 'xpack.observability_onboarding.autoDetectPanel.exploreMetricsDataLabel', + label: i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.systemOverviewLabel', { defaultMessage: 'Explore metrics data', } - ) - : i18n.translate( - 'xpack.observability_onboarding.autoDetectPanel.exploreLogsDataLabel', - { - defaultMessage: 'Explore logs data', - } ), - href, - }; - })} - /> - - ))} + href: assetDetailsLocator.getRedirectUrl({ + assetType: 'host', + assetId: integration.metadata?.hostname, + }), + }, + ] + : []; + break; + default: + actionLinks = + dashboardLocator !== undefined + ? integration.kibanaAssets + .filter((asset) => asset.type === 'dashboard') + .map((asset) => { + const dashboard = + DASHBOARDS[asset.id as keyof typeof DASHBOARDS]; + const href = dashboardLocator.getRedirectUrl({ + dashboardId: asset.id, + }); + + return { + id: asset.id, + title: + dashboard.type === 'metrics' + ? i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.exploreMetricsDataTitle', + { + defaultMessage: + 'Overview your metrics data with this pre-made dashboard', + } + ) + : i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.exploreLogsDataTitle', + { + defaultMessage: + 'Overview your logs data with this pre-made dashboard', + } + ), + label: + dashboard.type === 'metrics' + ? i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.exploreMetricsDataLabel', + { + defaultMessage: 'Explore metrics data', + } + ) + : i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.exploreLogsDataLabel', + { + defaultMessage: 'Explore logs data', + } + ), + href, + }; + }) + : []; + } + + return ( + + ) : ( + + ) + } + title={i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.h3.getStartedWithNginxLabel', + { + defaultMessage: 'Get started with {title}', + values: { title: integration.title }, + } + )} + isDisabled={status !== 'dataReceived'} + initialIsOpen + > + + + ); + })} {customIntegrations.length > 0 && ( ), + doc: ( + + {i18n.translate( + 'xpack.observability_onboarding.otelKubernetesPanel.certmanagerDocsLinkLabel', + { defaultMessage: 'in our documentation' } + )} + + ), }} />{' '} @@ -213,17 +225,33 @@ helm install opentelemetry-kube-stack open-telemetry/opentelemetry-kube-stack \\ ]} /> - - {`apiVersion: v1 -kind: Pod + + {`# To annotate specific deployment Pods modify its manifest +apiVersion: apps/v1 +kind: Deployment metadata: - name: my-app - annotations: - instrumentation.opentelemetry.io/inject-${idSelected}: "${namespace}/elastic-instrumentation" + name: myapp spec: - containers: - - name: my-app - image: my-app:latest`} + ... + template: + metadata: + annotations: + instrumentation.opentelemetry.io/inject-${idSelected}: "${namespace}/elastic-instrumentation" + ... + spec: + containers: + - image: myapplication-image + name: app + ... + +# To annotate all resources in a namespace +kubectl annotate namespace my-namespace instrumentation.opentelemetry.io/inject-${idSelected}="${namespace}/elastic-instrumentation" + +# Restart your deployment +kubectl rollout restart deployment myapp -n my-namespace + +# Check annotations have been applied correctly and auto-instrumentation library is injected +kubectl describe pod -n my-namespace`} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_logs/index.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_logs/index.tsx index bb3b76556a617..4d0de71d6faaf 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_logs/index.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_logs/index.tsx @@ -30,9 +30,9 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import useAsyncFn from 'react-use/lib/useAsyncFn'; import { FormattedMessage } from '@kbn/i18n-react'; import { ObservabilityOnboardingAppServices } from '../../..'; -import { ApiKeyBanner } from '../custom_logs/api_key_banner'; import { useFetcher } from '../../../hooks/use_fetcher'; import { MultiIntegrationInstallBanner } from './multi_integration_install_banner'; +import { EmptyPrompt } from '../shared/empty_prompt'; import { FeedbackButtons } from '../shared/feedback_buttons'; const HOST_COMMAND = i18n.translate( @@ -46,11 +46,15 @@ const HOST_COMMAND = i18n.translate( export const OtelLogsPanel: React.FC = () => { const { data: apiKeyData, - status: apiKeyStatus, error, - } = useFetcher((callApi) => { - return callApi('POST /internal/observability_onboarding/otel/api_key', {}); - }, []); + refetch, + } = useFetcher( + (callApi) => { + return callApi('POST /internal/observability_onboarding/otel/api_key', {}); + }, + [], + { showToastOnError: false } + ); const { data: setup } = useFetcher((callApi) => { return callApi('GET /internal/observability_onboarding/logs/setup/environment'); @@ -116,15 +120,14 @@ rm ./otel.yml && cp ./otel_samples/platformlogs_hostmetrics.yml ./otel.yml && mk const selectedContent = installTabContents.find((tab) => tab.id === selectedTab)!; + if (error) { + return ; + } + return ( - {error && ( - - - - )} ({ type, dataset })) ?? [], kibanaAssets: pkg.installed_kibana, + metadata: integration.metadata, }; } @@ -482,7 +490,8 @@ async function ensureInstalledIntegrations( * Example input: * * ```text - * system registry + * system registry hostname + * nginx registry * product_service custom /path/to/access.log * product_service custom /path/to/error.log * checkout_service custom /path/to/access.log @@ -495,42 +504,55 @@ function parseIntegrationsTSV(tsv: string) { .trim() .split('\n') .map((line) => line.split('\t', 3)) - .reduce>( - (acc, [pkgName, installSource, logFilePath]) => { - const key = `${pkgName}-${installSource}`; - if (installSource === 'registry') { - if (logFilePath) { - throw new Error(`Integration '${pkgName}' does not support a file path`); - } - acc[key] = { - pkgName, - installSource, - }; - return acc; - } else if (installSource === 'custom') { - if (!logFilePath) { - throw new Error(`Missing file path for integration: ${pkgName}`); - } - // Append file path if integration is already in the list - const existing = acc[key]; - if (existing && existing.installSource === 'custom') { - existing.logFilePaths.push(logFilePath); - return acc; - } - acc[key] = { - pkgName, - installSource, - logFilePaths: [logFilePath], - }; + .reduce>((acc, [pkgName, installSource, parameter]) => { + const key = `${pkgName}-${installSource}`; + if (installSource === 'registry') { + const metadata = parseRegistryIntegrationMetadata(pkgName, parameter); + + acc[key] = { + pkgName, + installSource, + metadata, + }; + return acc; + } else if (installSource === 'custom') { + if (!parameter) { + throw new Error(`Missing file path for integration: ${pkgName}`); + } + // Append file path if integration is already in the list + const existing = acc[key]; + if (existing && existing.installSource === 'custom') { + existing.logFilePaths.push(parameter); return acc; } - throw new Error(`Invalid install source: ${installSource}`); - }, - {} - ) + acc[key] = { + pkgName, + installSource, + logFilePaths: [parameter], + }; + return acc; + } + throw new Error(`Invalid install source: ${installSource}`); + }, {}) ); } +function parseRegistryIntegrationMetadata( + pkgName: string, + parameter: string +): RegistryIntegrationMetadata | undefined { + switch (pkgName) { + case 'system': + if (!parameter) { + throw new Error('Missing hostname for System integration'); + } + + return { hostname: parameter }; + default: + return undefined; + } +} + const generateAgentConfigTar = ({ elasticsearchUrl, installedIntegrations, diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/route.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/route.ts index a848ea50f9d96..017925cc44dee 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/route.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/route.ts @@ -6,6 +6,7 @@ */ import * as t from 'io-ts'; +import Boom from '@hapi/boom'; import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route'; import { getFallbackESUrl } from '../../lib/get_fallback_urls'; import { getKibanaUrl } from '../../lib/get_fallback_urls'; @@ -80,6 +81,12 @@ const createAPIKeyRoute = createObservabilityOnboardingServerRoute({ const { elasticsearch: { client }, } = await context.core; + + const hasPrivileges = await hasLogMonitoringPrivileges(client.asCurrentUser); + if (!hasPrivileges) { + throw Boom.forbidden('Insufficient permissions to create shipper API key'); + } + const { encoded: apiKeyEncoded } = await createShipperApiKey(client.asCurrentUser, 'otel logs'); return { apiKeyEncoded }; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts index c9cded0805f65..4b35272eaa330 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts @@ -52,25 +52,30 @@ export interface ObservabilityOnboardingRouteCreateOptions { }; } -export const IntegrationRT = t.type({ - installSource: t.union([t.literal('registry'), t.literal('custom')]), - pkgName: t.string, - pkgVersion: t.string, - title: t.string, - config: t.string, - dataStreams: t.array( - t.type({ - type: t.string, - dataset: t.string, - }) - ), - kibanaAssets: t.array( - t.type({ - type: t.string, - id: t.string, - }) - ), -}); +export const IntegrationRT = t.intersection([ + t.type({ + installSource: t.union([t.literal('registry'), t.literal('custom')]), + pkgName: t.string, + pkgVersion: t.string, + title: t.string, + config: t.string, + dataStreams: t.array( + t.type({ + type: t.string, + dataset: t.string, + }) + ), + kibanaAssets: t.array( + t.type({ + type: t.string, + id: t.string, + }) + ), + }), + t.partial({ + metadata: t.type({ hostname: t.string }), + }), +]); export type InstalledIntegration = t.TypeOf; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/saved_objects/observability_onboarding_status.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/saved_objects/observability_onboarding_status.ts index c59bec0285266..03be370e6cf6b 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/saved_objects/observability_onboarding_status.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/saved_objects/observability_onboarding_status.ts @@ -75,6 +75,13 @@ export const InstallIntegrationsStepPayloadSchema = schema.arrayOf( id: schema.string(), }) ), + metadata: schema.maybe( + schema.oneOf([ + schema.object({ + hostname: schema.string(), + }), + ]) + ), }) ); diff --git a/x-pack/plugins/observability_solution/observability_shared/common/entity/entity_types.ts b/x-pack/plugins/observability_solution/observability_shared/common/entity/entity_types.ts index b905f542d3473..4d8be9efc59c6 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/entity/entity_types.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/entity/entity_types.ts @@ -5,7 +5,25 @@ * 2.0. */ -export enum EntityType { - HOST = 'host', - CONTAINER = 'container', -} +const createKubernetesEntity = (base: T) => ({ + ecs: `kubernetes_${base}_ecs` as const, + semconv: `kubernetes_${base}_semconv` as const, +}); + +export const ENTITY_TYPES = { + HOST: 'host', + CONTAINER: 'container', + SERVICE: 'service', + KUBERNETES: { + CLUSTER: createKubernetesEntity('cluster'), + CONTAINER: createKubernetesEntity('container'), + CRONJOB: createKubernetesEntity('cron_job'), + DAEMONSET: createKubernetesEntity('daemon_set'), + DEPLOYMENT: createKubernetesEntity('deployment'), + JOB: createKubernetesEntity('job'), + NAMESPACE: createKubernetesEntity('namespace'), + NODE: createKubernetesEntity('node'), + POD: createKubernetesEntity('pod'), + STATEFULSET: createKubernetesEntity('stateful_set'), + }, +} as const; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/entity/index.ts b/x-pack/plugins/observability_solution/observability_shared/common/entity/index.ts index 27bef43d5ff7a..adc07a2931b60 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/entity/index.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/entity/index.ts @@ -5,5 +5,5 @@ * 2.0. */ -export { EntityType } from './entity_types'; +export { ENTITY_TYPES } from './entity_types'; export { EntityDataStreamType } from './entity_data_stream_types'; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/index.ts b/x-pack/plugins/observability_solution/observability_shared/common/index.ts index e9be61e8fde34..b4b7731d166b7 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/index.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/index.ts @@ -193,6 +193,7 @@ export type { export { ServiceOverviewLocatorDefinition, + SERVICE_OVERVIEW_LOCATOR_ID, TransactionDetailsByNameLocatorDefinition, ASSET_DETAILS_FLYOUT_LOCATOR_ID, AssetDetailsFlyoutLocatorDefinition, @@ -218,4 +219,4 @@ export { export { COMMON_OBSERVABILITY_GROUPING } from './embeddable_grouping'; -export { EntityType, EntityDataStreamType } from './entity'; +export { ENTITY_TYPES, EntityDataStreamType } from './entity'; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/locators/apm/service_overview_locator.ts b/x-pack/plugins/observability_solution/observability_shared/common/locators/apm/service_overview_locator.ts index 2a4e8aac330ec..e216640f31b4f 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/locators/apm/service_overview_locator.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/locators/apm/service_overview_locator.ts @@ -16,9 +16,10 @@ export interface ServiceOverviewParams extends SerializableRecord { } export type ServiceOverviewLocator = LocatorPublic; +export const SERVICE_OVERVIEW_LOCATOR_ID = 'serviceOverviewLocator'; export class ServiceOverviewLocatorDefinition implements LocatorDefinition { - public readonly id = 'serviceOverviewLocator'; + public readonly id = SERVICE_OVERVIEW_LOCATOR_ID; public readonly getLocation = async ({ rangeFrom, diff --git a/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.test.tsx b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.test.tsx index 15849039bde8b..c166057df0304 100644 --- a/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.test.tsx @@ -11,12 +11,18 @@ import { MemoryRouter } from 'react-router-dom'; import { CoreStart } from '@kbn/core/public'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; import { useBreadcrumbs } from './use_breadcrumbs'; +import { BehaviorSubject } from 'rxjs'; +import { ChromeStyle } from '@kbn/core-chrome-browser'; const setBreadcrumbs = jest.fn(); const setTitle = jest.fn(); const kibanaServices = { application: { getUrlForApp: () => {}, navigateToApp: () => {} }, - chrome: { setBreadcrumbs, docTitle: { change: setTitle } }, + chrome: { + setBreadcrumbs, + docTitle: { change: setTitle }, + getChromeStyle$: () => new BehaviorSubject('classic').asObservable(), + }, uiSettings: { get: () => true }, settings: { client: { get: () => true } }, } as unknown as Partial; @@ -61,9 +67,15 @@ describe('useBreadcrumbs', () => { it('sets the overview breadcrumb', () => { renderHook(() => useBreadcrumbs([]), { wrapper: Wrapper }); - expect(setBreadcrumbs).toHaveBeenCalledWith([ - { href: '/overview', onClick: expect.any(Function), text: 'Observability' }, - ]); + expect(setBreadcrumbs).toHaveBeenCalledWith( + [{ href: '/overview', onClick: expect.any(Function), text: 'Observability' }], + { + project: { + absolute: true, + value: [{ href: '/overview', onClick: expect.any(Function), text: 'Observability' }], + }, + } + ); }); it('sets the overview title', () => { @@ -86,17 +98,29 @@ describe('useBreadcrumbs', () => { { wrapper: Wrapper } ); - expect(setBreadcrumbs).toHaveBeenCalledWith([ - { href: '/overview', onClick: expect.any(Function), text: 'Observability' }, + expect(setBreadcrumbs).toHaveBeenCalledWith( + [ + { href: '/overview', onClick: expect.any(Function), text: 'Observability' }, + { + href: '/one', + onClick: expect.any(Function), + text: 'One', + }, + { + text: 'Two', + }, + ], { - href: '/one', - onClick: expect.any(Function), - text: 'One', - }, - { - text: 'Two', - }, - ]); + project: { + absolute: true, + value: [ + { href: '/overview', onClick: expect.any(Function), text: 'Observability' }, + { href: '/one', onClick: expect.any(Function), text: 'One' }, + { text: 'Two' }, + ], + }, + } + ); }); it('sets the title', () => { diff --git a/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.ts b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.ts index 4137d541c4e39..5c9c0d3981bb0 100644 --- a/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.ts +++ b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_breadcrumbs.ts @@ -11,8 +11,16 @@ import { MouseEvent, useEffect, useMemo } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { ChromeBreadcrumbsAppendExtension } from '@kbn/core-chrome-browser'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import useObservable from 'react-use/lib/useObservable'; import { useQueryParams } from './use_query_params'; +const OBSERVABILITY_TEXT = i18n.translate( + 'xpack.observabilityShared.breadcrumbs.observabilityLinkText', + { + defaultMessage: 'Observability', + } +); + function addClickHandlers( breadcrumbs: ChromeBreadcrumb[], navigateToHref?: (url: string) => Promise @@ -33,23 +41,49 @@ function addClickHandlers( } function getTitleFromBreadCrumbs(breadcrumbs: ChromeBreadcrumb[]) { - return breadcrumbs.map(({ text }) => text?.toString() ?? '').reverse(); + return breadcrumbs + .map(({ text }) => text?.toString() ?? '') + .reverse() + .concat([OBSERVABILITY_TEXT]); } +/** + * + * By default the breadcrumbs will be passed to either serverless.setBreadcrumbs or chrome.setBreadcrumbs depending on the + * environment. The breadcrumbs will *also* be passed to the project style breadcrumbs for stateful project style. We will use "project style" + * here to refer to serverless chrome and stateful project style chrome. Classic refers to stateful classic chrome. + * + * Project style breadcrumbs add a root crumb ("deployment" etc) and "nav crumbs" which are derived from the navigation structure. By default + * the "absolute" mode is used which means the breadcrumbs passed here will omit the navigation derived "nav crumbs". You can pass + * absoluteProjectStyleBreadcrumbs: false to include the 'smart' "nav crumbs". + * + * In classic mode (not project style) the 'Observability' crumb is added. + * + * You can also pass classicOnly to only set breadrumbs in the classic chrome context. This can be useful if your solution just wants to defer all project style crumbs to the "nav crumbs". + */ export const useBreadcrumbs = ( extraCrumbs: ChromeBreadcrumb[], options?: { app?: { id: string; label: string }; breadcrumbsAppendExtension?: ChromeBreadcrumbsAppendExtension; serverless?: ServerlessPluginStart; + absoluteProjectStyleBreadcrumbs?: boolean; + classicOnly?: boolean; } ) => { const params = useQueryParams(); const { app, breadcrumbsAppendExtension, serverless } = options ?? {}; + const absolute = options?.absoluteProjectStyleBreadcrumbs === false ? false : true; + const classicOnly = options?.classicOnly ?? false; const { services: { - chrome: { docTitle, setBreadcrumbs: chromeSetBreadcrumbs, setBreadcrumbsAppendExtension }, + chrome: { + docTitle, + setBreadcrumbs: chromeSetBreadcrumbs, + setBreadcrumbsAppendExtension, + getChromeStyle$, + }, application: { getUrlForApp, navigateToUrl }, }, } = useKibana<{ @@ -58,11 +92,27 @@ export const useBreadcrumbs = ( }>(); const setTitle = docTitle.change; const appPath = getUrlForApp(app?.id ?? 'observability-overview') ?? ''; + const chromeStyle = useObservable(getChromeStyle$()); - const setBreadcrumbs = useMemo( - () => serverless?.setBreadcrumbs ?? chromeSetBreadcrumbs, - [serverless, chromeSetBreadcrumbs] - ); + const setBreadcrumbs = useMemo(() => { + if (!serverless?.setBreadcrumbs) { + return (breadcrumbs: ChromeBreadcrumb[]) => + chromeSetBreadcrumbs( + breadcrumbs, + !classicOnly + ? { + project: { + value: breadcrumbs, + absolute, + }, + } + : undefined + ); + } + if (!classicOnly) + return (breadcrumbs: ChromeBreadcrumb[]) => + serverless?.setBreadcrumbs(breadcrumbs, { absolute }); + }, [serverless, classicOnly, absolute, chromeSetBreadcrumbs]); useEffect(() => { if (breadcrumbsAppendExtension) { @@ -76,15 +126,12 @@ export const useBreadcrumbs = ( }, [breadcrumbsAppendExtension, setBreadcrumbsAppendExtension]); useEffect(() => { - const breadcrumbs = serverless + const isProjectStyle = serverless || chromeStyle === 'project'; + const breadcrumbs = isProjectStyle ? extraCrumbs : [ { - text: - app?.label ?? - i18n.translate('xpack.observabilityShared.breadcrumbs.observabilityLinkText', { - defaultMessage: 'Observability', - }), + text: app?.label ?? OBSERVABILITY_TEXT, href: appPath + '/overview', }, ...extraCrumbs, @@ -94,11 +141,12 @@ export const useBreadcrumbs = ( setBreadcrumbs(addClickHandlers(breadcrumbs, navigateToUrl)); } if (setTitle) { - setTitle(getTitleFromBreadCrumbs(breadcrumbs)); + setTitle(getTitleFromBreadCrumbs(extraCrumbs)); } }, [ app?.label, appPath, + chromeStyle, extraCrumbs, navigateToUrl, params, diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_overview_grid.tsx b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_overview_grid.tsx index 1ca47e02f4df3..f452f77cb1da3 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_overview_grid.tsx +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_overview_grid.tsx @@ -9,7 +9,6 @@ import React from 'react'; import { ALL_VALUE, HistoricalSummaryResponse, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { Chart, - DARK_THEME, isMetricElementEvent, Metric, MetricTrendShape, @@ -73,12 +72,18 @@ const getSloChartData = ({ }; }; +const ROW_HEIGHT = 220; +const ITEMS_PER_ROW = 4; + export function SloCardChartList({ sloId }: { sloId: string }) { const { http: { basePath }, uiSettings, + charts, } = useKibana().services; + const baseTheme = charts.theme.useChartsBaseTheme(); + const [selectedSlo, setSelectedSlo] = React.useState(null); const kqlQuery = `slo.id:"${sloId}"`; @@ -89,6 +94,7 @@ export function SloCardChartList({ sloId }: { sloId: string }) { const { data: activeAlertsBySlo } = useFetchActiveAlerts({ sloIdsAndInstanceIds: [[sloId, ALL_VALUE]], + rangeFrom: 'now-24h', }); const { data: rulesBySlo } = useFetchRulesForSlo({ @@ -151,16 +157,24 @@ export function SloCardChartList({ sloId }: { sloId: string }) { ); } + const height = sloList?.results + ? ROW_HEIGHT * Math.ceil(sloList.results.length / ITEMS_PER_ROW) + : ROW_HEIGHT; + return ( <> -
- +
+ { if (isMetricElementEvent(d)) { const { columnIndex, rowIndex } = d; - const slo = sloList?.results[rowIndex * 4 + columnIndex]; + const slo = sloList?.results[rowIndex * ITEMS_PER_ROW + columnIndex]; setSelectedSlo(slo ?? null); } }} diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts index 1f353e6a38558..6ad34d8c4dc86 100644 --- a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts @@ -20,6 +20,7 @@ type SloIdAndInstanceId = [string, string]; interface Params { sloIdsAndInstanceIds: SloIdAndInstanceId[]; shouldRefetch?: boolean; + rangeFrom?: string; } export interface UseFetchActiveAlerts { @@ -46,6 +47,7 @@ const EMPTY_ACTIVE_ALERTS_MAP = new ActiveAlerts(); export function useFetchActiveAlerts({ sloIdsAndInstanceIds = [], shouldRefetch = false, + rangeFrom = 'now-5m/m', }: Params): UseFetchActiveAlerts { const { http } = useKibana().services; @@ -63,7 +65,7 @@ export function useFetchActiveAlerts({ { range: { '@timestamp': { - gte: 'now-5m/m', + gte: rangeFrom, }, }, }, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/slo_details.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/slo_details.tsx index 26cdf62b4f7b4..9a32c150e1b8c 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/slo_details.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/slo_details.tsx @@ -40,6 +40,7 @@ export function SloDetailsPage() { application: { navigateToUrl }, http: { basePath }, observabilityAIAssistant, + serverless, } = useKibana().services; const { ObservabilityPageTemplate } = usePluginContext(); const { hasAtLeast } = useLicense(); @@ -105,7 +106,7 @@ export function SloDetailsPage() { } }, [onPageReady, slo, isLoading]); - useBreadcrumbs(getBreadcrumbs(basePath, slo)); + useBreadcrumbs(getBreadcrumbs(basePath, slo), { serverless }); const isSloNotFound = !isLoading && slo === undefined; if (isSloNotFound) { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/common/query_search_bar.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/common/query_search_bar.tsx index d238aacf1df60..394d8c303e953 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/common/query_search_bar.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/common/query_search_bar.tsx @@ -69,7 +69,7 @@ export const QuerySearchBar = memo( field.onChange(String(value?.query)); } else { field.onChange({ - ...(field.value ?? {}), + filters: field.value?.filters ?? [], kqlQuery: String(value?.query), }); } @@ -111,15 +111,27 @@ export const QuerySearchBar = memo( } onQuerySubmit={(value) => handleQueryChange(value.query, value.dateRange)} onFiltersUpdated={(filters) => { + const updatedFilters = filters.map((filter) => { + const { $state, meta, ...rest } = filter; + const query = filter?.query ? { ...filter.query } : { ...rest }; + return { + meta: { + ...meta, + alias: meta?.alias ?? JSON.stringify(query), + }, + query, + }; + }); + if (kqlQuerySchema.is(field.value)) { field.onChange({ - filters, + filters: updatedFilters, kqlQuery: field.value, }); } else { field.onChange({ - ...(field.value ?? {}), - filters, + kqlQuery: field.value?.kqlQuery ?? '', + filters: updatedFilters, }); } }} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx index aa008838a8b3c..7dcce93c0d003 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx @@ -22,6 +22,7 @@ export function SloEditPage() { const { application: { navigateToUrl }, http: { basePath }, + serverless, } = useKibana().services; const { sloId } = useParams<{ sloId: string | undefined }>(); @@ -32,32 +33,35 @@ export function SloEditPage() { const hasRightLicense = hasAtLeast('platinum'); const { data: slo } = useFetchSloDetails({ sloId }); - useBreadcrumbs([ - { - href: basePath.prepend(paths.slos), - text: i18n.translate('xpack.slo.breadcrumbs.sloLabel', { - defaultMessage: 'SLOs', - }), - deepLinkId: 'slo', - }, - ...(!!slo - ? [ - { - href: basePath.prepend(paths.sloDetails(slo!.id)), - text: slo!.name, - }, - ] - : []), - { - text: slo - ? i18n.translate('xpack.slo.breadcrumbs.sloEditLabel', { - defaultMessage: 'Edit', - }) - : i18n.translate('xpack.slo.breadcrumbs.sloCreateLabel', { - defaultMessage: 'Create', - }), - }, - ]); + useBreadcrumbs( + [ + { + href: basePath.prepend(paths.slos), + text: i18n.translate('xpack.slo.breadcrumbs.sloLabel', { + defaultMessage: 'SLOs', + }), + deepLinkId: 'slo', + }, + ...(!!slo + ? [ + { + href: basePath.prepend(paths.sloDetails(slo!.id)), + text: slo!.name, + }, + ] + : []), + { + text: slo + ? i18n.translate('xpack.slo.breadcrumbs.sloEditLabel', { + defaultMessage: 'Edit', + }) + : i18n.translate('xpack.slo.breadcrumbs.sloCreateLabel', { + defaultMessage: 'Create', + }), + }, + ], + { serverless } + ); useEffect(() => { if (hasRightLicense === false || permissions?.hasAllReadRequested === false) { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_outdated_definitions/index.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_outdated_definitions/index.tsx index a9afc480676c8..5a35061b464e5 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_outdated_definitions/index.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_outdated_definitions/index.tsx @@ -23,26 +23,30 @@ import { OutdatedSloSearchBar } from './outdated_slo_search_bar'; export function SlosOutdatedDefinitions() { const { http: { basePath }, + serverless, } = useKibana().services; const { data: permissions } = usePermissions(); const { ObservabilityPageTemplate } = usePluginContext(); const { hasAtLeast } = useLicense(); - useBreadcrumbs([ - { - href: basePath.prepend(paths.slos), - text: i18n.translate('xpack.slo.breadcrumbs.slosLinkText', { - defaultMessage: 'SLOs', - }), - deepLinkId: 'slo', - }, - { - text: i18n.translate('xpack.slo.breadcrumbs.slosOutdatedDefinitions', { - defaultMessage: 'Outdated SLO Definitions', - }), - }, - ]); + useBreadcrumbs( + [ + { + href: basePath.prepend(paths.slos), + text: i18n.translate('xpack.slo.breadcrumbs.slosLinkText', { + defaultMessage: 'SLOs', + }), + deepLinkId: 'slo', + }, + { + text: i18n.translate('xpack.slo.breadcrumbs.slosOutdatedDefinitions', { + defaultMessage: 'Outdated SLO Definitions', + }), + }, + ], + { serverless } + ); const [search, setSearch] = useState(''); const [activePage, setActivePage] = useState(0); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_settings/slo_settings.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_settings/slo_settings.tsx index d2a2da4a5fafa..ca41c7561fb46 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_settings/slo_settings.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_settings/slo_settings.tsx @@ -16,17 +16,21 @@ import { HeaderMenu } from '../../components/header_menu/header_menu'; export function SloSettingsPage() { const { http: { basePath }, + serverless, } = useKibana().services; const { ObservabilityPageTemplate } = usePluginContext(); - useBreadcrumbs([ - { - href: basePath.prepend(paths.slosSettings), - text: i18n.translate('xpack.slo.breadcrumbs.slosSettingsText', { - defaultMessage: 'SLOs Settings', - }), - }, - ]); + useBreadcrumbs( + [ + { + href: basePath.prepend(paths.slosSettings), + text: i18n.translate('xpack.slo.breadcrumbs.slosSettingsText', { + defaultMessage: 'SLOs Settings', + }), + }, + ], + { serverless } + ); return ( 0 ? 2 : 1; + return ( { @@ -57,13 +63,14 @@ export function SloCardItemBadges({ slo, activeAlerts, rules, handleCreateRule } ) : ( <> + { if ((!isLoading && total === 0) || hasAtLeast('platinum') === false || isError) { diff --git a/x-pack/plugins/observability_solution/synthetics/common/field_names.ts b/x-pack/plugins/observability_solution/synthetics/common/field_names.ts index e7f8e83d73b4b..45be741982b01 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/field_names.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/field_names.ts @@ -15,6 +15,7 @@ export const OBSERVER_NAME = 'observer.name'; export const SERVICE_NAME = 'service.name'; export const OBSERVER_GEO_NAME = 'observer.geo.name'; export const ERROR_MESSAGE = 'error.message'; +export const ERROR_STACK_TRACE = 'error.stack_trace'; export const STATE_ID = 'monitor.state.id'; export const CERT_COMMON_NAME = 'tls.server.x509.subject.common_name'; diff --git a/x-pack/plugins/observability_solution/synthetics/common/requests/get_certs_request_body.ts b/x-pack/plugins/observability_solution/synthetics/common/requests/get_certs_request_body.ts index f151192a730ed..31f389a909004 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/requests/get_certs_request_body.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/requests/get_certs_request_body.ts @@ -150,7 +150,7 @@ export const getCertsRequestBody = ({ 'service', 'labels', 'tags', - 'error.message', + 'error', ], collapse: { field: 'tls.server.hash.sha256', @@ -222,6 +222,7 @@ export const processCertsResult = (result: CertificatesResults): CertResult => { locationId: ping?.observer?.name, locationName: ping?.observer?.geo?.name, errorMessage: ping?.error?.message, + errorStackTrace: ping?.error?.stack_trace, }; }); const total = result.aggregations?.total?.value ?? 0; diff --git a/x-pack/plugins/observability_solution/synthetics/common/rules/synthetics_rule_field_map.ts b/x-pack/plugins/observability_solution/synthetics/common/rules/synthetics_rule_field_map.ts index f82f44ba2d24d..390916026668c 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/rules/synthetics_rule_field_map.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/rules/synthetics_rule_field_map.ts @@ -32,6 +32,10 @@ export const syntheticsRuleFieldMap: FieldMap = { type: 'text', required: false, }, + 'error.stack_trace': { + type: 'wildcard', + required: false, + }, 'agent.name': { type: 'keyword', required: false, diff --git a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/certs.ts b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/certs.ts index 4fe14a54c0d66..49ac5573294e1 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/certs.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/certs.ts @@ -51,6 +51,7 @@ export const CertType = t.intersection([ '@timestamp': t.string, serviceName: t.string, errorMessage: t.string, + errorStackTrace: t.union([t.string, t.null]), labels: t.record(t.string, t.string), tags: t.array(t.string), }), diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/hooks/use_get_data_stream_statuses.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/hooks/use_get_data_stream_statuses.ts index f3b3136200bd7..00d301e9eb706 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/hooks/use_get_data_stream_statuses.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/hooks/use_get_data_stream_statuses.ts @@ -94,6 +94,7 @@ function toMissingDataStream({ privileges: { delete_index: true, manage_data_stream_lifecycle: true }, hidden: false, nextGenerationManagedBy: 'Data stream lifecycle', + indexMode: 'standard', }; } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx index 14799683d96d5..d380d95c90aa4 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx @@ -38,7 +38,6 @@ export interface SyntheticsAppProps { setBadge: (badge?: ChromeBadge) => void; renderGlobalHelpControls(): void; commonlyUsedRanges: CommonlyUsedDateRange[]; - setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; appMountParameters: AppMountParameters; isDev: boolean; isServerless: boolean; @@ -89,7 +88,6 @@ export const SyntheticsSettingsContextProvider: React.FC diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx index 5e524eca31bda..c97cefc194069 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { coreMock } from '@kbn/core/public/mocks'; import { ChromeBreadcrumb } from '@kbn/core/public'; import { render } from '../utils/testing'; import React from 'react'; @@ -18,6 +19,8 @@ import { } from '../utils/url_params/get_supported_url_params'; import { makeBaseBreadcrumb, useBreadcrumbs } from './use_breadcrumbs'; import { SyntheticsSettingsContext } from '../contexts'; +import { BehaviorSubject } from 'rxjs'; +import { ChromeStyle } from '@kbn/core-chrome-browser'; describe('useBreadcrumbs', () => { it('sets the given breadcrumbs', () => { @@ -71,9 +74,10 @@ describe('useBreadcrumbs', () => { const urlParams: SyntheticsUrlParams = getSupportedUrlParams({}); expect(JSON.stringify(getBreadcrumbs())).toEqual( JSON.stringify( - makeBaseBreadcrumb('/app/synthetics', '/app/observability', urlParams, false).concat( - expectedCrumbs - ) + [ + { text: 'Observability', href: '/app/observability/overview' }, + ...makeBaseBreadcrumb('/app/synthetics', urlParams), + ].concat(expectedCrumbs) ) ); }); @@ -84,6 +88,8 @@ const mockCore: () => [() => ChromeBreadcrumb[], any] = () => { const get = () => { return breadcrumbObj; }; + const defaultCoreMock = coreMock.createStart(); + const core = { application: { getUrlForApp: (app: string) => @@ -91,6 +97,8 @@ const mockCore: () => [() => ChromeBreadcrumb[], any] = () => { navigateToUrl: jest.fn(), }, chrome: { + ...defaultCoreMock.chrome, + getChromeStyle$: () => new BehaviorSubject('classic').asObservable(), setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => { breadcrumbObj = newBreadcrumbs; }, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.ts index 6d174f773e5a1..c311b08ff22f8 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.ts @@ -7,47 +7,20 @@ import { ChromeBreadcrumb } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; -import { MouseEvent, useContext, useEffect } from 'react'; +import { useMemo } from 'react'; import { EuiBreadcrumb } from '@elastic/eui'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { useBreadcrumbs as useObservabilityBreadcrumbs } from '@kbn/observability-shared-plugin/public'; +import { ClientPluginsStart } from '../../../plugin'; import { SyntheticsUrlParams, stringifyUrlParams } from '../utils/url_params'; import { useUrlParams } from './use_url_params'; import { PLUGIN } from '../../../../common/constants/plugin'; -import { SyntheticsSettingsContext } from '../contexts'; const EMPTY_QUERY = '?'; -function handleBreadcrumbClick( - breadcrumbs: ChromeBreadcrumb[], - navigateToHref?: (url: string) => Promise -) { - return breadcrumbs.map((bc) => ({ - ...bc, - ...(bc.href - ? { - onClick: (event: MouseEvent) => { - if (navigateToHref && bc.href) { - event.preventDefault(); - navigateToHref(bc.href); - } - }, - } - : {}), - ...(bc['data-test-subj'] - ? { - 'data-test-subj': bc['data-test-subj'], - } - : { - 'data-test-subj': bc.href, - }), - })); -} - export const makeBaseBreadcrumb = ( uptimePath: string, - observabilityPath: string, - params?: SyntheticsUrlParams, - isServerless?: boolean + params?: SyntheticsUrlParams ): EuiBreadcrumb[] => { if (params) { const crumbParams: Partial = { ...params }; @@ -59,18 +32,6 @@ export const makeBaseBreadcrumb = ( const baseBreadcrumbs: EuiBreadcrumb[] = []; - // serverless Kibana has a curated UX flow, and "Observability" is already a given, - // thus we don't need to include it explicitly in the breadcrumb trail - if (!isServerless) { - baseBreadcrumbs.push({ - text: i18n.translate('xpack.synthetics.breadcrumbs.observabilityText', { - defaultMessage: 'Observability', - }), - href: observabilityPath, - 'data-test-subj': 'observabilityPathBreadcrumb', - }); - } - baseBreadcrumbs.push({ text: i18n.translate('xpack.synthetics.breadcrumbs.overviewBreadcrumbText', { defaultMessage: 'Synthetics', @@ -84,32 +45,12 @@ export const makeBaseBreadcrumb = ( export const useBreadcrumbs = (extraCrumbs: ChromeBreadcrumb[]) => { const params = useUrlParams()[0](); - const kibana = useKibana(); - const { setBreadcrumbs, isServerless } = useContext(SyntheticsSettingsContext); + const kibana = useKibana(); const syntheticsPath = kibana.services.application?.getUrlForApp(PLUGIN.SYNTHETICS_PLUGIN_ID) ?? ''; - const observabilityPath = - kibana.services.application?.getUrlForApp('observability-overview') ?? ''; - const navigate = kibana.services.application?.navigateToUrl; + const breadcrumbs = useMemo(() => { + return makeBaseBreadcrumb(syntheticsPath, params).concat(extraCrumbs); + }, [extraCrumbs, params, syntheticsPath]); - useEffect(() => { - if (setBreadcrumbs) { - setBreadcrumbs( - handleBreadcrumbClick( - makeBaseBreadcrumb(syntheticsPath, observabilityPath, params, isServerless).concat( - extraCrumbs - ), - navigate - ) - ); - } - }, [ - syntheticsPath, - observabilityPath, - extraCrumbs, - navigate, - params, - setBreadcrumbs, - isServerless, - ]); + useObservabilityBreadcrumbs(breadcrumbs, { serverless: kibana.services.serverless }); }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/render_app.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/render_app.tsx index 925f39fca7c07..19f97a6e50960 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/render_app.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/render_app.tsx @@ -66,7 +66,6 @@ export const getSyntheticsAppProps = (): SyntheticsAppProps => { setBadge, appMountParameters, isServerless, - setBreadcrumbs: startPlugins.serverless?.setBreadcrumbs ?? coreStart.chrome.setBreadcrumbs, }; }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/rtl_helpers.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/rtl_helpers.tsx index af007700c4484..93ff3de42d360 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/rtl_helpers.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/rtl_helpers.tsx @@ -7,7 +7,7 @@ import React, { ReactElement, ReactNode } from 'react'; import { i18n } from '@kbn/i18n'; -import { of } from 'rxjs'; +import { BehaviorSubject, of } from 'rxjs'; // eslint-disable-next-line import/no-extraneous-dependencies import { render as reactTestLibRender, @@ -29,6 +29,7 @@ import { KibanaContextProvider, KibanaServices } from '@kbn/kibana-react-plugin/ import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; +import { ChromeStyle } from '@kbn/core-chrome-browser'; import { mockState } from './__mocks__/synthetics_store.mock'; import { MountWithReduxProvider } from './helper_with_redux'; import { AppState } from '../../state'; @@ -166,6 +167,10 @@ export const mockCore: () => Partial = () => {
), }, + chrome: { + ...defaultCore.chrome, + getChromeStyle$: () => new BehaviorSubject('classic').asObservable(), + }, }; return core; diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/message_utils.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/message_utils.ts index 812a900667cf7..6f01e9b234bf6 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/message_utils.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/message_utils.ts @@ -24,6 +24,7 @@ import { AGENT_NAME, STATE_ID, SERVICE_NAME, + ERROR_STACK_TRACE, } from '../../../common/field_names'; import { OverviewPing } from '../../../common/runtime_types'; import { UNNAMED_LOCATION } from '../../../common/constants'; @@ -42,6 +43,8 @@ export const getMonitorAlertDocument = ( [OBSERVER_GEO_NAME]: locationNames, [OBSERVER_NAME]: locationIds, [ERROR_MESSAGE]: monitorSummary.lastErrorMessage, + // done to avoid assigning null to the field + [ERROR_STACK_TRACE]: monitorSummary.lastErrorStack ? monitorSummary.lastErrorStack : undefined, [AGENT_NAME]: monitorSummary.hostName, [ALERT_REASON]: monitorSummary.reason, [STATE_ID]: monitorSummary.stateId, @@ -114,7 +117,9 @@ export const getMonitorSummary = ({ monitorId: monitorInfo.monitor?.id, monitorName, monitorType: typeToLabelMap[monitorInfo.monitor?.type] || monitorInfo.monitor?.type, - lastErrorMessage: monitorInfo.error?.message!, + lastErrorMessage: monitorInfo.error?.message, + // done to avoid assigning null to the field + lastErrorStack: monitorInfo.error?.stack_trace ? monitorInfo.error?.stack_trace : undefined, serviceName: monitorInfo.service?.name, labels: monitorInfo.labels, locationName: formattedLocationName, diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/types.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/types.ts index 82294e55c08fc..85ae989876107 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/types.ts @@ -69,6 +69,7 @@ export interface MonitorSummaryStatusRule { }; stateId?: string; lastErrorMessage?: string; + lastErrorStack?: string | null; timestamp: string; labels?: Record; } diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/message_utils.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/message_utils.ts index 15a6f093becd9..a6a7d82fb3335 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/message_utils.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/message_utils.ts @@ -29,6 +29,7 @@ import { CERT_VALID_NOT_AFTER, CERT_VALID_NOT_BEFORE, ERROR_MESSAGE, + ERROR_STACK_TRACE, MONITOR_ID, MONITOR_NAME, MONITOR_TYPE, @@ -103,6 +104,7 @@ export const getCertSummary = (cert: Cert, expirationThreshold: number, ageThres configId: cert.configId, monitorTags: cert.tags, errorMessage: cert.errorMessage, + errorStackTrace: cert.errorStackTrace, labels: cert.labels, }; }; @@ -123,6 +125,8 @@ export const getTLSAlertDocument = (cert: Cert, monitorSummary: CertSummary, uui [OBSERVER_GEO_NAME]: monitorSummary.locationName ? [monitorSummary.locationName] : [], [OBSERVER_NAME]: monitorSummary.locationId ? [monitorSummary.locationId] : [], [ERROR_MESSAGE]: monitorSummary.errorMessage, + // done to avoid assigning null to the field + [ERROR_STACK_TRACE]: monitorSummary.errorStackTrace ? monitorSummary.errorStackTrace : undefined, 'location.id': monitorSummary.locationId ? [monitorSummary.locationId] : [], 'location.name': monitorSummary.locationName ? [monitorSummary.locationName] : [], labels: cert.labels, diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/translations.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/translations.ts index 40017b00646f1..03063f92ee56c 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/translations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/translations.ts @@ -79,6 +79,15 @@ export const commonMonitorStateI18: Array<{ } ), }, + { + name: 'lastErrorStack', + description: i18n.translate( + 'xpack.synthetics.alertRules.monitorStatus.actionVariables.state.lastErrorStack', + { + defaultMessage: 'Monitor last error stack trace.', + } + ), + }, { name: 'locationName', description: i18n.translate( diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/add_monitor_api.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/add_monitor_api.ts index b80a4f5be6825..f8c7fa9ed9b23 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/add_monitor_api.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/add_monitor_api.ts @@ -10,10 +10,10 @@ import { SavedObject } from '@kbn/core-saved-objects-common/src/server_types'; import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { isValidNamespace } from '@kbn/fleet-plugin/common'; import { i18n } from '@kbn/i18n'; +import { DeleteMonitorAPI } from '../services/delete_monitor_api'; import { parseMonitorLocations } from './utils'; import { MonitorValidationError } from '../monitor_validation'; import { getSavedObjectKqlFilter } from '../../common'; -import { deleteMonitor } from '../delete_monitor'; import { monitorAttributes, syntheticsMonitorType } from '../../../../common/types/saved_objects'; import { PrivateLocationAttributes } from '../../../runtime_types/private_locations'; import { ConfigKey } from '../../../../common/constants/monitor_management'; @@ -339,9 +339,9 @@ export class AddEditMonitorAPI { if (encryptedMonitor) { await savedObjectsClient.delete(syntheticsMonitorType, newMonitorId); - await deleteMonitor({ - routeContext: this.routeContext, - monitorId: newMonitorId, + const deleteMonitorAPI = new DeleteMonitorAPI(this.routeContext); + await deleteMonitorAPI.execute({ + monitorIds: [newMonitorId], }); } } catch (e) { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor_project.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor_project.ts index 75427a22aced2..8311a6407bf6a 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor_project.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor_project.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; +import { validateSpaceId } from './services/validate_space_id'; import { RouteContext, SyntheticsRestApiRouteFactory } from '../types'; import { ProjectMonitor } from '../../../common/runtime_types'; @@ -46,9 +47,7 @@ export const addSyntheticsProjectMonitorRoute: SyntheticsRestApiRouteFactory = ( } try { - const { id: spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { - id: DEFAULT_SPACE_ID, - }; + const spaceId = await validateSpaceId(routeContext); const permissionError = await validatePermissions(routeContext, monitors); diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/add_monitor_bulk.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/add_monitor_bulk.ts index b6a090165382b..2ecbbf83d471c 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/add_monitor_bulk.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/add_monitor_bulk.ts @@ -10,10 +10,10 @@ import { SavedObjectsBulkResponse } from '@kbn/core-saved-objects-api-server'; import { v4 as uuidV4 } from 'uuid'; import { NewPackagePolicy } from '@kbn/fleet-plugin/common'; import { SavedObjectError } from '@kbn/core-saved-objects-common'; +import { deleteMonitorBulk } from './delete_monitor_bulk'; import { SyntheticsServerSetup } from '../../../types'; import { RouteContext } from '../../types'; import { formatTelemetryEvent, sendTelemetryEvents } from '../../telemetry/monitor_upgrade_sender'; -import { deleteMonitor } from '../delete_monitor'; import { formatSecrets } from '../../../synthetics_service/utils'; import { syntheticsMonitorType } from '../../../../common/types/saved_objects'; import { @@ -24,6 +24,7 @@ import { SyntheticsMonitor, type SyntheticsPrivateLocations, } from '../../../../common/runtime_types'; +import { DeleteMonitorAPI } from '../services/delete_monitor_api'; export const createNewSavedObjectMonitorBulk = async ({ soClient, @@ -146,15 +147,10 @@ const rollBackNewMonitorBulk = async ( ) => { const { server } = routeContext; try { - await pMap( - monitorsToCreate, - async (monitor) => - deleteMonitor({ - routeContext, - monitorId: monitor.id, - }), - { concurrency: 100, stopOnError: false } - ); + const deleteMonitorAPI = new DeleteMonitorAPI(routeContext); + await deleteMonitorAPI.execute({ + monitorIds: monitorsToCreate.map(({ id }) => id), + }); } catch (e) { // ignore errors here server.logger.error(e); @@ -194,11 +190,9 @@ export const deleteMonitorIfCreated = async ({ newMonitorId ); if (encryptedMonitor) { - await savedObjectsClient.delete(syntheticsMonitorType, newMonitorId); - - await deleteMonitor({ + await deleteMonitorBulk({ + monitors: [encryptedMonitor], routeContext, - monitorId: newMonitorId, }); } } catch (e) { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts index 7df12b17b6092..9a031b3e7111a 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts @@ -4,10 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { SavedObjectsClientContract, KibanaRequest } from '@kbn/core/server'; import { SavedObject } from '@kbn/core-saved-objects-server'; -import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; -import { SyntheticsServerSetup } from '../../../types'; import { formatTelemetryDeleteEvent, sendTelemetryEvents, @@ -19,29 +16,20 @@ import { EncryptedSyntheticsMonitorAttributes, SyntheticsMonitorWithId, } from '../../../../common/runtime_types'; -import { SyntheticsMonitorClient } from '../../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; import { syntheticsMonitorType } from '../../../../common/types/saved_objects'; +import { RouteContext } from '../../types'; export const deleteMonitorBulk = async ({ - savedObjectsClient, - server, monitors, - syntheticsMonitorClient, - request, + routeContext, }: { - savedObjectsClient: SavedObjectsClientContract; - server: SyntheticsServerSetup; monitors: Array>; - syntheticsMonitorClient: SyntheticsMonitorClient; - request: KibanaRequest; + routeContext: RouteContext; }) => { + const { savedObjectsClient, server, spaceId, syntheticsMonitorClient } = routeContext; const { logger, telemetry, stackVersion } = server; try { - const { id: spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { - id: DEFAULT_SPACE_ID, - }; - const deleteSyncPromise = syntheticsMonitorClient.deleteMonitors( monitors.map((normalizedMonitor) => ({ ...normalizedMonitor.attributes, @@ -55,7 +43,7 @@ export const deleteMonitorBulk = async ({ monitors.map((monitor) => ({ type: syntheticsMonitorType, id: monitor.id })) ); - const [errors] = await Promise.all([deleteSyncPromise, deletePromises]); + const [errors, result] = await Promise.all([deleteSyncPromise, deletePromises]); monitors.forEach((monitor) => { sendTelemetryEvents( @@ -71,7 +59,7 @@ export const deleteMonitorBulk = async ({ ); }); - return errors; + return { errors, result }; } catch (e) { throw e; } diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor.ts index b7a1d0b2d48d8..f40f06f66b1ff 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor.ts @@ -5,27 +5,10 @@ * 2.0. */ import { schema } from '@kbn/config-schema'; -import { SavedObjectsClientContract, SavedObjectsErrorHelpers } from '@kbn/core/server'; -import pMap from 'p-map'; -import { validatePermissions } from './edit_monitor'; -import { SyntheticsServerSetup } from '../../types'; -import { RouteContext, SyntheticsRestApiRouteFactory } from '../types'; -import { syntheticsMonitorType } from '../../../common/types/saved_objects'; -import { - ConfigKey, - DeleteParamsResponse, - EncryptedSyntheticsMonitorAttributes, - MonitorFields, - SyntheticsMonitorWithId, - SyntheticsMonitorWithSecretsAttributes, -} from '../../../common/runtime_types'; +import { DeleteMonitorAPI } from './services/delete_monitor_api'; +import { SyntheticsRestApiRouteFactory } from '../types'; +import { DeleteParamsResponse } from '../../../common/runtime_types'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; -import { - formatTelemetryDeleteEvent, - sendErrorTelemetryEvents, - sendTelemetryEvents, -} from '../telemetry/monitor_upgrade_sender'; -import { formatSecrets, normalizeSecrets } from '../../synthetics_service/utils/secrets'; export const deleteSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory< DeleteParamsResponse[], @@ -62,7 +45,6 @@ export const deleteSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory< }); } - const result: Array<{ id: string; deleted: boolean; error?: string }> = []; const idsToDelete = [...(ids ?? []), ...(queryId ? [queryId] : [])]; if (idsToDelete.length === 0) { return response.badRequest({ @@ -70,178 +52,21 @@ export const deleteSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory< }); } - await pMap(idsToDelete, async (id) => { - try { - const { errors, res } = await deleteMonitor({ - routeContext, - monitorId: id, - }); - if (res) { - return res; - } - - if (errors && errors.length > 0) { - return response.ok({ - body: { message: 'error pushing monitor to the service', attributes: { errors } }, - }); - } + const deleteMonitorAPI = new DeleteMonitorAPI(routeContext); + try { + const { errors } = await deleteMonitorAPI.execute({ + monitorIds: idsToDelete, + }); - result.push({ id, deleted: true }); - } catch (getErr) { - if (SavedObjectsErrorHelpers.isNotFoundError(getErr)) { - result.push({ id, deleted: false, error: `Monitor id ${id} not found!` }); - } else { - throw getErr; - } + if (errors && errors.length > 0) { + return response.ok({ + body: { message: 'error pushing monitor to the service', attributes: { errors } }, + }); } - }); + } catch (getErr) { + throw getErr; + } - return result; + return deleteMonitorAPI.result; }, }); - -export const deleteMonitor = async ({ - routeContext, - monitorId, -}: { - routeContext: RouteContext; - monitorId: string; -}) => { - const { response, spaceId, savedObjectsClient, server, syntheticsMonitorClient } = routeContext; - const { logger, telemetry, stackVersion } = server; - - const { monitor, monitorWithSecret } = await getMonitorToDelete( - monitorId, - savedObjectsClient, - server, - spaceId - ); - - const err = await validatePermissions(routeContext, monitor.attributes.locations); - if (err) { - return { - res: response.forbidden({ - body: { - message: err, - }, - }), - }; - } - - let deletePromise; - - try { - deletePromise = savedObjectsClient.delete(syntheticsMonitorType, monitorId); - - const deleteSyncPromise = syntheticsMonitorClient.deleteMonitors( - [ - { - ...monitor.attributes, - id: (monitor.attributes as MonitorFields)[ConfigKey.MONITOR_QUERY_ID], - }, - /* Type cast encrypted saved objects to decrypted saved objects for delete flow only. - * Deletion does not require all monitor fields */ - ] as SyntheticsMonitorWithId[], - savedObjectsClient, - spaceId - ); - - const [errors] = await Promise.all([deleteSyncPromise, deletePromise]).catch((e) => { - server.logger.error(e); - throw e; - }); - - sendTelemetryEvents( - logger, - telemetry, - formatTelemetryDeleteEvent( - monitor, - stackVersion, - new Date().toISOString(), - Boolean((monitor.attributes as MonitorFields)[ConfigKey.SOURCE_INLINE]), - errors - ) - ); - - return { errors }; - } catch (e) { - if (deletePromise) { - await deletePromise; - } - server.logger.error( - `Unable to delete Synthetics monitor ${monitor.attributes[ConfigKey.NAME]}` - ); - - if (monitorWithSecret) { - await restoreDeletedMonitor({ - monitorId, - normalizedMonitor: formatSecrets({ - ...monitorWithSecret.attributes, - }), - savedObjectsClient, - }); - } - throw e; - } -}; - -const getMonitorToDelete = async ( - monitorId: string, - soClient: SavedObjectsClientContract, - server: SyntheticsServerSetup, - spaceId: string -) => { - const encryptedSOClient = server.encryptedSavedObjects.getClient(); - - try { - const monitor = - await encryptedSOClient.getDecryptedAsInternalUser( - syntheticsMonitorType, - monitorId, - { - namespace: spaceId, - } - ); - return { monitor: normalizeSecrets(monitor), monitorWithSecret: normalizeSecrets(monitor) }; - } catch (e) { - server.logger.error(`Failed to decrypt monitor to delete ${monitorId}${e}`); - sendErrorTelemetryEvents(server.logger, server.telemetry, { - reason: `Failed to decrypt monitor to delete ${monitorId}`, - message: e?.message, - type: 'deletionError', - code: e?.code, - status: e.status, - stackVersion: server.stackVersion, - }); - } - - const monitor = await soClient.get( - syntheticsMonitorType, - monitorId - ); - return { monitor, withSecrets: false }; -}; - -const restoreDeletedMonitor = async ({ - monitorId, - savedObjectsClient, - normalizedMonitor, -}: { - monitorId: string; - normalizedMonitor: SyntheticsMonitorWithSecretsAttributes; - savedObjectsClient: SavedObjectsClientContract; -}) => { - try { - await savedObjectsClient.get( - syntheticsMonitorType, - monitorId - ); - } catch (e) { - if (SavedObjectsErrorHelpers.isNotFoundError(e)) { - await savedObjectsClient.create(syntheticsMonitorType, normalizedMonitor, { - id: monitorId, - overwrite: true, - }); - } - } -}; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts index 2136634be7ef7..7b36780937694 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts @@ -12,6 +12,7 @@ import { ConfigKey } from '../../../common/runtime_types'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; import { getMonitors, getSavedObjectKqlFilter } from '../common'; import { deleteMonitorBulk } from './bulk_cruds/delete_monitor_bulk'; +import { validateSpaceId } from './services/validate_space_id'; export const deleteSyntheticsMonitorProjectRoute: SyntheticsRestApiRouteFactory = () => ({ method: 'DELETE', @@ -25,7 +26,7 @@ export const deleteSyntheticsMonitorProjectRoute: SyntheticsRestApiRouteFactory }), }, handler: async (routeContext): Promise => { - const { request, response, savedObjectsClient, server, syntheticsMonitorClient } = routeContext; + const { request, response } = routeContext; const { projectName } = request.params; const { monitors: monitorsToDelete } = request.body; const decodedProjectName = decodeURI(projectName); @@ -37,6 +38,8 @@ export const deleteSyntheticsMonitorProjectRoute: SyntheticsRestApiRouteFactory }); } + await validateSpaceId(routeContext); + const deleteFilter = `${syntheticsMonitorType}.attributes.${ ConfigKey.PROJECT_ID }: "${decodedProjectName}" AND ${getSavedObjectKqlFilter({ @@ -57,10 +60,7 @@ export const deleteSyntheticsMonitorProjectRoute: SyntheticsRestApiRouteFactory await deleteMonitorBulk({ monitors, - server, - savedObjectsClient, - syntheticsMonitorClient, - request, + routeContext, }); return { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/formatters/saved_object_to_monitor.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/formatters/saved_object_to_monitor.test.ts index 40aec3b468a37..18c4bf71cdfec 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/formatters/saved_object_to_monitor.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/formatters/saved_object_to_monitor.test.ts @@ -70,6 +70,9 @@ describe('mergeSourceMonitor', () => { const result = mapSavedObjectToMonitor({ monitor: { attributes: testMonitor } } as any); expect(result).toEqual({ + __ui: { + is_tls_enabled: false, + }, alert: { status: { enabled: true, @@ -78,53 +81,48 @@ describe('mergeSourceMonitor', () => { enabled: true, }, }, + 'check.request.method': 'GET', + 'check.response.status': ['404'], config_id: 'ae88f0aa-9c7d-4a5f-96dc-89d65a0ca947', custom_heartbeat_id: 'todos-lightweight-test-projects-default', enabled: true, id: 'todos-lightweight-test-projects-default', ipv4: true, ipv6: true, - locations: ['us_central', 'us_east'], - private_locations: ['pvt_us_east'], - max_redirects: 0, + locations: [ + { + geo: { + lat: 41.25, + lon: -95.86, + }, + id: 'us_central', + isServiceManaged: true, + label: 'North America - US Central', + }, + ], + max_attempts: 2, + max_redirects: '0', mode: 'any', name: 'Todos Lightweight', namespace: 'default', + origin: 'project', original_space: 'default', - proxy_url: '', + project_id: 'test-projects', + 'response.include_body': 'on_error', + 'response.include_body_max_bytes': '1024', + 'response.include_headers': true, retest_on_failure: true, revision: 21, schedule: { number: '3', unit: 'm', }, - 'service.name': '', - tags: [], + 'ssl.key': 'test-key', + 'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'], + 'ssl.verification_mode': 'full', timeout: '16', type: 'http', url: '${devUrl}', - 'url.port': null, - ssl: { - certificate: '', - certificate_authorities: '', - supported_protocols: ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'], - verification_mode: 'full', - key: 'test-key', - }, - response: { - include_body: 'on_error', - include_body_max_bytes: '1024', - include_headers: true, - }, - check: { - request: { - method: 'GET', - }, - response: { - status: ['404'], - }, - }, - params: {}, }); }); @@ -157,30 +155,12 @@ describe('mergeSourceMonitor', () => { locations: [ { geo: { - lon: -95.86, lat: 41.25, - }, - isServiceManaged: true, - id: 'us_central', - label: 'North America - US Central', - }, - { - geo: { lon: -95.86, - lat: 41.25, }, + id: 'us_central', isServiceManaged: true, - id: 'us-east4-a', - label: 'US East', - }, - { - geo: { - lon: -95.86, - lat: 41.25, - }, - isServiceManaged: false, - id: 'pvt_us_east', - label: 'US East (Private)', + label: 'North America - US Central', }, ], max_redirects: '0', @@ -249,24 +229,6 @@ const testMonitor = { id: 'us_central', label: 'North America - US Central', }, - { - geo: { - lon: -95.86, - lat: 41.25, - }, - isServiceManaged: true, - id: 'us-east4-a', - label: 'US East', - }, - { - geo: { - lon: -95.86, - lat: 41.25, - }, - isServiceManaged: false, - id: 'pvt_us_east', - label: 'US East (Private)', - }, ], namespace: 'default', origin: 'project', diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/formatters/saved_object_to_monitor.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/formatters/saved_object_to_monitor.ts index 06746fc235769..4156620abdd78 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/formatters/saved_object_to_monitor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/formatters/saved_object_to_monitor.ts @@ -7,7 +7,6 @@ import { SavedObject } from '@kbn/core/server'; import { mergeWith, omit, omitBy } from 'lodash'; -import { LocationsMap } from '../../../synthetics_service/project_monitor/normalizers/common_fields'; import { ConfigKey, EncryptedSyntheticsMonitor, @@ -22,14 +21,6 @@ const keysToOmit = [ ConfigKey.CONFIG_HASH, ConfigKey.JOURNEY_ID, ConfigKey.FORM_MONITOR_TYPE, - ConfigKey.MAX_ATTEMPTS, - ConfigKey.MONITOR_SOURCE_TYPE, - ConfigKey.METADATA, - ConfigKey.SOURCE_PROJECT_CONTENT, - ConfigKey.PROJECT_ID, - ConfigKey.JOURNEY_FILTERS_MATCH, - ConfigKey.JOURNEY_FILTERS_TAGS, - ConfigKey.MONITOR_SOURCE_TYPE, ]; type Result = MonitorFieldsResult & { @@ -39,14 +30,25 @@ type Result = MonitorFieldsResult & { ssl: Record; response: Record; check: Record; - locations: string[]; - private_locations: string[]; }; export const transformPublicKeys = (result: Result) => { + if (result[ConfigKey.SOURCE_INLINE]) { + result.inline_script = result[ConfigKey.SOURCE_INLINE]; + } + if (result[ConfigKey.HOSTS]) { + result.host = result[ConfigKey.HOSTS]; + } + if (result[ConfigKey.PARAMS]) { + try { + result[ConfigKey.PARAMS] = JSON.parse(result[ConfigKey.PARAMS] ?? '{}'); + } catch (e) { + // ignore + } + } + let formattedResult = { ...result, - ...formatLocations(result), [ConfigKey.PARAMS]: formatParams(result), retest_on_failure: (result[ConfigKey.MAX_ATTEMPTS] ?? 1) > 1, ...(result[ConfigKey.HOSTS] && { host: result[ConfigKey.HOSTS] }), @@ -58,20 +60,8 @@ export const transformPublicKeys = (result: Result) => { ...(result[ConfigKey.SOURCE_INLINE] && { inline_script: result[ConfigKey.SOURCE_INLINE] }), [ConfigKey.PLAYWRIGHT_OPTIONS]: formatPWOptions(result), }; - } else { - formattedResult.ssl = formatNestedFields(formattedResult, 'ssl'); - formattedResult.response = formatNestedFields(formattedResult, 'response'); - formattedResult.check = formatNestedFields(formattedResult, 'check'); - if (formattedResult[ConfigKey.MAX_REDIRECTS]) { - formattedResult[ConfigKey.MAX_REDIRECTS] = Number(formattedResult[ConfigKey.MAX_REDIRECTS]); - } } - const res = omit(formattedResult, keysToOmit) as Result; - - return omitBy( - res, - (_, key) => key.startsWith('response.') || key.startsWith('ssl.') || key.startsWith('check.') - ); + return omit(formattedResult, keysToOmit) as Result; }; export function mapSavedObjectToMonitor({ @@ -81,7 +71,7 @@ export function mapSavedObjectToMonitor({ monitor: SavedObject; internal?: boolean; }) { - const result = { + let result = { ...monitor.attributes, created_at: monitor.created_at, updated_at: monitor.updated_at, @@ -89,7 +79,9 @@ export function mapSavedObjectToMonitor({ if (internal) { return result; } - return transformPublicKeys(result); + result = transformPublicKeys(result); + // omit undefined value or null value + return omitBy(result, removeMonitorEmptyValues); } export function mergeSourceMonitor( normalizedPreviousMonitor: EncryptedSyntheticsMonitor, @@ -108,24 +100,6 @@ const customizer = (destVal: any, srcValue: any, key: string) => { } }; -const formatLocations = (config: MonitorFields) => { - const locMap = Object.entries(LocationsMap); - const locations = config[ConfigKey.LOCATIONS] - ?.filter((location) => location.isServiceManaged) - .map((location) => { - return locMap.find(([_key, value]) => value === location.id)?.[0] ?? location.id; - }); - - const privateLocations = config[ConfigKey.LOCATIONS] - ?.filter((location) => !location.isServiceManaged) - .map((location) => location.id); - - return { - ...(locations && { locations }), - ...(privateLocations && { private_locations: privateLocations }), - }; -}; - const formatParams = (config: MonitorFields) => { if (config[ConfigKey.PARAMS]) { try { @@ -177,3 +151,17 @@ const formatNestedFields = ( return obj; }; + +export const removeMonitorEmptyValues = (v: any) => { + // value is falsy + return ( + v === undefined || + v === null || + // value is empty string + (typeof v === 'string' && v.trim() === '') || + // is empty array + (Array.isArray(v) && v.length === 0) || + // object is has no values + (typeof v === 'object' && Object.keys(v).length === 0) + ); +}; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/delete_monitor_api.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/delete_monitor_api.ts new file mode 100644 index 0000000000000..bd162fc043592 --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/delete_monitor_api.ts @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import pMap from 'p-map'; +import { SavedObject, SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server'; +import { deleteMonitorBulk } from '../bulk_cruds/delete_monitor_bulk'; +import { validatePermissions } from '../edit_monitor'; +import { + EncryptedSyntheticsMonitorAttributes, + SyntheticsMonitor, + SyntheticsMonitorWithSecretsAttributes, +} from '../../../../common/runtime_types'; +import { syntheticsMonitorType } from '../../../../common/types/saved_objects'; +import { normalizeSecrets } from '../../../synthetics_service/utils'; +import { sendErrorTelemetryEvents } from '../../telemetry/monitor_upgrade_sender'; +import { RouteContext } from '../../types'; + +export class DeleteMonitorAPI { + routeContext: RouteContext; + result: Array<{ id: string; deleted: boolean; error?: string }> = []; + constructor(routeContext: RouteContext) { + this.routeContext = routeContext; + } + + async getMonitorsToDelete(monitorIds: string[]) { + const result: Array> = []; + await pMap( + monitorIds, + async (monitorId) => { + const monitor = await this.getMonitorToDelete(monitorId); + if (monitor) { + result.push(monitor); + } + }, + { + stopOnError: false, + } + ); + return result; + } + + async getMonitorToDelete(monitorId: string) { + const { spaceId, savedObjectsClient, server } = this.routeContext; + try { + const encryptedSOClient = server.encryptedSavedObjects.getClient(); + + const monitor = + await encryptedSOClient.getDecryptedAsInternalUser( + syntheticsMonitorType, + monitorId, + { + namespace: spaceId, + } + ); + return normalizeSecrets(monitor); + } catch (e) { + if (SavedObjectsErrorHelpers.isNotFoundError(e)) { + this.result.push({ + id: monitorId, + deleted: false, + error: `Monitor id ${monitorId} not found!`, + }); + } else { + server.logger.error(`Failed to decrypt monitor to delete ${monitorId}${e}`); + sendErrorTelemetryEvents(server.logger, server.telemetry, { + reason: `Failed to decrypt monitor to delete ${monitorId}`, + message: e?.message, + type: 'deletionError', + code: e?.code, + status: e.status, + stackVersion: server.stackVersion, + }); + return await savedObjectsClient.get( + syntheticsMonitorType, + monitorId + ); + } + } + } + + async execute({ monitorIds }: { monitorIds: string[] }) { + const { response, server } = this.routeContext; + + const monitors = await this.getMonitorsToDelete(monitorIds); + for (const monitor of monitors) { + const err = await validatePermissions(this.routeContext, monitor.attributes.locations); + if (err) { + return { + res: response.forbidden({ + body: { + message: err, + }, + }), + }; + } + } + + try { + const { errors, result } = await deleteMonitorBulk({ + monitors, + routeContext: this.routeContext, + }); + + result.statuses?.forEach((res) => { + this.result.push({ + id: res.id, + deleted: res.success, + }); + }); + + return { errors }; + } catch (e) { + server.logger.error(`Unable to delete Synthetics monitor with error ${e.message}`); + server.logger.error(e); + throw e; + } + } +} diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/validate_space_id.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/validate_space_id.ts new file mode 100644 index 0000000000000..9f456efc3f5b1 --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/validate_space_id.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; +import { RouteContext } from '../../types'; + +export const validateSpaceId = async (routeContext: RouteContext) => { + const { server, request, spaceId } = routeContext; + // If the spaceId is the default space, return it, it always exists + if (spaceId === DEFAULT_SPACE_ID) { + return spaceId; + } + const { id } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { + id: DEFAULT_SPACE_ID, + }; + return id; +}; diff --git a/x-pack/plugins/observability_solution/synthetics/tsconfig.json b/x-pack/plugins/observability_solution/synthetics/tsconfig.json index 24411ebdcb0c5..5df6d4257b4e9 100644 --- a/x-pack/plugins/observability_solution/synthetics/tsconfig.json +++ b/x-pack/plugins/observability_solution/synthetics/tsconfig.json @@ -104,7 +104,8 @@ "@kbn/babel-register", "@kbn/slo-plugin", "@kbn/ebt-tools", - "@kbn/alerting-types" + "@kbn/alerting-types", + "@kbn/core-chrome-browser" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/uptime/common/rules/uptime_rule_field_map.ts b/x-pack/plugins/observability_solution/uptime/common/rules/uptime_rule_field_map.ts index 6e0f73e183462..c157177b585ba 100644 --- a/x-pack/plugins/observability_solution/uptime/common/rules/uptime_rule_field_map.ts +++ b/x-pack/plugins/observability_solution/uptime/common/rules/uptime_rule_field_map.ts @@ -32,6 +32,10 @@ export const uptimeRuleFieldMap: FieldMap = { type: 'text', required: false, }, + 'error.stack_trace': { + type: 'wildcard', + required: false, + }, 'agent.name': { type: 'keyword', required: false, diff --git a/x-pack/plugins/observability_solution/ux/public/application/application.test.tsx b/x-pack/plugins/observability_solution/ux/public/application/application.test.tsx index ef9c7df0a1a8d..2b9dd676eac17 100644 --- a/x-pack/plugins/observability_solution/ux/public/application/application.test.tsx +++ b/x-pack/plugins/observability_solution/ux/public/application/application.test.tsx @@ -17,6 +17,8 @@ import { coreMock } from '@kbn/core/public/mocks'; import { merge } from 'lodash'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; +import { BehaviorSubject } from 'rxjs'; +import { ChromeStyle } from '@kbn/core-chrome-browser'; jest.mock('../services/rest/data_view', () => ({ createStaticDataView: () => Promise.resolve(undefined), @@ -122,6 +124,10 @@ const mockCore = merge({}, coreStart, { return uiSettings[key]; }, }, + chrome: { + ...coreStart.chrome, + getChromeStyle$: () => new BehaviorSubject('classic').asObservable(), + }, }); export const mockApmPluginContextValue = { diff --git a/x-pack/plugins/observability_solution/ux/tsconfig.json b/x-pack/plugins/observability_solution/ux/tsconfig.json index 94da70641f150..b27a700aa9b1f 100644 --- a/x-pack/plugins/observability_solution/ux/tsconfig.json +++ b/x-pack/plugins/observability_solution/ux/tsconfig.json @@ -49,7 +49,8 @@ "@kbn/react-kibana-context-render", "@kbn/react-kibana-context-theme", "@kbn/search-types", - "@kbn/server-route-repository-utils" + "@kbn/server-route-repository-utils", + "@kbn/core-chrome-browser" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_automated_action_results.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_automated_action_results.cy.ts index 1bc058b188fcc..cd36950ba3b60 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_automated_action_results.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_automated_action_results.cy.ts @@ -11,7 +11,8 @@ import { checkActionItemsInResults, loadRuleAlerts } from '../../tasks/live_quer const UUID_REGEX = '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}'; -// FLAKY: https://github.com/elastic/kibana/issues/169727 +// FLAKY: https://github.com/elastic/kibana/issues/178404 +// FLAKY: https://github.com/elastic/kibana/issues/197335 describe.skip('Alert Flyout Automated Action Results', () => { let ruleId: string; diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts index 2dbd905b4df93..1817a81e46821 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts @@ -49,8 +49,7 @@ describe.skip('Alert Event Details - Cases', { tags: ['@ess', '@serverless'] }, cleanupRule(ruleId); }); - // FLAKY: https://github.com/elastic/kibana/issues/197151 - describe.skip('Case creation', () => { + describe('Case creation', () => { let caseId: string; before(() => { @@ -86,8 +85,7 @@ describe.skip('Alert Event Details - Cases', { tags: ['@ess', '@serverless'] }, }); }); - // FLAKY: https://github.com/elastic/kibana/issues/176783 - describe.skip('Case', () => { + describe('Case', () => { let caseId: string; beforeEach(() => { diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts index f7585d32a2bba..2b04a99bd4f9c 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts @@ -18,9 +18,7 @@ import { import { closeModalIfVisible, closeToastIfVisible } from '../../tasks/integrations'; import { RESULTS_TABLE, RESULTS_TABLE_BUTTON } from '../../screens/live_query'; -// Failing: See https://github.com/elastic/kibana/issues/181889 -// Failing: See https://github.com/elastic/kibana/issues/181889 -describe.skip( +describe( 'Alert Event Details', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'], diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts index 4f6d30dd71431..95f0d947b8e84 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts @@ -15,8 +15,7 @@ import { } from '../../tasks/live_query'; import { OSQUERY_FLYOUT_BODY_EDITOR } from '../../screens/live_query'; -// FLAKY: https://github.com/elastic/kibana/issues/170157 -describe.skip( +describe( 'Alert Event Details - dynamic params', { tags: ['@ess', '@serverless'], diff --git a/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts index 89881c47083fd..4bafc3d173156 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts @@ -18,8 +18,7 @@ import { typeInOsqueryFieldInput, } from '../../tasks/live_query'; -// Failing: See https://github.com/elastic/kibana/issues/192128 -describe.skip('EcsMapping', { tags: ['@ess', '@serverless'] }, () => { +describe('EcsMapping', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { beforeEach(() => { initializeDataViews(); }); diff --git a/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts b/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts index b332951b1a444..2eaf015f23220 100644 --- a/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { waitForAlertsToPopulate } from '@kbn/test-suites-xpack/security_solution_cypress/cypress/tasks/create_new_rule'; import { disableNewFeaturesTours } from '../../tasks/navigation'; import { initializeDataViews } from '../../tasks/login'; import { checkResults, clickRuleName, submitQuery } from '../../tasks/live_query'; @@ -31,9 +32,8 @@ describe('Alert Test', { tags: ['@ess'] }, () => { onBeforeLoad: (win) => disableNewFeaturesTours(win), }); clickRuleName(ruleName); - cy.getBySel('expand-event').first().click({ force: true }); - - cy.wait(500); + waitForAlertsToPopulate(); + cy.getBySel('expand-event').first().click(); cy.getBySel('securitySolutionFlyoutInvestigationGuideButton').click(); cy.contains('Get processes').click(); }); diff --git a/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts b/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts index 2b0db52f45699..4aa2879883b38 100644 --- a/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts +++ b/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts @@ -231,7 +231,7 @@ export const loadRule = (includeResponseActions = false) => { tags: [], license: '', interval: '1m', - from: 'now-120s', + from: 'now-360s', to: 'now', meta: { from: '1m', kibana_siem_app_url: 'http://localhost:5620/app/security' }, actions: [], diff --git a/x-pack/plugins/osquery/cypress/tasks/live_query.ts b/x-pack/plugins/osquery/cypress/tasks/live_query.ts index c8ef188010130..910427272c5ff 100644 --- a/x-pack/plugins/osquery/cypress/tasks/live_query.ts +++ b/x-pack/plugins/osquery/cypress/tasks/live_query.ts @@ -58,7 +58,7 @@ export const verifyQueryTimeout = (timeout: string) => { // sometimes the results get stuck in the tests, this is a workaround export const checkResults = () => { - cy.getBySel('osqueryResultsTable').then(($table) => { + cy.getBySel('osqueryResultsTable', { timeout: 120000 }).then(($table) => { if ($table.find('div .euiDataGridRow').length > 0) { cy.getBySel('dataGridRowCell', { timeout: 120000 }).should('have.lengthOf.above', 0); } else { @@ -158,6 +158,7 @@ export const checkActionItemsInResults = ({ cases: boolean; timeline: boolean; }) => { + checkResults(); cy.contains('View in Discover').should(discover ? 'exist' : 'not.exist'); cy.contains('View in Lens').should(lens ? 'exist' : 'not.exist'); cy.contains('Add to Case').should(cases ? 'exist' : 'not.exist'); diff --git a/x-pack/plugins/osquery/server/routes/fleet_wrapper/get_agent_policies.ts b/x-pack/plugins/osquery/server/routes/fleet_wrapper/get_agent_policies.ts index 9e84410712506..64b10f0a8248e 100644 --- a/x-pack/plugins/osquery/server/routes/fleet_wrapper/get_agent_policies.ts +++ b/x-pack/plugins/osquery/server/routes/fleet_wrapper/get_agent_policies.ts @@ -59,7 +59,7 @@ export const getAgentPoliciesRoute = (router: IRouter, osqueryContext: OsqueryAp (agentPolicy: GetAgentPoliciesResponseItem) => agentService?.asInternalUser .getAgentStatusForAgentPolicy(agentPolicy.id) - .then(({ total: agentTotal }) => (agentPolicy.agents = agentTotal)), + .then(({ active: agentTotal }) => (agentPolicy.agents = agentTotal)), { concurrency: 10 } ); } diff --git a/x-pack/plugins/rule_registry/server/index.ts b/x-pack/plugins/rule_registry/server/index.ts index 826d0d6f23bab..de0685b8c9617 100644 --- a/x-pack/plugins/rule_registry/server/index.ts +++ b/x-pack/plugins/rule_registry/server/index.ts @@ -25,13 +25,6 @@ export * from './rule_data_plugin_service'; export * from './rule_data_client'; export * from './alert_data_client/audit_events'; -export { createLifecycleRuleTypeFactory } from './utils/create_lifecycle_rule_type_factory'; -export type { - LifecycleRuleExecutor, - LifecycleAlertService, - LifecycleAlertServices, -} from './utils/create_lifecycle_executor'; -export { createLifecycleExecutor } from './utils/create_lifecycle_executor'; export { createPersistenceRuleTypeWrapper } from './utils/create_persistence_rule_type_wrapper'; export * from './utils/persistence_types'; export type { AlertsClient } from './alert_data_client/alerts_client'; diff --git a/x-pack/plugins/rule_registry/server/mocks.ts b/x-pack/plugins/rule_registry/server/mocks.ts index 7ab1391ca1dec..ef5ae00ca0c56 100644 --- a/x-pack/plugins/rule_registry/server/mocks.ts +++ b/x-pack/plugins/rule_registry/server/mocks.ts @@ -11,10 +11,8 @@ import { ruleDataServiceMock, RuleDataServiceMock, } from './rule_data_plugin_service/rule_data_plugin_service.mock'; -import { createLifecycleAlertServicesMock } from './utils/lifecycle_alert_services.mock'; export const ruleRegistryMocks = { - createLifecycleAlertServices: createLifecycleAlertServicesMock, createRuleDataService: ruleDataServiceMock.create, createRuleDataClient: createRuleDataClientMock, createAlertsClientMock: alertsClientMock, diff --git a/x-pack/plugins/rule_registry/server/plugin.ts b/x-pack/plugins/rule_registry/server/plugin.ts index 7f6b6e0bf6002..60ee2256ae377 100644 --- a/x-pack/plugins/rule_registry/server/plugin.ts +++ b/x-pack/plugins/rule_registry/server/plugin.ts @@ -29,7 +29,6 @@ import type { PluginSetup as DataPluginSetup, } from '@kbn/data-plugin/server'; -import { createLifecycleRuleTypeFactory } from './utils/create_lifecycle_rule_type_factory'; import type { RuleRegistryPluginConfig } from './config'; import { type IRuleDataService, RuleDataService, Dataset } from './rule_data_plugin_service'; import { AlertsClientFactory } from './alert_data_client/alerts_client_factory'; @@ -52,7 +51,6 @@ export interface RuleRegistryPluginStartDependencies { export interface RuleRegistryPluginSetupContract { ruleDataService: IRuleDataService; - createLifecycleRuleTypeFactory: typeof createLifecycleRuleTypeFactory; dataset: typeof Dataset; } @@ -153,7 +151,6 @@ export class RuleRegistryPlugin return { ruleDataService: this.ruleDataService, - createLifecycleRuleTypeFactory, dataset: Dataset, }; } diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts deleted file mode 100644 index b895c49c14a5f..0000000000000 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts +++ /dev/null @@ -1,2408 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { loggerMock } from '@kbn/logging-mocks'; -import { pick } from 'lodash'; -import { - ALERT_INSTANCE_ID, - ALERT_MAINTENANCE_WINDOW_IDS, - ALERT_RULE_CATEGORY, - ALERT_RULE_CONSUMER, - ALERT_RULE_NAME, - ALERT_RULE_PRODUCER, - ALERT_RULE_TYPE_ID, - ALERT_RULE_UUID, - ALERT_STATUS, - ALERT_STATUS_ACTIVE, - ALERT_STATUS_RECOVERED, - ALERT_WORKFLOW_STATUS, - ALERT_UUID, - EVENT_ACTION, - EVENT_KIND, - SPACE_IDS, - ALERT_FLAPPING, - TAGS, - ALERT_CONSECUTIVE_MATCHES, -} from '../../common/technical_rule_data_field_names'; -import { createRuleDataClientMock } from '../rule_data_client/rule_data_client.mock'; -import { createLifecycleExecutor } from './create_lifecycle_executor'; -import { createDefaultAlertExecutorOptions } from './rule_executor.test_helpers'; - -describe('createLifecycleExecutor', () => { - it('wraps and unwraps the original executor state', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - // @ts-ignore 4.3.5 upgrade - Expression produces a union type that is too complex to represent.ts(2590) - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async (options) => { - expect(options.state).toEqual(initialRuleState); - - const nextRuleState: TestRuleState = { - aRuleStateKey: 'NEXT_RULE_STATE_VALUE', - }; - - return { state: nextRuleState }; - }); - - const newExecutorResult = await executor( - createDefaultAlertExecutorOptions({ - params: {}, - state: { wrapped: initialRuleState, trackedAlerts: {}, trackedAlertsRecovered: {} }, - logger, - }) - ); - - expect(newExecutorResult.state).toEqual({ - wrapped: { - aRuleStateKey: 'NEXT_RULE_STATE_VALUE', - }, - trackedAlerts: {}, - trackedAlertsRecovered: {}, - }); - }); - - it('writes initial documents for newly firing alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: { [TAGS]: ['source-tag1', 'source-tag2'] }, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: { [TAGS]: ['source-tag3', 'source-tag4'] }, - }); - - return { state }; - }); - - await executor( - createDefaultAlertExecutorOptions({ - params: {}, - state: { wrapped: initialRuleState, trackedAlerts: {}, trackedAlertsRecovered: {} }, - logger, - }) - ); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: [ - // alert documents - { create: { _id: expect.any(String) } }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'open', - [EVENT_KIND]: 'signal', - [TAGS]: ['source-tag1', 'source-tag2', 'rule-tag1', 'rule-tag2'], - }), - { create: { _id: expect.any(String) } }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'open', - [EVENT_KIND]: 'signal', - [TAGS]: ['source-tag3', 'source-tag4', 'rule-tag1', 'rule-tag2'], - }), - ], - }) - ); - expect((await ruleDataClientMock.getWriter()).bulk).not.toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // evaluation documents - { create: {} }, - expect.objectContaining({ - [EVENT_KIND]: 'event', - }), - ]), - }) - ); - }); - - it('updates existing documents for repeatedly firing alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'closed', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 1, - _primary_term: 3, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: [ - // alert document - { - index: { - _id: 'TEST_ALERT_0_UUID', - _index: '.alerts-index-name', - if_primary_term: 2, - if_seq_no: 4, - require_alias: false, - }, - }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_WORKFLOW_STATUS]: 'closed', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, - - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - }), - { - index: { - _id: 'TEST_ALERT_1_UUID', - _index: '.alerts-index-name', - if_primary_term: 3, - if_seq_no: 1, - require_alias: false, - }, - }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - }), - ], - }) - ); - expect((await ruleDataClientMock.getWriter()).bulk).not.toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // evaluation documents - { index: {} }, - expect.objectContaining({ - [EVENT_KIND]: 'event', - }), - ]), - }) - ); - }); - - it('logs warning if existing documents are in unexpected index', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'closed', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc - }, - _index: 'partial-.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 1, - _primary_term: 3, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: [ - // alert document - { - index: { - _id: 'TEST_ALERT_1_UUID', - _index: '.alerts-index-name', - if_primary_term: 3, - if_seq_no: 1, - require_alias: false, - }, - }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - }), - ], - }) - ); - expect((await ruleDataClientMock.getWriter()).bulk).not.toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // evaluation documents - { index: {} }, - expect.objectContaining({ - [EVENT_KIND]: 'event', - }), - ]), - }) - ); - expect(logger.warn).toHaveBeenCalledWith( - `Could not update alert TEST_ALERT_0 in partial-.alerts-index-name. Partial and restored alert indices are not supported.` - ); - }); - - it('updates existing documents for recovered alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc - [TAGS]: ['source-tag1', 'source-tag2'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc - [TAGS]: ['source-tag3', 'source-tag4'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - // TEST_ALERT_0 has recovered - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // alert document - { index: expect.objectContaining({ _id: 'TEST_ALERT_0_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_STATUS]: ALERT_STATUS_RECOVERED, - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, - [TAGS]: ['source-tag1', 'source-tag2', 'rule-tag1', 'rule-tag2'], - [EVENT_ACTION]: 'close', - [EVENT_KIND]: 'signal', - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_1_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - [TAGS]: ['source-tag3', 'source-tag4', 'rule-tag1', 'rule-tag2'], - }), - ]), - }) - ); - expect((await ruleDataClientMock.getWriter()).bulk).not.toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // evaluation documents - { index: {} }, - expect.objectContaining({ - [EVENT_KIND]: 'event', - }), - ]), - }) - ); - }); - - it('does not write alert documents when rule execution is cancelled and feature flags indicate to skip', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async (options) => { - expect(options.state).toEqual(initialRuleState); - - const nextRuleState: TestRuleState = { - aRuleStateKey: 'NEXT_RULE_STATE_VALUE', - }; - - return { state: nextRuleState }; - }); - - await executor( - createDefaultAlertExecutorOptions({ - params: {}, - state: { wrapped: initialRuleState, trackedAlerts: {}, trackedAlertsRecovered: {} }, - shouldWriteAlerts: false, - logger, - }) - ); - - expect((await ruleDataClientMock.getWriter()).bulk).not.toHaveBeenCalled(); - }); - - it('throws error when writer initialization fails', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getWriter = jest - .fn() - .mockRejectedValueOnce(new Error('error initializing!')); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async (options) => { - const nextRuleState: TestRuleState = { - aRuleStateKey: 'NEXT_RULE_STATE_VALUE', - }; - - return { state: nextRuleState }; - }); - - await expect(() => - executor( - createDefaultAlertExecutorOptions({ - params: {}, - state: { wrapped: initialRuleState, trackedAlerts: {}, trackedAlertsRecovered: {} }, - shouldWriteAlerts: false, - logger, - }) - ) - ).rejects.toThrowErrorMatchingInlineSnapshot(`"error initializing!"`); - }); - - describe('updating flappingHistory', () => { - it('sets flapping state to true on a new alert', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - const { - state: { trackedAlerts, trackedAlertsRecovered }, - } = await executor( - createDefaultAlertExecutorOptions({ - params: {}, - state: { wrapped: initialRuleState, trackedAlerts: {}, trackedAlertsRecovered: {} }, - logger, - }) - ); - - const alerts = pick(trackedAlerts, [ - 'TEST_ALERT_0.flappingHistory', - 'TEST_ALERT_1.flappingHistory', - ]); - expect(alerts).toMatchInlineSnapshot(` - Object { - "TEST_ALERT_0": Object { - "flappingHistory": Array [ - true, - ], - }, - "TEST_ALERT_1": Object { - "flappingHistory": Array [ - true, - ], - }, - } - `); - expect(trackedAlertsRecovered).toMatchInlineSnapshot(`Object {}`); - }); - - it('sets flapping state to false on an alert that is still active', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'closed', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - const { - state: { trackedAlerts, trackedAlertsRecovered }, - } = await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - const alerts = pick(trackedAlerts, [ - 'TEST_ALERT_0.flappingHistory', - 'TEST_ALERT_1.flappingHistory', - ]); - expect(alerts).toMatchInlineSnapshot(` - Object { - "TEST_ALERT_0": Object { - "flappingHistory": Array [ - false, - ], - }, - "TEST_ALERT_1": Object { - "flappingHistory": Array [ - false, - ], - }, - } - `); - expect(trackedAlertsRecovered).toMatchInlineSnapshot(`Object {}`); - }); - - it('sets flapping state to true on an alert that is active and previously recovered', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'closed', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - const { - state: { trackedAlerts, trackedAlertsRecovered }, - } = await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlertsRecovered: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlerts: {}, - }, - logger, - }) - ); - - const alerts = pick(trackedAlerts, [ - 'TEST_ALERT_0.flappingHistory', - 'TEST_ALERT_1.flappingHistory', - ]); - expect(alerts).toMatchInlineSnapshot(` - Object { - "TEST_ALERT_0": Object { - "flappingHistory": Array [ - true, - ], - }, - "TEST_ALERT_1": Object { - "flappingHistory": Array [ - true, - ], - }, - } - `); - expect(trackedAlertsRecovered).toMatchInlineSnapshot(`Object {}`); - }); - - it('sets flapping state to true on an alert that is recovered and previously active', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - // TEST_ALERT_0 has recovered - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - const { - state: { trackedAlerts, trackedAlertsRecovered }, - } = await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - const recovered = pick(trackedAlertsRecovered, ['TEST_ALERT_0.flappingHistory']); - expect(recovered).toMatchInlineSnapshot(` - Object { - "TEST_ALERT_0": Object { - "flappingHistory": Array [ - true, - ], - }, - } - `); - const active = pick(trackedAlerts, ['TEST_ALERT_1.flappingHistory']); - expect(active).toMatchInlineSnapshot(` - Object { - "TEST_ALERT_1": Object { - "flappingHistory": Array [ - false, - ], - }, - } - `); - }); - - it('sets flapping state to false on an alert that is still recovered', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - // TEST_ALERT_0 has recovered - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - const { - state: { trackedAlerts, trackedAlertsRecovered }, - } = await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - }, - logger, - }) - ); - - const recovered = pick(trackedAlertsRecovered, ['TEST_ALERT_0.flappingHistory']); - expect(recovered).toMatchInlineSnapshot(`Object {}`); - const active = pick(trackedAlerts, ['TEST_ALERT_1.flappingHistory']); - expect(active).toMatchInlineSnapshot(` - Object { - "TEST_ALERT_1": Object { - "flappingHistory": Array [ - false, - ], - }, - } - `); - }); - }); - - describe('set maintenance window ids on the document', () => { - const maintenanceWindowIds = ['test-id-1', 'test-id-2']; - - it('updates documents with maintenance window ids for newly firing alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: { [TAGS]: ['source-tag1', 'source-tag2'] }, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: { [TAGS]: ['source-tag3', 'source-tag4'] }, - }); - - return { state }; - }); - - await executor( - createDefaultAlertExecutorOptions({ - params: {}, - state: { wrapped: initialRuleState, trackedAlerts: {}, trackedAlertsRecovered: {} }, - logger, - }) - ); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: [ - // alert documents - { create: { _id: expect.any(String) } }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'open', - [EVENT_KIND]: 'signal', - [TAGS]: ['source-tag1', 'source-tag2', 'rule-tag1', 'rule-tag2'], - [ALERT_MAINTENANCE_WINDOW_IDS]: maintenanceWindowIds, - }), - { create: { _id: expect.any(String) } }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'open', - [EVENT_KIND]: 'signal', - [TAGS]: ['source-tag3', 'source-tag4', 'rule-tag1', 'rule-tag2'], - [ALERT_MAINTENANCE_WINDOW_IDS]: maintenanceWindowIds, - }), - ], - }) - ); - expect((await ruleDataClientMock.getWriter()).bulk).not.toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // evaluation documents - { index: {} }, - expect.objectContaining({ - [EVENT_KIND]: 'event', - }), - ]), - }) - ); - }); - - it('does not update documents with maintenance window ids for repeatedly firing alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'closed', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: [ - // alert document - { index: expect.objectContaining({ _id: 'TEST_ALERT_0_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_WORKFLOW_STATUS]: 'closed', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_1_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - }), - ], - }) - ); - expect((await ruleDataClientMock.getWriter()).bulk).not.toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // evaluation documents - { index: {} }, - expect.objectContaining({ - [EVENT_KIND]: 'event', - }), - ]), - }) - ); - }); - - it('does not update documents with maintenance window ids for recovered alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc - [TAGS]: ['source-tag1', 'source-tag2'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc - [TAGS]: ['source-tag3', 'source-tag4'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - // TEST_ALERT_0 has recovered - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - - return { state }; - }); - - await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // alert document - { index: expect.objectContaining({ _id: 'TEST_ALERT_0_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_STATUS]: ALERT_STATUS_RECOVERED, - labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, - [TAGS]: ['source-tag1', 'source-tag2', 'rule-tag1', 'rule-tag2'], - [EVENT_ACTION]: 'close', - [EVENT_KIND]: 'signal', - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_1_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - [TAGS]: ['source-tag3', 'source-tag4', 'rule-tag1', 'rule-tag2'], - }), - ]), - }) - ); - expect((await ruleDataClientMock.getWriter()).bulk).not.toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // evaluation documents - { index: {} }, - expect.objectContaining({ - [EVENT_KIND]: 'event', - }), - ]), - }) - ); - }); - }); - - describe('set flapping on the document', () => { - const flapping = new Array(16).fill(false).concat([true, true, true, true]); - const notFlapping = new Array(20).fill(false); - - it('updates documents with flapping for active alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'closed', - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_2', - [ALERT_UUID]: 'ALERT_2_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_3', - [ALERT_UUID]: 'ALERT_3_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_2', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_3', - fields: {}, - }); - - return { state }; - }); - - const serializedAlerts = await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: flapping, - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [false, false], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_2: { - alertId: 'TEST_ALERT_2', - alertUuid: 'TEST_ALERT_2_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: flapping, - flapping: true, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_3: { - alertId: 'TEST_ALERT_3', - alertUuid: 'TEST_ALERT_3_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [false, false], - flapping: true, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - expect(serializedAlerts.state.trackedAlerts).toEqual({ - TEST_ALERT_0: { - activeCount: 1, - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - flapping: true, - flappingHistory: flapping.slice(1).concat([false]), - pendingRecoveredCount: 0, - started: '2020-01-01T12:00:00.000Z', - }, - TEST_ALERT_1: { - activeCount: 1, - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - flapping: false, - flappingHistory: [false, false, false], - pendingRecoveredCount: 0, - started: '2020-01-02T12:00:00.000Z', - }, - TEST_ALERT_2: { - activeCount: 1, - alertId: 'TEST_ALERT_2', - alertUuid: 'TEST_ALERT_2_UUID', - flapping: true, - flappingHistory: flapping.slice(1).concat([false]), - pendingRecoveredCount: 0, - started: '2020-01-01T12:00:00.000Z', - }, - TEST_ALERT_3: { - activeCount: 1, - alertId: 'TEST_ALERT_3', - alertUuid: 'TEST_ALERT_3_UUID', - flapping: true, - flappingHistory: [false, false, false], - pendingRecoveredCount: 0, - started: '2020-01-02T12:00:00.000Z', - }, - }); - - expect(serializedAlerts.state.trackedAlertsRecovered).toEqual({}); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: [ - // alert document - { index: expect.objectContaining({ _id: 'TEST_ALERT_0_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_WORKFLOW_STATUS]: 'closed', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_FLAPPING]: false, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_1_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - [ALERT_FLAPPING]: false, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_2_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_2', - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - [ALERT_FLAPPING]: true, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_3_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_3', - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - [ALERT_FLAPPING]: true, - }), - ], - }) - ); - }); - - it('updates existing documents for recovered alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_2', - [ALERT_UUID]: 'ALERT_2_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_3', - [ALERT_UUID]: 'ALERT_3_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - return { state }; - }); - - const serializedAlerts = await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [true, true, true, true], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: notFlapping, - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_2: { - alertId: 'TEST_ALERT_2', - alertUuid: 'TEST_ALERT_2_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [true, true], - flapping: true, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_3: { - alertId: 'TEST_ALERT_3', - alertUuid: 'TEST_ALERT_3_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: notFlapping, - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - expect(serializedAlerts.state.trackedAlerts).toEqual({ - TEST_ALERT_2: { - activeCount: 0, - alertId: 'TEST_ALERT_2', - alertUuid: 'TEST_ALERT_2_UUID', - flapping: true, - flappingHistory: [true, true, true], - pendingRecoveredCount: 1, - started: '2020-01-02T12:00:00.000Z', - }, - }); - - expect(serializedAlerts.state.trackedAlertsRecovered).toEqual({ - TEST_ALERT_0: { - activeCount: 0, - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - flapping: true, - flappingHistory: [true, true, true, true, true], - pendingRecoveredCount: 0, - started: '2020-01-01T12:00:00.000Z', - }, - TEST_ALERT_1: { - activeCount: 0, - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - flapping: false, - flappingHistory: notFlapping.slice(0, notFlapping.length - 1).concat([true]), - pendingRecoveredCount: 0, - started: '2020-01-02T12:00:00.000Z', - }, - TEST_ALERT_3: { - activeCount: 0, - alertId: 'TEST_ALERT_3', - alertUuid: 'TEST_ALERT_3_UUID', - flapping: false, - flappingHistory: notFlapping.slice(0, notFlapping.length - 1).concat([true]), - pendingRecoveredCount: 0, - started: '2020-01-02T12:00:00.000Z', - }, - }); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // alert document - { index: expect.objectContaining({ _id: 'TEST_ALERT_0_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_STATUS]: ALERT_STATUS_RECOVERED, - [EVENT_ACTION]: 'close', - [EVENT_KIND]: 'signal', - [ALERT_FLAPPING]: false, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_1_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_STATUS]: ALERT_STATUS_RECOVERED, - [EVENT_ACTION]: 'close', - [EVENT_KIND]: 'signal', - [ALERT_FLAPPING]: false, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_2_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_2', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - [ALERT_FLAPPING]: true, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_3_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_3', - [ALERT_STATUS]: ALERT_STATUS_RECOVERED, - [EVENT_ACTION]: 'close', - [EVENT_KIND]: 'signal', - [ALERT_FLAPPING]: false, - }), - ]), - }) - ); - }); - }); - - describe('set consecutive matches on the document', () => { - it('updates documents with consecutive matches for active alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'closed', - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_2', - [ALERT_UUID]: 'ALERT_2_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_3', - [ALERT_UUID]: 'ALERT_3_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: 'open', - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - services.alertWithLifecycle({ - id: 'TEST_ALERT_0', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_1', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_2', - fields: {}, - }); - services.alertWithLifecycle({ - id: 'TEST_ALERT_3', - fields: {}, - }); - - return { state }; - }); - - const serializedAlerts = await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_2: { - alertId: 'TEST_ALERT_2', - alertUuid: 'TEST_ALERT_2_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_3: { - alertId: 'TEST_ALERT_3', - alertUuid: 'TEST_ALERT_3_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - expect(serializedAlerts.state.trackedAlerts).toEqual({ - TEST_ALERT_0: { - activeCount: 1, - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - flapping: false, - flappingHistory: [false], - pendingRecoveredCount: 0, - started: '2020-01-01T12:00:00.000Z', - }, - TEST_ALERT_1: { - activeCount: 1, - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - flapping: false, - flappingHistory: [false], - pendingRecoveredCount: 0, - started: '2020-01-02T12:00:00.000Z', - }, - TEST_ALERT_2: { - activeCount: 1, - alertId: 'TEST_ALERT_2', - alertUuid: 'TEST_ALERT_2_UUID', - flapping: false, - flappingHistory: [false], - pendingRecoveredCount: 0, - started: '2020-01-01T12:00:00.000Z', - }, - TEST_ALERT_3: { - activeCount: 1, - alertId: 'TEST_ALERT_3', - alertUuid: 'TEST_ALERT_3_UUID', - flapping: false, - flappingHistory: [false], - pendingRecoveredCount: 0, - started: '2020-01-02T12:00:00.000Z', - }, - }); - - expect(serializedAlerts.state.trackedAlertsRecovered).toEqual({}); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: [ - // alert document - { index: expect.objectContaining({ _id: 'TEST_ALERT_0_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_WORKFLOW_STATUS]: 'closed', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [ALERT_CONSECUTIVE_MATCHES]: 1, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_1_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - [ALERT_CONSECUTIVE_MATCHES]: 1, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_2_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_2', - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - [ALERT_CONSECUTIVE_MATCHES]: 1, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_3_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_3', - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [EVENT_ACTION]: 'active', - [EVENT_KIND]: 'signal', - [ALERT_CONSECUTIVE_MATCHES]: 1, - }), - ], - }) - ); - }); - - it('updates existing documents for recovered alerts', async () => { - const logger = loggerMock.create(); - const ruleDataClientMock = createRuleDataClientMock(); - ruleDataClientMock.getReader().search.mockResolvedValue({ - hits: { - hits: [ - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_UUID]: 'ALERT_0_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_UUID]: 'ALERT_1_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_2', - [ALERT_UUID]: 'ALERT_2_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - { - _source: { - '@timestamp': '', - [ALERT_INSTANCE_ID]: 'TEST_ALERT_3', - [ALERT_UUID]: 'ALERT_3_UUID', - [ALERT_RULE_CATEGORY]: 'RULE_TYPE_NAME', - [ALERT_RULE_CONSUMER]: 'CONSUMER', - [ALERT_RULE_NAME]: 'NAME', - [ALERT_RULE_PRODUCER]: 'PRODUCER', - [ALERT_RULE_TYPE_ID]: 'RULE_TYPE_ID', - [ALERT_RULE_UUID]: 'RULE_UUID', - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, - [SPACE_IDS]: ['fake-space-id'], - }, - _index: '.alerts-index-name', - _seq_no: 4, - _primary_term: 2, - }, - ], - }, - } as any); - const executor = createLifecycleExecutor( - logger, - ruleDataClientMock - )<{}, TestRuleState, never, never, never>(async ({ services, state }) => { - return { state }; - }); - - const serializedAlerts = await executor( - createDefaultAlertExecutorOptions({ - alertId: 'TEST_ALERT_0', - params: {}, - state: { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_1: { - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_2: { - alertId: 'TEST_ALERT_2', - alertUuid: 'TEST_ALERT_2_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - TEST_ALERT_3: { - alertId: 'TEST_ALERT_3', - alertUuid: 'TEST_ALERT_3_UUID', - started: '2020-01-02T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }, - logger, - }) - ); - - expect(serializedAlerts.state.trackedAlerts).toEqual({}); - - expect(serializedAlerts.state.trackedAlertsRecovered).toEqual({ - TEST_ALERT_0: { - activeCount: 0, - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - flapping: false, - flappingHistory: [true], - pendingRecoveredCount: 0, - started: '2020-01-01T12:00:00.000Z', - }, - TEST_ALERT_1: { - activeCount: 0, - alertId: 'TEST_ALERT_1', - alertUuid: 'TEST_ALERT_1_UUID', - flapping: false, - flappingHistory: [true], - pendingRecoveredCount: 0, - started: '2020-01-02T12:00:00.000Z', - }, - TEST_ALERT_2: { - activeCount: 0, - alertId: 'TEST_ALERT_2', - alertUuid: 'TEST_ALERT_2_UUID', - flapping: false, - flappingHistory: [true], - pendingRecoveredCount: 0, - started: '2020-01-02T12:00:00.000Z', - }, - TEST_ALERT_3: { - activeCount: 0, - alertId: 'TEST_ALERT_3', - alertUuid: 'TEST_ALERT_3_UUID', - flapping: false, - flappingHistory: [true], - pendingRecoveredCount: 0, - started: '2020-01-02T12:00:00.000Z', - }, - }); - - expect((await ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.arrayContaining([ - // alert document - { index: expect.objectContaining({ _id: 'TEST_ALERT_0_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_0', - [ALERT_STATUS]: ALERT_STATUS_RECOVERED, - [EVENT_ACTION]: 'close', - [EVENT_KIND]: 'signal', - [ALERT_CONSECUTIVE_MATCHES]: 0, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_1_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_1', - [ALERT_STATUS]: ALERT_STATUS_RECOVERED, - [EVENT_ACTION]: 'close', - [EVENT_KIND]: 'signal', - [ALERT_CONSECUTIVE_MATCHES]: 0, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_2_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_2', - [ALERT_STATUS]: ALERT_STATUS_RECOVERED, - [EVENT_ACTION]: 'close', - [EVENT_KIND]: 'signal', - [ALERT_CONSECUTIVE_MATCHES]: 0, - }), - { index: expect.objectContaining({ _id: 'TEST_ALERT_3_UUID' }) }, - expect.objectContaining({ - [ALERT_INSTANCE_ID]: 'TEST_ALERT_3', - [ALERT_STATUS]: ALERT_STATUS_RECOVERED, - [EVENT_ACTION]: 'close', - [EVENT_KIND]: 'signal', - [ALERT_CONSECUTIVE_MATCHES]: 0, - }), - ]), - }) - ); - }); - }); -}); - -type TestRuleState = Record & { - aRuleStateKey: string; -}; - -const initialRuleState: TestRuleState = { - aRuleStateKey: 'INITIAL_RULE_STATE_VALUE', -}; diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts deleted file mode 100644 index cdbdf56fabc51..0000000000000 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { Logger } from '@kbn/logging'; -import type { PublicContract } from '@kbn/utility-types'; -import { getOrElse } from 'fp-ts/lib/Either'; -import { v4 } from 'uuid'; -import { difference } from 'lodash'; -import { - RuleExecutorOptions, - Alert, - AlertInstanceContext, - AlertInstanceState, - RuleTypeParams, - RuleTypeState, - isValidAlertIndexName, -} from '@kbn/alerting-plugin/server'; -import { isFlapping } from '@kbn/alerting-plugin/server/lib'; -import { wrappedStateRt, WrappedLifecycleRuleState } from '@kbn/alerting-state-types'; -export type { - TrackedLifecycleAlertState, - WrappedLifecycleRuleState, -} from '@kbn/alerting-state-types'; -import { ParsedExperimentalFields } from '../../common/parse_experimental_fields'; -import { ParsedTechnicalFields } from '../../common/parse_technical_fields'; -import { - ALERT_TIME_RANGE, - ALERT_DURATION, - ALERT_END, - ALERT_INSTANCE_ID, - ALERT_START, - ALERT_STATUS, - ALERT_STATUS_ACTIVE, - ALERT_STATUS_RECOVERED, - ALERT_UUID, - ALERT_WORKFLOW_STATUS, - EVENT_ACTION, - EVENT_KIND, - TAGS, - TIMESTAMP, - VERSION, - ALERT_FLAPPING, - ALERT_MAINTENANCE_WINDOW_IDS, -} from '../../common/technical_rule_data_field_names'; -import { CommonAlertFieldNameLatest, CommonAlertIdFieldNameLatest } from '../../common/schemas'; -import { IRuleDataClient } from '../rule_data_client'; -import { AlertExecutorOptionsWithExtraServices } from '../types'; -import { fetchExistingAlerts } from './fetch_existing_alerts'; -import { getCommonAlertFields } from './get_common_alert_fields'; -import { getUpdatedFlappingHistory } from './get_updated_flapping_history'; -import { fetchAlertByAlertUUID } from './fetch_alert_by_uuid'; -import { getAlertsForNotification } from './get_alerts_for_notification'; - -type ImplicitTechnicalFieldName = CommonAlertFieldNameLatest | CommonAlertIdFieldNameLatest; - -type ExplicitTechnicalAlertFields = Partial< - Omit ->; - -type ExplicitAlertFields = Record & // every field can have values of arbitrary types - ExplicitTechnicalAlertFields; // but technical fields must obey their respective type - -export type LifecycleAlertService< - InstanceState extends AlertInstanceState = never, - InstanceContext extends AlertInstanceContext = never, - ActionGroupIds extends string = never -> = (alert: { - id: string; - fields: ExplicitAlertFields; -}) => Alert; - -export interface LifecycleAlertServices< - InstanceState extends AlertInstanceState = never, - InstanceContext extends AlertInstanceContext = never, - ActionGroupIds extends string = never -> { - alertWithLifecycle: LifecycleAlertService; - getAlertStartedDate: (alertInstanceId: string) => string | null; - getAlertUuid: (alertInstanceId: string) => string; - getAlertByAlertUuid: ( - alertUuid: string - ) => Promise | null> | null; -} - -export type LifecycleRuleExecutor< - Params extends RuleTypeParams = never, - State extends RuleTypeState = never, - InstanceState extends AlertInstanceState = never, - InstanceContext extends AlertInstanceContext = never, - ActionGroupIds extends string = never -> = ( - options: AlertExecutorOptionsWithExtraServices< - Params, - State, - InstanceState, - InstanceContext, - ActionGroupIds, - LifecycleAlertServices - > -) => Promise<{ state: State }>; - -export const createLifecycleExecutor = - (logger: Logger, ruleDataClient: PublicContract) => - < - Params extends RuleTypeParams = never, - State extends RuleTypeState = never, - InstanceState extends AlertInstanceState = never, - InstanceContext extends AlertInstanceContext = never, - ActionGroupIds extends string = never - >( - wrappedExecutor: LifecycleRuleExecutor< - Params, - State, - InstanceState, - InstanceContext, - ActionGroupIds - > - ) => - async ( - options: RuleExecutorOptions< - Params, - WrappedLifecycleRuleState, - InstanceState, - InstanceContext, - ActionGroupIds - > - ): Promise<{ state: WrappedLifecycleRuleState }> => { - const { - services: { alertFactory, getMaintenanceWindowIds, shouldWriteAlerts }, - state: previousState, - flappingSettings, - rule, - } = options; - - const ruleDataClientWriter = await ruleDataClient.getWriter(); - - const state = getOrElse( - (): WrappedLifecycleRuleState => ({ - wrapped: previousState as State, - trackedAlerts: {}, - trackedAlertsRecovered: {}, - }) - )(wrappedStateRt().decode(previousState)); - - const commonRuleFields = getCommonAlertFields(options); - - const currentAlerts: Record = {}; - const alertUuidMap: Map = new Map(); - - const lifecycleAlertServices: LifecycleAlertServices< - InstanceState, - InstanceContext, - ActionGroupIds - > = { - alertWithLifecycle: ({ id, fields }) => { - currentAlerts[id] = fields; - const alert = alertFactory.create(id); - const uuid = alert.getUuid(); - alertUuidMap.set(id, uuid); - return alert; - }, - getAlertStartedDate: (alertId: string) => state.trackedAlerts[alertId]?.started ?? null, - getAlertUuid: (alertId: string) => { - const uuid = alertUuidMap.get(alertId); - if (uuid) { - return uuid; - } - - const trackedAlert = state.trackedAlerts[alertId]; - if (trackedAlert) { - return trackedAlert.alertUuid; - } - - const trackedRecoveredAlert = state.trackedAlertsRecovered[alertId]; - if (trackedRecoveredAlert) { - return trackedRecoveredAlert.alertUuid; - } - - const alertInfo = `alert ${alertId} of rule ${rule.ruleTypeId}:${rule.id}`; - logger.warn( - `[Rule Registry] requesting uuid for ${alertInfo} which is not tracked, generating dynamically` - ); - return v4(); - }, - getAlertByAlertUuid: async (alertUuid: string) => { - try { - return await fetchAlertByAlertUUID(ruleDataClient, alertUuid); - } catch (err) { - return null; - } - }, - }; - - const wrappedExecutorResult = await wrappedExecutor({ - ...options, - state: state.wrapped != null ? state.wrapped : ({} as State), - services: { - ...options.services, - ...lifecycleAlertServices, - }, - }); - - const currentAlertIds = Object.keys(currentAlerts); - const trackedAlertIds = Object.keys(state.trackedAlerts); - const trackedAlertRecoveredIds = Object.keys(state.trackedAlertsRecovered); - const newAlertIds = difference(currentAlertIds, trackedAlertIds); - const allAlertIds = [...new Set(currentAlertIds.concat(trackedAlertIds))]; - - const trackedAlertStates = Object.values(state.trackedAlerts); - - logger.debug( - `[Rule Registry] Tracking ${allAlertIds.length} alerts (${newAlertIds.length} new, ${trackedAlertStates.length} previous)` - ); - - // load maintenance window ids if there are new alerts - const maintenanceWindowIds: string[] = allAlertIds.length - ? await getMaintenanceWindowIds() - : []; - - interface TrackedAlertData { - indexName: string; - fields: Partial; - seqNo: number | undefined; - primaryTerm: number | undefined; - } - - const trackedAlertsDataMap: Record = {}; - - if (trackedAlertStates.length) { - const result = await fetchExistingAlerts( - ruleDataClient, - trackedAlertStates, - commonRuleFields - ); - result.forEach((hit) => { - const alertInstanceId = hit._source ? hit._source[ALERT_INSTANCE_ID] : void 0; - if (alertInstanceId && hit._source) { - const alertLabel = `${rule.ruleTypeId}:${rule.id} ${alertInstanceId}`; - if (hit._seq_no == null) { - logger.error(`missing _seq_no on alert instance ${alertLabel}`); - } else if (hit._primary_term == null) { - logger.error(`missing _primary_term on alert instance ${alertLabel}`); - } else { - trackedAlertsDataMap[alertInstanceId] = { - indexName: hit._index, - fields: hit._source, - seqNo: hit._seq_no, - primaryTerm: hit._primary_term, - }; - } - } - }); - } - - const makeEventsDataMapFor = (alertIds: string[]) => - alertIds - .filter((alertId) => { - const alertData = trackedAlertsDataMap[alertId]; - const alertIndex = alertData?.indexName; - if (!alertIndex) { - return true; - } else if (!isValidAlertIndexName(alertIndex)) { - logger.warn( - `Could not update alert ${alertId} in ${alertIndex}. Partial and restored alert indices are not supported.` - ); - return false; - } - return true; - }) - .map((alertId) => { - const alertData = trackedAlertsDataMap[alertId]; - const currentAlertData = currentAlerts[alertId]; - const trackedAlert = state.trackedAlerts[alertId]; - - if (!alertData) { - logger.debug(`[Rule Registry] Could not find alert data for ${alertId}`); - } - - const isNew = !trackedAlert; - const isRecovered = !currentAlertData; - const isActive = !isRecovered; - - const flappingHistory = getUpdatedFlappingHistory( - flappingSettings, - alertId, - state, - isNew, - isRecovered, - isActive, - trackedAlertRecoveredIds - ); - - const { alertUuid, started, flapping, pendingRecoveredCount, activeCount } = !isNew - ? state.trackedAlerts[alertId] - : { - alertUuid: lifecycleAlertServices.getAlertUuid(alertId), - started: commonRuleFields[TIMESTAMP], - flapping: state.trackedAlertsRecovered[alertId] - ? state.trackedAlertsRecovered[alertId].flapping - : false, - pendingRecoveredCount: 0, - activeCount: 0, - }; - - const event: ParsedTechnicalFields & ParsedExperimentalFields = { - ...alertData?.fields, - ...commonRuleFields, - ...currentAlertData, - [ALERT_DURATION]: (options.startedAt.getTime() - new Date(started).getTime()) * 1000, - [ALERT_TIME_RANGE]: isRecovered - ? { - gte: started, - lte: commonRuleFields[TIMESTAMP], - } - : { gte: started }, - [ALERT_INSTANCE_ID]: alertId, - [ALERT_START]: started, - [ALERT_UUID]: alertUuid, - [ALERT_STATUS]: isRecovered ? ALERT_STATUS_RECOVERED : ALERT_STATUS_ACTIVE, - [ALERT_WORKFLOW_STATUS]: alertData?.fields[ALERT_WORKFLOW_STATUS] ?? 'open', - [EVENT_KIND]: 'signal', - [EVENT_ACTION]: isNew ? 'open' : isActive ? 'active' : 'close', - [TAGS]: Array.from( - new Set([ - ...(currentAlertData?.tags ?? []), - ...(alertData?.fields[TAGS] ?? []), - ...(options.rule.tags ?? []), - ]) - ), - [VERSION]: ruleDataClient.kibanaVersion, - [ALERT_FLAPPING]: flapping, - ...(isRecovered ? { [ALERT_END]: commonRuleFields[TIMESTAMP] } : {}), - ...(isNew && maintenanceWindowIds?.length - ? { [ALERT_MAINTENANCE_WINDOW_IDS]: maintenanceWindowIds } - : {}), - }; - - return { - indexName: alertData?.indexName, - seqNo: alertData?.seqNo, - primaryTerm: alertData?.primaryTerm, - event, - flappingHistory, - flapping, - pendingRecoveredCount, - activeCount, - }; - }); - - const trackedEventsToIndex = makeEventsDataMapFor(trackedAlertIds); - const newEventsToIndex = makeEventsDataMapFor(newAlertIds); - const trackedRecoveredEventsToIndex = makeEventsDataMapFor(trackedAlertRecoveredIds); - const allEventsToIndex = getAlertsForNotification( - flappingSettings, - rule.alertDelay?.active ?? 0, - trackedEventsToIndex, - newEventsToIndex, - { maintenanceWindowIds, timestamp: commonRuleFields[TIMESTAMP] } - ); - - // Only write alerts if: - // - writing is enabled - // AND - // - rule execution has not been cancelled due to timeout - // OR - // - if execution has been cancelled due to timeout, if feature flags are configured to write alerts anyway - const writeAlerts = ruleDataClient.isWriteEnabled() && shouldWriteAlerts(); - - if (allEventsToIndex.length > 0 && writeAlerts) { - logger.debug(`[Rule Registry] Preparing to index ${allEventsToIndex.length} alerts.`); - - await ruleDataClientWriter.bulk({ - body: allEventsToIndex.flatMap(({ event, indexName, seqNo, primaryTerm }) => [ - indexName - ? { - index: { - _id: event[ALERT_UUID]!, - _index: indexName, - if_seq_no: seqNo, - if_primary_term: primaryTerm, - require_alias: false, - }, - } - : { - create: { - _id: event[ALERT_UUID]!, - }, - }, - event, - ]), - refresh: true, - }); - } else { - logger.debug( - `[Rule Registry] Not indexing ${allEventsToIndex.length} alerts because writing has been disabled.` - ); - } - - const nextTrackedAlerts = Object.fromEntries( - [...newEventsToIndex, ...trackedEventsToIndex] - .filter(({ event }) => event[ALERT_STATUS] !== ALERT_STATUS_RECOVERED) - .map( - ({ - event, - flappingHistory, - flapping: isCurrentlyFlapping, - pendingRecoveredCount, - activeCount, - }) => { - const alertId = event[ALERT_INSTANCE_ID]!; - const alertUuid = event[ALERT_UUID]!; - const started = new Date(event[ALERT_START]!).toISOString(); - const flapping = isFlapping(flappingSettings, flappingHistory, isCurrentlyFlapping); - return [ - alertId, - { - alertId, - alertUuid, - started, - flappingHistory, - flapping, - pendingRecoveredCount, - activeCount, - }, - ]; - } - ) - ); - - const nextTrackedAlertsRecovered = Object.fromEntries( - [...allEventsToIndex, ...trackedRecoveredEventsToIndex] - .filter( - ({ event, flappingHistory, flapping }) => - // return recovered alerts if they are flapping or if the flapping array is not at capacity - // this is a space saving effort that will stop tracking a recovered alert if it wasn't flapping and doesn't have state changes - // in the last max capcity number of executions - event[ALERT_STATUS] === ALERT_STATUS_RECOVERED && - (flapping || flappingHistory.filter((f: boolean) => f).length > 0) - ) - .map( - ({ - event, - flappingHistory, - flapping: isCurrentlyFlapping, - pendingRecoveredCount, - activeCount, - }) => { - const alertId = event[ALERT_INSTANCE_ID]!; - const alertUuid = event[ALERT_UUID]!; - const started = new Date(event[ALERT_START]!).toISOString(); - const flapping = isFlapping(flappingSettings, flappingHistory, isCurrentlyFlapping); - return [ - alertId, - { - alertId, - alertUuid, - started, - flappingHistory, - flapping, - pendingRecoveredCount, - activeCount, - }, - ]; - } - ) - ); - - return { - state: { - wrapped: wrappedExecutorResult?.state ?? ({} as State), - trackedAlerts: writeAlerts ? nextTrackedAlerts : {}, - trackedAlertsRecovered: writeAlerts ? nextTrackedAlertsRecovered : {}, - }, - }; - }; diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_executor_mock.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_executor_mock.ts deleted file mode 100644 index bf0d98d5156af..0000000000000 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_executor_mock.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, -} from '@kbn/alerting-plugin/server'; -import { AlertExecutorOptionsWithExtraServices } from '../types'; - -import { LifecycleAlertServices, LifecycleRuleExecutor } from './create_lifecycle_executor'; - -export const createLifecycleRuleExecutorMock = - < - Params extends RuleTypeParams = never, - State extends RuleTypeState = never, - InstanceState extends AlertInstanceState = never, - InstanceContext extends AlertInstanceContext = never, - ActionGroupIds extends string = never - >( - executor: LifecycleRuleExecutor - ) => - async ( - options: AlertExecutorOptionsWithExtraServices< - Params, - State, - InstanceState, - InstanceContext, - ActionGroupIds, - LifecycleAlertServices - > - ) => - await executor(options); diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts deleted file mode 100644 index 6dbc33b666497..0000000000000 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { - ALERT_DURATION, - ALERT_STATUS, - ALERT_STATUS_ACTIVE, - ALERT_STATUS_RECOVERED, - ALERT_UUID, - ALERT_TIME_RANGE, -} from '@kbn/rule-data-utils'; -import { loggerMock } from '@kbn/logging-mocks'; -import { castArray, omit } from 'lodash'; -import { createRuleDataClientMock } from '../rule_data_client/rule_data_client.mock'; -import { createLifecycleRuleTypeFactory } from './create_lifecycle_rule_type_factory'; -import { ISearchStartSearchSource } from '@kbn/data-plugin/common'; -import { SharePluginStart } from '@kbn/share-plugin/server'; -import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; -import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common/rules_settings'; - -type RuleTestHelpers = ReturnType; - -function createRule(shouldWriteAlerts: boolean = true) { - const ruleDataClientMock = createRuleDataClientMock(); - - const factory = createLifecycleRuleTypeFactory({ - ruleDataClient: ruleDataClientMock, - logger: loggerMock.create(), - }); - - let nextAlerts: Array<{ id: string; fields: Record }> = []; - - const type = factory({ - actionGroups: [ - { - id: 'warning', - name: 'warning', - }, - ], - actionVariables: { - context: [], - params: [], - state: [], - }, - defaultActionGroupId: 'warning', - executor: async ({ services }) => { - nextAlerts.forEach((alert) => { - services.alertWithLifecycle(alert); - }); - nextAlerts = []; - return { state: {} }; - }, - id: 'ruleTypeId', - isExportable: true, - minimumLicenseRequired: 'basic', - name: 'ruleTypeName', - category: 'test', - producer: 'producer', - validate: { - params: schema.object( - {}, - { - unknowns: 'allow', - } - ), - }, - }); - - let state: Record = {}; - let previousStartedAt: Date | null; - const createdAt = new Date('2021-06-16T09:00:00.000Z'); - - const scheduleActions = jest.fn(); - - let uuidCounter = 1; - const getUuid = jest.fn(() => `uuid-${uuidCounter++}`); - - const alertFactory = { - create: () => { - return { - scheduleActions, - getUuid, - } as any; - }, - alertLimit: { - getValue: () => 1000, - setLimitReached: () => {}, - }, - done: () => ({ getRecoveredAlerts: () => [] }), - }; - - return { - alertWithLifecycle: async (alerts: Array<{ id: string; fields: Record }>) => { - nextAlerts = alerts; - - const startedAt = new Date((previousStartedAt ?? createdAt).getTime() + 60000); - - scheduleActions.mockClear(); - - ({ state } = ((await type.executor({ - executionId: 'b33f65d7-6e8b-4aae-8d20-c93613dec9f9', - logger: loggerMock.create(), - namespace: 'namespace', - params: { threshold: 1, operator: '>' }, - previousStartedAt, - rule: { - id: 'alertId', - actions: [], - consumer: 'consumer', - createdAt, - createdBy: 'createdBy', - enabled: true, - muteAll: false, - name: 'name', - notifyWhen: 'onActionGroupChange', - producer: 'producer', - revision: 0, - ruleTypeId: 'ruleTypeId', - ruleTypeName: 'ruleTypeName', - schedule: { - interval: '1m', - }, - snoozeSchedule: [], - tags: ['tags'], - throttle: null, - updatedAt: createdAt, - updatedBy: 'updatedBy', - }, - services: { - alertsClient: null, - alertFactory, - savedObjectsClient: {} as any, - scopedClusterClient: {} as any, - search: {} as any, - getMaintenanceWindowIds: async () => [], - getSearchSourceClient: async () => ({} as ISearchStartSearchSource), - shouldStopExecution: () => false, - shouldWriteAlerts: () => shouldWriteAlerts, - uiSettingsClient: {} as any, - share: {} as SharePluginStart, - getDataViews: async () => dataViewPluginMocks.createStartContract(), - }, - spaceId: 'spaceId', - startedAt, - startedAtOverridden: false, - state, - flappingSettings: DEFAULT_FLAPPING_SETTINGS, - getTimeRange: () => { - const date = new Date(Date.now()).toISOString(); - return { dateStart: date, dateEnd: date }; - }, - })) ?? {}) as Record); - - previousStartedAt = startedAt; - }, - scheduleActions, - ruleDataClientMock, - }; -} - -describe('createLifecycleRuleTypeFactory', () => { - describe('with a new rule', () => { - let helpers: RuleTestHelpers; - - beforeEach(() => { - helpers = createRule(); - }); - - describe('when writing is disabled', () => { - beforeEach(() => { - helpers.ruleDataClientMock.isWriteEnabled.mockReturnValue(false); - }); - - it("doesn't persist anything", async () => { - await helpers.alertWithLifecycle([ - { - id: 'opbeans-java', - fields: { - 'service.name': 'opbeans-java', - }, - }, - ]); - - expect((await helpers.ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledTimes(0); - }); - }); - - describe('when rule is cancelled due to timeout and config flags indicate to skip actions', () => { - beforeEach(() => { - helpers = createRule(false); - helpers.ruleDataClientMock.isWriteEnabled.mockReturnValue(true); - }); - - it("doesn't persist anything", async () => { - await helpers.alertWithLifecycle([ - { - id: 'opbeans-java', - fields: { - 'service.name': 'opbeans-java', - }, - }, - ]); - - expect((await helpers.ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledTimes(0); - }); - }); - - describe('when alerts are new', () => { - beforeEach(async () => { - await helpers.alertWithLifecycle([ - { - id: 'opbeans-java', - fields: { - 'service.name': 'opbeans-java', - }, - }, - { - id: 'opbeans-node', - fields: { - 'service.name': 'opbeans-node', - }, - }, - ]); - }); - - it('writes the correct alerts', async () => { - expect((await helpers.ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledTimes(1); - - const body = (await helpers.ruleDataClientMock.getWriter()).bulk.mock.calls[0][0].body!; - - const documents: any[] = body.filter((op: any) => !isOpDoc(op)); - - const evaluationDocuments = documents.filter((doc) => doc['event.kind'] === 'event'); - const alertDocuments = documents.filter((doc) => doc['event.kind'] === 'signal'); - - expect(evaluationDocuments.length).toBe(0); - expect(alertDocuments.length).toBe(2); - - expect( - alertDocuments.every((doc) => doc[ALERT_STATUS] === ALERT_STATUS_ACTIVE) - ).toBeTruthy(); - - expect(alertDocuments.every((doc) => doc[ALERT_DURATION] === 0)).toBeTruthy(); - - expect(alertDocuments.every((doc) => doc['event.action'] === 'open')).toBeTruthy(); - - expect(documents.map((doc) => omit(doc, ALERT_UUID))).toMatchInlineSnapshot(` - Array [ - Object { - "@timestamp": "2021-06-16T09:01:00.000Z", - "event.action": "open", - "event.kind": "signal", - "kibana.alert.consecutive_matches": 1, - "kibana.alert.duration.us": 0, - "kibana.alert.flapping": false, - "kibana.alert.instance.id": "opbeans-java", - "kibana.alert.rule.category": "ruleTypeName", - "kibana.alert.rule.consumer": "consumer", - "kibana.alert.rule.execution.uuid": "b33f65d7-6e8b-4aae-8d20-c93613dec9f9", - "kibana.alert.rule.name": "name", - "kibana.alert.rule.parameters": Object { - "operator": ">", - "threshold": 1, - }, - "kibana.alert.rule.producer": "producer", - "kibana.alert.rule.revision": 0, - "kibana.alert.rule.rule_type_id": "ruleTypeId", - "kibana.alert.rule.tags": Array [ - "tags", - ], - "kibana.alert.rule.uuid": "alertId", - "kibana.alert.start": "2021-06-16T09:01:00.000Z", - "kibana.alert.status": "active", - "kibana.alert.time_range": Object { - "gte": "2021-06-16T09:01:00.000Z", - }, - "kibana.alert.workflow_status": "open", - "kibana.space_ids": Array [ - "spaceId", - ], - "kibana.version": "7.16.0", - "service.name": "opbeans-java", - "tags": Array [ - "tags", - ], - }, - Object { - "@timestamp": "2021-06-16T09:01:00.000Z", - "event.action": "open", - "event.kind": "signal", - "kibana.alert.consecutive_matches": 1, - "kibana.alert.duration.us": 0, - "kibana.alert.flapping": false, - "kibana.alert.instance.id": "opbeans-node", - "kibana.alert.rule.category": "ruleTypeName", - "kibana.alert.rule.consumer": "consumer", - "kibana.alert.rule.execution.uuid": "b33f65d7-6e8b-4aae-8d20-c93613dec9f9", - "kibana.alert.rule.name": "name", - "kibana.alert.rule.parameters": Object { - "operator": ">", - "threshold": 1, - }, - "kibana.alert.rule.producer": "producer", - "kibana.alert.rule.revision": 0, - "kibana.alert.rule.rule_type_id": "ruleTypeId", - "kibana.alert.rule.tags": Array [ - "tags", - ], - "kibana.alert.rule.uuid": "alertId", - "kibana.alert.start": "2021-06-16T09:01:00.000Z", - "kibana.alert.status": "active", - "kibana.alert.time_range": Object { - "gte": "2021-06-16T09:01:00.000Z", - }, - "kibana.alert.workflow_status": "open", - "kibana.space_ids": Array [ - "spaceId", - ], - "kibana.version": "7.16.0", - "service.name": "opbeans-node", - "tags": Array [ - "tags", - ], - }, - ] - `); - }); - }); - - describe('when alerts are active', () => { - beforeEach(async () => { - await helpers.alertWithLifecycle([ - { - id: 'opbeans-java', - fields: { - 'service.name': 'opbeans-java', - }, - }, - { - id: 'opbeans-node', - fields: { - 'service.name': 'opbeans-node', - }, - }, - ]); - - // TODO mock the resolved value before calling alertWithLifecycle again - const lastOpbeansNodeDoc = ( - await helpers.ruleDataClientMock.getWriter() - ).bulk.mock.calls[0][0].body - ?.concat() - .reverse() - .find((doc: any) => !isOpDoc(doc) && doc['service.name'] === 'opbeans-node') as Record< - string, - any - >; - - // @ts-ignore 4.3.5 upgrade - helpers.ruleDataClientMock.getReader().search.mockResolvedValueOnce({ - hits: { - hits: [{ _source: lastOpbeansNodeDoc } as any], - total: { - value: 1, - relation: 'eq', - }, - }, - took: 0, - timed_out: false, - _shards: { - failed: 0, - successful: 1, - total: 1, - }, - }); - - await helpers.alertWithLifecycle([ - { - id: 'opbeans-java', - fields: { - 'service.name': 'opbeans-java', - }, - }, - { - id: 'opbeans-node', - fields: { - 'service.name': 'opbeans-node', - 'kibana.alert.workflow_status': 'closed', - }, - }, - ]); - }); - - it('writes the correct alerts', async () => { - expect((await helpers.ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledTimes(2); - const body = (await helpers.ruleDataClientMock.getWriter()).bulk.mock.calls[1][0].body!; - - const documents: any[] = body.filter((op: any) => !isOpDoc(op)); - - const evaluationDocuments = documents.filter((doc) => doc['event.kind'] === 'event'); - const alertDocuments = documents.filter((doc) => doc['event.kind'] === 'signal'); - - expect(evaluationDocuments.length).toBe(0); - expect(alertDocuments.length).toBe(2); - - expect( - alertDocuments.every((doc) => doc[ALERT_STATUS] === ALERT_STATUS_ACTIVE) - ).toBeTruthy(); - expect(alertDocuments.every((doc) => doc['event.action'] === 'active')).toBeTruthy(); - - expect(alertDocuments.every((doc) => doc[ALERT_DURATION] > 0)).toBeTruthy(); - }); - }); - - describe('when alerts recover', () => { - beforeEach(async () => { - await helpers.alertWithLifecycle([ - { - id: 'opbeans-java', - fields: { - 'service.name': 'opbeans-java', - }, - }, - { - id: 'opbeans-node', - fields: { - 'service.name': 'opbeans-node', - }, - }, - ]); - - const lastOpbeansNodeDoc = ( - await helpers.ruleDataClientMock.getWriter() - ).bulk.mock.calls[0][0].body - ?.concat() - .reverse() - .find((doc: any) => !isOpDoc(doc) && doc['service.name'] === 'opbeans-node') as Record< - string, - any - >; - - helpers.ruleDataClientMock.getReader().search.mockResolvedValueOnce({ - hits: { - hits: [ - { - _source: lastOpbeansNodeDoc, - _index: '.alerts-a', - _primary_term: 4, - _seq_no: 2, - } as any, - ], - total: { - value: 1, - relation: 'eq', - }, - }, - took: 0, - timed_out: false, - _shards: { - failed: 0, - successful: 1, - total: 1, - }, - }); - - await helpers.alertWithLifecycle([ - { - id: 'opbeans-java', - fields: { - 'service.name': 'opbeans-java', - }, - }, - ]); - }); - - it('writes the correct alerts', async () => { - expect((await helpers.ruleDataClientMock.getWriter()).bulk).toHaveBeenCalledTimes(2); - - const body = (await helpers.ruleDataClientMock.getWriter()).bulk.mock.calls[1][0].body!; - - const documents: any[] = body.filter((op: any) => !isOpDoc(op)); - - const opbeansJavaAlertDoc = documents.find( - (doc) => castArray(doc['service.name'])[0] === 'opbeans-java' - ); - const opbeansNodeAlertDoc = documents.find( - (doc) => castArray(doc['service.name'])[0] === 'opbeans-node' - ); - - expect(opbeansJavaAlertDoc['event.action']).toBe('active'); - expect(opbeansJavaAlertDoc[ALERT_STATUS]).toBe(ALERT_STATUS_ACTIVE); - - expect(opbeansNodeAlertDoc['event.action']).toBe('close'); - expect(opbeansNodeAlertDoc[ALERT_STATUS]).toBe(ALERT_STATUS_RECOVERED); - expect(opbeansNodeAlertDoc[ALERT_TIME_RANGE]).toEqual({ - gte: '2021-06-16T09:01:00.000Z', - lte: '2021-06-16T09:02:00.000Z', - }); - }); - }); - }); -}); - -function isOpDoc(doc: any) { - if (doc?.index?._id) return true; - if (doc?.create?._id) return true; - return false; -} diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type_factory.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type_factory.ts deleted file mode 100644 index 7f1be5ff54f83..0000000000000 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type_factory.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { Logger } from '@kbn/logging'; -import { - AlertInstanceContext, - AlertInstanceState, - RuleTypeParams, - RuleTypeState, -} from '@kbn/alerting-plugin/common'; -import { IRuleDataClient } from '../rule_data_client'; -import { AlertTypeWithExecutor } from '../types'; -import { createLifecycleExecutor, LifecycleAlertServices } from './create_lifecycle_executor'; - -export const createLifecycleRuleTypeFactory = - ({ logger, ruleDataClient }: { logger: Logger; ruleDataClient: IRuleDataClient }) => - < - TParams extends RuleTypeParams, - TAlertInstanceState extends AlertInstanceState, - TAlertInstanceContext extends AlertInstanceContext, - TActionGroupIds extends string, - TServices extends LifecycleAlertServices< - TAlertInstanceState, - TAlertInstanceContext, - TActionGroupIds - > - >( - type: AlertTypeWithExecutor - ): AlertTypeWithExecutor => { - const createBoundLifecycleExecutor = createLifecycleExecutor(logger, ruleDataClient); - const executor = createBoundLifecycleExecutor< - TParams, - RuleTypeState, - AlertInstanceState, - TAlertInstanceContext, - string - >(type.executor as any); - return { - ...type, - executor: executor as any, - }; - }; diff --git a/x-pack/plugins/rule_registry/server/utils/get_updated_flapping_history.test.ts b/x-pack/plugins/rule_registry/server/utils/get_updated_flapping_history.test.ts deleted file mode 100644 index 84685779186d9..0000000000000 --- a/x-pack/plugins/rule_registry/server/utils/get_updated_flapping_history.test.ts +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - DEFAULT_FLAPPING_SETTINGS, - DISABLE_FLAPPING_SETTINGS, -} from '@kbn/alerting-plugin/common/rules_settings'; -import { getUpdatedFlappingHistory } from './get_updated_flapping_history'; - -describe('getUpdatedFlappingHistory', () => { - type TestRuleState = Record & { - aRuleStateKey: string; - }; - const initialRuleState: TestRuleState = { - aRuleStateKey: 'INITIAL_RULE_STATE_VALUE', - }; - - test('sets flapping state to true if the alert is new', () => { - const state = { wrapped: initialRuleState, trackedAlerts: {}, trackedAlertsRecovered: {} }; - expect( - getUpdatedFlappingHistory( - DEFAULT_FLAPPING_SETTINGS, - 'TEST_ALERT_0', - state, - true, - false, - false, - [] - ) - ).toMatchInlineSnapshot(` - Array [ - true, - ] - `); - }); - - test('sets flapping state to false on an alert that is still active', () => { - const state = { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }; - expect( - getUpdatedFlappingHistory( - DEFAULT_FLAPPING_SETTINGS, - 'TEST_ALERT_0', - state, - false, - false, - true, - [] - ) - ).toMatchInlineSnapshot(` - Array [ - false, - ] - `); - }); - - test('sets flapping state to true on an alert that is active and previously recovered', () => { - const state = { - wrapped: initialRuleState, - trackedAlertsRecovered: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlerts: {}, - }; - const recoveredIds = ['TEST_ALERT_0']; - expect( - getUpdatedFlappingHistory( - DEFAULT_FLAPPING_SETTINGS, - 'TEST_ALERT_0', - state, - true, - false, - true, - recoveredIds - ) - ).toMatchInlineSnapshot(` - Array [ - true, - ] - `); - expect(recoveredIds).toEqual([]); - }); - - test('sets flapping state to true on an alert that is recovered and previously active', () => { - const state = { - wrapped: initialRuleState, - trackedAlerts: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - trackedAlertsRecovered: {}, - }; - const recoveredIds = ['TEST_ALERT_0']; - expect( - getUpdatedFlappingHistory( - DEFAULT_FLAPPING_SETTINGS, - 'TEST_ALERT_0', - state, - false, - true, - false, - recoveredIds - ) - ).toMatchInlineSnapshot(` - Array [ - true, - ] - `); - expect(recoveredIds).toEqual(['TEST_ALERT_0']); - }); - - test('sets flapping state to false on an alert that is still recovered', () => { - const state = { - wrapped: initialRuleState, - trackedAlerts: {}, - trackedAlertsRecovered: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - }; - const recoveredIds = ['TEST_ALERT_0']; - expect( - getUpdatedFlappingHistory( - DEFAULT_FLAPPING_SETTINGS, - 'TEST_ALERT_0', - state, - false, - true, - false, - recoveredIds - ) - ).toMatchInlineSnapshot(` - Array [ - false, - ] - `); - expect(recoveredIds).toEqual(['TEST_ALERT_0']); - }); - - test('does not set flapping state if flapping is not enabled', () => { - const state = { - wrapped: initialRuleState, - trackedAlerts: {}, - trackedAlertsRecovered: { - TEST_ALERT_0: { - alertId: 'TEST_ALERT_0', - alertUuid: 'TEST_ALERT_0_UUID', - started: '2020-01-01T12:00:00.000Z', - flappingHistory: [], - flapping: false, - pendingRecoveredCount: 0, - activeCount: 0, - }, - }, - }; - expect( - getUpdatedFlappingHistory( - DISABLE_FLAPPING_SETTINGS, - 'TEST_ALERT_0', - state, - false, - true, - false, - ['TEST_ALERT_0'] - ) - ).toMatchInlineSnapshot(`Array []`); - }); -}); diff --git a/x-pack/plugins/rule_registry/server/utils/get_updated_flapping_history.ts b/x-pack/plugins/rule_registry/server/utils/get_updated_flapping_history.ts deleted file mode 100644 index 854f919722330..0000000000000 --- a/x-pack/plugins/rule_registry/server/utils/get_updated_flapping_history.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { RuleTypeState } from '@kbn/alerting-plugin/common'; -import { RulesSettingsFlappingProperties } from '@kbn/alerting-plugin/common/rules_settings'; -import { updateFlappingHistory } from '@kbn/alerting-plugin/server/lib'; -import { remove } from 'lodash'; -import { WrappedLifecycleRuleState } from './create_lifecycle_executor'; - -export function getUpdatedFlappingHistory( - flappingSettings: RulesSettingsFlappingProperties, - alertId: string, - state: WrappedLifecycleRuleState, - isNew: boolean, - isRecovered: boolean, - isActive: boolean, - recoveredIds: string[] -) { - // duplicating this logic to determine flapping at this level - let flappingHistory: boolean[] = []; - if (flappingSettings.enabled) { - if (isRecovered) { - if (state.trackedAlerts[alertId]) { - // this alert has flapped from active to recovered - flappingHistory = updateFlappingHistory( - flappingSettings, - state.trackedAlerts[alertId].flappingHistory, - true - ); - } else if (state.trackedAlertsRecovered[alertId]) { - // this alert is still recovered - flappingHistory = updateFlappingHistory( - flappingSettings, - state.trackedAlertsRecovered[alertId].flappingHistory, - false - ); - } - } else if (isNew) { - if (state.trackedAlertsRecovered[alertId]) { - // this alert has flapped from recovered to active - flappingHistory = updateFlappingHistory( - flappingSettings, - state.trackedAlertsRecovered[alertId].flappingHistory, - true - ); - remove(recoveredIds, (id) => id === alertId); - } else { - flappingHistory = updateFlappingHistory(flappingSettings, [], true); - } - } else if (isActive) { - // this alert is still active - flappingHistory = updateFlappingHistory( - flappingSettings, - state.trackedAlerts[alertId].flappingHistory, - false - ); - } - } - return flappingHistory; -} diff --git a/x-pack/plugins/rule_registry/server/utils/lifecycle_alert_services.mock.ts b/x-pack/plugins/rule_registry/server/utils/lifecycle_alert_services.mock.ts deleted file mode 100644 index 9324bcfd76cb4..0000000000000 --- a/x-pack/plugins/rule_registry/server/utils/lifecycle_alert_services.mock.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { AlertInstanceContext, AlertInstanceState } from '@kbn/alerting-plugin/server'; -import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; -import { LifecycleAlertServices } from './create_lifecycle_executor'; - -/** - * This wraps the alerts to enable the preservation of the generic type - * arguments of the factory function. - **/ -class AlertsMockWrapper< - InstanceState extends AlertInstanceState = AlertInstanceState, - InstanceContext extends AlertInstanceContext = AlertInstanceContext -> { - createAlertServices() { - return alertsMock.createRuleExecutorServices(); - } -} - -type AlertServices< - InstanceState extends AlertInstanceState = AlertInstanceState, - InstanceContext extends AlertInstanceContext = AlertInstanceContext -> = ReturnType['createAlertServices']>; - -export const createLifecycleAlertServicesMock = < - InstanceState extends AlertInstanceState = never, - InstanceContext extends AlertInstanceContext = never, - ActionGroupIds extends string = never ->( - alertServices: AlertServices -): LifecycleAlertServices => ({ - alertWithLifecycle: ({ id }) => alertServices.alertFactory.create(id), - getAlertStartedDate: jest.fn((id: string) => null), - getAlertUuid: jest.fn((id: string) => 'mock-alert-uuid'), - getAlertByAlertUuid: jest.fn((id: string) => Promise.resolve(null)), -}); diff --git a/x-pack/plugins/rule_registry/tsconfig.json b/x-pack/plugins/rule_registry/tsconfig.json index 71f1e13a199b5..8c244ed95e014 100644 --- a/x-pack/plugins/rule_registry/tsconfig.json +++ b/x-pack/plugins/rule_registry/tsconfig.json @@ -34,7 +34,6 @@ "@kbn/alerts-as-data-utils", "@kbn/core-http-router-server-mocks", "@kbn/core-http-server", - "@kbn/alerting-state-types", "@kbn/alerting-types" ], "exclude": [ diff --git a/x-pack/plugins/search_indices/public/constants.ts b/x-pack/plugins/search_indices/public/constants.ts index bf9cf14a4ea17..fa5d7fde6d4c8 100644 --- a/x-pack/plugins/search_indices/public/constants.ts +++ b/x-pack/plugins/search_indices/public/constants.ts @@ -7,6 +7,7 @@ export enum QueryKeys { FetchIndex = 'fetchIndex', + FetchMapping = 'fetchMapping', FetchSearchIndicesStatus = 'fetchSearchIndicesStatus', FetchUserStartPrivileges = 'fetchUserStartPrivileges', SearchDocuments = 'searchDocuments', diff --git a/x-pack/plugins/search_indices/public/hooks/api/use_index_mappings.ts b/x-pack/plugins/search_indices/public/hooks/api/use_index_mappings.ts index 0e57e17465922..1d5a83aa920ed 100644 --- a/x-pack/plugins/search_indices/public/hooks/api/use_index_mappings.ts +++ b/x-pack/plugins/search_indices/public/hooks/api/use_index_mappings.ts @@ -8,12 +8,16 @@ import { useQuery } from '@tanstack/react-query'; import { useKibana } from '../use_kibana'; import { Mappings } from '../../types'; +import { QueryKeys } from '../../constants'; +const POLLING_INTERVAL = 15 * 1000; export const useIndexMapping = (indexName: string) => { const { http } = useKibana().services; - const queryKey = ['fetchMapping', indexName]; + const queryKey = [QueryKeys.FetchMapping, indexName]; const result = useQuery({ queryKey, + refetchInterval: POLLING_INTERVAL, + refetchIntervalInBackground: true, refetchOnWindowFocus: 'always', queryFn: () => http.fetch(`/api/index_management/mapping/${encodeURIComponent(indexName)}`), diff --git a/x-pack/plugins/search_playground/public/components/summarization_panel/summarization_model.tsx b/x-pack/plugins/search_playground/public/components/summarization_panel/summarization_model.tsx index e13823d87fd8d..54c8713b35336 100644 --- a/x-pack/plugins/search_playground/public/components/summarization_panel/summarization_model.tsx +++ b/x-pack/plugins/search_playground/public/components/summarization_panel/summarization_model.tsx @@ -93,7 +93,9 @@ export const SummarizationModel: React.FC = ({ useEffect(() => { usageTracker?.click( - `${AnalyticsEvents.modelSelected}_${selectedModel!.value || selectedModel!.connectorType}` + `${AnalyticsEvents.modelSelected}_${ + selectedModel?.value || selectedModel?.connectorType || 'unknown' + }` ); }, [usageTracker, selectedModel]); diff --git a/x-pack/plugins/security/public/session/session_expiration_toast.test.tsx b/x-pack/plugins/security/public/session/session_expiration_toast.test.tsx index f2f1f6ff92f79..46b733c535ec4 100644 --- a/x-pack/plugins/security/public/session/session_expiration_toast.test.tsx +++ b/x-pack/plugins/security/public/session/session_expiration_toast.test.tsx @@ -40,10 +40,25 @@ describe('createSessionExpirationToast', () => { }); describe('SessionExpirationToast', () => { - it('renders session expiration time', () => { + it('renders session expiration time in minutes when >= 60s remaining', () => { const sessionState$ = of({ lastExtensionTime: Date.now(), - expiresInMs: 60 * 1000, + expiresInMs: 60 * 2000, + canBeExtended: true, + }); + + const { getByText } = render( + + + + ); + getByText(/You will be logged out in [0-9]+ minutes/); + }); + + it('renders session expiration time in seconds when < 60s remaining', () => { + const sessionState$ = of({ + lastExtensionTime: Date.now(), + expiresInMs: 60 * 900, canBeExtended: true, }); diff --git a/x-pack/plugins/security/public/session/session_expiration_toast.tsx b/x-pack/plugins/security/public/session/session_expiration_toast.tsx index de0c460f0f3e1..f38638a77bc33 100644 --- a/x-pack/plugins/security/public/session/session_expiration_toast.tsx +++ b/x-pack/plugins/security/public/session/session_expiration_toast.tsx @@ -44,7 +44,7 @@ export const SessionExpirationToast: FunctionComponent, + timeout: , }} /> ); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts index fe7c97b32d27b..07f314da4232b 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts @@ -29,6 +29,11 @@ export function defineDeleteRolesRoutes({ router }: RouteDefinitionParams) { request: { params: schema.object({ name: schema.string({ minLength: 1 }) }), }, + response: { + 204: { + description: 'Indicates a successful call.', + }, + }, }, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.ts index 760feb4d94950..031da53092b09 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.ts @@ -34,11 +34,30 @@ export function defineGetRolesRoutes({ version: API_VERSIONS.roles.public.v1, validate: { request: { - params: schema.object({ name: schema.string({ minLength: 1 }) }), + params: schema.object({ + name: schema.string({ + minLength: 1, + meta: { description: 'The role name.' }, + }), + }), query: schema.maybe( - schema.object({ replaceDeprecatedPrivileges: schema.maybe(schema.boolean()) }) + schema.object({ + replaceDeprecatedPrivileges: schema.maybe( + schema.boolean({ + meta: { + description: + 'If `true` and the response contains any privileges that are associated with deprecated features, they are omitted in favor of details about the appropriate replacement feature privileges.', + }, + }) + ), + }) ), }, + response: { + 200: { + description: 'Indicates a successful call.', + }, + }, }, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts index 81164e0d38c59..5979922cd64e4 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts @@ -36,9 +36,23 @@ export function defineGetAllRolesRoutes({ validate: { request: { query: schema.maybe( - schema.object({ replaceDeprecatedPrivileges: schema.maybe(schema.boolean()) }) + schema.object({ + replaceDeprecatedPrivileges: schema.maybe( + schema.boolean({ + meta: { + description: + 'If `true` and the response contains any privileges that are associated with deprecated features, they are omitted in favor of details about the appropriate replacement feature privileges.', + }, + }) + ), + }) ), }, + response: { + 200: { + description: 'Indicates a successful call.', + }, + }, }, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.test.ts index 06d6d396ce022..956ced4309304 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.test.ts @@ -149,7 +149,7 @@ describe('GET all roles by space id', () => { const paramsSchema = (config.validate as any).params; - expect(config.options).toEqual({ tags: ['access:manage_spaces'] }); + expect(config.security?.authz).toEqual({ requiredPrivileges: ['manage_spaces'] }); expect(() => paramsSchema.validate({})).toThrowErrorMatchingInlineSnapshot( `"[spaceId]: expected value of type [string] but got [undefined]"` ); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.ts index 734f0292db116..a441ba15164c1 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all_by_space.ts @@ -24,8 +24,10 @@ export function defineGetAllRolesBySpaceRoutes({ router.get( { path: '/internal/security/roles/{spaceId}', - options: { - tags: ['access:manage_spaces'], + security: { + authz: { + requiredPrivileges: ['manage_spaces'], + }, }, validate: { params: schema.object({ spaceId: schema.string({ minLength: 1 }) }), diff --git a/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.ts b/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.ts index 52c8178a651a7..4022098b9fd56 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.ts @@ -53,13 +53,28 @@ export function getPutPayloadSchema( /** * Optional text to describe the Role */ - description: schema.maybe(schema.string({ maxLength: 2048 })), + description: schema.maybe( + schema.string({ + maxLength: 2048, + meta: { description: 'A description for the role.' }, + }) + ), /** * An optional meta-data dictionary. Within the metadata, keys that begin with _ are reserved * for system usage. */ - metadata: schema.maybe(schema.recordOf(schema.string(), schema.any())), + metadata: schema.maybe( + schema.recordOf( + schema.string({ + meta: { + description: + 'A metadata dictionary. Keys that begin with `_` are reserved for system usage.', + }, + }), + schema.any() + ) + ), /** * Elasticsearch specific portion of the role definition. diff --git a/x-pack/plugins/security/server/routes/authorization/roles/post.ts b/x-pack/plugins/security/server/routes/authorization/roles/post.ts index 0fe918ee5cc3e..949553e960c9b 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/post.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/post.ts @@ -62,6 +62,11 @@ export function defineBulkCreateOrUpdateRolesRoutes({ }; }), }, + response: { + 200: { + description: 'Indicates a successful call.', + }, + }, }, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.ts index 16e2ab819e781..268c84ff7420e 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.ts @@ -26,6 +26,8 @@ export function definePutRolesRoutes({ path: '/api/security/role/{name}', access: 'public', summary: `Create or update a role`, + description: + 'Create a new Kibana role or update the attributes of an existing role. Kibana roles are stored in the Elasticsearch native realm.', options: { tags: ['oas-tag:roles'], }, @@ -35,8 +37,19 @@ export function definePutRolesRoutes({ version: API_VERSIONS.roles.public.v1, validate: { request: { - params: schema.object({ name: schema.string({ minLength: 1, maxLength: 1024 }) }), - query: schema.object({ createOnly: schema.boolean({ defaultValue: false }) }), + params: schema.object({ + name: schema.string({ + minLength: 1, + maxLength: 1024, + meta: { description: 'The role name.' }, + }), + }), + query: schema.object({ + createOnly: schema.boolean({ + defaultValue: false, + meta: { description: 'When true, a role is not overwritten if it already exists.' }, + }), + }), body: getPutPayloadSchema(() => { const privileges = authz.privileges.get(); return { @@ -45,6 +58,11 @@ export function definePutRolesRoutes({ }; }), }, + response: { + 204: { + description: 'Indicates a successful call.', + }, + }, }, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/session_management/invalidate.test.ts b/x-pack/plugins/security/server/routes/session_management/invalidate.test.ts index fbc14015d80c1..12c31be12dd57 100644 --- a/x-pack/plugins/security/server/routes/session_management/invalidate.test.ts +++ b/x-pack/plugins/security/server/routes/session_management/invalidate.test.ts @@ -46,9 +46,10 @@ describe('Invalidate sessions routes', () => { expect(routeConfig.options).toEqual({ access: 'public', summary: 'Invalidate user sessions', - tags: ['access:sessionManagement'], }); + expect(routeConfig.security?.authz).toEqual({ requiredPrivileges: ['sessionManagement'] }); + const bodySchema = (routeConfig.validate as any).body as ObjectType; expect(() => bodySchema.validate({})).toThrowErrorMatchingInlineSnapshot( `"[match]: expected at least one defined value but got [undefined]"` diff --git a/x-pack/plugins/security/server/routes/session_management/invalidate.ts b/x-pack/plugins/security/server/routes/session_management/invalidate.ts index a45d8f00c1ca4..bbc81c21706d9 100644 --- a/x-pack/plugins/security/server/routes/session_management/invalidate.ts +++ b/x-pack/plugins/security/server/routes/session_management/invalidate.ts @@ -37,6 +37,11 @@ export function defineInvalidateSessionsRoutes({ ), }), }, + security: { + authz: { + requiredPrivileges: ['sessionManagement'], + }, + }, options: { // The invalidate session API was introduced to address situations where the session index // could grow rapidly - when session timeouts are disabled, or with anonymous access. @@ -44,7 +49,7 @@ export function defineInvalidateSessionsRoutes({ // anonymous access. However, keeping this endpoint available internally in serverless would // be useful in situations where we need to batch-invalidate user sessions. access: buildFlavor === 'serverless' ? 'internal' : 'public', - tags: ['access:sessionManagement'], + summary: `Invalidate user sessions`, }, }, diff --git a/x-pack/plugins/security/server/routes/user_profile/bulk_get.test.ts b/x-pack/plugins/security/server/routes/user_profile/bulk_get.test.ts index f5d449bd8423d..eece6b58f8f01 100644 --- a/x-pack/plugins/security/server/routes/user_profile/bulk_get.test.ts +++ b/x-pack/plugins/security/server/routes/user_profile/bulk_get.test.ts @@ -51,7 +51,7 @@ describe('Bulk get profile routes', () => { }); it('correctly defines route.', () => { - expect(routeConfig.options).toEqual({ tags: ['access:bulkGetUserProfiles'] }); + expect(routeConfig.security?.authz).toEqual({ requiredPrivileges: ['bulkGetUserProfiles'] }); const bodySchema = (routeConfig.validate as any).body as ObjectType; expect(() => bodySchema.validate(0)).toThrowErrorMatchingInlineSnapshot( diff --git a/x-pack/plugins/security/server/routes/user_profile/bulk_get.ts b/x-pack/plugins/security/server/routes/user_profile/bulk_get.ts index 20da1d573901f..0ffe760d57d52 100644 --- a/x-pack/plugins/security/server/routes/user_profile/bulk_get.ts +++ b/x-pack/plugins/security/server/routes/user_profile/bulk_get.ts @@ -24,7 +24,11 @@ export function defineBulkGetUserProfilesRoute({ dataPath: schema.maybe(schema.string()), }), }, - options: { tags: ['access:bulkGetUserProfiles'] }, + security: { + authz: { + requiredPrivileges: ['bulkGetUserProfiles'], + }, + }, }, createLicensedRouteHandler(async (context, request, response) => { const userProfileServiceInternal = getUserProfileService(); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts index 2dd83ca89bee0..228bf1e515675 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts @@ -36,6 +36,7 @@ export const EngineDescriptor = z.object({ status: EngineStatus, filter: z.string().optional(), fieldHistoryLength: z.number().int(), + error: z.object({}).optional(), }); export type InspectQuery = z.infer; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml index 810961392aad1..00b100516b76c 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml @@ -30,6 +30,8 @@ components: type: string fieldHistoryLength: type: integer + error: + type: object EngineStatus: type: string diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.gen.ts index 151fb05f41856..0ee6445dd71e3 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.gen.ts @@ -54,7 +54,7 @@ export const GetNotesRequestQuery = z.object({ sortField: z.string().nullable().optional(), sortOrder: z.string().nullable().optional(), filter: z.string().nullable().optional(), - userFilter: z.string().nullable().optional(), + createdByFilter: z.string().nullable().optional(), associatedFilter: AssociatedFilterType.optional(), }); export type GetNotesRequestQueryInput = z.input; diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml index 019c11baa7386..e142126817707 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml @@ -52,7 +52,7 @@ paths: type: string nullable: true - in: query - name: userFilter + name: createdByFilter schema: nullable: true type: string diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts index 534d7e5c2b8a4..19aa53eca6649 100644 --- a/x-pack/plugins/security_solution/common/endpoint/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -55,6 +55,9 @@ export const telemetryIndexPattern = 'metrics-endpoint.telemetry-*'; export const ENDPOINT_HEARTBEAT_INDEX = '.logs-endpoint.heartbeat-default'; export const ENDPOINT_HEARTBEAT_INDEX_PATTERN = '.logs-endpoint.heartbeat-*'; +// Endpoint diagnostics index +export const DEFAULT_DIAGNOSTIC_INDEX_PATTERN = '.logs-endpoint.diagnostic.collection-*' as const; + // File storage indexes supporting endpoint Upload/download export const FILE_STORAGE_METADATA_INDEX = getFileMetadataIndexName('endpoint'); export const FILE_STORAGE_DATA_INDEX = getFileDataIndexName('endpoint'); diff --git a/x-pack/plugins/security_solution/common/endpoint/utils/index_name_utilities.test.ts b/x-pack/plugins/security_solution/common/endpoint/utils/index_name_utilities.test.ts new file mode 100644 index 0000000000000..25eb35bf88872 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/utils/index_name_utilities.test.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { buildIndexNameWithNamespace } from './index_name_utilities'; + +describe('index name utilities', () => { + describe('buildIndexNameWithNamespace()', () => { + test.each(['logs-endpoint.foo', 'logs-endpoint.foo-', 'logs-endpoint.foo-*'])( + `should build correct index name for: %s`, + (prefix) => { + expect(buildIndexNameWithNamespace(prefix, 'bar')).toEqual('logs-endpoint.foo-bar'); + } + ); + }); +}); diff --git a/x-pack/plugins/security_solution/common/endpoint/utils/index_name_utilities.ts b/x-pack/plugins/security_solution/common/endpoint/utils/index_name_utilities.ts new file mode 100644 index 0000000000000..80db5392f653f --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/utils/index_name_utilities.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Builds an index name that includes the `namespace` using the provided index name prefix or pattern. + * + * @param indexNamePrefixOrPattern + * @param namespace + * + * @example + * + * buildIndexNameWithNamespace('logs-foo.bar-*', 'default'); // == 'logs-foo.bar-default' + * buildIndexNameWithNamespace('logs-foo.bar', 'default'); // == 'logs-foo.bar-default' + * buildIndexNameWithNamespace('logs-foo.bar-', 'default'); // == 'logs-foo.bar-default' + */ +export const buildIndexNameWithNamespace = ( + indexNamePrefixOrPattern: string, + namespace: string +): string => { + if (indexNamePrefixOrPattern.endsWith('*')) { + const hasDash = indexNamePrefixOrPattern.endsWith('-*'); + return `${indexNamePrefixOrPattern.substring(0, indexNamePrefixOrPattern.length - 1)}${ + hasDash ? '' : '-' + }${namespace}`; + } + + return `${indexNamePrefixOrPattern}${ + indexNamePrefixOrPattern.endsWith('-') ? '' : '-' + }${namespace}`; +}; diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 792b6352912b3..892b0a0226639 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -94,9 +94,9 @@ export const allowedExperimentalValues = Object.freeze({ endpointManagementSpaceAwarenessEnabled: false, /** - * Enables new notes + * Disables new notes */ - securitySolutionNotesEnabled: false, + securitySolutionNotesDisabled: false, /** * Disables entity and alert previews @@ -111,7 +111,7 @@ export const allowedExperimentalValues = Object.freeze({ /** * Enables new Knowledge Base Entries features, introduced in `8.15.0`. */ - assistantKnowledgeBaseByDefault: false, + assistantKnowledgeBaseByDefault: true, /** * Enables the Managed User section inside the new user details flyout. diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml index fef2850b44c90..60bd38c246f34 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml @@ -785,6 +785,8 @@ components: EngineDescriptor: type: object properties: + error: + type: object fieldHistoryLength: type: integer filter: diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 7a928b357603b..562bf9b80d3ea 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -98,7 +98,7 @@ paths: nullable: true type: string - in: query - name: userFilter + name: createdByFilter schema: nullable: true type: string diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml index 3a5054f17a460..fc63924118968 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml @@ -785,6 +785,8 @@ components: EngineDescriptor: type: object properties: + error: + type: object fieldHistoryLength: type: integer filter: diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 6ffcd585d8160..a68919aa0e1fd 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -98,7 +98,7 @@ paths: nullable: true type: string - in: query - name: userFilter + name: createdByFilter schema: nullable: true type: string diff --git a/x-pack/plugins/security_solution/public/app/components/top_values_popover/top_values_popover.tsx b/x-pack/plugins/security_solution/public/app/components/top_values_popover/top_values_popover.tsx index f03be50f39660..3f7842c4a2e92 100644 --- a/x-pack/plugins/security_solution/public/app/components/top_values_popover/top_values_popover.tsx +++ b/x-pack/plugins/security_solution/public/app/components/top_values_popover/top_values_popover.tsx @@ -16,7 +16,7 @@ import { useKibana } from '../../../common/lib/kibana'; export const TopValuesPopover = React.memo(() => { const { pathname } = useLocation(); - const { browserFields, indexPattern } = useSourcererDataView(getScopeFromPath(pathname)); + const { browserFields, sourcererDataView } = useSourcererDataView(getScopeFromPath(pathname)); const { services: { topValuesPopover }, } = useKibana(); @@ -44,7 +44,7 @@ export const TopValuesPopover = React.memo(() => { showLegend scopeId={data.scopeId} toggleTopN={onClose} - indexPattern={indexPattern} + dataViewSpec={sourcererDataView} browserFields={browserFields} /> diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx index c03dc319952b5..8d4088b19f9b6 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx @@ -7,14 +7,13 @@ import React, { memo, useEffect, useState } from 'react'; import type { Criteria, EuiBasicTableColumn } from '@elastic/eui'; -import { EuiSpacer, EuiIcon, EuiPanel, EuiLink, EuiText, EuiBasicTable } from '@elastic/eui'; +import { EuiSpacer, EuiPanel, EuiText, EuiBasicTable, EuiIcon } from '@elastic/eui'; import { useMisconfigurationFindings } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_findings'; import { i18n } from '@kbn/i18n'; import type { CspFinding, CspFindingResult } from '@kbn/cloud-security-posture-common'; import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { euiThemeVars } from '@kbn/ui-theme'; import { DistributionBar } from '@kbn/security-solution-distribution-bar'; -import { useNavigateFindings } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; import type { CspBenchmarkRuleMetadata } from '@kbn/cloud-security-posture-common/schema/rules/latest'; import { CspEvaluationBadge } from '@kbn/cloud-security-posture'; import { @@ -24,6 +23,9 @@ import { uiMetricService, } from '@kbn/cloud-security-posture-common/utils/ui_metrics'; import { METRIC_TYPE } from '@kbn/analytics'; +import { useGetNavigationUrlParams } from '@kbn/cloud-security-posture/src/hooks/use_get_navigation_url_params'; +import { SecurityPageName } from '@kbn/deeplinks-security'; +import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; type MisconfigurationFindingDetailFields = Pick; @@ -114,18 +116,14 @@ export const MisconfigurationFindingsDetailsTable = memo( } }; - const navToFindings = useNavigateFindings(); + const getNavUrlParams = useGetNavigationUrlParams(); - const navToFindingsByRuleAndResourceId = (ruleId: string, resourceId: string) => { - navToFindings({ 'rule.id': ruleId, 'resource.id': resourceId }); + const getFindingsPageUrlFilteredByRuleAndResourceId = (ruleId: string, resourceId: string) => { + return getNavUrlParams({ 'rule.id': ruleId, 'resource.id': resourceId }, 'configurations'); }; - const navToFindingsByName = (name: string, queryField: 'host.name' | 'user.name') => { - uiMetricService.trackUiMetric( - METRIC_TYPE.CLICK, - NAV_TO_FINDINGS_BY_RULE_NAME_FRPOM_ENTITY_FLYOUT - ); - navToFindings({ [queryField]: name }, ['rule.name']); + const getFindingsPageUrl = (name: string, queryField: 'host.name' | 'user.name') => { + return getNavUrlParams({ [queryField]: name }, 'configurations', ['rule.name']); }; const columns: Array> = [ @@ -134,13 +132,23 @@ export const MisconfigurationFindingsDetailsTable = memo( name: '', width: '5%', render: (rule: CspBenchmarkRuleMetadata, finding: MisconfigurationFindingDetailFields) => ( - { - navToFindingsByRuleAndResourceId(rule?.id, finding?.resource?.id); + uiMetricService.trackUiMetric( + METRIC_TYPE.CLICK, + NAV_TO_FINDINGS_BY_RULE_NAME_FRPOM_ENTITY_FLYOUT + ); }} > - + ), }, { @@ -170,13 +178,16 @@ export const MisconfigurationFindingsDetailsTable = memo( return ( <> - { uiMetricService.trackUiMetric( METRIC_TYPE.CLICK, NAV_TO_FINDINGS_BY_HOST_NAME_FRPOM_ENTITY_FLYOUT ); - navToFindingsByName(queryName, fieldName); }} > {i18n.translate( @@ -186,7 +197,7 @@ export const MisconfigurationFindingsDetailsTable = memo( } )} - + diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx index f3422564186ed..82c5f91bf4250 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx @@ -7,12 +7,11 @@ import React, { memo, useEffect, useState } from 'react'; import type { Criteria, EuiBasicTableColumn } from '@elastic/eui'; -import { EuiSpacer, EuiIcon, EuiPanel, EuiLink, EuiText, EuiBasicTable } from '@elastic/eui'; +import { EuiSpacer, EuiPanel, EuiText, EuiBasicTable, EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import type { VulnSeverity } from '@kbn/cloud-security-posture-common'; import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { DistributionBar } from '@kbn/security-solution-distribution-bar'; -import { useNavigateVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; import { useVulnerabilitiesFindings } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_findings'; import type { CspVulnerabilityFinding, @@ -29,6 +28,9 @@ import { uiMetricService, } from '@kbn/cloud-security-posture-common/utils/ui_metrics'; import { METRIC_TYPE } from '@kbn/analytics'; +import { SecurityPageName } from '@kbn/deeplinks-security'; +import { useGetNavigationUrlParams } from '@kbn/cloud-security-posture/src/hooks/use_get_navigation_url_params'; +import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; type VulnerabilitiesFindingDetailFields = Pick< CspVulnerabilityFinding, @@ -38,6 +40,7 @@ type VulnerabilitiesFindingDetailFields = Pick< interface VulnerabilitiesPackage extends Vulnerability { package: { name: string; + version: string; }; } @@ -94,20 +97,27 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ queryName }: { queryN } }; - const navToVulnerabilities = useNavigateVulnerabilities(); + const getNavUrlParams = useGetNavigationUrlParams(); - const navToVulnerabilitiesByName = (name: string, queryField: 'host.name' | 'user.name') => { - navToVulnerabilities({ [queryField]: name }); + const getVulnerabilityUrl = (name: string, queryField: 'host.name' | 'user.name') => { + return getNavUrlParams({ [queryField]: name }, 'vulnerabilities'); }; - const navToVulnerabilityByVulnerabilityAndResourceId = ( + const getVulnerabilityUrlFilteredByVulnerabilityAndResourceId = ( vulnerabilityId: string, - resourceId: string + resourceId: string, + vulnerabilityPackageName: string, + vulnerabilityPackageVersion: string ) => { - navToVulnerabilities({ - 'vulnerability.id': vulnerabilityId, - 'resource.id': resourceId, - }); + return getNavUrlParams( + { + 'vulnerability.id': vulnerabilityId, + 'resource.id': resourceId, + 'vulnerability.package.name': vulnerabilityPackageName, + 'vulnerability.package.version': vulnerabilityPackageVersion, + }, + 'vulnerabilities' + ); }; const columns: Array> = [ @@ -119,16 +129,19 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ queryName }: { queryN vulnerability: VulnerabilitiesPackage, finding: VulnerabilitiesFindingDetailFields ) => ( - { - navToVulnerabilityByVulnerabilityAndResourceId( - vulnerability?.id, - finding?.resource?.id || '' - ); - }} + - + ), }, { @@ -189,20 +202,23 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ queryName }: { queryN return ( <> - { uiMetricService.trackUiMetric( METRIC_TYPE.CLICK, NAV_TO_FINDINGS_BY_HOST_NAME_FRPOM_ENTITY_FLYOUT ); - navToVulnerabilitiesByName(queryName, 'host.name'); }} > {i18n.translate('xpack.securitySolution.flyout.left.insights.vulnerability.tableTitle', { defaultMessage: 'Vulnerability ', })} - + ; - numberOfPassedFindings?: number; - numberOfFailedFindings?: number; }) => { return ( diff --git a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx index 931c519ae9b57..5ec3e0c2d0e3d 100644 --- a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx @@ -93,8 +93,8 @@ const RowActionComponent = ({ [columnHeaders, timelineNonEcsData] ); - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const handleOnEventDetailPanelOpened = useCallback(() => { @@ -175,12 +175,12 @@ const RowActionComponent = ({ showCheckboxes={showCheckboxes} tabType={tabType} timelineId={tableId} - toggleShowNotes={securitySolutionNotesEnabled ? toggleShowNotes : undefined} + toggleShowNotes={securitySolutionNotesDisabled ? undefined : toggleShowNotes} width={width} setEventsLoading={setEventsLoading} setEventsDeleted={setEventsDeleted} refetch={refetch} - showNotes={securitySolutionNotesEnabled ? true : false} + showNotes={!securitySolutionNotesDisabled} /> )} diff --git a/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx index dd5cbb4131b4c..0a5156bddcc99 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx @@ -16,6 +16,9 @@ import { useGlobalFullScreen } from '../../containers/use_full_screen'; import { licenseService } from '../../hooks/use_license'; import { mockHistory } from '../../mock/router'; import { DEFAULT_EVENTS_STACK_BY_VALUE } from './histogram_configurations'; +import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; + +jest.mock('../../hooks/use_experimental_features'); const mockGetDefaultControlColumn = jest.fn(); jest.mock('../../../timelines/components/timeline/body/control_columns', () => ({ @@ -95,6 +98,7 @@ describe('EventsQueryTabBody', () => { }; beforeEach(() => { + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false); jest.clearAllMocks(); }); @@ -106,7 +110,7 @@ describe('EventsQueryTabBody', () => { ); expect(queryByText('MockedStatefulEventsViewer')).toBeInTheDocument(); - expect(mockGetDefaultControlColumn).toHaveBeenCalledWith(4); + expect(mockGetDefaultControlColumn).toHaveBeenCalledWith(5); }); it('renders the matrix histogram when globalFullScreen is false', () => { @@ -186,7 +190,19 @@ describe('EventsQueryTabBody', () => { expect(spy).toHaveBeenCalled(); }); - it('only have 4 columns on Action bar for non-Enterprise user', () => { + it('should have 5 columns on Action bar for non-Enterprise user', () => { + render( + + + + ); + + expect(mockGetDefaultControlColumn).toHaveBeenCalledWith(5); + }); + + it('should have 4 columns on Action bar for non-Enterprise user and securitySolutionNotesDisabled is true', () => { + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); + render( @@ -196,10 +212,23 @@ describe('EventsQueryTabBody', () => { expect(mockGetDefaultControlColumn).toHaveBeenCalledWith(4); }); - it('shows 5 columns on Action bar for Enterprise user', () => { + it('should 6 columns on Action bar for Enterprise user', () => { const licenseServiceMock = licenseService as jest.Mocked; + licenseServiceMock.isEnterprise.mockReturnValue(true); + render( + + + + ); + + expect(mockGetDefaultControlColumn).toHaveBeenCalledWith(6); + }); + + it('should 6 columns on Action bar for Enterprise user and securitySolutionNotesDisabled is true', () => { + const licenseServiceMock = licenseService as jest.Mocked; licenseServiceMock.isEnterprise.mockReturnValue(true); + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); render( diff --git a/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx b/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx index 92c94549ca891..70e56f4a8b4d2 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx @@ -75,10 +75,10 @@ const EventsQueryTabBodyComponent: React.FC = const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); const isEnterprisePlus = useLicense().isEnterprise(); let ACTION_BUTTON_COUNT = isEnterprisePlus ? 6 : 5; - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); - if (!securitySolutionNotesEnabled) { + if (securitySolutionNotesDisabled) { ACTION_BUTTON_COUNT--; } const leadingControlColumns = useMemo( diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx index e251370c7e4d3..b86f65e020a11 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -180,9 +180,8 @@ const StatefulEventsViewerComponent: React.FC = ({ onEventDetailsPanelOpened(); }, [activeStep, incrementStep, isTourAnchor, isTourShown, onEventDetailsPanelOpened]); - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); /* only applicable for new event based notes */ @@ -270,7 +270,7 @@ const ActionsComponent: React.FC = ({ /* note ids associated with the document AND attached to the current timeline, used for pinning */ const timelineNoteIds = useMemo(() => { - if (securitySolutionNotesEnabled) { + if (!securitySolutionNotesDisabled) { // if timeline is unsaved, there is no notes associated to timeline yet return savedObjectId ? documentBasedNotesInTimeline.map((note) => note.noteId) : []; } @@ -280,13 +280,13 @@ const ActionsComponent: React.FC = ({ eventId, documentBasedNotesInTimeline, savedObjectId, - securitySolutionNotesEnabled, + securitySolutionNotesDisabled, ]); /* note count of the document */ const notesCount = useMemo( - () => (securitySolutionNotesEnabled ? documentBasedNotes.length : timelineNoteIds.length), - [documentBasedNotes, timelineNoteIds, securitySolutionNotesEnabled] + () => (securitySolutionNotesDisabled ? timelineNoteIds.length : documentBasedNotes.length), + [documentBasedNotes, timelineNoteIds, securitySolutionNotesDisabled] ); // we hide the analyzer icon if the data is not available for the resolver diff --git a/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/index.tsx b/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/index.tsx index 0496033b0ab45..e8fa43d0a189e 100644 --- a/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/index.tsx @@ -281,7 +281,7 @@ const InsightEditorComponent = ({ onCancel, }: EuiMarkdownEditorUiPluginEditorProps) => { const isEditMode = node != null; - const { indexPattern } = useSourcererDataView(SourcererScopeName.default); + const { sourcererDataView } = useSourcererDataView(SourcererScopeName.default); const { unifiedSearch: { ui: { FiltersBuilderLazy }, @@ -400,7 +400,7 @@ const InsightEditorComponent = ({ ); }, [labelController.field.value, providers, dataView]); const filtersStub = useMemo(() => { - const index = indexPattern && indexPattern.getName ? indexPattern.getName() : '*'; + const index = sourcererDataView.name ?? '*'; return [ { $state: { @@ -414,7 +414,7 @@ const InsightEditorComponent = ({ }, }, ]; - }, [indexPattern]); + }, [sourcererDataView]); const isPlatinum = useLicense().isAtLeast('platinum'); return ( diff --git a/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/use_insight_query.ts b/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/use_insight_query.ts index 43323a6b62f7a..a88485237e21c 100644 --- a/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/use_insight_query.ts +++ b/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/use_insight_query.ts @@ -41,7 +41,7 @@ export const useInsightQuery = ({ }: UseInsightQuery): UseInsightQueryResult => { const { uiSettings } = useKibana().services; const esQueryConfig = useMemo(() => getEsQueryConfig(uiSettings), [uiSettings]); - const { browserFields, selectedPatterns, indexPattern, dataViewId } = useSourcererDataView( + const { browserFields, selectedPatterns, sourcererDataView, dataViewId } = useSourcererDataView( SourcererScopeName.timeline ); const [hasError, setHasError] = useState(false); @@ -51,7 +51,7 @@ export const useInsightQuery = ({ const parsedCombinedQueries = combineQueries({ config: esQueryConfig, dataProviders, - indexPattern, + indexPattern: sourcererDataView, browserFields, filters, kqlQuery: { @@ -66,7 +66,7 @@ export const useInsightQuery = ({ setHasError(true); return null; } - }, [browserFields, dataProviders, esQueryConfig, hasError, indexPattern, filters]); + }, [browserFields, dataProviders, esQueryConfig, hasError, sourcererDataView, filters]); const [dataLoadingState, { events, totalCount }] = useTimelineEvents({ dataViewId, diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx index 6c45faf63e566..2359aed5d6949 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx @@ -10,7 +10,7 @@ import { mount } from 'enzyme'; import React from 'react'; import { waitFor } from '@testing-library/react'; import { mockBrowserFields } from '../../containers/source/mock'; -import { mockGlobalState, TestProviders, mockIndexPattern, createMockStore } from '../../mock'; +import { mockGlobalState, TestProviders, createMockStore, mockDataViewSpec } from '../../mock'; import type { State } from '../../store'; import type { Props } from './top_n'; @@ -145,7 +145,7 @@ const store = createMockStore(state); const testProps = { browserFields: mockBrowserFields, field, - indexPattern: mockIndexPattern, + indexPattern: mockDataViewSpec, scopeId: TableId.hostsPageEvents, toggleTopN: jest.fn(), onFilterAdded: jest.fn(), diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx index cdad88b247f2d..11ec06908afe7 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx @@ -9,8 +9,8 @@ import React, { useMemo } from 'react'; import type { ConnectedProps } from 'react-redux'; import { connect } from 'react-redux'; -import type { DataViewBase, Filter, Query } from '@kbn/es-query'; -import { getEsQueryConfig } from '@kbn/data-plugin/common'; +import type { Filter, Query } from '@kbn/es-query'; +import { type DataViewSpec, getEsQueryConfig } from '@kbn/data-plugin/common'; import { isActiveTimeline } from '../../../helpers'; import { InputsModelId } from '../../store/inputs/constants'; import { useGlobalTime } from '../../containers/use_global_time'; @@ -77,7 +77,7 @@ const connector = connect(makeMapStateToProps); export interface OwnProps { browserFields: BrowserFields; field: string; - indexPattern: DataViewBase; + dataViewSpec?: DataViewSpec; scopeId?: string; toggleTopN: () => void; onFilterAdded?: () => void; @@ -97,7 +97,7 @@ const StatefulTopNComponent: React.FC = ({ browserFields, dataProviders, field, - indexPattern, + dataViewSpec: indexPattern, globalFilters = EMPTY_FILTERS, globalQuery = EMPTY_QUERY, kqlMode, diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/top_n.test.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/top_n.test.tsx index 79ab897e34bfc..73086e2d584be 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/top_n.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/top_n.test.tsx @@ -10,7 +10,7 @@ import { mount } from 'enzyme'; import React from 'react'; import { waitFor } from '@testing-library/react'; -import { TestProviders, mockIndexPattern } from '../../mock'; +import { TestProviders, mockDataViewSpec } from '../../mock'; import { allEvents, defaultOptions } from './helpers'; import type { Props as TopNProps } from './top_n'; @@ -107,7 +107,7 @@ describe('TopN', () => { field, filters: [], from: '2020-04-14T00:31:47.695Z', - indexPattern: mockIndexPattern, + indexPattern: mockDataViewSpec, options: defaultOptions, query, setAbsoluteRangeDatePickerTarget: InputsModelId.global, diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/top_n.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/top_n.tsx index 48386a71a07fc..5c3cecfe3fce3 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/top_n.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/top_n.tsx @@ -9,7 +9,8 @@ import { EuiButtonIcon, EuiSuperSelect } from '@elastic/eui'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; -import type { DataViewBase, Filter, Query } from '@kbn/es-query'; +import type { Filter, Query } from '@kbn/es-query'; +import type { DataViewSpec } from '@kbn/data-plugin/common'; import type { GlobalTimeArgs } from '../../containers/use_global_time'; import { EventsByDataset } from '../../../overview/components/events_by_dataset'; import { SignalsByCategory } from '../../../overview/components/signals_by_category'; @@ -48,7 +49,7 @@ export interface Props extends Pick = ({ filters={applicableFilters} from={from} headerChildren={headerChildren} - indexPattern={indexPattern} + dataViewSpec={indexPattern} onlyField={field} paddingSize={paddingSize} query={query} diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_by_status_donut.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_by_status_donut.test.ts index 98f64ab00152a..7240f1de35ac6 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_by_status_donut.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_by_status_donut.test.ts @@ -20,6 +20,7 @@ jest.mock('../../../../../../sourcerer/containers', () => ({ dataViewId: 'security-solution-my-test', indicesExist: true, selectedPatterns: ['signal-index'], + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_histogram.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_histogram.test.ts index dd4b7050632e0..d712f69a295a1 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_histogram.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_histogram.test.ts @@ -20,6 +20,7 @@ jest.mock('../../../../../../sourcerer/containers', () => ({ dataViewId: 'security-solution-my-test', indicesExist: true, selectedPatterns: ['signal-index'], + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_table.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_table.test.ts index 399bf374bb707..cec804e090f10 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_table.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/alerts_table.test.ts @@ -32,6 +32,7 @@ jest.mock('../../../../../../sourcerer/containers', () => ({ dataViewId: 'security-solution-my-test', indicesExist: true, selectedPatterns: ['signal-index'], + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/rule_preview.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/rule_preview.test.ts index 6c704ae9e532f..73f871def8ee9 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/rule_preview.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/alerts/rule_preview.test.ts @@ -22,6 +22,7 @@ jest.mock('../../../../../../sourcerer/containers', () => ({ dataViewId: 'security-solution-my-test', indicesExist: true, selectedPatterns: ['signal-index'], + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/authentication.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/authentication.test.ts index 1abba440af95c..6d2b510da4897 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/authentication.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/authentication.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/event.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/event.test.ts index a7855ff7367bd..b29b10f8b9b4e 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/event.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/event.test.ts @@ -22,6 +22,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/external_alert.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/external_alert.test.ts index 5c4998a03524c..8fd7c0a57cc6e 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/external_alert.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/external_alert.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_host_area.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_host_area.test.ts index 9c7ff9e3acf7b..6ab9c4b599057 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_host_area.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_host_area.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_host_metric.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_host_metric.test.ts index d2714b44c2930..0a146fae457ef 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_host_metric.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_host_metric.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_area.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_area.test.ts index 3a591a1eb2b1a..003176c784c17 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_area.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_area.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_bar.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_bar.test.ts index fa3f49f7b1054..5121aab8bf8bf 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_bar.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_bar.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_destination_metric.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_destination_metric.test.ts index a2ae91e0c0422..eff175a0b5466 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_destination_metric.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_destination_metric.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_source_metric.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_source_metric.test.ts index e94efb88b58ad..cd9f68d632478 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_source_metric.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_source_metric.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/dns_top_domains.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/dns_top_domains.test.ts index e398b33f0570b..bb0d0cb5c9012 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/dns_top_domains.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/dns_top_domains.test.ts @@ -19,6 +19,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_dns_queries.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_dns_queries.test.ts index 9e766f03163d8..6c0cb3d3d8198 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_dns_queries.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_dns_queries.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_network_events.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_network_events.test.ts index ef921e3601373..6e2a66567f1e0 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_network_events.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_network_events.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_tls_handshakes.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_tls_handshakes.test.ts index d6c4eb3fadc25..f0b87c0ee221a 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_tls_handshakes.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_tls_handshakes.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_flow_ids.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_flow_ids.test.ts index ba0cd4f60fe99..414bc1263e93e 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_flow_ids.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_flow_ids.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_area.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_area.test.ts index 7a19fa5e024fc..9ac8d9733d157 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_area.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_area.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_bar.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_bar.test.ts index 9b4cd751ee54b..25fc271e7ef62 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_bar.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_bar.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_destination_metric.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_destination_metric.test.ts index 5c3479c53c410..a7fd2208bec47 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_destination_metric.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_destination_metric.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_source_metric.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_source_metric.test.ts index a076dc40a46e4..6208d5c97bdc9 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_source_metric.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_source_metric.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_total_users_area.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_total_users_area.test.ts index 50b72daa8d532..a34e98b70e607 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_total_users_area.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_total_users_area.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_total_users_metric.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_total_users_metric.test.ts index fae4b63083906..affbdd4a77905 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_total_users_metric.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_total_users_metric.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentication_metric_failure.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentication_metric_failure.test.ts index 6c9de837708e6..4c93280dd3b9e 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentication_metric_failure.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentication_metric_failure.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_area.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_area.test.ts index 3f00f93c24875..599ceb9745f53 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_area.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_area.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_bar.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_bar.test.ts index 6a6cd9cc7ad3b..2231459b347ed 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_bar.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_bar.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_metric_success.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_metric_success.test.ts index 367a883e93dec..3ab3de0592d77 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_metric_success.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_metric_success.test.ts @@ -17,6 +17,7 @@ jest.mock('../../../../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.test.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.test.tsx index 22fa8c774eebe..8ed7d40519ace 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.test.tsx @@ -35,6 +35,7 @@ describe('useLensAttributes', () => { dataViewId: 'security-solution-default', indicesExist: true, selectedPatterns: ['auditbeat-*'], + sourcererDataView: {}, }); (useRouteSpy as jest.Mock).mockReturnValue([ { @@ -237,6 +238,7 @@ describe('useLensAttributes', () => { dataViewId: 'security-solution-default', indicesExist: false, selectedPatterns: ['auditbeat-*'], + sourcererDataView: {}, }); const { result } = renderHook( () => @@ -255,6 +257,7 @@ describe('useLensAttributes', () => { dataViewId: 'security-solution-default', indicesExist: false, selectedPatterns: ['auditbeat-*'], + sourcererDataView: {}, }); const { result } = renderHook( () => @@ -273,6 +276,7 @@ describe('useLensAttributes', () => { dataViewId: 'security-solution-default', indicesExist: false, selectedPatterns: ['auditbeat-*'], + sourcererDataView: {}, }); const { result } = renderHook( () => @@ -294,6 +298,7 @@ describe('useLensAttributes', () => { dataViewId: 'security-solution-default', indicesExist: false, selectedPatterns: ['auditbeat-*'], + sourcererDataView: {}, }); const { result } = renderHook( () => diff --git a/x-pack/plugins/security_solution/public/common/lib/kuery/index.test.ts b/x-pack/plugins/security_solution/public/common/lib/kuery/index.test.ts index 095f49d2f1e0e..98c59d415d447 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kuery/index.test.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kuery/index.test.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import type { DataProvider } from '../../../../common/types/timeline'; import { convertToBuildEsQuery, buildGlobalQuery } from '.'; -import { mockIndexPattern } from '../../mock'; +import { mockDataViewSpec } from '../../mock'; describe('convertToBuildEsQuery', () => { /** @@ -61,7 +61,7 @@ describe('convertToBuildEsQuery', () => { const [converted, _] = convertToBuildEsQuery({ config, queries: queryWithNestedFields, - indexPattern: mockIndexPattern, + dataViewSpec: mockDataViewSpec, filters, }); @@ -176,7 +176,7 @@ describe('convertToBuildEsQuery', () => { const [converted, _] = convertToBuildEsQuery({ config: configWithOverride, queries: queryWithNestedFields, - indexPattern: mockIndexPattern, + dataViewSpec: mockDataViewSpec, filters, }); diff --git a/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts b/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts index b3f98a8483f30..c3ae79dd80e95 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts @@ -14,6 +14,7 @@ import { } from '@kbn/es-query'; import { get, isEmpty } from 'lodash/fp'; import memoizeOne from 'memoize-one'; +import type { DataViewSpec } from '@kbn/data-plugin/common'; import { prepareKQLParam } from '../../../../common/utils/kql'; import type { BrowserFields } from '../../../../common/search_strategy'; import type { DataProvider, DataProvidersAnd } from '../../../../common/types'; @@ -29,7 +30,7 @@ export type PrimitiveOrArrayOfPrimitives = export interface CombineQueries { config: EsQueryConfig; dataProviders: DataProvider[]; - indexPattern: DataViewBase; + indexPattern?: DataViewSpec; browserFields: BrowserFields; filters: Filter[]; kqlQuery: Query; @@ -199,14 +200,18 @@ export const isDataProviderEmpty = (dataProviders: DataProvider[]) => { return isEmpty(dataProviders) || isEmpty(dataProviders.filter((d) => d.enabled === true)); }; +export const dataViewSpecToViewBase = (dataViewSpec?: DataViewSpec): DataViewBase => { + return { title: dataViewSpec?.title || '', fields: Object.values(dataViewSpec?.fields || {}) }; +}; + export const convertToBuildEsQuery = ({ config, - indexPattern, + dataViewSpec, queries, filters, }: { config: EsQueryConfig; - indexPattern: DataViewBase | undefined; + dataViewSpec: DataViewSpec | undefined; queries: Query[]; filters: Filter[]; }): [string, undefined] | [undefined, Error] => { @@ -214,7 +219,7 @@ export const convertToBuildEsQuery = ({ return [ JSON.stringify( buildEsQuery( - indexPattern, + dataViewSpecToViewBase(dataViewSpec), queries, filters.filter((f) => f.meta.disabled === false), { @@ -253,7 +258,7 @@ export const combineQueries = ({ const [filterQuery, kqlError] = convertToBuildEsQuery({ config, queries: [kuery], - indexPattern, + dataViewSpec: indexPattern, filters, }); @@ -281,7 +286,7 @@ export const combineQueries = ({ const [filterQuery, kqlError] = convertToBuildEsQuery({ config, queries: [kuery], - indexPattern, + dataViewSpec: indexPattern, filters, }); diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts index cb247891d79b3..5d0e9bcfd918a 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts @@ -68,6 +68,8 @@ export enum TelemetryEventTypes { EntityDetailsClicked = 'Entity Details Clicked', EntityAlertsClicked = 'Entity Alerts Clicked', EntityRiskFiltered = 'Entity Risk Filtered', + EntityStoreEnablementToggleClicked = 'Entity Store Enablement Toggle Clicked', + EntityStoreDashboardInitButtonClicked = 'Entity Store Initialization Button Clicked', MLJobUpdate = 'ML Job Update', AddRiskInputToTimelineClicked = 'Add Risk Input To Timeline Clicked', ToggleRiskSummaryClicked = 'Toggle Risk Summary Clicked', diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/index.ts index aedbc7eb01fae..5a45970de6af1 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/index.ts @@ -214,3 +214,36 @@ export const assetCriticalityCsvImportedEvent: TelemetryEvent = { }, }, }; + +export const entityStoreInitEvent: TelemetryEvent = { + eventType: TelemetryEventTypes.EntityStoreDashboardInitButtonClicked, + schema: { + timestamp: { + type: 'date', + _meta: { + description: 'Timestamp of the event', + optional: false, + }, + }, + }, +}; + +export const entityStoreEnablementEvent: TelemetryEvent = { + eventType: TelemetryEventTypes.EntityStoreEnablementToggleClicked, + schema: { + timestamp: { + type: 'date', + _meta: { + description: 'Timestamp of the event', + optional: false, + }, + }, + action: { + type: 'keyword', + _meta: { + description: 'Event toggle action', + optional: false, + }, + }, + }, +}; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts index 91a71a7dacca2..3313e99a31184 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts @@ -59,6 +59,15 @@ export interface ReportAssetCriticalityCsvImportedParams { }; } +export interface ReportEntityStoreEnablementParams { + timestamp: string; + action: 'start' | 'stop'; +} + +export interface ReportEntityStoreInitParams { + timestamp: string; +} + export type ReportEntityAnalyticsTelemetryEventParams = | ReportEntityDetailsClickedParams | ReportEntityAlertsClickedParams @@ -68,7 +77,9 @@ export type ReportEntityAnalyticsTelemetryEventParams = | ReportAddRiskInputToTimelineClickedParams | ReportAssetCriticalityCsvPreviewGeneratedParams | ReportAssetCriticalityFileSelectedParams - | ReportAssetCriticalityCsvImportedParams; + | ReportAssetCriticalityCsvImportedParams + | ReportEntityStoreEnablementParams + | ReportEntityStoreInitParams; export type EntityAnalyticsTelemetryEvent = | { @@ -106,4 +117,12 @@ export type EntityAnalyticsTelemetryEvent = | { eventType: TelemetryEventTypes.AssetCriticalityCsvImported; schema: RootSchema; + } + | { + eventType: TelemetryEventTypes.EntityStoreEnablementToggleClicked; + schema: RootSchema; + } + | { + eventType: TelemetryEventTypes.EntityStoreDashboardInitButtonClicked; + schema: RootSchema; }; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts index a0328099b9ff7..3e7c9f1138391 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts @@ -21,6 +21,8 @@ import { assetCriticalityCsvPreviewGeneratedEvent, assetCriticalityFileSelectedEvent, assetCriticalityCsvImportedEvent, + entityStoreEnablementEvent, + entityStoreInitEvent, } from './entity_analytics'; import { assistantInvokedEvent, @@ -172,6 +174,8 @@ export const telemetryEvents = [ assetCriticalityCsvPreviewGeneratedEvent, assetCriticalityFileSelectedEvent, assetCriticalityCsvImportedEvent, + entityStoreEnablementEvent, + entityStoreInitEvent, toggleRiskSummaryClickedEvent, RiskInputsExpandedFlyoutOpenedEvent, addRiskInputToTimelineClickedEvent, diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts index 98d6aa64bb9cb..87d4b215543dc 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts @@ -43,4 +43,6 @@ export const createTelemetryClientMock = (): jest.Mocked = reportOpenNoteInExpandableFlyoutClicked: jest.fn(), reportAddNoteFromExpandableFlyoutClicked: jest.fn(), reportPreviewRule: jest.fn(), + reportEntityStoreEnablement: jest.fn(), + reportEntityStoreInit: jest.fn(), }); diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts index e09f0a3c2eb66..689209f284dbb 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts @@ -45,6 +45,8 @@ import type { ReportEventLogShowSourceEventDateRangeParams, ReportEventLogFilterByRunTypeParams, PreviewRuleParams, + ReportEntityStoreEnablementParams, + ReportEntityStoreInitParams, } from './types'; import { TelemetryEventTypes } from './constants'; @@ -216,4 +218,12 @@ export class TelemetryClient implements TelemetryClientStart { public reportPreviewRule = (params: PreviewRuleParams) => { this.analytics.reportEvent(TelemetryEventTypes.PreviewRule, params); }; + + public reportEntityStoreEnablement = (params: ReportEntityStoreEnablementParams) => { + this.analytics.reportEvent(TelemetryEventTypes.EntityStoreEnablementToggleClicked, params); + }; + + public reportEntityStoreInit = (params: ReportEntityStoreInitParams) => { + this.analytics.reportEvent(TelemetryEventTypes.EntityStoreDashboardInitButtonClicked, params); + }; } diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts index 55b91837a2585..95896bf74a6a7 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts @@ -32,6 +32,8 @@ import type { ReportAssetCriticalityCsvPreviewGeneratedParams, ReportAssetCriticalityFileSelectedParams, ReportAssetCriticalityCsvImportedParams, + ReportEntityStoreEnablementParams, + ReportEntityStoreInitParams, } from './events/entity_analytics/types'; import type { AssistantTelemetryEvent, @@ -78,17 +80,7 @@ export * from './events/ai_assistant/types'; export * from './events/alerts_grouping/types'; export * from './events/data_quality/types'; export * from './events/onboarding/types'; -export type { - ReportEntityAlertsClickedParams, - ReportEntityDetailsClickedParams, - ReportEntityRiskFilteredParams, - ReportRiskInputsExpandedFlyoutOpenedParams, - ReportToggleRiskSummaryClickedParams, - ReportAddRiskInputToTimelineClickedParams, - ReportAssetCriticalityCsvPreviewGeneratedParams, - ReportAssetCriticalityFileSelectedParams, - ReportAssetCriticalityCsvImportedParams, -} from './events/entity_analytics/types'; +export * from './events/entity_analytics/types'; export * from './events/document_details/types'; export * from './events/manual_rule_run/types'; export * from './events/event_log/types'; @@ -168,6 +160,9 @@ export interface TelemetryClientStart { ): void; reportAssetCriticalityCsvImported(params: ReportAssetCriticalityCsvImportedParams): void; reportCellActionClicked(params: ReportCellActionClickedParams): void; + // Entity Analytics Entity Store + reportEntityStoreEnablement(params: ReportEntityStoreEnablementParams): void; + reportEntityStoreInit(params: ReportEntityStoreInitParams): void; reportAnomaliesCountClicked(params: ReportAnomaliesCountClickedParams): void; reportDataQualityIndexChecked(params: ReportDataQualityIndexCheckedParams): void; diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index 5874062f05523..6473f6fa5a67e 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -550,7 +550,7 @@ export const mockGlobalState: State = { direction: 'desc' as const, }, filter: '', - userFilter: '', + createdByFilter: '', associatedFilter: AssociatedFilter.all, search: '', selectedIds: [], diff --git a/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts b/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts index cc04177139a89..ec042d0b01e2d 100644 --- a/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts +++ b/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts @@ -110,3 +110,8 @@ export const mockIndexPattern: SecuritySolutionDataViewBase = { }; export const mockIndexNames = ['filebeat-*', 'auditbeat-*', 'packetbeat-*']; + +export const mockDataViewSpec = { + fields: Object.fromEntries(mockIndexPattern.fields.map((f) => [f.name, f])), + title: 'filebeat-*,auditbeat-*,packetbeat-*', +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts index 9dcca93d8fdd2..808597ff36495 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts @@ -22,11 +22,11 @@ const getQeryAst = (query: string) => { describe('computeHasMetadataOperator', () => { it('should be false if query does not have operator', () => { expect(computeHasMetadataOperator(getQeryAst('from test*'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* [metadata]'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* [metadata id]'))).toBe(false); + expect(computeHasMetadataOperator(getQeryAst('from test* metadata'))).toBe(false); + expect(computeHasMetadataOperator(getQeryAst('from test* metadata id'))).toBe(false); expect(computeHasMetadataOperator(getQeryAst('from metadata*'))).toBe(false); expect(computeHasMetadataOperator(getQeryAst('from test* | keep metadata'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* | eval x="[metadata _id]"'))).toBe( + expect(computeHasMetadataOperator(getQeryAst('from test* | eval x="metadata _id"'))).toBe( false ); }); @@ -48,19 +48,19 @@ describe('computeHasMetadataOperator', () => { ).toBe(true); // still validates deprecated square bracket syntax - expect(computeHasMetadataOperator(getQeryAst('from test* [metadata _id]'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* [metadata _id, _index]'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* [metadata _index, _id]'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* [ metadata _id ]'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* [ metadata _id] '))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* [ metadata _id] | limit 10'))).toBe( + expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id'))).toBe(true); + expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id, _index'))).toBe(true); + expect(computeHasMetadataOperator(getQeryAst('from test* metadata _index, _id'))).toBe(true); + expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id '))).toBe(true); + expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id '))).toBe(true); + expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id | limit 10'))).toBe( true ); expect( computeHasMetadataOperator( - getQeryAst(`from packetbeat* [metadata + getQeryAst(`from packetbeat* metadata - _id ] + _id | limit 100`) ) ).toBe(true); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts index 869e379c21aed..c508676cae92c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts @@ -154,7 +154,7 @@ export const parseEsqlQuery = (query: string) => { return { errors, isEsqlQueryAggregating, - // non-aggregating query which does not have [metadata], is not a valid one + // non-aggregating query which does not have metadata, is not a valid one isMissingMetadataOperator: !isEsqlQueryAggregating && !computeHasMetadataOperator(ast), }; }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/index.test.tsx deleted file mode 100644 index e37b21550852b..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/index.test.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { shallow, mount } from 'enzyme'; - -import { DataViewSelector } from '.'; -import type { DataViewSelectorProps } from '.'; -import { TestProviders, useFormFieldMock } from '../../../../common/mock'; - -jest.mock('../../../../common/lib/kibana'); - -describe('data_view_selector', () => { - let mockField: DataViewSelectorProps['field']; - - beforeEach(() => { - mockField = useFormFieldMock({ - value: undefined, - }); - }); - - it('renders correctly', () => { - const Component = () => { - return ; - }; - const wrapper = shallow(); - - expect(wrapper.dive().find('[data-test-subj="pick-rule-data-source"]')).toHaveLength(1); - }); - - it('displays alerts on alerts warning when default security view selected', () => { - const wrapper = mount( - - ({ - value: 'security-solution-default', - })} - /> - - ); - - expect(wrapper.find('[data-test-subj="defaultSecurityDataViewWarning"]').exists()).toBeTruthy(); - }); - - it('does not display alerts on alerts warning when default security view is not selected', () => { - const wrapper = mount( - - ({ - value: '1234', - })} - /> - - ); - - expect(wrapper.find('[data-test-subj="defaultSecurityDataViewWarning"]').exists()).toBeFalsy(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/index.tsx deleted file mode 100644 index 45efbfcadec8c..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/index.tsx +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo, useState, useEffect } from 'react'; - -import type { EuiComboBoxOptionOption } from '@elastic/eui'; -import { EuiCallOut, EuiComboBox, EuiFormRow, EuiSpacer } from '@elastic/eui'; - -import type { DataViewListItem } from '@kbn/data-views-plugin/common'; -import type { FieldHook } from '../../../../shared_imports'; -import { getFieldValidityAndErrorMessage } from '../../../../shared_imports'; -import * as i18n from './translations'; -import type { DefineStepRule } from '../../../../detections/pages/detection_engine/rules/types'; - -export interface DataViewSelectorProps { - kibanaDataViews: Record; - field: FieldHook; -} - -export const DataViewSelector = ({ kibanaDataViews, field }: DataViewSelectorProps) => { - let isInvalid; - let errorMessage; - let dataViewId: string | null | undefined; - - if (field != null) { - const fieldAndError = getFieldValidityAndErrorMessage(field); - isInvalid = fieldAndError.isInvalid; - errorMessage = fieldAndError.errorMessage; - dataViewId = field.value; - } - - const kibanaDataViewsDefined = useMemo( - () => kibanaDataViews != null && Object.keys(kibanaDataViews).length > 0, - [kibanaDataViews] - ); - - // Most likely case here is that a data view of an existing rule was deleted - // and can no longer be found - const selectedDataViewNotFound = useMemo( - () => - dataViewId != null && - dataViewId !== '' && - kibanaDataViewsDefined && - !Object.hasOwn(kibanaDataViews, dataViewId), - [kibanaDataViewsDefined, dataViewId, kibanaDataViews] - ); - const [selectedOption, setSelectedOption] = useState>>( - !selectedDataViewNotFound && dataViewId != null && dataViewId !== '' - ? [{ id: kibanaDataViews[dataViewId].id, label: kibanaDataViews[dataViewId].title }] - : [] - ); - - const [showDataViewAlertsOnAlertsWarning, setShowDataViewAlertsOnAlertsWarning] = useState(false); - - useEffect(() => { - if (!selectedDataViewNotFound && dataViewId) { - const dataViewsTitle = kibanaDataViews[dataViewId].title; - const dataViewsId = kibanaDataViews[dataViewId].id; - - setShowDataViewAlertsOnAlertsWarning(dataViewsId === 'security-solution-default'); - - setSelectedOption([{ id: dataViewsId, label: dataViewsTitle }]); - } else { - setSelectedOption([]); - } - }, [ - dataViewId, - field, - kibanaDataViews, - selectedDataViewNotFound, - setShowDataViewAlertsOnAlertsWarning, - ]); - - // TODO: optimize this, pass down array of data view ids - // at the same time we grab the data views in the top level form component - const dataViewOptions = useMemo(() => { - return kibanaDataViewsDefined - ? Object.values(kibanaDataViews).map((dv) => ({ - label: dv.title, - id: dv.id, - })) - : []; - }, [kibanaDataViewsDefined, kibanaDataViews]); - - const onChangeDataViews = (options: Array>) => { - const selectedDataViewOption = options; - setSelectedOption(selectedDataViewOption ?? []); - - if ( - selectedDataViewOption != null && - selectedDataViewOption.length > 0 && - selectedDataViewOption[0].id != null - ) { - const selectedDataViewId = selectedDataViewOption[0].id; - field?.setValue(selectedDataViewId); - } else { - field?.setValue(undefined); - } - }; - - return ( - <> - {selectedDataViewNotFound && dataViewId != null && ( - <> - -

{i18n.DATA_VIEW_NOT_FOUND_WARNING_DESCRIPTION(dataViewId)}

-
- - - )} - {showDataViewAlertsOnAlertsWarning && ( - <> - -

{i18n.DATA_VIEW_ALERTS_ON_ALERTS_WARNING_DESCRIPTION}

-
- - - )} - - - - - ); -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/__mocks__/use_data_views.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/__mocks__/use_data_views.ts new file mode 100644 index 0000000000000..248729f1f46e7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/__mocks__/use_data_views.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const useDataViews = jest.fn().mockReturnValue({ + data: [], + isFetching: false, +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/data_view_selector_field.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/data_view_selector_field.test.tsx new file mode 100644 index 0000000000000..6cfdf060434b8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/data_view_selector_field.test.tsx @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { screen, render } from '@testing-library/react'; +import { TestProviders, useFormFieldMock } from '../../../../common/mock'; +import { DataViewSelectorField } from './data_view_selector_field'; +import { useDataViews } from './use_data_views'; + +jest.mock('../../../../common/lib/kibana'); +jest.mock('./use_data_views'); + +describe('data_view_selector', () => { + it('renders correctly', () => { + (useDataViews as jest.Mock).mockReturnValue({ data: [], isFetching: false }); + + render( + ({ + value: undefined, + })} + />, + { wrapper: TestProviders } + ); + + expect(screen.queryByTestId('pick-rule-data-source')).toBeInTheDocument(); + }); + + it('disables the combobox while data views are fetching', () => { + (useDataViews as jest.Mock).mockReturnValue({ data: [], isFetching: true }); + + render( + ({ + value: undefined, + })} + />, + { wrapper: TestProviders } + ); + + expect(screen.getByRole('combobox')).toBeDisabled(); + }); + + it('displays alerts on alerts warning when default security view selected', () => { + const dataViews = [ + { + id: 'security-solution-default', + title: + '-*elastic-cloud-logs-*,.alerts-security.alerts-default,apm-*-transaction*,auditbeat-*,endgame-*,filebeat-*,logs-*,packetbeat-*,traces-apm*,winlogbeat-*', + }, + { + id: '1234', + title: 'logs-*', + }, + ]; + (useDataViews as jest.Mock).mockReturnValue({ data: dataViews, isFetching: false }); + + render( + ({ + value: 'security-solution-default', + })} + />, + { wrapper: TestProviders } + ); + + expect(screen.queryByTestId('defaultSecurityDataViewWarning')).toBeInTheDocument(); + }); + + it('does not display alerts on alerts warning when default security view is not selected', () => { + const dataViews = [ + { + id: 'security-solution-default', + title: + '-*elastic-cloud-logs-*,.alerts-security.alerts-default,apm-*-transaction*,auditbeat-*,endgame-*,filebeat-*,logs-*,packetbeat-*,traces-apm*,winlogbeat-*', + }, + { + id: '1234', + title: 'logs-*', + }, + ]; + (useDataViews as jest.Mock).mockReturnValue({ data: dataViews, isFetching: false }); + + render( + ({ + value: '1234', + })} + />, + { wrapper: TestProviders } + ); + + expect(screen.queryByTestId('defaultSecurityDataViewWarning')).not.toBeInTheDocument(); + }); + + it('displays warning on missing data view', () => { + (useDataViews as jest.Mock).mockReturnValue({ data: [], isFetching: false }); + + render( + ({ + value: 'non-existent-id', + })} + />, + { wrapper: TestProviders } + ); + + expect(screen.queryByTestId('missingDataViewWarning')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/data_view_selector_field.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/data_view_selector_field.tsx new file mode 100644 index 0000000000000..aacd80ea53236 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/data_view_selector_field.tsx @@ -0,0 +1,95 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo, useCallback } from 'react'; +import type { EuiComboBoxOptionOption } from '@elastic/eui'; +import { EuiCallOut, EuiComboBox, EuiFormRow, EuiSpacer } from '@elastic/eui'; +import type { FieldHook } from '../../../../shared_imports'; +import { getFieldValidityAndErrorMessage } from '../../../../shared_imports'; +import { isDataViewIdValid } from '../../validators/data_view_id_validator_factory'; +import { useDataViews } from './use_data_views'; +import * as i18n from './translations'; + +const SECURITY_DEFAULT_DATA_VIEW_ID = 'security-solution-default'; + +export interface DataViewSelectorProps { + field: FieldHook; +} + +export function DataViewSelectorField({ field }: DataViewSelectorProps): JSX.Element { + const { data: dataViews, isFetching: areDataViewsFetching } = useDataViews(); + const fieldAndError = field ? getFieldValidityAndErrorMessage(field) : undefined; + const isInvalid = fieldAndError?.isInvalid; + const errorMessage = fieldAndError?.errorMessage; + const comboBoxOptions = useMemo( + () => + dataViews.map(({ id, title: label }) => ({ + id, + label, + })), + [dataViews] + ); + const selectedOption = useMemo( + () => comboBoxOptions.find(({ id }) => id === field.value), + [comboBoxOptions, field] + ); + + const handleDataViewsChange = useCallback( + (options: Array>) => field.setValue(options[0]?.id), + [field] + ); + + return ( + <> + {!areDataViewsFetching && isDataViewIdValid(field.value) && !selectedOption && ( + <> + +

{i18n.DATA_VIEW_NOT_FOUND_WARNING_DESCRIPTION(field.value)}

+
+ + + )} + {field.value === SECURITY_DEFAULT_DATA_VIEW_ID && ( + <> + +

{i18n.DATA_VIEW_ALERTS_ON_ALERTS_WARNING_DESCRIPTION}

+
+ + + )} + + + + + ); +} diff --git a/x-pack/plugins/cloud/common/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/index.ts similarity index 81% rename from x-pack/plugins/cloud/common/index.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/index.ts index 4aa6ce8d5edf0..5cc0e111b13de 100644 --- a/x-pack/plugins/cloud/common/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export type { OnBoardingDefaultSolution } from './types'; +export * from './data_view_selector_field'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/translations.tsx similarity index 84% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/translations.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/translations.tsx index eff760157e82f..717666ac0c0c1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector/translations.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/translations.tsx @@ -31,7 +31,7 @@ export const DATA_VIEW_NOT_FOUND_WARNING_DESCRIPTION = (dataView: string) => } ); -export const DDATA_VIEW_ALERTS_ON_ALERTS_WARNING_LABEL = i18n.translate( +export const DATA_VIEW_ALERTS_ON_ALERTS_WARNING_LABEL = i18n.translate( 'xpack.securitySolution.detectionEngine.stepDefineRule.dataViewIncludesAlertsIndexLabel', { defaultMessage: 'Default Security data view', @@ -45,3 +45,10 @@ export const DATA_VIEW_ALERTS_ON_ALERTS_WARNING_DESCRIPTION = i18n.translate( 'The default Security data view includes the alerts index. This could result in redundant alerts being generated from existing alerts.', } ); + +export const DATA_VIEWS_FETCH_ERROR = i18n.translate( + 'xpack.securitySolution.detectionEngine.stepDefineRule.dataViewFetchError', + { + defaultMessage: 'Unable to retrieve available data views', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/use_data_views.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/use_data_views.ts new file mode 100644 index 0000000000000..a68aa4f976269 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/data_view_selector_field/use_data_views.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useState } from 'react'; +import type { DataViewListItem } from '@kbn/data-views-plugin/common'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { useKibana } from '../../../../common/lib/kibana'; +import * as i18n from './translations'; + +interface UseDataViewsResult { + data: DataViewListItem[]; + isFetching: boolean; +} + +/** + * Fetches known Kibana data views from the Data View Service. + */ +export function useDataViews(): UseDataViewsResult { + const { + data: { dataViews: dataViewsService }, + } = useKibana().services; + const { addError } = useAppToasts(); + + const [isFetching, setIsFetching] = useState(false); + const [dataViews, setDataViews] = useState([]); + + useEffect(() => { + setIsFetching(true); + (async () => { + try { + setDataViews(await dataViewsService.getIdsWithTitle(true)); + } catch (e) { + addError(e, { title: i18n.DATA_VIEWS_FETCH_ERROR }); + } finally { + setIsFetching(false); + } + })(); + }, [dataViewsService, addError]); + + return { data: dataViews, isFetching }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/index.tsx index f941cad91d3a4..7d51009dccda3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/index.tsx @@ -108,6 +108,8 @@ const RulePreviewComponent: React.FC = ({ const [isDateRangeInvalid, setIsDateRangeInvalid] = useState(false); + const isLoggedRequestsSupported = RULE_TYPES_SUPPORTING_LOGGED_REQUESTS.includes(ruleType); + useEffect(() => { const { start, end } = refreshedTimeframe(startDate, endDate); setTimeframeStart(start); @@ -194,7 +196,7 @@ const RulePreviewComponent: React.FC = ({ interval: scheduleRuleData.interval, lookback: scheduleRuleData.from, }, - enableLoggedRequests: showElasticsearchRequests, + enableLoggedRequests: showElasticsearchRequests && isLoggedRequestsSupported, }); setIsRefreshing(true); }, [ @@ -205,6 +207,7 @@ const RulePreviewComponent: React.FC = ({ startDate, startTransaction, showElasticsearchRequests, + isLoggedRequestsSupported, ]); const isDirty = useMemo( @@ -279,7 +282,7 @@ const RulePreviewComponent: React.FC = ({
- {RULE_TYPES_SUPPORTING_LOGGED_REQUESTS.includes(ruleType) ? ( + {isLoggedRequestsSupported ? ( @@ -312,7 +315,7 @@ const RulePreviewComponent: React.FC = ({ logs={logs} hasNoiseWarning={hasNoiseWarning} isAborted={isAborted} - showElasticsearchRequests={showElasticsearchRequests} + showElasticsearchRequests={showElasticsearchRequests && isLoggedRequestsSupported} />
); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx index 3e7d19ad7db5f..cc8f2abda9c4e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx @@ -48,6 +48,8 @@ jest.mock('../ai_assistant', () => { }; }); +jest.mock('../data_view_selector_field/use_data_views'); + const mockRedirectLegacyUrl = jest.fn(); const mockGetLegacyUrlConflict = jest.fn(); jest.mock('../../../../common/lib/kibana', () => { @@ -79,104 +81,6 @@ jest.mock('../../../../common/lib/kibana', () => { }, }, data: { - dataViews: { - getIdsWithTitle: async () => - Promise.resolve([{ id: 'myfakeid', title: 'hello*,world*,refreshed*' }]), - create: async ({ title }: { title: string }) => - Promise.resolve({ - id: 'myfakeid', - matchedIndices: ['hello', 'world', 'refreshed'], - fields: [ - { - name: 'bytes', - type: 'number', - esTypes: ['long'], - aggregatable: true, - searchable: true, - count: 10, - readFromDocValues: true, - scripted: false, - isMapped: true, - }, - { - name: 'ssl', - type: 'boolean', - esTypes: ['boolean'], - aggregatable: true, - searchable: true, - count: 20, - readFromDocValues: true, - scripted: false, - isMapped: true, - }, - { - name: '@timestamp', - type: 'date', - esTypes: ['date'], - aggregatable: true, - searchable: true, - count: 30, - readFromDocValues: true, - scripted: false, - isMapped: true, - }, - ], - getIndexPattern: () => 'hello*,world*,refreshed*', - getRuntimeMappings: () => ({ - myfield: { - type: 'keyword', - }, - }), - }), - get: async (dataViewId: string, displayErrors?: boolean, refreshFields = false) => - Promise.resolve({ - id: dataViewId, - matchedIndices: refreshFields - ? ['hello', 'world', 'refreshed'] - : ['hello', 'world'], - fields: [ - { - name: 'bytes', - type: 'number', - esTypes: ['long'], - aggregatable: true, - searchable: true, - count: 10, - readFromDocValues: true, - scripted: false, - isMapped: true, - }, - { - name: 'ssl', - type: 'boolean', - esTypes: ['boolean'], - aggregatable: true, - searchable: true, - count: 20, - readFromDocValues: true, - scripted: false, - isMapped: true, - }, - { - name: '@timestamp', - type: 'date', - esTypes: ['date'], - aggregatable: true, - searchable: true, - count: 30, - readFromDocValues: true, - scripted: false, - isMapped: true, - }, - ], - getIndexPattern: () => 'hello*,world*,refreshed*', - getRuntimeMappings: () => ({ - myfield: { - type: 'keyword', - }, - }), - }), - }, search: { search: () => ({ subscribe: () => ({ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx index 6b9780b8c029b..99fb8f2ba469e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx @@ -11,7 +11,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiFormRow, - EuiLoadingSpinner, EuiSpacer, EuiButtonGroup, EuiText, @@ -82,7 +81,7 @@ import { isSuppressionRuleInGA, } from '../../../../../common/detection_engine/utils'; import { EqlQueryBar } from '../eql_query_bar'; -import { DataViewSelector } from '../data_view_selector'; +import { DataViewSelectorField } from '../data_view_selector_field'; import { ThreatMatchInput } from '../threatmatch_input'; import { useFetchIndex } from '../../../../common/containers/source'; import { NewTermsFields } from '../new_terms_fields'; @@ -184,7 +183,6 @@ const StepDefineRuleComponent: FC = ({ isLoading, isQueryBarValid, isUpdateView = false, - kibanaDataViews, optionsSelected, queryBarSavedId, queryBarTitle, @@ -653,21 +651,6 @@ const StepDefineRuleComponent: FC = ({ [dataSourceType] ); - const DataViewSelectorMemo = useMemo(() => { - return kibanaDataViews == null || Object.keys(kibanaDataViews).length === 0 ? ( - - ) : ( - - ); - }, [kibanaDataViews]); - const DataSource = useMemo(() => { return ( @@ -714,7 +697,11 @@ const StepDefineRuleComponent: FC = ({ - {DataViewSelectorMemo} + = ({ dataSourceType, onChangeDataSource, dataViewIndexPatternToggleButtonOptions, - DataViewSelectorMemo, indexModified, handleResetIndices, ]); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx index 5c8d8d89c46d0..fc8468b094fa1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx @@ -44,6 +44,8 @@ import { EQL_SEQUENCE_SUPPRESSION_GROUPBY_VALIDATION_TEXT, } from './translations'; import { getQueryRequiredMessage } from './utils'; +import { dataViewIdValidatorFactory } from '../../validators/data_view_id_validator_factory'; +import { indexPatternValidatorFactory } from '../../validators/index_pattern_validator_factory'; export const schema: FormSchema = { index: { @@ -59,27 +61,18 @@ export const schema: FormSchema = { helpText: {INDEX_HELPER_TEXT}, validations: [ { - validator: ( - ...args: Parameters - ): ReturnType> | undefined => { + validator: (...args: Parameters) => { const [{ formData }] = args; - const skipValidation = + + if ( isMlRule(formData.ruleType) || isEsqlRule(formData.ruleType) || - formData.dataSourceType !== DataSourceType.IndexPatterns; - - if (skipValidation) { + formData.dataSourceType !== DataSourceType.IndexPatterns + ) { return; } - return fieldValidators.emptyField( - i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.outputIndiceNameFieldRequiredError', - { - defaultMessage: 'A minimum of one index pattern is required.', - } - ) - )(...args); + return indexPatternValidatorFactory()(...args); }, }, ], @@ -94,32 +87,14 @@ export const schema: FormSchema = { fieldsToValidateOnChange: ['dataViewId'], validations: [ { - validator: ( - ...args: Parameters - ): ReturnType> | undefined => { - const [{ path, formData }] = args; - // the dropdown defaults the dataViewId to an empty string somehow on render.. - // need to figure this out. - const notEmptyDataViewId = formData.dataViewId != null && formData.dataViewId !== ''; - - const skipValidation = - isMlRule(formData.ruleType) || - notEmptyDataViewId || - formData.dataSourceType !== DataSourceType.DataView; + validator: (...args: Parameters) => { + const [{ formData }] = args; - if (skipValidation) { + if (isMlRule(formData.ruleType) || formData.dataSourceType !== DataSourceType.DataView) { return; } - return { - path, - message: i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.dataViewSelectorFieldRequired', - { - defaultMessage: 'Please select an available Data View or Index Pattern.', - } - ), - }; + return dataViewIdValidatorFactory()(...args); }, }, ], diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.tsx index 90b302c3bc904..9e232e4bff2be 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.tsx @@ -149,7 +149,7 @@ export const useRuleIndexPattern = ({ if (dataSourceType === DataSourceType.DataView) { const fetchDataView = async () => { - if (dataViewId != null) { + if (dataViewId != null && dataViewId !== '') { const dv = await data.dataViews.get(dataViewId); setIndexPattern(dv); } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx index 28d137ac522ae..0c6a6fb07ce5c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx @@ -19,8 +19,6 @@ import { import React, { memo, useCallback, useRef, useState, useMemo, useEffect } from 'react'; import styled from 'styled-components'; -import type { DataViewListItem } from '@kbn/data-views-plugin/common'; - import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { isMlRule, @@ -123,11 +121,7 @@ const CreateRulePageComponent: React.FC = () => { useListsConfig(); const { addSuccess } = useAppToasts(); const { navigateToApp } = useKibana().services.application; - const { - application, - data: { dataViews }, - triggersActionsUi, - } = useKibana().services; + const { application, triggersActionsUi } = useKibana().services; const loading = userInfoLoading || listsConfigLoading; const [activeStep, setActiveStep] = useState(RuleStep.defineRule); const getNextStep = (step: RuleStep): RuleStep | undefined => @@ -204,7 +198,6 @@ const CreateRulePageComponent: React.FC = () => { const { mutateAsync: createRule, isLoading: isCreateRuleLoading } = useCreateRule(); const ruleType = defineStepData.ruleType; const actionMessageParams = useMemo(() => getActionMessageParams(ruleType), [ruleType]); - const [dataViewOptions, setDataViewOptions] = useState<{ [x: string]: DataViewListItem }>({}); const [isRulePreviewVisible, setIsRulePreviewVisible] = useState(true); const collapseFn = useRef<() => void | undefined>(); const [prevRuleType, setPrevRuleType] = useState(); @@ -256,20 +249,6 @@ const CreateRulePageComponent: React.FC = () => { const { starting: isStartingJobs, startMlJobs } = useStartMlJobs(); - useEffect(() => { - const fetchDV = async () => { - const dataViewsRefs = await dataViews.getIdsWithTitle(); - const dataViewIdIndexPatternMap = dataViewsRefs.reduce( - (acc, item) => ({ - ...acc, - [item.id]: item, - }), - {} - ); - setDataViewOptions(dataViewIdIndexPatternMap); - }; - fetchDV(); - }, [dataViews]); const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern({ dataSourceType: defineStepData.dataSourceType, index: memoizedIndex, @@ -573,7 +552,6 @@ const CreateRulePageComponent: React.FC = () => { > { ), [ activeStep, - dataViewOptions, defineRuleNextStep, defineStepData.dataSourceType, defineStepData.groupByFields, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx index 9151e6965bd11..1657f57ec83e8 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx @@ -18,11 +18,9 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { FC } from 'react'; -import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { memo, useCallback, useMemo, useRef, useState } from 'react'; import { useParams } from 'react-router-dom'; -import type { DataViewListItem } from '@kbn/data-views-plugin/common'; - import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { isEsqlRule } from '../../../../../common/detection_engine/utils'; import { RulePreview } from '../../components/rule_preview'; @@ -85,7 +83,7 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { ] = useUserData(); const { loading: listsConfigLoading, needsConfiguration: needsListsConfiguration } = useListsConfig(); - const { data: dataServices, application, triggersActionsUi } = useKibana().services; + const { application, triggersActionsUi } = useKibana().services; const { navigateToApp } = application; const { detailName: ruleId } = useParams<{ detailName: string }>(); @@ -94,7 +92,6 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { rule.immutable ? RuleStep.ruleActions : RuleStep.defineRule ); const { mutateAsync: updateRule, isLoading } = useUpdateRule(); - const [dataViewOptions, setDataViewOptions] = useState<{ [x: string]: DataViewListItem }>({}); const [isRulePreviewVisible, setIsRulePreviewVisible] = useState(true); const collapseFn = useRef<() => void | undefined>(); const [isQueryBarValid, setIsQueryBarValid] = useState(false); @@ -103,21 +100,6 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { const [isSaveWithErrorsModalVisible, setIsSaveWithErrorsModalVisible] = useState(false); const [nonBlockingRuleErrors, setNonBlockingRuleErrors] = useState([]); - useEffect(() => { - const fetchDataViews = async () => { - const dataViewsRefs = await dataServices.dataViews.getIdsWithTitle(); - const dataViewIdIndexPatternMap = dataViewsRefs.reduce( - (acc, item) => ({ - ...acc, - [item.id]: item, - }), - {} - ); - setDataViewOptions(dataViewIdIndexPatternMap); - }; - fetchDataViews(); - }, [dataServices.dataViews]); - const backOptions = useMemo( () => ({ path: getRuleDetailsUrl(ruleId ?? ''), @@ -241,7 +223,6 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { = ({ rule }) => { loading, isSavedQueryLoading, isLoading, - dataViewOptions, indicesConfig, threatIndicesConfig, savedQuery, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/data_view_id_validator_factory.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/data_view_id_validator_factory.ts new file mode 100644 index 0000000000000..57ef5ff6e0133 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/data_view_id_validator_factory.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { FormData, ValidationFunc } from '../../../shared_imports'; + +export function dataViewIdValidatorFactory(): ValidationFunc { + return (...args) => { + const [{ path, value }] = args; + + return !isDataViewIdValid(value) + ? { + path, + message: i18n.translate( + 'xpack.securitySolution.ruleManagement.ruleCreation.validation.dataView.requiredError', + { + defaultMessage: 'Please select an available Data View.', + } + ), + } + : undefined; + }; +} + +export function isDataViewIdValid(dataViewId: unknown): dataViewId is string { + return typeof dataViewId === 'string' && dataViewId !== ''; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/index_pattern_validator_factory.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/index_pattern_validator_factory.ts new file mode 100644 index 0000000000000..9962d3b835b3c --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/index_pattern_validator_factory.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { ERROR_CODE } from '../../../shared_imports'; +import { fieldValidators, type FormData, type ValidationFunc } from '../../../shared_imports'; + +export function indexPatternValidatorFactory(): ValidationFunc { + return fieldValidators.emptyField( + i18n.translate( + 'xpack.securitySolution.ruleManagement.ruleCreation.validation.indexPatterns.requiredError', + { + defaultMessage: 'A minimum of one index pattern is required.', + } + ) + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx index 3a221836e3a35..4ed02135143ff 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx @@ -47,11 +47,11 @@ const coreStart = coreMock.createStart(); const mockUseSourcererDataView = useSourcererDataView as jest.Mock; mockUseSourcererDataView.mockReturnValue({ - indexPattern: { fields: [] }, missingPatterns: {}, selectedPatterns: {}, scopeSelectedPatterns: {}, loading: false, + sourcererDataView: {}, }); const mockUseRuleExecutionEvents = useExecutionResults as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx index 048780b259d22..4546e55522ce5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx @@ -37,6 +37,7 @@ import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser'; import type { I18nStart } from '@kbn/core-i18n-browser'; import type { ThemeServiceStart } from '@kbn/core-theme-browser'; +import { dataViewSpecToViewBase } from '../../../../../common/lib/kuery'; import { InputsModelId } from '../../../../../common/store/inputs/constants'; import { @@ -159,7 +160,7 @@ const ExecutionLogTableComponent: React.FC = ({ } = useRuleDetailsContext(); // Index for `add filter` action and toasts for errors - const { indexPattern } = useSourcererDataView(SourcererScopeName.detections); + const { sourcererDataView } = useSourcererDataView(SourcererScopeName.detections); const { addError, addSuccess, remove } = useAppToasts(); // QueryString, Filters, and TimeRange state @@ -232,9 +233,10 @@ const ExecutionLogTableComponent: React.FC = ({ const maxEvents = events?.total ?? 0; // Cache UUID field from data view as it can be expensive to iterate all data view fields - const uuidDataViewField = useMemo(() => { - return indexPattern.fields.find((f) => f.name === EXECUTION_UUID_FIELD_NAME); - }, [indexPattern]); + const uuidDataViewField = useMemo( + () => sourcererDataView.fields?.[EXECUTION_UUID_FIELD_NAME], + [sourcererDataView] + ); // Callbacks const onTableChangeCallback = useCallback( @@ -299,12 +301,18 @@ const ExecutionLogTableComponent: React.FC = ({ const onFilterByExecutionIdCallback = useCallback( (executionId: string, executionStart: string) => { - if (uuidDataViewField != null) { + const dataViewAsViewBase = dataViewSpecToViewBase(sourcererDataView); + + if ( + uuidDataViewField != null && + typeof uuidDataViewField !== 'undefined' && + dataViewAsViewBase + ) { // Update cached global query state with current state as a rollback point cachedGlobalQueryState.current = { filters, query, timerange }; // Create filter & daterange constraints const filter = buildFilter( - indexPattern, + dataViewAsViewBase, uuidDataViewField, FILTERS.PHRASE, false, @@ -350,18 +358,18 @@ const ExecutionLogTableComponent: React.FC = ({ } }, [ - addError, - addSuccess, - dispatch, - filterManager, + uuidDataViewField, filters, - indexPattern, query, - resetGlobalQueryState, - selectAlertsTab, timerange, - uuidDataViewField, + sourcererDataView, + dispatch, + filterManager, + selectAlertsTab, + addSuccess, + resetGlobalQueryState, startServices, + addError, ] ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index 91ba4276a79b2..851d219ad43d3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -759,7 +759,7 @@ const RuleDetailsPageComponent: React.FC = ({ hasIndexWrite={hasIndexWrite ?? false} loading={loading} renderChildComponent={renderGroupedAlertTable} - runtimeMappings={sourcererDataView?.runtimeFieldMap as RunTimeMappings} + runtimeMappings={sourcererDataView.runtimeFieldMap as RunTimeMappings} signalIndexName={signalIndexName} tableId={TableId.alertsOnRuleDetailsPage} to={to} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx index 184633d813675..623ae20fa484f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx @@ -58,7 +58,7 @@ import { useRequiredFieldsStyles, } from './rule_definition_section.styles'; import { getQueryLanguageLabel } from './helpers'; -import { useDefaultIndexPattern } from './use_default_index_pattern'; +import { useDefaultIndexPattern } from '../../hooks/use_default_index_pattern'; interface SavedQueryNameProps { savedQueryName: string; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx index 0cb7ce3982868..fefd35fcfaf65 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { FieldFormWrapper } from './field_form_wrapper'; +import { RuleFieldEditFormWrapper } from './fields/rule_field_edit_form_wrapper'; import { NameEdit, nameSchema } from './fields/name'; import type { UpgradeableCommonFields } from '../../../../model/prebuilt_rule_upgrade/fields'; interface CommonRuleFieldEditProps { @@ -16,7 +16,7 @@ interface CommonRuleFieldEditProps { export function CommonRuleFieldEdit({ fieldName }: CommonRuleFieldEditProps) { switch (fieldName) { case 'name': - return ; + return ; default: return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/custom_query_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/custom_query_rule_field_edit.tsx index 3dc3cc5b87023..e71f061f140e4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/custom_query_rule_field_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/custom_query_rule_field_edit.tsx @@ -6,14 +6,9 @@ */ import React from 'react'; -import { FieldFormWrapper } from './field_form_wrapper'; -import { - KqlQueryEdit, - kqlQuerySchema, - kqlQuerySerializer, - kqlQueryDeserializer, -} from './fields/kql_query'; import type { UpgradeableCustomQueryFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import { KqlQueryEditForm } from './fields/kql_query'; +import { DataSourceEditForm } from './fields/data_source'; interface CustomQueryRuleFieldEditProps { fieldName: UpgradeableCustomQueryFields; @@ -22,14 +17,9 @@ interface CustomQueryRuleFieldEditProps { export function CustomQueryRuleFieldEdit({ fieldName }: CustomQueryRuleFieldEditProps) { switch (fieldName) { case 'kql_query': - return ( - - ); + return ; + case 'data_source': + return ; default: return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/eql_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/eql_rule_field_edit.tsx new file mode 100644 index 0000000000000..a15cc87b3324c --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/eql_rule_field_edit.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { UpgradeableEqlFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import { DataSourceEditForm } from './fields/data_source'; + +interface EqlRuleFieldEditProps { + fieldName: UpgradeableEqlFields; +} + +export function EqlRuleFieldEdit({ fieldName }: EqlRuleFieldEditProps) { + switch (fieldName) { + case 'data_source': + return ; + default: + return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented + } +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit.tsx new file mode 100644 index 0000000000000..2f697288221cf --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { PropsWithChildren } from 'react'; +import { css } from '@emotion/css'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { DataSourceType } from '../../../../../../../../../common/api/detection_engine/prebuilt_rules'; +import { UseMultiFields } from '../../../../../../../../shared_imports'; +import type { RuleFieldEditComponentProps } from '../rule_field_edit_component_props'; +import { IndexPatternField } from './index_pattern_edit'; +import { DataSourceInfoText } from './data_source_info_text'; +import { DataViewField } from './data_view_field'; +import { DataSourceTypeSelectorField } from './data_source_type_selector_field'; + +export function DataSourceEdit({ resetForm }: RuleFieldEditComponentProps): JSX.Element { + return ( + + fields={{ + type: { + path: 'type', + }, + indexPatterns: { + path: 'index_patterns', + }, + dataViewId: { + path: 'data_view_id', + }, + }} + > + {({ type, indexPatterns, dataViewId }) => ( + + + + + + + + + + + + + + + + + )} + + ); +} + +interface TabProps { + visible: boolean; +} + +const hidden = css` + display: none; +`; + +function TabContent({ visible, children }: PropsWithChildren): JSX.Element { + return ; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit_form.tsx new file mode 100644 index 0000000000000..b1dc66ad032d1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit_form.tsx @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiText } from '@elastic/eui'; +import { indexPatternValidatorFactory } from '../../../../../../../rule_creation_ui/validators/index_pattern_validator_factory'; +import { dataViewIdValidatorFactory } from '../../../../../../../rule_creation_ui/validators/data_view_id_validator_factory'; +import type { ValidationFunc, ERROR_CODE } from '../../../../../../../../shared_imports'; +import { + type FormData, + type FormSchema, + FIELD_TYPES, +} from '../../../../../../../../shared_imports'; +import { DataSourceType } from '../../../../../../../../../common/api/detection_engine/prebuilt_rules'; +import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; +import { DataSourceEdit } from './data_source_edit'; +import { INDEX_HELPER_TEXT } from '../../../../../../../rule_creation_ui/components/step_define_rule/translations'; + +export function DataSourceEditForm(): JSX.Element { + return ( + + ); +} + +function dataSourceDeserializer(defaultValue: FormData): FormData { + if (!defaultValue.data_source) { + throw new Error(`dataSourceDeserializer expects "data_source" field`); + } + + return defaultValue.data_source; +} + +function dataSourceSerializer(formData: FormData): FormData { + return { + data_source: formData, + }; +} + +const dataSourceSchema = { + type: { + default: DataSourceType.index_patterns, + }, + index_patterns: { + defaultValue: [], + type: FIELD_TYPES.COMBO_BOX, + label: i18n.translate( + 'xpack.securitySolution.ruleManagement.threeWayDiff.finalEdit.indexPatterns.label', + { + defaultMessage: 'Index patterns', + } + ), + helpText: {INDEX_HELPER_TEXT}, + validations: [ + { + validator: ( + ...args: Parameters + ): ReturnType> | undefined => { + const [{ formData }] = args; + + if (formData.type !== DataSourceType.index_patterns) { + return; + } + + return indexPatternValidatorFactory()(...args); + }, + }, + ], + }, + data_view_id: { + label: i18n.translate( + 'xpack.securitySolution.ruleManagement.threeWayDiff.finalEdit.dataViewSelector.name', + { + defaultMessage: 'Data view', + } + ), + validations: [ + { + validator: (...args: Parameters) => { + const [{ formData }] = args; + + if (formData.type !== DataSourceType.data_view) { + return; + } + + return dataViewIdValidatorFactory()(...args); + }, + }, + ], + }, +} as FormSchema<{ + type: string; + index_patterns: string[]; + data_view_id: string; +}>; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_info_text.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_info_text.tsx new file mode 100644 index 0000000000000..737dcf2061f29 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_info_text.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { DocLink } from '../../../../../../../../common/components/links_to_docs/doc_link'; + +export function DataSourceInfoText(): JSX.Element { + return ( + + + + + + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_type_selector_field.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_type_selector_field.tsx new file mode 100644 index 0000000000000..f43051853a4d4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_type_selector_field.tsx @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useMemo } from 'react'; +import { i18n as i18nCore } from '@kbn/i18n'; +import type { EuiButtonGroupOptionProps } from '@elastic/eui'; +import { EuiButtonGroup } from '@elastic/eui'; +import { DataSourceType } from '../../../../../../../../../common/api/detection_engine/prebuilt_rules'; +import type { FieldHook } from '../../../../../../../../shared_imports'; +import type { ResetFormFn } from '../rule_field_edit_component_props'; + +interface DataSourceTypeSelectorFieldProps { + field: FieldHook; + resetForm: ResetFormFn; +} + +export function DataSourceTypeSelectorField({ + field, + resetForm, +}: DataSourceTypeSelectorFieldProps): JSX.Element { + const dataViewIndexPatternToggleButtonOptions: EuiButtonGroupOptionProps[] = useMemo( + () => [ + { + id: DataSourceType.index_patterns, + label: i18nCore.translate( + 'xpack.securitySolution.ruleDefine.indexTypeSelect.indexPattern', + { + defaultMessage: 'Index Patterns', + } + ), + iconType: field.value === DataSourceType.index_patterns ? 'checkInCircleFilled' : 'empty', + 'data-test-subj': `rule-index-toggle-${DataSourceType.index_patterns}`, + }, + { + id: DataSourceType.data_view, + label: i18nCore.translate('xpack.securitySolution.ruleDefine.indexTypeSelect.dataView', { + defaultMessage: 'Data View', + }), + iconType: field.value === DataSourceType.data_view ? 'checkInCircleFilled' : 'empty', + 'data-test-subj': `rule-index-toggle-${DataSourceType.data_view}`, + }, + ], + [field.value] + ); + const handleDataSourceChange = useCallback( + (optionId: string) => { + field.setValue(optionId); + resetForm({ resetValues: false }); + }, + [field, resetForm] + ); + + return ( + + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_view_field.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_view_field.tsx new file mode 100644 index 0000000000000..b534817596e66 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_view_field.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { DataViewSelectorField } from '../../../../../../../rule_creation_ui/components/data_view_selector_field'; +import type { FieldHook } from '../../../../../../../../shared_imports'; + +interface DataViewFieldProps { + field: FieldHook; +} + +export function DataViewField({ field }: DataViewFieldProps): JSX.Element { + return ; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/index.ts new file mode 100644 index 0000000000000..407874ac13143 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './data_source_edit_form'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/index_pattern_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/index_pattern_edit.tsx new file mode 100644 index 0000000000000..ec9f294af7612 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/index_pattern_edit.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import { isEqual } from 'lodash'; +import { css } from '@emotion/css'; +import { EuiButtonEmpty } from '@elastic/eui'; +import { useDefaultIndexPattern } from '../../../../../../hooks/use_default_index_pattern'; +import type { FieldHook } from '../../../../../../../../shared_imports'; +import { Field } from '../../../../../../../../shared_imports'; +import * as i18n from './translations'; + +interface IndexPatternFieldProps { + field: FieldHook; +} + +export function IndexPatternField({ field }: IndexPatternFieldProps): JSX.Element { + const defaultIndexPattern = useDefaultIndexPattern(); + const isIndexModified = !isEqual(field.value, defaultIndexPattern); + + const handleResetIndices = useCallback( + () => field.setValue(defaultIndexPattern), + [field, defaultIndexPattern] + ); + + return ( + } + idAria="indexPatternEdit" + data-test-subj="indexPatternEdit" + euiFieldProps={{ + fullWidth: true, + placeholder: '', + }} + labelAppend={ + isIndexModified ? ( + + {i18n.RESET_DEFAULT_INDEX} + + ) : undefined + } + /> + ); +} + +const xxsHeight = css` + height: 16px; +`; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/translations.tsx new file mode 100644 index 0000000000000..c1aede50af35f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/translations.tsx @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const RESET_DEFAULT_INDEX = i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.resetDefaultIndicesButton', + { + defaultMessage: 'Reset to default index patterns', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query.tsx deleted file mode 100644 index 69a00436b6992..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query.tsx +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback } from 'react'; -import useToggle from 'react-use/lib/useToggle'; -import { css } from '@emotion/css'; -import { EuiButtonEmpty } from '@elastic/eui'; -import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; -import type { FormSchema, FormData } from '../../../../../../../shared_imports'; -import { HiddenField, UseField } from '../../../../../../../shared_imports'; -import { schema } from '../../../../../../rule_creation_ui/components/step_define_rule/schema'; -import { QueryBarDefineRule } from '../../../../../../rule_creation_ui/components/query_bar'; -import type { FieldValueQueryBar } from '../../../../../../rule_creation_ui/components/query_bar'; -import * as stepDefineRuleI18n from '../../../../../../rule_creation_ui/components/step_define_rule/translations'; -import { useRuleIndexPattern } from '../../../../../../rule_creation_ui/pages/form'; -import { - DataSourceType as DataSourceTypeSnakeCase, - KqlQueryLanguage, - KqlQueryType, - RuleQuery, - SavedQueryId, - RuleKqlQuery, -} from '../../../../../../../../common/api/detection_engine'; -import type { - DiffableRule, - DiffableRuleTypes, - InlineKqlQuery, - SavedKqlQuery, -} from '../../../../../../../../common/api/detection_engine'; -import { useDefaultIndexPattern } from '../../../use_default_index_pattern'; -import { DataSourceType } from '../../../../../../../detections/pages/detection_engine/rules/types'; -import { isFilters } from '../../../helpers'; -import type { SetRuleQuery } from '../../../../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; -import { useRuleFromTimeline } from '../../../../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; -import { useGetSavedQuery } from '../../../../../../../detections/pages/detection_engine/rules/use_get_saved_query'; - -export const kqlQuerySchema = { - ruleType: schema.ruleType, - queryBar: schema.queryBar, -} as FormSchema<{ - ruleType: DiffableRuleTypes; - queryBar: FieldValueQueryBar; -}>; - -interface KqlQueryEditProps { - finalDiffableRule: DiffableRule; - setValidity: (isValid: boolean) => void; - setFieldValue: (fieldName: string, fieldValue: unknown) => void; -} - -export function KqlQueryEdit({ - finalDiffableRule, - setValidity, - setFieldValue, -}: KqlQueryEditProps): JSX.Element { - const defaultIndexPattern = useDefaultIndexPattern(); - const indexPatternParameters = getUseRuleIndexPatternParameters( - finalDiffableRule, - defaultIndexPattern - ); - const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern(indexPatternParameters); - - const [isTimelineSearchOpen, toggleIsTimelineSearchOpen] = useToggle(false); - - const handleSetRuleFromTimeline = useCallback( - ({ queryBar: timelineQueryBar }) => { - setFieldValue('queryBar', timelineQueryBar); - }, - [setFieldValue] - ); - - const { onOpenTimeline } = useRuleFromTimeline(handleSetRuleFromTimeline); - - const isSavedQueryRule = finalDiffableRule.type === 'saved_query'; - - const { savedQuery } = useGetSavedQuery({ - savedQueryId: getSavedQueryId(finalDiffableRule), - ruleType: finalDiffableRule.type, - }); - - return ( - <> - - - ), - }} - component={QueryBarDefineRule} - componentProps={{ - indexPattern, - isLoading: isIndexPatternLoading, - openTimelineSearch: isTimelineSearchOpen, - onCloseTimelineSearch: toggleIsTimelineSearchOpen, - onValidityChange: setValidity, - onOpenTimeline, - isDisabled: isSavedQueryRule, - defaultSavedQuery: savedQuery, - resetToSavedQuery: isSavedQueryRule, - }} - /> - - ); -} - -const timelineButtonClassName = css` - height: 18px; - font-size: 12px; -`; - -function ImportTimelineQueryButton({ - handleOpenTimelineSearch, -}: { - handleOpenTimelineSearch: () => void; -}) { - return ( - - {stepDefineRuleI18n.IMPORT_TIMELINE_QUERY} - - ); -} - -export function kqlQuerySerializer(formData: FormData): { - kql_query: RuleKqlQuery; -} { - const formValue = formData as { ruleType: Type; queryBar: FieldValueQueryBar }; - - if (formValue.ruleType === 'saved_query') { - const savedQueryId = SavedQueryId.parse(formValue.queryBar.saved_id); - - const savedKqlQuery: SavedKqlQuery = { - type: KqlQueryType.saved_query, - saved_query_id: savedQueryId, - }; - - return { - kql_query: savedKqlQuery, - }; - } - - const query = RuleQuery.parse(formValue.queryBar.query.query); - const language = KqlQueryLanguage.parse(formValue.queryBar.query.language); - - const inlineKqlQuery: InlineKqlQuery = { - type: KqlQueryType.inline_query, - query, - language, - filters: formValue.queryBar.filters, - }; - - return { kql_query: inlineKqlQuery }; -} - -export function kqlQueryDeserializer( - fieldValue: FormData, - finalDiffableRule: DiffableRule -): { - ruleType: Type; - queryBar: FieldValueQueryBar; -} { - const parsedFieldValue = RuleKqlQuery.parse(fieldValue); - - if (parsedFieldValue.type === KqlQueryType.inline_query) { - const returnValue = { - ruleType: finalDiffableRule.type, - queryBar: { - query: { - query: parsedFieldValue.query, - language: parsedFieldValue.language, - }, - filters: isFilters(parsedFieldValue.filters) ? parsedFieldValue.filters : [], - saved_id: null, - }, - }; - - return returnValue; - } - - const returnValue = { - ruleType: finalDiffableRule.type, - queryBar: { - query: { - query: '', - language: '', - }, - filters: [], - saved_id: parsedFieldValue.saved_query_id, - }, - }; - - return returnValue; -} - -interface UseRuleIndexPatternParameters { - dataSourceType: DataSourceType; - index: string[]; - dataViewId: string | undefined; -} - -function getUseRuleIndexPatternParameters( - finalDiffableRule: DiffableRule, - defaultIndexPattern: string[] -): UseRuleIndexPatternParameters { - if (!('data_source' in finalDiffableRule) || !finalDiffableRule.data_source) { - return { - dataSourceType: DataSourceType.IndexPatterns, - index: defaultIndexPattern, - dataViewId: undefined, - }; - } - if (finalDiffableRule.data_source.type === DataSourceTypeSnakeCase.data_view) { - return { - dataSourceType: DataSourceType.DataView, - index: [], - dataViewId: finalDiffableRule.data_source.data_view_id, - }; - } - return { - dataSourceType: DataSourceType.IndexPatterns, - index: finalDiffableRule.data_source.index_patterns, - dataViewId: undefined, - }; -} - -function getSavedQueryId(diffableRule: DiffableRule): string | undefined { - if (diffableRule.type === 'saved_query' && 'saved_query_id' in diffableRule.kql_query) { - return diffableRule.kql_query.saved_query_id; - } - - return undefined; -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/index.ts new file mode 100644 index 0000000000000..f04cdb36c19a9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './kql_query_edit_form'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx new file mode 100644 index 0000000000000..e1e4ddb0d14e9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import useToggle from 'react-use/lib/useToggle'; +import { css } from '@emotion/css'; +import { EuiButtonEmpty } from '@elastic/eui'; +import { schema } from '../../../../../../../rule_creation_ui/components/step_define_rule/schema'; +import { HiddenField, UseField } from '../../../../../../../../shared_imports'; +import { QueryBarDefineRule } from '../../../../../../../rule_creation_ui/components/query_bar'; +import * as stepDefineRuleI18n from '../../../../../../../rule_creation_ui/components/step_define_rule/translations'; +import { useRuleIndexPattern } from '../../../../../../../rule_creation_ui/pages/form'; +import { DataSourceType as DataSourceTypeSnakeCase } from '../../../../../../../../../common/api/detection_engine'; +import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; +import { useDefaultIndexPattern } from '../../../../../../hooks/use_default_index_pattern'; +import { DataSourceType } from '../../../../../../../../detections/pages/detection_engine/rules/types'; +import type { SetRuleQuery } from '../../../../../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; +import { useRuleFromTimeline } from '../../../../../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; +import { useGetSavedQuery } from '../../../../../../../../detections/pages/detection_engine/rules/use_get_saved_query'; +import type { RuleFieldEditComponentProps } from '../rule_field_edit_component_props'; + +export function KqlQueryEdit({ + finalDiffableRule, + setFieldValue, +}: RuleFieldEditComponentProps): JSX.Element { + const defaultIndexPattern = useDefaultIndexPattern(); + const indexPatternParameters = getRuleIndexPatternParameters( + finalDiffableRule, + defaultIndexPattern + ); + const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern(indexPatternParameters); + + const [isTimelineSearchOpen, toggleIsTimelineSearchOpen] = useToggle(false); + + const handleSetRuleFromTimeline = useCallback( + ({ queryBar: timelineQueryBar }) => { + setFieldValue('queryBar', timelineQueryBar); + }, + [setFieldValue] + ); + + const { onOpenTimeline } = useRuleFromTimeline(handleSetRuleFromTimeline); + + const isSavedQueryRule = finalDiffableRule.type === 'saved_query'; + + const { savedQuery } = useGetSavedQuery({ + savedQueryId: getSavedQueryId(finalDiffableRule), + ruleType: finalDiffableRule.type, + }); + + return ( + <> + + + ), + }} + component={QueryBarDefineRule} + componentProps={{ + indexPattern, + isLoading: isIndexPatternLoading, + openTimelineSearch: isTimelineSearchOpen, + onCloseTimelineSearch: toggleIsTimelineSearchOpen, + onOpenTimeline, + isDisabled: isSavedQueryRule, + defaultSavedQuery: savedQuery, + resetToSavedQuery: isSavedQueryRule, + }} + /> + + ); +} + +const timelineButtonClassName = css` + height: 18px; + font-size: 12px; +`; + +function ImportTimelineQueryButton({ + handleOpenTimelineSearch, +}: { + handleOpenTimelineSearch: () => void; +}) { + return ( + + {stepDefineRuleI18n.IMPORT_TIMELINE_QUERY} + + ); +} + +interface RuleIndexPatternParameters { + dataSourceType: DataSourceType; + index: string[]; + dataViewId: string | undefined; +} + +function getRuleIndexPatternParameters( + finalDiffableRule: DiffableRule, + defaultIndexPattern: string[] +): RuleIndexPatternParameters { + if (!('data_source' in finalDiffableRule) || !finalDiffableRule.data_source) { + return { + dataSourceType: DataSourceType.IndexPatterns, + index: defaultIndexPattern, + dataViewId: undefined, + }; + } + if (finalDiffableRule.data_source.type === DataSourceTypeSnakeCase.data_view) { + return { + dataSourceType: DataSourceType.DataView, + index: [], + dataViewId: finalDiffableRule.data_source.data_view_id, + }; + } + return { + dataSourceType: DataSourceType.IndexPatterns, + index: finalDiffableRule.data_source.index_patterns, + dataViewId: undefined, + }; +} + +function getSavedQueryId(diffableRule: DiffableRule): string | undefined { + if (diffableRule.type === 'saved_query' && 'saved_query_id' in diffableRule.kql_query) { + return diffableRule.kql_query.saved_query_id; + } + + return undefined; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx new file mode 100644 index 0000000000000..b6bab6e57976c --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx @@ -0,0 +1,118 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { FormData, FormSchema } from '../../../../../../../../shared_imports'; +import { schema } from '../../../../../../../rule_creation_ui/components/step_define_rule/schema'; +import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; +import type { FieldValueQueryBar } from '../../../../../../../rule_creation_ui/components/query_bar'; +import { + KqlQueryLanguage, + KqlQueryType, + RuleQuery, + SavedQueryId, + RuleKqlQuery, +} from '../../../../../../../../../common/api/detection_engine'; +import type { + DiffableRule, + DiffableRuleTypes, + InlineKqlQuery, + SavedKqlQuery, +} from '../../../../../../../../../common/api/detection_engine'; +import { isFilters } from '../../../../helpers'; +import { KqlQueryEdit } from './kql_query_edit'; + +export function KqlQueryEditForm(): JSX.Element { + return ( + + ); +} + +const kqlQuerySchema = { + ruleType: schema.ruleType, + queryBar: schema.queryBar, +} as FormSchema<{ + ruleType: DiffableRuleTypes; + queryBar: FieldValueQueryBar; +}>; + +function kqlQueryDeserializer( + fieldValue: FormData, + finalDiffableRule: DiffableRule +): { + ruleType: Type; + queryBar: FieldValueQueryBar; +} { + const parsedFieldValue = RuleKqlQuery.parse(fieldValue.kql_query); + + if (parsedFieldValue.type === KqlQueryType.inline_query) { + const returnValue = { + ruleType: finalDiffableRule.type, + queryBar: { + query: { + query: parsedFieldValue.query, + language: parsedFieldValue.language, + }, + filters: isFilters(parsedFieldValue.filters) ? parsedFieldValue.filters : [], + saved_id: null, + }, + }; + + return returnValue; + } + + const returnValue = { + ruleType: finalDiffableRule.type, + queryBar: { + query: { + query: '', + language: '', + }, + filters: [], + saved_id: parsedFieldValue.saved_query_id, + }, + }; + + return returnValue; +} + +function kqlQuerySerializer(formData: FormData): { + kql_query: RuleKqlQuery; +} { + const formValue = formData as { ruleType: Type; queryBar: FieldValueQueryBar }; + + if (formValue.ruleType === 'saved_query') { + const savedQueryId = SavedQueryId.parse(formValue.queryBar.saved_id); + + const savedKqlQuery: SavedKqlQuery = { + type: KqlQueryType.saved_query, + saved_query_id: savedQueryId, + }; + + return { + kql_query: savedKqlQuery, + }; + } + + const query = RuleQuery.parse(formValue.queryBar.query.query); + const language = KqlQueryLanguage.parse(formValue.queryBar.query.language); + + const inlineKqlQuery: InlineKqlQuery = { + type: KqlQueryType.inline_query, + query, + language, + filters: formValue.queryBar.filters, + }; + + return { kql_query: inlineKqlQuery }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_component_props.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_component_props.ts new file mode 100644 index 0000000000000..46ba6efdd847b --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_component_props.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FormData } from '../../../../../../../shared_imports'; +import type { DiffableRule } from '../../../../../../../../common/api/detection_engine'; + +export interface RuleFieldEditComponentProps { + finalDiffableRule: DiffableRule; + setFieldValue: SetFieldValueFn; + resetForm: ResetFormFn; +} + +type SetFieldValueFn = (fieldName: string, fieldValue: unknown) => void; + +export type ResetFormFn = (options?: { + resetValues?: boolean; + defaultValue?: Partial | undefined; +}) => void; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/field_form_wrapper.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx similarity index 61% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/field_form_wrapper.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx index b4a53ee7aea0a..26a2574489b16 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/field_form_wrapper.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx @@ -5,28 +5,30 @@ * 2.0. */ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect } from 'react'; import { EuiButtonEmpty, EuiFlexGroup } from '@elastic/eui'; -import { useForm, Form } from '../../../../../../shared_imports'; -import type { FormSchema, FormData } from '../../../../../../shared_imports'; +import { useForm, Form } from '../../../../../../../shared_imports'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; import type { DiffableAllFields, DiffableRule, -} from '../../../../../../../common/api/detection_engine'; -import { useFinalSideContext } from '../final_side/final_side_context'; -import { useDiffableRuleContext } from '../diffable_rule_context'; -import * as i18n from '../translations'; +} from '../../../../../../../../common/api/detection_engine'; +import { useFinalSideContext } from '../../final_side/final_side_context'; +import { useDiffableRuleContext } from '../../diffable_rule_context'; +import * as i18n from '../../translations'; +import type { RuleFieldEditComponentProps } from './rule_field_edit_component_props'; -type FieldComponent = React.ComponentType<{ - finalDiffableRule: DiffableRule; - setValidity: (isValid: boolean) => void; - setFieldValue: (fieldName: string, fieldValue: unknown) => void; -}>; +type RuleFieldEditComponent = React.ComponentType; -interface FieldFormWrapperProps { - component: FieldComponent; - fieldFormSchema: FormSchema; - deserializer?: (fieldValue: FormData, finalDiffableRule: DiffableRule) => FormData; +export type FieldDeserializerFn = ( + defaultRuleFieldValue: FormData, + finalDiffableRule: DiffableRule +) => FormData; + +interface RuleFieldEditFormWrapperProps { + component: RuleFieldEditComponent; + ruleFieldFormSchema: FormSchema; + deserializer?: FieldDeserializerFn; serializer?: (formData: FormData) => FormData; } @@ -35,30 +37,23 @@ interface FieldFormWrapperProps { * * @param {Object} props - Component props. * @param {React.ComponentType} props.component - Field component to be wrapped. - * @param {FormSchema} props.fieldFormSchema - Configuration schema for the field. + * @param {FormSchema} props.ruleFieldFormSchema - Configuration schema for the field. * @param {Function} props.deserializer - Deserializer prepares initial form data. It converts field value from a DiffableRule format to a format used by the form. * @param {Function} props.serializer - Serializer prepares form data for submission. It converts form data back to a DiffableRule format. */ -export function FieldFormWrapper({ +export function RuleFieldEditFormWrapper({ component: FieldComponent, - fieldFormSchema, + ruleFieldFormSchema, deserializer, serializer, -}: FieldFormWrapperProps) { +}: RuleFieldEditFormWrapperProps) { const { fieldName, setReadOnlyMode } = useFinalSideContext(); const { finalDiffableRule, setRuleFieldResolvedValue } = useDiffableRuleContext(); const deserialize = useCallback( - (defaultValue: FormData): FormData => { - if (!deserializer) { - return defaultValue; - } - - const rule = finalDiffableRule as Record; - const fieldValue = rule[fieldName] as FormData; - return deserializer(fieldValue, finalDiffableRule); - }, - [deserializer, fieldName, finalDiffableRule] + (defaultValue: FormData): FormData => + deserializer ? deserializer(defaultValue, finalDiffableRule) : defaultValue, + [deserializer, finalDiffableRule] ); const handleSubmit = useCallback( @@ -78,16 +73,18 @@ export function FieldFormWrapper({ ); const { form } = useForm({ - schema: fieldFormSchema, + schema: ruleFieldFormSchema, defaultValue: getDefaultValue(fieldName, finalDiffableRule), deserializer: deserialize, serializer, onSubmit: handleSubmit, }); - const [validity, setValidity] = useState(undefined); - - const isValid = validity === undefined ? form.isValid : validity; + // form.isValid has `undefined` value until all fields are dirty. + // Run the validation upfront to visualize form validity state. + useEffect(() => { + form.validate(); + }, [form]); return ( <> @@ -95,15 +92,15 @@ export function FieldFormWrapper({ {i18n.CANCEL_BUTTON_LABEL} - + {i18n.SAVE_BUTTON_LABEL}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/final_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/final_edit.tsx index 698d138208d70..5c32c8edc7924 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/final_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/final_edit.tsx @@ -20,9 +20,11 @@ import type { UpgradeableThreatMatchFields, UpgradeableThresholdFields, UpgradeableNewTermsFields, + UpgradeableEqlFields, } from '../../../../model/prebuilt_rule_upgrade/fields'; import { isCommonFieldName } from '../../../../model/prebuilt_rule_upgrade/fields'; import { useFinalSideContext } from '../final_side/final_side_context'; +import { EqlRuleFieldEdit } from './eql_rule_field_edit'; export function FinalEdit() { const { finalDiffableRule } = useDiffableRuleContext(); @@ -40,7 +42,7 @@ export function FinalEdit() { case 'saved_query': return ; case 'eql': - return {'Rule type not yet implemented'}; + return ; case 'esql': return {'Rule type not yet implemented'}; case 'threat_match': diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/new_terms_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/new_terms_rule_field_edit.tsx index 183200aef1c43..e5d01b3cfff7d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/new_terms_rule_field_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/new_terms_rule_field_edit.tsx @@ -6,14 +6,9 @@ */ import React from 'react'; -import { FieldFormWrapper } from './field_form_wrapper'; -import { - KqlQueryEdit, - kqlQuerySchema, - kqlQuerySerializer, - kqlQueryDeserializer, -} from './fields/kql_query'; import type { UpgradeableNewTermsFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import { KqlQueryEditForm } from './fields/kql_query'; +import { DataSourceEditForm } from './fields/data_source'; interface NewTermsRuleFieldEditProps { fieldName: UpgradeableNewTermsFields; @@ -22,14 +17,9 @@ interface NewTermsRuleFieldEditProps { export function NewTermsRuleFieldEdit({ fieldName }: NewTermsRuleFieldEditProps) { switch (fieldName) { case 'kql_query': - return ( - - ); + return ; + case 'data_source': + return ; default: return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/saved_query_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/saved_query_rule_field_edit.tsx index fa573e6339e9f..851b8f6c95fb5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/saved_query_rule_field_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/saved_query_rule_field_edit.tsx @@ -6,14 +6,9 @@ */ import React from 'react'; -import { FieldFormWrapper } from './field_form_wrapper'; -import { - KqlQueryEdit, - kqlQuerySchema, - kqlQuerySerializer, - kqlQueryDeserializer, -} from './fields/kql_query'; import type { UpgradeableSavedQueryFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import { KqlQueryEditForm } from './fields/kql_query'; +import { DataSourceEditForm } from './fields/data_source'; interface SavedQueryRuleFieldEditProps { fieldName: UpgradeableSavedQueryFields; @@ -22,14 +17,9 @@ interface SavedQueryRuleFieldEditProps { export function SavedQueryRuleFieldEdit({ fieldName }: SavedQueryRuleFieldEditProps) { switch (fieldName) { case 'kql_query': - return ( - - ); + return ; + case 'data_source': + return ; default: return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/threat_match_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/threat_match_rule_field_edit.tsx index 5f2adbb113fd5..6a92f7372563e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/threat_match_rule_field_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/threat_match_rule_field_edit.tsx @@ -6,14 +6,9 @@ */ import React from 'react'; -import { FieldFormWrapper } from './field_form_wrapper'; -import { - KqlQueryEdit, - kqlQuerySchema, - kqlQuerySerializer, - kqlQueryDeserializer, -} from './fields/kql_query'; import type { UpgradeableThreatMatchFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import { KqlQueryEditForm } from './fields/kql_query'; +import { DataSourceEditForm } from './fields/data_source'; interface ThreatMatchRuleFieldEditProps { fieldName: UpgradeableThreatMatchFields; @@ -22,14 +17,9 @@ interface ThreatMatchRuleFieldEditProps { export function ThreatMatchRuleFieldEdit({ fieldName }: ThreatMatchRuleFieldEditProps) { switch (fieldName) { case 'kql_query': - return ( - - ); + return ; + case 'data_source': + return ; default: return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/threshold_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/threshold_rule_field_edit.tsx index 4975ca49205e7..d1fc2372d7a16 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/threshold_rule_field_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/threshold_rule_field_edit.tsx @@ -6,14 +6,9 @@ */ import React from 'react'; -import { FieldFormWrapper } from './field_form_wrapper'; -import { - KqlQueryEdit, - kqlQuerySchema, - kqlQuerySerializer, - kqlQueryDeserializer, -} from './fields/kql_query'; import type { UpgradeableThresholdFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import { KqlQueryEditForm } from './fields/kql_query'; +import { DataSourceEditForm } from './fields/data_source'; interface ThresholdRuleFieldEditProps { fieldName: UpgradeableThresholdFields; @@ -22,14 +17,9 @@ interface ThresholdRuleFieldEditProps { export function ThresholdRuleFieldEdit({ fieldName }: ThresholdRuleFieldEditProps) { switch (fieldName) { case 'kql_query': - return ( - - ); + return ; + case 'data_source': + return ; default: return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/use_default_index_pattern.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/hooks/use_default_index_pattern.tsx similarity index 63% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/use_default_index_pattern.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/hooks/use_default_index_pattern.tsx index 3482df562bac0..b5ca86c6f1f57 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/use_default_index_pattern.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/hooks/use_default_index_pattern.tsx @@ -5,23 +5,21 @@ * 2.0. */ -import { useKibana } from '../../../../common/lib/kibana/kibana_react'; -import { DEFAULT_INDEX_KEY, DEFAULT_INDEX_PATTERN } from '../../../../../common/constants'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; +import { useKibana } from '../../../common/lib/kibana/kibana_react'; +import { DEFAULT_INDEX_KEY, DEFAULT_INDEX_PATTERN } from '../../../../common/constants'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; /** * Gets the default index pattern for cases when rule has neither index patterns or data view. * First checks the config value. If it's not present falls back to the hardcoded default value. */ -export function useDefaultIndexPattern() { +export function useDefaultIndexPattern(): string[] { const { services } = useKibana(); const isPrebuiltRulesCustomizationEnabled = useIsExperimentalFeatureEnabled( 'prebuiltRulesCustomizationEnabled' ); - if (isPrebuiltRulesCustomizationEnabled) { - return services.settings.client.get(DEFAULT_INDEX_KEY, DEFAULT_INDEX_PATTERN); - } - - return []; + return isPrebuiltRulesCustomizationEnabled + ? services.settings.client.get(DEFAULT_INDEX_KEY, DEFAULT_INDEX_PATTERN) + : []; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts index d44f9738b1fd6..29c5b2b201fe6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts @@ -6,6 +6,7 @@ */ import { useCallback, useMemo, useState } from 'react'; +import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import type { RulesUpgradeState, FieldsUpgradeState, @@ -32,6 +33,9 @@ interface UseRulesUpgradeStateResult { export function usePrebuiltRulesUpgradeState( ruleUpgradeInfos: RuleUpgradeInfoForReview[] ): UseRulesUpgradeStateResult { + const isPrebuiltRulesCustomizationEnabled = useIsExperimentalFeatureEnabled( + 'prebuiltRulesCustomizationEnabled' + ); const [rulesResolvedConflicts, setRulesResolvedConflicts] = useState({}); const setRuleFieldResolvedValue = useCallback( @@ -61,16 +65,17 @@ export function usePrebuiltRulesUpgradeState( ruleUpgradeInfo.diff.fields, rulesResolvedConflicts[ruleUpgradeInfo.rule_id] ?? {} ), - hasUnresolvedConflicts: - getUnacceptedConflictsCount( - ruleUpgradeInfo.diff.fields, - rulesResolvedConflicts[ruleUpgradeInfo.rule_id] ?? {} - ) > 0, + hasUnresolvedConflicts: isPrebuiltRulesCustomizationEnabled + ? getUnacceptedConflictsCount( + ruleUpgradeInfo.diff.fields, + rulesResolvedConflicts[ruleUpgradeInfo.rule_id] ?? {} + ) > 0 + : false, }; } return state; - }, [ruleUpgradeInfos, rulesResolvedConflicts]); + }, [ruleUpgradeInfos, rulesResolvedConflicts, isPrebuiltRulesCustomizationEnabled]); return { rulesUpgradeState, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/index.test.tsx index 668f323d147cb..38d68f2af0ad6 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/index.test.tsx @@ -156,6 +156,7 @@ describe('ChartPanels', () => { indicesExist: true, indexPattern: {}, browserFields: mockBrowserFields, + sourcererDataView: {}, }); (useAlertsLocalStorage as jest.Mock).mockReturnValue({ diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.test.tsx index 17c7ce8195c0c..cf57c9d59b080 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.test.tsx @@ -159,6 +159,7 @@ describe('GroupedAlertsTable', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ ...sourcererDataView, selectedPatterns: ['myFakebeat-*'], + sourcererDataView: {}, }); mockUseQueryAlerts.mockImplementation((i) => { if (i.skip) { diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx index 8b02530fec07a..a1cbdc8004727 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx @@ -67,7 +67,9 @@ const useStorage = (storage: Storage, tableId: string) => const GroupedAlertsTableComponent: React.FC = (props) => { const dispatch = useDispatch(); - const { indexPattern, selectedPatterns } = useSourcererDataView(SourcererScopeName.detections); + const { sourcererDataView, selectedPatterns } = useSourcererDataView( + SourcererScopeName.detections + ); const { services: { storage, telemetry }, @@ -102,6 +104,8 @@ const GroupedAlertsTableComponent: React.FC = (props) [dispatch, props.tableId] ); + const fields = useMemo(() => Object.values(sourcererDataView.fields || {}), [sourcererDataView]); + const { getGrouping, selectedGroups, setSelectedGroups } = useGrouping({ componentProps: { groupPanelRenderer: renderGroupPanel, @@ -110,7 +114,7 @@ const GroupedAlertsTableComponent: React.FC = (props) unit: defaultUnit, }, defaultGroupingOptions: getDefaultGroupingOptions(props.tableId), - fields: indexPattern.fields, + fields, groupingId: props.tableId, maxGroupingLevels: MAX_GROUPING_LEVELS, onGroupChange, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_sub_grouping.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_sub_grouping.tsx index 4b8c912c61a65..c941f5ecf46ed 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_sub_grouping.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_sub_grouping.tsx @@ -91,15 +91,15 @@ export const GroupedSubLevelComponent: React.FC = ({ const { services: { uiSettings }, } = useKibana(); - const { browserFields, indexPattern } = useSourcererDataView(SourcererScopeName.detections); + const { browserFields, sourcererDataView } = useSourcererDataView(SourcererScopeName.detections); const getGlobalQuery = useCallback( (customFilters: Filter[]) => { - if (browserFields != null && indexPattern != null) { + if (browserFields != null && sourcererDataView) { return combineQueries({ config: getEsQueryConfig(uiSettings), dataProviders: [], - indexPattern, + indexPattern: sourcererDataView, browserFields, filters: [ ...(defaultFilters ?? []), @@ -120,10 +120,10 @@ export const GroupedSubLevelComponent: React.FC = ({ from, globalFilters, globalQuery, - indexPattern, parentGroupingFilter, to, uiSettings, + sourcererDataView, ] ); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx index 3b637340e01e4..0ca0e99bb7fd0 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -129,11 +129,7 @@ export const AlertsTableComponent: FC = ({ enableIpDetailsFlyout: true, onRuleChange, }); - const { - browserFields, - indexPattern: indexPatterns, - sourcererDataView, - } = useSourcererDataView(sourcererScope); + const { browserFields, sourcererDataView } = useSourcererDataView(sourcererScope); const license = useLicense(); const getGlobalFiltersQuerySelector = useMemo( @@ -167,11 +163,11 @@ export const AlertsTableComponent: FC = ({ } = useShallowEqualSelector((state: State) => eventsViewerSelector(state, tableId)); const combinedQuery = useMemo(() => { - if (browserFields != null && indexPatterns != null) { + if (browserFields != null && sourcererDataView) { return combineQueries({ config: getEsQueryConfig(uiSettings), dataProviders: [], - indexPattern: indexPatterns, + indexPattern: sourcererDataView, browserFields, filters: [...allFilters], kqlQuery: globalQuery, @@ -179,7 +175,7 @@ export const AlertsTableComponent: FC = ({ }); } return null; - }, [browserFields, globalQuery, indexPatterns, uiSettings, allFilters]); + }, [browserFields, globalQuery, sourcererDataView, uiSettings, allFilters]); useInvalidFilterQuery({ id: tableId, @@ -297,13 +293,13 @@ export const AlertsTableComponent: FC = ({ onUpdate: onAlertTableUpdate, cellContext, onLoaded: onLoad, - runtimeMappings: sourcererDataView?.runtimeFieldMap as RunTimeMappings, toolbarVisibility, // if records are too less, we don't want table to be of fixed height. // it should shrink to the content height. // Height setting enables/disables virtualization depending on fixed/undefined height values respectively. height: count >= 20 ? `${DEFAULT_DATA_GRID_HEIGHT}px` : undefined, initialPageSize: 50, + runtimeMappings: sourcererDataView.runtimeFieldMap as RunTimeMappings, }), [ triggersActionsUi.alertsTableConfigurationRegistry, @@ -317,9 +313,9 @@ export const AlertsTableComponent: FC = ({ onAlertTableUpdate, cellContext, onLoad, - sourcererDataView?.runtimeFieldMap, toolbarVisibility, count, + sourcererDataView.runtimeFieldMap, ] ); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline.tsx index 7399926f7e9a2..0086f40ffa44b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline.tsx @@ -67,7 +67,6 @@ export const useAddBulkToTimelineAction = ({ const { browserFields, dataViewId, - indexPattern, sourcererDataView, // important to get selectedPatterns from useSourcererDataView // in order to include the exclude filters in the search that are not stored in the timeline @@ -96,13 +95,13 @@ export const useAddBulkToTimelineAction = ({ return combineQueries({ config: esQueryConfig, dataProviders: [], - indexPattern, + indexPattern: sourcererDataView, filters: combinedFilters, kqlQuery: { query: '', language: 'kuery' }, browserFields, kqlMode: 'filter', }); - }, [esQueryConfig, indexPattern, combinedFilters, browserFields]); + }, [esQueryConfig, sourcererDataView, combinedFilters, browserFields]); const filterQuery = useMemo(() => { if (!combinedQuery) return ''; @@ -120,7 +119,7 @@ export const useAddBulkToTimelineAction = ({ sort: timelineQuerySortField, indexNames: selectedPatterns, filterQuery, - runtimeMappings: sourcererDataView?.runtimeFieldMap as RunTimeMappings, + runtimeMappings: sourcererDataView.runtimeFieldMap as RunTimeMappings, limit: Math.min(BULK_ADD_TO_TIMELINE_LIMIT, totalCount), timerangeKind: 'absolute', }); diff --git a/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.test.tsx b/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.test.tsx index 82d6a4726dbc2..d9683d9de1b04 100644 --- a/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.test.tsx @@ -72,9 +72,9 @@ describe('DetectionEngineFilters', () => { }, timeRange: { from: 'now-15m', to: 'now' }, onInit: jest.fn(), - indexPattern: { + dataViewSpec: { title: 'mock-title', - fields: [], + fields: {}, }, }; diff --git a/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx b/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx index 126c86055aa4c..6c60aec51382e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx @@ -13,21 +13,24 @@ import { ControlGroupRenderer } from '@kbn/controls-plugin/public'; import type { AlertFilterControlsProps } from '@kbn/alerts-ui-shared/src/alert_filter_controls'; import { AlertFilterControls } from '@kbn/alerts-ui-shared/src/alert_filter_controls'; import { useHistory } from 'react-router-dom'; +import type { DataViewSpec } from '@kbn/data-plugin/common'; import { useKibana } from '../../../common/lib/kibana'; import { DEFAULT_DETECTION_PAGE_FILTERS } from '../../../../common/constants'; import { URL_PARAM_KEY } from '../../../common/hooks/use_url_state'; import { useSpaceId } from '../../../common/hooks/use_space_id'; -import type { SecuritySolutionDataViewBase } from '../../../common/types'; import { SECURITY_ALERT_DATA_VIEW } from '../../constants'; export type DetectionEngineFiltersProps = Pick< AlertFilterControlsProps, 'filters' | 'onFiltersChange' | 'query' | 'timeRange' | 'onInit' > & { - indexPattern?: SecuritySolutionDataViewBase; + dataViewSpec?: DataViewSpec; }; -export const DetectionEngineFilters = ({ indexPattern, ...props }: DetectionEngineFiltersProps) => { +export const DetectionEngineFilters = ({ + dataViewSpec: indexPattern, + ...props +}: DetectionEngineFiltersProps) => { const { http, notifications, dataViews } = useKibana().services; const spaceId = useSpaceId(); const history = useHistory(); diff --git a/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.test.tsx b/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.test.tsx index 926109d90558d..6057410e1615e 100644 --- a/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.test.tsx @@ -27,6 +27,7 @@ jest.mock('../../../sourcerer/containers', () => ({ defaultIndex: 'defaultIndex', loading: false, indicesExist: true, + sourcererDataView: {}, }), })); jest.mock('../../../common/components/guided_onboarding_tour/tour_step'); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts index 7d44864681f0e..ce653c82d7831 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts @@ -112,6 +112,7 @@ describe('useRuleFromTimeline', () => { ...mockSourcererScope, dataViewId: 'custom-data-view-id', selectedPatterns: ['awesome-*'], + sourcererDataView: {}, }); }); diff --git a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_actions_column.tsx b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_actions_column.tsx index 39b8d7cad3f60..286d377d86f56 100644 --- a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_actions_column.tsx +++ b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_actions_column.tsx @@ -47,10 +47,10 @@ export const getUseActionColumnHook = } // we only want to show the note icon if the new notes system feature flag is enabled - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); - if (!securitySolutionNotesEnabled) { + if (securitySolutionNotesDisabled) { ACTION_BUTTON_COUNT--; } diff --git a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.test.tsx b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.test.tsx index 7334be4e2a466..d2ca9bd93198a 100644 --- a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.test.tsx @@ -74,6 +74,7 @@ describe('usePersistentControls', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ ...sourcererDataView, selectedPatterns: ['myFakebeat-*'], + sourcererDataView: {}, }); }); diff --git a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx index 1cce1c8a34594..dbd47281c5f2a 100644 --- a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx +++ b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx @@ -35,7 +35,7 @@ export const getPersistentControlsHook = (tableId: TableId) => { services: { telemetry }, } = useKibana(); - const { indexPattern } = useSourcererDataView(SourcererScopeName.detections); + const { sourcererDataView } = useSourcererDataView(SourcererScopeName.detections); const groupId = useMemo(() => groupIdSelector(), []); const { options } = useDeepEqualSelector((state) => groupId(state, tableId)) ?? { options: [], @@ -60,10 +60,14 @@ export const getPersistentControlsHook = (tableId: TableId) => { [dispatch, trackGroupChange] ); + const fields = useMemo(() => { + return Object.values(sourcererDataView.fields || {}); + }, [sourcererDataView.fields]); + const groupSelector = useGetGroupSelectorStateless({ groupingId: tableId, onGroupChange, - fields: indexPattern.fields, + fields, defaultGroupingOptions: options, maxGroupingLevels: 3, }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.test.tsx index 18efc5fcbad7f..4f8b8a391ea87 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.test.tsx @@ -212,8 +212,11 @@ describe('DetectionEnginePageComponent', () => { ]); (useSourcererDataView as jest.Mock).mockReturnValue({ indicesExist: true, - indexPattern: {}, browserFields: mockBrowserFields, + sourcererDataView: { + fields: {}, + title: '', + }, }); jest .spyOn(alertFilterControlsPackage, 'AlertFilterControls') diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx index 7784fbb5760c3..01aab96481d5a 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx @@ -151,11 +151,9 @@ const DetectionEnginePageComponent: React.FC = () FilterGroupHandler | undefined >(); - const { - sourcererDataView, - loading: isLoadingIndexPattern, - indexPattern, - } = useSourcererDataView(SourcererScopeName.detections); + const { sourcererDataView, loading: isLoadingIndexPattern } = useSourcererDataView( + SourcererScopeName.detections + ); const { formatUrl } = useFormatUrl(SecurityPageName.rules); @@ -314,10 +312,10 @@ const DetectionEnginePageComponent: React.FC = () mode: 'absolute', }} onInit={setDetectionPageFilterHandler} - indexPattern={indexPattern} + dataViewSpec={sourcererDataView} /> ), - [from, indexPattern, onFilterControlsChange, query, to, topLevelFilters] + [from, sourcererDataView, onFilterControlsChange, query, to, topLevelFilters] ); const renderAlertTable = useCallback( @@ -419,7 +417,7 @@ const DetectionEnginePageComponent: React.FC = () alertsDefaultFilters={alertsDefaultFilters} isLoadingIndexPattern={isChartPanelLoading} query={query} - runtimeMappings={sourcererDataView?.runtimeFieldMap as RunTimeMappings} + runtimeMappings={sourcererDataView.runtimeFieldMap as RunTimeMappings} signalIndexName={signalIndexName} updateDateRangeCallback={updateDateRangeCallback} /> @@ -435,7 +433,7 @@ const DetectionEnginePageComponent: React.FC = () hasIndexWrite={hasIndexWrite ?? false} loading={isAlertTableLoading} renderChildComponent={renderAlertTable} - runtimeMappings={sourcererDataView?.runtimeFieldMap as RunTimeMappings} + runtimeMappings={sourcererDataView.runtimeFieldMap as RunTimeMappings} signalIndexName={signalIndexName} tableId={TableId.alertsOnAlertsPage} to={to} diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/entity_store.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/entity_store.ts index 34789402c89a5..54f5415d24a35 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/entity_store.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/entity_store.ts @@ -43,9 +43,10 @@ export const useEntityStoreRoutes = () => { }); }; - const deleteEntityEngine = async (entityType: EntityType) => { + const deleteEntityEngine = async (entityType: EntityType, deleteData: boolean) => { return http.fetch(`/api/entity_store/engines/${entityType}`, { method: 'DELETE', + query: { data: deleteData }, version: API_VERSIONS.public.v1, }); }; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_preview_risk_scores.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_preview_risk_scores.ts index 837358aa96170..96a4453815125 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_preview_risk_scores.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_preview_risk_scores.ts @@ -9,38 +9,50 @@ import dateMath from '@kbn/datemath'; import type { RiskScoresPreviewRequest } from '../../../../common/api/entity_analytics/risk_engine/preview_route.gen'; import { useEntityAnalyticsRoutes } from '../api'; +export type UseRiskScorePreviewParams = Omit & { + data_view_id?: string; +}; + export const useRiskScorePreview = ({ data_view_id: dataViewId, range, filter, -}: RiskScoresPreviewRequest) => { +}: UseRiskScorePreviewParams) => { const { fetchRiskScorePreview } = useEntityAnalyticsRoutes(); - return useQuery(['POST', 'FETCH_PREVIEW_RISK_SCORE', range, filter], async ({ signal }) => { - const params: RiskScoresPreviewRequest = { data_view_id: dataViewId }; - if (range) { - const startTime = dateMath.parse(range.start)?.utc().toISOString(); - const endTime = dateMath - .parse(range.end, { - roundUp: true, - }) - ?.utc() - .toISOString(); - - if (startTime && endTime) { - params.range = { - start: startTime, - end: endTime, - }; + return useQuery( + ['POST', 'FETCH_PREVIEW_RISK_SCORE', range, filter], + async ({ signal }) => { + if (!dataViewId) { + return; + } + + const params: RiskScoresPreviewRequest = { data_view_id: dataViewId }; + if (range) { + const startTime = dateMath.parse(range.start)?.utc().toISOString(); + const endTime = dateMath + .parse(range.end, { + roundUp: true, + }) + ?.utc() + .toISOString(); + + if (startTime && endTime) { + params.range = { + start: startTime, + end: endTime, + }; + } } - } - if (filter) { - params.filter = filter; - } + if (filter) { + params.filter = filter; + } - const response = await fetchRiskScorePreview({ signal, params }); + const response = await fetchRiskScorePreview({ signal, params }); - return response; - }); + return response; + }, + { enabled: !!dataViewId } + ); }; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx index 3a71b48055fcc..07629b2c6e0b6 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx @@ -7,6 +7,7 @@ import { EuiButtonEmpty, + EuiButton, EuiCallOut, EuiCodeBlock, EuiFlexGroup, @@ -17,7 +18,8 @@ import { import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; -import type { BulkUpsertAssetCriticalityRecordsResponse } from '../../../../../common/entity_analytics/asset_criticality/types'; +import { SecurityPageName } from '@kbn/deeplinks-security'; +import type { BulkUpsertAssetCriticalityRecordsResponse } from '../../../../../common/api/entity_analytics'; import { buildAnnotationsFromError } from '../helpers'; import { ScheduleRiskEngineCallout } from './schedule_risk_engine_callout'; @@ -61,7 +63,7 @@ export const AssetCriticalityResultStep: React.FC<{ data-test-subj="asset-criticality-result-step-success" title={ } @@ -69,9 +71,18 @@ export const AssetCriticalityResultStep: React.FC<{ iconType="checkInCircleFilled" > + + + { + + } + diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_panels.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_panels.tsx index 3b4f661e949f2..63ffcf7b9eae1 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_panels.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_panels.tsx @@ -15,6 +15,7 @@ import { EuiLoadingLogo, EuiPanel, EuiImage, + EuiCallOut, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -50,9 +51,25 @@ const EntityStoreDashboardPanelsComponent = () => { const entityStore = useEntityEngineStatus(); const riskEngineStatus = useRiskEngineStatus(); - const { enable: enableStore } = useEntityStoreEnablement(); + const { enable: enableStore, query } = useEntityStoreEnablement(); + const { mutate: initRiskEngine } = useInitRiskEngineMutation(); + const callouts = entityStore.errors.map((err, i) => ( + + } + color="danger" + iconType="error" + > +

{err?.message}

+
+ )); + const enableEntityStore = (enable: Enablements) => () => { setModalState({ visible: false }); if (enable.riskScore) { @@ -66,6 +83,7 @@ const EntityStoreDashboardPanelsComponent = () => { }; setRiskEngineInitializing(true); initRiskEngine(undefined, options); + return; } if (enable.entityStore) { @@ -73,6 +91,26 @@ const EntityStoreDashboardPanelsComponent = () => { } }; + if (query.error) { + return ( + <> + + } + color="danger" + iconType="error" + > +

{(query.error as { body: { message: string } }).body.message}

+
+ {callouts} + + ); + } + if (entityStore.status === 'loading') { return ( @@ -103,27 +141,27 @@ const EntityStoreDashboardPanelsComponent = () => { ); } + // TODO Rename variable because the Risk score could be installed but disabled const isRiskScoreAvailable = riskEngineStatus.data && riskEngineStatus.data.risk_engine_status !== RiskEngineStatusEnum.NOT_INSTALLED; return ( - {entityStore.status === 'enabled' && isRiskScoreAvailable && ( + {entityStore.status === 'error' && isRiskScoreAvailable && ( <> + {callouts} - - - )} - {entityStore.status === 'enabled' && !isRiskScoreAvailable && ( + {entityStore.status === 'error' && !isRiskScoreAvailable && ( <> + {callouts} setModalState({ visible: true })} @@ -131,43 +169,69 @@ const EntityStoreDashboardPanelsComponent = () => { enablements="riskScore" /> - + + )} + {entityStore.status === 'enabled' && isRiskScoreAvailable && ( + <> + + + + + + )} - - {entityStore.status === 'not_installed' && !isRiskScoreAvailable && ( - // TODO: Move modal inside EnableEntityStore component, eliminating the onEnable prop in favour of forwarding the riskScoreEnabled status - setModalState({ visible: true })} - loadingRiskEngine={riskEngineInitializing} - /> - )} - - {entityStore.status === 'not_installed' && isRiskScoreAvailable && ( + {entityStore.status === 'enabled' && !isRiskScoreAvailable && ( <> - setModalState({ - visible: true, - }) - } + onEnable={() => setModalState({ visible: true })} + loadingRiskEngine={riskEngineInitializing} + enablements="riskScore" /> + - - - - + )} + {(entityStore.status === 'not_installed' || entityStore.status === 'stopped') && + !isRiskScoreAvailable && ( + // TODO: Move modal inside EnableEntityStore component, eliminating the onEnable prop in favour of forwarding the riskScoreEnabled status + setModalState({ visible: true })} + loadingRiskEngine={riskEngineInitializing} + /> + )} + + {(entityStore.status === 'not_installed' || entityStore.status === 'stopped') && + isRiskScoreAvailable && ( + <> + + + setModalState({ + visible: true, + }) + } + /> + + + + + + + + + )} + setModalState({ visible })} diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/entities_list.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/entities_list.test.tsx index 0e598d6463c5a..91f0c42eab385 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/entities_list.test.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/entities_list.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { render, screen, fireEvent } from '@testing-library/react'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { EntitiesList } from './entities_list'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useQueryToggle } from '../../../common/containers/query_toggle'; @@ -15,6 +15,7 @@ import { useErrorToast } from '../../../common/hooks/use_error_toast'; import type { ListEntitiesResponse } from '../../../../common/api/entity_analytics/entity_store/entities/list_entities.gen'; import { useGlobalFilterQuery } from '../../../common/hooks/use_global_filter_query'; import { TestProviders } from '../../../common/mock'; +import { times } from 'lodash/fp'; jest.mock('../../../common/containers/use_global_time'); jest.mock('../../../common/containers/query_toggle'); @@ -22,21 +23,23 @@ jest.mock('./hooks/use_entities_list_query'); jest.mock('../../../common/hooks/use_error_toast'); jest.mock('../../../common/hooks/use_global_filter_query'); -const entityName = 'Entity Name'; +const secondPageTestId = 'pagination-button-1'; +const entityName = 'Entity Name 1'; const responseData: ListEntitiesResponse = { page: 1, per_page: 10, - total: 1, - records: [ - { + total: 20, + records: times( + (index) => ({ '@timestamp': '2021-08-02T14:00:00.000Z', - user: { name: entityName }, + user: { name: `Entity Name ${index}` }, entity: { - name: entityName, + name: `Entity Name ${index}`, source: 'test-index', }, - }, - ], + }), + 10 + ), inspect: undefined, }; @@ -81,7 +84,7 @@ describe('EntitiesList', () => { it('displays the correct number of rows', () => { render(, { wrapper: TestProviders }); - expect(screen.getAllByRole('row')).toHaveLength(2); + expect(screen.getAllByRole('row')).toHaveLength(10 + 1); }); it('calls refetch on time range change', () => { @@ -112,6 +115,21 @@ describe('EntitiesList', () => { ); }); + it('should reset the page when sort order changes ', async () => { + render(, { wrapper: TestProviders }); + + const secondPageButton = screen.getByTestId(secondPageTestId); + fireEvent.click(secondPageButton); + + const columnHeader = screen.getByText('Name'); + fireEvent.click(columnHeader); + + await waitFor(() => { + const firstPageButton = screen.getByTestId('pagination-button-0'); + expect(firstPageButton).toHaveAttribute('aria-current', 'true'); + }); + }); + it('displays error toast when there is an error', () => { const error = new Error('Test error'); mockUseEntitiesListQuery.mockReturnValueOnce({ diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/entities_list.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/entities_list.tsx index aa03e41c553cb..69afa8dd32108 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/entities_list.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/entities_list.tsx @@ -94,6 +94,11 @@ export const EntitiesList: React.FC = () => { inspect: data?.inspect ?? null, }); + // Reset the active page when the search criteria changes + useEffect(() => { + setActivePage(0); + }, [sorting, limit, filter]); + const columns = useEntitiesListColumns(); // Force a refetch when "refresh" button is clicked. @@ -112,7 +117,7 @@ export const EntitiesList: React.FC = () => { return ( ['refetchInterval']; } +interface EngineError { + message: string; +} + export const useEntityEngineStatus = (opts: Options = {}) => { // QUESTION: Maybe we should have an `EnablementStatus` API route for this? const { listEntityEngines } = useEntityStoreRoutes(); @@ -33,6 +37,10 @@ export const useEntityEngineStatus = (opts: Options = {}) => { return 'not_installed'; } + if (data?.engines?.some((engine) => engine.status === 'error')) { + return 'error'; + } + if (data?.engines?.every((engine) => engine.status === 'stopped')) { return 'stopped'; } @@ -52,7 +60,12 @@ export const useEntityEngineStatus = (opts: Options = {}) => { return 'enabled'; })(); + const errors = (data?.engines + ?.filter((engine) => engine.status === 'error') + .map((engine) => engine.error) ?? []) as EngineError[]; + return { status, + errors, }; }; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts index 29e9e6c5098c4..21e73241451e5 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts @@ -9,6 +9,7 @@ import type { UseMutationOptions } from '@tanstack/react-query'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useCallback, useState } from 'react'; +import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import type { DeleteEntityEngineResponse, InitEntityEngineResponse, @@ -21,6 +22,7 @@ const ENTITY_STORE_ENABLEMENT_INIT = 'ENTITY_STORE_ENABLEMENT_INIT'; export const useEntityStoreEnablement = () => { const [polling, setPolling] = useState(false); + const { telemetry } = useKibana().services; useEntityEngineStatus({ disabled: !polling, @@ -39,17 +41,21 @@ export const useEntityStoreEnablement = () => { }); const { initEntityStore } = useEntityStoreRoutes(); - const { refetch: initialize } = useQuery({ + const { refetch: initialize, ...query } = useQuery({ queryKey: [ENTITY_STORE_ENABLEMENT_INIT], - queryFn: () => Promise.all([initEntityStore('user'), initEntityStore('host')]), + queryFn: async () => + initEntityStore('user').then((usr) => initEntityStore('host').then((host) => [usr, host])), enabled: false, }); const enable = useCallback(() => { - initialize().then(() => setPolling(true)); - }, [initialize]); + telemetry?.reportEntityStoreInit({ + timestamp: new Date().toISOString(), + }); + return initialize().then(() => setPolling(true)); + }, [initialize, telemetry]); - return { enable }; + return { enable, query }; }; export const INIT_ENTITY_ENGINE_STATUS_KEY = ['POST', 'INIT_ENTITY_ENGINE']; @@ -65,10 +71,19 @@ export const useInvalidateEntityEngineStatusQuery = () => { }; export const useInitEntityEngineMutation = (options?: UseMutationOptions<{}>) => { + const { telemetry } = useKibana().services; const invalidateEntityEngineStatusQuery = useInvalidateEntityEngineStatusQuery(); const { initEntityStore } = useEntityStoreRoutes(); return useMutation( - () => Promise.all([initEntityStore('user'), initEntityStore('host')]), + () => { + telemetry?.reportEntityStoreEnablement({ + timestamp: new Date().toISOString(), + action: 'start', + }); + return initEntityStore('user').then((usr) => + initEntityStore('host').then((host) => [usr, host]) + ); + }, { ...options, mutationKey: INIT_ENTITY_ENGINE_STATUS_KEY, @@ -86,10 +101,19 @@ export const useInitEntityEngineMutation = (options?: UseMutationOptions<{}>) => export const STOP_ENTITY_ENGINE_STATUS_KEY = ['POST', 'STOP_ENTITY_ENGINE']; export const useStopEntityEngineMutation = (options?: UseMutationOptions<{}>) => { + const { telemetry } = useKibana().services; const invalidateEntityEngineStatusQuery = useInvalidateEntityEngineStatusQuery(); const { stopEntityStore } = useEntityStoreRoutes(); return useMutation( - () => Promise.all([stopEntityStore('user'), stopEntityStore('host')]), + () => { + telemetry?.reportEntityStoreEnablement({ + timestamp: new Date().toISOString(), + action: 'stop', + }); + return stopEntityStore('user').then((usr) => + stopEntityStore('host').then((host) => [usr, host]) + ); + }, { ...options, mutationKey: STOP_ENTITY_ENGINE_STATUS_KEY, @@ -110,7 +134,10 @@ export const useDeleteEntityEngineMutation = (options?: UseMutationOptions<{}>) const invalidateEntityEngineStatusQuery = useInvalidateEntityEngineStatusQuery(); const { deleteEntityEngine } = useEntityStoreRoutes(); return useMutation( - () => Promise.all([deleteEntityEngine('user'), deleteEntityEngine('host')]), + () => + deleteEntityEngine('user', true).then((usr) => + deleteEntityEngine('host', true).then((host) => [usr, host]) + ), { ...options, mutationKey: DELETE_ENTITY_ENGINE_STATUS_KEY, diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/translations.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/translations.ts index 127ff5c88506b..4c113dd533acb 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/translations.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/translations.ts @@ -51,7 +51,7 @@ export const ENABLEMENT_DESCRIPTION_RISK_ENGINE_ONLY = i18n.translate( export const ENABLEMENT_DESCRIPTION_ENTITY_STORE_ONLY = i18n.translate( 'xpack.securitySolution.entityAnalytics.entityStore.enablement.description.store', { - defaultMessage: "Allows comprehensive monitoring of your system's hosts and users.", + defaultMessage: 'Store host and user entities observed in events.', } ); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_preview_section.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_preview_section.tsx index b8f7870e23b56..9693bf13589ad 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_preview_section.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_preview_section.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState, useCallback, useMemo } from 'react'; +import React, { useState, useCallback, useMemo, useEffect } from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; import { EuiAccordion, @@ -148,18 +148,21 @@ const RiskEnginePreview = () => { bool: { must: [], filter: [], should: [], must_not: [] }, }); + const [dataViewsArray, setDataViewsArray] = useState([]); + const { unifiedSearch: { ui: { SearchBar }, }, + dataViews, } = useKibana().services; const { addError } = useAppToasts(); - const { indexPattern } = useSourcererDataView(SourcererScopeName.detections); + const { sourcererDataView } = useSourcererDataView(SourcererScopeName.detections); const { data, isLoading, refetch, isError } = useRiskScorePreview({ - data_view_id: indexPattern.title, // TODO @nkhristinin verify this is correct + data_view_id: sourcererDataView.title, filter: filters, range: { start: dateRange.from, @@ -190,6 +193,10 @@ const RiskEnginePreview = () => { [addError, setDateRange, setFilters] ); + useEffect(() => { + dataViews.create(sourcererDataView).then((dataView) => setDataViewsArray([dataView])); + }, [dataViews, sourcererDataView]); + if (isError) { return ( { {i18n.PREVIEW_DESCRIPTION} - {indexPattern && ( - - )} + diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/top_risk_score_contributors_alerts/index.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/top_risk_score_contributors_alerts/index.tsx index c5c534a6bc370..e75c081ebc010 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/top_risk_score_contributors_alerts/index.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/top_risk_score_contributors_alerts/index.tsx @@ -122,7 +122,7 @@ export const TopRiskScoreContributorsAlerts: React.FC ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_over_time_area.test.ts b/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_over_time_area.test.ts index aa2a2cd77ef4b..0212363ea9a65 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_over_time_area.test.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_over_time_area.test.ts @@ -17,6 +17,7 @@ jest.mock('../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_summary.test.ts b/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_summary.test.ts index af5564e576de8..2a00cb1691970 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_summary.test.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_summary.test.ts @@ -18,6 +18,7 @@ jest.mock('../../sourcerer/containers', () => ({ selectedPatterns: ['auditbeat-mytest-*'], dataViewId: 'security-solution-my-test', indicesExist: true, + sourcererDataView: {}, }), })); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.tsx b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.tsx index 8b2292448b13d..1ca2b0e2b02da 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.tsx @@ -290,7 +290,7 @@ export const EntityStoreManagementPage = () => { {isEntityStoreFeatureFlagDisabled && } diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.test.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.test.tsx index 8d89e580a97e8..53f006bac1d49 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.test.tsx @@ -11,6 +11,7 @@ import useResizeObserver from 'use-resize-observer/polyfilled'; import { createMockStore, + mockDataViewSpec, mockGlobalState, mockIndexPattern, TestProviders, @@ -109,7 +110,7 @@ describe('body', () => { setQuery={jest.fn()} hostDetailsPagePath={hostDetailsPagePath} indexNames={[]} - indexPattern={mockIndexPattern} + dataViewSpec={mockDataViewSpec} type={HostsType.details} hostDetailsFilter={mockHostDetailsPageFilters} filterQuery={filterQuery} @@ -128,34 +129,32 @@ describe('body', () => { startDate: '2020-07-07T08:20:18.966Z', type: 'details', indexPattern: { - fields: [ - { name: '@timestamp', searchable: true, type: 'date', aggregatable: true }, - { name: '@version', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.ephemeral_id', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.hostname', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.id', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.test1', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.test2', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.test3', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.test4', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.test5', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.test6', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.test7', searchable: true, type: 'string', aggregatable: true }, - { name: 'agent.test8', searchable: true, type: 'string', aggregatable: true }, - { name: 'host.name', searchable: true, type: 'string', aggregatable: true }, - { + fields: { + '@timestamp': { searchable: true, type: 'date', aggregatable: true }, + '@version': { searchable: true, type: 'string', aggregatable: true }, + 'agent.ephemeral_id': { searchable: true, type: 'string', aggregatable: true }, + 'agent.hostname': { searchable: true, type: 'string', aggregatable: true }, + 'agent.id': { searchable: true, type: 'string', aggregatable: true }, + 'agent.test1': { searchable: true, type: 'string', aggregatable: true }, + 'agent.test2': { searchable: true, type: 'string', aggregatable: true }, + 'agent.test3': { searchable: true, type: 'string', aggregatable: true }, + 'agent.test4': { searchable: true, type: 'string', aggregatable: true }, + 'agent.test5': { searchable: true, type: 'string', aggregatable: true }, + 'agent.test6': { searchable: true, type: 'string', aggregatable: true }, + 'agent.test7': { searchable: true, type: 'string', aggregatable: true }, + 'agent.test8': { searchable: true, type: 'string', aggregatable: true }, + 'host.name': { searchable: true, type: 'string', aggregatable: true }, + 'nestedField.firstAttributes': { aggregatable: false, - name: 'nestedField.firstAttributes', searchable: true, type: 'string', }, - { + 'nestedField.secondAttributes': { aggregatable: false, - name: 'nestedField.secondAttributes', searchable: true, type: 'string', }, - ], + }, title: 'filebeat-*,auditbeat-*,packetbeat-*', }, hostName: 'host-1', diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.tsx index 4a758dadc5cbd..2938a0a6288fb 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.tsx @@ -29,7 +29,7 @@ export const HostDetailsTabs = React.memo( detailName, filterQuery, indexNames, - indexPattern, + dataViewSpec: indexPattern, hostDetailsPagePath, hostDetailsFilter, }) => { diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx index 6e5b69f408263..ed0e436c7e69a 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx @@ -21,6 +21,7 @@ import { buildEsQuery } from '@kbn/es-query'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; import { dataTableSelectors, tableDefaults, TableId } from '@kbn/securitysolution-data-table'; import type { NarrowDateRange } from '../../../../common/components/ml/types'; +import { dataViewSpecToViewBase } from '../../../../common/lib/kuery'; import { useCalculateEntityRiskScore } from '../../../../entity_analytics/api/hooks/use_calculate_entity_risk_score'; import { useAssetCriticalityData, @@ -128,8 +129,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta [dispatch] ); - const { indexPattern, indicesExist, selectedPatterns, sourcererDataView } = - useSourcererDataView(); + const { indicesExist, selectedPatterns, sourcererDataView } = useSourcererDataView(); const [loading, { inspect, hostDetails: hostOverview, id, refetch }] = useHostDetails({ endDate: to, startDate: from, @@ -142,7 +142,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta try { return [ buildEsQuery( - indexPattern, + dataViewSpecToViewBase(sourcererDataView), [query], [...hostDetailsPageFilters, ...globalFilters], getEsQueryConfig(uiSettings) @@ -151,7 +151,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta } catch (e) { return [undefined, e]; } - }, [globalFilters, indexPattern, query, uiSettings, hostDetailsPageFilters]); + }, [sourcererDataView, query, hostDetailsPageFilters, globalFilters, uiSettings]); const stringifiedAdditionalFilters = JSON.stringify(rawFilteredQuery); useInvalidFilterQuery({ @@ -315,7 +315,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta setQuery={setQuery} filterQuery={stringifiedAdditionalFilters} hostDetailsPagePath={hostDetailsPagePath} - indexPattern={indexPattern} + dataViewSpec={sourcererDataView} /> diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/types.ts b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/types.ts index dc5b3baccdc5c..fe23a0485dac8 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/types.ts +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/types.ts @@ -5,7 +5,8 @@ * 2.0. */ -import type { DataViewBase, Filter } from '@kbn/es-query'; +import type { Filter } from '@kbn/es-query'; +import type { DataViewSpec } from '@kbn/data-plugin/common'; import type { HostsTableType } from '../../store/model'; import type { HostsQueryProps } from '../types'; import type { NavTab } from '../../../../common/components/navigation/types'; @@ -40,6 +41,6 @@ export type HostDetailsTabsProps = HostBodyComponentDispatchProps & indexNames: string[]; hostDetailsFilter: Filter[]; filterQuery?: string; - indexPattern: DataViewBase; + dataViewSpec?: DataViewSpec; type: hostsModel.HostsType; }; diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/hosts.tsx index 17d5bdd3a82f2..59d57aeca5d14 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/hosts.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/hosts.tsx @@ -104,27 +104,26 @@ const HostsComponent = () => { return globalFilters; }, [globalFilters, severitySelection, tabName]); - const { indicesExist, indexPattern, selectedPatterns, sourcererDataView } = - useSourcererDataView(); + const { indicesExist, selectedPatterns, sourcererDataView } = useSourcererDataView(); const [globalFilterQuery, kqlError] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - indexPattern, + dataViewSpec: sourcererDataView, queries: [query], filters: globalFilters, }), - [globalFilters, indexPattern, uiSettings, query] + [globalFilters, sourcererDataView, uiSettings, query] ); const [tabsFilterQuery] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - indexPattern, + dataViewSpec: sourcererDataView, queries: [query], filters: tabsFilters, }), - [indexPattern, query, tabsFilters, uiSettings] + [sourcererDataView, query, tabsFilters, uiSettings] ); useInvalidFilterQuery({ diff --git a/x-pack/plugins/security_solution/public/explore/network/pages/details/index.test.tsx b/x-pack/plugins/security_solution/public/explore/network/pages/details/index.test.tsx index 19b3f653b8f14..9807f4b336b96 100644 --- a/x-pack/plugins/security_solution/public/explore/network/pages/details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/explore/network/pages/details/index.test.tsx @@ -127,6 +127,7 @@ describe('Network Details', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ indicesExist: false, indexPattern: {}, + sourcererDataView: {}, }); global.fetch = jest.fn().mockImplementationOnce(() => Promise.resolve({ @@ -147,6 +148,7 @@ describe('Network Details', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ indicesExist: true, indexPattern: {}, + sourcererDataView: {}, }); (useParams as jest.Mock).mockReturnValue({ detailName: ip, @@ -167,6 +169,7 @@ describe('Network Details', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ indicesExist: true, indexPattern: {}, + sourcererDataView: {}, }); (useParams as jest.Mock).mockReturnValue({ detailName: ip, @@ -191,6 +194,7 @@ describe('Network Details', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ indicesExist: false, indexPattern: {}, + sourcererDataView: {}, }); (useParams as jest.Mock).mockReturnValue({ detailName: ip, diff --git a/x-pack/plugins/security_solution/public/explore/network/pages/details/index.tsx b/x-pack/plugins/security_solution/public/explore/network/pages/details/index.tsx index adcf8a21ba47c..0eb3fb36638b8 100644 --- a/x-pack/plugins/security_solution/public/explore/network/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/network/pages/details/index.tsx @@ -13,6 +13,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiSpacer } from '@elasti import { getEsQueryConfig } from '@kbn/data-plugin/common'; import { buildEsQuery } from '@kbn/es-query'; +import { dataViewSpecToViewBase } from '../../../../common/lib/kuery'; import { AlertsByStatus } from '../../../../overview/components/detection_response/alerts_by_status'; import { useSignalIndex } from '../../../../detections/containers/detection_engine/alerts/use_signal_index'; import { InputsModelId } from '../../../../common/store/inputs/constants'; @@ -104,8 +105,7 @@ const NetworkDetailsComponent: React.FC = () => { dispatch(setNetworkDetailsTablesActivePageToZero()); }, [detailName, dispatch]); - const { indicesExist, indexPattern, selectedPatterns, sourcererDataView } = - useSourcererDataView(); + const { indicesExist, selectedPatterns, sourcererDataView } = useSourcererDataView(); const ip = decodeIpv6(detailName); const networkDetailsFilter = useMemo(() => getNetworkDetailsPageFilter(ip), [ip]); @@ -114,7 +114,7 @@ const NetworkDetailsComponent: React.FC = () => { try { return [ buildEsQuery( - indexPattern, + dataViewSpecToViewBase(sourcererDataView), [query], [...networkDetailsFilter, ...globalFilters], getEsQueryConfig(uiSettings) @@ -123,7 +123,7 @@ const NetworkDetailsComponent: React.FC = () => { } catch (e) { return [undefined, e]; } - }, [globalFilters, indexPattern, networkDetailsFilter, query, uiSettings]); + }, [globalFilters, networkDetailsFilter, query, sourcererDataView, uiSettings]); const additionalFilters = useMemo( () => (rawFilteredQuery ? [rawFilteredQuery] : []), @@ -166,6 +166,10 @@ const NetworkDetailsComponent: React.FC = () => { [detailName, flowTarget] ); + const indexPattern = useMemo(() => { + return dataViewSpecToViewBase(sourcererDataView); + }, [sourcererDataView]); + return (
{indicesExist ? ( diff --git a/x-pack/plugins/security_solution/public/explore/network/pages/navigation/network_routes.tsx b/x-pack/plugins/security_solution/public/explore/network/pages/navigation/network_routes.tsx index ca9d7d4a7b085..6e49c65454239 100644 --- a/x-pack/plugins/security_solution/public/explore/network/pages/navigation/network_routes.tsx +++ b/x-pack/plugins/security_solution/public/explore/network/pages/navigation/network_routes.tsx @@ -5,12 +5,13 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; import { EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { TableId } from '@kbn/securitysolution-data-table'; +import { dataViewSpecToViewBase } from '../../../../common/lib/kuery'; import { FlowTargetSourceDest } from '../../../../../common/search_strategy/security_solution/network'; import { @@ -30,7 +31,9 @@ import { NetworkRouteType } from './types'; import { NETWORK_PATH } from '../../../../../common/constants'; export const NetworkRoutes = React.memo( - ({ type, to, filterQuery, isInitializing, from, indexPattern, indexNames, setQuery }) => { + ({ type, to, filterQuery, isInitializing, from, dataViewSpec, indexNames, setQuery }) => { + const index = useMemo(() => dataViewSpecToViewBase(dataViewSpec), [dataViewSpec]); + const networkAnomaliesFilterQuery = { bool: { should: [ @@ -61,7 +64,7 @@ export const NetworkRoutes = React.memo( const tabProps = { ...commonProps, - indexPattern, + indexPattern: index, }; const anomaliesProps = { diff --git a/x-pack/plugins/security_solution/public/explore/network/pages/navigation/types.ts b/x-pack/plugins/security_solution/public/explore/network/pages/navigation/types.ts index 2ed0756634707..339ad2fc71acc 100644 --- a/x-pack/plugins/security_solution/public/explore/network/pages/navigation/types.ts +++ b/x-pack/plugins/security_solution/public/explore/network/pages/navigation/types.ts @@ -5,9 +5,10 @@ * 2.0. */ -import type { DataViewBase } from '@kbn/es-query'; import type { Optional } from 'utility-types'; +import type { DataViewBase } from '@kbn/es-query'; +import type { DataViewSpec } from '@kbn/data-plugin/common'; import type { ESTermQuery } from '../../../../../common/typed_json'; import type { NavTab } from '../../../../common/components/navigation/types'; @@ -45,7 +46,7 @@ export type HttpQueryTabBodyProps = QueryTabBodyProps; export type NetworkRoutesProps = GlobalTimeArgs & { type: networkModel.NetworkType; filterQuery?: string | ESTermQuery; - indexPattern: DataViewBase; + dataViewSpec: DataViewSpec; indexNames: string[]; }; diff --git a/x-pack/plugins/security_solution/public/explore/network/pages/network.test.tsx b/x-pack/plugins/security_solution/public/explore/network/pages/network.test.tsx index e868a38266f80..4f44045cbf6f3 100644 --- a/x-pack/plugins/security_solution/public/explore/network/pages/network.test.tsx +++ b/x-pack/plugins/security_solution/public/explore/network/pages/network.test.tsx @@ -221,6 +221,7 @@ describe('Network page - rendering', () => { selectedPatterns: [], indicesExist: true, indexPattern: { fields: [], title: 'title' }, + sourcererDataView: {}, }); const myStore = createMockStore(); const wrapper = mount( diff --git a/x-pack/plugins/security_solution/public/explore/network/pages/network.tsx b/x-pack/plugins/security_solution/public/explore/network/pages/network.tsx index 00a88da0cfcf5..0732b31805609 100644 --- a/x-pack/plugins/security_solution/public/explore/network/pages/network.tsx +++ b/x-pack/plugins/security_solution/public/explore/network/pages/network.tsx @@ -88,8 +88,7 @@ const NetworkComponent = React.memo( return globalFilters; }, [tabName, globalFilters]); - const { indicesExist, indexPattern, selectedPatterns, sourcererDataView } = - useSourcererDataView(); + const { indicesExist, selectedPatterns, sourcererDataView } = useSourcererDataView(); const onSkipFocusBeforeEventsTable = useCallback(() => { containerElement.current @@ -117,14 +116,14 @@ const NetworkComponent = React.memo( const [filterQuery, kqlError] = convertToBuildEsQuery({ config: getEsQueryConfig(kibana.services.uiSettings), - indexPattern, + dataViewSpec: sourcererDataView, queries: [query], filters: globalFilters, }); const [tabsFilterQuery] = convertToBuildEsQuery({ config: getEsQueryConfig(kibana.services.uiSettings), - indexPattern, + dataViewSpec: sourcererDataView, queries: [query], filters: tabsFilters, }); @@ -175,7 +174,7 @@ const NetworkComponent = React.memo( - {capabilitiesFetched && !isInitializing ? ( + {capabilitiesFetched && !isInitializing && sourcererDataView ? ( <> @@ -187,7 +186,7 @@ const NetworkComponent = React.memo( filterQuery={tabsFilterQuery} from={from} isInitializing={isInitializing} - indexPattern={indexPattern} + dataViewSpec={sourcererDataView} indexNames={selectedPatterns} setQuery={setQuery} type={networkModel.NetworkType.page} diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx index a53eaf43269bf..6ac48dd527904 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx @@ -20,6 +20,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { Filter } from '@kbn/es-query'; import { buildEsQuery } from '@kbn/es-query'; import { dataTableSelectors, TableId } from '@kbn/securitysolution-data-table'; +import { dataViewSpecToViewBase } from '../../../../common/lib/kuery'; import { useCalculateEntityRiskScore } from '../../../../entity_analytics/api/hooks/use_calculate_entity_risk_score'; import { useAssetCriticalityData, @@ -115,14 +116,13 @@ const UsersDetailsComponent: React.FC = ({ [detailName] ); - const { indicesExist, indexPattern, selectedPatterns, sourcererDataView } = - useSourcererDataView(); + const { indicesExist, selectedPatterns, sourcererDataView } = useSourcererDataView(); const [rawFilteredQuery, kqlError] = useMemo(() => { try { return [ buildEsQuery( - indexPattern, + dataViewSpecToViewBase(sourcererDataView), [query], [...usersDetailsPageFilters, ...globalFilters], getEsQueryConfig(uiSettings) @@ -131,7 +131,7 @@ const UsersDetailsComponent: React.FC = ({ } catch (e) { return [undefined, e]; } - }, [globalFilters, indexPattern, query, uiSettings, usersDetailsPageFilters]); + }, [globalFilters, sourcererDataView, query, uiSettings, usersDetailsPageFilters]); const stringifiedAdditionalFilters = JSON.stringify(rawFilteredQuery); useInvalidFilterQuery({ @@ -293,7 +293,7 @@ const UsersDetailsComponent: React.FC = ({ filterQuery={stringifiedAdditionalFilters} from={from} indexNames={selectedPatterns} - indexPattern={indexPattern} + dataViewSpec={sourcererDataView} isInitializing={isInitializing} userDetailFilter={usersDetailsPageFilters} setQuery={setQuery} diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/details/types.ts b/x-pack/plugins/security_solution/public/explore/users/pages/details/types.ts index 002d1339a1898..8b531af663990 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/details/types.ts +++ b/x-pack/plugins/security_solution/public/explore/users/pages/details/types.ts @@ -7,7 +7,8 @@ import type { ActionCreator } from 'typescript-fsa'; -import type { DataViewBase, Filter, Query } from '@kbn/es-query'; +import { type DataViewSpec } from '@kbn/data-plugin/common'; +import type { Filter, Query } from '@kbn/es-query'; import type { UsersQueryProps } from '../types'; import type { NavTab } from '../../../../common/components/navigation/types'; @@ -47,6 +48,6 @@ export type UsersDetailsTabsProps = UserBodyComponentDispatchProps & indexNames: string[]; userDetailFilter: Filter[]; filterQuery?: string; - indexPattern: DataViewBase; + dataViewSpec?: DataViewSpec; type: usersModel.UsersType; }; diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/users.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/users.tsx index 61cd8888bfb4c..767d009aff16c 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/users.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/pages/users.tsx @@ -98,27 +98,26 @@ const UsersComponent = () => { return globalFilters; }, [severitySelection, tabName, globalFilters]); - const { indicesExist, indexPattern, selectedPatterns, sourcererDataView } = - useSourcererDataView(); + const { indicesExist, selectedPatterns, sourcererDataView } = useSourcererDataView(); const [globalFiltersQuery, kqlError] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - indexPattern, + dataViewSpec: sourcererDataView, queries: [query], filters: globalFilters, }), - [globalFilters, indexPattern, uiSettings, query] + [globalFilters, sourcererDataView, uiSettings, query] ); const [tabsFilterQuery] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - indexPattern, + dataViewSpec: sourcererDataView, queries: [query], filters: tabsFilters, }), - [indexPattern, query, tabsFilters, uiSettings] + [sourcererDataView, query, tabsFilters, uiSettings] ); useInvalidFilterQuery({ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/entities_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/entities_details.test.tsx index b6c5dc0078b02..53936a5ed2e99 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/entities_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/entities_details.test.tsx @@ -65,7 +65,9 @@ jest.mock('../../../../helper_hooks', () => ({ })); jest.mock('../../../../sourcerer/containers', () => ({ - useSourcererDataView: jest.fn().mockReturnValue({ selectedPatterns: ['index'] }), + useSourcererDataView: jest + .fn() + .mockReturnValue({ selectedPatterns: ['index'], sourcererDataView: {} }), })); jest.mock('../../../../common/components/ml/anomaly/anomaly_table_provider', () => ({ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx index 23f6969c36778..895ff3d1b7697 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx @@ -88,7 +88,9 @@ jest.mock('../../../../helper_hooks', () => ({ })); jest.mock('../../../../sourcerer/containers', () => ({ - useSourcererDataView: jest.fn().mockReturnValue({ selectedPatterns: ['index'] }), + useSourcererDataView: jest + .fn() + .mockReturnValue({ selectedPatterns: ['index'], sourcererDataView: {} }), })); jest.mock('../../../../common/components/ml/anomaly/anomaly_table_provider', () => ({ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/session_view.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/session_view.test.tsx index 6db3c4fb4a90d..ff3a834225d68 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/session_view.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/session_view.test.tsx @@ -88,8 +88,7 @@ describe('', () => { loading: false, indicesExist: true, selectedPatterns: ['index'], - indexPattern: { fields: [], title: '' }, - sourcererDataView: undefined, + sourcererDataView: {}, }); }); it('renders session view correctly', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx index a2c53afb8c3f3..d4150c01d06a6 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx @@ -80,7 +80,9 @@ jest.mock('../../../../common/components/ml/hooks/use_ml_capabilities'); const mockUseMlUserPermissions = useMlCapabilities as jest.Mock; jest.mock('../../../../sourcerer/containers', () => ({ - useSourcererDataView: jest.fn().mockReturnValue({ selectedPatterns: ['index'] }), + useSourcererDataView: jest + .fn() + .mockReturnValue({ selectedPatterns: ['index'], sourcererDataView: {} }), })); jest.mock('../../../../common/components/ml/anomaly/anomaly_table_provider', () => ({ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/hooks/use_threat_intelligence_details.test.ts b/x-pack/plugins/security_solution/public/flyout/document_details/left/hooks/use_threat_intelligence_details.test.ts index e40cd74709cfd..17e564a1eb8ab 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/hooks/use_threat_intelligence_details.test.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/hooks/use_threat_intelligence_details.test.ts @@ -50,8 +50,7 @@ describe('useThreatIntelligenceDetails', () => { loading: false, indicesExist: true, selectedPatterns: [], - indexPattern: { fields: [], title: '' }, - sourcererDataView: undefined, + sourcererDataView: {}, }); jest diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/hooks/use_threat_intelligence_details.ts b/x-pack/plugins/security_solution/public/flyout/document_details/left/hooks/use_threat_intelligence_details.ts index a7b8256b502f5..7826d98b65a3a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/hooks/use_threat_intelligence_details.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/hooks/use_threat_intelligence_details.ts @@ -71,7 +71,7 @@ export const useThreatIntelligenceDetails = (): ThreatIntelligenceDetailsResult const [isEventDataLoading, eventData] = useTimelineEventsDetails({ indexName, eventId, - runtimeMappings: sourcererDataView.sourcererDataView?.runtimeFieldMap as RunTimeMappings, + runtimeMappings: sourcererDataView.sourcererDataView.runtimeFieldMap as RunTimeMappings, skip: !eventId, }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx index 8e6b817e275e5..32b0b10d61ffd 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx @@ -36,8 +36,8 @@ export const LeftPanel: FC> = memo(({ path }) => { const { openLeftPanel } = useExpandableFlyoutApi(); const { eventId, indexName, scopeId, getFieldsData, isPreview } = useDocumentDetailsContext(); const eventKind = getField(getFieldsData('event.kind')); - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const [visualizationInFlyoutEnabled] = useUiSetting$( @@ -49,14 +49,14 @@ export const LeftPanel: FC> = memo(({ path }) => { eventKind === EventKind.signal ? [tabs.insightsTab, tabs.investigationTab, tabs.responseTab] : [tabs.insightsTab]; - if (securitySolutionNotesEnabled && !isPreview) { + if (!securitySolutionNotesDisabled && !isPreview) { tabList.push(tabs.notesTab); } if (visualizationInFlyoutEnabled && !isPreview) { return [tabs.visualizeTab, ...tabList]; } return tabList; - }, [eventKind, isPreview, securitySolutionNotesEnabled, visualizationInFlyoutEnabled]); + }, [eventKind, isPreview, securitySolutionNotesDisabled, visualizationInFlyoutEnabled]); const selectedTabId = useMemo(() => { const defaultTab = tabsDisplayed[0].id; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.test.tsx index 6d72ca9e58dfa..8a8293badb6af 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.test.tsx @@ -78,7 +78,7 @@ describe('', () => { }); it('should render notes section if experimental flag is enabled', () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false); const { getByTestId } = renderHeader(mockContextValue); expect(getByTestId(NOTES_TITLE_TEST_ID)).toBeInTheDocument(); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.tsx index f128fada5fb29..931da6e8e57c8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.tsx @@ -40,8 +40,8 @@ export const AlertHeaderTitle = memo(() => { refetchFlyoutData, getFieldsData, } = useDocumentDetailsContext(); - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const { isAlert, ruleName, timestamp, ruleId } = useBasicDataFromDetailsData( @@ -98,7 +98,30 @@ export const AlertHeaderTitle = memo(() => { /> )} - {securitySolutionNotesEnabled ? ( + {securitySolutionNotesDisabled ? ( + + + + + + + + + + + + ) : ( { - ) : ( - - - - - - - - - - - )} ); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx index f4a97b7deed11..71292b73a68e0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx @@ -22,7 +22,8 @@ import { CORRELATIONS_RELATED_CASES_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, CORRELATIONS_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, } from './test_ids'; import { useShowRelatedAlertsByAncestry } from '../../shared/hooks/use_show_related_alerts_by_ancestry'; import { useShowRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_show_related_alerts_by_same_source_event'; @@ -58,17 +59,32 @@ const TITLE_LINK_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(CORRELATIO const TITLE_ICON_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(CORRELATIONS_TEST_ID); const TITLE_TEXT_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(CORRELATIONS_TEST_ID); -const SUPPRESSED_ALERTS_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); -const RELATED_ALERTS_BY_ANCESTRY_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const SUPPRESSED_ALERTS_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID +); +const SUPPRESSED_ALERTS_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( + CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID +); +const RELATED_ALERTS_BY_ANCESTRY_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID +); +const RELATED_ALERTS_BY_ANCESTRY_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID ); -const RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); -const RELATED_ALERTS_BY_SESSION_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const RELATED_ALERTS_BY_SAME_SOURCE_EVENT_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( + CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID +); +const RELATED_ALERTS_BY_SESSION_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID +); +const RELATED_ALERTS_BY_SESSION_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID ); -const RELATED_CASES_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); +const RELATED_CASES_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); +const RELATED_CASES_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); const panelContextValue = { eventId: 'event id', @@ -193,11 +209,16 @@ describe('', () => { }); const { getByTestId, queryByText } = render(renderCorrelationsOverview(panelContextValue)); - expect(getByTestId(RELATED_ALERTS_BY_ANCESTRY_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(RELATED_CASES_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(SUPPRESSED_ALERTS_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_ANCESTRY_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_ANCESTRY_VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_SESSION_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_SESSION_VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_CASES_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_CASES_VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(SUPPRESSED_ALERTS_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(SUPPRESSED_ALERTS_VALUE_TEST_ID)).toBeInTheDocument(); expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); @@ -215,11 +236,18 @@ describe('', () => { jest.mocked(useShowSuppressedAlerts).mockReturnValue({ show: false, alertSuppressionCount: 0 }); const { getByText, queryByTestId } = render(renderCorrelationsOverview(panelContextValue)); - expect(queryByTestId(RELATED_ALERTS_BY_ANCESTRY_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(RELATED_CASES_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(SUPPRESSED_ALERTS_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_ANCESTRY_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_ANCESTRY_VALUE_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect( + queryByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_VALUE_TEST_ID) + ).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_SESSION_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_SESSION_VALUE_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_CASES_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_CASES_VALUE_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(SUPPRESSED_ALERTS_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(SUPPRESSED_ALERTS_VALUE_TEST_ID)).not.toBeInTheDocument(); expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx index c2494b4cde675..9ab130cfc2de1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx @@ -134,7 +134,7 @@ export const CorrelationsOverview: React.FC = () => { data-test-subj={CORRELATIONS_TEST_ID} > {canShowAtLeastOneInsight ? ( - + {showSuppressedAlerts && ( )} diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.stories.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.stories.tsx deleted file mode 100644 index eb76108d6b215..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.stories.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import type { Story } from '@storybook/react'; -import { css } from '@emotion/react'; -import { InsightsSummaryRow } from './insights_summary_row'; - -export default { - component: InsightsSummaryRow, - title: 'Flyout/InsightsSummaryRow', -}; - -const wrapper = (children: React.ReactNode) => ( -
- {children} -
-); - -export const Default: Story = () => - wrapper( - - ); - -export const InvalidColor: Story = () => - wrapper( - - ); - -export const NoColor: Story = () => - wrapper(); - -export const LongText: Story = () => - wrapper( - - ); - -export const LongNumber: Story = () => - wrapper( - - ); - -export const Loading: Story = () => - wrapper(); - -export const Error: Story = () => - wrapper(); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx index 3e10e83332a97..2a721e317781e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx @@ -9,74 +9,147 @@ import React from 'react'; import { render } from '@testing-library/react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { InsightsSummaryRow } from './insights_summary_row'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; + +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); + +const mockOpenLeftPanel = jest.fn(); +const scopeId = 'scopeId'; +const eventId = 'eventId'; +const indexName = 'indexName'; const testId = 'test'; -const iconTestId = `${testId}Icon`; +const textTestId = `${testId}Text`; +const buttonTestId = `${testId}Button`; const valueTestId = `${testId}Value`; -const colorTestId = `${testId}Color`; const loadingTestId = `${testId}Loading`; describe('', () => { - it('should render by default', () => { + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + }); + + it('should render loading skeleton if loading is true', () => { const { getByTestId } = render( + {'value for this'}
} + data-test-subj={testId} + /> + ); + + expect(getByTestId(loadingTestId)).toBeInTheDocument(); + }); + + it('should only render null when error is true', () => { + const { container } = render( + {'value for this'}
} /> + ); + + expect(container).toBeEmptyDOMElement(); + }); + + it('should render the value component', () => { + const { getByTestId, queryByTestId } = render( {'value for this'}
} data-test-subj={testId} /> ); - expect(getByTestId(iconTestId)).toBeInTheDocument(); - expect(getByTestId(valueTestId)).toHaveTextContent('1 this is a test for red'); - expect(getByTestId(colorTestId)).toBeInTheDocument(); + expect(getByTestId(textTestId)).toHaveTextContent('this is a test for red'); + expect(getByTestId(valueTestId)).toHaveTextContent('value for this'); + expect(queryByTestId(buttonTestId)).not.toBeInTheDocument(); }); - it('should render loading skeletton if loading is true', () => { - const { getByTestId } = render( - + it('should render the value as EuiBadge and EuiButtonEmpty', () => { + const { getByTestId, queryByTestId } = render( + + + ); - expect(getByTestId(loadingTestId)).toBeInTheDocument(); + expect(getByTestId(textTestId)).toHaveTextContent('this is a test for red'); + expect(getByTestId(buttonTestId)).toHaveTextContent('2'); + expect(queryByTestId(valueTestId)).not.toBeInTheDocument(); }); - it('should only render null when error is true', () => { - const { container } = render(); + it('should render big numbers formatted correctly', () => { + const { getByTestId } = render( + + + + ); - expect(container).toBeEmptyDOMElement(); + expect(getByTestId(buttonTestId)).toHaveTextContent('2k'); }); - it('should handle big number in a compact notation', () => { + it('should open the expanded section to the correct tab when the number is clicked', () => { const { getByTestId } = render( ); + getByTestId(buttonTestId).click(); - expect(getByTestId(valueTestId)).toHaveTextContent('160k this is a test for red'); + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: 'subTab', + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); }); - it(`should not show the colored dot if color isn't provided`, () => { - const { queryByTestId } = render( + it('should disabled the click when in preview mode', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: true, + }); + + const { getByTestId } = render( ); + const button = getByTestId(buttonTestId); + + expect(button).toHaveAttribute('disabled'); - expect(queryByTestId(colorTestId)).not.toBeInTheDocument(); + button.click(); + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx index 23f838f5068bb..56a19d2eca965 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx @@ -6,19 +6,25 @@ */ import type { ReactElement, VFC } from 'react'; -import React from 'react'; +import React, { useMemo, useCallback } from 'react'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; -import { - EuiIcon, - EuiFlexGroup, - EuiFlexItem, - EuiHealth, - EuiSkeletonText, - useEuiTheme, -} from '@elastic/eui'; +import { EuiBadge, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSkeletonText } from '@elastic/eui'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; import { FormattedCount } from '../../../../common/components/formatted_number'; +const LOADING = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.insightSummaryLoadingAriaLabel', + { defaultMessage: 'Loading' } +); +const BUTTON = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.insightSummaryButtonAriaLabel', + { defaultMessage: 'Click to see more details' } +); + export interface InsightsSummaryRowProps { /** * Optional parameter used to display a loading spinner @@ -29,22 +35,17 @@ export interface InsightsSummaryRowProps { */ error?: boolean; /** - * Icon to display on the left side of each row + * Text corresponding of the number of results/entries */ - icon: string; + text: string | ReactElement; /** * Number of results/entries found */ - value?: number; + value: number | ReactElement; /** - * Text corresponding of the number of results/entries + * Optional parameter used to know which subtab to navigate to when the user clicks on the button */ - text: string | ReactElement; - /** - * Optional parameter for now, will be used to display a dot on the right side - * (corresponding to some sort of severity?) - */ - color?: string; // TODO remove optional when we have guidance on what the colors will actually be + expandedSubTab?: string; /** * Prefix data-test-subj because this component will be used in multiple places */ @@ -52,35 +53,73 @@ export interface InsightsSummaryRowProps { } /** - * Panel showing summary information as an icon, a count and text as well as a severity colored dot. + * Panel showing summary information. + * The default display is a text on the left and a count on the right, displayed with a clickable EuiBadge. + * The left and right section can accept a ReactElement to allow for more complex display. * Should be used for Entities, Threat intelligence, Prevalence, Correlations and Results components under the Insights section. - * The colored dot is currently optional but will ultimately be mandatory (waiting on PM and UIUX). */ export const InsightsSummaryRow: VFC = ({ loading = false, error = false, - icon, value, text, - color, + expandedSubTab, 'data-test-subj': dataTestSubj, }) => { - const { euiTheme } = useEuiTheme(); + const { eventId, indexName, scopeId, isPreviewMode } = useDocumentDetailsContext(); + const { openLeftPanel } = useExpandableFlyoutApi(); + + const onClick = useCallback(() => { + openLeftPanel({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: expandedSubTab, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }, [eventId, expandedSubTab, indexName, openLeftPanel, scopeId]); + + const textDataTestSubj = useMemo(() => `${dataTestSubj}Text`, [dataTestSubj]); + const loadingDataTestSubj = useMemo(() => `${dataTestSubj}Loading`, [dataTestSubj]); + + const button = useMemo(() => { + const buttonDataTestSubj = `${dataTestSubj}Button`; + const valueDataTestSubj = `${dataTestSubj}Value`; + + return ( + <> + {typeof value === 'number' ? ( + + + + + + ) : ( +
{value}
+ )} + + ); + }, [dataTestSubj, isPreviewMode, onClick, value]); - const loadingDataTestSubj = `${dataTestSubj}Loading`; if (loading) { return ( ); @@ -90,10 +129,6 @@ export const InsightsSummaryRow: VFC = ({ return null; } - const iconDataTestSubj = `${dataTestSubj}Icon`; - const valueDataTestSubj = `${dataTestSubj}Value`; - const colorDataTestSubj = `${dataTestSubj}Color`; - return ( = ({ alignItems={'center'} responsive={false} > - - - = ({ overflow: hidden; `} > - {value && } {text} + {text} - {color && ( - - - - )} + {button} ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx index a47ed04c85b5a..527b9830b3948 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx @@ -8,7 +8,11 @@ import { render } from '@testing-library/react'; import { TestProviders } from '../../../../common/mock'; import { DocumentDetailsContext } from '../../shared/context'; -import { PREVALENCE_TEST_ID } from './test_ids'; +import { + PREVALENCE_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, + SUMMARY_ROW_VALUE_TEST_ID, +} from './test_ids'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelInsightsTab } from '../../left'; import React from 'react'; @@ -149,21 +153,19 @@ describe('', () => { expect(getByTestId(TITLE_LINK_TEST_ID)).toHaveTextContent('Prevalence'); - const iconDataTestSubj1 = `${PREVALENCE_TEST_ID}${field1}Icon`; - const valueDataTestSubj1 = `${PREVALENCE_TEST_ID}${field1}Value`; - expect(getByTestId(iconDataTestSubj1)).toBeInTheDocument(); - expect(getByTestId(valueDataTestSubj1)).toBeInTheDocument(); - expect(getByTestId(valueDataTestSubj1)).toHaveTextContent('field1, value1 is uncommon'); - - const iconDataTestSubj2 = `${PREVALENCE_TEST_ID}${field2}Icon`; - const valueDataTestSubj2 = `${PREVALENCE_TEST_ID}${field2}Value`; - expect(getByTestId(iconDataTestSubj2)).toBeInTheDocument(); - expect(getByTestId(valueDataTestSubj2)).toBeInTheDocument(); - expect(getByTestId(valueDataTestSubj2)).toHaveTextContent('field2, value2,value22 is uncommon'); - - const iconDataTestSubj3 = `${PREVALENCE_TEST_ID}${field3}Icon`; - const valueDataTestSubj3 = `${PREVALENCE_TEST_ID}${field3}Value`; - expect(queryByTestId(iconDataTestSubj3)).not.toBeInTheDocument(); + const textDataTestSubj1 = SUMMARY_ROW_TEXT_TEST_ID(`${PREVALENCE_TEST_ID}${field1}`); + const valueDataTestSubj1 = SUMMARY_ROW_VALUE_TEST_ID(`${PREVALENCE_TEST_ID}${field1}`); + expect(getByTestId(textDataTestSubj1)).toHaveTextContent('field1, value1'); + expect(getByTestId(valueDataTestSubj1)).toHaveTextContent('Uncommon'); + + const textDataTestSubj2 = SUMMARY_ROW_TEXT_TEST_ID(`${PREVALENCE_TEST_ID}${field2}`); + const valueDataTestSubj2 = SUMMARY_ROW_VALUE_TEST_ID(`${PREVALENCE_TEST_ID}${field2}`); + expect(getByTestId(textDataTestSubj2)).toHaveTextContent('field2, value2'); + expect(getByTestId(valueDataTestSubj2)).toHaveTextContent('Uncommon'); + + const textDataTestSubj3 = SUMMARY_ROW_TEXT_TEST_ID(`${PREVALENCE_TEST_ID}${field3}`); + const valueDataTestSubj3 = SUMMARY_ROW_VALUE_TEST_ID(`${PREVALENCE_TEST_ID}${field3}`); + expect(queryByTestId(textDataTestSubj3)).not.toBeInTheDocument(); expect(queryByTestId(valueDataTestSubj3)).not.toBeInTheDocument(); expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx index 96ee603607742..adb660f67ce72 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx @@ -7,7 +7,7 @@ import type { FC } from 'react'; import React, { useCallback, useMemo } from 'react'; -import { EuiFlexGroup } from '@elastic/eui'; +import { EuiBadge, EuiFlexGroup } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandablePanel } from '@kbn/security-solution-common'; @@ -19,6 +19,13 @@ import { LeftPanelInsightsTab } from '../../left'; import { PREVALENCE_TAB_ID } from '../../left/components/prevalence_details'; import { InsightsSummaryRow } from './insights_summary_row'; +const UNCOMMON = ( + +); + const PERCENTAGE_THRESHOLD = 0.1; // we show the prevalence if its value is below 10% const DEFAULT_FROM = 'now-30d'; const DEFAULT_TO = 'now'; @@ -104,18 +111,17 @@ export const PrevalenceOverview: FC = () => { content={{ loading, error }} data-test-subj={PREVALENCE_TEST_ID} > - + {uncommonData.length > 0 ? ( uncommonData.map((d) => ( + <> + {d.field} + {','} {d.values.toString()} + } + value={{UNCOMMON}} data-test-subj={`${PREVALENCE_TEST_ID}${d.field}`} key={`${PREVALENCE_TEST_ID}${d.field}`} /> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx index 5aad641c6e400..38efe27b16ea9 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx @@ -9,22 +9,32 @@ import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { - SUMMARY_ROW_ICON_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { RelatedAlertsByAncestry } from './related_alerts_by_ancestry'; import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_related_alerts_by_ancestry'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../../shared/hooks/use_fetch_related_alerts_by_ancestry'); +const mockOpenLeftPanel = jest.fn(); const documentId = 'documentId'; const indices = ['indices']; const scopeId = 'scopeId'; +const eventId = 'eventId'; +const indexName = 'indexName'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID ); @@ -37,34 +47,40 @@ const renderRelatedAlertsByAncestry = () => ); describe('', () => { - it('should render many related alerts correctly', () => { + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + }); + + it('should render single related alert correctly', () => { (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 2, + dataCount: 1, }); const { getByTestId } = renderRelatedAlertsByAncestry(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 alerts related by ancestry'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alert related by ancestry'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); }); - it('should render single related alerts correctly', () => { + it('should render multiple related alerts correctly', () => { (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 1, + dataCount: 2, }); const { getByTestId } = renderRelatedAlertsByAncestry(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 alert related by ancestry'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by ancestry'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should render loading skeleton', () => { @@ -85,4 +101,28 @@ describe('', () => { const { container } = renderRelatedAlertsByAncestry(); expect(container).toBeEmptyDOMElement(); }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsByAncestry(); + getByTestId(BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx index 2e628ba61a7be..4b225d5595883 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx @@ -5,14 +5,13 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_related_alerts_by_ancestry'; import { InsightsSummaryRow } from './insights_summary_row'; import { CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID } from './test_ids'; -const ICON = 'warning'; - export interface RelatedAlertsByAncestryProps { /** * Id of the document @@ -41,21 +40,25 @@ export const RelatedAlertsByAncestry: React.VFC = indices, scopeId, }); - const text = ( - + + const text = useMemo( + () => ( + + ), + [dataCount] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx index d52d547397789..80e7c99a60917 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx @@ -9,23 +9,33 @@ import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { - SUMMARY_ROW_ICON_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; import { RelatedAlertsBySameSourceEvent } from './related_alerts_by_same_source_event'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../../shared/hooks/use_fetch_related_alerts_by_same_source_event'); +const mockOpenLeftPanel = jest.fn(); const originalEventId = 'originalEventId'; const scopeId = 'scopeId'; +const eventId = 'eventId'; +const indexName = 'indexName'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID( +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID( @@ -40,34 +50,40 @@ const renderRelatedAlertsBySameSourceEvent = () => ); describe('', () => { - it('should render many related alerts correctly', () => { + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + }); + + it('should render single related alert correctly', () => { (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 2, + dataCount: 1, }); const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 alerts related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alert related by source event'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); }); - it('should render single related alerts correctly', () => { + it('should render multiple related alerts correctly', () => { (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 1, + dataCount: 2, }); const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 alert related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by source event'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should render loading skeleton', () => { @@ -87,10 +103,31 @@ describe('', () => { }); const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('0 alerts related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by source event'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('0'); + }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ + loading: false, + error: true, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); + getByTestId(BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx index 0c1550dbb8692..dade35ca75546 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx @@ -5,13 +5,12 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; -import { InsightsSummaryRow } from './insights_summary_row'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; import { CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID } from './test_ids'; - -const ICON = 'warning'; +import { InsightsSummaryRow } from './insights_summary_row'; +import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; export interface RelatedAlertsBySameSourceEventProps { /** @@ -35,20 +34,24 @@ export const RelatedAlertsBySameSourceEvent: React.VFC + + const text = useMemo( + () => ( + + ), + [dataCount] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx index 96ab397229420..4aeeef1feb8b1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx @@ -9,21 +9,31 @@ import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { - SUMMARY_ROW_ICON_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { RelatedAlertsBySession } from './related_alerts_by_session'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../../shared/hooks/use_fetch_related_alerts_by_session'); +const mockOpenLeftPanel = jest.fn(); +const eventId = 'eventId'; +const indexName = 'indexName'; const entityId = 'entityId'; const scopeId = 'scopeId'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); const renderRelatedAlertsBySession = () => @@ -34,34 +44,40 @@ const renderRelatedAlertsBySession = () => ); describe('', () => { - it('should render many related alerts correctly', () => { + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + }); + + it('should render single related alerts correctly', () => { (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 2, + dataCount: 1, }); const { getByTestId } = renderRelatedAlertsBySession(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 alerts related by session'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alert related by session'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); }); - it('should render single related alerts correctly', () => { + it('should render multiple related alerts correctly', () => { (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 1, + dataCount: 2, }); const { getByTestId } = renderRelatedAlertsBySession(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 alert related by session'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by session'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should render loading skeleton', () => { @@ -82,4 +98,28 @@ describe('', () => { const { container } = renderRelatedAlertsBySession(); expect(container).toBeEmptyDOMElement(); }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsBySession(); + getByTestId(BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx index 4b41389137fad..9037ebca232a0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx @@ -5,14 +5,13 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; import { InsightsSummaryRow } from './insights_summary_row'; import { CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID } from './test_ids'; -const ICON = 'warning'; - export interface RelatedAlertsBySessionProps { /** * Value of the process.entry_leader.entity_id field @@ -35,21 +34,25 @@ export const RelatedAlertsBySession: React.VFC = ({ entityId, scopeId, }); - const text = ( - + + const text = useMemo( + () => ( + + ), + [dataCount] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx index 3d20e6399af38..e55d0e109d1d7 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx @@ -10,19 +10,29 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { CORRELATIONS_RELATED_CASES_TEST_ID, - SUMMARY_ROW_ICON_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { RelatedCases } from './related_cases'; import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../../shared/hooks/use_fetch_related_cases'); +const mockOpenLeftPanel = jest.fn(); const eventId = 'eventId'; +const indexName = 'indexName'; +const scopeId = 'scopeId'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); const renderRelatedCases = () => @@ -33,34 +43,40 @@ const renderRelatedCases = () => ); describe('', () => { - it('should render many related cases correctly', () => { + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + }); + + it('should render single related case correctly', () => { (useFetchRelatedCases as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 2, + dataCount: 1, }); const { getByTestId } = renderRelatedCases(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 related cases'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Related case'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); }); - it('should render single related case correctly', () => { + it('should render multiple related cases correctly', () => { (useFetchRelatedCases as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 1, + dataCount: 2, }); const { getByTestId } = renderRelatedCases(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 related case'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Related cases'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should render loading skeleton', () => { @@ -81,4 +97,28 @@ describe('', () => { const { container } = renderRelatedCases(); expect(container).toBeEmptyDOMElement(); }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + (useFetchRelatedCases as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedCases(); + getByTestId(BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx index d45cc971dc046..8a01b21799d86 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx @@ -5,13 +5,12 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; -import { InsightsSummaryRow } from './insights_summary_row'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; import { CORRELATIONS_RELATED_CASES_TEST_ID } from './test_ids'; - -const ICON = 'warning'; +import { InsightsSummaryRow } from './insights_summary_row'; +import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; export interface RelatedCasesProps { /** @@ -21,25 +20,29 @@ export interface RelatedCasesProps { } /** - * + * Show related cases in summary row */ export const RelatedCases: React.VFC = ({ eventId }) => { const { loading, error, dataCount } = useFetchRelatedCases({ eventId }); - const text = ( - + + const text = useMemo( + () => ( + + ), + [dataCount] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx index b5954c251c014..331283e194ed0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx @@ -9,16 +9,27 @@ import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { - SUMMARY_ROW_ICON_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { SuppressedAlerts } from './suppressed_alerts'; import { isSuppressionRuleInGA } from '../../../../../common/detection_engine/utils'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); +jest.mock('../../../../../common/detection_engine/utils', () => ({ + isSuppressionRuleInGA: jest.fn().mockReturnValue(false), +})); + +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); const renderSuppressedAlerts = (alertSuppressionCount: number) => render( @@ -27,34 +38,30 @@ const renderSuppressedAlerts = (alertSuppressionCount: number) => ); -jest.mock('../../../../../common/detection_engine/utils', () => ({ - isSuppressionRuleInGA: jest.fn().mockReturnValue(false), -})); - +const mockOpenLeftPanel = jest.fn(); +const scopeId = 'scopeId'; +const eventId = 'eventId'; +const indexName = 'indexName'; const isSuppressionRuleInGAMock = isSuppressionRuleInGA as jest.Mock; describe('', () => { - it('should render zero suppressed alert correctly', () => { - const { getByTestId } = renderSuppressedAlerts(0); + beforeEach(() => { + jest.clearAllMocks(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('0 suppressed alert'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); - expect( - getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) - ).toBeInTheDocument(); + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); }); it('should render single suppressed alert correctly', () => { const { getByTestId } = renderSuppressedAlerts(1); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 suppressed alert'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Suppressed alert'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); expect( getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) ).toBeInTheDocument(); @@ -63,14 +70,8 @@ describe('', () => { it('should render multiple suppressed alerts row correctly', () => { const { getByTestId } = renderSuppressedAlerts(2); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 suppressed alerts'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); - expect( - getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) - ).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Suppressed alerts'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should not render Technical Preview badge if rule type is in GA', () => { @@ -81,4 +82,22 @@ describe('', () => { queryByTestId(CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) ).not.toBeInTheDocument(); }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + const { getByTestId } = renderSuppressedAlerts(1); + getByTestId(BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx index a8cd147a4ac14..c7eb50aeb383a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx @@ -5,18 +5,19 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiBetaBadge } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { i18n } from '@kbn/i18n'; -import { isSuppressionRuleInGA } from '../../../../../common/detection_engine/utils'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { InsightsSummaryRow } from './insights_summary_row'; import { CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, } from './test_ids'; -import { InsightsSummaryRow } from './insights_summary_row'; +import { isSuppressionRuleInGA } from '../../../../../common/detection_engine/utils'; const SUPPRESSED_ALERTS_COUNT_TECHNICAL_PREVIEW = i18n.translate( 'xpack.securitySolution.flyout.right.overview.insights.suppressedAlertsCountTechnicalPreview', @@ -43,21 +44,24 @@ export const SuppressedAlerts: React.VFC = ({ alertSuppressionCount, ruleType, }) => { + const text = useMemo( + () => ( + + ), + [alertSuppressionCount] + ); + return ( - } + expandedSubTab={CORRELATIONS_TAB_ID} data-test-subj={CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID} key={`correlation-row-suppressed-alerts`} /> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts index e649c578bf487..959f8f106bb08 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts @@ -104,8 +104,9 @@ export const INSIGHTS_CONTENT_TEST_ID = INSIGHTS_TEST_ID + CONTENT_TEST_ID; /* Summary row */ export const SUMMARY_ROW_LOADING_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Loading`; -export const SUMMARY_ROW_ICON_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Icon`; +export const SUMMARY_ROW_TEXT_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Text`; export const SUMMARY_ROW_VALUE_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Value`; +export const SUMMARY_ROW_BUTTON_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Button`; /* Entities */ @@ -146,6 +147,10 @@ export const ENTITIES_HOST_OVERVIEW_VULNERABILITIES_TEST_ID = /* Threat intelligence */ export const INSIGHTS_THREAT_INTELLIGENCE_TEST_ID = `${PREFIX}InsightsThreatIntelligence` as const; +export const INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID = + `${INSIGHTS_THREAT_INTELLIGENCE_TEST_ID}ThreatMatches` as const; +export const INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID = + `${INSIGHTS_THREAT_INTELLIGENCE_TEST_ID}EnrichedWithThreatIntelligence` as const; /* Correlations */ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx index af92283b781b5..f451862e0990e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx @@ -6,18 +6,23 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; -import { useExpandableFlyoutApi, type ExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { DocumentDetailsContext } from '../../shared/context'; -import { TestProviders } from '../../../../common/mock'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useDocumentDetailsContext } from '../../shared/context'; import { ThreatIntelligenceOverview } from './threat_intelligence_overview'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelInsightsTab } from '../../left'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { THREAT_INTELLIGENCE_TAB_ID } from '../../left/components/threat_intelligence_details'; -import { INSIGHTS_THREAT_INTELLIGENCE_TEST_ID } from './test_ids'; import { - EXPANDABLE_PANEL_CONTENT_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, +} from './test_ids'; +import { EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, @@ -25,6 +30,8 @@ import { EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, } from '@kbn/security-solution-common'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../hooks/use_fetch_threat_intelligence'); const TOGGLE_ICON_TEST_ID = EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID( @@ -39,32 +46,45 @@ const TITLE_ICON_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID( const TITLE_TEXT_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID( INSIGHTS_THREAT_INTELLIGENCE_TEST_ID ); -const CONTENT_TEST_ID = EXPANDABLE_PANEL_CONTENT_TEST_ID(INSIGHTS_THREAT_INTELLIGENCE_TEST_ID); const LOADING_TEST_ID = EXPANDABLE_PANEL_LOADING_TEST_ID(INSIGHTS_THREAT_INTELLIGENCE_TEST_ID); +const THREAT_MATCHES_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID +); +const THREAT_MATCHES_BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID +); +const ENRICHED_WITH_THREAT_INTELLIGENCE_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID +); +const ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID +); -const panelContextValue = { - eventId: 'event id', - indexName: 'indexName', - dataFormattedForFieldBrowser: [], -} as unknown as DocumentDetailsContext; +const mockOpenLeftPanel = jest.fn(); +const eventId = 'eventId'; +const indexName = 'indexName'; +const scopeId = 'scopeId'; +const dataFormattedForFieldBrowser = ['scopeId']; -jest.mock('@kbn/expandable-flyout'); - -const renderThreatIntelligenceOverview = (contextValue: DocumentDetailsContext) => ( - - +const renderThreatIntelligenceOverview = () => + render( + - - -); - -const flyoutContextValue = { - openLeftPanel: jest.fn(), -} as unknown as ExpandableFlyoutApi; + + ); describe('', () => { - beforeAll(() => { - jest.mocked(useExpandableFlyoutApi).mockReturnValue(flyoutContextValue); + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + dataFormattedForFieldBrowser, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); }); it('should render wrapper component', () => { @@ -72,9 +92,7 @@ describe('', () => { loading: false, }); - const { getByTestId, queryByTestId } = render( - renderThreatIntelligenceOverview(panelContextValue) - ); + const { getByTestId, queryByTestId } = renderThreatIntelligenceOverview(); expect(queryByTestId(TOGGLE_ICON_TEST_ID)).not.toBeInTheDocument(); expect(getByTestId(TITLE_ICON_TEST_ID)).toBeInTheDocument(); @@ -82,14 +100,19 @@ describe('', () => { expect(queryByTestId(TITLE_TEXT_TEST_ID)).not.toBeInTheDocument(); }); - it('should not render link if isPrenviewMode is true', () => { + it('should not render link if isPreviewMode is true', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + dataFormattedForFieldBrowser, + isPreviewMode: true, + }); (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ loading: false, }); - const { getByTestId, queryByTestId } = render( - renderThreatIntelligenceOverview({ ...panelContextValue, isPreviewMode: true }) - ); + const { getByTestId, queryByTestId } = renderThreatIntelligenceOverview(); expect(queryByTestId(TOGGLE_ICON_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(TITLE_ICON_TEST_ID)).not.toBeInTheDocument(); @@ -104,13 +127,15 @@ describe('', () => { threatEnrichmentsCount: 1, }); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); + const { getByTestId } = renderThreatIntelligenceOverview(); expect(getByTestId(TITLE_LINK_TEST_ID)).toHaveTextContent('Threat intelligence'); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent('1 threat match detected'); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent( - '1 field enriched with threat intelligence' + expect(getByTestId(THREAT_MATCHES_TEXT_TEST_ID)).toHaveTextContent('Threat match detected'); + expect(getByTestId(THREAT_MATCHES_BUTTON_TEST_ID)).toHaveTextContent('1'); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_TEXT_TEST_ID)).toHaveTextContent( + 'Field enriched with threat intelligence' ); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID)).toHaveTextContent('1'); }); it('should render 2 matches detected and 2 fields enriched', () => { @@ -120,72 +145,85 @@ describe('', () => { threatEnrichmentsCount: 2, }); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); + const { getByTestId } = renderThreatIntelligenceOverview(); expect(getByTestId(TITLE_LINK_TEST_ID)).toHaveTextContent('Threat intelligence'); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent('2 threat matches detected'); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent( - '2 fields enriched with threat intelligence' + expect(getByTestId(THREAT_MATCHES_TEXT_TEST_ID)).toHaveTextContent('Threat matches detected'); + expect(getByTestId(THREAT_MATCHES_BUTTON_TEST_ID)).toHaveTextContent('2'); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_TEXT_TEST_ID)).toHaveTextContent( + 'Fields enriched with threat intelligence' ); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID)).toHaveTextContent('2'); }); - it('should render 0 fields enriched', () => { + it('should render loading', () => { (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ - loading: false, - threatMatchesCount: 1, - threatEnrichmentsCount: 0, + loading: true, }); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); + const { getByTestId } = renderThreatIntelligenceOverview(); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent( - '0 fields enriched with threat intelligence' - ); + expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); }); - it('should render 0 matches detected', () => { + it('should navigate to left section Insights tab when clicking on button', () => { (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ loading: false, - threatMatchesCount: 0, - threatEnrichmentsCount: 2, + threatMatchesCount: 1, + threatEnrichmentsCount: 1, }); + const { getByTestId } = renderThreatIntelligenceOverview(); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); - - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent('0 threat matches detected'); - }); - - it('should render loading', () => { - (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ - loading: true, + getByTestId(TITLE_LINK_TEST_ID).click(); + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: THREAT_INTELLIGENCE_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, }); - - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); - - expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); }); - it('should navigate to left section Insights tab when clicking on button', () => { + it('should open the expanded section to the correct tab when the number is clicked', () => { (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ loading: false, threatMatchesCount: 1, threatEnrichmentsCount: 1, }); - const { getByTestId } = render( - - - - - - ); - getByTestId(TITLE_LINK_TEST_ID).click(); - expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ + const { getByTestId } = renderThreatIntelligenceOverview(); + getByTestId(THREAT_MATCHES_BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: THREAT_INTELLIGENCE_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + + getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ id: DocumentDetailsLeftPanelKey, - path: { tab: LeftPanelInsightsTab, subTab: THREAT_INTELLIGENCE_TAB_ID }, + path: { + tab: LeftPanelInsightsTab, + subTab: THREAT_INTELLIGENCE_TAB_ID, + }, params: { - id: panelContextValue.eventId, - indexName: panelContextValue.indexName, + id: eventId, + indexName, + scopeId, }, }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx index 10b23ecfc2340..0a737a973ea2d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx @@ -14,11 +14,28 @@ import { ExpandablePanel } from '@kbn/security-solution-common'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { InsightsSummaryRow } from './insights_summary_row'; import { useDocumentDetailsContext } from '../../shared/context'; -import { INSIGHTS_THREAT_INTELLIGENCE_TEST_ID } from './test_ids'; +import { + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID, +} from './test_ids'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelInsightsTab } from '../../left'; import { THREAT_INTELLIGENCE_TAB_ID } from '../../left/components/threat_intelligence_details'; +const TITLE = ( + +); +const TOOLTIP = ( + +); + /** * Threat intelligence section under Insights section, overview tab. * The component fetches the necessary data, then pass it down to the InsightsSubSection component for loading and error state, @@ -53,26 +70,38 @@ export const ThreatIntelligenceOverview: FC = () => { !isPreviewMode ? { callback: goToThreatIntelligenceTab, - tooltip: ( - - ), + tooltip: TOOLTIP, } : undefined, [isPreviewMode, goToThreatIntelligenceTab] ); + const threatMatchCountText = useMemo( + () => ( + + ), + [threatMatchesCount] + ); + + const threatEnrichmentsCountText = useMemo( + () => ( + + ), + [threatEnrichmentsCount] + ); + return ( - ), + title: TITLE, link, iconType: !isPreviewMode ? 'arrowStart' : undefined, }} @@ -81,32 +110,20 @@ export const ThreatIntelligenceOverview: FC = () => { > - } - data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_TEST_ID} + expandedSubTab={THREAT_INTELLIGENCE_TAB_ID} + data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID} /> - } - data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_TEST_ID} + expandedSubTab={THREAT_INTELLIGENCE_TAB_ID} + data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID} /> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_event_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_event_details.test.tsx index de1020bac4d00..efa56c9e65720 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_event_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_event_details.test.tsx @@ -53,6 +53,7 @@ describe('useEventDetails', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ browserFields: {}, indexPattern: {}, + sourcererDataView: {}, }); (useTimelineEventsDetails as jest.Mock).mockReturnValue([false, [], {}, {}, jest.fn()]); jest.mocked(useGetFieldsData).mockReturnValue({ getFieldsData: (field: string) => field }); @@ -63,7 +64,7 @@ describe('useEventDetails', () => { expect(hookResult.result.current.dataAsNestedObject).toEqual({}); expect(hookResult.result.current.dataFormattedForFieldBrowser).toEqual([]); expect(hookResult.result.current.getFieldsData('test')).toEqual('test'); - expect(hookResult.result.current.indexPattern).toEqual({}); + expect('indexPattern' in hookResult.result.current).toEqual(true); expect(hookResult.result.current.loading).toEqual(false); expect(hookResult.result.current.refetchFlyoutData()).toEqual(undefined); expect(hookResult.result.current.searchHit).toEqual({}); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_event_details.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_event_details.ts index 40acb8690ce64..b880e372d5bed 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_event_details.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_event_details.ts @@ -8,7 +8,7 @@ import type { BrowserFields, TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { SecurityPageName } from '@kbn/security-solution-navigation'; -import type { DataViewBase } from '@kbn/es-query'; +import { type DataViewSpec } from '@kbn/data-plugin/common'; import { DEFAULT_ALERTS_INDEX, DEFAULT_PREVIEW_INDEX } from '../../../../../common/constants'; import type { RunTimeMappings } from '../../../../../common/api/search_strategy'; import { useSpaceId } from '../../../../common/hooks/use_space_id'; @@ -66,7 +66,7 @@ export interface UseEventDetailsResult { /** * Index pattern for rule details */ - indexPattern: DataViewBase; + indexPattern?: DataViewSpec; /** * Whether the data is loading */ @@ -102,7 +102,7 @@ export const useEventDetails = ({ useTimelineEventsDetails({ indexName: eventIndex, eventId: eventId ?? '', - runtimeMappings: sourcererDataView?.sourcererDataView?.runtimeFieldMap as RunTimeMappings, + runtimeMappings: sourcererDataView.sourcererDataView.runtimeFieldMap as RunTimeMappings, skip: !eventId, }); const { getFieldsData } = useGetFieldsData({ fieldsData: searchHit?.fields }); @@ -112,7 +112,7 @@ export const useEventDetails = ({ dataAsNestedObject, dataFormattedForFieldBrowser, getFieldsData, - indexPattern: sourcererDataView.indexPattern, + indexPattern: sourcererDataView.sourcererDataView, loading, refetchFlyoutData, searchHit, diff --git a/x-pack/plugins/security_solution/public/flyout/network_details/components/network_details.tsx b/x-pack/plugins/security_solution/public/flyout/network_details/components/network_details.tsx index b36ef2fd55854..715f6dfa43589 100644 --- a/x-pack/plugins/security_solution/public/flyout/network_details/components/network_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/network_details/components/network_details.tsx @@ -76,10 +76,10 @@ export const NetworkDetails = ({ services: { uiSettings }, } = useKibana(); - const { indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); + const { indicesExist, sourcererDataView, selectedPatterns } = useSourcererDataView(); const [filterQuery, kqlError] = convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - indexPattern, + dataViewSpec: sourcererDataView, queries: [query], filters, }); diff --git a/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx b/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx index c2d84e543dc0f..55c8a4472379b 100644 --- a/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx @@ -25,12 +25,13 @@ import { convertToBuildEsQuery } from '../../common/lib/kuery'; import { useInvalidFilterQuery } from '../../common/hooks/use_invalid_filter_query'; import { SessionsView } from '../../common/components/sessions_viewer'; import { kubernetesSessionsHeaders } from './constants'; +import { dataViewSpecToIndexPattern } from './utils/data_view_spec_to_index_pattern'; export const KubernetesContainer = React.memo(() => { const { kubernetesSecurity, uiSettings } = useKibana().services; const { globalFullScreen } = useGlobalFullScreen(); - const { indexPattern, sourcererDataView, dataViewId } = useSourcererDataView(); + const { sourcererDataView, dataViewId } = useSourcererDataView(); const { from, to } = useGlobalTime(); const getGlobalFiltersQuerySelector = useMemo( @@ -45,11 +46,11 @@ export const KubernetesContainer = React.memo(() => { () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - indexPattern, + dataViewSpec: sourcererDataView, queries: [query], filters, }), - [filters, indexPattern, uiSettings, query] + [filters, sourcererDataView, uiSettings, query] ); useInvalidFilterQuery({ @@ -84,7 +85,7 @@ export const KubernetesContainer = React.memo(() => { ), - indexPattern, + indexPattern: dataViewSpecToIndexPattern(sourcererDataView), globalFilter: { filterQuery, startDate: from, diff --git a/x-pack/plugins/security_solution/public/kubernetes/pages/utils/data_view_spec_to_index_pattern.ts b/x-pack/plugins/security_solution/public/kubernetes/pages/utils/data_view_spec_to_index_pattern.ts new file mode 100644 index 0000000000000..f4cb604ec3d8f --- /dev/null +++ b/x-pack/plugins/security_solution/public/kubernetes/pages/utils/data_view_spec_to_index_pattern.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DataViewSpec } from '@kbn/data-plugin/common'; +import type { IndexPattern } from '@kbn/kubernetes-security-plugin/public/types'; + +export const dataViewSpecToIndexPattern = ( + dataViewSpec?: DataViewSpec +): IndexPattern | undefined => { + return dataViewSpec as IndexPattern | undefined; +}; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts index 6ab7979c46086..b5c41d1e66faf 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts @@ -35,8 +35,7 @@ const loginWithoutAccess = (url: string) => { loadPage(url); }; -// Failing: See https://github.com/elastic/kibana/issues/191914 -describe.skip('Artifacts pages', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { +describe('Artifacts pages', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { let endpointData: ReturnTypeFromChainable | undefined; before(() => { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/blocklist.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/blocklist.cy.ts index 32dad9b0bbc0d..f0d3eb96e4581 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/blocklist.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/blocklist.cy.ts @@ -41,7 +41,7 @@ const { describe( 'Blocklist', { - tags: ['@ess', '@serverless', '@skipInServerlessMKI'], // @skipInServerlessMKI until kibana is rebuilt after merge + tags: ['@ess', '@serverless'], }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/event_filters.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/event_filters.cy.ts index 0e3f837c9091c..af7310953e86e 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/event_filters.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/event_filters.cy.ts @@ -41,8 +41,7 @@ describe('Event Filters', { tags: ['@ess', '@serverless', '@skipInServerlessMKI' removeAllArtifacts(); }); - // FLAKY: https://github.com/elastic/kibana/issues/194135 - describe.skip('when editing event filter value', () => { + describe('when editing event filter value', () => { let eventFiltersMock: ArtifactsFixtureType; beforeEach(() => { login(); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts index 887fa47d03918..86e07e65e83ae 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts @@ -5,13 +5,13 @@ * 2.0. */ +import { waitForAlertsToPopulate } from '@kbn/test-suites-xpack/security_solution_cypress/cypress/tasks/create_new_rule'; +import { login } from '../../tasks/login'; +import { waitForEndpointListPageToBeLoaded } from '../../tasks/response_console'; import type { PolicyData } from '../../../../../common/endpoint/types'; -import { APP_ENDPOINTS_PATH } from '../../../../../common/constants'; import { closeAllToasts } from '../../tasks/toasts'; import { toggleRuleOffAndOn, visitRuleAlerts } from '../../tasks/isolate'; import { cleanupRule, loadRule } from '../../tasks/api_fixtures'; -import { login } from '../../tasks/login'; -import { loadPage } from '../../tasks/common'; import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../tasks/fleet'; import { changeAlertsFilter } from '../../tasks/alerts'; @@ -38,21 +38,33 @@ describe( let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; + let ruleId: string; + let ruleName: string; + beforeEach(() => { + login(); + }); before(() => { - getEndpointIntegrationVersion().then((version) => - createAgentPolicyTask(version, 'automated_response_actions').then((data) => { - indexedPolicy = data; - policy = indexedPolicy.integrationPolicies[0]; - - return enableAllPolicyProtections(policy.id).then(() => { - // Create and enroll a new Endpoint host - return createEndpointHost(policy.policy_ids[0]).then((host) => { - createdHost = host as CreateAndEnrollEndpointHostResponse; + getEndpointIntegrationVersion() + .then((version) => + createAgentPolicyTask(version, 'automated_response_actions').then((data) => { + indexedPolicy = data; + policy = indexedPolicy.integrationPolicies[0]; + + return enableAllPolicyProtections(policy.id).then(() => { + // Create and enroll a new Endpoint host + return createEndpointHost(policy.policy_ids[0]).then((host) => { + createdHost = host as CreateAndEnrollEndpointHostResponse; + }); }); + }) + ) + .then(() => { + loadRule().then((data) => { + ruleId = data.id; + ruleName = data.name; }); - }) - ); + }); }); after(() => { @@ -67,48 +79,29 @@ describe( if (createdHost) { deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] }); } - }); - beforeEach(() => { - login(); + if (ruleId) { + cleanupRule(ruleId); + } }); - // FLAKY: https://github.com/elastic/kibana/issues/169828 - describe.skip('From alerts', () => { - let ruleId: string; - let ruleName: string; - - before(() => { - loadRule().then((data) => { - ruleId = data.id; - ruleName = data.name; - }); - }); - - after(() => { - if (ruleId) { - cleanupRule(ruleId); - } - }); - - it('should have generated endpoint and rule', () => { - loadPage(APP_ENDPOINTS_PATH); - cy.contains(createdHost.hostname).should('exist'); + it('should have been called against a created host', () => { + waitForEndpointListPageToBeLoaded(createdHost.hostname); + toggleRuleOffAndOn(ruleName); - toggleRuleOffAndOn(ruleName); + visitRuleAlerts(ruleName); + closeAllToasts(); - visitRuleAlerts(ruleName); - closeAllToasts(); + changeAlertsFilter(`process.name: "agentbeat" and agent.id: "${createdHost.agentId}"`); + waitForAlertsToPopulate(); - changeAlertsFilter(`process.name: "agentbeat" and agent.id: "${createdHost.agentId}"`); - cy.getByTestSubj('expand-event').first().click(); - cy.getByTestSubj('securitySolutionFlyoutNavigationExpandDetailButton').click(); - cy.getByTestSubj('securitySolutionFlyoutResponseTab').click(); + cy.getByTestSubj('expand-event').first().click(); + cy.getByTestSubj('securitySolutionFlyoutNavigationExpandDetailButton').click(); + cy.getByTestSubj('securitySolutionFlyoutResponseTab').click(); - cy.contains(/isolate is pending|isolate completed successfully/g); - cy.contains(/kill-process is pending|kill-process completed successfully/g); - cy.contains('The action was called with a non-existing event field name: entity_id'); - }); + cy.contains(/isolate is pending|isolate completed successfully/g); + cy.contains(/kill-process is pending|kill-process completed successfully/g); + cy.contains('The action was called with a non-existing event field name: entity_id'); }); } ); diff --git a/x-pack/plugins/security_solution/public/management/cypress/support/plugin_handlers/endpoint_data_loader.ts b/x-pack/plugins/security_solution/public/management/cypress/support/plugin_handlers/endpoint_data_loader.ts index 76004f91ccb48..4b4e9adef0ec2 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/support/plugin_handlers/endpoint_data_loader.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/support/plugin_handlers/endpoint_data_loader.ts @@ -10,6 +10,10 @@ import type { KbnClient } from '@kbn/test'; import pRetry from 'p-retry'; import { kibanaPackageJson } from '@kbn/repo-info'; import type { ToolingLog } from '@kbn/tooling-log'; +import { + RETRYABLE_TRANSIENT_ERRORS, + retryOnError, +} from '../../../../../common/endpoint/data_loaders/utils'; import { fetchFleetLatestAvailableAgentVersion } from '../../../../../common/endpoint/utils/fetch_fleet_version'; import { dump } from '../../../../../scripts/endpoint/common/utils'; import { STARTED_TRANSFORM_STATES } from '../../../../../common/constants'; @@ -158,18 +162,17 @@ const stopTransform = async ( ): Promise => { log.debug(`Stopping transform id: ${transformId}`); - await esClient.transform - .stopTransform({ - transform_id: `${transformId}*`, - force: true, - wait_for_completion: true, - allow_no_match: true, - }) - .catch((e) => { - Error.captureStackTrace(e); - log.verbose(dump(e, 8)); - throw e; - }); + await retryOnError( + () => + esClient.transform.stopTransform({ + transform_id: `${transformId}*`, + force: true, + wait_for_completion: true, + allow_no_match: true, + }), + RETRYABLE_TRANSIENT_ERRORS, + log + ); }; const startTransform = async ( @@ -177,9 +180,14 @@ const startTransform = async ( log: ToolingLog, transformId: string ): Promise => { - const transformsResponse = await esClient.transform.getTransformStats({ - transform_id: `${transformId}*`, - }); + const transformsResponse = await retryOnError( + () => + esClient.transform.getTransformStats({ + transform_id: `${transformId}*`, + }), + RETRYABLE_TRANSIENT_ERRORS, + log + ); log.verbose( `Transform status found for [${transformId}*] returned:\n${dump(transformsResponse)}` @@ -193,7 +201,11 @@ const startTransform = async ( log.debug(`Staring transform id: [${transform.id}]`); - return esClient.transform.startTransform({ transform_id: transform.id }); + return retryOnError( + () => esClient.transform.startTransform({ transform_id: transform.id }), + RETRYABLE_TRANSIENT_ERRORS, + log + ); }) ); }; diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/api_fixtures.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/api_fixtures.ts index 1bd0e5652b442..e6e44e7e5517a 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/api_fixtures.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/api_fixtures.ts @@ -55,7 +55,7 @@ export const loadRule = (body = {}, includeResponseActions = true) => tags: [], license: '', interval: '1m', - from: 'now-120s', + from: 'now-360s', to: 'now', meta: { from: '1m', kibana_siem_app_url: 'http://localhost:5620/app/security' }, actions: [], diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts index e122eebedfc33..5372b46e11f9e 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts @@ -22,7 +22,7 @@ import { } from '@kbn/fleet-plugin/common'; import type { GetOneAgentResponse, - PutAgentReassignResponse, + PostAgentReassignResponse, UpdateAgentPolicyResponse, } from '@kbn/fleet-plugin/common/types'; import { uninstallTokensRouteService } from '@kbn/fleet-plugin/common/services/routes'; @@ -56,10 +56,10 @@ export const getAgentByHostName = (hostname: string): Cypress.Chainable = export const reassignAgentPolicy = ( agentId: string, agentPolicyId: string -): Cypress.Chainable> => - request({ +): Cypress.Chainable> => + request({ url: agentRouteService.getReassignPath(agentId), - method: 'PUT', + method: 'POST', body: { policy_id: agentPolicyId, }, diff --git a/x-pack/plugins/security_solution/public/management/cypress/tsconfig.json b/x-pack/plugins/security_solution/public/management/cypress/tsconfig.json index 5d124d1035259..c983368164906 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tsconfig.json +++ b/x-pack/plugins/security_solution/public/management/cypress/tsconfig.json @@ -34,5 +34,6 @@ "@kbn/security-solution-serverless", "@kbn/dev-utils", "@kbn/spaces-plugin", + "@kbn/test-suites-xpack/security_solution_cypress/cypress", ] } diff --git a/x-pack/plugins/security_solution/public/management/links.ts b/x-pack/plugins/security_solution/public/management/links.ts index 27b5b62eac6f8..61cbc1a511c09 100644 --- a/x-pack/plugins/security_solution/public/management/links.ts +++ b/x-pack/plugins/security_solution/public/management/links.ts @@ -198,7 +198,7 @@ export const links: LinkItem = { id: SecurityPageName.entityAnalyticsEntityStoreManagement, title: ENTITY_STORE, description: i18n.translate('xpack.securitySolution.appLinks.entityStoreDescription', { - defaultMessage: "Allows comprehensive monitoring of your system's hosts and users.", + defaultMessage: 'Store host and user entities observed in events.', }), landingIcon: IconAssetCriticality, path: ENTITY_ANALYTICS_ENTITY_STORE_MANAGEMENT_PATH, @@ -229,7 +229,8 @@ export const links: LinkItem = { path: NOTES_PATH, skipUrlState: true, hideTimeline: true, - experimentalKey: 'securitySolutionNotesEnabled', + hideWhenExperimentalKey: 'securitySolutionNotesDisabled', + globalSearchDisabled: true, }, ], }; diff --git a/x-pack/plugins/security_solution/public/management/pages/index.tsx b/x-pack/plugins/security_solution/public/management/pages/index.tsx index dc8314acc276c..d558b1271dc6b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/index.tsx @@ -88,8 +88,8 @@ const NotesTelemetry = () => ( ); export const ManagementContainer = memo(() => { - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const { @@ -162,7 +162,7 @@ export const ManagementContainer = memo(() => { hasPrivilege={canReadActionsLogManagement} /> - {securitySolutionNotesEnabled && ( + {!securitySolutionNotesDisabled && ( )} diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx index ffcee81a3cb8f..75e932d5385fd 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx @@ -124,7 +124,7 @@ describe('Policy Details', () => { if (path === `${AGENT_API_ROUTES.STATUS_PATTERN}`) { asyncActions = asyncActions.then(async () => sleep()); return Promise.resolve({ - results: { events: 0, total: 5, online: 3, error: 1, offline: 1 }, + results: { events: 0, active: 5, online: 3, error: 1, offline: 1 }, success: true, }); } diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx index 7f72a8d475134..13f18d071d543 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx @@ -60,7 +60,7 @@ export const PolicyDetails = React.memo(() => { const headerRightContent = ( { @@ -63,7 +63,7 @@ export const fetchNotes = async ({ sortField, sortOrder, filter, - userFilter, + createdByFilter, associatedFilter, search, }, diff --git a/x-pack/plugins/security_solution/public/notes/components/user_filter_dropdown.test.tsx b/x-pack/plugins/security_solution/public/notes/components/created_by_filter_dropdown.test.tsx similarity index 74% rename from x-pack/plugins/security_solution/public/notes/components/user_filter_dropdown.test.tsx rename to x-pack/plugins/security_solution/public/notes/components/created_by_filter_dropdown.test.tsx index b095036e58632..301e59db1bfc1 100644 --- a/x-pack/plugins/security_solution/public/notes/components/user_filter_dropdown.test.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/created_by_filter_dropdown.test.tsx @@ -7,8 +7,8 @@ import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; -import { UserFilterDropdown } from './user_filter_dropdown'; -import { USER_SELECT_TEST_ID } from './test_ids'; +import { CreatedByFilterDropdown } from './created_by_filter_dropdown'; +import { CREATED_BY_SELECT_TEST_ID } from './test_ids'; import { useSuggestUsers } from '../../common/components/user_profiles/use_suggest_users'; import { useLicense } from '../../common/hooks/use_license'; import { useUpsellingMessage } from '../../common/hooks/use_upselling'; @@ -32,16 +32,25 @@ describe('UserFilterDropdown', () => { jest.clearAllMocks(); (useSuggestUsers as jest.Mock).mockReturnValue({ isLoading: false, - data: [{ user: { username: 'test' } }, { user: { username: 'elastic' } }], + data: [ + { + uid: '1', + user: { username: 'test' }, + }, + { + uid: '2', + user: { username: 'elastic' }, + }, + ], }); (useLicense as jest.Mock).mockReturnValue({ isPlatinumPlus: () => true }); (useUpsellingMessage as jest.Mock).mockReturnValue('upsellingMessage'); }); it('should render the component enabled', () => { - const { getByTestId } = render(); + const { getByTestId } = render(); - const dropdown = getByTestId(USER_SELECT_TEST_ID); + const dropdown = getByTestId(CREATED_BY_SELECT_TEST_ID); expect(dropdown).toBeInTheDocument(); expect(dropdown).not.toHaveClass('euiComboBox-isDisabled'); @@ -50,13 +59,13 @@ describe('UserFilterDropdown', () => { it('should render the dropdown disabled', async () => { (useLicense as jest.Mock).mockReturnValue({ isPlatinumPlus: () => false }); - const { getByTestId } = render(); + const { getByTestId } = render(); - expect(getByTestId(USER_SELECT_TEST_ID)).toHaveClass('euiComboBox-isDisabled'); + expect(getByTestId(CREATED_BY_SELECT_TEST_ID)).toHaveClass('euiComboBox-isDisabled'); }); it('should call the correct action when select a user', async () => { - const { getByTestId } = render(); + const { getByTestId } = render(); const userSelect = getByTestId('comboBoxSearchInput'); userSelect.focus(); diff --git a/x-pack/plugins/security_solution/public/notes/components/user_filter_dropdown.tsx b/x-pack/plugins/security_solution/public/notes/components/created_by_filter_dropdown.tsx similarity index 68% rename from x-pack/plugins/security_solution/public/notes/components/user_filter_dropdown.tsx rename to x-pack/plugins/security_solution/public/notes/components/created_by_filter_dropdown.tsx index 78f4ef6dd2ac8..4b962e4c1ef60 100644 --- a/x-pack/plugins/security_solution/public/notes/components/user_filter_dropdown.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/created_by_filter_dropdown.tsx @@ -13,15 +13,26 @@ import { i18n } from '@kbn/i18n'; import type { EuiComboBoxOptionOption } from '@elastic/eui/src/components/combo_box/types'; import { useLicense } from '../../common/hooks/use_license'; import { useUpsellingMessage } from '../../common/hooks/use_upselling'; -import { USER_SELECT_TEST_ID } from './test_ids'; +import { CREATED_BY_SELECT_TEST_ID } from './test_ids'; import { useSuggestUsers } from '../../common/components/user_profiles/use_suggest_users'; -import { userFilterUsers } from '..'; +import { userFilterCreatedBy } from '..'; -export const USERS_DROPDOWN = i18n.translate('xpack.securitySolution.notes.usersDropdownLabel', { - defaultMessage: 'Users', +export const CREATED_BY = i18n.translate('xpack.securitySolution.notes.createdByDropdownLabel', { + defaultMessage: 'Created by', }); -export const UserFilterDropdown = React.memo(() => { +interface User { + /** + * uuid of the UserProfile + */ + id: string; + /** + * full_name || email || username of the UserProfile + */ + label: string; +} + +export const CreatedByFilterDropdown = React.memo(() => { const dispatch = useDispatch(); const isPlatinumPlus = useLicense().isPlatinumPlus(); const upsellingMessage = useUpsellingMessage('note_management_user_filter'); @@ -30,19 +41,21 @@ export const UserFilterDropdown = React.memo(() => { searchTerm: '', enabled: isPlatinumPlus, }); - const users = useMemo( + + const users: User[] = useMemo( () => (data || []).map((userProfile: UserProfileWithAvatar) => ({ - label: userProfile.user.full_name || userProfile.user.username, + id: userProfile.uid, + label: userProfile.user.full_name || userProfile.user.email || userProfile.user.username, })), [data] ); - const [selectedUser, setSelectedUser] = useState>>(); + const [selectedUser, setSelectedUser] = useState>>(); const onChange = useCallback( - (user: Array>) => { + (user: Array>) => { setSelectedUser(user); - dispatch(userFilterUsers(user.length > 0 ? user[0].label : '')); + dispatch(userFilterCreatedBy(user.length > 0 ? (user[0].id as string) : '')); }, [dispatch] ); @@ -50,14 +63,14 @@ export const UserFilterDropdown = React.memo(() => { const dropdown = useMemo( () => ( ), [isLoading, isPlatinumPlus, onChange, selectedUser, users] @@ -76,4 +89,4 @@ export const UserFilterDropdown = React.memo(() => { ); }); -UserFilterDropdown.displayName = 'UserFilterDropdown'; +CreatedByFilterDropdown.displayName = 'CreatedByFilterDropdown'; diff --git a/x-pack/plugins/security_solution/public/notes/components/search_row.test.tsx b/x-pack/plugins/security_solution/public/notes/components/search_row.test.tsx index 447ade158306b..cdae928b4ad87 100644 --- a/x-pack/plugins/security_solution/public/notes/components/search_row.test.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/search_row.test.tsx @@ -9,7 +9,11 @@ import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { SearchRow } from './search_row'; -import { ASSOCIATED_NOT_SELECT_TEST_ID, SEARCH_BAR_TEST_ID, USER_SELECT_TEST_ID } from './test_ids'; +import { + ASSOCIATED_NOT_SELECT_TEST_ID, + SEARCH_BAR_TEST_ID, + CREATED_BY_SELECT_TEST_ID, +} from './test_ids'; import { AssociatedFilter } from '../../../common/notes/constants'; import { useSuggestUsers } from '../../common/components/user_profiles/use_suggest_users'; import { TestProviders } from '../../common/mock'; @@ -43,7 +47,7 @@ describe('SearchRow', () => { ); expect(getByTestId(SEARCH_BAR_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(USER_SELECT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(CREATED_BY_SELECT_TEST_ID)).toBeInTheDocument(); expect(getByTestId(ASSOCIATED_NOT_SELECT_TEST_ID)).toBeInTheDocument(); }); diff --git a/x-pack/plugins/security_solution/public/notes/components/search_row.tsx b/x-pack/plugins/security_solution/public/notes/components/search_row.tsx index 3c4093f913acf..ea006f9a3f01f 100644 --- a/x-pack/plugins/security_solution/public/notes/components/search_row.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/search_row.tsx @@ -16,7 +16,7 @@ import { } from '@elastic/eui'; import { useDispatch } from 'react-redux'; import { i18n } from '@kbn/i18n'; -import { UserFilterDropdown } from './user_filter_dropdown'; +import { CreatedByFilterDropdown } from './created_by_filter_dropdown'; import { ASSOCIATED_NOT_SELECT_TEST_ID, SEARCH_BAR_TEST_ID } from './test_ids'; import { userFilterAssociatedNotes, userSearchedNotes } from '..'; import { AssociatedFilter } from '../../../common/notes/constants'; @@ -65,7 +65,7 @@ export const SearchRow = React.memo(() => { - + { const pagination = useSelector(selectNotesPagination); const sort = useSelector(selectNotesTableSort); const selectedItems = useSelector(selectNotesTableSelectedIds); - const notesUserFilters = useSelector(selectNotesTableUserFilters); - const notesAssociatedFilters = useSelector(selectNotesTableAssociatedFilter); + const notesCreatedByFilter = useSelector(selectNotesTableCreatedByFilter); + const notesAssociatedFilter = useSelector(selectNotesTableAssociatedFilter); const resultsCount = useMemo(() => { const { perPage, page, total } = pagination; const startOfCurrentPage = perPage * (page - 1) + 1; @@ -87,8 +87,8 @@ export const NotesUtilityBar = React.memo(() => { sortField: sort.field, sortOrder: sort.direction, filter: '', - userFilter: notesUserFilters, - associatedFilter: notesAssociatedFilters, + createdByFilter: notesCreatedByFilter, + associatedFilter: notesAssociatedFilter, search: notesSearch, }) ); @@ -98,8 +98,8 @@ export const NotesUtilityBar = React.memo(() => { pagination.perPage, sort.field, sort.direction, - notesUserFilters, - notesAssociatedFilters, + notesCreatedByFilter, + notesAssociatedFilter, notesSearch, ]); return ( diff --git a/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.test.ts b/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.test.ts index eb5b23641b80c..7498a6f40c6b6 100644 --- a/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.test.ts +++ b/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.test.ts @@ -45,8 +45,8 @@ describe('useFetchNotes', () => { expect(typeof result.current.onLoad).toBe('function'); }); - it('should not dispatch action when securitySolutionNotesEnabled is false', () => { - mockedUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('should not dispatch action when securitySolutionNotesDisabled is true', () => { + mockedUseIsExperimentalFeatureEnabled.mockReturnValue(true); const { result } = renderHook(() => useFetchNotes()); result.current.onLoad([{ _id: '1' }]); @@ -54,7 +54,7 @@ describe('useFetchNotes', () => { }); it('should not dispatch action when events array is empty', () => { - mockedUseIsExperimentalFeatureEnabled.mockReturnValue(true); + mockedUseIsExperimentalFeatureEnabled.mockReturnValue(false); const { result } = renderHook(() => useFetchNotes()); result.current.onLoad([]); @@ -62,7 +62,7 @@ describe('useFetchNotes', () => { }); it('should dispatch fetchNotesByDocumentIds with correct ids when conditions are met', () => { - mockedUseIsExperimentalFeatureEnabled.mockReturnValue(true); + mockedUseIsExperimentalFeatureEnabled.mockReturnValue(false); const { result } = renderHook(() => useFetchNotes()); const events = [{ _id: '1' }, { _id: '2' }, { _id: '3' }]; @@ -74,7 +74,7 @@ describe('useFetchNotes', () => { }); it('should memoize onLoad function', () => { - mockedUseIsExperimentalFeatureEnabled.mockReturnValue(true); + mockedUseIsExperimentalFeatureEnabled.mockReturnValue(false); const { result, rerender } = renderHook(() => useFetchNotes()); const firstOnLoad = result.current.onLoad; @@ -84,7 +84,7 @@ describe('useFetchNotes', () => { expect(firstOnLoad).toBe(secondOnLoad); }); - it('should update onLoad when securitySolutionNotesEnabled changes', () => { + it('should update onLoad when securitySolutionNotesDisabled changes', () => { mockedUseIsExperimentalFeatureEnabled.mockReturnValue(true); const { result, rerender } = renderHook(() => useFetchNotes()); diff --git a/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.ts b/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.ts index 2cf599e76bcc9..cdfa8b7600dfd 100644 --- a/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.ts +++ b/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.ts @@ -22,19 +22,19 @@ export interface UseFetchNotesResult { */ export const useFetchNotes = (): UseFetchNotesResult => { const dispatch = useDispatch(); - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const onLoad = useCallback( (events: Array>) => { - if (!securitySolutionNotesEnabled || events.length === 0) return; + if (securitySolutionNotesDisabled || events.length === 0) return; const eventIds: string[] = events .map((event) => event._id) .filter((id) => id != null) as string[]; dispatch(fetchNotesByDocumentIds({ documentIds: eventIds })); }, - [dispatch, securitySolutionNotesEnabled] + [dispatch, securitySolutionNotesDisabled] ); return { onLoad }; diff --git a/x-pack/plugins/security_solution/public/notes/links.ts b/x-pack/plugins/security_solution/public/notes/links.ts index ef6c691b6246a..b09877e200fb9 100644 --- a/x-pack/plugins/security_solution/public/notes/links.ts +++ b/x-pack/plugins/security_solution/public/notes/links.ts @@ -21,5 +21,5 @@ export const links: LinkItem = { }), ], links: [], - experimentalKey: 'securitySolutionNotesEnabled', + hideWhenExperimentalKey: 'securitySolutionNotesDisabled', }; diff --git a/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx b/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx index 4795d6146be4d..3060e5ccf93d9 100644 --- a/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx +++ b/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx @@ -36,7 +36,7 @@ import { selectNotesTablePendingDeleteIds, selectFetchNotesError, ReqStatus, - selectNotesTableUserFilters, + selectNotesTableCreatedByFilter, selectNotesTableAssociatedFilter, } from '..'; import type { NotesState } from '..'; @@ -121,8 +121,8 @@ export const NoteManagementPage = () => { const pagination = useSelector(selectNotesPagination); const sort = useSelector(selectNotesTableSort); const notesSearch = useSelector(selectNotesTableSearch); - const notesUserFilters = useSelector(selectNotesTableUserFilters); - const notesAssociatedFilters = useSelector(selectNotesTableAssociatedFilter); + const notesCreatedByFilter = useSelector(selectNotesTableCreatedByFilter); + const notesAssociatedFilter = useSelector(selectNotesTableAssociatedFilter); const pendingDeleteIds = useSelector(selectNotesTablePendingDeleteIds); const isDeleteModalVisible = pendingDeleteIds.length > 0; const fetchNotesStatus = useSelector(selectFetchNotesStatus); @@ -138,8 +138,8 @@ export const NoteManagementPage = () => { sortField: sort.field, sortOrder: sort.direction, filter: '', - userFilter: notesUserFilters, - associatedFilter: notesAssociatedFilters, + createdByFilter: notesCreatedByFilter, + associatedFilter: notesAssociatedFilter, search: notesSearch, }) ); @@ -149,8 +149,8 @@ export const NoteManagementPage = () => { pagination.perPage, sort.field, sort.direction, - notesUserFilters, - notesAssociatedFilters, + notesCreatedByFilter, + notesAssociatedFilter, notesSearch, ]); diff --git a/x-pack/plugins/security_solution/public/notes/store/notes.slice.test.ts b/x-pack/plugins/security_solution/public/notes/store/notes.slice.test.ts index 65fa293bd824a..46bcec9b448f9 100644 --- a/x-pack/plugins/security_solution/public/notes/store/notes.slice.test.ts +++ b/x-pack/plugins/security_solution/public/notes/store/notes.slice.test.ts @@ -38,7 +38,7 @@ import { selectNotesTableSort, selectSortedNotesByDocumentId, selectSortedNotesBySavedObjectId, - selectNotesTableUserFilters, + selectNotesTableCreatedByFilter, selectNotesTableAssociatedFilter, userClosedDeleteModal, userFilteredNotes, @@ -49,7 +49,7 @@ import { userSelectedRow, userSelectedNotesForDeletion, userSortedNotes, - userFilterUsers, + userFilterCreatedBy, userClosedCreateErrorToast, userFilterAssociatedNotes, } from './notes.slice'; @@ -104,7 +104,7 @@ const initialNonEmptyState: NotesState = { direction: 'desc' as const, }, filter: '', - userFilter: '', + createdByFilter: '', associatedFilter: AssociatedFilter.all, search: '', selectedIds: [], @@ -508,13 +508,13 @@ describe('notesSlice', () => { }); }); - describe('userFilterUsers', () => { + describe('userFilterCreatedBy', () => { it('should set correct value to filter users', () => { - const action = { type: userFilterUsers.type, payload: 'abc' }; + const action = { type: userFilterCreatedBy.type, payload: 'abc' }; expect(notesReducer(initalEmptyState, action)).toEqual({ ...initalEmptyState, - userFilter: 'abc', + createdByFilter: 'abc', }); }); }); @@ -866,12 +866,12 @@ describe('notesSlice', () => { expect(selectNotesTableSearch(state)).toBe('test search'); }); - it('should select user filter', () => { + it('should select createdBy filter', () => { const state = { ...mockGlobalState, - notes: { ...initialNotesState, userFilter: 'abc' }, + notes: { ...initialNotesState, createdByFilter: 'abc' }, }; - expect(selectNotesTableUserFilters(state)).toBe('abc'); + expect(selectNotesTableCreatedByFilter(state)).toBe('abc'); }); it('should select associated filter', () => { diff --git a/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts b/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts index 28bf609a4f210..259a14b208969 100644 --- a/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts +++ b/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts @@ -58,7 +58,7 @@ export interface NotesState extends EntityState { direction: 'asc' | 'desc'; }; filter: string; - userFilter: string; + createdByFilter: string; search: string; associatedFilter: AssociatedFilter; selectedIds: string[]; @@ -94,7 +94,7 @@ export const initialNotesState: NotesState = notesAdapter.getInitialState({ direction: 'desc', }, filter: '', - userFilter: '', + createdByFilter: '', associatedFilter: AssociatedFilter.all, search: '', selectedIds: [], @@ -129,13 +129,13 @@ export const fetchNotes = createAsyncThunk< sortField: string; sortOrder: string; filter: string; - userFilter: string; + createdByFilter: string; associatedFilter: AssociatedFilter; search: string; }, {} >('notes/fetchNotes', async (args) => { - const { page, perPage, sortField, sortOrder, filter, userFilter, associatedFilter, search } = + const { page, perPage, sortField, sortOrder, filter, createdByFilter, associatedFilter, search } = args; const res = await fetchNotesApi({ page, @@ -143,7 +143,7 @@ export const fetchNotes = createAsyncThunk< sortField, sortOrder, filter, - userFilter, + createdByFilter, associatedFilter, search, }); @@ -169,7 +169,7 @@ export const deleteNotes = createAsyncThunk { state.filter = action.payload; }, - userFilterUsers: (state: NotesState, action: { payload: string }) => { - state.userFilter = action.payload; + userFilterCreatedBy: (state: NotesState, action: { payload: string }) => { + state.createdByFilter = action.payload; }, userFilterAssociatedNotes: (state: NotesState, action: { payload: AssociatedFilter }) => { state.associatedFilter = action.payload; @@ -332,7 +332,7 @@ export const selectNotesTableSelectedIds = (state: State) => state.notes.selecte export const selectNotesTableSearch = (state: State) => state.notes.search; -export const selectNotesTableUserFilters = (state: State) => state.notes.userFilter; +export const selectNotesTableCreatedByFilter = (state: State) => state.notes.createdByFilter; export const selectNotesTableAssociatedFilter = (state: State) => state.notes.associatedFilter; @@ -423,7 +423,7 @@ export const { userSelectedPerPage, userSortedNotes, userFilteredNotes, - userFilterUsers, + userFilterCreatedBy, userFilterAssociatedNotes, userSearchedNotes, userSelectedRow, diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.tsx index c0369ed23d61c..85d3994d44530 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.tsx @@ -6,7 +6,16 @@ */ import React, { useCallback, useMemo } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiLink, + EuiSpacer, + EuiText, + useEuiTheme, + COLOR_MODES_STANDARD, +} from '@elastic/eui'; import { SecurityPageName } from '@kbn/security-solution-navigation'; import { SecuritySolutionLinkButton } from '../../../../../common/components/links'; import { OnboardingCardId } from '../../../../constants'; @@ -21,6 +30,9 @@ export const AlertsCard: OnboardingCardComponent = ({ setExpandedCardId, setComplete, }) => { + const { colorMode } = useEuiTheme(); + const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; + const isIntegrationsCardComplete = useMemo( () => isCardComplete(OnboardingCardId.integrations), [isCardComplete] @@ -39,7 +51,11 @@ export const AlertsCard: OnboardingCardComponent = ({ alignItems="flexStart" > - + {i18n.ALERTS_CARD_DESCRIPTION} {!isIntegrationsCardComplete && ( diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_card.tsx index 4b87f23dd2435..b728606937020 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_card.tsx @@ -6,7 +6,16 @@ */ import React, { useCallback, useMemo } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiText } from '@elastic/eui'; +import { + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiLink, + EuiText, + useEuiTheme, + COLOR_MODES_STANDARD, +} from '@elastic/eui'; import { css } from '@emotion/css'; import { OnboardingCardId } from '../../../../constants'; import type { OnboardingCardComponent } from '../../../../types'; @@ -15,6 +24,7 @@ import { OnboardingCardContentPanel } from '../common/card_content_panel'; import { ConnectorCards } from './connectors/connector_cards'; import { CardCallOut } from '../common/card_callout'; import type { AssistantCardMetadata } from './types'; +import { MissingPrivilegesDescription } from './connectors/missing_privileges_tooltip'; export const AssistantCard: OnboardingCardComponent = ({ isCardComplete, @@ -22,6 +32,8 @@ export const AssistantCard: OnboardingCardComponent = ({ checkCompleteMetadata, checkComplete, }) => { + const { euiTheme, colorMode } = useEuiTheme(); + const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; const isIntegrationsCardComplete = useMemo( () => isCardComplete(OnboardingCardId.integrations), [isCardComplete] @@ -32,43 +44,60 @@ export const AssistantCard: OnboardingCardComponent = ({ }, [setExpandedCardId]); const connectors = checkCompleteMetadata?.connectors; + const canExecuteConnectors = checkCompleteMetadata?.canExecuteConnectors; + const canCreateConnectors = checkCompleteMetadata?.canCreateConnectors; return ( - - - - - {i18n.ASSISTANT_CARD_DESCRIPTION} - - - - {isIntegrationsCardComplete ? ( - - ) : ( - - - - {i18n.ASSISTANT_CARD_CALLOUT_INTEGRATIONS_BUTTON} - - - - - - } + + {canExecuteConnectors ? ( + + + + {i18n.ASSISTANT_CARD_DESCRIPTION} + + + + {isIntegrationsCardComplete ? ( + - - )} - - + ) : ( + + + + {i18n.ASSISTANT_CARD_CALLOUT_INTEGRATIONS_BUTTON} + + + + + + } + /> + + )} + + + ) : ( + + + + )} ); }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_check_complete.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_check_complete.ts index bdb52b3a0e614..8c0d029cee583 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_check_complete.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_check_complete.ts @@ -14,8 +14,11 @@ import type { AssistantCardMetadata } from './types'; export const checkAssistantCardComplete: OnboardingCardCheckComplete< AssistantCardMetadata -> = async ({ http }) => { +> = async ({ http, application }) => { const allConnectors = await loadConnectors({ http }); + const { + capabilities: { actions }, + } = application; const aiConnectors = allConnectors.reduce((acc: AIConnector[], connector) => { if (!connector.isMissingSecrets && AllowedActionTypeIds.includes(connector.actionTypeId)) { @@ -37,6 +40,8 @@ export const checkAssistantCardComplete: OnboardingCardCheckComplete< completeBadgeText, metadata: { connectors: aiConnectors, + canExecuteConnectors: Boolean(actions?.show && actions?.execute), + canCreateConnectors: Boolean(actions?.save), }, }; }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/connector_cards.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/connector_cards.tsx index 3cdefaa1fe490..472459b631b0a 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/connector_cards.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/connector_cards.tsx @@ -15,69 +15,104 @@ import { EuiText, EuiBadge, EuiSpacer, + EuiCallOut, } from '@elastic/eui'; import { css } from '@emotion/css'; import { useKibana } from '../../../../../../common/lib/kibana'; import { CreateConnectorPopover } from './create_connector_popover'; import { ConnectorSetup } from './connector_setup'; +import * as i18n from './translations'; +import { MissingPrivilegesDescription } from './missing_privileges_tooltip'; interface ConnectorCardsProps { connectors?: AIConnector[]; onConnectorSaved: () => void; + canCreateConnectors?: boolean; } export const ConnectorCards = React.memo( - ({ connectors, onConnectorSaved }) => { + ({ connectors, onConnectorSaved, canCreateConnectors }) => { const { triggersActionsUi: { actionTypeRegistry }, } = useKibana().services; - if (!connectors) return ; + if (!connectors) { + return ; + } + + const hasConnectors = connectors.length > 0; - if (connectors.length > 0) { + // show callout when user is missing actions.save privilege + if (!hasConnectors && !canCreateConnectors) { return ( - <> - - {connectors.map((connector) => ( - - - - - {connector.name} - - - - {actionTypeRegistry.get(connector.actionTypeId).actionTypeTitle} - - - - - - ))} - - - - + + + ); } - return ; + return ( + <> + {hasConnectors ? ( + <> + + + + + ) : ( + + )} + + ); } ); ConnectorCards.displayName = 'ConnectorCards'; + +interface ConnectorListProps { + connectors: AIConnector[]; + actionTypeRegistry: ReturnType< + typeof useKibana + >['services']['triggersActionsUi']['actionTypeRegistry']; +} + +const ConnectorList = React.memo(({ connectors, actionTypeRegistry }) => ( + + {connectors.map((connector) => ( + + + + + {connector.name} + + + + {actionTypeRegistry.get(connector.actionTypeId).actionTypeTitle} + + + + + + ))} + +)); + +ConnectorList.displayName = 'ConnectorList'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/create_connector_popover.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/create_connector_popover.tsx index de432d6597afd..32bcd66f49249 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/create_connector_popover.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/create_connector_popover.tsx @@ -8,14 +8,16 @@ import React, { useCallback, useState } from 'react'; import { css } from '@emotion/css'; import { EuiPopover, EuiLink, EuiText } from '@elastic/eui'; import { ConnectorSetup } from './connector_setup'; -import * as i18n from '../translations'; +import * as i18n from './translations'; +import { MissingPrivilegesTooltip } from './missing_privileges_tooltip'; interface CreateConnectorPopoverProps { onConnectorSaved: () => void; + canCreateConnectors?: boolean; } export const CreateConnectorPopover = React.memo( - ({ onConnectorSaved }) => { + ({ onConnectorSaved, canCreateConnectors }) => { const [isOpen, setIsPopoverOpen] = useState(false); const closePopover = useCallback(() => setIsPopoverOpen(false), []); @@ -23,6 +25,15 @@ export const CreateConnectorPopover = React.memo( () => setIsPopoverOpen((isPopoverOpen) => !isPopoverOpen), [] ); + if (!canCreateConnectors) { + return ( + + + {i18n.ASSISTANT_CARD_CREATE_NEW_CONNECTOR_POPOVER} + + + ); + } return ( (({ children }) => ( + } + > + {children} + +)); +MissingPrivilegesTooltip.displayName = 'MissingPrivilegesTooltip'; + +export const MissingPrivilegesDescription = React.memo(() => { + return ( + + {i18n.PRIVILEGES_REQUIRED_TITLE} + + +
    +
  • {i18n.REQUIRED_PRIVILEGES_CONNECTORS_ALL}
  • +
+
+
+ {i18n.CONTACT_ADMINISTRATOR} +
+ ); +}); +MissingPrivilegesDescription.displayName = 'MissingPrivilegesDescription'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/translations.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/translations.ts new file mode 100644 index 0000000000000..983a6a67f5b32 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/translations.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const ASSISTANT_CARD_CREATE_NEW_CONNECTOR_POPOVER = i18n.translate( + 'xpack.securitySolution.onboarding.assistantCard.createNewConnectorPopover', + { + defaultMessage: 'Create new connector', + } +); + +export const PRIVILEGES_MISSING_TITLE = i18n.translate( + 'xpack.securitySolution.onboarding.assistantCard.missingPrivileges.title', + { + defaultMessage: 'Missing privileges', + } +); + +export const PRIVILEGES_REQUIRED_TITLE = i18n.translate( + 'xpack.securitySolution.onboarding.assistantCard.requiredPrivileges', + { + defaultMessage: 'The minimum Kibana privileges required to use this feature are:', + } +); + +export const REQUIRED_PRIVILEGES_CONNECTORS_ALL = i18n.translate( + 'xpack.securitySolution.onboarding.assistantCard.requiredPrivileges.connectorsAll', + { + defaultMessage: 'Management > Connectors: All', + } +); + +export const CONTACT_ADMINISTRATOR = i18n.translate( + 'xpack.securitySolution.onboarding.assistantCard.missingPrivileges.contactAdministrator', + { + defaultMessage: 'Contact your administrator for assistance.', + } +); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts index 27deda4190f2e..fedf975052327 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts @@ -27,6 +27,6 @@ export const assistantCardConfig: OnboardingCardConfig = checkComplete: checkAssistantCardComplete, // Both capabilities are needed for this card, so we should use a double array to create an AND conditional // (a single array would create an OR conditional between them) - capabilities: [['securitySolutionAssistant.ai-assistant', 'actions.show']], + capabilities: [['securitySolutionAssistant.ai-assistant']], licenseType: 'enterprise', }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/translations.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/translations.ts index 41e73bdacf061..de3c111280436 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/translations.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/translations.ts @@ -42,3 +42,10 @@ export const ASSISTANT_CARD_CREATE_NEW_CONNECTOR_POPOVER = i18n.translate( defaultMessage: 'Create new connector', } ); + +export const PRIVILEGES_MISSING_TITLE = i18n.translate( + 'xpack.securitySolution.onboarding.assistantCard.callout.title', + { + defaultMessage: 'Missing privileges', + } +); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/types.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/types.ts index f1e0216406391..d6647adf054fe 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/types.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/types.ts @@ -9,4 +9,6 @@ import type { ActionConnector } from '@kbn/alerts-ui-shared'; export interface AssistantCardMetadata { connectors: ActionConnector[]; + canExecuteConnectors: boolean; + canCreateConnectors: boolean; } diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_image_panel.styles.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_image_panel.styles.ts index d8f6d6c278ee3..c7998135aa8ae 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_image_panel.styles.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_image_panel.styles.ts @@ -6,13 +6,15 @@ */ import { css } from '@emotion/css'; -import { useEuiTheme, useEuiShadow } from '@elastic/eui'; +import { useEuiTheme, useEuiShadow, COLOR_MODES_STANDARD } from '@elastic/eui'; export const useCardContentImagePanelStyles = () => { - const { euiTheme } = useEuiTheme(); + const { euiTheme, colorMode } = useEuiTheme(); const shadowStyles = useEuiShadow('m'); + const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; return css` padding-top: 8px; + ${isDarkMode ? `background-color: ${euiTheme.colors.lightestShade}` : ''}; .cardSpacer { width: 8%; } diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.tsx index df98800d83f32..201aa4f0d3150 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.tsx @@ -6,7 +6,16 @@ */ import React, { useCallback, useMemo } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiLink, + EuiSpacer, + EuiText, + useEuiTheme, + COLOR_MODES_STANDARD, +} from '@elastic/eui'; import { SecurityPageName } from '@kbn/security-solution-navigation'; import { OnboardingCardId } from '../../../../constants'; import type { OnboardingCardComponent } from '../../../../types'; @@ -21,6 +30,9 @@ export const DashboardsCard: OnboardingCardComponent = ({ setComplete, setExpandedCardId, }) => { + const { colorMode } = useEuiTheme(); + const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; + const isIntegrationsCardComplete = useMemo( () => isCardComplete(OnboardingCardId.integrations), [isCardComplete] @@ -42,7 +54,11 @@ export const DashboardsCard: OnboardingCardComponent = ({ alignItems="flexStart" > - + {i18n.DASHBOARDS_CARD_DESCRIPTION} {!isIntegrationsCardComplete && ( diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.tsx index 7f283c0ffbc78..50c722d49c359 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.tsx @@ -6,7 +6,16 @@ */ import React, { useCallback, useMemo } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiLink, + EuiSpacer, + EuiText, + useEuiTheme, + COLOR_MODES_STANDARD, +} from '@elastic/eui'; import { SecurityPageName } from '@kbn/security-solution-navigation'; import { SecuritySolutionLinkButton } from '../../../../../common/components/links'; import { OnboardingCardId } from '../../../../constants'; @@ -17,6 +26,9 @@ import rulesImageSrc from './images/rules.png'; import * as i18n from './translations'; export const RulesCard: OnboardingCardComponent = ({ isCardComplete, setExpandedCardId }) => { + const { colorMode } = useEuiTheme(); + const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; + const isIntegrationsCardComplete = useMemo( () => isCardComplete(OnboardingCardId.integrations), [isCardComplete] @@ -35,7 +47,11 @@ export const RulesCard: OnboardingCardComponent = ({ isCardComplete, setExpanded alignItems="flexStart" > - + {i18n.RULES_CARD_DESCRIPTION} {!isIntegrationsCardComplete && ( diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/constants.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/constants.ts index f67b991e0ea75..722dfad89fc5b 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/constants.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/constants.ts @@ -8,7 +8,6 @@ export const TELEMETRY_FOOTER_LINK = `footer_link`; export enum OnboardingFooterLinkItemId { - video = 'video', documentation = 'documentation', demo = 'demo', forum = 'forum', diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/footer_items.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/footer_items.ts index f064947f657a4..40a6e01f6c037 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/footer_items.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/footer_items.ts @@ -5,78 +5,90 @@ * 2.0. */ import { i18n } from '@kbn/i18n'; -import documentation from './images/documentation.png'; -import forum from './images/forum.png'; -import demo from './images/demo.png'; -import labs from './images/labs.png'; +import { COLOR_MODES_STANDARD, useEuiTheme } from '@elastic/eui'; +import documentationImage from './images/documentation.png'; +import darkDocumentationImage from './images/documentation_dark.png'; +import forumImage from './images/forum.png'; +import darkForumImge from './images/forum_dark.png'; +import demoImage from './images/demo.png'; +import darkDemoImage from './images/demo_dark.png'; +import labsImage from './images/labs.png'; +import darkLabsImage from './images/labs_dark.png'; import { OnboardingFooterLinkItemId } from './constants'; -export const footerItems = [ - { - icon: documentation, - id: OnboardingFooterLinkItemId.documentation, - title: i18n.translate('xpack.securitySolution.onboarding.footer.documentation.title', { - defaultMessage: 'Browse documentation', - }), - description: i18n.translate( - 'xpack.securitySolution.onboarding.footer.documentation.description', - { - defaultMessage: 'In-depth guides on all Elastic features', - } - ), - link: { - title: i18n.translate('xpack.securitySolution.onboarding.footer.documentation.link.title', { - defaultMessage: 'Start reading', +export const useFooterItems = () => { + const { colorMode } = useEuiTheme(); + const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; + + const footerItems = [ + { + icon: isDarkMode ? darkDocumentationImage : documentationImage, + id: OnboardingFooterLinkItemId.documentation, + title: i18n.translate('xpack.securitySolution.onboarding.footer.documentation.title', { + defaultMessage: 'Browse documentation', }), - href: 'https://docs.elastic.co/integrations/elastic-security-intro', + description: i18n.translate( + 'xpack.securitySolution.onboarding.footer.documentation.description', + { + defaultMessage: 'In-depth guides on all Elastic features', + } + ), + link: { + title: i18n.translate('xpack.securitySolution.onboarding.footer.documentation.link.title', { + defaultMessage: 'Start reading', + }), + href: 'https://docs.elastic.co/integrations/elastic-security-intro', + }, }, - }, - { - icon: forum, - id: OnboardingFooterLinkItemId.forum, - title: i18n.translate('xpack.securitySolution.onboarding.footer.forum.title', { - defaultMessage: 'Explore forum', - }), - description: i18n.translate('xpack.securitySolution.onboarding.footer.forum.description', { - defaultMessage: 'Exchange thoughts about Elastic', - }), - link: { - title: i18n.translate('xpack.securitySolution.onboarding.footer.forum.link.title', { - defaultMessage: 'Discuss Forum', + { + icon: isDarkMode ? darkForumImge : forumImage, + id: OnboardingFooterLinkItemId.forum, + title: i18n.translate('xpack.securitySolution.onboarding.footer.forum.title', { + defaultMessage: 'Explore forum', + }), + description: i18n.translate('xpack.securitySolution.onboarding.footer.forum.description', { + defaultMessage: 'Exchange thoughts about Elastic', }), - href: 'https://discuss.elastic.co/c/security/83', + link: { + title: i18n.translate('xpack.securitySolution.onboarding.footer.forum.link.title', { + defaultMessage: 'Discuss Forum', + }), + href: 'https://discuss.elastic.co/c/security/83', + }, }, - }, - { - icon: demo, - id: OnboardingFooterLinkItemId.demo, - title: i18n.translate('xpack.securitySolution.onboarding.footer.demo.title', { - defaultMessage: 'View demo project', - }), - description: i18n.translate('xpack.securitySolution.onboarding.footer.demo.description', { - defaultMessage: 'Discover Elastic using sample data', - }), - link: { - title: i18n.translate('xpack.securitySolution.onboarding.footer.demo.link.title', { - defaultMessage: 'Explore demo', + { + icon: isDarkMode ? darkDemoImage : demoImage, + id: OnboardingFooterLinkItemId.demo, + title: i18n.translate('xpack.securitySolution.onboarding.footer.demo.title', { + defaultMessage: 'View demo project', + }), + description: i18n.translate('xpack.securitySolution.onboarding.footer.demo.description', { + defaultMessage: 'Discover Elastic using sample data', }), - href: 'https://www.elastic.co/demo-gallery?solutions=security&features=null', + link: { + title: i18n.translate('xpack.securitySolution.onboarding.footer.demo.link.title', { + defaultMessage: 'Explore demo', + }), + href: 'https://www.elastic.co/demo-gallery?solutions=security&features=null', + }, }, - }, - { - icon: labs, - id: OnboardingFooterLinkItemId.labs, - title: i18n.translate('xpack.securitySolution.onboarding.footer.labs.title', { - defaultMessage: 'Elastic Security Labs', - }), - description: i18n.translate('xpack.securitySolution.onboarding.footer.labs.description', { - defaultMessage: 'Insights from security researchers', - }), - link: { - title: i18n.translate('xpack.securitySolution.onboarding.footer.labs.link.title', { - defaultMessage: 'Learn more', + { + icon: isDarkMode ? darkLabsImage : labsImage, + id: OnboardingFooterLinkItemId.labs, + title: i18n.translate('xpack.securitySolution.onboarding.footer.labs.title', { + defaultMessage: 'Elastic Security Labs', }), - href: 'https://www.elastic.co/security-labs', + description: i18n.translate('xpack.securitySolution.onboarding.footer.labs.description', { + defaultMessage: 'Insights from security researchers', + }), + link: { + title: i18n.translate('xpack.securitySolution.onboarding.footer.labs.link.title', { + defaultMessage: 'Learn more', + }), + href: 'https://www.elastic.co/security-labs', + }, }, - }, -] as const; + ] as const; + + return footerItems; +}; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/images/demo_dark.png b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/images/demo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..fb90f857c06949116e3926721656d474286b624e GIT binary patch literal 11618 zcmV-oEuGSdP)k4c6Y|~KZC55jW`P=JHTQiYW`Sc zCs>5W#@QiCzLHwH`UZhkrFSld6PBo`?_B1b+N1Z zs_w38z7Nn+v%9*wy8HM0z2EiTBT^_73WY+UP$(1%g+ifFZnxLh z)%!+A9{Jgq+g4mu?3c>#-Pr$Q?{;_flEM*`0;B*0eQm41eQIjT zKY0Jnwx;HmKvh+Ze|C0;3$>uNbqzH&w^B(-DHn8^hr?}J^A+2wF8c+9zrlx`yKKbZ8Q9(~t*+OqmPtO=B zlA?$dap~;r^3Rig@IvoL`$JQqKxjPV(_3^Jc{D^rL-(n?qJo$LP-$ryy}V-|&CSiy z@X#QwS=+Wu@WH^q4H~?EmkQZ)vhahN8XrFolu2iQw3IH>8gpP1m!>$(q* zx2|5xt@h~1LmC@>M2$@?+$z`AHAY?wfyb@Q|Fq@#r$QnAKXY>;%JAaWm#DC?i0<4O z-~wJ*S;Z8gl#dib_yKc~BKIpQsv`HHG;7zk`Pp6n@bJ(Re`#`X%c~#Gbr#GHp zKXgxbcb6I=Oehz~075@GUC_Y<{wqv?1Mtgb0RxLnsDw3!Te5NE^UQ^5;Lkx3`k8V- z5ShS5UV~%%Z(QZ~H$1(G3pE~_m>B1eL0KT=5c2Y_ zS@ns>W8B37V#L6))9n4K4T~KMSaDc)j1YXZVF7VnT?5%66mx27GU_wjXYc>eI2V*0 z!L`mbz!<%P?ABAPX-8M$sIa0G;2WJ?fooST9eFe|6u{s0ECch@hK*e4A*ArTg_RXR zs4jf+Tkhuz7egF_=LQD)x$6S|9p{l1p{c2rS?LWdW_Uy;Od;@k+=pv}<6w>9Y5_bB z%ML*oqX&-R0rl`8S0({m8XS)iK%`WGh$jFPuzmZksLujLn0!3W-7SmJttT`+`S!6N z{`cdwLRb+&@LQc-9h$Dcq3e3!nT^j;^TaAHAVLTr;3Ck(NG9%+5WZ?Ktqc-~U;8Sy>1B(=Q%}kP88Uu-?9PGx8eb<;%+}NIrJ;>UI3M$;rq3 zv32X7qJn|~{`X@em~ClU%~PR1Up+rZLqijP51bo{Qfs6)Q4<(>G)zlNOZ;!V9yhpQ z!biv77+L1$=lD6zKyaBdv-e!Zul3&D0jg#1D^jQ!$=0pk5K{?c#>Yo_&^^qQ0H2W+ z+{AZ*tk=QKFTB*TY10ei*RS>EZ8|kC72x0>baYhL)cuU*%sW^<-UrLt(9q1E8)fOs zf`Y<`a6pj39J9nt%u2U13keH*p@s2&2ujEcaiA7{UJx-DScHL2s2TGtL1EuP^ERn#|zbcpTS;>&N>G zDvkG(g&zttJ~qmg1}~*QK={YEm|qMbL_mngE-|+O!5;!rE8vUYWj9!4;f?^2 znGpppkzN#OPuT~DAinV8OZ>j@*-MQ$K#nuQu9wE#mnTYzfE?A}7Iw|`Mw(T`2vC$* zN?`|5w@@g!Z7>D^1+^Dne0f6u>5Nur4`sV-r-`zcwC*;Kl@O4(H-L-rF zd+hFa$#8WbY_MpsWWtK$2Ytlc51-*KSOMXMwUn(g_=H(+SWH-8oExJA1PZ|}&JDK& zZUsgKxIjL`GGD)TnIDH60#`9g;Fyw<5ctxqU0hM;R!*42%G-2_ua_XMaO6@t*h}ubY{k<}MLFV~E{kMZ@_Y4BqvvYFXQ{ z_m$82U)g)${OQx)Z@uum0=)IjqlXJf{}CI?+T$Gyp@mQj;pb_?{;M?f;64|6xGds0 zvk(DTdprm0c>n%wE+{ycP!tF(gc|)nvhbj#VPRpORT0m%fX=T=)Upl~z+AE0l3;Y=pabYo$>O;B(c~`k3OZ=N3NdGcl#a_fS$C9tlK& zPSgzqP)fY7ac%8)?%nRFs;VoyclYK=@-Uvw0)4V532hJcuVpfVaN+og++Oe#Gv!ipSu3z~vBD{Koam z{D++6LwT!3MnvO1J+Pq2nuyoJ9l3e)8V^)U%gX5d`Exvolr1mZAju+fFp?A$7R1cl z2yi^!Z`9}|!hI+%MjR24%iy_Y7GOh&pn18oTG3p~m2F$laTIZ)e{Tf}oaL#k1fu|GzzW(mr`#;n) z?Q7=eWZ?&k%*UOXnWnYt+Sqe-G0z8KV3`hXHE~}6R|b}^b=6vaPFQCMjg?>vHv~eA z%nk0t&xh}g`^#R(@{RNJ^Hjxz*6i*e4Ow1ZxlCd4H(H{FFOR?Ngxv}#l*k?>0=|nv zc5Go$anv=*Dc3b?{Z!x35O{gVr#gxX3s2m+6ZA}M;28xFzCKC$d@~Rr2nc>$VWG{! z2f@C{0!lnCtg%@b@VH0^0{qx^R{h?++bnBzi@zTf<_;S{VBv8s2rR|O0XJ=d2|iMy zaFgJ^u&Q(E3c~f{-MK1+Km1pSC0m+9s%I;u+-w;vbzWIH!KquvKW>R?goSqRu4TsvP&Za zVL?n#RaG5%46j4SB+gx1TNgDVAaJ~X{gNSc)-DI0M;a2A9ivYfa~<%QsL0~R-Gw!6 zk@Mp**=>`7FhTLcXpz7=JWt@sXG4lrW9JjshU8b;PC5}?ym zbh1Jj(7cAmI<#ub z$1W}`Ml3T3w|3m(N-A4-d@s2ELgwFNq!Yoo8H{d77n{FZ{$A27Iq~-x8x729V|J;p zZQH(=etYg$u1b}_1o93eI$$jXT8M{Hx| z#zFY);u}oCtgfz&Iilbipd50W1wi^)R(eeE8N7ctuxWF<@5c3uKPQ*q8U=vxv;R7h zd5y@2r-BG>kyb<|#9Y0V2{PeFh6F{iL@YU0ia@*q7sl-K!%`xjFH(szB6ctb;>jS+ zAp<2r$7rhOMBs}NPPC4|kjRDx&xhw%An0Dt`>mdNW^>g0EwJwxt7o*fuHLivmCyUn z{^sNfasfH-1~t;0@b}~P@;D7rckq8-Fw&;Nmo>K&i1vj#W8z36h?J-q(V1yC=hzO! z9_1DGBbMkeP2~KzPPj-LHf&sWPIIagZ4$8Lh?Sa}!mStK*6OllGwJLIw}toiPHLe8 zy*XaXD5oPpwuK)**sXznp6$R73#*1yp!kuIA%cLJyDdf5DVfp6D!nP1?&|9sC=~{R z{XAV6&t-#PTa9W^^l*o2h^A+zxDYosHb+;|jkya*5sP*UTszz-QCWxU10w?CfX`#~ zna%Jn-MaeLwJmM0efpKp{UuA2&QOlXX%;BkmLESRrZrk+JD%ITjj!mC3}QxDqF_{5 zYmuf+1T?3LduUMniqA^X=eEk9_n3!FMKpNl0liEcz zcuq_&1$bR?QE|H=134pSBY@%azeWxcFZdJ|%qqY{Fqo(n6F{kw%^sx-gcpUVSoIK4 zZWQ5U@ZF$5h71idV-RkDz+TL7lM$IQ`17#xvEECxm!qFbG}_6r4U|-TpU5O(>LrfF z^V00O*6lCt^IyKyo0FIzCknuX|NHE}uTzTP%fpvz{*lqQg1#KP;n+^V!`57j>*~N| zz~mSN#&V@K7RWN;JyQ)pV}bN1s;<^uuFDxQ1Q|g;));DFE)N1$t42Y9?pD!`E%!8u zg5m;8LYRYVaUTIrs0cpwBwBbq@|n(PuJ0}5^^G$j*6 zml(!^TWNOvs0qY!d!pVahH@c$CJKu9zN|h2n&9`<^c+A~{K4CUs$xEZ;2V5X|NIxE%s%2%zn(z5te6w1StFg?oVD>J=6i@HDSj)xs*C5xqoDN!cZ_ z0>*>Edwkw86buOmRITwnX_^+;u{SV&?)1s5b&_T+4QfnSj|zAS%8D_^kFtfxY#`0q zlElhyR!p%U5!Mt#`2wrHCQ`gg1&m71+Dzg%^Z0Q%7=3Q@R!Rl9I1h}J@V53{%bv$P z;`{9RCgw)Tjfwbv<#rHZ2qZt{ zElD!20O83jO86CtQ(jpKH?_TDvF!VlVKS-!2zn{ajE`dFQCd>YQ?7G!vmHBje>S7? zlQ9K=-_J5WU8GQ?fM|aw(vR%i7syz*K*kin@cT3F!zuC)EH@vXZpl}@@%d_--lGhW z5d|=cU4Bw1QUFCXRFaWaMxPQ(jkbTI^E+LX0UTEV<@zX`0M%l7%BikvN3a?oIgI1W zq7>%1yDt?+gJX2*Z?02GWigdh6jR+(KB{V}pgOav~JgGTDNmGDY65yK-ek@jf7(1V7@d9OO0Z3 z{r~Jf+D#7OSS8q~_Wq8N2z=dA34U;Kn10b^KUW*du;GB8o(cG=vZ;bH1x6z%WWIsX z6eDaR%wD)fp`V}QZV=k2Wp?lR%viCeZFg!zKgULZLgEE4&-e^u^9wYNol_PTX?iC9 zgrv#gDf;-weboP9kSoHruWq4C(DS`hG&wXy`Nki-^TmV}U~zHYm_W1qcVRA(ueP=h z1+v%40US{PqtUH{T+Hm!67^1mXkccR2Bv3d##qG+l#NV0S!Oy8vLd{CG?3BJV5Ne_ zIBWnY;B&OK@EilIn$gtMdJr=AgYK>#N)tyEK#D$%Q$8Sp5G#^oah?y&RiB(y|hSs1kl2o=qh0CA^e#VdNWXh5cAvj9oj*P z^r7+UyY0k#_vzXiv`5u$W4T zO-vx*@cCmccQ5ucUbSkCAF}vvch@mWfs{u8H(CGRj8C{i_yLMozkcT|xs}T13fr3- zz#L*M9f<%~Y+fQS!48B{U}cI=de6N@SLo^e{)DTa ziGuTO{^GN?$K+Em4*wsk&6$^P$9`&;l>dMOE#c7cqZA6IZ@ z>@m5STW9Z)A~Rr_c@)S(Qp(DUye8 zTxje`hWj6#I~CbG4Tz=Rv1bF|$7=dvEW<-dkdy+rsqh8&#|tP0NDWkj#l#p`dMs%v zZ#0OtMzN=IQ)JI&td&~k`_<`RB{gd-DFrAX{VU`W2BuS6ST@@X_9+EO6;TcLv0|85 zg5JFU02G67WL{kx-nnw~^GUhr2`fN&(`riE$I1i`X6I;ZVS&5=Cb%fl1KX~m1p@94 zMgw`%4lDwU$FR>EU>T!8GHy`9Ssj^=j1!j*ak|VqoYilIU3CweZ7bHW7`-lgS9on&DAAPz#kWjpu&=?)s^H{+RDmEkviO!Vb)$0xljOuwHMYO zLXP$a+~iHj5f5Cw(#IR)*0*h-qT*tIytW8i1z2#Q|1a27Sx#;Q*X8yY#j8N@Q6WaU z6Dd)&M96gl6wS~l1O*bx60e38@0SXYOKB@FBR{(Zr{gbdn@x7tCbs*#B6%SEu=*91 zl{`CSM$`^OO9YgF)v)|_=Zxb>>&{k(9Og51HRLAX`am%i>4DXu&0yLigdc4Yax)x& z>x127M9_Ts(#O=>dqymsVk^V;3ZT1tpD!^AxP>n_*OMZB5Wt#)TlD$7xb@|jYXsfB z8*Y)lb0^6E<{2RNdh`=ryLu^L_g=ONpu0E*5d1z9IyYp5;QA=v-x*N-75)7(XmOC! zps@I`@=%KU`bKJO3@>uOanqK_1e%3~dB5FzS^i?Y0<62O0AV(`d$P5Cld$y2=!n*6xH&=rpb!`lL~oEx2|EVCFyaP`1hX>>@MMB9-^c0# zmRSDZu?@tsz-Q{i6R5MP1VZ?g>ytUK`a|Vl6`%7fTY32X!_56zV6M{K+zd4|wnUT$ zX;Ku?&^t6d^nj*EA6eD{>_z~;S4IFqHkCjLe|A6-OrG=t;1Y?Y60wLbZjeQ^CpvRXrxI6s0mE5)F+zgFl|yUnCUhJUF#7* zBcF!{fMr0Seatn2djtk&=lD*NjP$#qpQdZq}3pJVN7txw3@UT&y4_~;VGIN^2Xi(iYL_h zeQE8NCeoX-3nZ$5&!U#Hw&&(Omp3Y61c%19p`c_w7(IfWp;43E=CC5deRqJG79uKQvgrE}q~E>|y}5 zvx6e1h|CTI9c>Lys=q#4;Wslhbl*~ztw#WjDL|gr0uDJX!h1xcaEAt-Pm&yN=9c(fXQLUr|x zQJEr4n`BCqybGjh`j`i%1S{gOR8~k6pK7JKRTVV1x`K*EXW4CzeE)EV|LTiay&#~YbmLD|$JTHo0aEBgac(A}`LX0-<<#uQVa|=GzLSvs_!<693 z&n)&qn0&dBsy=#1^?x-$1vBp4bkLmM6bN@m20||ov&8^{<+{4YQL@0M9h!nl{JjeV zA2&Oo1PgT~)cV8AV7l9hQUNw8#N%q@^mAscp_Nx7s~(k;8#& zv?Yhdm-_poR)_;WcDz;4{BC!br7^ef1=85i;qnD?ogh}WM1V|*7gC0x-tVJr|8W<+ zH|1^bwXkq`(;ODU!d%}Mx4yJ&b!dS3!nnyGGc-RpXY0wtsRU~$DbInwJo2Tsn8FV* z5)A&yX4j7f5PnRkZ)~Yb>Gk_weKxIjLUP*2Xg070yhPUGF8nLT=*ftn9QH-lJQtDVEg74+R@?O?I8HBFh+3; z!j1KT;P2Z7%REi0X{nC@8s%?01S~qNd*a8JCZsIc215UZu0WLaPIlvvt;T+9PY3+8 z`HRnz+d&NgD@9{T^y(U)^8Q2bqiHB zMQ3pCymx`cEq4=o{Zs5$-e3QuaJ1viZG85Y+d+_wjq}XGu$jgxU+N=3cX!tq4}|j& z^u{DhvgyT4)B1c9J@ zKb7@Q@LNUSC=>h#)cV6qRR7nv_;EddaVl!v{}!fLUT}qEu3otqwPh+OEh{@8?{x`C z0S|=VpgaSC-(-@nL4XOtxb(p_$~9)!2a5%qdvEz@kM7T^k7ju~*9z=9bNO$s(bhkF zvhzCb-#8h}+J+c1b92*_EaoND!PC!fJ|6FNaYukf(&C=PYe0BD`>!@qvS6K1_{h1o zj>!5fbA6cQhajg4lsY869zpfiuWq4SfEAyuR(Z2Zdm`f#W5u|*SCamO z{gJ{CWgEPw zS@}L>KD-k=xH!yjGPwwdYiv@RSOZjmk-~b)q}D?TkkGHM=Sezr-&;GQ{O0P31zP|A zZg4-@4rEIv|LfUhE`mA#o(*<%MDJV+%Wux&q{AuGDB$LR7|n2E=|nS{MhO}1gcN|; zJ*ECYoaS@F zWz5BBmns7THxjO4C8Pl1Txw!NiW|X?XBJfC%SQ~$3BgCIaP5CPPwTsW8~GoKQP%%B z@*21Y=Z-~Z)}UBsq0AI=mIlE3rxW;E5i1}Ld}|+hh4JyRo_P6xLE_7zXu4x?Pu|D!@tL-evC^JSTYo{UfEdBBn|p->SV>}Ldh-25k55+gIq9GhfG5#%`m0JFpdP>#^#V-&xRQ4%CI z!{hYno|)Zy50taJ0dj!ibxr)13~2Zo4O%Yr#f9dx|M}BYyC%AI8Cf5^)=3uUmuQf= z2>w^rQDI5=tHg-2Zr2*RbM|gp$_Amr=P-|8|J3~({=V5{Zfc&5cz1dCX}K@Ddd^)x z78~Gtv6BDv_)N^}!!e20Ocsa6Y5qq1->TMEM@`MGR9sv_#YM%`x@z6=v%l#{Dp`|s zOCq%x-)K2vLNTa z?@;`dBP?bw6MnS$W&@#QvJyau5g0%BrDyr`5Bi2;jtDqTRC!}5vY6!J7BCw8^sNsJ ztKVj6e6ox7Hl;vHBLHw>6i8(RNCc$rFj8bQSQNxd6T&UP$S^q^UceRZj$P*HEOW22 zrNpU%5uxSzW)}Obrq(S@X}dcqi~zxR-ah&ir9jHlqI8Yk*K#xp!~z!o77IM#9+`93 z*@Rnq_WrN1Q7V>;AcVbz?5$?V=sn8iXGs(onn_ld5VZ-6Xku5$l8SH#Evm?wY8=!x zE#>rl$|C?cboj_k_Me|pB$W{Wf-Wp5Zpa9sr$<;;w}2lT)!S#7n~;pJjL+A{Vg^`! zH+`OT!7h=N38qVv905|c{vfT1vCuqC*WaToa`srSC$>oy0Wf@bxCii+;qF+u2e9;m zeZzSt_?adh>kraW02CeAD1elxpA<1My9cm>$X-2pK189R?8hp3LehmVGifi4kc&~k z%Rtzbz&k^_)*qz3OJrCBy*pPx;aSqQ{=kuKQoYn9r^pX9O?#6Zz!3%bL3dY=o`=h) zDBOy63^GR!;MhjlOB($tscn@MnP;rnL60M?I)Ir&oku!Jr|&0vd@6MSqzLC#n$UAp zCebo&R|n8E{pb(6|GbMF!chePEG_yw_FsD<$7ZS(Lg8&}6d7X2mx;y8^nde<(ku zl@{}xLLpPuTDSdshyElhUPIOt03_Qgp;&=v^rxBj`(=_^87^JUo<4bc_ud0gx&SE@ zCQ$5pr~A*pOIakV3INWW?&;aJcmGrD<0jNEq*xgsk0taNN`*!fg*yY zzt1fH*C_{NH3l$~Oy{T~Z|QyK?W5Z%M`Sz=YKKwcRyBf^OK&FI91yCPzF-_B6cWNCUr*W+UfUkFU`3u7tB0nj-2r@mdXL3SIy5zJD5D&~MV_)EQHL1pX zptZqBa|X%9xOxPTF*-@H6uYxKQ7fEg4AU61+0mH}o>2gxTq4)wdY8wHrxZZ&jn1wv zUDsW=SMf>)Ye5;y;dly9DgaQUfotf+YJgY}jXa2F6+mE&28T(-2HD0_zP=T%D}*Hr z3TH3xJ@A(WnuazC)lioOuopxL^Y#Bn_tC#2kK_3fK*pGOkNwL0q;MSO=l8Jxj=Hs| zl?r*K00LG;?$E+PvY!-A5X6RbPVC9$Hu6#d1WFOoCT|5_kk<+zP>PToaCMf5-p^;j z7pw>c5U?2GAp7qyixUE*SVlhj`0-d#3LxM$1gu%A>-$NK3h35+n_2whUd`pF!-`Y@ z8MsFUL|LNktb<$51lXh$+3%!g| zfEZwgk2*o$b9)8W#N-YDS(4uq+p|jk7ZO4 zPxzVZ(WZr)^!SbW-#*eKf5!q1W?YCN)c9LRmWF76oioVJIc5Z{K~g9b3WY+UP$(1% gg+ifFC=?0uFT0js4#gz~bpQYW07*qoM6N<$f=mh+1ONa4 literal 0 HcmV?d00001 diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/images/documentation_dark.png b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/images/documentation_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..8692b53f96ea5ae6e2de86201ac31b65bc47b1d3 GIT binary patch literal 12021 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 T#jRS+>s6MTw$F@#Y-lJp23npXWb% zI2uwzac0P&^aaQ{o?~X7-+lcbk6MK|@ZE#a_3hE_lYJjYGqahEsdO^p_f6vtV;Aa2G?maJzRQdfQK97nIj|^XKj5POU zlp6Vqqdk3UmBFtn9ET3|MBhLDe#~d7UC-|Ooml+Rxv0gy`0?Jjs$f(c0|>z*@oVw!&h;B#%~zHK=kw`DOuz*( z3DM|g6^~y~e!pLsqDA)YQbV@~G*i{pH|TxQ7+_GeOG?huBImq#;jC(IX&qU!X6-SL z$MZ{JhGVJ%u%a2@55M<%_oee+zS^;_^H9gS^^r4QoYI8b)U{PLHQg)OGa}It4%-fK z01{kZAJI&JN^fm#*XAIZOlsn@zX9)|5e9^rI9J!^t(sx@Oc=nu?{#e+lA1w0auq*2 z^;^9?AfLBU7)(AdF1z(sc|1ps9_@*%6$+nPf%xH}p4isy-S6~YkN-Fn3dh!WMuS5` zgZhH+*x4Lvi^SH}*6V$2Nw44-os>AH;U<+<91RZLD6@?GsNvt>1@; zmqjgu@$u2DU2kk^(M)jd+D$F78%2Fj32}H1LGS?#MjWTEd-tYejr^9}JqLiQUQ8_{NjbEAFO&i+We0j9y22b|9vVv=wm?+g#d#IuaO_{z89Tes{y z@?U=TXYZ;Nf)$|w4jw!d3)MEfGm}pAOiYYLo153@i=7cK54Fl4QXB|WtG4!a>ej6r zYGPtsGXm0<$z+7!>-B!Mb#?j?XK;9UP#ENjmTF9ZZ3=?w`t>VX$~orhl}lQqG&i?u z4TEL?9Ai)?lD&TYMt!VkB>f)D$1%n%pe3-Vn2(g4CoJcjmfz6O(5R1*5LAVNp@{N$ z4?OYYGY4P($KM|P_;~NKhn36f1N=ZjIG<&`BTr+zMj{~s(k~&IzPP#J8(>?bBZc7H z*)KGKaqjv){YVoF)&9we53-t}T^NV`CdJv?E}`GJNOVLPh|fT~zzm$@j%W%r0M9R9 zz97;&q&1P-{&P-X-h(+$eEflaZMNZS@cqybIGAXk&5v!(Y6vu!*XKL7p`-IpmeWUA z77ais_w=(b|EX6gJmsi)p9@&+s8l4`*jz3a8o}6g@wT&m02sPGsE

-x|0f#BbM9 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 literal 0 HcmV?d00001 diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.tsx index fdf743d339a60..125d2af118d3f 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.tsx @@ -8,13 +8,14 @@ import React, { useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; import { useFooterStyles } from './onboarding_footer.styles'; -import { footerItems } from './footer_items'; +import { useFooterItems } from './footer_items'; import { trackOnboardingLinkClick } from '../../common/lib/telemetry'; import type { OnboardingFooterLinkItemId } from './constants'; import { TELEMETRY_FOOTER_LINK } from './constants'; export const OnboardingFooter = React.memo(() => { const styles = useFooterStyles(); + const footerItems = useFooterItems(); return ( {footerItems.map(({ id, title, icon, description, link }) => ( diff --git a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.test.tsx index 6bd427d547c86..68149045e798c 100644 --- a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.test.tsx @@ -10,7 +10,7 @@ import React from 'react'; import type { OverviewHostProps } from '../overview_host'; import type { OverviewNetworkProps } from '../overview_network'; -import { mockIndexPattern, TestProviders } from '../../../common/mock'; +import { mockDataViewSpec, TestProviders } from '../../../common/mock'; import { EventCounts } from '.'; @@ -24,7 +24,7 @@ describe('EventCounts', () => { filters: [], from, indexNames: [], - indexPattern: mockIndexPattern, + dataViewSpec: mockDataViewSpec, setQuery: jest.fn(), to, query: { diff --git a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx index 34692b8cc12d3..3f20d3365537f 100644 --- a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx @@ -8,8 +8,8 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React, { useMemo } from 'react'; -import type { DataViewBase, Filter, Query } from '@kbn/es-query'; -import { getEsQueryConfig } from '@kbn/data-plugin/common'; +import type { Filter, Query } from '@kbn/es-query'; +import { type DataViewSpec, getEsQueryConfig } from '@kbn/data-plugin/common'; import { ID as OverviewHostQueryId } from '../../containers/overview_host'; import { OverviewHost } from '../overview_host'; import { OverviewNetwork } from '../overview_network'; @@ -26,7 +26,7 @@ import { SecurityPageName } from '../../../../common/constants'; interface Props extends Pick { filters: Filter[]; indexNames: string[]; - indexPattern: DataViewBase; + dataViewSpec?: DataViewSpec; query: Query; } @@ -34,7 +34,7 @@ const EventCountsComponent: React.FC = ({ filters, from, indexNames, - indexPattern, + dataViewSpec, query, setQuery, to, @@ -45,22 +45,22 @@ const EventCountsComponent: React.FC = ({ () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - indexPattern, + dataViewSpec, queries: [query], filters: [...filters, ...fieldNameExistsFilter(SecurityPageName.hosts)], }), - [filters, indexPattern, query, uiSettings] + [dataViewSpec, filters, query, uiSettings] ); const [networkFilterQuery] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - indexPattern, + dataViewSpec, queries: [query], filters: [...filters, ...sourceOrDestinationIpExistsFilter], }), - [filters, indexPattern, uiSettings, query] + [uiSettings, dataViewSpec, query, filters] ); useInvalidFilterQuery({ diff --git a/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx b/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx index eb551d4ba20aa..a30ae72ed9b00 100644 --- a/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx @@ -9,9 +9,10 @@ import { Position } from '@elastic/charts'; import numeral from '@elastic/numeral'; import React, { useEffect, useMemo, useCallback } from 'react'; -import type { DataViewBase, Filter, Query } from '@kbn/es-query'; +import type { Filter, Query } from '@kbn/es-query'; import styled from 'styled-components'; import { EuiButton } from '@elastic/eui'; +import type { DataViewSpec } from '@kbn/data-plugin/common'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; import { DEFAULT_NUMBER_FORMAT, APP_UI_ID } from '../../../../common/constants'; import { SHOWING, UNIT } from '../../../common/components/events_viewer/translations'; @@ -46,7 +47,7 @@ interface Props extends Pick = ({ filters, from, headerChildren, - indexPattern, + dataViewSpec, onlyField, paddingSize, query, @@ -132,13 +133,13 @@ const EventsByDatasetComponent: React.FC = ({ if (filterQueryFromProps == null) { return convertToBuildEsQuery({ config: getEsQueryConfig(kibana.services.uiSettings), - indexPattern, + dataViewSpec, queries: [query], filters, }); } return [filterQueryFromProps]; - }, [filterQueryFromProps, kibana, indexPattern, query, filters]); + }, [filterQueryFromProps, kibana.services.uiSettings, dataViewSpec, query, filters]); useInvalidFilterQuery({ id: uniqueQueryId, diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx index 0450b922acb44..e70a0f8e51577 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx @@ -50,8 +50,7 @@ const OverviewComponent = () => { const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); const { from, deleteQuery, setQuery, to } = useGlobalTime(); - const { indicesExist, sourcererDataView, indexPattern, selectedPatterns } = - useSourcererDataView(); + const { indicesExist, sourcererDataView, selectedPatterns } = useSourcererDataView(); const endpointMetadataIndex = useMemo(() => { return [ENDPOINT_METADATA_INDEX]; @@ -114,7 +113,7 @@ const OverviewComponent = () => { deleteQuery={deleteQuery} filters={filters} from={from} - indexPattern={indexPattern} + dataViewSpec={sourcererDataView} query={query} queryType="overview" setQuery={setQuery} @@ -127,7 +126,7 @@ const OverviewComponent = () => { filters={filters} from={from} indexNames={selectedPatterns} - indexPattern={indexPattern} + dataViewSpec={sourcererDataView} query={query} setQuery={setQuery} to={to} diff --git a/x-pack/plugins/security_solution/public/sourcerer/components/alerts_sourcerer.test.tsx b/x-pack/plugins/security_solution/public/sourcerer/components/alerts_sourcerer.test.tsx index 60bbe58824e41..619f7e91eae82 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/components/alerts_sourcerer.test.tsx +++ b/x-pack/plugins/security_solution/public/sourcerer/components/alerts_sourcerer.test.tsx @@ -72,6 +72,7 @@ describe('sourcerer on alerts page or rules details page', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ ...sourcererDataView, indicesExist: true, + sourcererDataView: {}, }); render( diff --git a/x-pack/plugins/security_solution/public/sourcerer/components/index.tsx b/x-pack/plugins/security_solution/public/sourcerer/components/index.tsx index 8b45d96669793..ad5a939b69995 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/components/index.tsx +++ b/x-pack/plugins/security_solution/public/sourcerer/components/index.tsx @@ -152,8 +152,8 @@ export const Sourcerer = React.memo(({ scope: scopeId } const { indicesExist, loading, sourcererDataView } = useSourcererDataView(scopeId); const activePatterns = useMemo( - () => (sourcererDataView?.title || '')?.split(',').filter(Boolean) as string[], - [sourcererDataView?.title] + () => (sourcererDataView.title || '')?.split(',').filter(Boolean) as string[], + [sourcererDataView.title] ); const [missingPatterns, setMissingPatterns] = useState( diff --git a/x-pack/plugins/security_solution/public/sourcerer/components/sourcerer_integration.test.tsx b/x-pack/plugins/security_solution/public/sourcerer/components/sourcerer_integration.test.tsx index d43a3a47ed267..5f21a814da363 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/components/sourcerer_integration.test.tsx +++ b/x-pack/plugins/security_solution/public/sourcerer/components/sourcerer_integration.test.tsx @@ -72,6 +72,7 @@ const patternListNoSignals = sortWithExcludesAtEnd( const sourcererDataView = { indicesExist: true, loading: false, + sourcererDataView: {}, }; describe('Sourcerer integration tests', () => { diff --git a/x-pack/plugins/security_solution/public/sourcerer/components/timeline_sourcerer.test.tsx b/x-pack/plugins/security_solution/public/sourcerer/components/timeline_sourcerer.test.tsx index ff86241164631..35a26856f4930 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/components/timeline_sourcerer.test.tsx +++ b/x-pack/plugins/security_solution/public/sourcerer/components/timeline_sourcerer.test.tsx @@ -56,6 +56,7 @@ const { id } = mockGlobalState.sourcerer.defaultDataView; const sourcererDataView = { indicesExist: true, loading: false, + sourcererDataView: {}, }; describe('timeline sourcerer', () => { diff --git a/x-pack/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.test.ts b/x-pack/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.test.ts index 18e34ba2067a1..87345f80ef701 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.test.ts +++ b/x-pack/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.test.ts @@ -40,7 +40,7 @@ describe('useGetScopedSourcererDataView', () => { it('should return undefined when no spec is provided', () => { mockGetSourcererDataView.mockReturnValueOnce({ ...mockSourcererScope, - sourcererDataView: undefined, + sourcererDataView: {}, }); const { result } = renderHookCustom({ sourcererScope: SourcererScopeName.timeline }); expect(result.current).toBeUndefined(); @@ -48,7 +48,7 @@ describe('useGetScopedSourcererDataView', () => { it('should return undefined when no spec is provided and should update the return when spec is updated to correct value', () => { mockGetSourcererDataView.mockReturnValueOnce({ ...mockSourcererScope, - sourcererDataView: undefined, + sourcererDataView: {}, }); const { rerender, result } = renderHookCustom({ sourcererScope: SourcererScopeName.timeline }); expect(result.current).toBeUndefined(); diff --git a/x-pack/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.tsx b/x-pack/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.tsx index 869b9d68e27ac..52b5ca9717e8d 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.tsx +++ b/x-pack/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.tsx @@ -30,7 +30,7 @@ export const useGetScopedSourcererDataView = ({ const { sourcererDataView } = useSourcererDataView(sourcererScope); const dataView = useMemo(() => { - if (sourcererDataView) { + if (Object.keys(sourcererDataView).length) { return new DataView({ spec: sourcererDataView, fieldFormats }); } else { return undefined; diff --git a/x-pack/plugins/security_solution/public/sourcerer/containers/hooks.test.tsx b/x-pack/plugins/security_solution/public/sourcerer/containers/hooks.test.tsx index 8b0150efa6126..e712e780636e4 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/containers/hooks.test.tsx +++ b/x-pack/plugins/security_solution/public/sourcerer/containers/hooks.test.tsx @@ -698,7 +698,6 @@ describe('Sourcerer Hooks', () => { '-filebeat-*', '-packetbeat-*', ]); - expect(result.current.indexPattern).toHaveProperty('getName'); }); }); @@ -710,7 +709,7 @@ describe('Sourcerer Hooks', () => { } ); - expect(result.current.sourcererDataView?.title).toBe( + expect(result.current.sourcererDataView.title).toBe( 'apm-*-transaction*,auditbeat-*,endgame-*,filebeat-*,logs-*,packetbeat-*,traces-apm*,winlogbeat-*,-*elastic-cloud-logs-*' ); @@ -727,8 +726,8 @@ describe('Sourcerer Hooks', () => { await rerender(); - expect(result.current.sourcererDataView?.title).toBe(testPatterns.join(',')); - expect(result.current.sourcererDataView?.name).toBe(testPatterns.join(',')); + expect(result.current.sourcererDataView.title).toBe(testPatterns.join(',')); + expect(result.current.sourcererDataView.name).toBe(testPatterns.join(',')); }); }); }); diff --git a/x-pack/plugins/security_solution/public/sourcerer/containers/index.tsx b/x-pack/plugins/security_solution/public/sourcerer/containers/index.tsx index 9765a26e60b0e..9643e9272f8be 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/containers/index.tsx +++ b/x-pack/plugins/security_solution/public/sourcerer/containers/index.tsx @@ -7,6 +7,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; +import type { FieldSpec } from '@kbn/data-plugin/common'; import { sourcererSelectors } from '../store'; import type { SelectedDataView, SourcererDataView, RunTimeMappings } from '../store/model'; import { SourcererScopeName } from '../store/model'; @@ -56,8 +57,7 @@ export const useSourcererDataView = ( id: fetchIndexReturn.dataView?.id ?? null, loading: indexPatternsLoading, patternList: fetchIndexReturn.indexes, - indexFields: fetchIndexReturn.indexPatterns - .fields as SelectedDataView['indexPattern']['fields'], + indexFields: fetchIndexReturn.indexPatterns.fields as FieldSpec[], fields: fetchIndexReturn.dataView?.fields, }), [fetchIndexReturn, indexPatternsLoading] diff --git a/x-pack/plugins/security_solution/public/sourcerer/containers/mocks.ts b/x-pack/plugins/security_solution/public/sourcerer/containers/mocks.ts index 283f41bc8be67..4d331ebab65ff 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/containers/mocks.ts +++ b/x-pack/plugins/security_solution/public/sourcerer/containers/mocks.ts @@ -38,19 +38,6 @@ export const mockSourcererScope: SelectedDataView = { }, }, }, - indexPattern: { - fields: [ - { - aggregatable: false, - esTypes: undefined, - name: '_id', - searchable: true, - subType: undefined, - type: 'string', - }, - ], - title: mockPatterns.join(), - }, sourcererDataView: mockGlobalState.sourcerer.defaultDataView, selectedPatterns: mockPatterns, indicesExist: true, diff --git a/x-pack/plugins/security_solution/public/sourcerer/store/model.ts b/x-pack/plugins/security_solution/public/sourcerer/store/model.ts index 3b3f8c56b261c..807c74a9c3f8f 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/store/model.ts +++ b/x-pack/plugins/security_solution/public/sourcerer/store/model.ts @@ -9,7 +9,6 @@ import type { BrowserFields } from '@kbn/timelines-plugin/common'; import { EMPTY_BROWSER_FIELDS } from '@kbn/timelines-plugin/common'; import type { DataViewSpec } from '@kbn/data-views-plugin/public'; import type { RuntimeFieldSpec, RuntimePrimitiveTypes } from '@kbn/data-views-plugin/common'; -import type { SecuritySolutionDataViewBase } from '../../common/types'; /** Uniquely identifies a Sourcerer Scope */ export enum SourcererScopeName { @@ -88,11 +87,6 @@ export interface SelectedDataView { */ browserFields: BrowserFields; dataViewId: string | null; // null if legacy pre-8.0 timeline - /** - * @deprecated use sourcererDataView - * DataViewBase with enhanced index fields used in timelines - */ - indexPattern: SecuritySolutionDataViewBase; /** do the selected indices exist */ indicesExist: boolean; /** is an update being made to the data view */ @@ -103,7 +97,7 @@ export interface SelectedDataView { * Easier to add this additional data rather than * try to extend the SelectedDataView type from DataView. */ - sourcererDataView: DataViewSpec | undefined; + sourcererDataView: DataViewSpec; } /** diff --git a/x-pack/plugins/security_solution/public/timelines/components/modal/actions/open_timeline_button.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/modal/actions/open_timeline_button.test.tsx index e0a48cebf4209..ffa8f0b1bb0b0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/modal/actions/open_timeline_button.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/modal/actions/open_timeline_button.test.tsx @@ -62,7 +62,11 @@ describe('OpenTimelineButton', () => { it('should open the modal after clicking on the button', async () => { (useParams as jest.Mock).mockReturnValue({ tabName: TimelineTypeEnum.template }); (useStartTransaction as jest.Mock).mockReturnValue({ startTransaction: jest.fn() }); - (useSourcererDataView as jest.Mock).mockReturnValue({ dataViewId: '', selectedPatterns: [] }); + (useSourcererDataView as jest.Mock).mockReturnValue({ + dataViewId: '', + selectedPatterns: [], + sourcererDataView: {}, + }); (useTimelineStatus as jest.Mock).mockReturnValue({ timelineStatus: 'active', templateTimelineFilter: null, diff --git a/x-pack/plugins/security_solution/public/timelines/components/modal/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/modal/header/index.test.tsx index 228c6bc70584c..25eef44d1469c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/modal/header/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/modal/header/index.test.tsx @@ -59,6 +59,7 @@ describe('TimelineModalHeader', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ browserFields: {}, indexPattern: { fields: [], title: '' }, + sourcererDataView: {}, }); const { getByTestId, getByText } = renderTimelineModalHeader(); @@ -78,6 +79,7 @@ describe('TimelineModalHeader', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ browserFields: {}, indexPattern: { fields: [], title: '' }, + sourcererDataView: {}, }); (useKibana as jest.Mock).mockReturnValue({ services: { @@ -107,6 +109,7 @@ describe('TimelineModalHeader', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ browserFields: {}, indexPattern: { fields: [], title: '' }, + sourcererDataView: {}, }); const spy = jest.spyOn(timelineActions, 'showTimeline'); diff --git a/x-pack/plugins/security_solution/public/timelines/components/modal/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/modal/header/index.tsx index e30e0c2cf2a10..7eccb11a35312 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/modal/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/modal/header/index.tsx @@ -70,7 +70,7 @@ interface FlyoutHeaderPanelProps { export const TimelineModalHeader = React.memo( ({ timelineId, openToggleRef }) => { const dispatch = useDispatch(); - const { browserFields, indexPattern } = useSourcererDataView(SourcererScopeName.timeline); + const { browserFields, sourcererDataView } = useSourcererDataView(SourcererScopeName.timeline); const { cases, uiSettings } = useKibana().services; const esQueryConfig = useMemo(() => getEsQueryConfig(uiSettings), [uiSettings]); const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); @@ -88,13 +88,21 @@ export const TimelineModalHeader = React.memo( combineQueries({ config: esQueryConfig, dataProviders, - indexPattern, + indexPattern: sourcererDataView, browserFields, filters: filters ? filters : [], kqlQuery: kqlQueryObj, kqlMode, }), - [browserFields, dataProviders, esQueryConfig, filters, indexPattern, kqlMode, kqlQueryObj] + [ + browserFields, + dataProviders, + esQueryConfig, + filters, + kqlMode, + kqlQueryObj, + sourcererDataView, + ] ); const isInspectDisabled = !isDataInTimeline || combinedQueries?.filterQuery === undefined; diff --git a/x-pack/plugins/security_solution/public/timelines/components/notes/old_notes.tsx b/x-pack/plugins/security_solution/public/timelines/components/notes/old_notes.tsx index 71432267ac0da..09c45d887b373 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/notes/old_notes.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/notes/old_notes.tsx @@ -111,7 +111,7 @@ interface NotesTabContentProps { } /** - * Renders the "old" notes tab content. This should be removed when we remove the securitySolutionNotesEnabled feature flag + * Renders the "old" notes tab content. This should be removed when we remove the securitySolutionNotesDisabled feature flag */ export const OldNotes: React.FC = React.memo(({ timelineId }) => { const dispatch = useDispatch(); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx index 47d79c1ba71c3..dce963737fb5a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx @@ -32,7 +32,7 @@ interface KpiExpandedProps { } export const TimelineKpisContainer = ({ timelineId }: KpiExpandedProps) => { - const { browserFields, indexPattern, selectedPatterns } = useSourcererDataView( + const { browserFields, sourcererDataView, selectedPatterns } = useSourcererDataView( SourcererScopeName.timeline ); @@ -82,13 +82,13 @@ export const TimelineKpisContainer = ({ timelineId }: KpiExpandedProps) => { combineQueries({ config: esQueryConfig, dataProviders, - indexPattern, + indexPattern: sourcererDataView, browserFields, filters: filters ? filters : [], kqlQuery, kqlMode, }), - [browserFields, dataProviders, esQueryConfig, filters, indexPattern, kqlMode, kqlQuery] + [browserFields, dataProviders, esQueryConfig, filters, sourcererDataView, kqlMode, kqlQuery] ); const isBlankTimeline: boolean = useMemo( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx index 59373b5d790f5..54b5a4a9aae2f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx @@ -79,7 +79,7 @@ export const EqlQueryBarTimeline = memo(({ timelineId }: { timelineId: string }) const { loading: indexPatternsLoading, - indexPattern, + sourcererDataView, selectedPatterns, } = useSourcererDataView(SourcererScopeName.timeline); @@ -123,27 +123,23 @@ export const EqlQueryBarTimeline = memo(({ timelineId }: { timelineId: string }) const prevEqlQuery = useRef(''); - const optionsData = useMemo( - () => - isEmpty(indexPattern.fields) - ? { - keywordFields: [], - dateFields: [], - nonDateFields: [], - } - : { - keywordFields: indexPattern.fields - .filter((f) => f.esTypes?.includes('keyword')) - .map((f) => ({ label: f.name })), - dateFields: indexPattern.fields - .filter((f) => f.type === 'date') - .map((f) => ({ label: f.name })), - nonDateFields: indexPattern.fields - .filter((f) => f.type !== 'date') - .map((f) => ({ label: f.name })), - }, - [indexPattern] - ); + const optionsData = useMemo(() => { + const fields = Object.values(sourcererDataView.fields || {}); + + return isEmpty(fields) + ? { + keywordFields: [], + dateFields: [], + nonDateFields: [], + } + : { + keywordFields: fields + .filter((f) => f.esTypes?.includes('keyword')) + .map((f) => ({ label: f.name })), + dateFields: fields.filter((f) => f.type === 'date').map((f) => ({ label: f.name })), + nonDateFields: fields.filter((f) => f.type !== 'date').map((f) => ({ label: f.name })), + }; + }, [sourcererDataView]); useEffect(() => { const { index: indexField } = getFields(); @@ -206,7 +202,7 @@ export const EqlQueryBarTimeline = memo(({ timelineId }: { timelineId: string }) idAria: 'timelineEqlQueryBar', isDisabled: indexPatternsLoading, isLoading: indexPatternsLoading, - indexPattern, + indexPattern: sourcererDataView, dataTestSubj: 'timelineEqlQueryBar', }} config={{ diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx index 3ac5ba0cb5ac8..1bb39aa4796d2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx @@ -17,7 +17,10 @@ import { InputsModelId } from '../../../../common/store/inputs/constants'; import { useSourcererDataView } from '../../../../sourcerer/containers'; import { SourcererScopeName } from '../../../../sourcerer/store/model'; -import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery'; +import { + convertKueryToElasticSearchQuery, + dataViewSpecToViewBase, +} from '../../../../common/lib/kuery'; import type { KqlMode } from '../../../store/model'; import { useSavedQueryServices } from '../../../../common/utils/saved_query_services'; import type { DispatchUpdateReduxTime } from '../../../../common/components/super_date_picker'; @@ -107,7 +110,7 @@ export const QueryBarTimeline = memo( const [dateRangeTo, setDateRangTo] = useState( toStr != null ? toStr : new Date(to).toISOString() ); - const { browserFields, indexPattern } = useSourcererDataView(SourcererScopeName.timeline); + const { browserFields, sourcererDataView } = useSourcererDataView(SourcererScopeName.timeline); const [savedQuery, setSavedQuery] = useState(undefined); const [filterQueryConverted, setFilterQueryConverted] = useState({ query: filterQuery != null ? filterQuery.expression : '', @@ -115,6 +118,11 @@ export const QueryBarTimeline = memo( }); const queryBarFilters = useMemo(() => getNonDropAreaFilters(filters), [filters]); + const indexPattern = useMemo( + () => dataViewSpecToViewBase(sourcererDataView), + [sourcererDataView] + ); + const [dataProvidersDsl, setDataProvidersDsl] = useState( convertKueryToElasticSearchQuery(buildGlobalQuery(dataProviders, browserFields), indexPattern) ); @@ -259,6 +267,10 @@ export const QueryBarTimeline = memo( [dataProvidersDsl, savedQueryId, savedQueryServices] ); + if (!indexPattern) { + return null; + } + return ( ( services: { data }, } = useKibana(); - const { indexPattern } = useSourcererDataView(SourcererScopeName.timeline); + const { sourcererDataView } = useSourcererDataView(SourcererScopeName.timeline); const getIsDataProviderVisible = useMemo( () => timelineSelectors.dataProviderVisibilitySelector(), @@ -86,25 +86,22 @@ const StatefulSearchOrFilterComponent = React.memo( useEffect(() => { let dv: DataView; - if (isDataView(indexPattern)) { - setDataView(indexPattern); - } else if (!filterQuery) { - const createDataView = async () => { - try { - dv = await data.dataViews.create({ title: indexPattern.title }); - setDataView(dv); - } catch (error) { - addError(error, { title: i18n.ERROR_PROCESSING_INDEX_PATTERNS }); - } - }; - createDataView(); - } + const createDataView = async () => { + try { + dv = await data.dataViews.create(sourcererDataView); + setDataView(dv); + } catch (error) { + addError(error, { title: i18n.ERROR_PROCESSING_INDEX_PATTERNS }); + } + }; + createDataView(); + return () => { if (dv?.id) { data.dataViews.clearInstanceCache(dv?.id); } }; - }, [data.dataViews, indexPattern, filterQuery, addError]); + }, [data.dataViews, filterQuery, addError, sourcererDataView]); const arrDataView = useMemo(() => (dataView != null ? [dataView] : []), [dataView]); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx index e41d9017d49be..602d2353f342f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx @@ -110,15 +110,15 @@ export const EqlTabContentComponent: React.FC = ({ indexNames: selectedPatterns, language: 'eql', limit: sampleSize, - runtimeMappings: sourcererDataView?.runtimeFieldMap as RunTimeMappings, + runtimeMappings: sourcererDataView.runtimeFieldMap as RunTimeMappings, skip: !canQueryTimeline(), startDate: start, timerangeKind, }); const { openFlyout } = useExpandableFlyoutApi(); - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const { @@ -139,7 +139,7 @@ export const EqlTabContentComponent: React.FC = ({ const onToggleShowNotes = useCallback( (eventId?: string) => { const indexName = selectedPatterns.join(','); - if (eventId && securitySolutionNotesEnabled) { + if (eventId && !securitySolutionNotesDisabled) { openFlyout({ right: { id: DocumentDetailsRightPanelKey, @@ -177,7 +177,7 @@ export const EqlTabContentComponent: React.FC = ({ }, [ openFlyout, - securitySolutionNotesEnabled, + securitySolutionNotesDisabled, selectedPatterns, telemetry, timelineId, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/index.tsx index 601a31d97fa5c..40d4f939b13fd 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/index.tsx @@ -253,8 +253,8 @@ const TabsContentComponent: React.FC = ({ selectTimelineESQLSavedSearchId(state, timelineId) ); - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const [visualizationInFlyoutEnabled] = useUiSetting$( @@ -320,16 +320,20 @@ const TabsContentComponent: React.FC = ({ } }, [fetchNotes, isTimelineSaved]); - const numberOfNotesNewSystem = useSelector((state: State) => + const notesNewSystem = useSelector((state: State) => selectSortedNotesBySavedObjectId(state, { savedObjectId: timelineSavedObjectId, sort: { field: 'created', direction: 'asc' }, }) ); + const numberOfNotesNewSystem = useMemo( + () => notesNewSystem.length + (isEmpty(timelineDescription) ? 0 : 1), + [notesNewSystem, timelineDescription] + ); const numberOfNotes = useMemo( - () => (securitySolutionNotesEnabled ? numberOfNotesNewSystem.length : numberOfNotesOldSystem), - [numberOfNotesNewSystem, numberOfNotesOldSystem, securitySolutionNotesEnabled] + () => (securitySolutionNotesDisabled ? numberOfNotesOldSystem : numberOfNotesNewSystem), + [numberOfNotesNewSystem, numberOfNotesOldSystem, securitySolutionNotesDisabled] ); const setActiveTab = useCallback( @@ -446,9 +450,7 @@ const TabsContentComponent: React.FC = ({ > {i18n.NOTES_TAB} {showTimeline && numberOfNotes > 0 && timelineType === TimelineTypeEnum.default && ( -

- {numberOfNotes} -
+ {numberOfNotes} )} = ({ {showTimeline && numberOfPinnedEvents > 0 && timelineType === TimelineTypeEnum.default && ( -
- {numberOfPinnedEvents} -
+ {numberOfPinnedEvents} )}
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.test.tsx index 4de3728e2290f..452dc1620b946 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.test.tsx @@ -70,14 +70,14 @@ const mockGlobalStateWithUnSavedTimeline: State = { describe('NotesTabContentComponent', () => { beforeEach(() => { jest.clearAllMocks(); - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false); (useUserPrivileges as jest.Mock).mockReturnValue({ kibanaSecuritySolutionsPrivileges: { crud: true }, }); }); it('should show the old note system', () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false); + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); const { getByTestId, queryByTestId } = render( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.tsx index aad74f15d4f62..58522d32dd55f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.tsx @@ -71,7 +71,7 @@ interface NotesTabContentProps { /** * Renders the notes tab content. - * At this time the component support the old notes system and the new notes system (via the securitySolutionNotesEnabled feature flag). + * At this time the component support the old notes system and the new notes system (via the securitySolutionNotesDisabled feature flag). * The old notes system is deprecated and will be removed in the future. * In both cases, the component fetches the notes for the timeline and renders: * - the timeline description @@ -86,8 +86,8 @@ const NotesTabContentComponent: React.FC = React.memo(({ t const { kibanaSecuritySolutionsPrivileges } = useUserPrivileges(); const canCreateNotes = kibanaSecuritySolutionsPrivileges.crud; - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const getScrollToTop = useMemo(() => getScrollToTopSelector(), []); @@ -180,7 +180,9 @@ const NotesTabContentComponent: React.FC = React.memo(({ t - {securitySolutionNotesEnabled ? ( + {securitySolutionNotesDisabled ? ( + + ) : ( {timelineDescription} @@ -213,8 +215,6 @@ const NotesTabContentComponent: React.FC = React.memo(({ t - ) : ( - )} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx index 959d6a3b52c3e..a12f3bb9fd530 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx @@ -138,7 +138,7 @@ export const PinnedTabContentComponent: React.FC = ({ fields: timelineQueryFields, limit: itemsPerPage, filterQuery, - runtimeMappings: sourcererDataView?.runtimeFieldMap as RunTimeMappings, + runtimeMappings: sourcererDataView.runtimeFieldMap as RunTimeMappings, skip: filterQuery === '', startDate: '', sort: timelineQuerySortField, @@ -146,8 +146,8 @@ export const PinnedTabContentComponent: React.FC = ({ }); const { openFlyout } = useExpandableFlyoutApi(); - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const { @@ -168,7 +168,7 @@ export const PinnedTabContentComponent: React.FC = ({ const onToggleShowNotes = useCallback( (eventId?: string) => { const indexName = selectedPatterns.join(','); - if (eventId && securitySolutionNotesEnabled) { + if (eventId && !securitySolutionNotesDisabled) { openFlyout({ right: { id: DocumentDetailsRightPanelKey, @@ -206,7 +206,7 @@ export const PinnedTabContentComponent: React.FC = ({ }, [ openFlyout, - securitySolutionNotesEnabled, + securitySolutionNotesDisabled, selectedPatterns, telemetry, timelineId, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx index 493fdb4bc603e..70afec0d73135 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx @@ -882,12 +882,12 @@ describe('query tab with unified timeline', () => { }); describe('Leading actions - notes', () => { - describe('securitySolutionNotesEnabled = true', () => { + describe('securitySolutionNotesDisabled = false', () => { beforeEach(() => { (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( jest.fn((feature: keyof ExperimentalFeatures) => { - if (feature === 'securitySolutionNotesEnabled') { - return true; + if (feature === 'securitySolutionNotesDisabled') { + return false; } return allowedExperimentalValues[feature]; }) @@ -937,12 +937,12 @@ describe('query tab with unified timeline', () => { ); }); - describe('securitySolutionNotesEnabled = false', () => { + describe('securitySolutionNotesDisabled = true', () => { beforeEach(() => { (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( jest.fn((feature: keyof ExperimentalFeatures) => { - if (feature === 'securitySolutionNotesEnabled') { - return false; + if (feature === 'securitySolutionNotesDisabled') { + return true; } return allowedExperimentalValues[feature]; }) @@ -1071,12 +1071,12 @@ describe('query tab with unified timeline', () => { }); describe('Leading actions - pin', () => { - describe('securitySolutionNotesEnabled = true', () => { + describe('securitySolutionNotesDisabled = false', () => { beforeEach(() => { (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( jest.fn((feature: keyof ExperimentalFeatures) => { - if (feature === 'securitySolutionNotesEnabled') { - return true; + if (feature === 'securitySolutionNotesDisabled') { + return false; } return allowedExperimentalValues[feature]; }) @@ -1155,12 +1155,12 @@ describe('query tab with unified timeline', () => { ); }); - describe('securitySolutionNotesEnabled = false', () => { + describe('securitySolutionNotesDisabled = true', () => { beforeEach(() => { (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( jest.fn((feature: keyof ExperimentalFeatures) => { - if (feature === 'securitySolutionNotesEnabled') { - return false; + if (feature === 'securitySolutionNotesDisabled') { + return true; } return allowedExperimentalValues[feature]; }) diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx index 478c13db7de73..8ea1db39a3618 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx @@ -86,7 +86,6 @@ export const QueryTabContentComponent: React.FC = ({ browserFields, dataViewId, loading: loadingSourcerer, - indexPattern, // important to get selectedPatterns from useSourcererDataView // in order to include the exclude filters in the search that are not stored in the timeline selectedPatterns, @@ -119,13 +118,13 @@ export const QueryTabContentComponent: React.FC = ({ return combineQueries({ config: esQueryConfig, dataProviders, - indexPattern, + indexPattern: sourcererDataView, browserFields, filters, kqlQuery, kqlMode, }); - }, [esQueryConfig, dataProviders, indexPattern, browserFields, filters, kqlQuery, kqlMode]); + }, [esQueryConfig, dataProviders, sourcererDataView, browserFields, filters, kqlQuery, kqlMode]); useInvalidFilterQuery({ id: timelineId, @@ -177,7 +176,7 @@ export const QueryTabContentComponent: React.FC = ({ indexNames: selectedPatterns, language: kqlQuery.language, limit: sampleSize, - runtimeMappings: sourcererDataView?.runtimeFieldMap as RunTimeMappings, + runtimeMappings: sourcererDataView.runtimeFieldMap as RunTimeMappings, skip: !canQueryTimeline, sort: timelineQuerySortField, startDate: start, @@ -185,8 +184,8 @@ export const QueryTabContentComponent: React.FC = ({ }); const { openFlyout } = useExpandableFlyoutApi(); - const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( - 'securitySolutionNotesEnabled' + const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( + 'securitySolutionNotesDisabled' ); const { @@ -207,7 +206,7 @@ export const QueryTabContentComponent: React.FC = ({ const onToggleShowNotes = useCallback( (eventId?: string) => { const indexName = selectedPatterns.join(','); - if (eventId && securitySolutionNotesEnabled) { + if (eventId && !securitySolutionNotesDisabled) { openFlyout({ right: { id: DocumentDetailsRightPanelKey, @@ -245,7 +244,7 @@ export const QueryTabContentComponent: React.FC = ({ }, [ openFlyout, - securitySolutionNotesEnabled, + securitySolutionNotesDisabled, selectedPatterns, telemetry, timelineId, diff --git a/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.test.tsx b/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.test.tsx index 43a0eab5a5d49..ee7dfc19d59f5 100644 --- a/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.test.tsx @@ -39,6 +39,7 @@ describe('TimelinesPage', () => { it('should render landing page if no indicesExist', () => { (useSourcererDataView as unknown as jest.Mock).mockReturnValue({ indicesExist: false, + sourcererDataView: {}, }); (useKibana as unknown as jest.Mock).mockReturnValue({}); @@ -52,6 +53,7 @@ describe('TimelinesPage', () => { it('should show the correct elements if user has crud', () => { (useSourcererDataView as unknown as jest.Mock).mockReturnValue({ indicesExist: true, + sourcererDataView: {}, }); (useKibana as unknown as jest.Mock).mockReturnValue({ services: { diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts index 92c13a521ed2c..a07823194fa69 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts @@ -21,10 +21,12 @@ import type { GetAgentsResponse, GetInfoResponse, GetOneAgentPolicyResponse, + GetOnePackagePolicyResponse, GetPackagePoliciesRequest, GetPackagePoliciesResponse, PackagePolicy, PostFleetSetupResponse, + UpdatePackagePolicyResponse, } from '@kbn/fleet-plugin/common'; import { AGENT_API_ROUTES, @@ -39,6 +41,7 @@ import { PACKAGE_POLICY_API_ROUTES, PACKAGE_POLICY_SAVED_OBJECT_TYPE, SETUP_API_ROUTE, + packagePolicyRouteService, } from '@kbn/fleet-plugin/common'; import type { ToolingLog } from '@kbn/tooling-log'; import type { KbnClient } from '@kbn/test'; @@ -57,11 +60,14 @@ import type { GetEnrollmentAPIKeysResponse, GetOutputsResponse, PostAgentUnenrollResponse, + UpdateAgentPolicyRequest, + UpdateAgentPolicyResponse, } from '@kbn/fleet-plugin/common/types'; import semver from 'semver'; import axios from 'axios'; import { userInfo } from 'os'; import pRetry from 'p-retry'; +import { getPolicyDataForUpdate } from '../../../common/endpoint/service/policy'; import { fetchActiveSpace } from './spaces'; import { fetchKibanaStatus } from '../../../common/endpoint/utils/kibana_status'; import { isFleetServerRunning } from './fleet_server/fleet_server_services'; @@ -76,6 +82,7 @@ import { } from '../../../common/endpoint/data_loaders/utils'; import { catchAxiosErrorFormatAndThrow } from '../../../common/endpoint/format_axios_error'; import { FleetAgentGenerator } from '../../../common/endpoint/data_generators/fleet_agent_generator'; +import type { PolicyData } from '../../../common/endpoint/types'; const fleetGenerator = new FleetAgentGenerator(); const CURRENT_USERNAME = userInfo().username.toLowerCase(); @@ -101,6 +108,39 @@ export const randomAgentPolicyName = (() => { */ const isValidArtifactVersion = (version: string) => !!version.match(/^\d+\.\d+\.\d+(-SNAPSHOT)?$/); +const getAgentPolicyDataForUpdate = ( + agentPolicy: AgentPolicy +): UpdateAgentPolicyRequest['body'] => { + return pick(agentPolicy, [ + 'advanced_settings', + 'agent_features', + 'data_output_id', + 'description', + 'download_source_id', + 'fleet_server_host_id', + 'global_data_tags', + 'has_fleet_server', + 'id', + 'inactivity_timeout', + 'is_default', + 'is_default_fleet_server', + 'is_managed', + 'is_protected', + 'keep_monitoring_alive', + 'monitoring_diagnostics', + 'monitoring_enabled', + 'monitoring_http', + 'monitoring_output_id', + 'monitoring_pprof_enabled', + 'name', + 'namespace', + 'overrides', + 'space_ids', + 'supports_agentless', + 'unenroll_timeout', + ]) as UpdateAgentPolicyRequest['body']; +}; + export const checkInFleetAgent = async ( esClient: Client, agentId: string, @@ -1369,3 +1409,93 @@ export const enableFleetSpaceAwareness = memoize(async (kbnClient: KbnClient): P }) .catch(catchAxiosErrorFormatAndThrow); }); + +/** + * Fetches a single integratino policy by id + * @param kbnClient + * @param policyId + */ +export const fetchIntegrationPolicy = async ( + kbnClient: KbnClient, + policyId: string +): Promise => { + return kbnClient + .request({ + path: packagePolicyRouteService.getInfoPath(policyId), + method: 'GET', + headers: { 'elastic-api-version': '2023-10-31' }, + }) + .catch(catchAxiosErrorFormatAndThrow) + .then((response) => response.data.item); +}; + +/** + * Update a fleet integration policy (aka: package policy) + * @param kbnClient + */ +export const updateIntegrationPolicy = async ( + kbnClient: KbnClient, + /** The Integration policy id */ + id: string, + policyData: Partial, + /** If set to `true`, then `policyData` can be a partial set of updates and not the full policy data */ + patch: boolean = false +): Promise => { + let fullPolicyData = policyData; + + if (patch) { + const currentSavedPolicy = await fetchIntegrationPolicy(kbnClient, id); + fullPolicyData = getPolicyDataForUpdate(currentSavedPolicy as PolicyData); + Object.assign(fullPolicyData, policyData); + } + + return kbnClient + .request({ + path: packagePolicyRouteService.getUpdatePath(id), + method: 'PUT', + body: fullPolicyData, + headers: { 'elastic-api-version': '2023-10-31' }, + }) + .catch(catchAxiosErrorFormatAndThrow) + .then((response) => response.data.item); +}; + +/** + * Updates a Fleet agent policy + * @param kbnClient + * @param id + * @param policyData + * @param patch + */ +export const updateAgentPolicy = async ( + kbnClient: KbnClient, + /** Fleet Agent Policy ID */ + id: string, + /** The updated agent policy data. Could be a `partial` update if `patch` arguments below is true */ + policyData: Partial, + /** + * If set to `true`, the `policyData` provided on input will first be merged with the latest version + * of the policy and then the updated applied + */ + patch: boolean = false +): Promise => { + let fullPolicyData = policyData; + + if (patch) { + const currentSavedPolicy = await fetchAgentPolicy(kbnClient, id); + + fullPolicyData = getAgentPolicyDataForUpdate(currentSavedPolicy); + delete fullPolicyData.id; + Object.assign(fullPolicyData, policyData); + } + + return kbnClient + .request({ + path: agentPolicyRouteService.getUpdatePath(id), + method: 'PUT', + body: fullPolicyData, + headers: { 'elastic-api-version': '2023-10-31' }, + }) + .catch(catchAxiosErrorFormatAndThrow) + .then((response) => response.data.item); +}; diff --git a/x-pack/plugins/security_solution/server/assistant/tools/esql/nl_to_esql_tool.ts b/x-pack/plugins/security_solution/server/assistant/tools/esql/nl_to_esql_tool.ts index 1205fb03b0458..11ca8ffd94edd 100644 --- a/x-pack/plugins/security_solution/server/assistant/tools/esql/nl_to_esql_tool.ts +++ b/x-pack/plugins/security_solution/server/assistant/tools/esql/nl_to_esql_tool.ts @@ -49,11 +49,7 @@ export const NL_TO_ESQL_TOOL: AssistantTool = { connectorId, input: question, ...(isOssModel ? { functionCalling: 'simulated' } : {}), - logger: { - debug: (source) => { - logger.debug(typeof source === 'function' ? source() : source); - }, - }, + logger, }) ); }; diff --git a/x-pack/plugins/security_solution/server/config.mock.ts b/x-pack/plugins/security_solution/server/config.mock.ts index 1d0d31e9387e2..5fb3dc7b3b48d 100644 --- a/x-pack/plugins/security_solution/server/config.mock.ts +++ b/x-pack/plugins/security_solution/server/config.mock.ts @@ -10,6 +10,7 @@ import type { ExperimentalFeatures } from '../common/experimental_features'; import { parseExperimentalConfigValue } from '../common/experimental_features'; import { getDefaultConfigSettings } from '../common/config_settings'; import type { ConfigType } from './config'; +import { duration } from 'moment'; export const createMockConfig = (): ConfigType => { const enableExperimental: Array = ['responseActionUploadEnabled']; @@ -45,6 +46,8 @@ export const createMockConfig = (): ConfigType => { }, }, entityStore: { + frequency: duration('1m'), + syncDelay: duration('5m'), developer: { pipelineDebugMode: false, }, diff --git a/x-pack/plugins/security_solution/server/config.ts b/x-pack/plugins/security_solution/server/config.ts index 1265aa4c25749..240e452cd44bc 100644 --- a/x-pack/plugins/security_solution/server/config.ts +++ b/x-pack/plugins/security_solution/server/config.ts @@ -176,6 +176,8 @@ export const configSchema = schema.object({ }), }), entityStore: schema.object({ + syncDelay: schema.duration({ defaultValue: '60s' }), + frequency: schema.duration({ defaultValue: '60s' }), developer: schema.object({ pipelineDebugMode: schema.boolean({ defaultValue: false }), }), diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index 192fb6059325a..1afa24ebbd529 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -31,10 +31,12 @@ import type { ResponseActionsClient } from './services'; import { getResponseActionsClient, NormalizedExternalConnectorClient } from './services'; import { getAgentPolicyCreateCallback, + getAgentPolicyPostUpdateCallback, getAgentPolicyUpdateCallback, getPackagePolicyCreateCallback, getPackagePolicyDeleteCallback, getPackagePolicyPostCreateCallback, + getPackagePolicyPostUpdateCallback, getPackagePolicyUpdateCallback, } from '../fleet_integration/fleet_integration'; import type { ManifestManager } from './services/artifacts'; @@ -117,7 +119,8 @@ export class EndpointAppContextService { this.savedObjectsFactoryService = savedObjectsFactory; this.fleetServicesFactory = new EndpointFleetServicesFactory( dependencies.fleetStartServices, - savedObjectsFactory + savedObjectsFactory, + this.createLogger('endpointFleetServices') ); this.registerFleetExtensions(); @@ -169,6 +172,8 @@ export class EndpointAppContextService { getAgentPolicyUpdateCallback(logger, productFeaturesService) ); + registerFleetCallback('agentPolicyPostUpdate', getAgentPolicyPostUpdateCallback(this)); + registerFleetCallback( 'packagePolicyCreate', getPackagePolicyCreateCallback( @@ -183,10 +188,7 @@ export class EndpointAppContextService { ) ); - registerFleetCallback( - 'packagePolicyPostCreate', - getPackagePolicyPostCreateCallback(logger, exceptionListsClient) - ); + registerFleetCallback('packagePolicyPostCreate', getPackagePolicyPostCreateCallback(this)); registerFleetCallback( 'packagePolicyUpdate', @@ -201,6 +203,8 @@ export class EndpointAppContextService { ) ); + registerFleetCallback('packagePolicyPostUpdate', getPackagePolicyPostUpdateCallback(this)); + registerFleetCallback( 'packagePolicyPostDelete', getPackagePolicyDeleteCallback(exceptionListsClient, soClient) @@ -218,6 +222,27 @@ export class EndpointAppContextService { return this.savedObjectsFactoryService; } + /** + * Is kibana running in serverless mode + */ + public isServerless(): boolean { + if (!this.setupDependencies) { + throw new EndpointAppContentServicesNotSetUpError(); + } + + // TODO:PT check what this returns when running locally with kibana in serverless emulation + + return Boolean(this.setupDependencies.cloud.isServerlessEnabled); + } + + public getInternalEsClient(): ElasticsearchClient { + if (!this.startDependencies?.esClient) { + throw new EndpointAppContentServicesNotStartedError(); + } + + return this.startDependencies.esClient; + } + private getFleetAuthzService(): FleetStartContract['authz'] { if (!this.startDependencies?.fleetStartServices) { throw new EndpointAppContentServicesNotStartedError(); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/simple_mem_cache.test.ts b/x-pack/plugins/security_solution/server/endpoint/lib/simple_mem_cache.test.ts similarity index 92% rename from x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/simple_mem_cache.test.ts rename to x-pack/plugins/security_solution/server/endpoint/lib/simple_mem_cache.test.ts index f351e2e40d5be..27ba3bdf23945 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/simple_mem_cache.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/simple_mem_cache.test.ts @@ -51,6 +51,13 @@ describe('SimpleMemCache class', () => { expect(cache.get(key)).toEqual(undefined); }); + it('should delete all entries from cache', () => { + cache.set(key, value); + cache.deleteAll(); + + expect(cache.get(key)).toEqual(undefined); + }); + it('should cleanup expired cache entries', () => { const key2 = 'myKey'; cache.set(key, value); // Default ttl of 10s diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/simple_mem_cache.ts b/x-pack/plugins/security_solution/server/endpoint/lib/simple_mem_cache.ts similarity index 95% rename from x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/simple_mem_cache.ts rename to x-pack/plugins/security_solution/server/endpoint/lib/simple_mem_cache.ts index fc355bf6c3797..a65a1ee6be71a 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/simple_mem_cache.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/simple_mem_cache.ts @@ -19,6 +19,8 @@ export interface SimpleMemCacheInterface { get(key: any): TValue | undefined; /** Delete a piece of data from cache */ delete(key: any): void; + /** Delete all cached entries */ + deleteAll(): void; /** Clean up the cache by removing all expired entries */ cleanup(): void; } @@ -79,6 +81,10 @@ export class SimpleMemCache implements SimpleMemCacheInterface { this.cache.delete(key); } + public deleteAll(): void { + this.cache.clear(); + } + public cleanup(): void { for (const [cacheKey, cacheData] of this.cache.entries()) { if (this.isExpired(cacheData)) { diff --git a/x-pack/plugins/security_solution/server/endpoint/migrations/ensure_indices_exists_for_policies.test.ts b/x-pack/plugins/security_solution/server/endpoint/migrations/ensure_indices_exists_for_policies.test.ts new file mode 100644 index 0000000000000..b167997b68dda --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/migrations/ensure_indices_exists_for_policies.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createMockEndpointAppContextService } from '../mocks'; +import { ensureIndicesExistsForPolicies } from './ensure_indices_exists_for_policies'; +import { createPolicyDataStreamsIfNeeded as _createPolicyDataStreamsIfNeeded } from '../../fleet_integration/handlers/create_policy_datastreams'; + +jest.mock('../../fleet_integration/handlers/create_policy_datastreams'); +const createPolicyDataStreamsIfNeededMock = + _createPolicyDataStreamsIfNeeded as unknown as jest.Mock; + +describe('Ensure indices exists for policies migration', () => { + let endpointAppContextServicesMock: ReturnType; + + beforeEach(() => { + endpointAppContextServicesMock = createMockEndpointAppContextService(); + + ( + endpointAppContextServicesMock.getInternalFleetServices().packagePolicy.listIds as jest.Mock + ).mockResolvedValue({ + items: ['foo-1', 'foo-2', 'foo-3'], + }); + }); + + it('should query fleet looking for all endpoint integration policies', async () => { + const fleetServicesMock = endpointAppContextServicesMock.getInternalFleetServices(); + await ensureIndicesExistsForPolicies(endpointAppContextServicesMock); + + expect(fleetServicesMock.packagePolicy.listIds).toHaveBeenCalledWith(expect.anything(), { + kuery: fleetServicesMock.endpointPolicyKuery, + perPage: 10000, + }); + }); + + it('should call createPolicyDataStreamsIfNeeded() with list of existing policies', async () => { + await ensureIndicesExistsForPolicies(endpointAppContextServicesMock); + + expect(createPolicyDataStreamsIfNeededMock).toHaveBeenCalledWith({ + endpointServices: endpointAppContextServicesMock, + endpointPolicyIds: ['foo-1', 'foo-2', 'foo-3'], + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/migrations/ensure_indices_exists_for_policies.ts b/x-pack/plugins/security_solution/server/endpoint/migrations/ensure_indices_exists_for_policies.ts new file mode 100644 index 0000000000000..778a333fc4818 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/migrations/ensure_indices_exists_for_policies.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createPolicyDataStreamsIfNeeded } from '../../fleet_integration/handlers/create_policy_datastreams'; +import type { EndpointAppContextService } from '../endpoint_app_context_services'; + +export const ensureIndicesExistsForPolicies = async ( + endpointServices: EndpointAppContextService +): Promise => { + const logger = endpointServices.createLogger('startupPolicyIndicesChecker'); + + const fleetServices = endpointServices.getInternalFleetServices(); + const soClient = fleetServices.savedObjects.createInternalUnscopedSoClient(); + const endpointPoliciesIds = await fleetServices.packagePolicy.listIds(soClient, { + kuery: fleetServices.endpointPolicyKuery, + perPage: 10000, + }); + + logger.info( + `Checking to ensure [${endpointPoliciesIds.items.length}] endpoint policies have backing indices` + ); + + await createPolicyDataStreamsIfNeeded({ + endpointServices, + endpointPolicyIds: endpointPoliciesIds.items, + }); +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks/mocks.ts index 5ab221b7bfc07..03c2e7e857e10 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks/mocks.ts @@ -76,6 +76,7 @@ import type { EndpointAuthz } from '../../../common/endpoint/types/authz'; import { createLicenseServiceMock } from '../../../common/license/mocks'; import { createFeatureUsageServiceMock } from '../services/feature_usage/mocks'; import { createProductFeaturesServiceMock } from '../../lib/product_features_service/mocks'; +import type { ConfigType } from '../../config'; /** * Creates a mocked EndpointAppContext. @@ -144,6 +145,8 @@ export const createMockEndpointAppContextService = ( return responseActionsClientMock.create(); }), savedObjects: createSavedObjectsClientFactoryMock({ savedObjectsServiceStart }).service, + isServerless: jest.fn().mockReturnValue(false), + getInternalEsClient: jest.fn().mockReturnValue(esClient), } as unknown as jest.Mocked; }; @@ -161,11 +164,15 @@ export const createMockEndpointAppContextServiceSetupContract = }; }; +type CreateMockEndpointAppContextServiceStartContractType = Omit< + DeeplyMockedKeys, + 'config' +> & { config: ConfigType }; // DeeplyMockedKeys doesn't support moment.Duration /** * Creates a mocked input contract for the `EndpointAppContextService#start()` method */ export const createMockEndpointAppContextServiceStartContract = - (): DeeplyMockedKeys => { + (): CreateMockEndpointAppContextServiceStartContractType => { const config = createMockConfig(); const logger = loggingSystemMock.create().get('mock_endpoint_app_context'); @@ -187,7 +194,7 @@ export const createMockEndpointAppContextServiceStartContract = securityMock.createMockAuthenticatedUser({ roles: ['superuser'] }) ); - const startContract: DeeplyMockedKeys = { + const startContract: CreateMockEndpointAppContextServiceStartContractType = { security, config, productFeaturesService: createProductFeaturesServiceMock( diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts index 0411e4a9c8f65..7a8f14b6e9a8e 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts @@ -20,7 +20,7 @@ import { } from '../../../../../lib/telemetry/event_based/events'; import { NotFoundError } from '../../../../errors'; import { fetchActionRequestById } from '../../utils/fetch_action_request_by_id'; -import { SimpleMemCache } from './simple_mem_cache'; +import { SimpleMemCache } from '../../../../lib/simple_mem_cache'; import { fetchActionResponses, fetchEndpointActionResponses, @@ -581,6 +581,10 @@ export abstract class ResponseActionsClientImpl implements ResponseActionsClient >( options: ResponseActionsClientWriteActionResponseToEndpointIndexOptions ): Promise> { + // FIXME:PT need to ensure we use a index below that has the proper `namespace` when agent type is Endpoint + // Background: Endpoint responses require that the document be written to an index that has the + // correct `namespace` as defined by the Integration/Agent policy and that logic is not currently implemented. + const doc = this.buildActionResponseEsDoc(options); this.log.debug(() => `Writing response action response:\n${stringify(doc)}`); @@ -594,7 +598,7 @@ export abstract class ResponseActionsClientImpl implements ResponseActionsClient .catch((err) => { throw new ResponseActionsClientError( `Failed to create action response document: ${err.message}`, - err.statusCode ?? 500, + 500, err ); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.mocks.ts b/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.mocks.ts index 91119ea3df5fb..302528b024f76 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.mocks.ts @@ -8,6 +8,8 @@ import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; import type { FleetStartContract } from '@kbn/fleet-plugin/server'; import { createFleetStartContractMock } from '@kbn/fleet-plugin/server/mocks'; +import type { MockedLogger } from '@kbn/logging-mocks'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import type { SavedObjectsClientFactory } from '../saved_objects'; import type { EndpointFleetServicesFactoryInterface, @@ -24,35 +26,41 @@ export interface EndpointFleetServicesFactoryInterfaceMocked asInternalUser: () => EndpointInternalFleetServicesInterfaceMocked; } -interface CreateEndpointFleetServicesFactoryMockOptions { +export interface CreateEndpointFleetServicesFactoryMockOptions { fleetDependencies: DeeplyMockedKeys; savedObjects: SavedObjectsClientFactory; + logger: MockedLogger; } -export const createEndpointFleetServicesFactoryMock = ( - dependencies: Partial = {} -): { +export interface CreateEndpointFleetServicesFactoryResponse { service: EndpointFleetServicesFactoryInterfaceMocked; dependencies: CreateEndpointFleetServicesFactoryMockOptions; -} => { +} + +export const createEndpointFleetServicesFactoryMock = ( + dependencies: Partial = {} +): CreateEndpointFleetServicesFactoryResponse => { const { fleetDependencies = createFleetStartContractMock(), savedObjects = createSavedObjectsClientFactoryMock().service, + logger = loggingSystemMock.createLogger(), } = dependencies; const serviceFactoryMock = new EndpointFleetServicesFactory( fleetDependencies, - savedObjects + savedObjects, + logger ) as unknown as EndpointFleetServicesFactoryInterfaceMocked; const fleetInternalServicesMocked = serviceFactoryMock.asInternalUser(); jest.spyOn(fleetInternalServicesMocked, 'ensureInCurrentSpace'); + jest.spyOn(fleetInternalServicesMocked, 'getPolicyNamespace'); const asInternalUserSpy = jest.spyOn(serviceFactoryMock, 'asInternalUser'); asInternalUserSpy.mockReturnValue(fleetInternalServicesMocked); return { service: serviceFactoryMock, - dependencies: { fleetDependencies, savedObjects }, + dependencies: { fleetDependencies, savedObjects, logger }, }; }; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.test.ts new file mode 100644 index 0000000000000..c1f7ca004e03e --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.test.ts @@ -0,0 +1,181 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + CreateEndpointFleetServicesFactoryResponse, + EndpointInternalFleetServicesInterfaceMocked, +} from './endpoint_fleet_services_factory.mocks'; +import { createEndpointFleetServicesFactoryMock } from './endpoint_fleet_services_factory.mocks'; +import { AgentNotFoundError } from '@kbn/fleet-plugin/server'; +import { NotFoundError } from '../../errors'; +import type { AgentPolicy, PackagePolicy } from '@kbn/fleet-plugin/common'; +import { FleetAgentPolicyGenerator } from '../../../../common/endpoint/data_generators/fleet_agent_policy_generator'; +import { FleetPackagePolicyGenerator } from '../../../../common/endpoint/data_generators/fleet_package_policy_generator'; + +describe('EndpointServiceFactory', () => { + let fleetServicesMock: EndpointInternalFleetServicesInterfaceMocked; + let fleetServicesFactoryMock: CreateEndpointFleetServicesFactoryResponse; + + beforeEach(() => { + fleetServicesFactoryMock = createEndpointFleetServicesFactoryMock(); + fleetServicesMock = fleetServicesFactoryMock.service.asInternalUser(); + }); + + it('should return fleet services when `asInternalUser()` is invoked', () => { + expect(Object.keys(fleetServicesMock)).toEqual([ + 'agent', + 'agentPolicy', + 'packages', + 'packagePolicy', + 'savedObjects', + 'endpointPolicyKuery', + 'ensureInCurrentSpace', + 'getPolicyNamespace', + ]); + }); + + describe('#ensureInCurentSpace()', () => { + it('should check agent ids', async () => { + await expect( + fleetServicesMock.ensureInCurrentSpace({ agentIds: ['123'] }) + ).resolves.toBeUndefined(); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentService.asInternalUser.getByIds + ).toHaveBeenCalledWith(['123']); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentPolicyService.getByIds + ).not.toHaveBeenCalled(); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.packagePolicyService.getByIDs + ).not.toHaveBeenCalled(); + }); + + it('should check integration policy ids', async () => { + await expect( + fleetServicesMock.ensureInCurrentSpace({ integrationPolicyIds: ['123'] }) + ).resolves.toBeUndefined(); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentService.asInternalUser.getByIds + ).not.toHaveBeenCalled(); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentPolicyService.getByIds + ).not.toHaveBeenCalled(); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.packagePolicyService.getByIDs + ).toHaveBeenCalledWith(expect.anything(), ['123']); + }); + + it('should check agent policy ids', async () => { + await expect( + fleetServicesMock.ensureInCurrentSpace({ agentPolicyIds: ['123'] }) + ).resolves.toBeUndefined(); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentService.asInternalUser.getByIds + ).not.toHaveBeenCalled(); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentPolicyService.getByIds + ).toHaveBeenCalledWith(expect.anything(), ['123']); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.packagePolicyService.getByIDs + ).not.toHaveBeenCalled(); + }); + + it('should check agent Ids, integration policy id and agent policy ids', async () => { + await expect( + fleetServicesMock.ensureInCurrentSpace({ + integrationPolicyIds: ['123'], + agentIds: ['123'], + agentPolicyIds: ['123'], + }) + ).resolves.toBeUndefined(); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentService.asInternalUser.getByIds + ).toHaveBeenCalledWith(['123']); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentPolicyService.getByIds + ).toHaveBeenCalledWith(expect.anything(), ['123']); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.packagePolicyService.getByIDs + ).toHaveBeenCalledWith(expect.anything(), ['123']); + }); + + it('should throw error any of the data is not visible in current space', async () => { + fleetServicesFactoryMock.dependencies.fleetDependencies.agentService.asInternalUser.getByIds.mockImplementation( + async () => { + throw new AgentNotFoundError('not found mock'); + } + ); + await expect( + fleetServicesMock.ensureInCurrentSpace({ + integrationPolicyIds: ['123'], + agentIds: ['123'], + agentPolicyIds: ['123'], + }) + ).rejects.toThrowError(NotFoundError); + }); + }); + + describe('#getPolicyNamespace()', () => { + let integrationPolicy: PackagePolicy; + let agentPolicy1: AgentPolicy; + let agentPolicy2: AgentPolicy; + + beforeEach(() => { + const agentPolicyGenerator = new FleetAgentPolicyGenerator('seed'); + const integrationPolicyGenerator = new FleetPackagePolicyGenerator('seed'); + + agentPolicy1 = agentPolicyGenerator.generate({ namespace: 'foo1' }); + agentPolicy2 = agentPolicyGenerator.generate({ namespace: 'foo2' }); + integrationPolicy = integrationPolicyGenerator.generate({ + namespace: undefined, + policy_ids: [agentPolicy1.id, agentPolicy2.id], + }); + + fleetServicesFactoryMock.dependencies.fleetDependencies.packagePolicyService.getByIDs.mockResolvedValue( + [integrationPolicy] + ); + fleetServicesFactoryMock.dependencies.fleetDependencies.agentPolicyService.getByIds.mockResolvedValue( + [agentPolicy1, agentPolicy2] + ); + }); + + it('should return namespace from agent policies if integration policy does not have one defined', async () => { + await expect( + fleetServicesMock.getPolicyNamespace({ + integrationPolicies: [integrationPolicy.id], + }) + ).resolves.toEqual({ + integrationPolicy: { + [integrationPolicy.id]: ['foo1', 'foo2'], + }, + }); + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentPolicyService.getByIds + ).toHaveBeenCalledWith(expect.anything(), [agentPolicy1.id, agentPolicy2.id]); + }); + + it('should return namespace from integration policy if defined', async () => { + integrationPolicy.namespace = 'bar'; + + await expect( + fleetServicesMock.getPolicyNamespace({ + integrationPolicies: [integrationPolicy.id], + }) + ).resolves.toEqual({ + integrationPolicy: { + [integrationPolicy.id]: ['bar'], + }, + }); + + // The agentPolicy sevice should not have been called because the package policy has + // a namespace id, so no need. + expect( + fleetServicesFactoryMock.dependencies.fleetDependencies.agentPolicyService.getByIds + ).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.ts b/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.ts index 50e2006272218..bbda061b3ceff 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.ts @@ -13,12 +13,14 @@ import type { PackageClient, } from '@kbn/fleet-plugin/server'; import { AgentNotFoundError } from '@kbn/fleet-plugin/server'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common'; -import type { SavedObjectsClientContract } from '@kbn/core/server'; +import type { AgentPolicy } from '@kbn/fleet-plugin/common'; +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, type PackagePolicy } from '@kbn/fleet-plugin/common'; +import type { Logger, SavedObjectsClientContract } from '@kbn/core/server'; import { AgentPolicyNotFoundError, PackagePolicyNotFoundError, } from '@kbn/fleet-plugin/server/errors'; +import { stringify } from '../../utils/stringify'; import { NotFoundError } from '../../errors'; import type { SavedObjectsClientFactory } from '../saved_objects'; @@ -37,14 +39,21 @@ export interface EndpointFleetServicesInterface { * Will check the data provided to ensure it is visible for the current space. Supports * several types of data (ex. integration policies, agent policies, etc) */ - ensureInCurrentSpace(options: EnsureInCurrentSpaceOptions): Promise; -} + ensureInCurrentSpace( + options: Pick< + CheckInCurrentSpaceOptions, + 'agentIds' | 'integrationPolicyIds' | 'agentPolicyIds' + > + ): Promise; -type EnsureInCurrentSpaceOptions = Partial<{ - agentIds: string[]; - agentPolicyIds: string[]; - integrationPolicyIds: string[]; -}>; + /** + * Retrieves the `namespace` assigned to Endpoint Integration Policies + * @param options + */ + getPolicyNamespace( + options: Pick + ): Promise; +} export interface EndpointInternalFleetServicesInterface extends EndpointFleetServicesInterface { savedObjects: SavedObjectsClientFactory; @@ -60,7 +69,8 @@ export interface EndpointFleetServicesFactoryInterface { export class EndpointFleetServicesFactory implements EndpointFleetServicesFactoryInterface { constructor( private readonly fleetDependencies: FleetStartContract, - private readonly savedObjects: SavedObjectsClientFactory + private readonly savedObjects: SavedObjectsClientFactory, + private readonly logger: Logger ) {} asInternalUser(spaceId?: string): EndpointInternalFleetServicesInterface { @@ -85,31 +95,31 @@ export class EndpointFleetServicesFactory implements EndpointFleetServicesFactor if (!soClient) { soClient = this.savedObjects.createInternalScopedSoClient({ spaceId }); } + return checkInCurrentSpace({ + soClient, + agentService: agent, + agentPolicyService: agentPolicy, + packagePolicyService: packagePolicy, + integrationPolicyIds, + agentPolicyIds, + agentIds, + }); + }; + + const getPolicyNamespace: EndpointFleetServicesInterface['getPolicyNamespace'] = async ( + options + ) => { + if (!soClient) { + soClient = this.savedObjects.createInternalScopedSoClient({ spaceId }); + } - const handlePromiseErrors = (err: Error): never => { - // We wrap the error with our own Error class so that the API can property return a 404 - if ( - err instanceof AgentNotFoundError || - err instanceof AgentPolicyNotFoundError || - err instanceof PackagePolicyNotFoundError - ) { - throw new NotFoundError(err.message, err); - } - - throw err; - }; - - await Promise.all([ - agentIds.length ? agent.getByIds(agentIds).catch(handlePromiseErrors) : null, - - agentPolicyIds.length - ? agentPolicy.getByIds(soClient, agentPolicyIds).catch(handlePromiseErrors) - : null, - - integrationPolicyIds.length - ? packagePolicy.getByIDs(soClient, integrationPolicyIds).catch(handlePromiseErrors) - : null, - ]); + return fetchEndpointPolicyNamespace({ + ...options, + soClient, + logger: this.logger, + packagePolicyService: packagePolicy, + agentPolicyService: agentPolicy, + }); }; return { @@ -123,6 +133,144 @@ export class EndpointFleetServicesFactory implements EndpointFleetServicesFactor endpointPolicyKuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: "endpoint"`, ensureInCurrentSpace, + getPolicyNamespace, }; } } + +interface CheckInCurrentSpaceOptions { + soClient: SavedObjectsClientContract; + agentService: AgentClient; + agentPolicyService: AgentPolicyServiceInterface; + packagePolicyService: PackagePolicyClient; + agentIds?: string[]; + agentPolicyIds?: string[]; + integrationPolicyIds?: string[]; +} + +/** + * Checks if data provided (integration policies, agent policies and/or agentIds) are visible in + * current space + * + * @param soClient + * @param agentService + * @param agentPolicyService + * @param packagePolicyService + * @param integrationPolicyIds + * @param agentPolicyIds + * @param agentIds + * + * @throws NotFoundError + */ +const checkInCurrentSpace = async ({ + soClient, + agentService, + agentPolicyService, + packagePolicyService, + integrationPolicyIds = [], + agentPolicyIds = [], + agentIds = [], +}: CheckInCurrentSpaceOptions): Promise => { + const handlePromiseErrors = (err: Error): never => { + // We wrap the error with our own Error class so that the API can property return a 404 + if ( + err instanceof AgentNotFoundError || + err instanceof AgentPolicyNotFoundError || + err instanceof PackagePolicyNotFoundError + ) { + throw new NotFoundError(err.message, err); + } + + throw err; + }; + + await Promise.all([ + agentIds.length ? agentService.getByIds(agentIds).catch(handlePromiseErrors) : null, + + agentPolicyIds.length + ? agentPolicyService.getByIds(soClient, agentPolicyIds).catch(handlePromiseErrors) + : null, + + integrationPolicyIds.length + ? packagePolicyService.getByIDs(soClient, integrationPolicyIds).catch(handlePromiseErrors) + : null, + ]); +}; + +interface FetchEndpointPolicyNamespaceOptions { + logger: Logger; + soClient: SavedObjectsClientContract; + packagePolicyService: PackagePolicyClient; + agentPolicyService: AgentPolicyServiceInterface; + /** A list of integration policies IDs */ + integrationPolicies: string[]; +} + +export interface FetchEndpointPolicyNamespaceResponse { + integrationPolicy: Record; +} + +const fetchEndpointPolicyNamespace = async ({ + logger, + soClient, + packagePolicyService, + agentPolicyService, + integrationPolicies, +}: FetchEndpointPolicyNamespaceOptions): Promise => { + const response: FetchEndpointPolicyNamespaceResponse = { + integrationPolicy: {}, + }; + const agentPolicyIdsToRetrieve = new Set(); + const retrievedIntegrationPolicies: Record = {}; + const retrievedAgentPolicies: Record = {}; + + if (integrationPolicies.length > 0) { + logger.debug( + () => `Retrieving package policies from fleet for:\n${stringify(integrationPolicies)}` + ); + const packagePolicies = + (await packagePolicyService.getByIDs(soClient, integrationPolicies)) ?? []; + + logger.trace(() => `Fleet package policies retrieved:\n${stringify(packagePolicies)}`); + + for (const packagePolicy of packagePolicies) { + retrievedIntegrationPolicies[packagePolicy.id] = packagePolicy; + + // Integration policy does not have an explicit namespace, which means it + // inherits it from the associated agent policies, so lets retrieve those + if (!packagePolicy.namespace) { + packagePolicy.policy_ids.forEach((agentPolicyId) => { + agentPolicyIdsToRetrieve.add(agentPolicyId); + }); + } + } + } + + if (agentPolicyIdsToRetrieve.size > 0) { + const ids = Array.from(agentPolicyIdsToRetrieve); + + logger.debug(() => `Retrieving agent policies from fleet for:\n${stringify(ids)}`); + + const agentPolicies = await agentPolicyService.getByIds(soClient, ids); + + logger.trace(() => `Fleet agent policies retrieved:\n${stringify(agentPolicies)}`); + + for (const agentPolicy of agentPolicies) { + retrievedAgentPolicies[agentPolicy.id] = agentPolicy; + } + } + + for (const integrationPolicyId of integrationPolicies) { + const integrationPolicyNamespace = retrievedIntegrationPolicies[integrationPolicyId].namespace; + + response.integrationPolicy[integrationPolicyId] = integrationPolicyNamespace + ? [integrationPolicyNamespace] + : retrievedIntegrationPolicies[integrationPolicyId].policy_ids.map((agentPolicyId) => { + return retrievedAgentPolicies[agentPolicyId].namespace; + }); + } + + logger.debug(() => `Policy namespaces:\n${stringify(response)}`); + + return response; +}; diff --git a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts index 6accb29354ee4..80337d1a927b8 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts @@ -7,6 +7,7 @@ import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import type { ElasticsearchClientMock } from '@kbn/core/server/mocks'; import { elasticsearchServiceMock, httpServerMock, @@ -38,7 +39,10 @@ import { import { requestContextMock } from '../lib/detection_engine/routes/__mocks__'; import { requestContextFactoryMock } from '../request_context_factory.mock'; import type { EndpointAppContextServiceStartContract } from '../endpoint/endpoint_app_context_services'; -import { createMockEndpointAppContextServiceStartContract } from '../endpoint/mocks'; +import { + createMockEndpointAppContextService, + createMockEndpointAppContextServiceStartContract, +} from '../endpoint/mocks'; import { licenseMock } from '@kbn/licensing-plugin/common/licensing.mock'; import { LicenseService } from '../../common/license'; import { Subject } from 'rxjs'; @@ -73,16 +77,30 @@ import { createProductFeaturesServiceMock } from '../lib/product_features_servic import * as moment from 'moment'; import type { PostAgentPolicyCreateCallback, + PostPackagePolicyPostCreateCallback, PutPackagePolicyUpdateCallback, } from '@kbn/fleet-plugin/server/types'; import type { EndpointMetadataService } from '../endpoint/services/metadata'; import { createEndpointMetadataServiceTestContextMock } from '../endpoint/services/metadata/mocks'; +import { createPolicyDataStreamsIfNeeded as _createPolicyDataStreamsIfNeeded } from './handlers/create_policy_datastreams'; jest.mock('uuid', () => ({ v4: (): string => 'NEW_UUID', })); -describe('ingest_integration tests ', () => { +jest.mock('./handlers/create_policy_datastreams', () => { + const actualModule = jest.requireActual('./handlers/create_policy_datastreams'); + + return { + ...actualModule, + createPolicyDataStreamsIfNeeded: jest.fn(async () => {}), + }; +}); + +const createPolicyDataStreamsIfNeededMock = + _createPolicyDataStreamsIfNeeded as unknown as jest.Mock; + +describe('Fleet integrations', () => { let endpointAppContextStartContract: EndpointAppContextServiceStartContract; let req: KibanaRequest; let ctx: ReturnType; @@ -350,10 +368,20 @@ describe('ingest_integration tests ', () => { }); describe('package policy post create callback', () => { - const soClient = savedObjectsClientMock.create(); - const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - const callback = getPackagePolicyPostCreateCallback(logger, exceptionListClient); - const policyConfig = generator.generatePolicyPackagePolicy() as PackagePolicy; + let soClient: ReturnType; + let esClient: ElasticsearchClientMock; + let callback: PostPackagePolicyPostCreateCallback; + let policyConfig: PackagePolicy; + let endpointAppContextServiceMock: ReturnType; + + beforeEach(() => { + soClient = savedObjectsClientMock.create(); + esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + endpointAppContextServiceMock = createMockEndpointAppContextService(); + endpointAppContextServiceMock.getExceptionListsClient.mockReturnValue(exceptionListClient); + callback = getPackagePolicyPostCreateCallback(endpointAppContextServiceMock); + policyConfig = generator.generatePolicyPackagePolicy() as PackagePolicy; + }); it('should create the Endpoint Event Filters List and add the correct Event Filters List Item attached to the policy given nonInteractiveSession parameter on integration config eventFilters', async () => { const integrationConfig = { @@ -374,11 +402,11 @@ describe('ingest_integration tests ', () => { req ); - expect(await exceptionListClient.createExceptionList).toHaveBeenCalledWith( + expect(exceptionListClient.createExceptionList).toHaveBeenCalledWith( expect.objectContaining({ listId: ENDPOINT_EVENT_FILTERS_LIST_ID }) ); - expect(await exceptionListClient.createExceptionListItem).toHaveBeenCalledWith( + expect(exceptionListClient.createExceptionListItem).toHaveBeenCalledWith( expect.objectContaining({ listId: ENDPOINT_EVENT_FILTERS_LIST_ID, tags: [`policy:${postCreatedPolicyConfig.id}`], @@ -413,14 +441,20 @@ describe('ingest_integration tests ', () => { req ); - expect(await exceptionListClient.createExceptionList).not.toHaveBeenCalled(); + expect(exceptionListClient.createExceptionList).not.toHaveBeenCalled(); - expect(await exceptionListClient.createExceptionListItem).not.toHaveBeenCalled(); + expect(exceptionListClient.createExceptionListItem).not.toHaveBeenCalled(); expect(postCreatedPolicyConfig.inputs[0]!.config!.integration_config.value).toEqual( integrationConfig ); }); + + it('should call `createPolicyDatastreamsIfNeeded`', async () => { + await callback(policyConfig, soClient, esClient, requestContextMock.convertContext(ctx), req); + + expect(createPolicyDataStreamsIfNeededMock).toHaveBeenCalled(); + }); }); describe('agent policy update callback', () => { diff --git a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts index 71c935e720511..54f1ce8cc7e01 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts @@ -27,8 +27,13 @@ import type { InfoResponse } from '@elastic/elasticsearch/lib/api/types'; import { ProductFeatureSecurityKey } from '@kbn/security-solution-features/keys'; import type { PostAgentPolicyCreateCallback, + PostAgentPolicyPostUpdateCallback, PostAgentPolicyUpdateCallback, + PutPackagePolicyPostUpdateCallback, } from '@kbn/fleet-plugin/server/types'; +import type { EndpointInternalFleetServicesInterface } from '../endpoint/services/fleet'; +import type { EndpointAppContextService } from '../endpoint/endpoint_app_context_services'; +import { createPolicyDataStreamsIfNeeded } from './handlers/create_policy_datastreams'; import { updateAntivirusRegistrationEnabled } from '../../common/endpoint/utils/update_antivirus_registration_enabled'; import { validatePolicyAgainstProductFeatures } from './handlers/validate_policy_against_product_features'; import { validateEndpointPackagePolicy } from './handlers/validate_endpoint_package_policy'; @@ -62,6 +67,32 @@ const isEndpointPackagePolicy = ( return packagePolicy.package?.name === 'endpoint'; }; +const getEndpointPolicyForAgentPolicy = async ( + fleetServices: EndpointInternalFleetServicesInterface, + agentPolicy: AgentPolicy +): Promise => { + let agentPolicyIntegrations: PackagePolicy[] | undefined = agentPolicy.package_policies; + + if (!agentPolicyIntegrations) { + const fullAgentPolicy = await fleetServices.agentPolicy.get( + fleetServices.savedObjects.createInternalScopedSoClient(), + agentPolicy.id, + true + ); + agentPolicyIntegrations = fullAgentPolicy?.package_policies ?? []; + } + + if (Array.isArray(agentPolicyIntegrations)) { + for (const integrationPolicy of agentPolicyIntegrations) { + if (isEndpointPackagePolicy(integrationPolicy)) { + return integrationPolicy; + } + } + } + + return undefined; +}; + const shouldUpdateMetaValues = ( endpointPackagePolicy: PolicyConfig, currentLicenseType: string, @@ -279,16 +310,47 @@ export const getPackagePolicyUpdateCallback = ( }; }; +export const getPackagePolicyPostUpdateCallback = ( + endpointServices: EndpointAppContextService +): PutPackagePolicyPostUpdateCallback => { + const logger = endpointServices.createLogger('endpointPackagePolicyPostUpdate'); + + return async (packagePolicy) => { + if (!isEndpointPackagePolicy(packagePolicy)) { + return packagePolicy; + } + + logger.debug(`Processing endpoint integration policy (post update): ${packagePolicy.id}`); + + // The check below will run in the background - we don't need to wait for it + createPolicyDataStreamsIfNeeded({ + endpointServices, + endpointPolicyIds: [packagePolicy.id], + }).catch(() => {}); // to silence @typescript-eslint/no-floating-promises + + return packagePolicy; + }; +}; + export const getPackagePolicyPostCreateCallback = ( - logger: Logger, - exceptionsClient: ExceptionListClient | undefined + endpointServices: EndpointAppContextService ): PostPackagePolicyPostCreateCallback => { + const logger = endpointServices.createLogger('endpointPolicyPostCreate'); + const exceptionsClient = endpointServices.getExceptionListsClient(); + return async (packagePolicy: PackagePolicy): Promise => { // We only care about Endpoint package policies if (!exceptionsClient || !isEndpointPackagePolicy(packagePolicy)) { return packagePolicy; } + // Check and create internal datastreams for this policy if needed. + // NOTE: we don't need for it to complete here, thus no `await`. + createPolicyDataStreamsIfNeeded({ + endpointServices, + endpointPolicyIds: [packagePolicy.id], + }).catch(() => {}); // to silence @typescript-eslint/no-floating-promises + const integrationConfig = packagePolicy?.inputs[0]?.config?.integration_config; if (integrationConfig && integrationConfig?.value?.eventFilters !== undefined) { @@ -353,6 +415,31 @@ export const getAgentPolicyUpdateCallback = ( }; }; +export const getAgentPolicyPostUpdateCallback = ( + endpointServices: EndpointAppContextService +): PostAgentPolicyPostUpdateCallback => { + const logger = endpointServices.createLogger('endpointPolicyPostUpdate'); + + return async (agentPolicy) => { + const fleetServices = endpointServices.getInternalFleetServices(); + const endpointPolicy = await getEndpointPolicyForAgentPolicy(fleetServices, agentPolicy); + + if (!endpointPolicy) { + return agentPolicy; + } + + logger.debug(`Processing post-update to Fleet agent policy: [${agentPolicy.id}]`); + + // We don't need to `await` for this function to execute. It can be done in the background + createPolicyDataStreamsIfNeeded({ + endpointServices, + endpointPolicyIds: [endpointPolicy.id], + }).catch(() => {}); // to silence @typescript-eslint/no-floating-promises + + return agentPolicy; + }; +}; + export const getPackagePolicyDeleteCallback = ( exceptionsClient: ExceptionListClient | undefined, savedObjectsClient: SavedObjectsClientContract | undefined diff --git a/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_policy_datastreams.test.ts b/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_policy_datastreams.test.ts new file mode 100644 index 0000000000000..0efaa5516a6f9 --- /dev/null +++ b/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_policy_datastreams.test.ts @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createMockEndpointAppContextService } from '../../endpoint/mocks'; +import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import type { FetchEndpointPolicyNamespaceResponse } from '../../endpoint/services/fleet'; +import { createPolicyDataStreamsIfNeeded } from './create_policy_datastreams'; + +describe('createPolicyDataStreamsIfNeeded()', () => { + let endpointServicesMock: ReturnType; + let esClientMock: ElasticsearchClientMock; + let policyNamespacesMock: FetchEndpointPolicyNamespaceResponse; + + beforeEach(() => { + endpointServicesMock = createMockEndpointAppContextService(); + + esClientMock = endpointServicesMock.getInternalEsClient() as ElasticsearchClientMock; + esClientMock.indices.exists.mockResolvedValue(false); + + policyNamespacesMock = { integrationPolicy: { '123': ['foo1', 'foo2'] } }; + ( + endpointServicesMock.getInternalFleetServices().getPolicyNamespace as jest.Mock + ).mockResolvedValue(policyNamespacesMock); + }); + + afterEach(() => { + createPolicyDataStreamsIfNeeded.cache.deleteAll(); + }); + + it('should create datastreams if they do not exist', async () => { + await createPolicyDataStreamsIfNeeded({ + endpointServices: endpointServicesMock, + endpointPolicyIds: ['123'], + }); + + expect(esClientMock.indices.createDataStream).toHaveBeenCalledTimes(4); + [ + '.logs-endpoint.diagnostic.collection-foo1', + '.logs-endpoint.diagnostic.collection-foo2', + '.logs-endpoint.action.responses-foo1', + '.logs-endpoint.action.responses-foo2', + ].forEach((indexName) => { + expect(esClientMock.indices.createDataStream).toHaveBeenCalledWith({ + name: indexName, + }); + }); + }); + + it('should not create datastream if they already exist', async () => { + esClientMock.indices.exists.mockImplementation(async (options) => { + return ( + options.index === '.logs-endpoint.action.responses-foo1' || + options.index === '.logs-endpoint.diagnostic.collection-foo1' + ); + }); + + await createPolicyDataStreamsIfNeeded({ + endpointServices: endpointServicesMock, + endpointPolicyIds: ['123'], + }); + + expect(esClientMock.indices.createDataStream).toHaveBeenCalledTimes(2); + ['.logs-endpoint.diagnostic.collection-foo2', '.logs-endpoint.action.responses-foo2'].forEach( + (indexName) => { + expect(esClientMock.indices.createDataStream).toHaveBeenCalledWith({ + name: indexName, + }); + } + ); + }); + + it('should create heartbeat index when running in serverless', async () => { + (endpointServicesMock.isServerless as jest.Mock).mockReturnValue(true); + await createPolicyDataStreamsIfNeeded({ + endpointServices: endpointServicesMock, + endpointPolicyIds: ['123'], + }); + + expect(esClientMock.indices.createDataStream).toHaveBeenCalledTimes(6); + [ + '.logs-endpoint.diagnostic.collection-foo1', + '.logs-endpoint.diagnostic.collection-foo2', + '.logs-endpoint.action.responses-foo1', + '.logs-endpoint.action.responses-foo2', + '.logs-endpoint.heartbeat-foo1', + '.logs-endpoint.heartbeat-foo2', + ].forEach((indexName) => { + expect(esClientMock.indices.createDataStream).toHaveBeenCalledWith({ + name: indexName, + }); + }); + }); + + it('should not call ES if index existence was already checked', async () => { + createPolicyDataStreamsIfNeeded.cache.set('.logs-endpoint.action.responses-foo1', true); + await createPolicyDataStreamsIfNeeded({ + endpointServices: endpointServicesMock, + endpointPolicyIds: ['123'], + }); + + expect(esClientMock.indices.exists).not.toHaveBeenCalledWith({ + index: '.logs-endpoint.action.responses-foo1', + }); + expect(esClientMock.indices.createDataStream).toHaveBeenCalledTimes(3); + [ + '.logs-endpoint.diagnostic.collection-foo1', + '.logs-endpoint.diagnostic.collection-foo2', + '.logs-endpoint.action.responses-foo2', + ].forEach((indexName) => { + expect(esClientMock.indices.createDataStream).toHaveBeenCalledWith({ + name: indexName, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_policy_datastreams.ts b/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_policy_datastreams.ts new file mode 100644 index 0000000000000..e94bc71cd4fa7 --- /dev/null +++ b/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_policy_datastreams.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import pMap from 'p-map'; +import { buildIndexNameWithNamespace } from '../../../common/endpoint/utils/index_name_utilities'; +import type { EndpointAppContextService } from '../../endpoint/endpoint_app_context_services'; +import { catchAndWrapError } from '../../endpoint/utils'; +import type { SimpleMemCacheInterface } from '../../endpoint/lib/simple_mem_cache'; +import { SimpleMemCache } from '../../endpoint/lib/simple_mem_cache'; +import { + DEFAULT_DIAGNOSTIC_INDEX_PATTERN, + ENDPOINT_ACTION_RESPONSES_DS, + ENDPOINT_HEARTBEAT_INDEX_PATTERN, +} from '../../../common/endpoint/constants'; +import { stringify } from '../../endpoint/utils/stringify'; + +const cache = new SimpleMemCache({ + // Cache of created Datastreams last for 12h, at which point it is checked again. + // This is just a safeguard case (for whatever reason) the index is deleted + // 1.8e+7 === hours + ttl: 1.8e7, +}); + +interface PolicyDataStreamsCreator { + (options: CreatePolicyDataStreamsOptions): Promise; + cache: SimpleMemCacheInterface; +} + +export interface CreatePolicyDataStreamsOptions { + endpointServices: EndpointAppContextService; + endpointPolicyIds: string[]; +} + +/** + * Ensures that the DOT index Datastreams necessary to support Elastic Defend are crated (prior to + * endpoint writing data to them) + */ +export const createPolicyDataStreamsIfNeeded: PolicyDataStreamsCreator = async ({ + endpointServices, + endpointPolicyIds, +}: CreatePolicyDataStreamsOptions): Promise => { + const logger = endpointServices.createLogger('endpointPolicyDatastreamCreator'); + const esClient = endpointServices.getInternalEsClient(); + + logger.debug( + () => + `Checking if datastreams need to be created for Endpoint integration policy [${endpointPolicyIds.join( + ', ' + )}]` + ); + + // FIXME:PT Need to ensure that the datastreams are created in all associated space ids that the policy is shared with + // This can be deferred to activity around support of Spaces - team issue: 8199 (epic) + // We might need to do much here other than to ensure we can access all policies across all spaces in order to get the namespace value + + const fleetServices = endpointServices.getInternalFleetServices(); + const policyNamespaces = await fleetServices.getPolicyNamespace({ + integrationPolicies: endpointPolicyIds, + }); + const indexesCreated: string[] = []; + const createErrors: string[] = []; + const indicesToCreate: string[] = Array.from( + Object.values(policyNamespaces.integrationPolicy).reduce>((acc, namespaceList) => { + for (const namespace of namespaceList) { + acc.add(buildIndexNameWithNamespace(DEFAULT_DIAGNOSTIC_INDEX_PATTERN, namespace)); + acc.add(buildIndexNameWithNamespace(ENDPOINT_ACTION_RESPONSES_DS, namespace)); + + if (endpointServices.isServerless()) { + acc.add(buildIndexNameWithNamespace(ENDPOINT_HEARTBEAT_INDEX_PATTERN, namespace)); + } + } + + return acc; + }, new Set()) + ); + + const processesDatastreamIndex = async (datastreamIndexName: string): Promise => { + if (cache.get(datastreamIndexName)) { + return; + } + + const doesDataStreamAlreadyExist = await esClient.indices + .exists({ index: datastreamIndexName }) + .catch(catchAndWrapError); + + if (doesDataStreamAlreadyExist) { + cache.set(datastreamIndexName, true); + return; + } + + await esClient.indices + .createDataStream({ name: datastreamIndexName }) + .then(() => { + indexesCreated.push(datastreamIndexName); + cache.set(datastreamIndexName, true); + }) + .catch((err) => { + // It's possible that between the `.exists()` check and this `.createDataStream()` that + // the index could have been created. If that's the case, then just ignore the error. + if (err.body?.error?.type === 'resource_already_exists_exception') { + cache.set(datastreamIndexName, true); + return; + } + + createErrors.push( + `Attempt to create datastream [${datastreamIndexName}] failed:\n${stringify( + err.body?.error ?? err + )}` + ); + }); + }; + + logger.debug( + () => + `Checking if the following datastream(s) need to be created:\n ${indicesToCreate.join( + '\n ' + )}` + ); + + await pMap(indicesToCreate, processesDatastreamIndex, { concurrency: 10 }); + + if (indexesCreated.length > 0) { + logger.info( + `Datastream(s) created in support of Elastic Defend policy [${endpointPolicyIds.join( + ', ' + )}]:\n ${indexesCreated.join('\n ')}` + ); + } else if (createErrors.length === 0) { + logger.debug(() => `Nothing to do. Datastreams already exist`); + } + + if (createErrors.length > 0) { + logger.error( + `${createErrors.length} errors encountered:\n${createErrors.join('\n--------\n')}` + ); + } +}; +createPolicyDataStreamsIfNeeded.cache = cache; diff --git a/x-pack/plugins/security_solution/server/integration_tests/lib/telemetry_helpers.ts b/x-pack/plugins/security_solution/server/integration_tests/lib/telemetry_helpers.ts index d83ff1e910ca5..a36d5e1be38de 100644 --- a/x-pack/plugins/security_solution/server/integration_tests/lib/telemetry_helpers.ts +++ b/x-pack/plugins/security_solution/server/integration_tests/lib/telemetry_helpers.ts @@ -30,6 +30,7 @@ import { packagePolicyService } from '@kbn/fleet-plugin/server/services'; import { ENDPOINT_ARTIFACT_LISTS } from '@kbn/securitysolution-list-constants'; import { DETECTION_TYPE, NAMESPACE_TYPE } from '@kbn/lists-plugin/common/constants.mock'; +import { DEFAULT_DIAGNOSTIC_INDEX_PATTERN } from '../../../common/endpoint/constants'; import { bulkInsert, updateTimestamps } from './helpers'; import { TelemetryEventsSender } from '../../lib/telemetry/sender'; import type { @@ -40,7 +41,6 @@ import type { SecurityTelemetryTask } from '../../lib/telemetry/task'; import { Plugin as SecuritySolutionPlugin } from '../../plugin'; import { AsyncTelemetryEventsSender } from '../../lib/telemetry/async_sender'; import { type ITelemetryReceiver, TelemetryReceiver } from '../../lib/telemetry/receiver'; -import { DEFAULT_DIAGNOSTIC_INDEX } from '../../lib/telemetry/constants'; import mockEndpointAlert from '../__mocks__/endpoint-alert.json'; import mockedRule from '../__mocks__/rule.json'; import fleetAgents from '../__mocks__/fleet-agents.json'; @@ -147,7 +147,7 @@ export function getTelemetryTask( } export async function createMockedEndpointAlert(esClient: ElasticsearchClient) { - const index = `${DEFAULT_DIAGNOSTIC_INDEX.replace('-*', '')}-001`; + const index = `${DEFAULT_DIAGNOSTIC_INDEX_PATTERN.replace('-*', '')}-001`; await esClient.indices.create({ index, body: { settings: { hidden: true } } }); @@ -223,7 +223,7 @@ export async function dropEndpointIndices(esClient: ElasticsearchClient) { } export async function cleanupMockedEndpointAlerts(esClient: ElasticsearchClient) { - const index = `${DEFAULT_DIAGNOSTIC_INDEX.replace('-*', '')}-001`; + const index = `${DEFAULT_DIAGNOSTIC_INDEX_PATTERN.replace('-*', '')}-001`; await esClient.indices.delete({ index }).catch(() => { // ignore errors diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/get_threshold_signal_history.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/get_threshold_signal_history.ts index 018d63c345e3a..e82e33c9e6e95 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/get_threshold_signal_history.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/get_threshold_signal_history.ts @@ -46,6 +46,9 @@ export const getThresholdSignalHistory = async ({ const response = await esClient.search({ ...request, index: indexPattern, + // If alerts index is not yet created, + // do not throw a 404 + ignore_unavailable: true, }); return { signalHistory: buildThresholdSignalHistory({ alerts: response.hits.hits }), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/get_alert_types.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/find_alerting_rules.sh similarity index 59% rename from x-pack/plugins/security_solution/server/lib/detection_engine/scripts/get_alert_types.sh rename to x-pack/plugins/security_solution/server/lib/detection_engine/scripts/find_alerting_rules.sh index 9b51c289ac2c3..c735dd333710c 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/get_alert_types.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/find_alerting_rules.sh @@ -10,9 +10,10 @@ set -e ./check_env_variables.sh -# Example: ./get_alert_types.sh -# https://github.com/elastic/kibana/blob/main/x-pack/plugins/alerting/README.md#get-apialerttypes-list-alert-types +# Example: ./find_alerting_rules.sh +# https://www.elastic.co/docs/api/doc/kibana/v8/operation/operation-findrules +# Related: use ./find_rules.sh to retrieve Detection Engine (Security) rules curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET ${KIBANA_URL}${SPACE_URL}/api/alerts/list_alert_types \ + -X GET ${KIBANA_URL}${SPACE_URL}/api/alerting/rules/_find \ | jq . diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/find_rules.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/find_rules.sh index ef8244ad6e200..422f3e2bb0545 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/find_rules.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/find_rules.sh @@ -12,5 +12,6 @@ set -e # Example: ./find_rules.sh curl -s -k \ + -H 'elastic-api-version: 2023-10-31' \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ -X GET ${KIBANA_URL}${SPACE_URL}/api/detection_engine/rules/_find | jq . diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/get_alert_instances.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/get_alerting_rule_types.sh similarity index 65% rename from x-pack/plugins/security_solution/server/lib/detection_engine/scripts/get_alert_instances.sh rename to x-pack/plugins/security_solution/server/lib/detection_engine/scripts/get_alerting_rule_types.sh index f2ba9bb70a7c6..59c960d67ba4d 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/get_alert_instances.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/get_alerting_rule_types.sh @@ -10,9 +10,9 @@ set -e ./check_env_variables.sh -# Example: ./get_alert_instances.sh -# https://github.com/elastic/kibana/blob/main/x-pack/plugins/alerting/README.md#get-apialert_find-find-alerts +# Example: ./get_rule_types.sh +# https://www.elastic.co/docs/api/doc/kibana/v8/operation/operation-getruletypes curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET ${KIBANA_URL}${SPACE_URL}/api/alerts/_find \ + -X GET ${KIBANA_URL}${SPACE_URL}/api/alerting/rule_types \ | jq . diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/actions.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/actions.ts new file mode 100644 index 0000000000000..63d594a9711a3 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/actions.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const EntityEngineActions = { + INIT: 'init', + START: 'start', + STOP: 'stop', + CREATE: 'create', + DELETE: 'delete', + EXECUTE: 'execute', +} as const; + +export type EntityEngineActions = (typeof EntityEngineActions)[keyof typeof EntityEngineActions]; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/resources.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/resources.ts new file mode 100644 index 0000000000000..67d33fb42dc93 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/resources.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const EntityStoreResource = { + ENTITY_ENGINE: 'entity_engine', + ENTITY_DEFINITION: 'entity_definition', + ENTITY_INDEX: 'entity_index', + INDEX_COMPONENT_TEMPLATE: 'index_component_template', + PLATFORM_PIPELINE: 'platform_pipeline', + FIELD_RETENTION_ENRICH_POLICY: 'field_retention_enrich_policy', + FIELD_RETENTION_ENRICH_POLICY_TASK: 'field_retention_enrich_policy_task', +} as const; + +export type EntityStoreResource = (typeof EntityStoreResource)[keyof typeof EntityStoreResource]; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/constants.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/constants.ts index 796932d79b364..8b2e802b17b6d 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/constants.ts @@ -9,8 +9,6 @@ import type { EngineStatus } from '../../../../common/api/entity_analytics'; export const DEFAULT_LOOKBACK_PERIOD = '24h'; -export const DEFAULT_INTERVAL = '30s'; - export const ENGINE_STATUS: Record, EngineStatus> = { INSTALLING: 'installing', STARTED: 'started', diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/ingest_pipeline.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/ingest_pipeline.ts index c2a5bff51f830..f4d2b848b726f 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/ingest_pipeline.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/ingest_pipeline.ts @@ -125,7 +125,7 @@ export const createPlatformPipeline = async ({ managed_by: 'entity_store', managed: true, }, - description: `Ingest pipeline for entity defiinition ${entityManagerDefinition.id}`, + description: `Ingest pipeline for entity definition ${entityManagerDefinition.id}`, processors: buildIngestPipeline({ namespace: unitedDefinition.namespace, version: unitedDefinition.version, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts index 858047952801d..733e85fd6ed55 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts @@ -15,6 +15,7 @@ import type { SortOrder } from '@elastic/elasticsearch/lib/api/types'; import type { EntityType } from '../../../../common/api/entity_analytics/entity_store/common.gen'; import type { DataViewsService } from '@kbn/data-views-plugin/common'; import type { AppClient } from '../../..'; +import type { EntityStoreConfig } from './types'; describe('EntityStoreDataClient', () => { const mockSavedObjectClient = savedObjectsClientMock.create(); @@ -29,6 +30,7 @@ describe('EntityStoreDataClient', () => { kibanaVersion: '9.0.0', dataViewsService: {} as DataViewsService, appClient: {} as AppClient, + config: {} as EntityStoreConfig, }); const defaultSearchParams = { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts index 429d77482841e..d1d56aa0e08cb 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts @@ -11,12 +11,15 @@ import type { SavedObjectsClientContract, AuditLogger, IScopedClusterClient, + AuditEvent, + AnalyticsServiceSetup, } from '@kbn/core/server'; import { EntityClient } from '@kbn/entityManager-plugin/server/lib/entity_client'; import type { SortOrder } from '@elastic/elasticsearch/lib/api/types'; import type { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; import type { DataViewsService } from '@kbn/data-views-plugin/common'; import { isEqual } from 'lodash/fp'; +import moment from 'moment'; import type { AppClient } from '../../..'; import type { Entity, @@ -53,7 +56,14 @@ import { isPromiseFulfilled, isPromiseRejected, } from './utils'; -import type { EntityRecord } from './types'; +import { EntityEngineActions } from './auditing/actions'; +import { EntityStoreResource } from './auditing/resources'; +import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../audit'; +import type { EntityRecord, EntityStoreConfig } from './types'; +import { + ENTITY_ENGINE_INITIALIZATION_EVENT, + ENTITY_ENGINE_RESOURCE_INIT_FAILURE_EVENT, +} from '../../telemetry/event_based/events'; import { CRITICALITY_VALUES } from '../asset_criticality/constants'; interface EntityStoreClientOpts { @@ -66,6 +76,8 @@ interface EntityStoreClientOpts { kibanaVersion: string; dataViewsService: DataViewsService; appClient: AppClient; + config: EntityStoreConfig; + telemetry?: AnalyticsServiceSetup; } interface SearchEntitiesParams { @@ -123,7 +135,7 @@ export class EntityStoreDataClient { throw new Error('Task Manager is not available'); } - const { logger } = this.options; + const { config } = this.options; await this.riskScoreDataClient.createRiskScoreLatestIndex(); @@ -135,8 +147,13 @@ export class EntityStoreDataClient { 'Asset criticality data migration is required before initializing entity store. If this error persists, please restart Kibana.' ); } - logger.info( - `In namespace ${this.options.namespace}: Initializing entity store for ${entityType}` + + this.log('info', entityType, `Initializing entity store`); + this.audit( + EntityEngineActions.INIT, + EntityStoreResource.ENTITY_ENGINE, + entityType, + 'Initializing entity engine' ); const descriptor = await this.engineClient.init(entityType, { @@ -144,9 +161,7 @@ export class EntityStoreDataClient { fieldHistoryLength, indexPattern, }); - logger.debug(`Initialized engine for ${entityType}`); - // first create the entity definition without starting it - // so that the index template is created which we can add a component template to + this.log('debug', entityType, `Initialized engine saved object`); this.asyncSetup( entityType, @@ -154,10 +169,11 @@ export class EntityStoreDataClient { this.options.taskManager, indexPattern, filter, + config, pipelineDebugMode - ).catch((error) => { - logger.error(`There was an error during async setup of the Entity Store: ${error}`); - }); + ).catch((e) => + this.log('error', entityType, `Error during async setup of entity store: ${e.message}`) + ); return descriptor; } @@ -168,8 +184,10 @@ export class EntityStoreDataClient { taskManager: TaskManagerStartContract, indexPattern: string, filter: string, + config: EntityStoreConfig, pipelineDebugMode: boolean ) { + const setupStartTime = moment().utc().toISOString(); const { logger, namespace, appClient, dataViewsService } = this.options; const indexPatterns = await buildIndexPatterns(namespace, appClient, dataViewsService); @@ -178,12 +196,11 @@ export class EntityStoreDataClient { entityType, namespace, fieldHistoryLength, + syncDelay: `${config.syncDelay.asSeconds()}s`, + frequency: `${config.frequency.asSeconds()}s`, }); const { entityManagerDefinition } = unitedDefinition; - const debugLog = (message: string) => - logger.debug(`[Entity Engine] [${entityType}] ${message}`); - try { // clean up any existing entity store await this.delete(entityType, taskManager, { deleteData: false, deleteEngine: false }); @@ -199,7 +216,7 @@ export class EntityStoreDataClient { }, installOnly: true, }); - debugLog(`Created entity definition`); + this.log(`debug`, entityType, `Created entity definition`); // the index must be in place with the correct mapping before the enrich policy is created // this is because the enrich policy will fail if the index does not exist with the correct fields @@ -207,14 +224,14 @@ export class EntityStoreDataClient { unitedDefinition, esClient: this.esClient, }); - debugLog(`Created entity index component template`); + this.log(`debug`, entityType, `Created entity index component template`); await createEntityIndex({ entityType, esClient: this.esClient, namespace, logger, }); - debugLog(`Created entity index`); + this.log(`debug`, entityType, `Created entity index`); // we must create and execute the enrich policy before the pipeline is created // this is because the pipeline will fail if the enrich index does not exist @@ -222,24 +239,24 @@ export class EntityStoreDataClient { unitedDefinition, esClient: this.esClient, }); - debugLog(`Created field retention enrich policy`); + this.log(`debug`, entityType, `Created field retention enrich policy`); + await executeFieldRetentionEnrichPolicy({ unitedDefinition, esClient: this.esClient, logger, }); - debugLog(`Executed field retention enrich policy`); + this.log(`debug`, entityType, `Executed field retention enrich policy`); await createPlatformPipeline({ debugMode: pipelineDebugMode, unitedDefinition, logger, esClient: this.esClient, }); - debugLog(`Created @platform pipeline`); + this.log(`debug`, entityType, `Created @platform pipeline`); // finally start the entity definition now that everything is in place const updated = await this.start(entityType, { force: true }); - debugLog(`Started entity definition`); // the task will execute the enrich policy on a schedule await startEntityStoreFieldRetentionEnrichTask({ @@ -247,15 +264,40 @@ export class EntityStoreDataClient { logger, taskManager, }); - logger.info(`Entity store initialized for ${entityType}`); + + this.log(`debug`, entityType, `Started entity store field retention enrich task`); + this.log(`info`, entityType, `Entity store initialized`); + + const setupEndTime = moment().utc().toISOString(); + const duration = moment(setupEndTime).diff(moment(setupStartTime), 'seconds'); + this.options.telemetry?.reportEvent(ENTITY_ENGINE_INITIALIZATION_EVENT.eventType, { + duration, + }); return updated; } catch (err) { - this.options.logger.error( - `Error initializing entity store for ${entityType}: ${err.message}` + this.log(`error`, entityType, `Error initializing entity store: ${err.message}`); + + this.audit( + EntityEngineActions.INIT, + EntityStoreResource.ENTITY_ENGINE, + entityType, + 'Failed to initialize entity engine resources', + err ); - await this.engineClient.update(entityType, ENGINE_STATUS.ERROR); + this.options.telemetry?.reportEvent(ENTITY_ENGINE_RESOURCE_INIT_FAILURE_EVENT.eventType, { + error: err.message, + }); + + await this.engineClient.update(entityType, { + status: ENGINE_STATUS.ERROR, + error: { + message: err.message, + stack: err.stack, + action: 'init', + }, + }); await this.delete(entityType, taskManager, { deleteData: true, deleteEngine: false }); } @@ -278,43 +320,56 @@ export class EntityStoreDataClient { } public async start(entityType: EntityType, options?: { force: boolean }) { + const { namespace } = this.options; const descriptor = await this.engineClient.get(entityType); if (!options?.force && descriptor.status !== ENGINE_STATUS.STOPPED) { throw new Error( - `In namespace ${this.options.namespace}: Cannot start Entity engine for ${entityType} when current status is: ${descriptor.status}` + `In namespace ${namespace}: Cannot start Entity engine for ${entityType} when current status is: ${descriptor.status}` ); } - this.options.logger.info( - `In namespace ${this.options.namespace}: Starting entity store for ${entityType}` - ); + this.log('info', entityType, `Starting entity store`); // startEntityDefinition requires more fields than the engine descriptor // provides so we need to fetch the full entity definition const fullEntityDefinition = await this.getExistingEntityDefinition(entityType); + this.audit( + EntityEngineActions.START, + EntityStoreResource.ENTITY_DEFINITION, + entityType, + 'Starting entity definition' + ); await this.entityClient.startEntityDefinition(fullEntityDefinition); + this.log('debug', entityType, `Started entity definition`); - return this.engineClient.update(entityType, ENGINE_STATUS.STARTED); + return this.engineClient.updateStatus(entityType, ENGINE_STATUS.STARTED); } public async stop(entityType: EntityType) { + const { namespace } = this.options; const descriptor = await this.engineClient.get(entityType); if (descriptor.status !== ENGINE_STATUS.STARTED) { throw new Error( - `In namespace ${this.options.namespace}: Cannot stop Entity engine for ${entityType} when current status is: ${descriptor.status}` + `In namespace ${namespace}: Cannot stop Entity engine for ${entityType} when current status is: ${descriptor.status}` ); } - this.options.logger.info( - `In namespace ${this.options.namespace}: Stopping entity store for ${entityType}` - ); + this.log('info', entityType, `Stopping entity store`); + // stopEntityDefinition requires more fields than the engine descriptor // provides so we need to fetch the full entity definition const fullEntityDefinition = await this.getExistingEntityDefinition(entityType); + this.audit( + EntityEngineActions.STOP, + EntityStoreResource.ENTITY_DEFINITION, + entityType, + 'Stopping entity definition' + ); await this.entityClient.stopEntityDefinition(fullEntityDefinition); + this.log('debug', entityType, `Stopped entity definition`); - return this.engineClient.update(entityType, ENGINE_STATUS.STOPPED); + return this.engineClient.updateStatus(entityType, ENGINE_STATUS.STOPPED); } public async get(entityType: EntityType) { @@ -330,42 +385,62 @@ export class EntityStoreDataClient { taskManager: TaskManagerStartContract, options = { deleteData: false, deleteEngine: true } ) { - const { namespace, logger, appClient, dataViewsService } = this.options; + const { namespace, logger, appClient, dataViewsService, config } = this.options; const { deleteData, deleteEngine } = options; const descriptor = await this.engineClient.maybeGet(entityType); const indexPatterns = await buildIndexPatterns(namespace, appClient, dataViewsService); + + // TODO delete unitedDefinition from this method. we only need the id for deletion const unitedDefinition = getUnitedEntityDefinition({ indexPatterns, entityType, namespace: this.options.namespace, fieldHistoryLength: descriptor?.fieldHistoryLength ?? 10, + syncDelay: `${config.syncDelay.asSeconds()}s`, + frequency: `${config.frequency.asSeconds()}s`, }); const { entityManagerDefinition } = unitedDefinition; - logger.info(`In namespace ${namespace}: Deleting entity store for ${entityType}`); + + this.log('info', entityType, `Deleting entity store`); + this.audit( + EntityEngineActions.DELETE, + EntityStoreResource.ENTITY_ENGINE, + entityType, + 'Deleting entity engine' + ); + try { - try { - await this.entityClient.deleteEntityDefinition({ + await this.entityClient + .deleteEntityDefinition({ id: entityManagerDefinition.id, deleteData, - }); - } catch (e) { - logger.error(`Error deleting entity definition for ${entityType}: ${e.message}`); - } + }) + // Swallowing the error as it is expected to fail if no entity definition exists + .catch((e) => + this.log(`warn`, entityType, `Error deleting entity definition: ${e.message}`) + ); + this.log('debug', entityType, `Deleted entity definition`); + await deleteEntityIndexComponentTemplate({ unitedDefinition, esClient: this.esClient, }); + this.log('debug', entityType, `Deleted entity index component template`); + await deletePlatformPipeline({ unitedDefinition, logger, esClient: this.esClient, }); + this.log('debug', entityType, `Deleted platform pipeline`); + await deleteFieldRetentionEnrichPolicy({ unitedDefinition, esClient: this.esClient, logger, }); + this.log('debug', entityType, `Deleted field retention enrich policy`); if (deleteData) { await deleteEntityIndex({ @@ -374,6 +449,7 @@ export class EntityStoreDataClient { namespace, logger, }); + this.log('debug', entityType, `Deleted entity index`); } if (descriptor && deleteEngine) { @@ -387,13 +463,23 @@ export class EntityStoreDataClient { logger, taskManager, }); + this.log('debug', entityType, `Deleted entity store field retention enrich task`); } + logger.info(`[Entity Store] In namespace ${namespace}: Deleted store for ${entityType}`); return { deleted: true }; - } catch (e) { - logger.error(`Error deleting entity store for ${entityType}: ${e.message}`); - // TODO: should we set the engine status to error here? - throw e; + } catch (err) { + this.log(`error`, entityType, `Error deleting entity store: ${err.message}`); + + this.audit( + EntityEngineActions.DELETE, + EntityStoreResource.ENTITY_ENGINE, + entityType, + 'Failed to delete entity engine', + err + ); + + throw err; } } @@ -481,7 +567,7 @@ export class EntityStoreDataClient { } // Update savedObject status - await this.engineClient.update(engine.type, ENGINE_STATUS.UPDATING); + await this.engineClient.updateStatus(engine.type, ENGINE_STATUS.UPDATING); try { // Update entity manager definition @@ -494,12 +580,12 @@ export class EntityStoreDataClient { }); // Restore the savedObject status and set the new index pattern - await this.engineClient.update(engine.type, originalStatus); + await this.engineClient.updateStatus(engine.type, originalStatus); return { type: engine.type, changes: { indexPatterns } }; } catch (error) { // Rollback the engine initial status when the update fails - await this.engineClient.update(engine.type, originalStatus); + await this.engineClient.updateStatus(engine.type, originalStatus); throw error; } @@ -521,4 +607,48 @@ export class EntityStoreDataClient { errors: updateErrors, }; } + + private log( + level: Exclude, + entityType: EntityType, + msg: string + ) { + this.options.logger[level]( + `[Entity Engine] [entity.${entityType}] [namespace: ${this.options.namespace}] ${msg}` + ); + } + + private audit( + action: EntityEngineActions, + resource: EntityStoreResource, + entityType: EntityType, + msg: string, + error?: Error + ) { + // NOTE: Excluding errors, all auditing events are currently WRITE events, meaning the outcome is always UNKNOWN. + // This may change in the future, depending on the audit action. + const outcome = error ? AUDIT_OUTCOME.FAILURE : AUDIT_OUTCOME.UNKNOWN; + + const type = + action === EntityEngineActions.CREATE + ? AUDIT_TYPE.CREATION + : EntityEngineActions.DELETE + ? AUDIT_TYPE.DELETION + : AUDIT_TYPE.CHANGE; + + const category = AUDIT_CATEGORY.DATABASE; + + const message = error ? `${msg}: ${error.message}` : msg; + const event: AuditEvent = { + message: `[Entity Engine] [entity.${entityType}] ${message}`, + event: { + action: `${action}_${entityType}_${resource}`, + category, + outcome, + type, + }, + }; + + return this.options.auditLogger?.log(event); + } } diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/stop.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/stop.ts index e1c28bc2cc073..3ec84e13aa1db 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/stop.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/stop.ts @@ -47,7 +47,7 @@ export const stopEntityEngineRoute = ( return response.ok({ body: { stopped: engine.status === ENGINE_STATUS.STOPPED } }); } catch (e) { - logger.error('Error in StopEntityEngine:', e); + logger.error(`Error in StopEntityEngine: ${e.message}`); const error = transformError(e); return siemResponse.error({ statusCode: error.statusCode, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/saved_object/engine_descriptor.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/saved_object/engine_descriptor.ts index af7b4ba80dde5..cfaea1b1da0ff 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/saved_object/engine_descriptor.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/saved_object/engine_descriptor.ts @@ -78,17 +78,21 @@ export class EngineDescriptorClient { return attributes; } - async update(entityType: EntityType, status: EngineStatus) { + async update(entityType: EntityType, engine: Partial) { const id = this.getSavedObjectId(entityType); const { attributes } = await this.deps.soClient.update( entityEngineDescriptorTypeName, id, - { status }, + engine, { refresh: 'wait_for' } ); return attributes; } + async updateStatus(entityType: EntityType, status: EngineStatus) { + return this.update(entityType, { status }); + } + async find(entityType: EntityType): Promise> { return this.deps.soClient.find({ type: entityEngineDescriptorTypeName, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts index d008c3afe6f17..708b74277faae 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts @@ -6,6 +6,7 @@ */ import moment from 'moment'; +import type { AnalyticsServiceSetup } from '@kbn/core/server'; import { type Logger, SavedObjectsErrorHelpers } from '@kbn/core/server'; import type { ConcreteTaskInstance, @@ -26,15 +27,21 @@ import { } from '../united_entity_definitions'; import { executeFieldRetentionEnrichPolicy } from '../elasticsearch_assets'; +import { getEntitiesIndexName } from '../utils'; +import { + FIELD_RETENTION_ENRICH_POLICY_EXECUTION_EVENT, + ENTITY_STORE_USAGE_EVENT, +} from '../../../telemetry/event_based/events'; + const logFactory = (logger: Logger, taskId: string) => (message: string): void => - logger.info(`[task ${taskId}]: ${message}`); + logger.info(`[Entity Store] [task ${taskId}]: ${message}`); const debugLogFactory = (logger: Logger, taskId: string) => (message: string): void => - logger.debug(`[task ${taskId}]: ${message}`); + logger.debug(`[Entity Store] [task ${taskId}]: ${message}`); const getTaskName = (): string => TYPE; @@ -44,18 +51,23 @@ type ExecuteEnrichPolicy = ( namespace: string, entityType: EntityType ) => ReturnType; +type GetStoreSize = (index: string | string[]) => Promise; export const registerEntityStoreFieldRetentionEnrichTask = ({ getStartServices, logger, + telemetry, taskManager, }: { getStartServices: EntityAnalyticsRoutesDeps['getStartServices']; logger: Logger; + telemetry: AnalyticsServiceSetup; taskManager: TaskManagerSetupContract | undefined; }): void => { if (!taskManager) { - logger.info('Task Manager is unavailable; skipping entity store enrich policy registration.'); + logger.info( + '[Entity Store] Task Manager is unavailable; skipping entity store enrich policy registration.' + ); return; } @@ -75,6 +87,14 @@ export const registerEntityStoreFieldRetentionEnrichTask = ({ }); }; + const getStoreSize: GetStoreSize = async (index) => { + const [coreStart] = await getStartServices(); + const esClient = coreStart.elasticsearch.client.asInternalUser; + + const { count } = await esClient.count({ index }); + return count; + }; + taskManager.registerTaskDefinitions({ [getTaskName()]: { title: 'Entity Analytics Entity Store - Execute Enrich Policy Task', @@ -82,6 +102,8 @@ export const registerEntityStoreFieldRetentionEnrichTask = ({ stateSchemaByVersion, createTaskRunner: createTaskRunnerFactory({ logger, + telemetry, + getStoreSize, executeEnrichPolicy, }), }, @@ -114,7 +136,7 @@ export const startEntityStoreFieldRetentionEnrichTask = async ({ params: { version: VERSION }, }); } catch (e) { - logger.warn(`[task ${taskId}]: error scheduling task, received ${e.message}`); + logger.warn(`[Entity Store] [task ${taskId}]: error scheduling task, received ${e.message}`); throw e; } }; @@ -130,9 +152,14 @@ export const removeEntityStoreFieldRetentionEnrichTask = async ({ }) => { try { await taskManager.remove(getTaskId(namespace)); + logger.info( + `[Entity Store] Removed entity store enrich policy task for namespace ${namespace}` + ); } catch (err) { if (!SavedObjectsErrorHelpers.isNotFoundError(err)) { - logger.error(`Failed to remove entity store enrich policy task: ${err.message}`); + logger.error( + `[Entity Store] Failed to remove entity store enrich policy task: ${err.message}` + ); throw err; } } @@ -140,14 +167,18 @@ export const removeEntityStoreFieldRetentionEnrichTask = async ({ export const runTask = async ({ executeEnrichPolicy, + getStoreSize, isCancelled, logger, taskInstance, + telemetry, }: { logger: Logger; isCancelled: () => boolean; executeEnrichPolicy: ExecuteEnrichPolicy; + getStoreSize: GetStoreSize; taskInstance: ConcreteTaskInstance; + telemetry: AnalyticsServiceSetup; }): Promise<{ state: EntityStoreFieldRetentionTaskState; }> => { @@ -171,13 +202,14 @@ export const runTask = async ({ } const entityTypes = getAvailableEntityTypes(); + for (const entityType of entityTypes) { const start = Date.now(); debugLog(`executing field retention enrich policy for ${entityType}`); try { const { executed } = await executeEnrichPolicy(state.namespace, entityType); if (!executed) { - debugLog(`Field retention encrich policy for ${entityType} does not exist`); + debugLog(`Field retention enrich policy for ${entityType} does not exist`); } else { log( `Executed field retention enrich policy for ${entityType} in ${Date.now() - start}ms` @@ -192,17 +224,39 @@ export const runTask = async ({ const taskDurationInSeconds = moment(taskCompletionTime).diff(moment(taskStartTime), 'seconds'); log(`task run completed in ${taskDurationInSeconds} seconds`); + telemetry.reportEvent(FIELD_RETENTION_ENRICH_POLICY_EXECUTION_EVENT.eventType, { + duration: taskDurationInSeconds, + interval: INTERVAL, + }); + + // Track entity store usage + const indices = entityTypes.map((entityType) => + getEntitiesIndexName(entityType, state.namespace) + ); + const storeSize = await getStoreSize(indices); + telemetry.reportEvent(ENTITY_STORE_USAGE_EVENT.eventType, { storeSize }); + return { state: updatedState, }; } catch (e) { - logger.error(`[task ${taskId}]: error running task, received ${e.message}`); + logger.error(`[Entity Store] [task ${taskId}]: error running task, received ${e.message}`); throw e; } }; const createTaskRunnerFactory = - ({ logger, executeEnrichPolicy }: { logger: Logger; executeEnrichPolicy: ExecuteEnrichPolicy }) => + ({ + logger, + telemetry, + executeEnrichPolicy, + getStoreSize, + }: { + logger: Logger; + telemetry: AnalyticsServiceSetup; + executeEnrichPolicy: ExecuteEnrichPolicy; + getStoreSize: GetStoreSize; + }) => ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { let cancelled = false; const isCancelled = () => cancelled; @@ -210,9 +264,11 @@ const createTaskRunnerFactory = run: async () => runTask({ executeEnrichPolicy, + getStoreSize, isCancelled, logger, taskInstance, + telemetry, }), cancel: async () => { cancelled = true; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/types.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/types.ts index e5f1e6db36bca..b71380b2e0677 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/types.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/types.ts @@ -7,6 +7,7 @@ import type { HostEntity, UserEntity } from '../../../../common/api/entity_analytics'; import type { CriticalityValues } from '../asset_criticality/constants'; +import type { EntityAnalyticsConfig } from '../types'; export interface HostEntityRecord extends Omit { asset?: { @@ -24,3 +25,5 @@ export interface UserEntityRecord extends Omit { * It represents the data stored in the entity store index. */ export type EntityRecord = HostEntityRecord | UserEntityRecord; + +export type EntityStoreConfig = EntityAnalyticsConfig['entityStore']; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.test.ts index d9c54e1fcd288..fa443ffa94047 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.test.ts @@ -15,6 +15,8 @@ describe('getUnitedEntityDefinition', () => { namespace: 'test', fieldHistoryLength: 10, indexPatterns, + syncDelay: '1m', + frequency: '1m', }); it('mapping', () => { @@ -172,6 +174,10 @@ describe('getUnitedEntityDefinition', () => { ], "latest": Object { "lookbackPeriod": "24h", + "settings": Object { + "frequency": "1m", + "syncDelay": "1m", + }, "timestampField": "@timestamp", }, "managed": true, @@ -312,6 +318,8 @@ describe('getUnitedEntityDefinition', () => { namespace: 'test', fieldHistoryLength: 10, indexPatterns, + syncDelay: '1m', + frequency: '1m', }); it('mapping', () => { @@ -445,6 +453,10 @@ describe('getUnitedEntityDefinition', () => { ], "latest": Object { "lookbackPeriod": "24h", + "settings": Object { + "frequency": "1m", + "syncDelay": "1m", + }, "timestampField": "@timestamp", }, "managed": true, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.ts index 32cb52a61d469..ba4963d5fea0a 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.ts @@ -25,6 +25,8 @@ interface Options { namespace: string; fieldHistoryLength: number; indexPatterns: string[]; + syncDelay: string; + frequency: string; } export const getUnitedEntityDefinition = memoize( @@ -33,6 +35,8 @@ export const getUnitedEntityDefinition = memoize( namespace, fieldHistoryLength, indexPatterns, + syncDelay, + frequency, }: Options): UnitedEntityDefinition => { const unitedDefinition = unitedDefinitionBuilders[entityType](fieldHistoryLength); @@ -47,6 +51,8 @@ export const getUnitedEntityDefinition = memoize( ...unitedDefinition, namespace, indexPatterns, + syncDelay, + frequency, }); } ); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/united_entity_definition.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/united_entity_definition.ts index c5315c5dca2b0..eced765c75193 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/united_entity_definition.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/united_entity_definition.ts @@ -7,7 +7,7 @@ import { entityDefinitionSchema, type EntityDefinition } from '@kbn/entities-schema'; import type { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/types'; import type { EntityType } from '../../../../../common/api/entity_analytics/entity_store/common.gen'; -import { DEFAULT_INTERVAL, DEFAULT_LOOKBACK_PERIOD } from '../constants'; +import { DEFAULT_LOOKBACK_PERIOD } from '../constants'; import { buildEntityDefinitionId, getIdentityFieldForEntityType } from '../utils'; import type { FieldRetentionDefinition, @@ -25,6 +25,8 @@ export class UnitedEntityDefinition { entityManagerDefinition: EntityDefinition; fieldRetentionDefinition: FieldRetentionDefinition; indexMappings: MappingTypeMapping; + syncDelay: string; + frequency: string; constructor(opts: { version: string; @@ -32,11 +34,15 @@ export class UnitedEntityDefinition { indexPatterns: string[]; fields: UnitedDefinitionField[]; namespace: string; + syncDelay: string; + frequency: string; }) { this.version = opts.version; this.entityType = opts.entityType; this.indexPatterns = opts.indexPatterns; this.fields = opts.fields; + this.frequency = opts.frequency; + this.syncDelay = opts.syncDelay; this.namespace = opts.namespace; this.entityManagerDefinition = this.toEntityManagerDefinition(); this.fieldRetentionDefinition = this.toFieldRetentionDefinition(); @@ -44,7 +50,7 @@ export class UnitedEntityDefinition { } private toEntityManagerDefinition(): EntityDefinition { - const { entityType, namespace, indexPatterns } = this; + const { entityType, namespace, indexPatterns, syncDelay, frequency } = this; const identityField = getIdentityFieldForEntityType(this.entityType); const metadata = this.fields .filter((field) => field.definition) @@ -61,7 +67,10 @@ export class UnitedEntityDefinition { latest: { timestampField: '@timestamp', lookbackPeriod: DEFAULT_LOOKBACK_PERIOD, - interval: DEFAULT_INTERVAL, + settings: { + syncDelay, + frequency, + }, }, version: this.version, managed: true, diff --git a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.test.ts b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.test.ts index a1b71a9c4f04f..8d274a30ca3c9 100644 --- a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.test.ts +++ b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.test.ts @@ -23,6 +23,7 @@ import type { import { ProductFeatureKey } from '@kbn/security-solution-features/keys'; import { httpServiceMock } from '@kbn/core-http-server-mocks'; import type { + AuthzEnabled, KibanaRequest, LifecycleResponseFactory, OnPostAuthHandler, @@ -181,11 +182,6 @@ describe('ProductFeaturesService', () => { lastRegisteredFn = fn; }); - const getReq = (tags: string[] = []) => - ({ - route: { options: { tags } }, - url: { pathname: '', search: '' }, - } as unknown as KibanaRequest); const res = { notFound: jest.fn() } as unknown as LifecycleResponseFactory; const toolkit = httpServiceMock.createOnPostAuthToolkit(); @@ -204,93 +200,281 @@ describe('ProductFeaturesService', () => { expect(mockHttpSetup.registerOnPostAuth).toHaveBeenCalledTimes(1); }); - it('should authorize when no tag matches', async () => { - const experimentalFeatures = {} as ExperimentalFeatures; - const productFeaturesService = new ProductFeaturesService( - loggerMock.create(), - experimentalFeatures - ); - productFeaturesService.registerApiAccessControl(mockHttpSetup); - - await lastRegisteredFn(getReq(['access:something', 'access:securitySolution']), res, toolkit); - - expect(MockedProductFeatures.mock.instances[0].isActionRegistered).not.toHaveBeenCalled(); - expect(res.notFound).not.toHaveBeenCalled(); - expect(toolkit.next).toHaveBeenCalledTimes(1); - }); - - it('should check when tag matches and return not found when not action registered', async () => { - const experimentalFeatures = {} as ExperimentalFeatures; - const productFeaturesService = new ProductFeaturesService( - loggerMock.create(), - experimentalFeatures - ); - productFeaturesService.registerApiAccessControl(mockHttpSetup); - - (MockedProductFeatures.mock.instances[0].isActionRegistered as jest.Mock).mockReturnValueOnce( - false - ); - await lastRegisteredFn(getReq(['access:securitySolution-foo']), res, toolkit); - - expect(MockedProductFeatures.mock.instances[0].isActionRegistered).toHaveBeenCalledWith( - 'api:securitySolution-foo' - ); - expect(res.notFound).toHaveBeenCalledTimes(1); - expect(toolkit.next).not.toHaveBeenCalled(); - }); - - it('should check when tag matches and continue when action registered', async () => { - const experimentalFeatures = {} as ExperimentalFeatures; - const productFeaturesService = new ProductFeaturesService( - loggerMock.create(), - experimentalFeatures - ); - productFeaturesService.registerApiAccessControl(mockHttpSetup); - - (MockedProductFeatures.mock.instances[0].isActionRegistered as jest.Mock).mockReturnValueOnce( - true - ); - await lastRegisteredFn(getReq(['access:securitySolution-foo']), res, toolkit); - - expect(MockedProductFeatures.mock.instances[0].isActionRegistered).toHaveBeenCalledWith( - 'api:securitySolution-foo' - ); - expect(res.notFound).not.toHaveBeenCalled(); - expect(toolkit.next).toHaveBeenCalledTimes(1); - }); - - it('should check when productFeature tag when it matches and return not found when not enabled', async () => { - const experimentalFeatures = {} as ExperimentalFeatures; - const productFeaturesService = new ProductFeaturesService( - loggerMock.create(), - experimentalFeatures - ); - productFeaturesService.registerApiAccessControl(mockHttpSetup); - - productFeaturesService.isEnabled = jest.fn().mockReturnValueOnce(false); - - await lastRegisteredFn(getReq(['securitySolutionProductFeature:foo']), res, toolkit); - - expect(productFeaturesService.isEnabled).toHaveBeenCalledWith('foo'); - expect(res.notFound).toHaveBeenCalledTimes(1); - expect(toolkit.next).not.toHaveBeenCalled(); + describe('when using productFeature tag', () => { + const getReq = (tags: string[] = []) => + ({ + route: { options: { tags } }, + url: { pathname: '', search: '' }, + } as unknown as KibanaRequest); + + it('should check when productFeature tag when it matches and return not found when not enabled', async () => { + const experimentalFeatures = {} as ExperimentalFeatures; + const productFeaturesService = new ProductFeaturesService( + loggerMock.create(), + experimentalFeatures + ); + productFeaturesService.registerApiAccessControl(mockHttpSetup); + + productFeaturesService.isEnabled = jest.fn().mockReturnValueOnce(false); + + await lastRegisteredFn(getReq(['securitySolutionProductFeature:foo']), res, toolkit); + + expect(productFeaturesService.isEnabled).toHaveBeenCalledWith('foo'); + expect(res.notFound).toHaveBeenCalledTimes(1); + expect(toolkit.next).not.toHaveBeenCalled(); + }); + + it('should check when productFeature tag when it matches and continue when enabled', async () => { + const experimentalFeatures = {} as ExperimentalFeatures; + const productFeaturesService = new ProductFeaturesService( + loggerMock.create(), + experimentalFeatures + ); + productFeaturesService.registerApiAccessControl(mockHttpSetup); + + productFeaturesService.isEnabled = jest.fn().mockReturnValueOnce(true); + + await lastRegisteredFn(getReq(['securitySolutionProductFeature:foo']), res, toolkit); + + expect(productFeaturesService.isEnabled).toHaveBeenCalledWith('foo'); + expect(res.notFound).not.toHaveBeenCalled(); + expect(toolkit.next).toHaveBeenCalledTimes(1); + }); }); - it('should check when productFeature tag when it matches and continue when enabled', async () => { - const experimentalFeatures = {} as ExperimentalFeatures; - const productFeaturesService = new ProductFeaturesService( - loggerMock.create(), - experimentalFeatures - ); - productFeaturesService.registerApiAccessControl(mockHttpSetup); - - productFeaturesService.isEnabled = jest.fn().mockReturnValueOnce(true); - - await lastRegisteredFn(getReq(['securitySolutionProductFeature:foo']), res, toolkit); - - expect(productFeaturesService.isEnabled).toHaveBeenCalledWith('foo'); - expect(res.notFound).not.toHaveBeenCalled(); - expect(toolkit.next).toHaveBeenCalledTimes(1); + // Documentation: https://docs.elastic.dev/kibana-dev-docs/key-concepts/security-api-authorization + describe('when using authorization', () => { + let productFeaturesService: ProductFeaturesService; + let mockIsActionRegistered: jest.Mock; + + beforeEach(() => { + const experimentalFeatures = {} as ExperimentalFeatures; + productFeaturesService = new ProductFeaturesService( + loggerMock.create(), + experimentalFeatures + ); + productFeaturesService.registerApiAccessControl(mockHttpSetup); + mockIsActionRegistered = MockedProductFeatures.mock.instances[0] + .isActionRegistered as jest.Mock; + }); + + describe('when using access tag', () => { + const getReq = (tags: string[] = []) => + ({ + route: { options: { tags } }, + url: { pathname: '', search: '' }, + } as unknown as KibanaRequest); + + it('should authorize when no tag matches', async () => { + await lastRegisteredFn( + getReq(['access:something', 'access:securitySolution']), + res, + toolkit + ); + + expect(mockIsActionRegistered).not.toHaveBeenCalled(); + expect(res.notFound).not.toHaveBeenCalled(); + expect(toolkit.next).toHaveBeenCalledTimes(1); + }); + + it('should check when tag matches and return not found when not action registered', async () => { + mockIsActionRegistered.mockReturnValueOnce(false); + await lastRegisteredFn(getReq(['access:securitySolution-foo']), res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-foo'); + expect(res.notFound).toHaveBeenCalledTimes(1); + expect(toolkit.next).not.toHaveBeenCalled(); + }); + + it('should check when tag matches and continue when action registered', async () => { + mockIsActionRegistered.mockReturnValueOnce(true); + await lastRegisteredFn(getReq(['access:securitySolution-foo']), res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-foo'); + expect(res.notFound).not.toHaveBeenCalled(); + expect(toolkit.next).toHaveBeenCalledTimes(1); + }); + }); + + describe('when using security authz', () => { + beforeEach(() => { + mockIsActionRegistered.mockImplementation((action: string) => action.includes('enabled')); + }); + + const getReq = (requiredPrivileges?: AuthzEnabled['requiredPrivileges']) => + ({ + route: { options: { security: { authz: { requiredPrivileges } } } }, + url: { pathname: '', search: '' }, + } as unknown as KibanaRequest); + + it('should authorize when no privilege matches', async () => { + await lastRegisteredFn(getReq(['something', 'securitySolution']), res, toolkit); + + expect(mockIsActionRegistered).not.toHaveBeenCalled(); + expect(res.notFound).not.toHaveBeenCalled(); + expect(toolkit.next).toHaveBeenCalledTimes(1); + }); + + it('should check when privilege matches and return not found when not action registered', async () => { + await lastRegisteredFn(getReq(['securitySolution-disabled']), res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-disabled'); + expect(res.notFound).toHaveBeenCalledTimes(1); + expect(toolkit.next).not.toHaveBeenCalled(); + }); + + it('should check when privilege matches and continue when action registered', async () => { + mockIsActionRegistered.mockReturnValueOnce(true); + await lastRegisteredFn(getReq(['securitySolution-enabled']), res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-enabled'); + expect(res.notFound).not.toHaveBeenCalled(); + expect(toolkit.next).toHaveBeenCalledTimes(1); + }); + + it('should restrict access when one action is not registered', async () => { + mockIsActionRegistered.mockReturnValueOnce(true); + await lastRegisteredFn( + getReq([ + 'securitySolution-enabled', + 'securitySolution-disabled', + 'securitySolution-enabled2', + ]), + res, + toolkit + ); + + expect(mockIsActionRegistered).toHaveBeenCalledTimes(2); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-enabled'); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-disabled'); + + expect(res.notFound).toHaveBeenCalledTimes(1); + expect(toolkit.next).not.toHaveBeenCalled(); + }); + + describe('when using nested requiredPrivileges', () => { + describe('when using allRequired', () => { + it('should allow access when all actions are registered', async () => { + const req = getReq([ + { + allRequired: [ + 'securitySolution-enabled', + 'securitySolution-enabled2', + 'securitySolution-enabled3', + ], + }, + ]); + await lastRegisteredFn(req, res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledTimes(3); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-enabled'); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-enabled2'); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-enabled3'); + + expect(res.notFound).not.toHaveBeenCalled(); + expect(toolkit.next).toHaveBeenCalledTimes(1); + }); + + it('should restrict access if one action is not registered', async () => { + const req = getReq([ + { + allRequired: [ + 'securitySolution-enabled', + 'securitySolution-disabled', + 'securitySolution-notCalled', + ], + }, + ]); + await lastRegisteredFn(req, res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledTimes(2); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-enabled'); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-disabled'); + + expect(res.notFound).toHaveBeenCalledTimes(1); + expect(toolkit.next).not.toHaveBeenCalled(); + }); + + it('should allow only based on security privileges and ignore non-security', async () => { + const req = getReq([ + { allRequired: ['notSecurityPrivilege', 'securitySolution-enabled'] }, + ]); + await lastRegisteredFn(req, res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledTimes(1); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-enabled'); + + expect(res.notFound).not.toHaveBeenCalled(); + expect(toolkit.next).toHaveBeenCalledTimes(1); + }); + + it('should restrict only based on security privileges and ignore non-security', async () => { + const req = getReq([ + { allRequired: ['notSecurityPrivilege', 'securitySolution-disabled'] }, + ]); + await lastRegisteredFn(req, res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledTimes(1); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-disabled'); + + expect(res.notFound).toHaveBeenCalledTimes(1); + expect(toolkit.next).not.toHaveBeenCalled(); + }); + }); + + describe('when using anyRequired', () => { + it('should allow access when one action is registered', async () => { + const req = getReq([ + { + anyRequired: [ + 'securitySolution-disabled', + 'securitySolution-enabled', + 'securitySolution-notCalled', + ], + }, + ]); + await lastRegisteredFn(req, res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledTimes(2); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-disabled'); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-enabled'); + + expect(res.notFound).not.toHaveBeenCalled(); + expect(toolkit.next).toHaveBeenCalledTimes(1); + }); + + it('should restrict access when no action is registered', async () => { + const req = getReq([ + { + anyRequired: ['securitySolution-disabled', 'securitySolution-disabled2'], + }, + ]); + await lastRegisteredFn(req, res, toolkit); + + expect(mockIsActionRegistered).toHaveBeenCalledTimes(2); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-disabled'); + expect(mockIsActionRegistered).toHaveBeenCalledWith('api:securitySolution-disabled2'); + + expect(res.notFound).toHaveBeenCalledTimes(1); + expect(toolkit.next).not.toHaveBeenCalled(); + }); + + it('should restrict only based on security privileges and allow when non-security privilege is present', async () => { + const req = getReq([ + { + anyRequired: ['notSecurityPrivilege', 'securitySolution-disabled'], + }, + ]); + await lastRegisteredFn(req, res, toolkit); + + expect(mockIsActionRegistered).not.toHaveBeenCalled(); + + expect(res.notFound).not.toHaveBeenCalled(); + expect(toolkit.next).toHaveBeenCalledTimes(1); + }); + }); + }); + }); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.ts b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.ts index 29ef513b40bb3..86928ff905545 100644 --- a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.ts +++ b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.ts @@ -11,7 +11,7 @@ * 2.0. */ -import type { HttpServiceSetup, Logger } from '@kbn/core/server'; +import type { AuthzEnabled, HttpServiceSetup, Logger, RouteAuthz } from '@kbn/core/server'; import { hiddenTypes as filesSavedObjectTypes } from '@kbn/files-plugin/server/saved_objects'; import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { ProductFeatureKeyType } from '@kbn/security-solution-features'; @@ -21,6 +21,7 @@ import { getCasesFeature, getSecurityFeature, } from '@kbn/security-solution-features/product_features'; +import type { RecursiveReadonly } from '@kbn/utility-types'; import type { ExperimentalFeatures } from '../../../common'; import { APP_ID } from '../../../common'; import { ProductFeatures } from './product_features'; @@ -28,6 +29,9 @@ import type { ProductFeaturesConfigurator } from './types'; import { securityDefaultSavedObjects } from './security_saved_objects'; import { casesApiTags, casesUiCapabilities } from './cases_privileges'; +// The prefix ("securitySolution-") used by all the Security Solution API action privileges. +export const API_ACTION_PREFIX = `${APP_ID}-`; + export class ProductFeaturesService { private securityProductFeatures: ProductFeatures; private casesProductFeatures: ProductFeatures; @@ -116,8 +120,6 @@ export class ProductFeaturesService { return this.productFeatures.has(productFeatureKey); } - public getApiActionName = (apiPrivilege: string) => `api:${APP_ID}-${apiPrivilege}`; - public isActionRegistered(action: string) { return ( this.securityProductFeatures.isActionRegistered(action) || @@ -127,6 +129,9 @@ export class ProductFeaturesService { ); } + public getApiActionName = (apiPrivilege: string) => `api:${API_ACTION_PREFIX}${apiPrivilege}`; + + /** @deprecated Use security.authz.requiredPrivileges instead */ public isApiPrivilegeEnabled(apiPrivilege: string) { return this.isActionRegistered(this.getApiActionName(apiPrivilege)); } @@ -135,14 +140,24 @@ export class ProductFeaturesService { // The `securitySolutionProductFeature:` prefix is used for ProductFeature based control. // Should be used only by routes that do not need RBAC, only direct productFeature control. const APP_FEATURE_TAG_PREFIX = 'securitySolutionProductFeature:'; - // The "access:securitySolution-" prefix is used for API action based control. - // Should be used by routes that need RBAC, extending the `access:` role privilege check from the security plugin. - // An additional check is performed to ensure the privilege has been registered by the productFeature service, - // preventing full access (`*`) roles, such as superuser, from bypassing productFeature controls. + + /** @deprecated Use security.authz.requiredPrivileges instead */ const API_ACTION_TAG_PREFIX = `access:${APP_ID}-`; + const isAuthzEnabled = (authz?: RecursiveReadonly): authz is AuthzEnabled => { + return Boolean((authz as AuthzEnabled)?.requiredPrivileges); + }; + + /** Returns true only if the API privilege is a security action and is disabled */ + const isApiPrivilegeSecurityAndDisabled = (apiPrivilege: string): boolean => { + if (apiPrivilege.startsWith(API_ACTION_PREFIX)) { + return !this.isActionRegistered(`api:${apiPrivilege}`); + } + return false; + }; + http.registerOnPostAuth((request, response, toolkit) => { - for (const tag of request.route.options.tags) { + for (const tag of request.route.options.tags ?? []) { let isEnabled = true; if (tag.startsWith(APP_FEATURE_TAG_PREFIX)) { isEnabled = this.isEnabled( @@ -159,6 +174,36 @@ export class ProductFeaturesService { return response.notFound(); } } + + // This control ensures the action privileges have been registered by the productFeature service, + // preventing full access (`*`) roles, such as superuser, from bypassing productFeature controls. + const authz = request.route.options.security?.authz; + if (isAuthzEnabled(authz)) { + const disabled = authz.requiredPrivileges.some((privilegeEntry) => { + if (typeof privilegeEntry === 'object') { + if (privilegeEntry.allRequired) { + if (privilegeEntry.allRequired.some(isApiPrivilegeSecurityAndDisabled)) { + return true; + } + } + if (privilegeEntry.anyRequired) { + if (privilegeEntry.anyRequired.every(isApiPrivilegeSecurityAndDisabled)) { + return true; + } + } + return false; + } else { + return isApiPrivilegeSecurityAndDisabled(privilegeEntry); + } + }); + if (disabled) { + this.logger.warn( + `Accessing disabled route "${request.url.pathname}${request.url.search}": responding with 404` + ); + return response.notFound(); + } + } + return toolkit.next(); }); } diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts index 8e50e4590a72f..50e0e0be47cdd 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts @@ -27,8 +27,6 @@ export const INSIGHTS_CHANNEL = 'security-insights-v1'; export const TASK_METRICS_CHANNEL = 'task-metrics'; -export const DEFAULT_DIAGNOSTIC_INDEX = '.logs-endpoint.diagnostic.collection-*' as const; - export const DEFAULT_ADVANCED_POLICY_CONFIG_SETTINGS = { linux: { advanced: { diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts b/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts index b8a2df85f10ad..02a39be555110 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts @@ -128,6 +128,69 @@ export const ASSET_CRITICALITY_SYSTEM_PROCESSED_ASSIGNMENT_FILE_EVENT: EventType }, }; +export const FIELD_RETENTION_ENRICH_POLICY_EXECUTION_EVENT: EventTypeOpts<{ + duration: number; + interval: string; +}> = { + eventType: 'field_retention_enrich_policy_execution', + schema: { + duration: { + type: 'long', + _meta: { + description: 'Duration (in seconds) of the field retention enrich policy execution time', + }, + }, + interval: { + type: 'keyword', + _meta: { + description: 'Configured interval for the field retention enrich policy task', + }, + }, + }, +}; + +export const ENTITY_ENGINE_RESOURCE_INIT_FAILURE_EVENT: EventTypeOpts<{ + error: string; +}> = { + eventType: 'entity_engine_resource_init_failure', + schema: { + error: { + type: 'keyword', + _meta: { + description: 'Error message for a resource initialization failure', + }, + }, + }, +}; + +export const ENTITY_ENGINE_INITIALIZATION_EVENT: EventTypeOpts<{ + duration: number; +}> = { + eventType: 'entity_engine_initialization', + schema: { + duration: { + type: 'long', + _meta: { + description: 'Duration (in seconds) of the entity engine initialization', + }, + }, + }, +}; + +export const ENTITY_STORE_USAGE_EVENT: EventTypeOpts<{ + storeSize: number; +}> = { + eventType: 'entity_store_usage', + schema: { + storeSize: { + type: 'long', + _meta: { + description: 'Number of entities stored in the entity store', + }, + }, + }, +}; + export const ALERT_SUPPRESSION_EVENT: EventTypeOpts<{ suppressionAlertsCreated: number; suppressionAlertsSuppressed: number; @@ -390,4 +453,8 @@ export const events = [ ENDPOINT_RESPONSE_ACTION_SENT_EVENT, ENDPOINT_RESPONSE_ACTION_SENT_ERROR_EVENT, ENDPOINT_RESPONSE_ACTION_STATUS_CHANGE_EVENT, + FIELD_RETENTION_ENRICH_POLICY_EXECUTION_EVENT, + ENTITY_ENGINE_RESOURCE_INIT_FAILURE_EVENT, + ENTITY_ENGINE_INITIALIZATION_EVENT, + ENTITY_STORE_USAGE_EVENT, ]; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts index 22f85d19c83d8..4d2ff971eeb62 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts @@ -48,6 +48,7 @@ import type { } from '@kbn/fleet-plugin/server'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; import moment from 'moment'; +import { DEFAULT_DIAGNOSTIC_INDEX_PATTERN } from '../../../common/endpoint/constants'; import type { ExperimentalFeatures } from '../../../common'; import type { EndpointAppContextService } from '../../endpoint/endpoint_app_context_services'; import { @@ -85,7 +86,6 @@ import type { import { telemetryConfiguration } from './configuration'; import { ENDPOINT_METRICS_INDEX } from '../../../common/constants'; import { PREBUILT_RULES_PACKAGE_NAME } from '../../../common/detection_engine/constants'; -import { DEFAULT_DIAGNOSTIC_INDEX } from './constants'; import type { TelemetryLogger } from './telemetry_logger'; export interface ITelemetryReceiver { @@ -546,7 +546,7 @@ export class TelemetryReceiver implements ITelemetryReceiver { to: executeTo, } as LogMeta); - let pitId = await this.openPointInTime(DEFAULT_DIAGNOSTIC_INDEX); + let pitId = await this.openPointInTime(DEFAULT_DIAGNOSTIC_INDEX_PATTERN); let fetchMore = true; let searchAfter: SortResults | undefined; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.ts index 35f5abeac10af..ec401a093c348 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.ts @@ -6,11 +6,12 @@ */ import type { Logger } from '@kbn/core/server'; +import { DEFAULT_DIAGNOSTIC_INDEX_PATTERN } from '../../../../common/endpoint/constants'; import type { ITelemetryEventsSender } from '../sender'; import type { ITelemetryReceiver } from '../receiver'; import type { TaskExecutionPeriod } from '../task'; import type { ITaskMetricsService } from '../task_metrics.types'; -import { DEFAULT_DIAGNOSTIC_INDEX, TELEMETRY_CHANNEL_TIMELINE } from '../constants'; +import { TELEMETRY_CHANNEL_TIMELINE } from '../constants'; import { ranges, TelemetryTimelineFetcher, newTelemetryLogger } from '../helpers'; export function createTelemetryDiagnosticTimelineTaskConfig() { @@ -43,7 +44,7 @@ export function createTelemetryDiagnosticTimelineTaskConfig() { const { rangeFrom, rangeTo } = ranges(taskExecutionPeriod); const alerts = await receiver.fetchTimelineAlerts( - DEFAULT_DIAGNOSTIC_INDEX, + DEFAULT_DIAGNOSTIC_INDEX_PATTERN, rangeFrom, rangeTo ); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts index 905e28872a5a4..90ec0bce1be00 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { StartServicesAccessor } from '@kbn/core-lifecycle-server'; +import type { StartPlugins } from '../../../plugin_contract'; import type { SecuritySolutionPluginRouter } from '../../../types'; import type { ConfigType } from '../../..'; import { @@ -27,7 +29,11 @@ import { persistNoteRoute, deleteNoteRoute, getNotesRoute } from './notes'; import { persistPinnedEventRoute } from './pinned_events'; -export function registerTimelineRoutes(router: SecuritySolutionPluginRouter, config: ConfigType) { +export function registerTimelineRoutes( + router: SecuritySolutionPluginRouter, + config: ConfigType, + startServices: StartServicesAccessor +) { createTimelinesRoute(router); patchTimelinesRoute(router); @@ -46,7 +52,7 @@ export function registerTimelineRoutes(router: SecuritySolutionPluginRouter, con persistNoteRoute(router); deleteNoteRoute(router); - getNotesRoute(router); + getNotesRoute(router, startServices); persistPinnedEventRoute(router); } diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts index 7b8c732ae54ca..0cd7853b38a1b 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts @@ -15,6 +15,9 @@ import type { } from '@kbn/core-saved-objects-api-server'; import type { KueryNode } from '@kbn/es-query'; import { nodeBuilder, nodeTypes } from '@kbn/es-query'; +import type { StartServicesAccessor } from '@kbn/core-lifecycle-server'; +import type { UserProfile } from '@kbn/core-user-profile-common'; +import type { StartPlugins } from '../../../../plugin_contract'; import { AssociatedFilter } from '../../../../../common/notes/constants'; import { timelineSavedObjectType } from '../../saved_object_mappings'; import type { SecuritySolutionPluginRouter } from '../../../../types'; @@ -27,7 +30,10 @@ import { noteSavedObjectType } from '../../saved_object_mappings/notes'; import { GetNotesRequestQuery, type GetNotesResponse } from '../../../../../common/api/timeline'; /* eslint-disable complexity */ -export const getNotesRoute = (router: SecuritySolutionPluginRouter) => { +export const getNotesRoute = ( + router: SecuritySolutionPluginRouter, + startServices: StartServicesAccessor +) => { router.versioned .get({ path: NOTE_URL, @@ -139,11 +145,41 @@ export const getNotesRoute = (router: SecuritySolutionPluginRouter) => { const filterKueryNodeArray = [filterAsKueryNode]; // retrieve all the notes created by a specific user - const userFilter = queryParams?.userFilter; - if (userFilter) { - filterKueryNodeArray.push( - nodeBuilder.is(`${noteSavedObjectType}.attributes.createdBy`, userFilter) - ); + // the createdByFilter value is the uuid of the user + const createdByFilter = queryParams?.createdByFilter; // now uuid + if (createdByFilter) { + // because the notes createdBy property can be either full_name, email or username + // see pickSaveNote (https://github.com/elastic/kibana/blob/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts#L302) + // which uses the getUserDisplayName (https://github.com/elastic/kibana/blob/main/packages/kbn-user-profile-components/src/user_profile.ts#L138) + const [_, { security }] = await startServices(); + const users: UserProfile[] = await security.userProfiles.bulkGet({ + uids: new Set([createdByFilter]), + }); + // once we retrieve the user by the uuid we can search all the notes that have the createdBy property with full_name, email or username values + if (users && users.length > 0) { + const { + user: { email, full_name: fullName, username: userName }, + } = users[0]; + const createdByNodeArray = []; + if (fullName) { + createdByNodeArray.push( + nodeBuilder.is(`${noteSavedObjectType}.attributes.createdBy`, fullName) + ); + } + if (userName) { + createdByNodeArray.push( + nodeBuilder.is(`${noteSavedObjectType}.attributes.createdBy`, userName) + ); + } + if (email) { + createdByNodeArray.push( + nodeBuilder.is(`${noteSavedObjectType}.attributes.createdBy`, email) + ); + } + filterKueryNodeArray.push(nodeBuilder.or(createdByNodeArray)); + } else { + throw new Error(`User with uid ${createdByFilter} not found`); + } } const associatedFilter = queryParams?.associatedFilter; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 794c37cd38b40..5b43aabbd0b62 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -19,6 +19,7 @@ import type { ILicense } from '@kbn/licensing-plugin/server'; import type { NewPackagePolicy, UpdatePackagePolicy } from '@kbn/fleet-plugin/common'; import { FLEET_ENDPOINT_PACKAGE } from '@kbn/fleet-plugin/common'; +import { ensureIndicesExistsForPolicies } from './endpoint/migrations/ensure_indices_exists_for_policies'; import { CompleteExternalResponseActionsTask } from './endpoint/lib/response_actions'; import { registerAgentRoutes } from './endpoint/routes/agent'; import { endpointPackagePoliciesStatsSearchStrategyProvider } from './search_strategy/endpoint_package_policies_stats'; @@ -232,6 +233,7 @@ export class Plugin implements ISecuritySolutionPlugin { registerEntityStoreFieldRetentionEnrichTask({ getStartServices: core.getStartServices, logger: this.logger, + telemetry: core.analytics, taskManager: plugins.taskManager, }); } @@ -605,8 +607,10 @@ export class Plugin implements ISecuritySolutionPlugin { plugins.fleet .fleetSetupCompleted() .then(async () => { + logger.info('Dependent plugin setup complete'); + if (this.manifestTask) { - logger.info('Dependent plugin setup complete - Starting ManifestTask'); + logger.info('Starting ManifestTask'); await this.manifestTask.start({ taskManager, }); @@ -624,6 +628,10 @@ export class Plugin implements ISecuritySolutionPlugin { ); await turnOffAgentPolicyFeatures(fleetServices, productFeaturesService, logger); + + // Ensure policies have backing DOT indices (We don't need to `await` this. + // It can run in the background) + ensureIndicesExistsForPolicies(this.endpointAppContextService).catch(() => {}); }) .catch(() => {}); diff --git a/x-pack/plugins/security_solution/server/request_context_factory.ts b/x-pack/plugins/security_solution/server/request_context_factory.ts index 8e3af9b9bce8a..bd5c29651e26e 100644 --- a/x-pack/plugins/security_solution/server/request_context_factory.ts +++ b/x-pack/plugins/security_solution/server/request_context_factory.ts @@ -225,6 +225,8 @@ export class RequestContextFactory implements IRequestContextFactory { taskManager: startPlugins.taskManager, auditLogger: getAuditLogger(), kibanaVersion: options.kibanaVersion, + config: config.entityAnalytics.entityStore, + telemetry: core.analytics, }); }), }; diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts index 0b80d142e14ce..8fb74afc770b5 100644 --- a/x-pack/plugins/security_solution/server/routes/index.ts +++ b/x-pack/plugins/security_solution/server/routes/index.ts @@ -100,7 +100,7 @@ export const initRoutes = ( registerResolverRoutes(router, getStartServices, config); - registerTimelineRoutes(router, config); + registerTimelineRoutes(router, config, getStartServices); // Detection Engine Signals routes that have the REST endpoints of /api/detection_engine/signals // POST /api/detection_engine/signals/status diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 15d082d32edda..a84f21c047ea8 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -231,5 +231,7 @@ "@kbn/serverless", "@kbn/core-user-profile-browser", "@kbn/data-stream-adapter", + "@kbn/core-lifecycle-server", + "@kbn/core-user-profile-common", ] } diff --git a/x-pack/plugins/serverless/public/plugin.tsx b/x-pack/plugins/serverless/public/plugin.tsx index 82578123452e7..dbb75788c105b 100644 --- a/x-pack/plugins/serverless/public/plugin.tsx +++ b/x-pack/plugins/serverless/public/plugin.tsx @@ -61,7 +61,7 @@ export class ServerlessPlugin const { currentType } = developer.projectSwitcher; core.chrome.navControls.registerRight({ - order: 500, + order: 5000, mount: (target) => this.mountProjectSwitcher(target, core, currentType), }); } diff --git a/x-pack/plugins/serverless/public/types.ts b/x-pack/plugins/serverless/public/types.ts index 4627d24659b8e..3a416a676ee92 100644 --- a/x-pack/plugins/serverless/public/types.ts +++ b/x-pack/plugins/serverless/public/types.ts @@ -10,6 +10,7 @@ import type { ChromeSetProjectBreadcrumbsParams, SideNavComponent, NavigationTreeDefinition, + SolutionId, } from '@kbn/core-chrome-browser'; import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; import type { Observable } from 'rxjs'; @@ -26,7 +27,7 @@ export interface ServerlessPluginStart { ) => void; setProjectHome(homeHref: string): void; initNavigation( - id: string, + id: SolutionId, navigationTree$: Observable, config?: { dataTestSubj?: string; diff --git a/x-pack/plugins/serverless_search/public/navigation_tree.ts b/x-pack/plugins/serverless_search/public/navigation_tree.ts index 3906eb8b2b864..b0f5a4658e7d2 100644 --- a/x-pack/plugins/serverless_search/public/navigation_tree.ts +++ b/x-pack/plugins/serverless_search/public/navigation_tree.ts @@ -130,18 +130,19 @@ export const navigationTree = (): NavigationTreeDefinition => ({ spaceBefore: 'm', children: [{ link: 'maps' }], }, - { - id: 'gettingStarted', - title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', { - defaultMessage: 'Getting Started', - }), - link: 'serverlessElasticsearch', - spaceBefore: 'm', - }, ], }, ], footer: [ + { + id: 'gettingStarted', + type: 'navItem', + title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', { + defaultMessage: 'Getting Started', + }), + link: 'serverlessElasticsearch', + icon: 'launch', + }, { type: 'navGroup', id: 'project_settings_project_nav', diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts index 491252a6d9e9f..3d246e4be2929 100644 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -149,7 +149,7 @@ export class ServerlessSearchPlugin serverless.setProjectHome(services.searchIndices.startRoute); const navigationTree$ = of(navigationTree()); - serverless.initNavigation('search', navigationTree$, { dataTestSubj: 'svlSearchSideNav' }); + serverless.initNavigation('es', navigationTree$, { dataTestSubj: 'svlSearchSideNav' }); const extendCardNavDefinitions = serverless.getNavigationCards( security.authz.isRoleManagementEnabled() diff --git a/x-pack/plugins/snapshot_restore/public/application/components/disable_tooltip.tsx b/x-pack/plugins/snapshot_restore/public/application/components/disable_tooltip.tsx new file mode 100644 index 0000000000000..8d82705b27022 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/application/components/disable_tooltip.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ReactElement } from 'react'; +import { EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export const MANAGED_REPOSITORY_TOOLTIP_MESSAGE = i18n.translate( + 'xpack.snapshotRestore.repositoryForm.disableToolTip', + { + defaultMessage: 'This field is disabled because you are editing a managed repository.', + } +); + +export const MANAGED_POLICY_TOOLTIP_MESSAGE = i18n.translate( + 'xpack.snapshotRestore.policyForm.disableToolTip', + { + defaultMessage: 'This field is disabled because you are editing a managed policy.', + } +); + +interface Props { + isManaged?: boolean; + tooltipMessage: string; + component: ReactElement; +} + +/** + * Component that wraps a given component (disabled field) with a tooltip if a repository + * or policy is managed (isManaged === true). + * + * @param {boolean} isManaged - Determines if the tooltip should be displayed. + * @param {string} tooltipMessage - The message to display inside the tooltip. + * @param {React.ReactElement} component - The component to wrap with the tooltip. + */ +export const DisableToolTip: React.FunctionComponent = ({ + isManaged, + tooltipMessage, + component, +}) => { + return isManaged ? ( + + {component} + + ) : ( + component + ); +}; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx index 2ad6c88af5f13..36fd8c10f684b 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx @@ -33,6 +33,7 @@ import { useLoadRepositories } from '../../../services/http'; import { linkToAddRepository } from '../../../services/navigation'; import { InlineLoading } from '../..'; import { StepProps } from '.'; +import { DisableToolTip, MANAGED_POLICY_TOOLTIP_MESSAGE } from '../../disable_tooltip'; export const PolicyStepLogistics: React.FunctionComponent = ({ policy, @@ -258,22 +259,28 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ } return ( - ({ - value: name, - text: name, - }))} - hasNoInitialSelection={!doesRepositoryExist} - value={!doesRepositoryExist ? '' : policy.repository} - onBlur={() => setTouched({ ...touched, repository: true })} - onChange={(e) => { - updatePolicy({ - repository: e.target.value, - }); - }} - fullWidth - data-test-subj="repositorySelect" - disabled={policy?.isManagedPolicy && isEditing} + ({ + value: name, + text: name, + }))} + hasNoInitialSelection={!doesRepositoryExist} + value={!doesRepositoryExist ? '' : policy.repository} + onBlur={() => setTouched({ ...touched, repository: true })} + onChange={(e) => { + updatePolicy({ + repository: e.target.value, + }); + }} + fullWidth + data-test-subj="repositorySelect" + disabled={policy?.isManagedPolicy && isEditing} + /> + } /> ); }; @@ -325,25 +332,31 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ } fullWidth > - { - updatePolicy({ - snapshotName: e.target.value, - }); - }} - onBlur={() => setTouched({ ...touched, snapshotName: true })} - placeholder={i18n.translate( - 'xpack.snapshotRestore.policyForm.stepLogistics.policySnapshotNamePlaceholder', - { - defaultMessage: `''`, - description: - 'Example date math snapshot name. Keeping the same syntax is important: ', - } - )} - data-test-subj="snapshotNameInput" - disabled={policy?.isManagedPolicy && isEditing} + { + updatePolicy({ + snapshotName: e.target.value, + }); + }} + onBlur={() => setTouched({ ...touched, snapshotName: true })} + placeholder={i18n.translate( + 'xpack.snapshotRestore.policyForm.stepLogistics.policySnapshotNamePlaceholder', + { + defaultMessage: `''`, + description: + 'Example date math snapshot name. Keeping the same syntax is important: ', + } + )} + data-test-subj="snapshotNameInput" + disabled={policy?.isManagedPolicy && isEditing} + /> + } /> diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/azure_settings.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/azure_settings.tsx index da061fa8c2abb..9f33e23a9cb29 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/azure_settings.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/azure_settings.tsx @@ -18,6 +18,7 @@ import { import { AzureRepository, Repository } from '../../../../../common/types'; import { RepositorySettingsValidation } from '../../../services/validation'; import { ChunkSizeField, MaxSnapshotsField, MaxRestoreField } from './common'; +import { DisableToolTip, MANAGED_REPOSITORY_TOOLTIP_MESSAGE } from '../../disable_tooltip'; interface Props { repository: AzureRepository; @@ -94,16 +95,22 @@ export const AzureSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.client)} error={settingErrors.client} > - { - updateRepositorySettings({ - client: e.target.value, - }); - }} - data-test-subj="clientInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + client: e.target.value, + }); + }} + data-test-subj="clientInput" + disabled={isManagedRepository} + /> + } /> @@ -139,16 +146,22 @@ export const AzureSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.container)} error={settingErrors.container} > - { - updateRepositorySettings({ - container: e.target.value, - }); - }} - data-test-subj="containerInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + container: e.target.value, + }); + }} + data-test-subj="containerInput" + disabled={isManagedRepository} + /> + } /> @@ -184,16 +197,22 @@ export const AzureSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.basePath)} error={settingErrors.basePath} > - { - updateRepositorySettings({ - basePath: e.target.value, - }); - }} - data-test-subj="basePathInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + basePath: e.target.value, + }); + }} + data-test-subj="basePathInput" + disabled={isManagedRepository} + /> + } /> diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/gcs_settings.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/gcs_settings.tsx index 865a628b984b6..75272fec0c7e1 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/gcs_settings.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/gcs_settings.tsx @@ -12,6 +12,7 @@ import { EuiDescribedFormGroup, EuiFieldText, EuiFormRow, EuiSwitch, EuiTitle } import { GCSRepository, Repository } from '../../../../../common/types'; import { RepositorySettingsValidation } from '../../../services/validation'; import { ChunkSizeField, MaxSnapshotsField, MaxRestoreField } from './common'; +import { DisableToolTip, MANAGED_REPOSITORY_TOOLTIP_MESSAGE } from '../../disable_tooltip'; interface Props { repository: GCSRepository; @@ -82,16 +83,22 @@ export const GCSSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.client)} error={settingErrors.client} > - { - updateRepositorySettings({ - client: e.target.value, - }); - }} - data-test-subj="clientInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + client: e.target.value, + }); + }} + data-test-subj="clientInput" + disabled={isManagedRepository} + /> + } /> @@ -127,16 +134,22 @@ export const GCSSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.bucket)} error={settingErrors.bucket} > - { - updateRepositorySettings({ - bucket: e.target.value, - }); - }} - data-test-subj="bucketInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + bucket: e.target.value, + }); + }} + data-test-subj="bucketInput" + disabled={isManagedRepository} + /> + } /> @@ -172,16 +185,22 @@ export const GCSSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.basePath)} error={settingErrors.basePath} > - { - updateRepositorySettings({ - basePath: e.target.value, - }); - }} - data-test-subj="basePathInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + basePath: e.target.value, + }); + }} + data-test-subj="basePathInput" + disabled={isManagedRepository} + /> + } /> diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/s3_settings.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/s3_settings.tsx index 88398315a327c..dd9953cf93a78 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/s3_settings.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/s3_settings.tsx @@ -20,6 +20,7 @@ import { import { Repository, S3Repository } from '../../../../../common/types'; import { RepositorySettingsValidation } from '../../../services/validation'; import { ChunkSizeField, MaxSnapshotsField, MaxRestoreField } from './common'; +import { DisableToolTip, MANAGED_REPOSITORY_TOOLTIP_MESSAGE } from '../../disable_tooltip'; interface Props { repository: S3Repository; @@ -117,16 +118,22 @@ export const S3Settings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.client)} error={settingErrors.client} > - { - updateRepositorySettings({ - client: e.target.value, - }); - }} - data-test-subj="clientInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + client: e.target.value, + }); + }} + data-test-subj="clientInput" + disabled={isManagedRepository} + /> + } /> @@ -162,16 +169,22 @@ export const S3Settings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.bucket)} error={settingErrors.bucket} > - { - updateRepositorySettings({ - bucket: e.target.value, - }); - }} - data-test-subj="bucketInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + bucket: e.target.value, + }); + }} + data-test-subj="bucketInput" + disabled={isManagedRepository} + /> + } /> @@ -207,16 +220,22 @@ export const S3Settings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.basePath)} error={settingErrors.basePath} > - { - updateRepositorySettings({ - basePath: e.target.value, - }); - }} - data-test-subj="basePathInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + basePath: e.target.value, + }); + }} + data-test-subj="basePathInput" + disabled={isManagedRepository} + /> + } /> diff --git a/x-pack/plugins/spaces/common/types/space/v1.ts b/x-pack/plugins/spaces/common/types/space/v1.ts index ebd841e914e69..3d7bb94cf65ab 100644 --- a/x-pack/plugins/spaces/common/types/space/v1.ts +++ b/x-pack/plugins/spaces/common/types/space/v1.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { OnBoardingDefaultSolution } from '@kbn/cloud-plugin/common'; +import type { SolutionId } from '@kbn/core-chrome-browser'; import type { SOLUTION_VIEW_CLASSIC } from '../../constants'; -export type SolutionView = OnBoardingDefaultSolution | typeof SOLUTION_VIEW_CLASSIC; +export type SolutionView = SolutionId | typeof SOLUTION_VIEW_CLASSIC; /** * A Space. diff --git a/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap b/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap index af2221e460a32..854beab6dfc93 100644 --- a/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap +++ b/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap @@ -27,11 +27,17 @@ exports[`NavControlPopover renders without crashing 1`] = ` - +
+
+